blob: df35f78b8275ed4c9f83a9f457b3e176bfc664a1 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
#ifndef QUICKSTEP_UTILITY_SCOPED_BUFFER_HPP_
#define QUICKSTEP_UTILITY_SCOPED_BUFFER_HPP_
#include <cstddef>
#include <cstdlib>
#include "utility/Alignment.hpp"
#include "utility/Macros.hpp"
#include "glog/logging.h"
namespace quickstep {
/** \addtogroup Utility
* @{
*/
/**
* @brief A class which manages an untyped buffer of heap memory which is freed
* when it goes out of scope.
**/
class ScopedBuffer {
public:
/**
* @brief Constructor which allocates a new chunk of memory of the specified
* size.
*
* @param alloc_size The number of bytes of memory to allocate.
* @param initialize If true, initialize all the bytes of the allocated memory to 0.
**/
explicit ScopedBuffer(const std::size_t alloc_size, bool initialize = true) {
internal_ptr_ = std::malloc(alloc_size);
if (initialize) {
memset(internal_ptr_, 0x0, alloc_size);
}
}
/**
* @brief Constructor which allocates a new chunk of memory of the specified
* size with the specified alignment.
*
* @param alloc_size The number of bytes of memory to allocate.
* @param alloc_alignment The alignment of the memory to allocate.
* @param initialize If true, initialize all the bytes of the allocated memory to 0.
**/
ScopedBuffer(const std::size_t alloc_size,
const std::size_t alloc_alignment,
const bool initialize = true) {
internal_ptr_ = malloc_with_alignment(alloc_size, alloc_alignment);
if (initialize) {
memset(internal_ptr_, 0x0, alloc_size);
}
}
/**
* @brief Constructor which takes ownership of an existing chunk of memory.
* @warning memory MUST be allocated with malloc(), not with new or on the
* stack.
*
* @param memory The memory to take ownership of.
**/
explicit ScopedBuffer(void *memory = nullptr)
: internal_ptr_(memory) {
}
/**
* @brief Move constructor.
*
* @param orig The ScopedBuffer to move from, taking ownership of its memory.
**/
ScopedBuffer(ScopedBuffer &&orig)
: internal_ptr_(orig.internal_ptr_) {
orig.internal_ptr_ = nullptr;
}
/**
* @brief Destructor which frees the memory held in this buffer.
**/
~ScopedBuffer() {
if (internal_ptr_ != nullptr) {
std::free(internal_ptr_);
}
}
/**
* @brief Move-assignment operator.
*
* @param rhs The ScopedBuffer to move from, taking ownership of its memory.
**/
ScopedBuffer& operator=(ScopedBuffer &&rhs) {
if (internal_ptr_ != nullptr) {
std::free(internal_ptr_);
}
internal_ptr_ = rhs.internal_ptr_;
rhs.internal_ptr_ = nullptr;
return *this;
}
/**
* @brief Free the buffer memory and create a new buffer of the specified
* size.
*
* @param alloc_size The number of bytes of memory to allocate.
* @param initialize If true, initialize all the bytes of the allocated memory to 0.
**/
void reset(const std::size_t alloc_size, const bool initialize = true) {
if (internal_ptr_ != nullptr) {
std::free(internal_ptr_);
}
internal_ptr_ = std::malloc(alloc_size);
if (initialize) {
memset(internal_ptr_, 0x0, alloc_size);
}
}
/**
* @brief Free the buffer memory and take ownership of the specified chunk of
* memory.
* @warning memory MUST be allocated with malloc(), not with new or on the
* stack.
*
* @param memory The memory to take ownership of.
**/
void reset(void *memory = nullptr) {
if (internal_ptr_ != NULL) {
std::free(internal_ptr_);
}
internal_ptr_ = memory;
}
/**
* @brief Resize this ScopedBuffer, growing or shrinking it and preserving
* its contents.
* @warning This method may relocate the ScopedBuffer in memory. Any pointers
* that were obtained by calling get() may become invalidated and
* should be reset after calling this method.
*
* @param new_alloc_size The new desired size, in bytes, for this
* ScopedBuffer.
**/
void resize(const std::size_t new_alloc_size) {
DCHECK(internal_ptr_ != nullptr);
if (new_alloc_size == 0) {
reset();
} else {
internal_ptr_ = std::realloc(internal_ptr_, new_alloc_size);
}
}
/**
* @brief Release ownership of the memory owned by this ScopedBuffer, and
* return a pointer to it.
* @warning The caller becomes responsible for managing the memory returned
* by this method, and should free it when it is no longer in use to
* avoid memory leaks.
*
* @return A pointer to the memory previously owned by this ScopedBuffer.
* NULL if empty() was true before the call.
**/
void* release() {
void *memory = internal_ptr_;
internal_ptr_ = nullptr;
return memory;
}
/**
* @brief Check whether this ScopedBuffer is empty, i.e. whether it currently
* owns any memory.
*
* @return Whether this ScopedBuffer is empty.
**/
inline bool empty() const {
return internal_ptr_ == nullptr;
}
/**
* @brief Get a pointer to the memory owned by this ScopedBuffer.
* @warning Do not call free() on the memory returned by this method. Use
* reset() or delete the ScopedBuffer instead.
*
* @return A pointer the memory managed by this ScopedBuffer.
**/
inline void* get() const {
return internal_ptr_;
}
private:
void *internal_ptr_;
DISALLOW_COPY_AND_ASSIGN(ScopedBuffer);
};
/** @} */
} // namespace quickstep
#endif // QUICKSTEP_UTILITY_SCOPED_BUFFER_HPP_