27#include "joedb/Freedom_Keeper.h"
28#include "joedb/error/Exception.h"
29#include "joedb/error/assert.h"
30#include "joedb/get_version.h"
31#include "joedb/hash_combine.h"
43 out <<
"#include \"joedb/Blob.h\"\n";
47 out <<
"#include \"joedb/ui/type_io.h\"\n";
48 out <<
"#include <sstream>\n";
52 out <<
"#include <map>\n";
55 out <<
"#include <unordered_map>\n";
57 out <<
"\nstatic_assert(std::string_view(joedb::get_version()) == \"";
69 using joedb::Record_Id;
70 using joedb::Table_Id;
71 using joedb::Field_Id;
75 for (
const auto &[tid, tname]: tables)
76 out <<
" class container_of_" << tname <<
";\n";
82 const bool custom_hash = !index.ordered && index.field_ids.size() > 1;
86 const int fields = int(index.field_ids.size());
88 out <<
" struct hash_of_index_of_" << index.name;
90 out <<
" size_t operator()(const ";
92 out <<
"&key) const noexcept\n";
96 for (
int i = 1; i < fields; i++)
98 out <<
"joedb::hash_combine\n";
99 out << std::string(i + 2,
' ') <<
"(\n";
100 out << std::string(i + 3,
' ');
103 for (
int i = fields; --i >= 0;)
115 out <<
">()(std::get<" << i <<
">(key))\n";
116 out << std::string(i + 3,
' ' );
120 out <<
",\n" << std::string(i + 3,
' ');
129 out <<
" using type_of_index_of_" << index.name <<
" = std::";
144 out <<
", std::less<>";
145 else if (custom_hash)
146 out <<
", hash_of_index_of_" << index.name;
151 out <<
"\n namespace detail\n {";
152 for (
const auto &[tid, tname]: tables)
154 out <<
"\n struct data_of_" << tname;
158 out <<
" Field_Id current_field_id = Field_Id(0);\n";
160 std::vector<std::string> fields;
162 for (
const auto &[fid, fname]: db.
get_fields(tid))
164 fields.emplace_back(
"field_value_of_" + fname);
168 out <<
" std::vector<";
170 out <<
"> " << fields.back() <<
";\n";
175 if (index.table_id == tid)
177 out <<
" std::vector<type_of_index_of_" << index.name;
178 out <<
"::iterator> ";
179 fields.emplace_back(
"iterator_over_" + index.name);
180 out << fields.back() <<
";\n";
185 joedb::Freedom_Keeper freedom_keeper;
187 size_t size() const {return freedom_keeper.size();}
189 void resize(size_t new_size)
193 fields.emplace_back("freedom_keeper");
194 for (
const std::string &field: fields)
195 out <<
" " << field <<
".resize(new_size);\n";
203 out <<
" class range_of_" << index.name <<
";\n";
206 out <<
" /// Store all the tables of the database\n";
207 out <<
" class Database\n {\n";
208 out <<
" friend class Readable;\n";
210 for (
const auto &[tid, tname]: tables)
211 out <<
" friend class container_of_" << tname <<
";\n";
215 out <<
" friend class range_of_" << index.name <<
";\n";
219 template<typename E = joedb::Exception>
220 static void throw_exception(std::string_view message)
232 for (
const auto &[tid, tname]: tables)
234 out <<
" bool is_valid(id_of_" << tname <<
" id) const {return is_valid_record_id_for_" << tname <<
"(id.get_record_id());}\n";
237 out <<
"\n protected:\n";
239 for (
const auto &[tid, tname]: tables)
241 out <<
" detail::data_of_" << tname <<
" storage_of_" << tname <<
";\n";
243 out <<
" bool is_valid_record_id_for_" << tname;
244 out <<
"(Record_Id record_id) const {return storage_of_" << tname;
245 out <<
".freedom_keeper.is_used(record_id);}\n";
258 out <<
" type_of_index_of_" << index.name;
259 out <<
" index_of_" << index.name <<
";\n";
261 out <<
" void remove_index_of_" << index.name <<
"(Record_Id record_id)\n";
263 out <<
" auto &iterator = storage_of_" << tname;
264 out <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)];\n";
265 out <<
" if (iterator != index_of_" << index.name <<
".end())\n";
267 out <<
" index_of_" << index.name <<
".erase(iterator);\n";
268 out <<
" iterator = index_of_" << index.name <<
".end();\n";
272 out <<
" void add_index_of_" << index.name <<
"(Record_Id record_id)\n";
274 out <<
" auto result = index_of_" << index.name;
275 out <<
".insert\n (\n type_of_index_of_" << index.name;
276 out <<
"::value_type\n (\n ";
279 for (
size_t i = 0; i < index.field_ids.size(); i++)
283 out <<
"storage_of_" << tname <<
".field_value_of_";
285 out <<
"[to_underlying(record_id)]";
288 out <<
",\n id_of_" << tname <<
"(record_id)\n )\n );\n";
291 out <<
" if (!result.second)\n";
293 out <<
" std::ostringstream out;\n";
294 out <<
" out << \"" << index.name <<
" unique index failure: (\";\n";
295 for (
size_t i = 0; i < index.field_ids.size(); i++)
298 out <<
" out << \", \";\n";
299 const auto type = db.
get_field_type(index.table_id, index.field_ids[i]);
301 out <<
"storage_of_" << tname <<
".field_value_of_";
303 out <<
"[to_underlying(record_id)]";
304 if (type.get_type_id() == joedb::Type::Type_Id::reference)
305 out <<
".get_record_id()";
308 out <<
" out << \") at id = \" << record_id << ' ';\n";
309 out <<
" out << \"was already at id = \" << result.first->second.get_id();\n";
310 out <<
" throw_exception(out.str());\n";
312 out <<
" storage_of_" << tname <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)] = result.first;\n";
315 out <<
" storage_of_" << tname <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)] = result;\n";
323 for (
const auto &[tid, tname]: tables)
325 out <<
" void internal_delete_" << tname <<
"(Record_Id record_id)\n";
327 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(record_id));\n";
330 if (index.table_id == tid)
331 out <<
" remove_index_of_" << index.name <<
"(record_id);\n";
333 for (
const auto &[fid, fname]: db.
get_fields(tid))
337 out <<
" storage_of_" << tname <<
".field_value_of_";
338 out << fname <<
"[to_underlying(record_id)]";
344 else if (type.
get_type_id() == Type::Type_Id::reference)
348 out <<
"(joedb::Record_Id::null)";
350 else if (type.
get_type_id() == Type::Type_Id::blob)
352 out <<
" = joedb::Blob()";
362 out <<
" storage_of_" << tname <<
".freedom_keeper.free(record_id);\n";
367 for (
const auto &[tid, tname]: tables)
369 out <<
" void internal_insert_" << tname <<
"(Record_Id record_id)\n";
373 if (index.table_id == tid)
375 out <<
" storage_of_" << tname;
376 out <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)] = ";
377 out <<
"index_of_" << index.name <<
".end();\n";
380 out <<
" storage_of_" << tname <<
".freedom_keeper.use(record_id);\n";
384 out <<
" void internal_vector_insert_" << tname <<
"(Record_Id record_id, size_t size)\n";
386 out <<
" JOEDB_RELEASE_ASSERT(storage_of_" << tname <<
".freedom_keeper.is_free_vector(record_id, size));\n";
387 out <<
" storage_of_" << tname <<
".freedom_keeper.use_vector(record_id, size);\n";
390 if (index.table_id == tid)
392 out <<
" std::fill_n\n";
394 out <<
" &storage_of_" << tname <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)],\n";
396 out <<
" index_of_" << index.name <<
".end()\n";
404 for (
const auto &[tid, tname]: tables)
406 for (
const auto &[fid, fname]: db.
get_fields(tid))
410 out <<
" void internal_update_" << tname <<
"__" << fname;
411 out <<
"\n (\n Record_Id record_id,\n ";
413 out <<
" field_value_of_" << fname <<
"\n )\n";
415 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(record_id));\n";
416 out <<
" storage_of_" << tname <<
".field_value_of_" << fname;
417 out <<
"[to_underlying(record_id)] = field_value_of_" << fname;
422 if (index.is_trigger(tid, fid))
424 out <<
" remove_index_of_" << index.name <<
"(record_id);\n";
425 out <<
" add_index_of_" << index.name <<
"(record_id);\n";
431 out <<
" void internal_update_vector_" << tname <<
"__" << fname <<
'\n';
433 out <<
" Record_Id record_id,\n";
434 out <<
" size_t size,\n";
440 out <<
" JOEDB_RELEASE_ASSERT(storage_of_" << tname <<
".freedom_keeper.is_used_vector(record_id, size));\n";
443 out <<
" *target = &storage_of_" << tname;
444 out <<
".field_value_of_" << fname <<
".data()[to_underlying(record_id)];\n";
445 out <<
" if (target != value)\n";
446 out <<
" std::copy_n(value, size, target);\n";
450 if (index.is_trigger(tid, fid))
452 out <<
" for (size_t i = 0; i < size; i++)\n";
453 out <<
" remove_index_of_" << index.name <<
"(record_id + i);\n";
454 out <<
" for (size_t i = 0; i < size; i++)\n";
455 out <<
" add_index_of_" << index.name <<
"(record_id + i);\n";
468 for (
const auto &[tid, tname]: tables)
477 out <<
" container_of_" << tname <<
" get_" << tname <<
"_table() const;\n\n";
479 out <<
" id_of_" << tname <<
" next(id_of_" << tname <<
" id) const\n";
481 out <<
" return id_of_" << tname <<
"\n (\n Record_Id(storage_of_" << tname <<
".freedom_keeper.get_next(id.get_record_id()))\n );\n";
484 out <<
" id_of_" << tname <<
" previous(id_of_" << tname <<
" id) const\n";
486 out <<
" return id_of_" << tname <<
"\n (\n Record_Id(storage_of_" << tname <<
".freedom_keeper.get_previous(id.get_record_id()))\n );\n";
491 out <<
" template<class Comparator>\n";
492 out <<
" std::vector<id_of_" << tname <<
"> sorted_" << tname;
493 out <<
"(Comparator comparator) const;\n\n";
499 out <<
" static id_of_" << tname <<
" null_" << tname <<
"()\n";
501 out <<
" return id_of_" << tname <<
"();\n";
509 out <<
" static constexpr id_of_" << tname <<
" the_" << tname <<
"()\n";
511 out <<
" return id_of_" << tname <<
"{0};\n";
518 for (
const auto &[fid, fname]: db.
get_fields(tid))
529 out <<
" get_" << fname <<
"(id_of_" << tname <<
" record";
531 out <<
" = id_of_" << tname <<
"{0}";
534 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(record.get_record_id()));\n";
537 out <<
")(storage_of_" << tname;
538 out <<
".field_value_of_" << fname <<
"[record.get_id()]);\n";
549 out <<
" const type_of_index_of_" << index.name;
550 out <<
" &get_index_of_" << index.name <<
"()\n";
552 out <<
" return index_of_" << index.name <<
";\n";
566 out <<
" id_of_" << tname <<
" next_" << index.name <<
'(';
567 out <<
"id_of_" << tname <<
" id) const\n";
569 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(id.get_record_id()));\n";
570 out <<
" auto iterator = storage_of_" << tname <<
".iterator_over_" << index.name <<
"[id.get_id()];\n";
571 out <<
" ++iterator;\n";
572 out <<
" if (iterator != index_of_" << index.name <<
".end())\n";
573 out <<
" return iterator->second;\n";
575 out <<
" return id_of_" << tname <<
"();\n";
580 out <<
" id_of_" << tname <<
" previous_" << index.name <<
'(';
581 out <<
"id_of_" << tname <<
" id) const\n";
583 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(id.get_record_id()));\n";
584 out <<
" auto iterator = storage_of_" << tname <<
".iterator_over_" << index.name <<
"[id.get_id()];\n";
585 out <<
" if (iterator != index_of_" << index.name <<
".begin())\n";
586 out <<
" return (--iterator)->second;\n";
588 out <<
" return id_of_" << tname <<
"();\n";
592 out <<
" id_of_" << tname <<
" find_" << index.name <<
'(';
593 for (
size_t i = 0; i < index.field_ids.size(); i++)
599 out <<
" field_value_of_";
604 out <<
" const auto i = index_of_" << index.name <<
".find(";
607 for (
size_t i = 0; i < index.field_ids.size(); i++)
611 out <<
"field_value_of_";
615 out <<
" if (i == index_of_" << index.name <<
".end())\n";
616 out <<
" return id_of_" << tname <<
"();\n";
618 out <<
" return i->second;\n";
623 out <<
" range_of_" << index.name <<
" find_" << index.name <<
'(';
624 for (
size_t i = 0; i < index.field_ids.size(); i++)
630 out <<
" field_value_of_";
642 for (
const auto &[tid, tname]: tables)
646 out <<
" /// returned by @ref Database::get_" << tname <<
"_table\n";
647 out <<
" class container_of_" << tname <<
"\n";
649 out <<
" friend class Database;\n";
651 out <<
" private:\n";
652 out <<
" const Database &db;\n";
653 out <<
" container_of_" << tname <<
"(const Database &db): db(db) {}\n";
656 out <<
" class iterator\n";
658 out <<
" friend class container_of_" << tname <<
";\n";
659 out <<
" private:\n";
662 out <<
" const joedb::Freedom_Keeper *fk;\n";
663 out <<
" Record_Id index;\n";
664 out <<
" iterator(const detail::data_of_" << tname <<
" &data): fk(&data.freedom_keeper), index(joedb::Freedom_Keeper_Constants::used_list) {}\n";
666 out <<
" using iterator_category = std::forward_iterator_tag;\n";
667 out <<
" using value_type = id_of_" << tname <<
";\n";
668 out <<
" using difference_type = std::ptrdiff_t;\n";
669 out <<
" using pointer = value_type*;\n";
670 out <<
" using reference = value_type&;\n";
672 out <<
" bool operator==(const iterator &i) const {return index == i.index;}\n";
673 out <<
" bool operator!=(const iterator &i) const {return index != i.index;}\n";
674 out <<
" iterator &operator++() {index = fk->get_next(index); return *this;}\n";
675 out <<
" iterator operator++(int) {auto copy = *this; index = fk->get_next(index); return copy;}\n";
676 out <<
" iterator &operator--() {index = fk->get_previous(index); return *this;}\n";
677 out <<
" iterator operator--(int) {auto copy = *this; index = fk->get_previous(index); return copy;}\n";
678 out <<
" id_of_" << tname <<
" operator*() const {return id_of_";
679 out << tname <<
"(Record_Id(index));}\n";
682 out <<
" iterator begin() const {return ++iterator(db.storage_of_" << tname <<
");}\n";
683 out <<
" iterator end() const {return iterator(db.storage_of_" << tname <<
");}\n";
684 out <<
" bool is_empty() const {return db.storage_of_" << tname
685 <<
".freedom_keeper.get_used_count() == Record_Id{0};}\n";
686 out <<
" joedb::index_t get_size() const {return to_underlying(db.storage_of_" << tname <<
".freedom_keeper.get_used_count());}\n";
687 out <<
" static id_of_" << tname <<
" get_at(size_t i) {return id_of_"
688 << tname <<
"(Record_Id(i));}\n";
689 out <<
" bool is_valid_at(size_t i) {return db.storage_of_" << tname <<
".freedom_keeper.is_used(Record_Id(i));}\n";
691 out <<
" id_of_" << tname <<
" first() const {return *begin();}\n";
692 out <<
" id_of_" << tname <<
" last() const {return *--end();}\n";
693 out <<
" id_of_" << tname <<
" get_end() const {return *end();}\n";
698 out <<
" inline container_of_" << tname <<
" Database::get_" << tname <<
"_table() const\n";
700 out <<
" return container_of_" << tname <<
"(*this);\n";
706 out <<
" template<class Comparator>\n";
707 out <<
" std::vector<id_of_" << tname <<
"> Database::sorted_" << tname;
708 out <<
"(Comparator comparator) const\n";
710 out <<
" std::vector<id_of_" << tname <<
"> result;\n";
711 out <<
" for (auto x: get_" << tname <<
"_table())\n";
712 out <<
" result.emplace_back(x);\n";
713 out <<
" std::sort(result.begin(), result.end(), comparator);\n";
714 out <<
" return result;\n";
726 out <<
" /// returned by @ref Database::find_" << index.name <<
'\n';
727 out <<
" class range_of_" << index.name <<
"\n";
729 out <<
" friend class Database;\n";
730 out <<
" private:\n";
731 out <<
" std::pair<type_of_index_of_" << index.name;
732 out <<
"::const_iterator, type_of_index_of_" << index.name;
733 out <<
"::const_iterator> range;\n";
734 out <<
" range_of_" << index.name <<
"(const Database &db";
735 for (
size_t i = 0; i < index.field_ids.size(); i++)
740 out <<
' ' << db.
get_field_name(index.table_id, index.field_ids[i]);
744 out <<
" range = db.index_of_" << index.name <<
".equal_range(";
747 for (
size_t i = 0; i < index.field_ids.size(); i++)
756 out <<
" class iterator\n";
758 out <<
" friend class range_of_" << index.name <<
";\n";
759 out <<
" private:\n";
760 out <<
" type_of_index_of_" << index.name;
761 out <<
"::const_iterator map_iterator;\n";
762 out <<
" iterator(type_of_index_of_" << index.name;
763 out <<
"::const_iterator map_iterator): map_iterator(map_iterator) {}\n"
765 <<
" bool operator !=(const iterator &i) const\n"