15 #include "allocators.h"
20 template<
typename SizeType =
unsigned>
26 template<
typename Type,
typename SizeType =
unsigned>
28 using Container = Type*;
35 template<GARLIC_ALLOCATOR Allocator,
typename SizeType =
unsigned>
37 using List = Array<GenericData, SizeType>;
38 using Object = Array<MemberPair<GenericData>, SizeType>;
39 using AllocatorType = Allocator;
41 TypeFlag type = TypeFlag::Null;
46 StringData<SizeType> string;
52 template<
typename Layer,
typename Iterator>
53 struct ConstMemberIteratorWrapper {
54 using output_type = MemberPair<Layer>;
55 using iterator_type = Iterator;
57 iterator_type iterator;
59 inline output_type wrap()
const {
61 Layer { iterator->key },
62 Layer { iterator->value }
67 template<
typename Layer,
typename Iterator,
typename Allocator>
68 struct MemberIteratorWrapper {
69 using output_type = MemberPair<Layer>;
70 using iterator_type = Iterator;
71 using allocator_type = Allocator;
73 iterator_type iterator;
74 allocator_type* allocator;
76 inline output_type wrap()
const {
78 Layer { iterator->key, *allocator },
79 Layer { iterator->value, *allocator }
84 template<
typename Layer,
typename Iterator,
typename Allocator>
85 struct ValueIteratorWrapper {
86 using output_type = Layer;
87 using iterator_type = Iterator;
88 using allocator_type = Allocator;
90 iterator_type iterator;
91 allocator_type* allocator;
93 inline output_type wrap()
const {
94 return output_type { *iterator, *allocator };
98 template<GARLIC_ALLOCATOR Allocator,
typename SizeType =
unsigned>
99 class GenericCloveView {
101 using DataType = GenericData<Allocator, SizeType>;
102 using ProviderValueIterator =
typename DataType::List::Container;
103 using ProviderMemberIterator =
typename DataType::Object::Container;
104 using ConstValueIterator = BasicRandomAccessIterator<GenericCloveView, ProviderValueIterator>;
105 using ConstMemberIterator = RandomAccessIterator<
106 ConstMemberIteratorWrapper<GenericCloveView, ProviderMemberIterator>>;
108 GenericCloveView (
const DataType& data) : data_(data) {}
110 bool is_null() const noexcept {
return data_.type & TypeFlag::Null; }
111 bool is_int() const noexcept {
return data_.type & TypeFlag::Integer; }
112 bool is_string() const noexcept {
return data_.type & TypeFlag::String; }
113 bool is_double() const noexcept {
return data_.type & TypeFlag::Double; }
114 bool is_object() const noexcept {
return data_.type & TypeFlag::Object; }
115 bool is_list() const noexcept {
return data_.type & TypeFlag::List; }
116 bool is_bool() const noexcept {
return data_.type & TypeFlag::Boolean; }
118 int get_int()
const {
return data_.integer; }
119 double get_double()
const {
return data_.dvalue; }
120 bool get_bool()
const {
return data_.boolean; }
121 const char* get_cstr()
const {
return data_.string.data; }
122 std::string get_string()
const {
123 return std::string{data_.string.data, data_.string.length};
125 std::string_view get_string_view()
const {
126 return std::string_view{data_.string.data, data_.string.length};
129 ConstValueIterator begin_list()
const {
return ConstValueIterator({data_.list.data}); }
130 ConstValueIterator end_list()
const {
131 return ConstValueIterator({data_.list.data + data_.list.length});
133 auto get_list()
const {
return ConstListRange<GenericCloveView>{*
this}; }
135 ConstMemberIterator begin_member()
const {
return ConstMemberIterator({data_.object.data}); }
136 ConstMemberIterator end_member()
const {
137 return ConstMemberIterator({data_.object.data + data_.object.length});
139 ConstMemberIterator find_member(text key)
const {
140 return std::find_if(this->begin_member(), this->end_member(), [&key](
auto item) {
141 return strncmp(item.key.get_cstr(), key.data(), key.size()) == 0;
144 ConstMemberIterator find_member(
const GenericCloveView& value)
const {
145 return this->find_member(value.get_cstr());
147 auto get_object()
const {
return ConstMemberRange<GenericCloveView>{*
this}; }
149 GenericCloveView get_view()
const {
return GenericCloveView{data_}; }
150 const DataType& get_inner_value()
const {
return data_; }
153 const DataType& data_;
157 template<GARLIC_ALLOCATOR Allocator,
typename SizeType =
unsigned>
158 class GenericCloveRef :
public GenericCloveView<Allocator> {
160 using ViewType = GenericCloveView<Allocator, SizeType>;
161 using DataType =
typename ViewType::DataType;
162 using AllocatorType = Allocator;
163 using ProviderValueIterator =
typename ViewType::ProviderValueIterator;
164 using ProviderMemberIterator =
typename ViewType::ProviderMemberIterator;
165 using ValueIterator = RandomAccessIterator<
166 ValueIteratorWrapper<GenericCloveRef, ProviderValueIterator, AllocatorType>>;
167 using MemberIterator = RandomAccessIterator<
168 MemberIteratorWrapper<GenericCloveRef, ProviderMemberIterator, AllocatorType>>;
169 using ViewType::begin_list;
170 using ViewType::end_list;
171 using ViewType::get_list;
172 using ViewType::begin_member;
173 using ViewType::end_member;
174 using ViewType::get_object;
175 using ViewType::find_member;
178 DataType& data, AllocatorType& allocator
179 ) : data_(data), allocator_(allocator), ViewType(data) {}
182 void set_string(
const char* str) {
183 this->prepare_string(strlen(str));
184 strcpy(this->data_.string.data, str);
187 void set_string(text value) {
188 this->prepare_string(value.size());
189 strncpy(this->data_.string.data, value.data(), value.size());
192 void set_double(
double value) {
194 this->data_.type = TypeFlag::Double;
195 this->data_.dvalue = value;
197 void set_int(
int value) {
199 this->data_.type = TypeFlag::Integer;
200 this->data_.integer = value;
202 void set_bool(
bool value) {
204 this->data_.type = TypeFlag::Boolean;
205 this->data_.boolean = value;
209 this->data_.type = TypeFlag::Null;
212 if (this->is_list())
return;
214 this->data_.type = TypeFlag::List;
215 this->data_.list.data =
reinterpret_cast<typename DataType::List::Container
>(
216 allocator_.allocate(256 *
sizeof(DataType))
218 this->data_.list.length = 0;
219 this->data_.list.capacity = 16;
222 if (this->is_object())
return;
224 this->data_.type = TypeFlag::Object;
225 this->data_.object.data =
reinterpret_cast<typename DataType::Object::Container
>(
226 allocator_.allocate(16 *
sizeof(MemberPair<DataType>))
228 this->data_.object.length = 0;
229 this->data_.object.capacity = 16;
232 GenericCloveRef& operator = (
double value) { this->set_double(value);
return *
this; }
233 GenericCloveRef& operator = (
int value) { this->set_int(value);
return *
this; }
234 GenericCloveRef& operator = (
bool value) { this->set_bool(value);
return *
this; }
235 GenericCloveRef& operator = (text value) { this->set_string(value);
return *
this; }
237 ValueIterator begin_list() {
238 return ValueIterator({data_.list.data, &allocator_});
240 ValueIterator end_list() {
241 return ValueIterator({data_.list.data + data_.list.length, &allocator_});
243 ListRange<GenericCloveRef> get_list() {
return ListRange<GenericCloveRef>{*
this}; }
245 MemberIterator begin_member() {
return MemberIterator({data_.object.data, &allocator_}); }
246 MemberIterator end_member() {
247 return MemberIterator({
248 data_.object.data + data_.object.length,
252 MemberRange<GenericCloveRef> get_object() {
return MemberRange<GenericCloveRef>{*
this}; }
257 std::for_each(this->begin_list(), this->end_list(), [](
auto item){ item.clean(); });
258 this->data_.list.length = 0;
261 template<
typename Callable>
262 void push_back_builder(Callable&& cb) {
265 cb(GenericCloveRef(value, allocator_));
266 this->push_back(std::move(value));
268 void push_back(DataType&& value) {
270 this->data_.list.data[this->data_.list.length++] = std::move(value);
273 this->push_back(DataType{});
275 void push_back(
const char* value) {
276 this->push_back(text (value));
278 void push_back(text value) {
280 GenericCloveRef(data, allocator_).set_string(value);
281 this->push_back(std::move(data));
283 void push_back(
double value) {
285 GenericCloveRef(data, allocator_).set_double(value);
286 this->push_back(std::move(data));
288 void push_back(
int value) {
290 GenericCloveRef(data, allocator_).set_int(value);
291 this->push_back(std::move(data));
293 void push_back(
bool value) {
295 GenericCloveRef(data, allocator_).set_bool(value);
296 this->push_back(std::move(data));
299 (*ValueIterator({this->data_.list.data + this->data_.list.length - 1, &allocator_})).clean();
300 this->data_.list.length--;
302 void erase(
const ValueIterator& first,
const ValueIterator& last) {
303 std::for_each(first, last, [](
auto item) { item.clean(); });
304 auto count = last.get_inner_iterator() - first.get_inner_iterator();
306 static_cast<void*
>(first.get_inner_iterator()),
307 static_cast<void*
>(last.get_inner_iterator()),
308 static_cast<SizeType
>(this->end_list().get_inner_iterator() - last.get_inner_iterator()) *
sizeof(DataType)
310 data_.list.length -= count;
312 void erase(
const ValueIterator& position) { this->erase(position, std::next(position)); }
315 MemberIterator find_member(text key) {
316 return std::find_if(this->begin_member(), this->end_member(), [&key](
auto item) {
317 return key.compare(item.key.get_cstr()) == 0;
321 template<
typename Callable>
322 void add_member_builder(text key, Callable&& cb) {
324 cb(GenericCloveRef(value, allocator_));
325 this->add_member(key, std::move(value));
328 void add_member(DataType&& key, DataType&& value) {
329 this->check_members();
330 this->data_.object.data[this->data_.object.length] = MemberPair<DataType>{std::move(key), std::move(value)};
331 this->data_.object.length++;
333 void add_member(text key, DataType&& value) {
334 DataType data; GenericCloveRef(data, allocator_).set_string(key);
335 this->add_member(std::move(data), std::move(value));
337 void add_member(text key) {
338 this->add_member(key, DataType{});
340 void add_member(text key,
const char* value) {
341 this->add_member(key, text(value));
343 void add_member(text key, text value) {
344 DataType data; GenericCloveRef(data, allocator_).set_string(value);
345 this->add_member(key, std::move(data));
347 void add_member(text key,
bool value) {
348 DataType data; GenericCloveRef(data, allocator_).set_bool(value);
349 this->add_member(key, std::move(data));
351 void add_member(text key,
double value) {
352 DataType data; GenericCloveRef(data, allocator_).set_double(value);
353 this->add_member(key, std::move(data));
355 void add_member(text key,
int value) {
356 DataType data; GenericCloveRef(data, allocator_).set_int(value);
357 this->add_member(key, std::move(data));
359 void remove_member(text key) {
360 auto it = this->find_member(key);
361 if (it != this->end_member()) this->erase_member(it);
363 void erase_member(
const MemberIterator& position) {
364 (*position).key.clean();
365 (*position).value.clean();
367 static_cast<void*
>(position.get_inner_iterator()),
368 static_cast<void*
>(position.get_inner_iterator() + 1),
369 static_cast<SizeType
>(this->end_member().get_inner_iterator() - position.get_inner_iterator() - 1) *
sizeof(MemberPair<DataType>)
373 GenericCloveRef get_reference() {
return GenericCloveRef(data_, allocator_); }
374 DataType& get_inner_value() {
return data_; }
378 AllocatorType& allocator_;
382 if (this->data_.list.length >= this->data_.list.capacity) {
383 auto new_capacity = this->data_.list.capacity + (this->data_.list.capacity + 1) / 2;
384 this->data_.list.data =
reinterpret_cast<typename DataType::List::Container
>(
385 allocator_.reallocate(
386 this->data_.list.data,
387 this->data_.list.capacity *
sizeof(DataType),
388 new_capacity *
sizeof(DataType))
390 this->data_.list.capacity = new_capacity;
394 void check_members() {
396 if (this->data_.object.length >= this->data_.object.capacity) {
397 auto new_capacity = this->data_.object.capacity + (this->data_.object.capacity + 1) / 2;
398 this->data_.object.data =
reinterpret_cast<typename DataType::Object::Container
>(
399 allocator_.reallocate(
400 this->data_.object.data,
401 this->data_.object.capacity *
sizeof(DataType),
402 new_capacity *
sizeof(DataType))
404 this->data_.object.capacity = new_capacity;
408 inline void prepare_string(SizeType length) {
410 this->data_.type = TypeFlag::String;
411 this->data_.string.length = length;
412 this->data_.string.data =
reinterpret_cast<char*
>(
413 allocator_.allocate(
sizeof(
char) * (length + 1)));
414 this->data_.string.data[length] =
'\0';
418 if (!AllocatorType::needs_free)
return;
419 switch (data_.type) {
420 case TypeFlag::String:
422 allocator_.free(
const_cast<char*
>(data_.string.data));
425 case TypeFlag::Object:
427 std::for_each(this->begin_member(), this->end_member(), [](
auto item) {
431 allocator_.free(data_.object.data);
436 std::for_each(this->begin_list(), this->end_list(), [](
auto item) { item.clean(); });
437 allocator_.free(data_.list.data);
447 template<GARLIC_ALLOCATOR Allocator,
typename SizeType =
unsigned>
448 class GenericCloveDocument :
public GenericCloveRef<Allocator, SizeType> {
450 using DataType = GenericData<Allocator, SizeType>;
451 using ViewType = GenericCloveView<Allocator, SizeType>;
452 using ReferenceType = GenericCloveRef<Allocator, SizeType>;
453 using DocumentType = GenericCloveDocument<Allocator, SizeType>;
455 explicit GenericCloveDocument(
456 std::shared_ptr<Allocator> allocator
457 ) : allocator_(allocator), ReferenceType(data_, *allocator) {}
458 GenericCloveDocument(
459 ) : allocator_(std::make_shared<Allocator>()), ReferenceType(data_, *allocator_) {}
460 ~GenericCloveDocument() { this->get_reference().set_null(); }
462 Allocator& get_allocator() {
return *allocator_; }
466 std::shared_ptr<Allocator> allocator_;
470 template<GARLIC_ALLOCATOR Allocator,
typename SizeType =
unsigned>
471 class GenericCloveValue :
public GenericCloveRef<Allocator, SizeType> {
473 using DataType = GenericData<Allocator>;
474 using ViewType = GenericCloveView<Allocator>;
475 using ReferenceType = GenericCloveRef<Allocator>;
476 using DocumentType = GenericCloveDocument<Allocator>;
478 explicit GenericCloveValue(
479 DocumentType& root) : ReferenceType(data_, root.get_allocator()) {}
481 explicit GenericCloveValue(
482 Allocator& allocator) : ReferenceType(data_, allocator) {}
483 ~GenericCloveValue() { this->get_reference().set_null(); }
485 DataType&& move_data() {
return std::move(data_); }