41 auto tables =
db.get_tables();
46#include "joedb/Freedom_Keeper.h"
47#include "joedb/error/Exception.h"
48#include "joedb/error/assert.h"
49#include "joedb/get_version.h"
50#include "joedb/hash_combine.h"
62 out <<
"#include \"joedb/Blob.h\"\n";
66 out <<
"#include \"joedb/ui/type_io.h\"\n";
67 out <<
"#include <sstream>\n";
70 if (
options.has_ordered_index())
71 out <<
"#include <map>\n";
73 if (
options.has_unordered_index())
74 out <<
"#include <unordered_map>\n";
76 out <<
"\nstatic_assert(std::string_view(joedb::get_version()) == \"";
88 using joedb::Record_Id;
89 using joedb::Table_Id;
90 using joedb::Field_Id;
94 for (
const auto &[tid, tname]: tables)
95 out <<
" class container_of_" << tname <<
";\n";
99 for (
const auto &index:
options.get_indices())
101 const bool custom_hash = !index.ordered && index.field_ids.size() > 1;
105 const int fields = int(index.field_ids.size());
107 out <<
" struct hash_of_index_of_" << index.name;
109 out <<
" size_t operator()(const ";
111 out <<
"&key) const noexcept\n";
115 for (
int i = 1; i < fields; i++)
117 out <<
"joedb::hash_combine\n";
118 out << std::string(i + 2,
' ') <<
"(\n";
119 out << std::string(i + 3,
' ');
122 for (
int i = fields; --i >= 0;)
134 out <<
">()(std::get<" << i <<
">(key))\n";
135 out << std::string(i + 3,
' ' );
139 out <<
",\n" << std::string(i + 3,
' ');
148 out <<
" using type_of_index_of_" << index.name <<
" = std::";
160 out <<
", id_of_" <<
options.db.get_table_name(index.table_id);
163 out <<
", std::less<>";
164 else if (custom_hash)
165 out <<
", hash_of_index_of_" << index.name;
170 out <<
"\n namespace detail\n {";
171 for (
const auto &[tid, tname]: tables)
173 out <<
"\n struct data_of_" << tname;
176 if (
db.get_freedom(tid).get_used_count() >
Record_Id{0})
177 out <<
" Field_Id current_field_id = Field_Id(0);\n";
179 std::vector<std::string> fields;
181 for (
const auto &[fid, fname]:
db.get_fields(tid))
183 fields.emplace_back(
"field_value_of_" + fname);
187 out <<
" std::vector<";
189 out <<
"> " << fields.back() <<
";\n";
192 for (
const auto &index:
options.get_indices())
194 if (index.table_id == tid)
196 out <<
" std::vector<type_of_index_of_" << index.name;
197 out <<
"::iterator> ";
198 fields.emplace_back(
"iterator_over_" + index.name);
199 out << fields.back() <<
";\n";
204 joedb::Freedom_Keeper freedom_keeper;
206 size_t size() const {return freedom_keeper.size();}
208 void resize(size_t new_size)
212 fields.emplace_back("freedom_keeper");
213 for (
const std::string &field: fields)
214 out <<
" " << field <<
".resize(new_size);\n";
220 for (
const auto &index:
options.get_indices())
222 out <<
" class range_of_" << index.name <<
";\n";
225 out <<
" /// Store all the tables of the database\n";
226 out <<
" class Database\n {\n";
227 out <<
" friend class Readable;\n";
229 for (
const auto &[tid, tname]: tables)
230 out <<
" friend class container_of_" << tname <<
";\n";
232 for (
const auto &index:
options.get_indices())
234 out <<
" friend class range_of_" << index.name <<
";\n";
238 template<typename E = joedb::Exception>
239 static void throw_exception(std::string_view message)
251 for (
const auto &[tid, tname]: tables)
253 out <<
" bool is_valid(id_of_" << tname <<
" id) const {return is_valid_record_id_for_" << tname <<
"(id.get_record_id());}\n";
256 out <<
"\n protected:\n";
258 for (
const auto &[tid, tname]: tables)
260 out <<
" detail::data_of_" << tname <<
" storage_of_" << tname <<
";\n";
262 out <<
" bool is_valid_record_id_for_" << tname;
263 out <<
"(Record_Id record_id) const {return storage_of_" << tname;
264 out <<
".freedom_keeper.is_used(record_id);}\n";
270 if (!
options.get_indices().empty())
273 for (
const auto &index:
options.get_indices())
275 const std::string &tname =
db.get_table_name(index.table_id);
277 out <<
" type_of_index_of_" << index.name;
278 out <<
" index_of_" << index.name <<
";\n";
280 out <<
" void remove_index_of_" << index.name <<
"(Record_Id record_id)\n";
282 out <<
" auto &iterator = storage_of_" << tname;
283 out <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)];\n";
284 out <<
" if (iterator != index_of_" << index.name <<
".end())\n";
286 out <<
" index_of_" << index.name <<
".erase(iterator);\n";
287 out <<
" iterator = index_of_" << index.name <<
".end();\n";
291 out <<
" void add_index_of_" << index.name <<
"(Record_Id record_id)\n";
293 out <<
" auto result = index_of_" << index.name;
294 out <<
".insert\n (\n type_of_index_of_" << index.name;
295 out <<
"::value_type\n (\n ";
298 for (
size_t i = 0; i < index.field_ids.size(); i++)
302 out <<
"storage_of_" << tname <<
".field_value_of_";
303 out <<
db.get_field_name(index.table_id, index.field_ids[i]);
304 out <<
"[to_underlying(record_id)]";
307 out <<
",\n id_of_" << tname <<
"(record_id)\n )\n );\n";
310 out <<
" if (!result.second)\n";
312 out <<
" std::ostringstream out;\n";
313 out <<
" out << \"" << index.name <<
" unique index failure: (\";\n";
314 for (
size_t i = 0; i < index.field_ids.size(); i++)
317 out <<
" out << \", \";\n";
318 const auto type =
db.get_field_type(index.table_id, index.field_ids[i]);
320 out <<
"storage_of_" << tname <<
".field_value_of_";
321 out <<
db.get_field_name(index.table_id, index.field_ids[i]);
322 out <<
"[to_underlying(record_id)]";
324 out <<
".get_record_id()";
327 out <<
" out << \") at id = \" << record_id << ' ';\n";
328 out <<
" out << \"was already at id = \" << result.first->second.get_id();\n";
329 out <<
" throw_exception(out.str());\n";
331 out <<
" storage_of_" << tname <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)] = result.first;\n";
334 out <<
" storage_of_" << tname <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)] = result;\n";
342 for (
const auto &[tid, tname]: tables)
344 out <<
" void internal_delete_" << tname <<
"(Record_Id record_id)\n";
346 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(record_id));\n";
348 for (
const auto &index:
options.get_indices())
349 if (index.table_id == tid)
350 out <<
" remove_index_of_" << index.name <<
"(record_id);\n";
352 for (
const auto &[fid, fname]:
db.get_fields(tid))
354 const Type &type =
db.get_field_type(tid, fid);
356 out <<
" storage_of_" << tname <<
".field_value_of_";
357 out << fname <<
"[to_underlying(record_id)]";
367 out <<
"(joedb::Record_Id::null)";
371 out <<
" = joedb::Blob()";
381 out <<
" storage_of_" << tname <<
".freedom_keeper.free(record_id);\n";
386 for (
const auto &[tid, tname]: tables)
388 out <<
" void internal_insert_" << tname <<
"(Record_Id record_id)\n";
391 for (
const auto &index:
options.get_indices())
392 if (index.table_id == tid)
394 out <<
" storage_of_" << tname;
395 out <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)] = ";
396 out <<
"index_of_" << index.name <<
".end();\n";
399 out <<
" storage_of_" << tname <<
".freedom_keeper.use(record_id);\n";
403 out <<
" void internal_vector_insert_" << tname <<
"(Record_Id record_id, size_t size)\n";
405 out <<
" JOEDB_RELEASE_ASSERT(storage_of_" << tname <<
".freedom_keeper.is_free_vector(record_id, size));\n";
406 out <<
" storage_of_" << tname <<
".freedom_keeper.use_vector(record_id, size);\n";
408 for (
const auto &index:
options.get_indices())
409 if (index.table_id == tid)
411 out <<
" std::fill_n\n";
413 out <<
" &storage_of_" << tname <<
".iterator_over_" << index.name <<
"[to_underlying(record_id)],\n";
415 out <<
" index_of_" << index.name <<
".end()\n";
423 for (
const auto &[tid, tname]: tables)
425 for (
const auto &[fid, fname]:
db.get_fields(tid))
427 const Type &type =
db.get_field_type(tid, fid);
429 out <<
" void internal_update_" << tname <<
"__" << fname;
430 out <<
"\n (\n Record_Id record_id,\n ";
432 out <<
" field_value_of_" << fname <<
"\n )\n";
434 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(record_id));\n";
435 out <<
" storage_of_" << tname <<
".field_value_of_" << fname;
436 out <<
"[to_underlying(record_id)] = field_value_of_" << fname;
439 for (
const auto &index:
options.get_indices())
441 if (index.is_trigger(tid, fid))
443 out <<
" remove_index_of_" << index.name <<
"(record_id);\n";
444 out <<
" add_index_of_" << index.name <<
"(record_id);\n";
450 out <<
" void internal_update_vector_" << tname <<
"__" << fname <<
'\n';
452 out <<
" Record_Id record_id,\n";
453 out <<
" size_t size,\n";
459 out <<
" JOEDB_RELEASE_ASSERT(storage_of_" << tname <<
".freedom_keeper.is_used_vector(record_id, size));\n";
462 out <<
" *target = &storage_of_" << tname;
463 out <<
".field_value_of_" << fname <<
".data()[to_underlying(record_id)];\n";
464 out <<
" if (target != value)\n";
465 out <<
" std::copy_n(value, size, target);\n";
467 for (
const auto &index:
options.get_indices())
469 if (index.is_trigger(tid, fid))
471 out <<
" for (size_t i = 0; i < size; i++)\n";
472 out <<
" remove_index_of_" << index.name <<
"(record_id + i);\n";
473 out <<
" for (size_t i = 0; i < size; i++)\n";
474 out <<
" add_index_of_" << index.name <<
"(record_id + i);\n";
487 for (
const auto &[tid, tname]: tables)
489 const bool single_row =
options.get_table_options(tid).single_row;
496 out <<
" container_of_" << tname <<
" get_" << tname <<
"_table() const;\n\n";
498 out <<
" id_of_" << tname <<
" next(id_of_" << tname <<
" id) const\n";
500 out <<
" return id_of_" << tname <<
"\n (\n Record_Id(storage_of_" << tname <<
".freedom_keeper.get_next(id.get_record_id()))\n );\n";
503 out <<
" id_of_" << tname <<
" previous(id_of_" << tname <<
" id) const\n";
505 out <<
" return id_of_" << tname <<
"\n (\n Record_Id(storage_of_" << tname <<
".freedom_keeper.get_previous(id.get_record_id()))\n );\n";
510 out <<
" template<class Comparator>\n";
511 out <<
" std::vector<id_of_" << tname <<
"> sorted_" << tname;
512 out <<
"(Comparator comparator) const;\n\n";
518 out <<
" static id_of_" << tname <<
" null_" << tname <<
"()\n";
520 out <<
" return id_of_" << tname <<
"();\n";
528 out <<
" static constexpr id_of_" << tname <<
" the_" << tname <<
"()\n";
530 out <<
" return id_of_" << tname <<
"{0};\n";
537 for (
const auto &[fid, fname]:
db.get_fields(tid))
539 const Type &type =
db.get_field_type(tid, fid);
548 out <<
" get_" << fname <<
"(id_of_" << tname <<
" record";
550 out <<
" = id_of_" << tname <<
"{0}";
553 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(record.get_record_id()));\n";
556 out <<
")(storage_of_" << tname;
557 out <<
".field_value_of_" << fname <<
"[record.get_id()]);\n";
565 for (
const auto &index:
options.get_indices())
568 out <<
" const type_of_index_of_" << index.name;
569 out <<
" &get_index_of_" << index.name <<
"()\n";
571 out <<
" return index_of_" << index.name <<
";\n";
578 for (
const auto &index:
options.get_indices())
582 const std::string &tname =
db.get_table_name(index.table_id);
585 out <<
" id_of_" << tname <<
" next_" << index.name <<
'(';
586 out <<
"id_of_" << tname <<
" id) const\n";
588 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(id.get_record_id()));\n";
589 out <<
" auto iterator = storage_of_" << tname <<
".iterator_over_" << index.name <<
"[id.get_id()];\n";
590 out <<
" ++iterator;\n";
591 out <<
" if (iterator != index_of_" << index.name <<
".end())\n";
592 out <<
" return iterator->second;\n";
594 out <<
" return id_of_" << tname <<
"();\n";
599 out <<
" id_of_" << tname <<
" previous_" << index.name <<
'(';
600 out <<
"id_of_" << tname <<
" id) const\n";
602 out <<
" JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname <<
"(id.get_record_id()));\n";
603 out <<
" auto iterator = storage_of_" << tname <<
".iterator_over_" << index.name <<
"[id.get_id()];\n";
604 out <<
" if (iterator != index_of_" << index.name <<
".begin())\n";
605 out <<
" return (--iterator)->second;\n";
607 out <<
" return id_of_" << tname <<
"();\n";
611 out <<
" id_of_" << tname <<
" find_" << index.name <<
'(';
612 write_index_parameters(out, index);
615 out <<
" const auto i = index_of_" << index.name <<
".find(";
618 for (
size_t i = 0; i < index.field_ids.size(); i++)
622 out <<
"field_value_of_";
623 out <<
db.get_field_name(index.table_id, index.field_ids[i]);
626 out <<
" if (i == index_of_" << index.name <<
".end())\n";
627 out <<
" return id_of_" << tname <<
"();\n";
629 out <<
" return i->second;\n";
634 out <<
" range_of_" << index.name <<
" find_" << index.name <<
'(';
635 write_index_parameters(out, index);
645 for (
const auto &[tid, tname]: tables)
647 const bool single_row =
options.get_table_options(tid).single_row;
649 out <<
" /// returned by @ref Database::get_" << tname <<
"_table\n";
650 out <<
" class container_of_" << tname <<
"\n";
652 out <<
" friend class Database;\n";
654 out <<
" private:\n";
655 out <<
" const Database &db;\n";
656 out <<
" container_of_" << tname <<
"(const Database &db): db(db) {}\n";
659 out <<
" class iterator\n";
661 out <<
" friend class container_of_" << tname <<
";\n";
662 out <<
" private:\n";
665 out <<
" const joedb::Freedom_Keeper *fk;\n";
666 out <<
" Record_Id index;\n";
667 out <<
" iterator(const detail::data_of_" << tname <<
" &data): fk(&data.freedom_keeper), index(joedb::Freedom_Keeper_Constants::used_list) {}\n";
669 out <<
" using iterator_category = std::forward_iterator_tag;\n";
670 out <<
" using value_type = id_of_" << tname <<
";\n";
671 out <<
" using difference_type = std::ptrdiff_t;\n";
672 out <<
" using pointer = value_type*;\n";
673 out <<
" using reference = value_type&;\n";
675 out <<
" bool operator==(const iterator &i) const {return index == i.index;}\n";
676 out <<
" bool operator!=(const iterator &i) const {return index != i.index;}\n";
677 out <<
" iterator &operator++() {index = fk->get_next(index); return *this;}\n";
678 out <<
" iterator operator++(int) {auto copy = *this; index = fk->get_next(index); return copy;}\n";
679 out <<
" iterator &operator--() {index = fk->get_previous(index); return *this;}\n";
680 out <<
" iterator operator--(int) {auto copy = *this; index = fk->get_previous(index); return copy;}\n";
681 out <<
" id_of_" << tname <<
" operator*() const {return id_of_";
682 out << tname <<
"(Record_Id(index));}\n";
685 out <<
" iterator begin() const {return ++iterator(db.storage_of_" << tname <<
");}\n";
686 out <<
" iterator end() const {return iterator(db.storage_of_" << tname <<
");}\n";
687 out <<
" bool is_empty() const {return db.storage_of_" << tname
688 <<
".freedom_keeper.get_used_count() == Record_Id{0};}\n";
689 out <<
" joedb::index_t get_size() const {return to_underlying(db.storage_of_" << tname <<
".freedom_keeper.get_used_count());}\n";
690 out <<
" static id_of_" << tname <<
" get_at(size_t i) {return id_of_"
691 << tname <<
"(Record_Id(i));}\n";
692 out <<
" bool is_valid_at(size_t i) {return db.storage_of_" << tname <<
".freedom_keeper.is_used(Record_Id(i));}\n";
694 out <<
" id_of_" << tname <<
" first() const {return *begin();}\n";
695 out <<
" id_of_" << tname <<
" last() const {return *--end();}\n";
696 out <<
" id_of_" << tname <<
" get_end() const {return *end();}\n";
701 out <<
" inline container_of_" << tname <<
" Database::get_" << tname <<
"_table() const\n";
703 out <<
" return container_of_" << tname <<
"(*this);\n";
709 out <<
" template<class Comparator>\n";
710 out <<
" std::vector<id_of_" << tname <<
"> Database::sorted_" << tname;
711 out <<
"(Comparator comparator) const\n";
713 out <<
" std::vector<id_of_" << tname <<
"> result;\n";
714 out <<
" for (auto x: get_" << tname <<
"_table())\n";
715 out <<
" result.emplace_back(x);\n";
716 out <<
" std::sort(result.begin(), result.end(), comparator);\n";
717 out <<
" return result;\n";
725 for (
const auto &index:
options.get_indices())
729 out <<
" /// returned by @ref Database::find_" << index.name <<
'\n';
730 out <<
" class range_of_" << index.name <<
"\n";
732 out <<
" friend class Database;\n";
733 out <<
" private:\n";
734 out <<
" std::pair<type_of_index_of_" << index.name;
735 out <<
"::const_iterator, type_of_index_of_" << index.name;
736 out <<
"::const_iterator> range;\n";
737 out <<
" range_of_" << index.name <<
"(const Database &db";
738 for (
size_t i = 0; i < index.field_ids.size(); i++)
741 const Type &type =
db.get_field_type(index.table_id, index.field_ids[i]);
743 out <<
' ' <<
db.get_field_name(index.table_id, index.field_ids[i]);
747 out <<
" range = db.index_of_" << index.name <<
".equal_range(";
750 for (
size_t i = 0; i < index.field_ids.size(); i++)
754 out <<
db.get_field_name(index.table_id, index.field_ids[i]);
759 out <<
" class iterator\n";
761 out <<
" friend class range_of_" << index.name <<
";\n";