#pragma once #include "tl/detail/prologue.h" #include #include #include "tl/api.h" #include "tl/hash_map.h" #include "tl/plain_assert.h" #include "tl/murmur_hash.h" #include namespace tl { class TL_API memory_buffer { public: using iterator = uint8_t *; using const_iterator = const uint8_t *; using value_type = uint8_t; memory_buffer(); ~memory_buffer(); explicit memory_buffer(size_t size, uint8_t value = 0); memory_buffer(const uint8_t* start, const uint8_t* end); memory_buffer(const uint8_t* start, size_t size); memory_buffer(const memory_buffer& other); memory_buffer& operator=(const memory_buffer& other); memory_buffer(memory_buffer&& other) noexcept; memory_buffer& operator=(memory_buffer&& other) noexcept; bool operator==(const memory_buffer& other) const; bool operator!=(const memory_buffer& other) const; inline void push_back(uint8_t c); void append(const memory_buffer& other); void append(const uint8_t* start, const uint8_t* end); void append(const uint8_t* start, size_t size); void assign(const uint8_t* start, const uint8_t* end); void erase(iterator begin, iterator end); void resize(size_t size, uint8_t value = 0); void resize_uninitialized(size_t size); void reserve(size_t capacity); void shrink_to_fit(); inline void swap(memory_buffer& other) noexcept; void clear(); inline const uint8_t* data() const; inline uint8_t* data(); inline const uint8_t& operator[](size_t i) const; inline uint8_t& operator[](size_t i); inline uint8_t front() const; inline uint8_t back() const; inline uint8_t& front(); inline uint8_t& back(); inline bool empty() const; inline size_t size() const; inline size_t capacity() const; inline iterator begin(); inline iterator end(); inline const_iterator begin() const; inline const_iterator end() const; private: //inline uint32_t& _capacity_unsafe(); //inline const uint32_t& _capacity_unsafe() const; static size_t get_grow_capacity(size_t needed, size_t capacity); //We're storing the sizes in uint32_t and in the allocated buffer itself to save some memory. //This means the memory_buffer is limited to 4GB! //Trying to go over 4GB will result in a crash struct Header// this is only for sizeof purposes { uint32_t m_capacity; uint32_t m_size; }; uint8_t* m_buf; }; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// #define _size() (*reinterpret_cast(m_buf)) #define _capacity() (*reinterpret_cast(m_buf + sizeof(uint32_t))) #define _data() (m_buf + sizeof(Header)) namespace tl { inline void memory_buffer::swap(memory_buffer& other) noexcept { std::swap(m_buf, other.m_buf); } inline void memory_buffer::push_back(uint8_t c) { const size_t size = _size(); const size_t capacity = _capacity(); if (size >= capacity) reserve(get_grow_capacity(size + 1u, capacity)); m_buf[sizeof(Header) + size] = c; _size() = uint32_t(size + 1); } inline const uint8_t* memory_buffer::data() const { return size() > 0 ? _data() : nullptr; } inline uint8_t* memory_buffer::data() { return size() > 0 ? _data() : nullptr; } inline size_t memory_buffer::size() const { return _size(); } inline size_t memory_buffer::capacity() const { return _capacity(); } inline const uint8_t& memory_buffer::operator[](size_t i) const { TL_PLAIN_ASSERT(i < size()); return _data()[i]; } inline uint8_t& memory_buffer::operator[](size_t i) { TL_PLAIN_ASSERT(i < size()); return _data()[i]; } inline uint8_t memory_buffer::front() const { TL_PLAIN_ASSERT(size() > 0); return *_data(); } inline uint8_t memory_buffer::back() const { TL_PLAIN_ASSERT(size() > 0); return _data()[_size() - 1]; } inline uint8_t& memory_buffer::front() { TL_PLAIN_ASSERT(size() > 0); return *_data(); } inline uint8_t& memory_buffer::back() { TL_PLAIN_ASSERT(size() > 0); return _data()[_size() - 1]; } inline bool memory_buffer::empty() const { return size() == 0; } inline memory_buffer::iterator memory_buffer::begin() { return _data(); } inline memory_buffer::iterator memory_buffer::end() { return _data() + _size(); } inline memory_buffer::const_iterator memory_buffer::begin() const { return _data(); } inline memory_buffer::const_iterator memory_buffer::end() const { return _data() + _size(); } } inline void swap(tl::memory_buffer& a, tl::memory_buffer& b) noexcept { a.swap(b); } template <> struct std::hash { size_t operator()(tl::memory_buffer const& s) const noexcept { if (s.empty()) return 0; return tl::murmur32(s.data(), s.size(), 0u); } }; template <> struct eastl::hash { size_t operator()(tl::memory_buffer const& s) const { if (s.empty()) return 0; return tl::murmur32(s.data(), s.size(), 0u); } }; #undef _size #undef _capacity #undef _data