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