Joedb 10.4.3
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Database_h.cpp
Go to the documentation of this file.
3#include "joedb/get_version.h"
4
5namespace joedb::generator
6{
7 ////////////////////////////////////////////////////////////////////////////
9 ////////////////////////////////////////////////////////////////////////////
10 (
11 const Compiler_Options &options
12 ):
13 Generator(".", "Database.h", options)
14 {
15 }
16
17 ////////////////////////////////////////////////////////////////////////////
18 void Database_h::write(std::ostream &out)
19 ////////////////////////////////////////////////////////////////////////////
20 {
21 const Database_Schema &db = options.get_db();
22 auto tables = db.get_tables();
23
25
26 out << R"RRR(
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"
32#include "ids.h"
33
34#include <string>
35#include <cstring>
36#include <vector>
37#include <algorithm>
38#include <string_view>
39
40)RRR";
41
42 if (options.has_blob())
43 out << "#include \"joedb/Blob.h\"\n";
44
46 {
47 out << "#include \"joedb/ui/type_io.h\"\n";
48 out << "#include <sstream>\n";
49 }
50
52 out << "#include <map>\n";
53
55 out << "#include <unordered_map>\n";
56
57 out << "\nstatic_assert(std::string_view(joedb::get_version()) == \"";
58 out << joedb::get_version() << "\");\n\n";
59
61
62 out << "\n /// @namespace " << namespace_string(options.get_name_space());
63 out << R"RRR(
64 ///
65 /// Automatically generated by joedbc
66)RRR";
67
68 out << R"RRR(
69 using joedb::Record_Id;
70 using joedb::Table_Id;
71 using joedb::Field_Id;
72
73)RRR";
74
75 for (const auto &[tid, tname]: tables)
76 out << " class container_of_" << tname << ";\n";
77
78 out << '\n';
79
80 for (const auto &index: options.get_indices())
81 {
82 const bool custom_hash = !index.ordered && index.field_ids.size() > 1;
83
84 if (custom_hash)
85 {
86 const int fields = int(index.field_ids.size());
87
88 out << " struct hash_of_index_of_" << index.name;
89 out << "\n {\n";
90 out << " size_t operator()(const ";
91 write_tuple_type(out, index, false);
92 out << "&key) const noexcept\n";
93 out << " {\n";
94 out << " return ";
95
96 for (int i = 1; i < fields; i++)
97 {
98 out << "joedb::hash_combine\n";
99 out << std::string(i + 2, ' ') << "(\n";
100 out << std::string(i + 3, ' ');
101 }
102
103 for (int i = fields; --i >= 0;)
104 {
105 out << "std::hash<";
106
107 const Type &type = options.db.get_field_type
108 (
109 index.table_id,
110 index.field_ids[i]
111 );
112
113 write_type(out, type, false, false);
114
115 out << ">()(std::get<" << i << ">(key))\n";
116 out << std::string(i + 3, ' ' );
117 if (i < fields - 1)
118 out << ')';
119 if (i > 0)
120 out << ",\n" << std::string(i + 3, ' ');
121 }
122
123 out << ";\n";
124
125 out << " }\n";
126 out << " };\n";
127 }
128
129 out << " using type_of_index_of_" << index.name << " = std::";
130
131 if (!index.ordered)
132 out << "unordered_";
133
134 if (!index.unique)
135 out << "multi";
136
137 out << "map<";
138
139 write_tuple_type(out, index, false);
140
141 out << ", id_of_" << options.db.get_table_name(index.table_id);
142
143 if (index.ordered)
144 out << ", std::less<>";
145 else if (custom_hash)
146 out << ", hash_of_index_of_" << index.name;
147
148 out << ">;\n";
149 }
150
151 out << "\n namespace detail\n {";
152 for (const auto &[tid, tname]: tables)
153 {
154 out << "\n struct data_of_" << tname;
155
156 out <<"\n {\n";
157 if (db.get_freedom(tid).get_used_count() > Record_Id{0})
158 out <<" Field_Id current_field_id = Field_Id(0);\n";
159
160 std::vector<std::string> fields;
161
162 for (const auto &[fid, fname]: db.get_fields(tid))
163 {
164 fields.emplace_back("field_value_of_" + fname);
165
166 const joedb::Type &type = db.get_field_type(tid, fid);
167
168 out << " std::vector<";
169 write_type(out, type, false, false);
170 out << "> " << fields.back() << ";\n";
171 }
172
173 for (const auto &index: options.get_indices())
174 {
175 if (index.table_id == tid)
176 {
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";
181 }
182 }
183
184 out << R"RRR(
185 joedb::Freedom_Keeper freedom_keeper;
186
187 size_t size() const {return freedom_keeper.size();}
188
189 void resize(size_t new_size)
190 {
191)RRR";
192
193 fields.emplace_back("freedom_keeper");
194 for (const std::string &field: fields)
195 out << " " << field << ".resize(new_size);\n";
196
197 out << " }\n };\n";
198 }
199 out << " }\n\n";
200
201 for (const auto &index: options.get_indices())
202 if (!index.unique)
203 out << " class range_of_" << index.name << ";\n";
204 out << '\n';
205
206 out << " /// Store all the tables of the database\n";
207 out << " class Database\n {\n";
208 out << " friend class Readable;\n";
209
210 for (const auto &[tid, tname]: tables)
211 out << " friend class container_of_" << tname << ";\n";
212
213 for (const auto &index: options.get_indices())
214 if (!index.unique)
215 out << " friend class range_of_" << index.name << ";\n";
216
217 out << R"RRR(
218 public:
219 template<typename E = joedb::Exception>
220 static void throw_exception(std::string_view message)
221 {
222 std::string s(")RRR" << namespace_string(options.get_name_space()) << R"RRR(: ");
223 s += message;
224 throw E(s);
225 }
226
227)RRR";
228
229 //
230 // Validity checks
231 //
232 for (const auto &[tid, tname]: tables)
233 {
234 out << " bool is_valid(id_of_" << tname << " id) const {return is_valid_record_id_for_" << tname << "(id.get_record_id());}\n";
235 }
236
237 out << "\n protected:\n";
238
239 for (const auto &[tid, tname]: tables)
240 {
241 out << " detail::data_of_" << tname << " storage_of_" << tname << ";\n";
242
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";
246 }
247
248 //
249 // Indices
250 //
251 if (!options.get_indices().empty())
252 out << '\n';
253
254 for (const auto &index: options.get_indices())
255 {
256 const std::string &tname = db.get_table_name(index.table_id);
257
258 out << " type_of_index_of_" << index.name;
259 out << " index_of_" << index.name << ";\n";
260
261 out << " void remove_index_of_" << index.name << "(Record_Id record_id)\n";
262 out << " {\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";
266 out << " {\n";
267 out << " index_of_" << index.name << ".erase(iterator);\n";
268 out << " iterator = index_of_" << index.name << ".end();\n";
269 out << " }\n";
270 out << " }\n";
271
272 out << " void add_index_of_" << index.name << "(Record_Id record_id)\n";
273 out << " {\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 ";
277 write_tuple_type(out, index, true);
278 out << '(';
279 for (size_t i = 0; i < index.field_ids.size(); i++)
280 {
281 if (i > 0)
282 out << ", ";
283 out << "storage_of_" << tname << ".field_value_of_";
284 out << db.get_field_name(index.table_id, index.field_ids[i]);
285 out << "[to_underlying(record_id)]";
286 }
287 out << ')';
288 out << ",\n id_of_" << tname << "(record_id)\n )\n );\n";
289 if (index.unique)
290 {
291 out << " if (!result.second)\n";
292 out << " {\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++)
296 {
297 if (i > 0)
298 out << " out << \", \";\n";
299 const auto type = db.get_field_type(index.table_id, index.field_ids[i]);
300 out << " joedb::write_" << get_type_string(type) << "(out, ";
301 out << "storage_of_" << tname << ".field_value_of_";
302 out << db.get_field_name(index.table_id, index.field_ids[i]);
303 out << "[to_underlying(record_id)]";
304 if (type.get_type_id() == joedb::Type::Type_Id::reference)
305 out << ".get_record_id()";
306 out << ");\n";
307 }
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";
311 out << " }\n";
312 out << " storage_of_" << tname << ".iterator_over_" << index.name << "[to_underlying(record_id)] = result.first;\n";
313 }
314 else
315 out << " storage_of_" << tname << ".iterator_over_" << index.name << "[to_underlying(record_id)] = result;\n";
316 out << " }\n";
317 }
318
319 //
320 // Internal data-modification functions
321 //
322 out << '\n';
323 for (const auto &[tid, tname]: tables)
324 {
325 out << " void internal_delete_" << tname << "(Record_Id record_id)\n";
326 out << " {\n";
327 out << " JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname << "(record_id));\n";
328
329 for (const auto &index: options.get_indices())
330 if (index.table_id == tid)
331 out << " remove_index_of_" << index.name << "(record_id);\n";
332
333 for (const auto &[fid, fname]: db.get_fields(tid))
334 {
335 const Type &type = db.get_field_type(tid, fid);
336
337 out << " storage_of_" << tname << ".field_value_of_";
338 out << fname << "[to_underlying(record_id)]";
339
340 if (type.get_type_id() == Type::Type_Id::string)
341 {
342 out << ".clear()";
343 }
344 else if (type.get_type_id() == Type::Type_Id::reference)
345 {
346 out << " = ";
347 write_type(out, type, false, false);
348 out << "(joedb::Record_Id::null)";
349 }
350 else if (type.get_type_id() == Type::Type_Id::blob)
351 {
352 out << " = joedb::Blob()";
353 }
354 else
355 {
356 out << " = 0";
357 }
358
359 out << ";\n";
360 }
361
362 out << " storage_of_" << tname << ".freedom_keeper.free(record_id);\n";
363 out << " }\n";
364 }
365
366 out << '\n';
367 for (const auto &[tid, tname]: tables)
368 {
369 out << " void internal_insert_" << tname << "(Record_Id record_id)\n";
370 out << " {\n";
371
372 for (const auto &index: options.get_indices())
373 if (index.table_id == tid)
374 {
375 out << " storage_of_" << tname;
376 out << ".iterator_over_" << index.name << "[to_underlying(record_id)] = ";
377 out << "index_of_" << index.name << ".end();\n";
378 }
379
380 out << " storage_of_" << tname << ".freedom_keeper.use(record_id);\n";
381
382 out << " }\n\n";
383
384 out << " void internal_vector_insert_" << tname << "(Record_Id record_id, size_t size)\n";
385 out << " {\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";
388
389 for (const auto &index: options.get_indices())
390 if (index.table_id == tid)
391 {
392 out << " std::fill_n\n";
393 out << " (\n";
394 out << " &storage_of_" << tname << ".iterator_over_" << index.name << "[to_underlying(record_id)],\n";
395 out << " size,\n";
396 out << " index_of_" << index.name << ".end()\n";
397 out << " );\n";
398 }
399
400 out << " }\n";
401 }
402
403 out << '\n';
404 for (const auto &[tid, tname]: tables)
405 {
406 for (const auto &[fid, fname]: db.get_fields(tid))
407 {
408 const Type &type = db.get_field_type(tid, fid);
409
410 out << " void internal_update_" << tname << "__" << fname;
411 out << "\n (\n Record_Id record_id,\n ";
412 write_type(out, type, false, true);
413 out << " field_value_of_" << fname << "\n )\n";
414 out << " {\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;
418 out << ";\n";
419
420 for (const auto &index: options.get_indices())
421 {
422 if (index.is_trigger(tid, fid))
423 {
424 out << " remove_index_of_" << index.name << "(record_id);\n";
425 out << " add_index_of_" << index.name << "(record_id);\n";
426 }
427 }
428
429 out << " }\n\n";
430
431 out << " void internal_update_vector_" << tname << "__" << fname << '\n';
432 out << " (\n";
433 out << " Record_Id record_id,\n";
434 out << " size_t size,\n";
435 out << " const ";
436 write_type(out, type, false, false);
437 out << " *value\n";
438 out << " )\n";
439 out << " {\n";
440 out << " JOEDB_RELEASE_ASSERT(storage_of_" << tname << ".freedom_keeper.is_used_vector(record_id, size));\n";
441 out << " ";
442 write_type(out, type, false, false);
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";
447
448 for (const auto &index: options.get_indices())
449 {
450 if (index.is_trigger(tid, fid))
451 {
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";
456 }
457 }
458
459 out << " }\n\n";
460 }
461 }
462
463 //
464 // Public stuff
465 //
466 out << " public:";
467
468 for (const auto &[tid, tname]: tables)
469 {
470 const bool single_row = options.get_table_options(tid).single_row;
471
472 out << '\n';
473
474 //
475 // Declaration of container access
476 //
477 out << " container_of_" << tname << " get_" << tname << "_table() const;\n\n";
478
479 out << " id_of_" << tname << " next(id_of_" << tname << " id) const\n";
480 out << " {\n";
481 out << " return id_of_" << tname << "\n (\n Record_Id(storage_of_" << tname << ".freedom_keeper.get_next(id.get_record_id()))\n );\n";
482 out << " }\n\n";
483
484 out << " id_of_" << tname << " previous(id_of_" << tname << " id) const\n";
485 out << " {\n";
486 out << " return id_of_" << tname << "\n (\n Record_Id(storage_of_" << tname << ".freedom_keeper.get_previous(id.get_record_id()))\n );\n";
487 out << " }\n\n";
488
489 if (!single_row)
490 {
491 out << " template<class Comparator>\n";
492 out << " std::vector<id_of_" << tname << "> sorted_" << tname;
493 out << "(Comparator comparator) const;\n\n";
494 }
495
496 //
497 // Easy access to null
498 //
499 out << " static id_of_" << tname << " null_" << tname << "()\n";
500 out << " {\n";
501 out << " return id_of_" << tname << "();\n";
502 out << " }\n";
503
504 //
505 // the_<table>
506 //
507 if (single_row)
508 {
509 out << " static constexpr id_of_" << tname << " the_" << tname << "()\n";
510 out << " {\n";
511 out << " return id_of_" << tname << "{0};\n";
512 out << " }\n";
513 }
514
515 //
516 // Loop over fields
517 //
518 for (const auto &[fid, fname]: db.get_fields(tid))
519 {
520 const Type &type = db.get_field_type(tid, fid);
521
522 out << '\n';
523
524 //
525 // Getter
526 //
527 out << " ";
528 write_type(out, type, true, false);
529 out << " get_" << fname << "(id_of_" << tname << " record";
530 if (single_row)
531 out << " = id_of_" << tname << "{0}";
532 out << ") const\n";
533 out << " {\n";
534 out << " JOEDB_RELEASE_ASSERT(is_valid_record_id_for_" << tname << "(record.get_record_id()));\n";
535 out << " return (";
536 write_type(out, type, true, false);
537 out << ")(storage_of_" << tname;
538 out << ".field_value_of_" << fname << "[record.get_id()]);\n";
539 out << " }\n";
540 }
541 }
542
543 //
544 // get_index_of_X
545 //
546 for (const auto &index: options.get_indices())
547 {
548 out << '\n';
549 out << " const type_of_index_of_" << index.name;
550 out << " &get_index_of_" << index.name << "()\n";
551 out << " {\n";
552 out << " return index_of_" << index.name << ";\n";
553 out << " }\n";
554 }
555
556 //
557 // find_index
558 //
559 for (const auto &index: options.get_indices())
560 {
561 if (index.unique)
562 {
563 const std::string &tname = db.get_table_name(index.table_id);
564 out << '\n';
565
566 out << " id_of_" << tname << " next_" << index.name << '(';
567 out << "id_of_" << tname << " id) const\n";
568 out << " {\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";
574 out << " else\n";
575 out << " return id_of_" << tname << "();\n";
576 out << " }\n";
577
578 if (index.ordered)
579 {
580 out << " id_of_" << tname << " previous_" << index.name << '(';
581 out << "id_of_" << tname << " id) const\n";
582 out << " {\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";
587 out << " else\n";
588 out << " return id_of_" << tname << "();\n";
589 out << " }\n";
590 }
591
592 out << " id_of_" << tname << " find_" << index.name << '(';
593 for (size_t i = 0; i < index.field_ids.size(); i++)
594 {
595 if (i > 0)
596 out << ", ";
597 const Type &type = db.get_field_type(index.table_id, index.field_ids[i]);
598 write_type(out, type, !index.ordered, true);
599 out << " field_value_of_";
600 out << db.get_field_name(index.table_id, index.field_ids[i]);
601 }
602 out << ") const\n";
603 out << " {\n";
604 out << " const auto i = index_of_" << index.name << ".find(";
605 write_tuple_type(out, index, true);
606 out << '(';
607 for (size_t i = 0; i < index.field_ids.size(); i++)
608 {
609 if (i > 0)
610 out << ", ";
611 out << "field_value_of_";
612 out << db.get_field_name(index.table_id, index.field_ids[i]);
613 }
614 out << "));\n";
615 out << " if (i == index_of_" << index.name << ".end())\n";
616 out << " return id_of_" << tname << "();\n";
617 out << " else\n";
618 out << " return i->second;\n";
619 out << " }\n";
620 }
621 else
622 {
623 out << " range_of_" << index.name << " find_" << index.name << '(';
624 for (size_t i = 0; i < index.field_ids.size(); i++)
625 {
626 if (i > 0)
627 out << ", ";
628 const Type &type = db.get_field_type(index.table_id, index.field_ids[i]);
629 write_type(out, type, !index.ordered, true);
630 out << " field_value_of_";
631 out << db.get_field_name(index.table_id, index.field_ids[i]);
632 }
633 out << ") const;\n";
634 }
635 }
636
637 out << " };\n";
638
639 //
640 // Plain iteration over tables
641 //
642 for (const auto &[tid, tname]: tables)
643 {
644 const bool single_row = options.get_table_options(tid).single_row;
645
646 out << " /// returned by @ref Database::get_" << tname << "_table\n";
647 out << " class container_of_" << tname << "\n";
648 out << " {\n";
649 out << " friend class Database;\n";
650 out << '\n';
651 out << " private:\n";
652 out << " const Database &db;\n";
653 out << " container_of_" << tname << "(const Database &db): db(db) {}\n";
654 out << '\n';
655 out << " public:\n";
656 out << " class iterator\n";
657 out << " {\n";
658 out << " friend class container_of_" << tname << ";\n";
659 out << " private:\n";
660
661
662 out << " const joedb::Freedom_Keeper *fk;\n"; // must use pointer for copy constructor
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";
665 out << " public:\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";
671 out << '\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";
680 out << " };\n";
681 out << '\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";
690
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";
694
695 out << " };\n";
696 out << '\n';
697
698 out << " inline container_of_" << tname << " Database::get_" << tname << "_table() const\n";
699 out << " {\n";
700 out << " return container_of_" << tname << "(*this);\n";
701 out << " }\n";
702 out << '\n';
703
704 if (!single_row)
705 {
706 out << " template<class Comparator>\n";
707 out << " std::vector<id_of_" << tname << "> Database::sorted_" << tname;
708 out << "(Comparator comparator) const\n";
709 out << " {\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";
715 out << " }\n";
716 }
717 }
718
719 //
720 // Index ranges for indexes that are not unique
721 //
722 for (const auto &index: options.get_indices())
723 {
724 if (!index.unique)
725 {
726 out << " /// returned by @ref Database::find_" << index.name << '\n';
727 out << " class range_of_" << index.name << "\n";
728 out << " {\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++)
736 {
737 out << ", ";
738 const Type &type = db.get_field_type(index.table_id, index.field_ids[i]);
739 write_type(out, type, !index.ordered, true);
740 out << ' ' << db.get_field_name(index.table_id, index.field_ids[i]);
741 }
742 out << ")\n";
743 out << " {\n";
744 out << " range = db.index_of_" << index.name << ".equal_range(";
745 write_tuple_type(out, index, true);
746 out << '(';
747 for (size_t i = 0; i < index.field_ids.size(); i++)
748 {
749 if (i > 0)
750 out << ", ";
751 out << db.get_field_name(index.table_id, index.field_ids[i]);
752 }
753 out << "));\n";
754 out << " }\n";
755 out << " public:\n";
756 out << " class iterator\n";
757 out << " {\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"
764 << " public:\n"
765 << " bool operator !=(const iterator &i) const\n"
766 << " {\n"
767 << " return map_iterator != i.map_iterator;\n"
768 << " }\n"
769 << " iterator &operator++() {map_iterator++; return *this;}\n"
770 << " id_of_" << db.get_table_name(index.table_id)
771 << " operator*() const {return map_iterator->second;}\n"
772 << " };\n"
773 << " iterator begin() const {return range.first;}\n"
774 << " iterator end() const {return range.second;}\n"
775 << " bool empty() const {return range.first == range.second;}\n"
776 << " size_t size() const {return size_t(std::distance(range.first, range.second));}\n"
777 << " };\n\n";
778
779 out << " inline range_of_" << index.name << " Database::find_" << index.name << '(';
780 for (size_t i = 0; i < index.field_ids.size(); i++)
781 {
782 if (i > 0)
783 out << ", ";
784 const Type &type = db.get_field_type(index.table_id, index.field_ids[i]);
785 write_type(out, type, !index.ordered, true);
786 out << " field_value_of_";
787 out << db.get_field_name(index.table_id, index.field_ids[i]);
788 }
789 out << ") const\n";
790 out << " {\n";
791 out << " return range_of_" << index.name << "(*this";
792 for (size_t i = 0; i < index.field_ids.size(); i++)
793 {
794 out << ", ";
795 out << "field_value_of_";
796 out << db.get_field_name(index.table_id, index.field_ids[i]);
797 }
798 out << ");\n";
799 out << " }\n";
800 }
801 }
802
805 }
806}
const std::vector< std::string > & get_name_space() const
const std::vector< Index > & get_indices() const
const Table_Options & get_table_options(Table_Id table_id) const
const Database & get_db() const
const Freedom_Keeper & get_freedom(Table_Id table_id) const override
const std::map< Table_Id, std::string > & get_tables() const override
const Type & get_field_type(Table_Id table_id, Field_Id field_id) const override
const std::map< Field_Id, std::string > & get_fields(Table_Id table_id) const override
Record_Id get_used_count() const
const std::string & get_field_name(Table_Id table_id, Field_Id field_id) const
Definition Readable.cpp:54
const std::string & get_table_name(Table_Id table_id) const
Definition Readable.cpp:38
Type_Id get_type_id() const
Definition Type.h:41
Database_h(const Compiler_Options &options)
void write(std::ostream &out) override
static const char * get_type_string(Type type)
const Compiler_Options & options
Definition Generator.h:16
void write_tuple_type(std::ostream &out, const Compiler_Options::Index &index, bool reference)
Definition Generator.cpp:84
void write_type(std::ostream &out, Type type, bool return_type, bool setter_type)
Definition Generator.cpp:42
void namespace_open(std::ostream &out, const std::vector< std::string > &n)
void namespace_close(std::ostream &out, const std::vector< std::string > &n)
void namespace_include_guard_open(std::ostream &out, const char *name, const std::vector< std::string > &n)
std::string namespace_string(const std::vector< std::string > &n, const char *delimiter)
void namespace_include_guard_close(std::ostream &out)
constexpr const char * get_version()
Definition get_version.h:7
One code generator for each of the file generated by joedbc.
Definition Client_h.cpp:5