Files
TL/include/tl/memory_buffer.h
jeanlemotan 8297b0b45f First
2024-07-02 18:06:33 +02:00

224 lines
4.9 KiB
C++

#pragma once
#include "tl/detail/prologue.h"
#include <cstdint>
#include <algorithm>
#include "tl/api.h"
#include "tl/hash_map.h"
#include "tl/plain_assert.h"
#include "tl/murmur_hash.h"
#include <unordered_map>
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<uint32_t*>(m_buf))
#define _capacity() (*reinterpret_cast<uint32_t*>(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<tl::memory_buffer>
{
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<tl::memory_buffer>
{
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