Skip to content

Commit 3e635de

Browse files
committed
Add DBBitArray
1 parent dd8eb56 commit 3e635de

4 files changed

Lines changed: 439 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ set(LCF_SOURCES
197197
set(LCF_HEADERS
198198
src/lcf/data.h
199199
src/lcf/dbarray.h
200+
src/lcf/dbbitarray.h
200201
src/lcf/dbstring.h
201202
src/lcf/encoder.h
202203
src/lcf/enum_tags.h

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ liblcf_la_SOURCES = \
204204
lcfinclude_HEADERS = \
205205
src/lcf/data.h \
206206
src/lcf/dbarray.h \
207+
src/lcf/dbbitarray.h \
207208
src/lcf/dbstring.h \
208209
src/lcf/encoder.h \
209210
src/lcf/enum_tags.h \

src/lcf/dbbitarray.h

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/*
2+
* This file is part of liblcf. Copyright (c) 2020 liblcf authors.
3+
* https://github.com/EasyRPG/liblcf - https://easyrpg.org
4+
*
5+
* liblcf is Free/Libre Open Source Software, released under the MIT License.
6+
* For the full copyright and license information, please view the COPYING
7+
* file that was distributed with this source code.
8+
*/
9+
10+
#ifndef LCF_DBBITARRAY_H
11+
#define LCF_DBBITARRAY_H
12+
#include <utility>
13+
#include <cstring>
14+
#include <iterator>
15+
#include <cstdint>
16+
#include <climits>
17+
#include <limits>
18+
#include <algorithm>
19+
#include <type_traits>
20+
21+
#include "lcf/dbarray.h"
22+
23+
namespace lcf {
24+
25+
class DBBitProxy {
26+
public:
27+
using size_type = DBArrayBase::size_type;
28+
29+
constexpr DBBitProxy() = default;
30+
31+
DBBitProxy& operator=(const DBBitProxy& x) noexcept = default;
32+
DBBitProxy& operator=(bool x) noexcept {
33+
auto& byte = _base[_idx / CHAR_BIT];
34+
auto bit = _idx % CHAR_BIT;
35+
byte ^= (-size_type(x) ^ byte) & (size_type(1) << bit);
36+
return *this;
37+
}
38+
39+
operator bool() const noexcept {
40+
auto byte = _base[_idx / CHAR_BIT];
41+
auto bit = _idx % CHAR_BIT;
42+
return byte & (1 << bit);
43+
}
44+
45+
void flip() {
46+
auto& byte = _base[_idx / CHAR_BIT];
47+
auto bit = _idx % CHAR_BIT;
48+
byte ^= (1 << bit);
49+
}
50+
51+
size_type index() const {
52+
return _idx;
53+
}
54+
55+
private:
56+
uint8_t* _base = nullptr;
57+
size_type _idx = 0;
58+
59+
constexpr DBBitProxy(void* base, size_type idx) : _base(static_cast<uint8_t*>(base)), _idx(idx) {}
60+
61+
template <typename P>
62+
friend class DBBitProxyIterator;
63+
friend class DBBitArray;
64+
};
65+
66+
template <typename ProxyType>
67+
class DBBitProxyIterator {
68+
public:
69+
using size_type = typename DBBitProxy::size_type;
70+
using ssize_type = typename std::make_signed<size_type>::type;
71+
72+
using difference_type = ssize_type;
73+
using value_type = ProxyType;
74+
using pointer = ProxyType*;
75+
using reference = ProxyType&;
76+
using iterator_category = std::bidirectional_iterator_tag;
77+
78+
constexpr DBBitProxyIterator() = default;
79+
80+
operator DBBitProxyIterator<const ProxyType>() const {
81+
return DBBitProxyIterator<const ProxyType>(_proxy._base, _proxy._idx);
82+
}
83+
84+
ProxyType& operator*() const { return _proxy; }
85+
ProxyType* operator->() const { return &_proxy; }
86+
87+
DBBitProxyIterator& operator++() { ++_proxy._idx; return *this; }
88+
DBBitProxyIterator operator++(int) { auto iter = *this; ++(*this); return iter; }
89+
90+
DBBitProxyIterator& operator--() { --_proxy._idx; return *this; }
91+
DBBitProxyIterator operator--(int) { auto iter = *this; --(*this); return iter; }
92+
93+
void swap(DBBitProxyIterator& o) {
94+
std::swap(_proxy._base, o._base);
95+
std::swap(_proxy._idx, o._idx);
96+
}
97+
98+
friend bool operator==(DBBitProxyIterator l, DBBitProxyIterator r) { return l->index() == r->index(); }
99+
friend bool operator!=(DBBitProxyIterator l, DBBitProxyIterator r) { return !(l == r); }
100+
101+
private:
102+
mutable DBBitProxy _proxy;
103+
104+
constexpr DBBitProxyIterator(void* base, size_type idx) : _proxy(base, idx) {}
105+
106+
friend class DBBitArray;
107+
};
108+
109+
110+
// An array data structure optimized for database storage.
111+
// Low memory footprint and not dynamically resizable.
112+
class DBBitArray : private DBArrayBase {
113+
public:
114+
using value_type = bool;
115+
using DBArrayBase::size_type;
116+
117+
using iterator = DBBitProxyIterator<DBBitProxy>;
118+
using const_iterator = DBBitProxyIterator<const DBBitProxy>;
119+
using reverse_iterator = std::reverse_iterator<iterator>;
120+
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
121+
122+
constexpr DBBitArray() = default;
123+
explicit DBBitArray(size_type count, bool value = false) : _storage(this->alloc(count)) {
124+
std::memset(_storage, value ? 0xff : 0x00, bytes_up_from_bits(count));
125+
}
126+
127+
template <typename Iter,
128+
typename std::enable_if<
129+
std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<Iter>::iterator_category>::value, int>::type = 0
130+
>
131+
DBBitArray(Iter first, Iter last) : _storage(this->alloc(std::distance(first, last))) {
132+
std::copy(first, last, begin());
133+
}
134+
135+
DBBitArray(std::initializer_list<bool> ilist)
136+
: DBBitArray(ilist.begin(), ilist.end()) {}
137+
138+
DBBitArray(const DBBitArray& o) : _storage(this->alloc(o.size())) {
139+
std::memcpy(_storage, o._storage, bytes_up_from_bits(o.size()));
140+
}
141+
DBBitArray(DBBitArray&& o) noexcept { swap(o); }
142+
143+
DBBitArray& operator=(const DBBitArray& o);
144+
DBBitArray& operator=(DBBitArray&& o) noexcept;
145+
146+
void swap(DBBitArray& o) noexcept {
147+
std::swap(_storage, o._storage);
148+
}
149+
150+
~DBBitArray() { destroy(); }
151+
152+
DBBitProxy operator[](size_type i) { return DBBitProxy(_storage, i); }
153+
bool operator[](size_type i) const { return DBBitProxy(_storage, i); }
154+
155+
DBBitProxy front() { return (*this)[0]; }
156+
bool front() const { return (*this)[0]; }
157+
158+
DBBitProxy back() { return (*this)[size()-1]; }
159+
bool back() const { return (*this)[size()-1]; }
160+
161+
iterator begin() { return iterator(_storage, 0); }
162+
iterator end() { return iterator(_storage, size()); }
163+
164+
const_iterator begin() const { return const_iterator(_storage, 0); }
165+
const_iterator end() const { return const_iterator(_storage, size()); }
166+
167+
const_iterator cbegin() const { return begin(); }
168+
const_iterator cend() const { return end(); }
169+
170+
reverse_iterator rbegin() { return reverse_iterator(end()); }
171+
reverse_iterator rend() { return reverse_iterator(begin()); }
172+
173+
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
174+
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
175+
176+
const_reverse_iterator crbegin() const { return rbegin(); }
177+
const_reverse_iterator crend() const { return rend(); }
178+
179+
bool empty() const { return size() == 0; }
180+
size_type size() const { return *get_size_ptr(_storage); }
181+
182+
void set_all() { std::memset(_storage, 0xff, bytes_up_from_bits(size())); }
183+
void reset_all() { std::memset(_storage, 0, bytes_up_from_bits(size())); }
184+
void flip_all() {
185+
auto* p = static_cast<uint8_t*>(_storage);
186+
for (size_t i = 0; i < bytes_up_from_bits(size()); ++i) {
187+
p[i] ^= p[i];
188+
}
189+
}
190+
191+
void set(size_type i) { (*this)[i] = true; }
192+
void reset(size_type i) { (*this)[i] = false; }
193+
void flip(size_type i) { (*this)[i].flip(); }
194+
195+
private:
196+
static constexpr size_type bytes_up_from_bits(size_type bits) {
197+
return (bits / CHAR_BIT) + (bits % CHAR_BIT != 0);
198+
}
199+
200+
void* alloc(size_type bits) {
201+
auto bytes = bytes_up_from_bits(bits);
202+
return DBArrayBase::alloc(bytes, bits, alignof(size_type));
203+
}
204+
205+
void free(void* p) {
206+
DBArrayBase::free(p, alignof(size_type));
207+
}
208+
209+
void destroy() noexcept;
210+
private:
211+
void* _storage = DBArrayBase::empty_buf();
212+
};
213+
214+
inline bool operator==(const DBBitArray& l, const DBBitArray& r) { return std::equal(l.begin(), l.end(), r.begin(), r.end()); }
215+
inline bool operator!=(const DBBitArray& l, const DBBitArray& r) { return !(l == r); }
216+
inline bool operator<(const DBBitArray& l, const DBBitArray& r) { return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); }
217+
inline bool operator>(const DBBitArray& l, const DBBitArray& r) { return r < l; }
218+
inline bool operator<=(const DBBitArray& l, const DBBitArray& r) { return !(l > r); }
219+
inline bool operator>=(const DBBitArray& l, const DBBitArray& r) { return !(l < r); }
220+
221+
inline DBBitArray& DBBitArray::operator=(const DBBitArray& o) {
222+
if (this != &o) {
223+
destroy();
224+
_storage = this->alloc(o.size());
225+
std::memcpy(_storage, o._storage, bytes_up_from_bits(o.size()));
226+
}
227+
return *this;
228+
}
229+
230+
inline DBBitArray& DBBitArray::operator=(DBBitArray&& o) noexcept {
231+
if (this != &o) {
232+
destroy();
233+
swap(o);
234+
}
235+
return *this;
236+
}
237+
238+
void DBBitArray::destroy() noexcept {
239+
if (_storage != this->empty_buf()) {
240+
free(_storage);
241+
_storage = this->empty_buf();
242+
}
243+
}
244+
245+
} // namespace lcf
246+
247+
#endif

0 commit comments

Comments
 (0)