Panda3D
internalName.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 internalName.cxx
10  * @author masad
11  * @date 2004-07-15
12  */
13 
14 #include "pandabase.h"
15 #include "internalName.h"
16 #include "datagram.h"
17 #include "datagramIterator.h"
18 #include "bamReader.h"
20 
21 using std::string;
22 
23 PT(InternalName) InternalName::_root;
24 PT(InternalName) InternalName::_error;
25 PT(InternalName) InternalName::_default;
26 PT(InternalName) InternalName::_vertex;
27 PT(InternalName) InternalName::_normal;
28 PT(InternalName) InternalName::_tangent;
29 PT(InternalName) InternalName::_binormal;
30 PT(InternalName) InternalName::_texcoord;
31 PT(InternalName) InternalName::_color;
32 PT(InternalName) InternalName::_rotate;
33 PT(InternalName) InternalName::_size;
34 PT(InternalName) InternalName::_aspect_ratio;
35 PT(InternalName) InternalName::_transform_blend;
36 PT(InternalName) InternalName::_transform_weight;
37 PT(InternalName) InternalName::_transform_index;
38 PT(InternalName) InternalName::_index;
39 PT(InternalName) InternalName::_world;
40 PT(InternalName) InternalName::_camera;
41 PT(InternalName) InternalName::_model;
42 PT(InternalName) InternalName::_view;
43 
44 TypeHandle InternalName::_type_handle;
45 TypeHandle InternalName::_texcoord_type_handle;
46 
47 #ifdef HAVE_PYTHON
48 InternalName::PyInternTable InternalName::_py_intern_table;
49 #endif
50 
51 InternalName::LiteralTable InternalName::_literal_table;
52 LightMutex InternalName::_literal_table_lock;
53 
54 /**
55  * Use make() to make a new InternalName instance.
56  */
57 InternalName::
58 InternalName(InternalName *parent, const string &basename) :
59  _parent(parent),
60  _basename(basename)
61 {
62 }
63 
64 /**
65  *
66  */
67 InternalName::
68 ~InternalName() {
69 #ifndef NDEBUG
70  if (_parent != nullptr) {
71  // unref() should have removed us from our parent's table already.
72  LightMutexHolder holder(_parent->_name_table_lock);
73  NameTable::iterator ni = _parent->_name_table.find(_basename);
74  nassertv(ni == _parent->_name_table.end());
75  }
76 #endif
77 }
78 
79 /**
80  * This method overrides ReferenceCount::unref() to clear the pointer from its
81  * parent's table when its reference count goes to zero.
82  */
83 bool InternalName::
84 unref() const {
85  if (_parent == nullptr) {
86  // No parent; no problem. This is the root InternalName. Actually, this
87  // probably shouldn't be destructing, but I guess it might at application
88  // shutdown.
90  }
91 
92  LightMutexHolder holder(_parent->_name_table_lock);
93 
94  if (ReferenceCount::unref()) {
95  return true;
96  }
97 
98  // The reference count has just reached zero.
99  NameTable::iterator ni = _parent->_name_table.find(_basename);
100  nassertr(ni != _parent->_name_table.end(), false);
101  _parent->_name_table.erase(ni);
102 
103  return false;
104 }
105 
106 /**
107  * Constructs a new InternalName based on this name, with the indicated string
108  * following it. This is a cheaper way to construct a hierarchical name than
109  * InternalName::make(parent->get_name() + ".basename").
110  */
111 PT(InternalName) InternalName::
112 append(const string &name) {
114 
115  if (name.empty()) {
116  return this;
117  }
118 
119  size_t dot = name.rfind('.');
120  if (dot != string::npos) {
121  return append(name.substr(0, dot))->append(name.substr(dot + 1));
122  }
123 
124  LightMutexHolder holder(_name_table_lock);
125 
126  NameTable::iterator ni = _name_table.find(name);
127  if (ni != _name_table.end()) {
128  return (*ni).second;
129  }
130 
131  InternalName *internal_name = new InternalName(this, name);
132  _name_table[name] = internal_name;
133  return internal_name;
134 }
135 
136 /**
137  * Returns the complete name represented by the InternalName and all of its
138  * parents.
139  */
140 string InternalName::
141 get_name() const {
142  if (_parent == get_root()) {
143  return _basename;
144 
145  } else if (_parent == nullptr) {
146  return string();
147 
148  } else {
149  return _parent->get_name() + "." + _basename;
150  }
151 }
152 
153 /**
154  * Like get_name, but uses a custom separator instead of ".".
155  */
156 string InternalName::
157 join(const string &sep) const {
158  if (_parent == get_root()) {
159  return _basename;
160 
161  } else if (_parent == nullptr) {
162  return string();
163 
164  } else {
165  return _parent->join(sep) + sep + _basename;
166  }
167 }
168 
169 /**
170  * Returns the index of the ancestor with the indicated basename, or -1 if no
171  * ancestor has that basename. Returns 0 if this name has the basename.
172  *
173  * This index value may be passed to get_ancestor() or get_net_basename() to
174  * retrieve more information about the indicated name.
175  */
176 int InternalName::
177 find_ancestor(const string &basename) const {
179 
180  if (_basename == basename) {
181  return 0;
182 
183  } else if (_parent != nullptr) {
184  int index = _parent->find_ancestor(basename);
185  if (index >= 0) {
186  return index + 1;
187  }
188  }
189 
190  return -1;
191 }
192 
193 /**
194  * Returns the ancestor with the indicated index number. 0 is this name
195  * itself, 1 is the name's parent, 2 is the parent's parent, and so on. If
196  * there are not enough ancestors, returns the root InternalName.
197  */
199 get_ancestor(int n) const {
201 
202  if (n == 0) {
203  return this;
204 
205  } else if (_parent != nullptr) {
206  return _parent->get_ancestor(n - 1);
207 
208  } else {
209  return get_root();
210  }
211 }
212 
213 /**
214  * Returns the oldest ancestor in the InternalName's chain, not counting the
215  * root. This will be the first name in the string, e.g. "texcoord.foo.bar"
216  * will return the InternalName "texcoord".
217  */
219 get_top() const {
221 
222  if (_parent != nullptr && _parent != get_root()) {
223  return _parent->get_top();
224  }
225  return this;
226 }
227 
228 /**
229  * Returns the basename of this name prefixed by the indicated number of
230  * ancestors. 0 is this name's basename, 1 is parent.basename, 2 is
231  * grandparent.parent.basename, and so on.
232  */
233 string InternalName::
234 get_net_basename(int n) const {
235  if (n < 0) {
236  return "";
237 
238  } else if (n == 0) {
239  return _basename;
240 
241  } else if (_parent != nullptr && _parent != get_root()) {
242  return _parent->get_net_basename(n - 1) + "." + _basename;
243 
244  } else {
245  return _basename;
246  }
247 }
248 
249 /**
250  *
251  */
252 void InternalName::
253 output(std::ostream &out) const {
254  if (_parent == get_root()) {
255  out << _basename;
256 
257  } else if (_parent == nullptr) {
258  out << "(root)";
259 
260  } else {
261  _parent->output(out);
262  out << '.' << _basename;
263  }
264 }
265 
266 /**
267  * Factory method to generate a InternalName object
268  */
269 void InternalName::
271  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
272  BamReader::get_factory()->register_factory(_texcoord_type_handle, make_texcoord_from_bam);
273 }
274 
275 /**
276  * Called by the BamReader to perform any final actions needed for setting up
277  * the object after all objects have been read and all pointers have been
278  * completed.
279  */
280 void InternalName::
282  // Unref the pointer that we explicitly reffed in make_from_bam().
283  unref();
284 
285  // We should never get back to zero after unreffing our own count, because
286  // we expect to have been stored in a pointer somewhere. If we do get to
287  // zero, it's a memory leak; the way to avoid this is to call unref_delete()
288  // above instead of unref(), but this is dangerous to do from within a
289  // virtual function.
290  nassertv(get_ref_count() != 0);
291 }
292 
293 /**
294  * Make using a string and an integer. Concatenates the two.
295  */
296 PT(InternalName) InternalName::
297 make(const string &name, int index) {
298  std::ostringstream full;
299  full << name << index;
300  return make(full.str());
301 }
302 
303 /**
304  * This function is called by the BamReader's factory when a new object of
305  * type InternalName is encountered in the Bam file. It should create the
306  * InternalName and extract its information from the file.
307  */
308 TypedWritable *InternalName::
309 make_from_bam(const FactoryParams &params) {
310  // The process of making a InternalName is slightly different than making
311  // other Writable objects. That is because all creation of InternalNames
312  // should be done through the make() constructor.
313  DatagramIterator scan;
314  BamReader *manager;
315 
316  parse_params(params, scan, manager);
317 
318  // The name is the only thing written to the data stream.
319  string name = scan.get_string();
320 
321  // Make a new InternalName with that name (or get the previous one if there
322  // is one already).
323  PT(InternalName) me = make(name);
324 
325  // But now we have a problem, since we have to hold the reference count and
326  // there's no way to return a TypedWritable while still holding the
327  // reference count! We work around this by explicitly upping the count, and
328  // also setting a finalize() callback to down it later.
329  me->ref();
330  manager->register_finalize(me);
331 
332  return me.p();
333 }
334 
335 /**
336  * This is a temporary method; it exists only to support old bam files (4.11
337  * through 4.17) generated before we renamed this class from TexCoordName to
338  * InternalName.
339  */
340 TypedWritable *InternalName::
341 make_texcoord_from_bam(const FactoryParams &params) {
342  DatagramIterator scan;
343  BamReader *manager;
344  parse_params(params, scan, manager);
345 
346  string name = scan.get_string();
347  PT(InternalName) me;
348  if (name == "default") {
349  me = get_texcoord();
350  } else {
351  me = get_texcoord_name(name);
352  }
353 
354  me->ref();
355  manager->register_finalize(me);
356 
357  return me.p();
358 }
359 
360 /**
361  * Function to write the important information in the particular object to a
362  * Datagram
363  */
364 void InternalName::
366  me.add_string(get_name());
367 }
std::string join(const std::string &sep) const
Like get_name, but uses a custom separator instead of ".".
get_ref_count
Returns the current reference count.
const std::string & get_name() const
Returns the name of the PreparedGraphicsObjects structure.
const InternalName * get_top() const
Returns the oldest ancestor in the InternalName's chain, not counting the root.
static void register_with_read_factory()
Factory method to generate a InternalName object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
std::string get_net_basename(int n) const
Returns the basename of this name prefixed by the indicated number of ancestors.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
std::string get_string()
Extracts a variable-length string.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
const InternalName * get_ancestor(int n) const
Returns the ancestor with the indicated index number.
Similar to MutexHolder, but for a light mutex.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:219
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:808
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
int find_ancestor(const std::string &basename) const
Returns the index of the ancestor with the indicated basename, or -1 if no ancestor has that basename...
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
This is a standard, non-reentrant mutex, similar to the Mutex class.
Definition: lightMutex.h:39
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PT(InternalName) InternalName
Constructs a new InternalName based on this name, with the indicated string following it.
virtual bool unref() const
This method overrides ReferenceCount::unref() to clear the pointer from its parent's table when its r...
virtual bool unref() const
Explicitly decrements the reference count.