Panda3D
interrogateDatabase.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file interrogateDatabase.cxx
10 * @author drose
11 * @date 2000-08-01
12 */
13
14#include "interrogateDatabase.h"
16#include "indexRemapper.h"
18
19using std::map;
20using std::string;
21
22InterrogateDatabase *InterrogateDatabase::_global_ptr = nullptr;
23int InterrogateDatabase::_file_major_version = 0;
24int InterrogateDatabase::_file_minor_version = 0;
25int InterrogateDatabase::_current_major_version = 3;
26int InterrogateDatabase::_current_minor_version = 3;
27
28/**
29 *
30 */
31InterrogateDatabase::
32InterrogateDatabase() {
33 _error_flag = false;
34 _next_index = 1;
35 _lookups_fresh = 0;
36}
37
38/**
39 * Returns the global pointer to the one InterrogateDatabase.
40 */
42get_ptr() {
43 if (_global_ptr == nullptr) {
44 if (interrogatedb_cat->is_debug()) {
45 interrogatedb_cat->debug()
46 << "Creating interrogate database\n";
47 }
48 _global_ptr = new InterrogateDatabase;
49 }
50 return _global_ptr;
51}
52
53/**
54 * Requests that the interrogate data for the given module be made available.
55 * The function pointers will be made available immediately, while the
56 * database file will be read later, the next time someone asks for
57 * interrogate data that requires it.
58 */
61 if (interrogatedb_cat->is_debug()) {
62 if (def->library_name == nullptr) {
63 interrogatedb_cat->debug()
64 << "Got interrogate data for anonymous module\n";
65 } else {
66 interrogatedb_cat->debug()
67 << "Got interrogate data for module " << def->library_name << "\n";
68 }
69 }
70
71 int num_indices = def->next_index - def->first_index;
72 if (num_indices > 0) {
73 // If the module def has any definitions--any index numbers used--assign
74 // it to its own unique range of index numbers.
75 def->first_index = _next_index;
76 _next_index += num_indices;
77 def->next_index = _next_index;
78
79 // Assign a reference to the module def by index number. When we need to
80 // look up a function by its index number, we'll be able to use this.
81 _modules.push_back(def);
82 }
83
84 if (def->num_unique_names > 0 && def->library_name != nullptr) {
85 // Define a lookup by hash for this module, mainly so we can look up
86 // functions by their unique names.
87 _modules_by_hash[def->library_hash_name] = def;
88 }
89
90 if (def->database_filename != nullptr) {
91 _requests.push_back(def);
92 }
93}
94
95/**
96 * Returns the global error flag. This will be set true if there was some
97 * problem importing the database (e.g. cannot find an .in file), or false if
98 * everything is ok.
99 */
102 return _error_flag;
103}
104
105/**
106 * Returns the total number of "global" types known to the interrogate
107 * database. These are types defined at the global level that should be
108 * considered for exporting, but not the incidental types (like pointers,
109 * etc.) that must be defined to support these.
110 */
113 check_latest();
114 return _global_types.size();
115}
116
117/**
118 * Returns the index of the nth global type known to the interrogate database.
119 */
121get_global_type(int n) {
122 check_latest();
123 if (n >= 0 && n < (int)_global_types.size()) {
124 return _global_types[n];
125 }
126 return 0;
127}
128
129/**
130 * Returns the total number of types known to the interrogate database. This
131 * includes all known types, global as well as incidental. See also
132 * get_num_global_types().
133 */
136 check_latest();
137 return _all_types.size();
138}
139
140/**
141 * Returns the index of the nth type known to the interrogate database.
142 */
144get_all_type(int n) {
145 check_latest();
146 if (n >= 0 && n < (int)_all_types.size()) {
147 return _all_types[n];
148 }
149 return 0;
150}
151
152/**
153 * Returns the total number of global functions known to the interrogate
154 * database. These are functions defined at the global level, e.g. non-
155 * member functions.
156 */
159 check_latest();
160 return _global_functions.size();
161}
162
163/**
164 * Returns the index of the nth global function known to the interrogate
165 * database.
166 */
168get_global_function(int n) {
169 check_latest();
170 if (n >= 0 && n < (int)_global_functions.size()) {
171 return _global_functions[n];
172 }
173 return 0;
174}
175
176/**
177 * Returns the total number of functions known to the interrogate database.
178 * This includes all known functions, global, method, or synthesized. See
179 * also get_num_global_functions().
180 */
183 check_latest();
184 return _all_functions.size();
185}
186
187/**
188 * Returns the index of the nth function known to the interrogate database.
189 */
191get_all_function(int n) {
192 check_latest();
193 if (n >= 0 && n < (int)_all_functions.size()) {
194 return _all_functions[n];
195 }
196 return 0;
197}
198
199/**
200 * Returns the total number of global manifest constants known to the
201 * interrogate database.
202 */
205 check_latest();
206 return _global_manifests.size();
207}
208
209/**
210 * Returns the index of the nth global manifest constant known to the
211 * interrogate database.
212 */
214get_global_manifest(int n) {
215 check_latest();
216 if (n >= 0 && n < (int)_global_manifests.size()) {
217 return _global_manifests[n];
218 }
219 return 0;
220}
221
222/**
223 * Returns the total number of global data elements known to the interrogate
224 * database.
225 */
228 check_latest();
229 return _global_elements.size();
230}
231
232/**
233 * Returns the index of the nth global data element known to the interrogate
234 * database.
235 */
237get_global_element(int n) {
238 check_latest();
239 if (n >= 0 && n < (int)_global_elements.size()) {
240 return _global_elements[n];
241 }
242 return 0;
243}
244
245/**
246 * Returns the type associated with the given TypeIndex, if there is one.
247 */
249get_type(TypeIndex type) {
250 static InterrogateType bogus_type;
251
252 check_latest();
253 TypeMap::const_iterator ti;
254 ti = _type_map.find(type);
255 if (ti == _type_map.end()) {
256 return bogus_type;
257 }
258 return (*ti).second;
259}
260
261/**
262 * Returns the function associated with the given FunctionIndex, if there is
263 * one.
264 */
266get_function(FunctionIndex function) {
267 static InterrogateFunction bogus_function;
268
269 check_latest();
270 FunctionMap::const_iterator fi;
271 fi = _function_map.find(function);
272 if (fi == _function_map.end()) {
273 return bogus_function;
274 }
275 return *(*fi).second;
276}
277
278/**
279 * Returns the function wrapper associated with the given
280 * FunctionWrapperIndex, if there is one.
281 */
283get_wrapper(FunctionWrapperIndex wrapper) {
284 static InterrogateFunctionWrapper bogus_wrapper;
285
286 check_latest();
287 FunctionWrapperMap::const_iterator wi;
288 wi = _wrapper_map.find(wrapper);
289 if (wi == _wrapper_map.end()) {
290 return bogus_wrapper;
291 }
292 return (*wi).second;
293}
294
295/**
296 * Returns the manifest constant associated with the given ManifestIndex, if
297 * there is one.
298 */
300get_manifest(ManifestIndex manifest) {
301 static InterrogateManifest bogus_manifest;
302
303 check_latest();
304 ManifestMap::const_iterator mi;
305 mi = _manifest_map.find(manifest);
306 if (mi == _manifest_map.end()) {
307 return bogus_manifest;
308 }
309 return (*mi).second;
310}
311
312/**
313 * Returns the data element associated with the given ElementIndex, if there
314 * is one.
315 */
317get_element(ElementIndex element) {
318 static InterrogateElement bogus_element;
319
320 check_latest();
321 ElementMap::const_iterator ei;
322 ei = _element_map.find(element);
323 if (ei == _element_map.end()) {
324 return bogus_element;
325 }
326 return (*ei).second;
327}
328
329/**
330 * Returns the make_seq associated with the given MakeSeqIndex, if there is
331 * one.
332 */
334get_make_seq(MakeSeqIndex make_seq) {
335 static InterrogateMakeSeq bogus_make_seq;
336
337 check_latest();
338 MakeSeqMap::const_iterator si;
339 si = _make_seq_map.find(make_seq);
340 if (si == _make_seq_map.end()) {
341 return bogus_make_seq;
342 }
343 return (*si).second;
344}
345
346/**
347 * Erases the type from the database.
348 */
350remove_type(TypeIndex type) {
351 _type_map.erase(type);
352}
353
354/**
355 * Returns the function pointer associated with the given function wrapper, if
356 * it has a pointer available. Returns NULL if the pointer is not available.
357 */
359get_fptr(FunctionWrapperIndex wrapper) {
361 int module_index;
362 if (find_module(wrapper, def, module_index)) {
363 if (module_index >= 0 && module_index < def->num_fptrs) {
364 return def->fptrs[module_index];
365 }
366 }
367 return nullptr;
368}
369
370/**
371 * Looks up the function wrapper corresponding to the given unique name, if
372 * available. Returns the corresponding wrapper index, or 0 if no such
373 * wrapper is found.
374 */
375FunctionWrapperIndex InterrogateDatabase::
376get_wrapper_by_unique_name(const string &unique_name) {
377 // First, split the unique_name into a library_hash_name and a
378 // wrapper_hash_name.
379
380 // The first four characters are always the library_name.
381 string library_hash_name = unique_name.substr(0, 4);
382 string wrapper_hash_name = unique_name.substr(4);
383
384 // Is the library_name defined?
385 ModulesByHash::const_iterator mi;
386 mi = _modules_by_hash.find(library_hash_name);
387 if (mi == _modules_by_hash.end()) {
388 return 0;
389 }
390
391 InterrogateModuleDef *def = (*mi).second;
392 int index_offset =
393 binary_search_wrapper_hash(def->unique_names,
394 def->unique_names + def->num_unique_names,
395 wrapper_hash_name);
396 if (index_offset >= 0) {
397 return def->first_index + index_offset;
398 }
399
400 return 0;
401}
402
403/**
404 * Returns the major version number of the interrogate database file currently
405 * being read.
406 */
409 return _file_major_version;
410}
411
412/**
413 * Returns the minor version number of the interrogate database file currently
414 * being read.
415 */
418 return _file_minor_version;
419}
420
421/**
422 * Returns the major version number currently expected in interrogate database
423 * files generated by this code base.
424 */
427 return _current_major_version;
428}
429
430/**
431 * Returns the minor version number currently expected in interrogate database
432 * files generated by this code base.
433 */
436 return _current_minor_version;
437}
438
439/**
440 * Sets the global error flag. This should be set true if there was some
441 * problem importing the database (e.g. cannot find an .in file).
442 */
444set_error_flag(bool error_flag) {
445 _error_flag = error_flag;
446}
447
448/**
449 * Returns a new index number suitable for the next thing, that will not be
450 * shared with any other index numbers.
451 */
454 return _next_index++;
455}
456
457/**
458 * Adds the indicated type to the database at the given index number.
459 */
461add_type(TypeIndex index, const InterrogateType &type) {
462 assert(index != 0);
463 bool inserted =
464 _type_map.insert(TypeMap::value_type(index, type)).second;
465
466 if (!inserted) {
467 // If there was already a type at that index, maybe it was a forward
468 // reference. If its _fully_defined bit isn't set, then it's ok.
469 InterrogateType &old_type = _type_map[index];
470 assert(!old_type.is_fully_defined());
471
472 // It was a forward reference. Merge it with the new one.
473 old_type.merge_with(type);
474 }
475
476 if (type.is_global()) {
477 _global_types.push_back(index);
478 }
479 _all_types.push_back(index);
480}
481
482/**
483 * Adds the indicated function to the database at the given index number.
484 */
486add_function(FunctionIndex index, InterrogateFunction *function) {
487 bool inserted =
488 _function_map.insert(FunctionMap::value_type(index, function)).second;
489 assert(inserted);
490
491 if (function->is_global()) {
492 _global_functions.push_back(index);
493 }
494 _all_functions.push_back(index);
495}
496
497/**
498 * Adds the indicated function wrapper to the database at the given index
499 * number.
500 */
502add_wrapper(FunctionWrapperIndex index,
503 const InterrogateFunctionWrapper &wrapper) {
504 bool inserted =
505 _wrapper_map.insert(FunctionWrapperMap::value_type(index, wrapper)).second;
506 assert(inserted);
507}
508
509/**
510 * Adds the indicated manifest constant to the database at the given index
511 * number.
512 */
514add_manifest(ManifestIndex index, const InterrogateManifest &manifest) {
515 bool inserted =
516 _manifest_map.insert(ManifestMap::value_type(index, manifest)).second;
517 assert(inserted);
518
519 _global_manifests.push_back(index);
520}
521
522/**
523 * Adds the indicated data element to the database at the given index number.
524 */
526add_element(ElementIndex index, const InterrogateElement &element) {
527 bool inserted =
528 _element_map.insert(ElementMap::value_type(index, element)).second;
529 assert(inserted);
530
531 if (element.is_global()) {
532 _global_elements.push_back(index);
533 }
534}
535
536/**
537 * Adds the indicated make_seq to the database at the given index number.
538 */
540add_make_seq(MakeSeqIndex index, const InterrogateMakeSeq &make_seq) {
541 bool inserted =
542 _make_seq_map.insert(MakeSeqMap::value_type(index, make_seq)).second;
543 assert(inserted);
544}
545
546/**
547 * Returns a non-const reference to the indicated type, allowing the user to
548 * update it.
549 */
551update_type(TypeIndex type) {
552 assert(type != 0);
553 check_latest();
554 return _type_map[type];
555}
556
557/**
558 * Returns a non-const reference to the indicated function, allowing the user
559 * to update it.
560 */
562update_function(FunctionIndex function) {
563 check_latest();
564 return *_function_map[function];
565}
566
567/**
568 * Returns a non-const reference to the indicated function wrapper, allowing
569 * the user to update it.
570 */
572update_wrapper(FunctionWrapperIndex wrapper) {
573 check_latest();
574 return _wrapper_map[wrapper];
575}
576
577/**
578 * Returns a non-const reference to the indicated manifest constant, allowing
579 * the user to update it.
580 */
582update_manifest(ManifestIndex manifest) {
583 check_latest();
584 return _manifest_map[manifest];
585}
586
587/**
588 * Returns a non-const reference to the indicated data element, allowing the
589 * user to update it.
590 */
592update_element(ElementIndex element) {
593 check_latest();
594 return _element_map[element];
595}
596
597/**
598 * Returns a non-const reference to the indicated make_seq, allowing the user
599 * to update it.
600 */
602update_make_seq(MakeSeqIndex make_seq) {
603 check_latest();
604 return _make_seq_map[make_seq];
605}
606
607/**
608 * Resequences all of the various index numbers so that all of the functions
609 * start at first_index and increment consecutively from there, and then all
610 * of the types follow. Returns the next available index number.
611 */
613remap_indices(int first_index) {
614 IndexRemapper remap;
615 return remap_indices(first_index, remap);
616}
617
618/**
619 * This flavor of remap_indices() accepts a map that should be empty on
620 * initial call, and will be filled with the mapping of old index number to
621 * new index number. This allows the caller to update its own data structures
622 * to match the new index numbers.
623 */
625remap_indices(int first_index, IndexRemapper &remap) {
626 remap.clear();
627
628 // First, build up the complete map.
629
630 // Get the wrapper indices first. This is important, because the
631 // InterrogateBuilder wants these to be first, and consecutive.
632 FunctionWrapperMap new_wrapper_map;
633 FunctionWrapperMap::iterator wi;
634 for (wi = _wrapper_map.begin(); wi != _wrapper_map.end(); ++wi) {
635 remap.add_mapping((*wi).first, first_index);
636 new_wrapper_map[first_index] = (*wi).second;
637 first_index++;
638 }
639
640 // Everything else can follow; it doesn't matter so much.
641 FunctionMap new_function_map;
642 FunctionMap::iterator fi;
643 for (fi = _function_map.begin(); fi != _function_map.end(); ++fi) {
644 remap.add_mapping((*fi).first, first_index);
645 new_function_map[first_index] = (*fi).second;
646 first_index++;
647 }
648
649 TypeMap new_type_map;
650 TypeMap::iterator ti;
651 for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
652 assert((*ti).first != 0);
653 remap.add_mapping((*ti).first, first_index);
654 new_type_map[first_index] = (*ti).second;
655 first_index++;
656 }
657
658 ManifestMap new_manifest_map;
659 ManifestMap::iterator mi;
660 for (mi = _manifest_map.begin(); mi != _manifest_map.end(); ++mi) {
661 remap.add_mapping((*mi).first, first_index);
662 new_manifest_map[first_index] = (*mi).second;
663 first_index++;
664 }
665
666 ElementMap new_element_map;
667 ElementMap::iterator ei;
668 for (ei = _element_map.begin(); ei != _element_map.end(); ++ei) {
669 remap.add_mapping((*ei).first, first_index);
670 new_element_map[first_index] = (*ei).second;
671 first_index++;
672 }
673
674 MakeSeqMap new_make_seq_map;
675 MakeSeqMap::iterator si;
676 for (si = _make_seq_map.begin(); si != _make_seq_map.end(); ++si) {
677 remap.add_mapping((*si).first, first_index);
678 new_make_seq_map[first_index] = (*si).second;
679 first_index++;
680 }
681
682 _next_index = first_index;
683
684 _wrapper_map.swap(new_wrapper_map);
685 _function_map.swap(new_function_map);
686 _type_map.swap(new_type_map);
687 _manifest_map.swap(new_manifest_map);
688 _element_map.swap(new_element_map);
689 _make_seq_map.swap(new_make_seq_map);
690
691 // Then, go back through and update all of the internal references.
692 for (wi = _wrapper_map.begin(); wi != _wrapper_map.end(); ++wi) {
693 (*wi).second.remap_indices(remap);
694 }
695 for (fi = _function_map.begin(); fi != _function_map.end(); ++fi) {
696 (*fi).second->remap_indices(remap);
697 }
698 for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
699 (*ti).second.remap_indices(remap);
700 }
701 for (mi = _manifest_map.begin(); mi != _manifest_map.end(); ++mi) {
702 (*mi).second.remap_indices(remap);
703 }
704 for (ei = _element_map.begin(); ei != _element_map.end(); ++ei) {
705 (*ei).second.remap_indices(remap);
706 }
707 for (si = _make_seq_map.begin(); si != _make_seq_map.end(); ++si) {
708 (*si).second.remap_indices(remap);
709 }
710 GlobalFunctions::iterator gfi;
711 for (gfi = _global_functions.begin(); gfi != _global_functions.end(); ++gfi) {
712 (*gfi) = remap.map_from(*gfi);
713 }
714 for (gfi = _all_functions.begin(); gfi != _all_functions.end(); ++gfi) {
715 (*gfi) = remap.map_from(*gfi);
716 }
717 GlobalTypes::iterator gti;
718 for (gti = _global_types.begin(); gti != _global_types.end(); ++gti) {
719 (*gti) = remap.map_from(*gti);
720 }
721 for (gti = _all_types.begin(); gti != _all_types.end(); ++gti) {
722 (*gti) = remap.map_from(*gti);
723 }
724 GlobalManifests::iterator gmi;
725 for (gmi = _global_manifests.begin(); gmi != _global_manifests.end(); ++gmi) {
726 (*gmi) = remap.map_from(*gmi);
727 }
728 GlobalElements::iterator gei;
729 for (gei = _global_elements.begin(); gei != _global_elements.end(); ++gei) {
730 (*gei) = remap.map_from(*gei);
731 }
732
733 return _next_index;
734}
735
736/**
737 * Writes the database to the indicated stream for later reading.
738 */
740write(std::ostream &out, InterrogateModuleDef *def) const {
741 // Write out the file header.
742 out << def->file_identifier << "\n"
743 << _current_major_version << " " << _current_minor_version << "\n";
744
745 // Write out the module definition.
746 idf_output_string(out, def->library_name);
747 idf_output_string(out, def->library_hash_name);
748 idf_output_string(out, def->module_name);
749 out << "\n";
750
751 // Now write out the components.
752
753 out << _function_map.size() << "\n";
754 FunctionMap::const_iterator fi;
755 for (fi = _function_map.begin(); fi != _function_map.end(); ++fi) {
756 out << (*fi).first << " " << *(*fi).second << "\n";
757 }
758
759 out << _wrapper_map.size() << "\n";
760 FunctionWrapperMap::const_iterator wi;
761 for (wi = _wrapper_map.begin(); wi != _wrapper_map.end(); ++wi) {
762 out << (*wi).first << " " << (*wi).second << "\n";
763 }
764
765 out << _type_map.size() << "\n";
766 TypeMap::const_iterator ti;
767 for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
768 out << (*ti).first << " " << (*ti).second << "\n";
769 }
770
771 out << _manifest_map.size() << "\n";
772 ManifestMap::const_iterator mi;
773 for (mi = _manifest_map.begin(); mi != _manifest_map.end(); ++mi) {
774 out << (*mi).first << " " << (*mi).second << "\n";
775 }
776
777 out << _element_map.size() << "\n";
778 ElementMap::const_iterator ei;
779 for (ei = _element_map.begin(); ei != _element_map.end(); ++ei) {
780 out << (*ei).first << " " << (*ei).second << "\n";
781 }
782
783 out << _make_seq_map.size() << "\n";
784 MakeSeqMap::const_iterator si;
785 for (si = _make_seq_map.begin(); si != _make_seq_map.end(); ++si) {
786 out << (*si).first << " " << (*si).second << "\n";
787 }
788}
789
790/**
791 * Reads a database from the indicated stream, associated with the indicated
792 * module definition and merges it with any existing data in the database,
793 * according to the expected index numbers specified in the module def. The
794 * header information has already been read.
795 *
796 * Returns true if the file is read successfully, false if there is an error.
797 */
799read(std::istream &in, InterrogateModuleDef *def) {
801 if (!temp.read_new(in, def)) {
802 return false;
803 }
804
805 if (def->first_index == 0 && def->next_index == 0) {
806 _next_index = temp.remap_indices(_next_index);
807
808 } else {
809 int next = temp.remap_indices(def->first_index);
810 if (next != def->next_index) {
811 interrogatedb_cat->error()
812 << "Module database file " << def->database_filename
813 << " is out of date.\n";
814 return false;
815 }
816 }
817
818 merge_from(temp);
819 return true;
820}
821
822/**
823 * Reads in the latest interrogate data.
824 */
825void InterrogateDatabase::
826load_latest() {
827 const DSearchPath &searchpath = interrogatedb_path;
828
829 Requests copy_requests;
830 copy_requests.swap(_requests);
831
832 Requests::const_iterator ri;
833 for (ri = copy_requests.begin(); ri != copy_requests.end(); ++ri) {
834 InterrogateModuleDef *def = (*ri);
835
836 if (def->database_filename != nullptr) {
837 Filename filename = def->database_filename;
838 Filename pathname = filename;
839 if (!pathname.empty() && pathname[0] != '/') {
840 pathname = searchpath.find_file(pathname);
841 }
842
843 if (pathname.empty()) {
844 interrogatedb_cat->error()
845 << "Unable to find " << filename << " on " << searchpath << "\n";
846 set_error_flag(true);
847
848 } else {
849
850 pifstream input;
851 pathname.set_text();
852 if (!pathname.open_read(input)) {
853 interrogatedb_cat->error() << "Unable to read " << pathname << ".\n";
854 set_error_flag(true);
855
856 } else {
857 int file_identifier;
858 input >> file_identifier
859 >> _file_major_version >> _file_minor_version;
860
861 if (def->file_identifier != 0 &&
862 file_identifier != def->file_identifier) {
863 interrogatedb_cat->warning()
864 << "Interrogate data in " << pathname
865 << " is out of sync with the compiled-in data"
866 << " (" << file_identifier << " != " << def->file_identifier << ").\n";
867 set_error_flag(true);
868 }
869
870 if (_file_major_version != _current_major_version ||
871 _file_minor_version > _current_minor_version) {
872 interrogatedb_cat->error()
873 << "Cannot read interrogate data in " << pathname
874 << "; database is version " << _file_major_version << "."
875 << _file_minor_version << " while we are expecting "
876 << _current_major_version << "." << _current_minor_version
877 << ".\n";
878 set_error_flag(true);
879
880 } else {
881 if (interrogatedb_cat->is_debug()) {
882 interrogatedb_cat->debug()
883 << "Reading " << filename << "\n";
884 }
885 if (!read(input, def)) {
886 interrogatedb_cat->error()
887 << "Error reading " << pathname << ".\n";
888 set_error_flag(true);
889 }
890 }
891 }
892 }
893 }
894 }
895
896 _requests.clear();
897}
898
899/**
900 * Reads from the indicated stream (the header information has already been
901 * read) into the newly-created database. It is an error if the database
902 * already has some data in it.
903 */
904bool InterrogateDatabase::
905read_new(std::istream &in, InterrogateModuleDef *def) {
906 // We've already read the header. Read the module definition.
907 idf_input_string(in, def->library_name);
908 idf_input_string(in, def->library_hash_name);
909 idf_input_string(in, def->module_name);
910
911 // Now read all of the components.
912
913 { // Functions.
914 int num_functions;
915 in >> num_functions;
916 if (in.fail()) {
917 return false;
918 }
919
920 while (num_functions > 0) {
921 FunctionIndex index;
922 InterrogateFunction *function = new InterrogateFunction(def);
923 in >> index >> *function;
924 if (in.fail()) {
925 delete function;
926 return false;
927 }
928
929 add_function(index, function);
930 num_functions--;
931 }
932 }
933
934 { // Wrappers.
935 int num_wrappers;
936 in >> num_wrappers;
937 if (in.fail()) {
938 return false;
939 }
940
941 while (num_wrappers > 0) {
942 FunctionWrapperIndex index;
943 InterrogateFunctionWrapper wrapper(def);
944 in >> index >> wrapper;
945 if (in.fail()) {
946 return false;
947 }
948
949 add_wrapper(index, wrapper);
950 num_wrappers--;
951 }
952 }
953
954 { // Types.
955 int num_types;
956 in >> num_types;
957 if (in.fail()) {
958 return false;
959 }
960
961 while (num_types > 0) {
962 TypeIndex index;
963 InterrogateType type(def);
964 in >> index >> type;
965 if (in.fail()) {
966 return false;
967 }
968
969 add_type(index, type);
970 num_types--;
971 }
972 }
973
974 { // Manifests.
975 int num_manifests;
976 in >> num_manifests;
977 if (in.fail()) {
978 return false;
979 }
980
981 while (num_manifests > 0) {
982 ManifestIndex index;
983 InterrogateManifest manifest(def);
984 in >> index >> manifest;
985 if (in.fail()) {
986 return false;
987 }
988
989 add_manifest(index, manifest);
990 num_manifests--;
991 }
992 }
993
994 { // Elements.
995 int num_elements;
996 in >> num_elements;
997 if (in.fail()) {
998 return false;
999 }
1000
1001 while (num_elements > 0) {
1002 ElementIndex index;
1003 InterrogateElement element(def);
1004 in >> index >> element;
1005 if (in.fail()) {
1006 return false;
1007 }
1008
1009 add_element(index, element);
1010 num_elements--;
1011 }
1012 }
1013
1014 { // MakeSeqs.
1015 int num_make_seqs;
1016 in >> num_make_seqs;
1017 if (in.fail()) {
1018 return false;
1019 }
1020
1021 while (num_make_seqs > 0) {
1022 MakeSeqIndex index;
1023 InterrogateMakeSeq make_seq(def);
1024 in >> index >> make_seq;
1025 if (in.fail()) {
1026 return false;
1027 }
1028
1029 add_make_seq(index, make_seq);
1030 num_make_seqs--;
1031 }
1032 }
1033
1034 return true;
1035}
1036
1037/**
1038 * Copies all the data from the indicated database into this one. It is an
1039 * error if any index numbers are shared between the two databases.
1040 */
1041void InterrogateDatabase::
1042merge_from(const InterrogateDatabase &other) {
1043 // We want to collapse shared types together.
1044 IndexRemapper remap;
1045
1046 // First, we need to build a set of types by name, so we know what types we
1047 // already have.
1048 map<string, TypeIndex> types_by_name;
1049
1050 TypeMap::const_iterator ti;
1051 for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
1052 const InterrogateType &type = (*ti).second;
1053 if (type.has_true_name()) {
1054 types_by_name[type.get_true_name()] = (*ti).first;
1055 }
1056 }
1057
1058 // Now go through the other set of types and determine the mapping into this
1059 // set.
1060 for (ti = other._type_map.begin(); ti != other._type_map.end(); ++ti) {
1061 TypeIndex other_type_index = (*ti).first;
1062 const InterrogateType &other_type = (*ti).second;
1063
1064 if (other_type.has_name()) {
1065 map<string, TypeIndex>::iterator ni;
1066 ni = types_by_name.find(other_type.get_true_name());
1067 if (ni != types_by_name.end()) {
1068 // Here's a type that we seem to have in common! We'll have to merge
1069 // them.
1070 TypeIndex this_type_index = (*ni).second;
1071 remap.add_mapping(other_type_index, this_type_index);
1072 }
1073 }
1074 }
1075
1076 // Now that we know the full type-to-type mapping, we can copy the new
1077 // types, one at a time.
1078 for (ti = other._type_map.begin(); ti != other._type_map.end(); ++ti) {
1079 TypeIndex other_type_index = (*ti).first;
1080 const InterrogateType &other_type = (*ti).second;
1081
1082 if (!remap.in_map(other_type_index)) {
1083 // Here's a new type.
1084 add_type(other_type_index, other_type);
1085 update_type(other_type_index).remap_indices(remap);
1086
1087 } else {
1088 // Here's a type to merge.
1089 TypeIndex this_type_index = remap.map_from(other_type_index);
1090
1091 InterrogateType &this_type = update_type(this_type_index);
1092 if (!this_type.is_global() && other_type.is_global()) {
1093 // If the type is about to become global, we need to add it to our
1094 // global_types list.
1095 _global_types.push_back(this_type_index);
1096 }
1097
1098 InterrogateType merge_type = other_type;
1099 merge_type.remap_indices(remap);
1100 this_type.merge_with(merge_type);
1101 }
1102 }
1103
1104 // And copy all of the functions, wrappers, manifests, and elements.
1105 FunctionMap::const_iterator fi;
1106 for (fi = other._function_map.begin();
1107 fi != other._function_map.end();
1108 ++fi) {
1109 FunctionIndex other_function_index = (*fi).first;
1110 InterrogateFunction *other_function = (*fi).second;
1111 add_function(other_function_index, other_function);
1112 update_function(other_function_index).remap_indices(remap);
1113 }
1114
1115 FunctionWrapperMap::const_iterator wi;
1116 for (wi = other._wrapper_map.begin();
1117 wi != other._wrapper_map.end();
1118 ++wi) {
1119 FunctionWrapperIndex other_wrapper_index = (*wi).first;
1120 const InterrogateFunctionWrapper &other_wrapper = (*wi).second;
1121 add_wrapper(other_wrapper_index, other_wrapper);
1122 update_wrapper(other_wrapper_index).remap_indices(remap);
1123 }
1124
1125 ManifestMap::const_iterator mi;
1126 for (mi = other._manifest_map.begin();
1127 mi != other._manifest_map.end();
1128 ++mi) {
1129 ManifestIndex other_manifest_index = (*mi).first;
1130 const InterrogateManifest &other_manifest = (*mi).second;
1131 add_manifest(other_manifest_index, other_manifest);
1132 update_manifest(other_manifest_index).remap_indices(remap);
1133 }
1134
1135 ElementMap::const_iterator ei;
1136 for (ei = other._element_map.begin();
1137 ei != other._element_map.end();
1138 ++ei) {
1139 ElementIndex other_element_index = (*ei).first;
1140 const InterrogateElement &other_element = (*ei).second;
1141 add_element(other_element_index, other_element);
1142 update_element(other_element_index).remap_indices(remap);
1143 }
1144
1145 MakeSeqMap::const_iterator si;
1146 for (si = other._make_seq_map.begin();
1147 si != other._make_seq_map.end();
1148 ++si) {
1149 MakeSeqIndex other_make_seq_index = (*si).first;
1150 const InterrogateMakeSeq &other_make_seq = (*si).second;
1151 add_make_seq(other_make_seq_index, other_make_seq);
1152 update_make_seq(other_make_seq_index).remap_indices(remap);
1153 }
1154
1155 _lookups_fresh = 0;
1156}
1157
1158/**
1159 * Looks up the wrapper definition in the set of module defs that are loaded
1160 * in at runtime and represent the part of the interrogate database that's
1161 * compiled in.
1162 *
1163 * If the wrapper definition is not found, returns false. If it is found,
1164 * returns true and sets def and module_index to the particular module and the
1165 * index within the module where the wrapper is defined.
1166 */
1167bool InterrogateDatabase::
1168find_module(FunctionWrapperIndex wrapper, InterrogateModuleDef *&def,
1169 int &module_index) {
1170 if (_modules.empty()) {
1171 return false;
1172 }
1173
1174 int mi = binary_search_module(0, _modules.size(), wrapper);
1175 assert(mi >= 0 && mi < (int)_modules.size());
1176 def = _modules[mi];
1177 module_index = wrapper - def->first_index;
1178
1179 return (wrapper < def->next_index);
1180}
1181
1182/**
1183 * Searches for the function module that includes the given function index by
1184 * binary search.
1185 */
1186int InterrogateDatabase::
1187binary_search_module(int begin, int end, FunctionIndex function) {
1188 int mid = begin + (end - begin) / 2;
1189 if (mid == begin) {
1190 return mid;
1191 }
1192
1193 int index = _modules[mid]->first_index;
1194 if (index <= function) {
1195 return binary_search_module(mid, end, function);
1196
1197 } else {
1198 return binary_search_module(begin, mid, function);
1199 }
1200}
1201
1202/**
1203 * Searches for the particular function wrapper's hash name within a given
1204 * module. Returns the index number local to the module, or -1 if it is not
1205 * found.
1206 */
1207int InterrogateDatabase::
1208binary_search_wrapper_hash(InterrogateUniqueNameDef *begin,
1210 const string &wrapper_hash_name) {
1211 if (end <= begin) {
1212 return -1;
1213 }
1214
1215 InterrogateUniqueNameDef *mid = begin + (end - begin) / 2;
1216 string name = mid->name;
1217 if (name < wrapper_hash_name) {
1218 return binary_search_wrapper_hash(mid, end, wrapper_hash_name);
1219
1220 } else if (wrapper_hash_name < name) {
1221 return binary_search_wrapper_hash(begin, mid, wrapper_hash_name);
1222
1223 } else {
1224 return mid->index_offset;
1225 }
1226}
1227
1228/**
1229 * Builds up the lookup of types by name.
1230 */
1231void InterrogateDatabase::
1232freshen_types_by_name() {
1233 _types_by_name.clear();
1234 TypeMap::const_iterator ti;
1235 for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
1236 _types_by_name[(*ti).second.get_name()] = (*ti).first;
1237 }
1238}
1239
1240/**
1241 * Builds up the lookup of types by scoped name.
1242 */
1243void InterrogateDatabase::
1244freshen_types_by_scoped_name() {
1245 _types_by_scoped_name.clear();
1246 TypeMap::const_iterator ti;
1247 for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
1248 _types_by_scoped_name[(*ti).second.get_scoped_name()] = (*ti).first;
1249 }
1250}
1251
1252/**
1253 * Builds up the lookup of types by true name.
1254 */
1255void InterrogateDatabase::
1256freshen_types_by_true_name() {
1257 _types_by_true_name.clear();
1258 TypeMap::const_iterator ti;
1259 for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) {
1260 _types_by_true_name[(*ti).second.get_true_name()] = (*ti).first;
1261 }
1262}
1263
1264/**
1265 * Builds up the lookup of manifests by name.
1266 */
1267void InterrogateDatabase::
1268freshen_manifests_by_name() {
1269 _manifests_by_name.clear();
1270 ManifestMap::const_iterator ti;
1271 for (ti = _manifest_map.begin(); ti != _manifest_map.end(); ++ti) {
1272 _manifests_by_name[(*ti).second.get_name()] = (*ti).first;
1273 }
1274}
1275
1276/**
1277 * Builds up the lookup of elements by name.
1278 */
1279void InterrogateDatabase::
1280freshen_elements_by_name() {
1281 _elements_by_name.clear();
1282 ElementMap::const_iterator ti;
1283 for (ti = _element_map.begin(); ti != _element_map.end(); ++ti) {
1284 _elements_by_name[(*ti).second.get_name()] = (*ti).first;
1285 }
1286}
1287
1288/**
1289 * Builds up the lookup of elements by scoped name.
1290 */
1291void InterrogateDatabase::
1292freshen_elements_by_scoped_name() {
1293 _elements_by_scoped_name.clear();
1294 ElementMap::const_iterator ti;
1295 for (ti = _element_map.begin(); ti != _element_map.end(); ++ti) {
1296 _elements_by_scoped_name[(*ti).second.get_scoped_name()] = (*ti).first;
1297 }
1298}
1299
1300/**
1301 * Looks up a type, manifest, or element in the indicated lookup table by
1302 * name. This is an internal support function.
1303 */
1304int InterrogateDatabase::
1305lookup(const string &name, Lookup &lookup, LookupType type,
1306 void (InterrogateDatabase::*freshen)()) {
1307 if ((_lookups_fresh & (int)type) == 0) {
1308 // The lookup table isn't fresh; we need to freshen it.
1309 (this->*freshen)();
1310 _lookups_fresh |= (int)type;
1311 }
1312
1313 Lookup::const_iterator li;
1314 li = lookup.find(name);
1315 if (li != lookup.end()) {
1316 return (*li).second;
1317 }
1318 return 0;
1319}
This class stores a list of directories that can be searched, in order, to locate a particular file.
Definition: dSearchPath.h:28
Filename find_file(const Filename &filename) const
Searches all the directories in the search list for the indicated file, in order.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:1863
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:424
This class manages a mapping of integers to integers.
Definition: indexRemapper.h:29
bool in_map(int from) const
Returns true if the given 'from' integer has been assigned a mapping, false if it has not.
void add_mapping(int from, int to)
Adds a mapping from the integer 'from' to 'to'.
void clear()
Removes all mappings from the object.
int map_from(int from) const
Returns the integer that the given 'from' integer had been set to map to, or the same integer if noth...
This stores all of the interrogate data and handles reading the data from a disk file when necessary.
int get_num_global_types()
Returns the total number of "global" types known to the interrogate database.
void remove_type(TypeIndex type)
Erases the type from the database.
void request_module(InterrogateModuleDef *def)
Requests that the interrogate data for the given module be made available.
ManifestIndex get_global_manifest(int n)
Returns the index of the nth global manifest constant known to the interrogate database.
const InterrogateFunction & get_function(FunctionIndex function)
Returns the function associated with the given FunctionIndex, if there is one.
InterrogateFunction & update_function(FunctionIndex function)
Returns a non-const reference to the indicated function, allowing the user to update it.
static int get_current_minor_version()
Returns the minor version number currently expected in interrogate database files generated by this c...
InterrogateType & update_type(TypeIndex type)
Returns a non-const reference to the indicated type, allowing the user to update it.
int get_num_all_functions()
Returns the total number of functions known to the interrogate database.
InterrogateElement & update_element(ElementIndex element)
Returns a non-const reference to the indicated data element, allowing the user to update it.
int get_num_all_types()
Returns the total number of types known to the interrogate database.
void add_manifest(ManifestIndex index, const InterrogateManifest &manifest)
Adds the indicated manifest constant to the database at the given index number.
const InterrogateMakeSeq & get_make_seq(MakeSeqIndex element)
Returns the make_seq associated with the given MakeSeqIndex, if there is one.
bool get_error_flag()
Returns the global error flag.
void add_wrapper(FunctionWrapperIndex index, const InterrogateFunctionWrapper &wrapper)
Adds the indicated function wrapper to the database at the given index number.
int get_num_global_elements()
Returns the total number of global data elements known to the interrogate database.
void add_type(TypeIndex index, const InterrogateType &type)
Adds the indicated type to the database at the given index number.
const InterrogateManifest & get_manifest(ManifestIndex manifest)
Returns the manifest constant associated with the given ManifestIndex, if there is one.
const InterrogateType & get_type(TypeIndex type)
Returns the type associated with the given TypeIndex, if there is one.
const InterrogateElement & get_element(ElementIndex element)
Returns the data element associated with the given ElementIndex, if there is one.
int get_num_global_manifests()
Returns the total number of global manifest constants known to the interrogate database.
InterrogateManifest & update_manifest(ManifestIndex manifest)
Returns a non-const reference to the indicated manifest constant, allowing the user to update it.
int get_num_global_functions()
Returns the total number of global functions known to the interrogate database.
InterrogateFunctionWrapper & update_wrapper(FunctionWrapperIndex wrapper)
Returns a non-const reference to the indicated function wrapper, allowing the user to update it.
void add_element(ElementIndex index, const InterrogateElement &element)
Adds the indicated data element to the database at the given index number.
static int get_file_minor_version()
Returns the minor version number of the interrogate database file currently being read.
bool read(std::istream &in, InterrogateModuleDef *def)
Reads a database from the indicated stream, associated with the indicated module definition and merge...
void set_error_flag(bool error_flag)
Sets the global error flag.
const InterrogateFunctionWrapper & get_wrapper(FunctionWrapperIndex wrapper)
Returns the function wrapper associated with the given FunctionWrapperIndex, if there is one.
static int get_current_major_version()
Returns the major version number currently expected in interrogate database files generated by this c...
int get_next_index()
Returns a new index number suitable for the next thing, that will not be shared with any other index ...
static InterrogateDatabase * get_ptr()
Returns the global pointer to the one InterrogateDatabase.
void * get_fptr(FunctionWrapperIndex wrapper)
Returns the function pointer associated with the given function wrapper, if it has a pointer availabl...
FunctionIndex get_all_function(int n)
Returns the index of the nth function known to the interrogate database.
TypeIndex get_all_type(int n)
Returns the index of the nth type known to the interrogate database.
FunctionWrapperIndex get_wrapper_by_unique_name(const std::string &unique_name)
Looks up the function wrapper corresponding to the given unique name, if available.
void add_make_seq(MakeSeqIndex index, const InterrogateMakeSeq &make_seq)
Adds the indicated make_seq to the database at the given index number.
InterrogateMakeSeq & update_make_seq(MakeSeqIndex make_seq)
Returns a non-const reference to the indicated make_seq, allowing the user to update it.
void add_function(FunctionIndex index, InterrogateFunction *function)
Adds the indicated function to the database at the given index number.
int remap_indices(int first_index)
Resequences all of the various index numbers so that all of the functions start at first_index and in...
void write(std::ostream &out, InterrogateModuleDef *def) const
Writes the database to the indicated stream for later reading.
static int get_file_major_version()
Returns the major version number of the interrogate database file currently being read.
ElementIndex get_global_element(int n)
Returns the index of the nth global data element known to the interrogate database.
TypeIndex get_global_type(int n)
Returns the index of the nth global type known to the interrogate database.
FunctionIndex get_global_function(int n)
Returns the index of the nth global function known to the interrogate database.
An internal representation of a data element, like a data member or a global variable.
bool is_global() const
Returns true if the element is marked as 'global'.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
An internal representation of a callable function.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
An internal representation of a function.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
Represents a synthetic method created via the MAKE_SEQ() macro.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
An internal representation of a manifest constant.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
An internal representation of a type.
bool is_global() const
Returns true if the type is marked as 'global'.
void merge_with(const InterrogateType &other)
Combines type with the other similar definition.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void idf_input_string(istream &in, string &str)
Reads the given string from the input file, as previously written by output_string().
void idf_output_string(ostream &out, const string &str, char whitespace)
Writes the indicated string to the output file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.