188 lines
5.5 KiB
C++
Executable File
188 lines
5.5 KiB
C++
Executable File
// =====================================================================================================================
|
|
// open-cpp-utils, an open-source cpp library with data structures that extend the STL.
|
|
// Copyright (C) 2024 Medusa Slockbower
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
// =====================================================================================================================
|
|
|
|
#ifndef OPEN_CPP_UTILS_ALLOCATION_H
|
|
#define OPEN_CPP_UTILS_ALLOCATION_H
|
|
|
|
#include <cassert>
|
|
#include <memory>
|
|
|
|
namespace open_cpp_utils
|
|
{
|
|
|
|
template<typename T, class Alloc = std::allocator<T>>
|
|
class allocation
|
|
{
|
|
public:
|
|
using data_type = T;
|
|
using reference = data_type&;
|
|
using const_reference = const data_type&;
|
|
using pointer = data_type*;
|
|
using const_pointer = const data_type*;
|
|
|
|
|
|
allocation();
|
|
allocation(size_t size);
|
|
allocation(allocation&& alloc) noexcept;
|
|
allocation(const allocation& alloc);
|
|
~allocation();
|
|
|
|
size_t size() const { return Size_; }
|
|
bool operator()() const { return Buffer_ != nullptr; }
|
|
|
|
void allocate(size_t size);
|
|
void reallocate(size_t size);
|
|
void free();
|
|
|
|
void clear(size_t offset, size_t size, const T& value);
|
|
void copy(const allocation& other, size_t offset, size_t o_offset, size_t size);
|
|
|
|
reference operator[](int i) { assert(i >= 0 && i < Size_); return Buffer_[i]; }
|
|
const_reference operator[](int i) const { assert(i >= 0 && i < Size_); return Buffer_[i]; }
|
|
|
|
operator pointer() { return Buffer_; }
|
|
operator const_pointer() const { return Buffer_; }
|
|
|
|
allocation& operator=(const allocation& other);
|
|
allocation& operator=(allocation&& other) noexcept;
|
|
|
|
pointer data() { return Buffer_; }
|
|
const_pointer data() const { return Buffer_; }
|
|
|
|
pointer begin() { return Buffer_; }
|
|
pointer end() { return Buffer_ + Size_; }
|
|
|
|
const_pointer begin() const { return Buffer_; }
|
|
const_pointer end() const { return Buffer_ + Size_; }
|
|
|
|
private:
|
|
Alloc Alloc_;
|
|
size_t Size_;
|
|
T* Buffer_;
|
|
};
|
|
|
|
template<typename T, class Alloc>
|
|
allocation<T, Alloc>::allocation()
|
|
: Alloc_(), Size_(0), Buffer_(nullptr) { }
|
|
|
|
template<typename T, class Alloc>
|
|
allocation<T, Alloc>::allocation(size_t size)
|
|
: Alloc_(), Size_(size), Buffer_(Alloc_.allocate(Size_)) { }
|
|
|
|
template<typename T, class Alloc>
|
|
allocation<T, Alloc>::allocation(allocation &&alloc) noexcept
|
|
: Alloc_(), Size_(alloc.Size_), Buffer_(alloc.Buffer_) { }
|
|
|
|
template<typename T, class Alloc>
|
|
allocation<T, Alloc>::allocation(const allocation &alloc)
|
|
: Alloc_(), Size_(alloc.Size_), Buffer_(Alloc_.allocate(Size_))
|
|
{
|
|
copy(alloc, 0, 0, Size_);
|
|
}
|
|
|
|
template<typename T, class Alloc>
|
|
allocation<T, Alloc>::~allocation()
|
|
{
|
|
Alloc_.deallocate(Buffer_, Size_);
|
|
Buffer_ = nullptr; Size_ = 0;
|
|
}
|
|
|
|
template<typename T, class Alloc>
|
|
void allocation<T, Alloc>::allocate(size_t size)
|
|
{
|
|
assert(Buffer_ != nullptr);
|
|
if(Buffer_ == nullptr) return;
|
|
|
|
Buffer_ = Alloc_.allocate(size);
|
|
}
|
|
|
|
template<typename T, class Alloc>
|
|
void allocation<T, Alloc>::reallocate(size_t size)
|
|
{
|
|
// Assertions for debug mode
|
|
assert(Buffer_ != nullptr);
|
|
|
|
// Safety checks
|
|
if(Buffer_ == nullptr) return;
|
|
|
|
const allocation old_ = std::move(*this);
|
|
std::construct_at(this, size);
|
|
std::memcpy(Buffer_, old_.Buffer_, old_.Size_);
|
|
}
|
|
|
|
template<typename T, class Alloc>
|
|
void allocation<T, Alloc>::free()
|
|
{
|
|
Alloc_.deallocate(Buffer_, Size_);
|
|
Buffer_ = nullptr; Size_ = 0;
|
|
}
|
|
|
|
template<typename T, class Alloc>
|
|
void allocation<T, Alloc>::clear(size_t offset, size_t size, const T &value)
|
|
{
|
|
// Safety checks
|
|
if(Buffer_ == nullptr) return;
|
|
size = std::min(size, Size_ - offset);
|
|
|
|
for(pointer it = Buffer_ + offset; it != Buffer_ + size; ++it)
|
|
{
|
|
std::destroy_at(it);
|
|
std::construct_at(it, value);
|
|
}
|
|
}
|
|
|
|
template<typename T, class Alloc>
|
|
void allocation<T, Alloc>::copy(const allocation &other, size_t offset, size_t o_offset, size_t size)
|
|
{
|
|
// Assertions for debug mode
|
|
assert(size <= Size_ - offset && size <= other.Size_ - o_offset);
|
|
|
|
// Safety checks
|
|
if(Buffer_ == nullptr || other.Buffer_ == nullptr) return;
|
|
if(offset >= Size_ || o_offset >= other.Size_) return;
|
|
size = std::min(size, Size_ - offset);
|
|
size = std::min(size, other.Size_ - o_offset);
|
|
|
|
std::memcpy(Buffer_ + offset, other.Buffer_ + o_offset, size * sizeof(data_type));
|
|
}
|
|
|
|
template<typename T, class Alloc>
|
|
allocation<T, Alloc> & allocation<T, Alloc>::operator=(const allocation &other)
|
|
{
|
|
if(&other == this) return *this;
|
|
|
|
Size_ = other.Size_;
|
|
Buffer_ = Alloc_.allocate(Size_);
|
|
copy(other, 0, 0, Size_);
|
|
return *this;
|
|
}
|
|
|
|
template<typename T, class Alloc>
|
|
allocation<T, Alloc> & allocation<T, Alloc>::operator=(allocation &&other) noexcept
|
|
{
|
|
if(&other == this) return *this;
|
|
|
|
Size_ = other.Size_;
|
|
Buffer_ = other.Buffer_;
|
|
return *this;
|
|
}
|
|
|
|
}
|
|
|
|
#endif //ALLOCATION_H
|