-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
563 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#include "lcf/dbarrayalloc.h" | ||
#include "lcf/dbarray.h" | ||
#include "lcf/dbstring.h" | ||
#include <cassert> | ||
#include <cstddef> | ||
|
||
//#define LCF_DEBUG_DBARRAY | ||
|
||
#ifdef LCF_DEBUG_DBARRAY | ||
#include <iostream> | ||
#endif | ||
|
||
namespace lcf { | ||
|
||
constexpr DBArrayAlloc::size_type DBArrayAlloc::_empty_buf; | ||
constexpr DBString::size_type DBString::npos; | ||
|
||
static ptrdiff_t HeaderSize(size_t align) { | ||
return std::max(sizeof(DBArrayAlloc::size_type), align); | ||
} | ||
|
||
static size_t AllocSize(size_t size, size_t align) { | ||
return HeaderSize(align) + size; | ||
} | ||
|
||
static void* Adjust(void* p, ptrdiff_t off) { | ||
return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(p) + off); | ||
} | ||
|
||
void* DBArrayAlloc::alloc(size_type size, size_type field_size, size_type align) { | ||
if (field_size == 0) { | ||
return empty_buf(); | ||
} | ||
assert(align <= alignof(std::max_align_t)); | ||
auto* raw = ::operator new(AllocSize(size, align)); | ||
auto* p = Adjust(raw, HeaderSize(align)); | ||
*get_size_ptr(p) = field_size; | ||
#ifdef LCF_DEBUG_DBARRAY | ||
std::cout << "DBArray: Allocated" | ||
<< " size=" << size | ||
<< " field_size=" << *get_size_ptr(p) | ||
<< " align=" << align | ||
<< " ptr=" << raw | ||
<< " adjusted=" << p | ||
<< std::endl; | ||
#endif | ||
return p; | ||
} | ||
|
||
void DBArrayAlloc::free(void* p, size_type align) noexcept { | ||
assert(p != nullptr); | ||
if (p != empty_buf()) { | ||
auto* raw = Adjust(p, -HeaderSize(align)); | ||
#ifdef LCF_DEBUG_DBARRAY | ||
std::cout << "DBArray: Free" | ||
<< " align=" << align | ||
<< " ptr=" << raw | ||
<< " adjusted=" << p | ||
<< " field_size=" << *get_size_ptr(p) | ||
<< std::endl; | ||
#endif | ||
::operator delete(raw); | ||
} | ||
} | ||
|
||
char* DBString::construct_z(const char* s, size_t len) { | ||
auto* p = alloc(len); | ||
if (len) { | ||
std::memcpy(p, s, len + 1); | ||
} | ||
return p; | ||
} | ||
|
||
char* DBString::construct_sv(const char* s, size_t len) { | ||
auto* p = alloc(len); | ||
if (len) { | ||
std::memcpy(p, s, len); | ||
p[len] = '\0'; | ||
} | ||
return p; | ||
} | ||
|
||
DBString& DBString::operator=(const DBString& o) { | ||
if (this != &o) { | ||
destroy(); | ||
_storage = construct_z(o.data(), o.size()); | ||
} | ||
return *this; | ||
} | ||
|
||
} // namespace lcf |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
/* | ||
* This file is part of liblcf. Copyright (c) 2020 liblcf authors. | ||
* https://github.com/EasyRPG/liblcf - https://easyrpg.org | ||
* | ||
* liblcf is Free/Libre Open Source Software, released under the MIT License. | ||
* For the full copyright and license information, please view the COPYING | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
#ifndef LCF_DBARRAY_H | ||
#define LCF_DBARRAY_H | ||
#include <utility> | ||
#include <string> | ||
#include <iterator> | ||
#include <cstdint> | ||
#include <limits> | ||
#include <algorithm> | ||
#include <type_traits> | ||
|
||
#include "lcf/dbarrayalloc.h" | ||
#include "lcf/scope_guard.h" | ||
|
||
namespace lcf { | ||
|
||
// An array data structure optimized for database storage. | ||
// Low memory footprint and not dynamically resizable. | ||
template <typename T> | ||
class DBArray { | ||
public: | ||
using value_type = T; | ||
using size_type = DBArrayAlloc::size_type; | ||
|
||
using iterator = T*; | ||
using const_iterator = const T*; | ||
using reverse_iterator = std::reverse_iterator<iterator>; | ||
using const_reverse_iterator = std::reverse_iterator<const_iterator>; | ||
|
||
constexpr DBArray() = default; | ||
explicit DBArray(size_type count) { | ||
construct(count, [](void* p) { new (p) T(); }); | ||
} | ||
|
||
explicit DBArray(size_type count, const T& value) { | ||
construct(count, [&](void* p) { new (p) T(value); }); | ||
} | ||
|
||
template <typename Iter, | ||
typename std::enable_if< | ||
std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<Iter>::iterator_category>::value, int>::type = 0 | ||
> | ||
DBArray(Iter first, Iter last) { | ||
construct(std::distance(first, last), [&](void* p) { new (p) T(*first); ++first; }); | ||
} | ||
|
||
DBArray(std::initializer_list<T> ilist) | ||
: DBArray(ilist.begin(), ilist.end()) {} | ||
|
||
DBArray(const DBArray& o) : DBArray(o.begin(), o.end()) {} | ||
DBArray(DBArray&& o) noexcept { swap(o); } | ||
|
||
DBArray& operator=(const DBArray&); | ||
DBArray& operator=(DBArray&& o) noexcept; | ||
|
||
void swap(DBArray& o) noexcept { | ||
std::swap(_storage, o._storage); | ||
} | ||
|
||
~DBArray() { destroy(); } | ||
|
||
T& operator[](size_type i) { return data()[i]; } | ||
const T& operator[](size_type i) const { return data()[i]; } | ||
|
||
T& front() { return (*this)[0]; } | ||
const T& front() const { return (*this)[0]; } | ||
|
||
T& back() { return (*this)[size()-1]; } | ||
const T& back() const { return (*this)[size()-1]; } | ||
|
||
T* data() { return reinterpret_cast<T*>(_storage); } | ||
const T* data() const { return reinterpret_cast<const T*>(_storage); } | ||
|
||
iterator begin() { return data(); } | ||
iterator end() { return data() + size(); } | ||
|
||
const_iterator begin() const { return data(); } | ||
const_iterator end() const { return data() + size(); } | ||
|
||
const_iterator cbegin() const { return begin(); } | ||
const_iterator cend() const { return end(); } | ||
|
||
reverse_iterator rbegin() { return reverse_iterator(end()); } | ||
reverse_iterator rend() { return reverse_iterator(begin()); } | ||
|
||
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } | ||
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } | ||
|
||
const_reverse_iterator crbegin() const { return rbegin(); } | ||
const_reverse_iterator crend() const { return rend(); } | ||
|
||
bool empty() const { return size() == 0; } | ||
size_type size() const { return *DBArrayAlloc::get_size_ptr(_storage); } | ||
|
||
private: | ||
T* alloc(size_t count) { | ||
return reinterpret_cast<T*>(DBArrayAlloc::alloc(count * sizeof(T), count, alignof(T))); | ||
} | ||
|
||
void free(void* p) { | ||
DBArrayAlloc::free(p, alignof(T)); | ||
} | ||
|
||
template <typename F> | ||
void construct(size_type count, const F& make); | ||
|
||
void destroy() noexcept; | ||
void destroy_impl(size_type n) noexcept; | ||
private: | ||
void* _storage = DBArrayAlloc::empty_buf(); | ||
}; | ||
|
||
template <typename T> | ||
inline bool operator==(const DBArray<T>& l, const DBArray<T>& r) { return std::equal(l.begin(), l.end(), r.begin(), r.end()); } | ||
template <typename T> | ||
inline bool operator!=(const DBArray<T>& l, const DBArray<T>& r) { return !(l == r); } | ||
template <typename T> | ||
inline bool operator<(const DBArray<T>& l, const DBArray<T>& r) { return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); } | ||
template <typename T> | ||
inline bool operator>(const DBArray<T>& l, const DBArray<T>& r) { return r < l; } | ||
template <typename T> | ||
inline bool operator<=(const DBArray<T>& l, const DBArray<T>& r) { return !(l > r); } | ||
template <typename T> | ||
inline bool operator>=(const DBArray<T>& l, const DBArray<T>& r) { return !(l < r); } | ||
|
||
} // namespace lcf | ||
|
||
namespace lcf { | ||
|
||
template <typename T> | ||
inline DBArray<T>& DBArray<T>::operator=(const DBArray<T>& o) { | ||
if (this != &o) { | ||
destroy(); | ||
if (!o.empty()) { | ||
auto iter = o.begin(); | ||
construct(o.size(), [&](void* p) { new (p) T(*(iter++)); }); | ||
} | ||
} | ||
return *this; | ||
} | ||
|
||
template <typename T> | ||
inline DBArray<T>& DBArray<T>::operator=(DBArray<T>&& o) noexcept { | ||
if (this != &o) { | ||
destroy(); | ||
swap(o); | ||
} | ||
return *this; | ||
} | ||
|
||
template <typename T> | ||
template <typename F> | ||
void DBArray<T>::construct(size_type count, const F& make) { | ||
auto* p = alloc(count); | ||
|
||
size_type i = 0; | ||
auto rollback = makeScopeGuard([&]() { destroy_impl(i); }); | ||
for (size_type i = 0; i < count; ++i) { | ||
make(p + i); | ||
} | ||
rollback.Dismiss(); | ||
_storage = p; | ||
} | ||
|
||
template <typename T> | ||
void DBArray<T>::destroy() noexcept { | ||
if (_storage != DBArrayAlloc::empty_buf()) { | ||
destroy_impl(size()); | ||
_storage = DBArrayAlloc::empty_buf(); | ||
} | ||
} | ||
|
||
template <typename T> | ||
void DBArray<T>::destroy_impl(size_type n) noexcept { | ||
while (n > 0) { | ||
data()[--n].~T(); | ||
} | ||
free(_storage); | ||
} | ||
|
||
} // namespace lcf | ||
|
||
#endif |
Oops, something went wrong.