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"
15 #include "config_interrogatedb.h"
16 #include "indexRemapper.h"
17 #include "interrogate_datafile.h"
18 
19 using std::map;
20 using std::string;
21 
22 InterrogateDatabase *InterrogateDatabase::_global_ptr = nullptr;
23 int InterrogateDatabase::_file_major_version = 0;
24 int InterrogateDatabase::_file_minor_version = 0;
25 int InterrogateDatabase::_current_major_version = 3;
26 int InterrogateDatabase::_current_minor_version = 3;
27 
28 /**
29  *
30  */
31 InterrogateDatabase::
32 InterrogateDatabase() {
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  */
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  */
120 TypeIndex InterrogateDatabase::
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  */
143 TypeIndex InterrogateDatabase::
144 get_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  */
167 FunctionIndex InterrogateDatabase::
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  */
190 FunctionIndex InterrogateDatabase::
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  */
213 ManifestIndex InterrogateDatabase::
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  */
236 ElementIndex InterrogateDatabase::
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  */
249 get_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  */
266 get_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  */
283 get_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  */
300 get_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  */
317 get_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  */
334 get_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  */
350 remove_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  */
359 get_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  */
375 FunctionWrapperIndex InterrogateDatabase::
376 get_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  */
444 set_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  */
461 add_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  */
486 add_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  */
502 add_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  */
514 add_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  */
526 add_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  */
540 add_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  */
551 update_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  */
562 update_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  */
572 update_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  */
582 update_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  */
592 update_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  */
602 update_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  */
613 remap_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  */
625 remap_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  */
740 write(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  */
799 read(std::istream &in, InterrogateModuleDef *def) {
800  InterrogateDatabase temp;
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  */
825 void InterrogateDatabase::
826 load_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  */
904 bool InterrogateDatabase::
905 read_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  */
1041 void InterrogateDatabase::
1042 merge_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  */
1167 bool InterrogateDatabase::
1168 find_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  */
1186 int InterrogateDatabase::
1187 binary_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  */
1207 int InterrogateDatabase::
1208 binary_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  */
1231 void InterrogateDatabase::
1232 freshen_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  */
1243 void InterrogateDatabase::
1244 freshen_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  */
1255 void InterrogateDatabase::
1256 freshen_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  */
1267 void InterrogateDatabase::
1268 freshen_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  */
1279 void InterrogateDatabase::
1280 freshen_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  */
1291 void InterrogateDatabase::
1292 freshen_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  */
1304 int InterrogateDatabase::
1305 lookup(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 }
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
InterrogateMakeSeq & update_make_seq(MakeSeqIndex make_seq)
Returns a non-const reference to the indicated make_seq, allowing the user to update it.
static int get_current_major_version()
Returns the major version number currently expected in interrogate database files generated by this c...
static int get_file_minor_version()
Returns the minor version number of the interrogate database file currently being read.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
const InterrogateManifest & get_manifest(ManifestIndex manifest)
Returns the manifest constant associated with the given ManifestIndex, if there is one.
static int get_current_minor_version()
Returns the minor version number currently expected in interrogate database files generated by this c...
int get_num_global_manifests()
Returns the total number of global manifest constants known to the interrogate database.
This class manages a mapping of integers to integers.
Definition: indexRemapper.h:29
void idf_output_string(ostream &out, const string &str, char whitespace)
Writes the indicated string to the output file.
TypeIndex get_all_type(int n)
Returns the index of the nth type known to the interrogate database.
bool get_error_flag()
Returns the global error flag.
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:424
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:1863
const InterrogateMakeSeq & get_make_seq(MakeSeqIndex element)
Returns the make_seq associated with the given MakeSeqIndex, if there is one.
FunctionIndex get_global_function(int n)
Returns the index of the nth global function known to the interrogate database.
Represents a synthetic method created via the MAKE_SEQ() macro.
InterrogateFunctionWrapper & update_wrapper(FunctionWrapperIndex wrapper)
Returns a non-const reference to the indicated function wrapper, allowing the user to update it.
void idf_input_string(istream &in, string &str)
Reads the given string from the input file, as previously written by output_string().
InterrogateElement & update_element(ElementIndex element)
Returns a non-const reference to the indicated data element, allowing the user to update it.
const InterrogateType & get_type(TypeIndex type)
Returns the type associated with the given TypeIndex, if there is one.
void request_module(InterrogateModuleDef *def)
Requests that the interrogate data for the given module be made available.
static InterrogateDatabase * get_ptr()
Returns the global pointer to the one InterrogateDatabase.
bool is_global() const
Returns true if the element is marked as 'global'.
ElementIndex get_global_element(int n)
Returns the index of the nth global data element known to the interrogate database.
InterrogateFunction & update_function(FunctionIndex function)
Returns a non-const reference to the indicated function, allowing the user to update it.
InterrogateManifest & update_manifest(ManifestIndex manifest)
Returns a non-const reference to the indicated manifest constant, allowing the user to update it.
This stores all of the interrogate data and handles reading the data from a disk file when necessary.
void * get_fptr(FunctionWrapperIndex wrapper)
Returns the function pointer associated with the given function wrapper, if it has a pointer availabl...
TypeIndex get_global_type(int n)
Returns the index of the nth global type known to the interrogate database.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
int get_num_global_functions()
Returns the total number of global functions known to the interrogate database.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
An internal representation of a type.
FunctionIndex get_all_function(int n)
Returns the index of the nth function known to the interrogate database.
void set_error_flag(bool error_flag)
Sets the global error flag.
void add_type(TypeIndex index, const InterrogateType &type)
Adds the indicated type to the database at the given index number.
InterrogateType & update_type(TypeIndex type)
Returns a non-const reference to the indicated type, allowing the user to update it.
static int get_file_major_version()
Returns the major version number of the interrogate database file currently being read.
An internal representation of a function.
An internal representation of a callable function.
void clear()
Removes all mappings from the object.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
void add_element(ElementIndex index, const InterrogateElement &element)
Adds the indicated data element to the database at the given index number.
void add_function(FunctionIndex index, InterrogateFunction *function)
Adds the indicated function to the database at the given index number.
ManifestIndex get_global_manifest(int n)
Returns the index of the nth global manifest constant known to the interrogate database.
An internal representation of a manifest constant.
bool is_global() const
Returns true if the type is marked as 'global'.
int get_next_index()
Returns a new index number suitable for the next thing, that will not be shared with any other index ...
const InterrogateElement & get_element(ElementIndex element)
Returns the data element associated with the given ElementIndex, if there is one.
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_types()
Returns the total number of "global" types known to the interrogate database.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool in_map(int from) const
Returns true if the given 'from' integer has been assigned a mapping, false if it has not.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
void remap_indices(const IndexRemapper &remap)
Remaps all internal index numbers according to the indicated map.
An internal representation of a data element, like a data member or a global variable.
const InterrogateFunctionWrapper & get_wrapper(FunctionWrapperIndex wrapper)
Returns the function wrapper associated with the given FunctionWrapperIndex, if there is one.
This class stores a list of directories that can be searched, in order, to locate a particular file.
Definition: dSearchPath.h:28
FunctionWrapperIndex get_wrapper_by_unique_name(const std::string &unique_name)
Looks up the function wrapper corresponding to the given unique name, if available.
int get_num_all_functions()
Returns the total number of functions 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.
bool read(std::istream &in, InterrogateModuleDef *def)
Reads a database from the indicated stream, associated with the indicated module definition and merge...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void add_make_seq(MakeSeqIndex index, const InterrogateMakeSeq &make_seq)
Adds the indicated make_seq to the database at the given index number.
void merge_with(const InterrogateType &other)
Combines type with the other similar definition.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void add_mapping(int from, int to)
Adds a mapping from the integer 'from' to 'to'.
void remove_type(TypeIndex type)
Erases the type from the database.
int get_num_all_types()
Returns the total number of types known to the interrogate database.
int get_num_global_elements()
Returns the total number of global data elements known to the interrogate database.
const InterrogateFunction & get_function(FunctionIndex function)
Returns the function associated with the given FunctionIndex, if there is one.
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...
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...
Filename find_file(const Filename &filename) const
Searches all the directories in the search list for the indicated file, in order.
void write(std::ostream &out, InterrogateModuleDef *def) const
Writes the database to the indicated stream for later reading.