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  */
120 void FactoryBase::
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  */
134 size_t FactoryBase::
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  */
163 void FactoryBase::
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  */
173 void FactoryBase::
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  */
182 size_t FactoryBase::
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  */
200 void FactoryBase::
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 }
size_t get_num_types() const
Returns the number of different types the Factory knows how to create.
TypeHandle get_type(size_t n) const
Returns the nth type the Factory knows how to create.
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
size_t get_num_preferred() const
Returns the number of types added to the preferred-type list.
void register_factory(TypeHandle handle, BaseCreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
Definition: typedObject.h:88
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void clear_preferred()
Empties the list of preferred 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,...
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
get_parent_class
Returns the nth parent class of this type.
Definition: typeHandle.h:137
TypeHandle get_preferred(size_t n) const
Returns the nth type added to the preferred-type list.
get_num_parent_classes
Returns the number of parent classes that this type is known to have.
Definition: typeHandle.h:137
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void add_preferred(TypeHandle handle)
Adds the indicated type to the end of the list of preferred types.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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