From 9ad96191ff91ec7efa6aa142e377201fe81b4c40 Mon Sep 17 00:00:00 2001 From: Brett Laptop Date: Wed, 19 Jun 2024 21:16:58 -0400 Subject: [PATCH] memory love, expanding buffer. might already have one of theses. should makes docs! --- CMakeLists.txt | 2 +- include/blt/std/memory.h | 262 ++++++++++++++++++++++++++++++++++++- libraries/parallel-hashmap | 2 +- 3 files changed, 263 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ec452b..5a570a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.20) include(cmake/color.cmake) -set(BLT_VERSION 0.17.14) +set(BLT_VERSION 0.17.15) set(BLT_TEST_VERSION 0.0.1) set(BLT_TARGET BLT) diff --git a/include/blt/std/memory.h b/include/blt/std/memory.h index 9b4b2a5..0915123 100644 --- a/include/blt/std/memory.h +++ b/include/blt/std/memory.h @@ -224,7 +224,7 @@ namespace blt constexpr inline const_iterator crbegin() const noexcept { - return const_reverse_iterator {cend()}; + return const_reverse_iterator{cend()}; } constexpr inline reverse_iterator crend() const noexcept @@ -248,6 +248,266 @@ namespace blt scoped_buffer operator=(scoped_buffer& copyAssignment) = delete; }; + + // TODO: might already have a version of this somewhere! + template || std::is_copy_assignable_v> + class expanding_buffer; + + template + class expanding_buffer + { + public: + using element_type = T; + using value_type = std::remove_cv_t; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using iterator = ptr_iterator; + using const_iterator = ptr_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + private: + T* buffer_ = nullptr; + size_t size_; + public: + constexpr expanding_buffer(): buffer_(nullptr), size_(0) + {} + + constexpr explicit expanding_buffer(size_t size): size_(size) + { + if (size > 0) + buffer_ = new T[size]; + else + buffer_ = nullptr; + } + + constexpr expanding_buffer(const expanding_buffer& copy) + { + if (copy.size() == 0) + { + buffer_ = nullptr; + size_ = 0; + return; + } + buffer_ = new T[copy.size()]; + size_ = copy.size_; + + if constexpr (std::is_trivially_copyable_v) + { + std::memcpy(buffer_, copy.buffer_, copy.size() * sizeof(T)); + } else + { + if constexpr (std::is_copy_constructible_v && !std::is_copy_assignable_v) + { + for (size_t i = 0; i < this->size_; i++) + buffer_[i] = T(copy[i]); + } else + for (size_t i = 0; i < this->size_; i++) + buffer_[i] = copy[i]; + } + } + + constexpr expanding_buffer& operator=(const expanding_buffer& copy) + { + if (© == this) + return *this; + + if (copy.size() == 0) + { + buffer_ = nullptr; + size_ = 0; + return *this; + } + + delete_this(buffer_, size()); + buffer_ = new T[copy.size()]; + size_ = copy.size_; + + if constexpr (std::is_trivially_copyable_v) + { + std::memcpy(buffer_, copy.buffer_, copy.size() * sizeof(T)); + } else + { + if constexpr (std::is_copy_constructible_v && !std::is_copy_assignable_v) + { + for (size_t i = 0; i < this->size_; i++) + buffer_[i] = T(copy[i]); + } else + for (size_t i = 0; i < this->size_; i++) + buffer_[i] = copy[i]; + } + return *this; + } + + constexpr expanding_buffer(expanding_buffer&& move) noexcept + { + delete_this(buffer_, size()); + buffer_ = move.buffer_; + size_ = move.size(); + move.buffer_ = nullptr; + } + + constexpr expanding_buffer& operator=(expanding_buffer&& moveAssignment) noexcept + { + delete_this(buffer_, size()); + buffer_ = moveAssignment.buffer_; + size_ = moveAssignment.size(); + moveAssignment.buffer_ = nullptr; + + return *this; + } + + /** + * Resize the internal buffer. Nothing will occur if the sizes are equal. + * This function WILL NOT COPY ANY DATA. It is meant for use when creating a scoped buffer without size. + */ + constexpr void resize(size_t size) + { + if (size == 0) + return; + if (size == size_) + return; + delete_this(buffer_, this->size()); + buffer_ = new T[size]; + size_ = size; + } + + constexpr inline T& operator[](size_t index) + { + if (index >= size()) + expand(index); + return buffer_[index]; + } + + constexpr inline const T& operator[](size_t index) const + { + if (index >= size()) + expand(index); + return buffer_[index]; + } + + constexpr inline T* operator*() + { + return buffer_; + } + + [[nodiscard]] constexpr inline size_t size() const + { + return size_; + } + + constexpr inline T*& ptr() + { + return buffer_; + } + + constexpr inline const T* const& ptr() const + { + return buffer_; + } + + constexpr inline const T* const& data() const + { + return buffer_; + } + + constexpr inline T*& data() + { + return buffer_; + } + + constexpr iterator begin() noexcept + { + return iterator{data()}; + } + + constexpr iterator end() noexcept + { + return iterator{data() + size()}; + } + + constexpr const_iterator cbegin() const noexcept + { + return const_iterator{data()}; + } + + constexpr const_iterator cend() const noexcept + { + return const_iterator{data() + size()}; + } + + constexpr inline reverse_iterator rbegin() noexcept + { + return reverse_iterator{end()}; + } + + constexpr inline reverse_iterator rend() noexcept + { + return reverse_iterator{begin()}; + } + + constexpr inline const_iterator crbegin() const noexcept + { + return const_reverse_iterator{cend()}; + } + + constexpr inline reverse_iterator crend() const noexcept + { + return reverse_iterator{cbegin()}; + } + + ~expanding_buffer() + { + delete_this(buffer_, size()); + } + + private: + void expand(blt::size_t size) + { + size = std::max(this->size(), size); + T* new_buffer = new T[blt::mem::next_byte_allocation(size)]; + if constexpr (std::is_trivially_copyable_v) + { + std::memcpy(new_buffer, buffer_, size * sizeof(T)); + } else + { + if constexpr (std::is_copy_constructible_v && !std::is_move_constructible_v) + { + for (size_t i = 0; i < size; i++) + new_buffer[i] = T(buffer_[i]); + } else + for (size_t i = 0; i < size; i++) + new_buffer[i] = std::move(buffer_[i]); + } + delete[] buffer_; + buffer_ = new_buffer; + } + + inline void delete_this(T* buffer, blt::size_t) + { +// if constexpr (std::is_trivially_destructible_v) +// return; +// if (buffer == nullptr) +// return; +// for (blt::size_t i = 0; i < size; i++) +// buffer[i]->~T(); +// free(buffer); + delete[] buffer; + } + }; + + template + class expanding_buffer : expanding_buffer + { + using expanding_buffer::expanding_buffer; + public: + expanding_buffer(const expanding_buffer& copy) = delete; + + expanding_buffer operator=(expanding_buffer& copyAssignment) = delete; + }; + + template struct nullptr_initializer { diff --git a/libraries/parallel-hashmap b/libraries/parallel-hashmap index d88c5e1..1036816 160000 --- a/libraries/parallel-hashmap +++ b/libraries/parallel-hashmap @@ -1 +1 @@ -Subproject commit d88c5e15079047777b418132ece5879e7c9aaa2b +Subproject commit 10368163ab1f4367d2f0685b5928b1c973ebd1ec