Panda3D
Loading...
Searching...
No Matches
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
21using std::string;
22
23PT(InternalName) InternalName::_root;
24PT(InternalName) InternalName::_error;
25PT(InternalName) InternalName::_default;
26PT(InternalName) InternalName::_vertex;
27PT(InternalName) InternalName::_normal;
28PT(InternalName) InternalName::_tangent;
29PT(InternalName) InternalName::_binormal;
30PT(InternalName) InternalName::_texcoord;
31PT(InternalName) InternalName::_color;
32PT(InternalName) InternalName::_rotate;
33PT(InternalName) InternalName::_size;
34PT(InternalName) InternalName::_aspect_ratio;
35PT(InternalName) InternalName::_transform_blend;
36PT(InternalName) InternalName::_transform_weight;
37PT(InternalName) InternalName::_transform_index;
38PT(InternalName) InternalName::_index;
39PT(InternalName) InternalName::_world;
40PT(InternalName) InternalName::_camera;
41PT(InternalName) InternalName::_model;
42PT(InternalName) InternalName::_view;
43
44TypeHandle InternalName::_type_handle;
45TypeHandle InternalName::_texcoord_type_handle;
46
47#ifdef HAVE_PYTHON
48InternalName::PyInternTable InternalName::_py_intern_table;
49#endif
50
51InternalName::LiteralTable InternalName::_literal_table;
52LightMutex InternalName::_literal_table_lock;
53
54/**
55 * Use make() to make a new InternalName instance.
56 */
57InternalName::
58InternalName(InternalName *parent, const string &basename) :
59 _parent(parent),
60 _basename(basename)
61{
62}
63
64/**
65 *
66 */
67InternalName::
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 */
84unref() 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
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 */
111PT(InternalName) InternalName::
112append(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 */
140string InternalName::
141get_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 */
157join(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 */
177find_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 */
199get_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 */
219get_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 */
234get_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 */
252void InternalName::
253output(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 */
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 */
296PT(InternalName) InternalName::
297make(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 */
308TypedWritable *InternalName::
309make_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 */
340TypedWritable *InternalName::
341make_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 */
365write_datagram(BamWriter *manager, Datagram &me) {
366 me.add_string(get_name());
367}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition bamWriter.h:63
A class to retrieve the individual data elements previously stored in a Datagram.
std::string get_string()
Extracts a variable-length string.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
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...
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
Encodes a string name in a hash table, mapping it to a pointer.
const InternalName * get_ancestor(int n) const
Returns the ancestor with the indicated index number.
std::string join(const std::string &sep) const
Like get_name, but uses a custom separator instead of ".".
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...
static void register_with_read_factory()
Factory method to generate a InternalName object.
std::string get_net_basename(int n) const
Returns the basename of this name prefixed by the indicated number of ancestors.
const InternalName * get_top() const
Returns the oldest ancestor in the InternalName's chain, not counting the root.
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual bool unref() const
This method overrides ReferenceCount::unref() to clear the pointer from its parent's table when its r...
get_name
Returns the complete name represented by the InternalName and all of its parents.
Similar to MutexHolder, but for a light mutex.
This is a standard, non-reentrant mutex, similar to the Mutex class.
Definition lightMutex.h:41
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
get_ref_count
Returns the current reference count.
virtual bool unref() const
Explicitly decrements the reference count.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.