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  */
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  */
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  */
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  */
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  */
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  */
281 finalize(BamReader *) {
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  */
365 write_datagram(BamWriter *manager, Datagram &me) {
366  me.add_string(get_name());
367 }
DatagramIterator::get_string
std::string get_string()
Extracts a variable-length string.
Definition: datagramIterator.cxx:26
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
internalName.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pandabase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
InternalName::get_top
const InternalName * get_top() const
Returns the oldest ancestor in the InternalName's chain, not counting the root.
Definition: internalName.cxx:219
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
preparedGraphicsObjects.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
InternalName::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
Definition: internalName.cxx:365
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
InternalName::get_net_basename
std::string get_net_basename(int n) const
Returns the basename of this name prefixed by the indicated number of ancestors.
Definition: internalName.cxx:234
InternalName
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
LightMutex
This is a standard, non-reentrant mutex, similar to the Mutex class.
Definition: lightMutex.h:41
Datagram::add_string
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:219
InternalName::get_ancestor
const InternalName * get_ancestor(int n) const
Returns the ancestor with the indicated index number.
Definition: internalName.cxx:199
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
BamReader::register_finalize
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
InternalName::get_name
get_name
Returns the complete name represented by the InternalName and all of its parents.
Definition: internalName.h:61
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
ReferenceCount::test_ref_count_integrity
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
Definition: referenceCount.I:197
InternalName::register_with_read_factory
static void register_with_read_factory()
Factory method to generate a InternalName object.
Definition: internalName.cxx:270
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Factory::register_factory
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
InternalName::join
std::string join(const std::string &sep) const
Like get_name, but uses a custom separator instead of ".".
Definition: internalName.cxx:157
ReferenceCount::unref
virtual bool unref() const
Explicitly decrements the reference count.
Definition: referenceCount.I:179
InternalName::find_ancestor
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...
Definition: internalName.cxx:177
PT
PT(InternalName) InternalName
Constructs a new InternalName based on this name, with the indicated string following it.
Definition: internalName.cxx:111
InternalName::finalize
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
Definition: internalName.cxx:281
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ReferenceCount::get_ref_count
get_ref_count
Returns the current reference count.
Definition: referenceCount.h:53
InternalName::unref
virtual bool unref() const
This method overrides ReferenceCount::unref() to clear the pointer from its parent's table when its r...
Definition: internalName.cxx:84
parse_params
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