Panda3D
factoryBase.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 factoryBase.cxx
10  * @author drose
11  * @date 2000-05-08
12  */
13 
14 #include "factoryBase.h"
15 #include "indent.h"
16 #include "config_putil.h"
17 
18 /**
19  * Attempts to create a new instance of some class of the indicated type, or
20  * some derivative if necessary. If an instance of the exact type cannot be
21  * created, the specified preferred will specify which derived class will be
22  * preferred.
23  */
25 make_instance(TypeHandle handle, const FactoryParams &params) {
26  TypedObject *instance = nullptr;
27 
28  instance = make_instance_exact(handle, params);
29  if (instance == nullptr) {
30  // Can't create an exact instance; try for a derived type.
31  instance = make_instance_more_specific(handle, params);
32  }
33 
34  if (util_cat.is_debug()) {
35  util_cat.debug()
36  << "make_instance(" << handle << ", params) returns "
37  << (void *)instance;
38  if (instance != nullptr) {
39  util_cat.debug(false)
40  << ", of type " << instance->get_type();
41  }
42  util_cat.debug(false) << "\n";
43  }
44  return instance;
45 }
46 
47 /**
48  * Attempts to create an instance of the type requested, or some base type of
49  * the type requested. Returns the new instance created, or NULL if the
50  * instance could not be created.
51  */
54  TypedObject *object = make_instance_exact(handle, params);
55 
56  if (object == nullptr) {
57  // Recursively search through the entire inheritance tree until we find
58  // something we know about.
59  if (handle.get_num_parent_classes() == 0) {
60  return nullptr;
61  }
62 
63  int num_parents = handle.get_num_parent_classes();
64  for (int i = 0; i < num_parents && object == nullptr; i++) {
65  object = make_instance_more_general(handle.get_parent_class(i), params);
66  }
67  }
68 
69  if (util_cat.is_debug()) {
70  util_cat.debug()
71  << "make_instance(" << handle << ", params) returns "
72  << (void *)object;
73  if (object != nullptr) {
74  util_cat.debug(false)
75  << ", of type " << object->get_type();
76  }
77  util_cat.debug(false) << "\n";
78  }
79 
80  return object;
81 }
82 
83 /**
84  * Returns the TypeHandle given, if it is a registered type, or if it is not
85  * registered, searches for the nearest ancestor of the indicated type that is
86  * registered and returns it. If no ancestor of the indicated type is
87  * registered, returns TypeHandle::none().
88  */
91  Creators::const_iterator ci = _creators.find(handle);
92  if (ci != _creators.end()) {
93  // This type is registered.
94  return handle;
95  }
96 
97  // Recursively search through the entire inheritance tree until we find
98  // something we know about.
99  if (handle.get_num_parent_classes() == 0) {
100  return TypeHandle::none();
101  }
102 
103  int num_parents = handle.get_num_parent_classes();
104  for (int i = 0; i < num_parents; i++) {
106  if (result != TypeHandle::none()) {
107  return result;
108  }
109  }
110 
111  // No known types.
112  return TypeHandle::none();
113 }
114 
115 /**
116  * Registers a new kind of thing the Factory will be able to create.
117  *
118  * @param user_data an optional pointer to be passed along to the function.
119  */
121 register_factory(TypeHandle handle, BaseCreateFunc *func, void *user_data) {
122  nassertv(handle != TypeHandle::none());
123  nassertv(func != nullptr);
124 
125  Creator creator;
126  creator._func = func;
127  creator._user_data = user_data;
128  _creators[handle] = creator;
129 }
130 
131 /**
132  * Returns the number of different types the Factory knows how to create.
133  */
135 get_num_types() const {
136  return _creators.size();
137 }
138 
139 /**
140  * Returns the nth type the Factory knows how to create. This is not a
141  * terribly efficient function; it's included primarily for debugging output.
142  * Normally you wouldn't need to traverse the list of the Factory's types.
143  */
145 get_type(size_t n) const {
146  nassertr(n < get_num_types(), TypeHandle::none());
147  Creators::const_iterator ci;
148  for (ci = _creators.begin(); ci != _creators.end(); ++ci) {
149  if (n == 0) {
150  return (*ci).first;
151  }
152  n--;
153  }
154 
155  // We shouldn't get here.
156  nassertr(false, TypeHandle::none());
157  return TypeHandle::none();
158 }
159 
160 /**
161  * Empties the list of preferred types.
162  */
164 clear_preferred() {
165  _preferred.clear();
166 }
167 
168 /**
169  * Adds the indicated type to the end of the list of preferred types. On the
170  * next call to make_instance(), if the exact type requested cannot be
171  * created, the preferred types are first tried in the order specified.
172  */
174 add_preferred(TypeHandle handle) {
175  nassertv(handle != TypeHandle::none());
176  _preferred.push_back(handle);
177 }
178 
179 /**
180  * Returns the number of types added to the preferred-type list.
181  */
183 get_num_preferred() const {
184  return _preferred.size();
185 }
186 
187 /**
188  * Returns the nth type added to the preferred-type list.
189  */
191 get_preferred(size_t n) const {
192  nassertr(n < get_num_preferred(), TypeHandle::none());
193  return _preferred[n];
194 }
195 
196 /**
197  * Writes a list of all known types the Factory can create to the indicated
198  * output stream, one per line.
199  */
201 write_types(std::ostream &out, int indent_level) const {
202  Creators::const_iterator ci;
203  for (ci = _creators.begin(); ci != _creators.end(); ++ci) {
204  indent(out, indent_level) << (*ci).first << "\n";
205  }
206 }
207 
208 /**
209  * Attempts to create an instance of the exact type requested by the given
210  * handle. Returns the new instance created, or NULL if the instance could
211  * not be created.
212  */
213 TypedObject *FactoryBase::
214 make_instance_exact(TypeHandle handle, FactoryParams params) {
215  Creators::const_iterator ci = _creators.find(handle);
216  if (ci == _creators.end()) {
217  return nullptr;
218  }
219 
220  Creator creator = (*ci).second;
221  nassertr(creator._func != nullptr, nullptr);
222  params._user_data = creator._user_data;
223  return (*creator._func)(params);
224 }
225 
226 /**
227  * Attempts to create an instance of some derived type of the type requested
228  * by the given handle. Returns the new instance created, or NULL if the
229  * instance could not be created.
230  */
231 TypedObject *FactoryBase::
232 make_instance_more_specific(TypeHandle handle, FactoryParams params) {
233  // First, walk through the established preferred list. Maybe one of these
234  // qualifies.
235 
236  for (TypeHandle ptype : _preferred) {
237  if (ptype.is_derived_from(handle)) {
238  TypedObject *object = make_instance_exact(ptype, params);
239  if (object != nullptr) {
240  return object;
241  }
242  }
243  }
244 
245  // No, we couldn't create anything on the preferred list, so create the
246  // first thing we know about that derives from the indicated type.
247  Creators::const_iterator ci;
248  for (ci = _creators.begin(); ci != _creators.end(); ++ci) {
249  TypeHandle ctype = (*ci).first;
250  if (ctype.is_derived_from(handle)) {
251  Creator creator = (*ci).second;
252  nassertr(creator._func != nullptr, nullptr);
253  params._user_data = creator._user_data;
254  TypedObject *object = (*creator._func)(params);
255  if (object != nullptr) {
256  return object;
257  }
258  }
259  }
260 
261  return nullptr;
262 }
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
config_putil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle::is_derived_from
bool is_derived_from(TypeHandle parent, TypedObject *object=nullptr) const
Returns true if this type is derived from the indicated type, false otherwise.
Definition: typeHandle.I:105
FactoryBase::make_instance
TypedObject * make_instance(TypeHandle handle, const FactoryParams &params)
Attempts to create a new instance of some class of the indicated type, or some derivative if necessar...
Definition: factoryBase.cxx:25
FactoryBase::get_num_types
size_t get_num_types() const
Returns the number of different types the Factory knows how to create.
Definition: factoryBase.cxx:135
FactoryBase::register_factory
void register_factory(TypeHandle handle, BaseCreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factoryBase.cxx:121
FactoryBase::get_num_preferred
size_t get_num_preferred() const
Returns the number of types added to the preferred-type list.
Definition: factoryBase.cxx:183
TypeHandle::get_parent_class
get_parent_class
Returns the nth parent class of this type.
Definition: typeHandle.h:137
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
FactoryBase::clear_preferred
void clear_preferred()
Empties the list of preferred types.
Definition: factoryBase.cxx:164
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
FactoryBase::write_types
void write_types(std::ostream &out, int indent_level=0) const
Writes a list of all known types the Factory can create to the indicated output stream,...
Definition: factoryBase.cxx:201
TypeHandle::get_num_parent_classes
get_num_parent_classes
Returns the number of parent classes that this type is known to have.
Definition: typeHandle.h:137
FactoryBase::find_registered_type
TypeHandle find_registered_type(TypeHandle handle)
Returns the TypeHandle given, if it is a registered type, or if it is not registered,...
Definition: factoryBase.cxx:90
factoryBase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
FactoryBase::get_preferred
TypeHandle get_preferred(size_t n) const
Returns the nth type added to the preferred-type list.
Definition: factoryBase.cxx:191
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
FactoryBase::add_preferred
void add_preferred(TypeHandle handle)
Adds the indicated type to the end of the list of preferred types.
Definition: factoryBase.cxx:174
FactoryBase::make_instance_more_general
TypedObject * make_instance_more_general(TypeHandle handle, const FactoryParams &params)
Attempts to create an instance of the type requested, or some base type of the type requested.
Definition: factoryBase.cxx:53
TypedObject
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
Definition: typedObject.h:88
FactoryBase::get_type
TypeHandle get_type(size_t n) const
Returns the nth type the Factory knows how to create.
Definition: factoryBase.cxx:145