Coin: SoSubField.h Source File

| Coin3D is Free Software, published under the BSD 3-clause license. | https://coin3d.github.io https://www.kongsberg.com/en/kogt/

SoSubField.h
1#ifndef COIN_SOSUBFIELD_H
2#define COIN_SOSUBFIELD_H
3
4/**************************************************************************\
5 * Copyright (c) Kongsberg Oil & Gas Technologies AS
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * Neither the name of the copyright holder nor the names of its
20 * contributors may be used to endorse or promote products derived from
21 * this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34\**************************************************************************/
35
36#include <Inventor/SbBasic.h> // for SO__QUOTE() definition
37#include <Inventor/SbName.h> // SoType::createType() needs to know SbName.
38#include <Inventor/C/tidbits.h>
39#include <cassert>
40
41#ifndef COIN_INTERNAL
42// Added to be Inventor compliant.
43#include <Inventor/fields/SoField.h>
44#include <Inventor/SoInput.h>
45#include <Inventor/SoOutput.h>
46#endif // !COIN_INTERNAL
47
48/**************************************************************************
49 *
50 * Header macros for single-value fields.
51 *
52 **************************************************************************/
53
54#define SO_SFIELD_CONSTRUCTOR_HEADER(_class_) \
55public: \
56 _class_(void); \
57 virtual ~_class_()
58
59
60#define SO_SFIELD_REQUIRED_HEADER(_class_) \
61private: \
62 static SoType classTypeId; \
63 static void atexit_cleanup(void) { SoType::removeType(_class_::classTypeId.getName()); _class_::classTypeId STATIC_SOTYPE_INIT; } \
64public: \
65 static void * createInstance(void); \
66 static SoType getClassTypeId(void); \
67 virtual SoType getTypeId(void) const; \
68 \
69 virtual void copyFrom(const SoField & field); \
70 const _class_ & operator=(const _class_ & field); \
71 virtual SbBool isSame(const SoField & field) const
72
73
74#define PRIVATE_SFIELD_IO_HEADER() \
75private: \
76 virtual SbBool readValue(SoInput * in); \
77 virtual void writeValue(SoOutput * out) const
78
79
80#define SO_SFIELD_VALUE_HEADER(_class_, _valtype_, _valref_) \
81 PRIVATE_SFIELD_IO_HEADER(); \
82protected: \
83 _valtype_ value; \
84 \
85public: \
86 _valref_ getValue(void) const { this->evaluate(); return this->value; } \
87 void setValue(_valref_ newvalue); \
88 _valref_ operator=(_valref_ newvalue) { this->setValue(newvalue); return this->value; } \
89 \
90 int operator==(const _class_ & field) const; \
91 int operator!=(const _class_ & field) const { return ! operator==(field); }
92
93
94// FIXME: is really the operator=() definition below necessary?
95// 19991226 mortene.
96#define SO_SFIELD_DERIVED_VALUE_HEADER(_class_, _valtype_, _valref_) \
97 PRIVATE_SFIELD_IO_HEADER(); \
98public: \
99 _valref_ operator=(_valref_ newvalue) { this->setValue(newvalue); return this->value; }
100
101
102
103#define SO_SFIELD_HEADER(_class_, _valtype_, _valref_) \
104 SO_SFIELD_CONSTRUCTOR_HEADER(_class_); \
105 SO_SFIELD_REQUIRED_HEADER(_class_); \
106 SO_SFIELD_VALUE_HEADER(_class_, _valtype_, _valref_)
107
108
109#define SO_SFIELD_DERIVED_HEADER(_class_, _valtype_, _valref_) \
110 SO_SFIELD_CONSTRUCTOR_HEADER(_class_); \
111 SO_SFIELD_REQUIRED_HEADER(_class_); \
112 SO_SFIELD_DERIVED_VALUE_HEADER(_class_, _valtype_, _valref_)
113
114
115
116/**************************************************************************
117 *
118 * Source macros for single-value fields.
119 *
120 **************************************************************************/
121
122#define PRIVATE_FIELD_INIT_CLASS(_class_, _classname_, _parent_, _createfunc_) \
123 do { \
124 /* Make sure superclass get initialized before subclass. */ \
125 assert(_parent_::getClassTypeId() != SoType::badType()); \
126 /* Make sure we only initialize once. */ \
127 assert(_class_::classTypeId == SoType::badType()); \
128 _class_::classTypeId = \
129 SoType::createType(_parent_::getClassTypeId(), _classname_, _createfunc_); \
130 cc_coin_atexit_static_internal \
131 ( \
132 _class_::atexit_cleanup \
133 ); \
134 } WHILE_0
135
136
137
138#define SO_SFIELD_INIT_CLASS(_class_, _parent_) \
139 do { \
140 const char * classname = SO__QUOTE(_class_); \
141 PRIVATE_FIELD_INIT_CLASS(_class_, classname, _parent_, &_class_::createInstance); \
142 } WHILE_0
143
144#define SO_SFIELD_CONSTRUCTOR_SOURCE(_class_) \
145_class_::_class_(void) { assert(_class_::classTypeId != SoType::badType()); } \
146_class_::~_class_() { }
147
148
149
150#define SO_SFIELD_VALUE_SOURCE(_class_, _valtype_, _valref_) \
151void \
152_class_::setValue(_valref_ valuearg) { \
153 this->value = valuearg; \
154 this->valueChanged(); \
155} \
156 \
157SbBool \
158_class_::operator==(const _class_ & field) const \
159{ \
160 return (this->getValue() == field.getValue()); \
161}
162
163
164#define PRIVATE_TYPEID_SOURCE(_class_) \
165 \
166 \
171SoType _class_::getTypeId(void) const { return _class_::classTypeId; } \
172 \
173 \
177SoType _class_::getClassTypeId(void) { return _class_::classTypeId; } \
178 \
182void * _class_::createInstance(void) { return new _class_; } \
183SoType _class_::classTypeId STATIC_SOTYPE_INIT
184
185
186#define PRIVATE_EQUALITY_SOURCE(_class_) \
187void \
188_class_::copyFrom(const SoField & field) \
189{ \
190 this->operator=(static_cast<const _class_ &>(field)); \
191} \
192 \
193SbBool \
194_class_::isSame(const SoField & field) const \
195{ \
196 if (field.getTypeId() != this->getTypeId()) return FALSE; \
197 return this->operator==(static_cast<const _class_ &>(field)); \
198}
199
200
201
202#define SO_SFIELD_REQUIRED_SOURCE(_class_) \
203PRIVATE_TYPEID_SOURCE(_class_); \
204PRIVATE_EQUALITY_SOURCE(_class_); \
205 \
206const _class_ & \
207_class_::operator=(const _class_ & field) \
208{ \
209 this->setValue(field.getValue()); \
210 return *this; \
211}
212
213
214
215#define SO_SFIELD_SOURCE(_class_, _valtype_, _valref_) \
216 SO_SFIELD_CONSTRUCTOR_SOURCE(_class_); \
217 SO_SFIELD_VALUE_SOURCE(_class_, _valtype_, _valref_); \
218 SO_SFIELD_REQUIRED_SOURCE(_class_)
219
220
221
222#define SO_SFIELD_DERIVED_SOURCE(_class_, _valtype_, _valref_) \
223 SO_SFIELD_CONSTRUCTOR_SOURCE(_class_); \
224 SO_SFIELD_REQUIRED_SOURCE(_class_)
225
226
227/**************************************************************************
228 *
229 * Header macros for multiple-value fields.
230 *
231 **************************************************************************/
232
233#define PRIVATE_MFIELD_IO_HEADER() \
234private: \
235 virtual SbBool read1Value(SoInput * in, int idx); \
236 virtual void write1Value(SoOutput * out, int idx) const
237
238
239
240#define SO_MFIELD_VALUE_HEADER(_class_, _valtype_, _valref_) \
241 PRIVATE_MFIELD_IO_HEADER(); \
242protected: \
243 virtual void deleteAllValues(void); \
244 virtual void copyValue(int to, int from); \
245 virtual int fieldSizeof(void) const; \
246 virtual void * valuesPtr(void); \
247 virtual void setValuesPtr(void * ptr); \
248 virtual void allocValues(int num); \
249 \
250 _valtype_ * values; \
251public: \
252 _valref_ operator[](const int idx) const \
253 { this->evaluate(); return this->values[idx]; } \
254 \
257 const _valtype_ * getValues(const int start) const \
258 { this->evaluate(); return const_cast<const _valtype_ *>(this->values + start); } \
259 int find(_valref_ value, SbBool addifnotfound = FALSE); \
260 void setValues(const int start, const int num, const _valtype_ * newvals); \
261 void set1Value(const int idx, _valref_ value); \
262 void setValue(_valref_ value); \
263 _valref_ operator=(_valref_ val) { this->setValue(val); return val; } \
264 SbBool operator==(const _class_ & field) const; \
265 SbBool operator!=(const _class_ & field) const { return !operator==(field); } \
266 _valtype_ * startEditing(void) { this->evaluate(); return this->values; } \
267 void finishEditing(void) { this->valueChanged(); }
268
269#define SO_MFIELD_DERIVED_VALUE_HEADER(_class_, _valtype_, _valref_) \
270 PRIVATE_MFIELD_IO_HEADER(); \
271public: \
272 _valref_ operator=(_valref_ val) { this->setValue(val); return val; }
273
274
275
276#define SO_MFIELD_HEADER(_class_, _valtype_, _valref_) \
277 SO_SFIELD_CONSTRUCTOR_HEADER(_class_); \
278 SO_SFIELD_REQUIRED_HEADER(_class_); \
279 SO_MFIELD_VALUE_HEADER(_class_, _valtype_, _valref_)
280
281
282
283#define SO_MFIELD_DERIVED_HEADER(_class_, _valtype_, _valref_) \
284 SO_SFIELD_CONSTRUCTOR_HEADER(_class_); \
285 SO_SFIELD_REQUIRED_HEADER(_class_); \
286 SO_MFIELD_DERIVED_VALUE_HEADER(_class_, _valtype_, _valref_)
287
288#define SO_MFIELD_SETVALUESPOINTER_HEADER(_valtype_) \
289 void setValuesPointer(const int num, const _valtype_ * userdata); \
290 void setValuesPointer(const int num, _valtype_ * userdata)
291
292
293/**************************************************************************
294 *
295 * Source macros for multiple-value fields.
296 *
297 **************************************************************************/
298
299
300#define SO_MFIELD_INIT_CLASS(_class_, _parent_) \
301 SO_SFIELD_INIT_CLASS(_class_, _parent_)
302
303
304
305#define SO_MFIELD_CONSTRUCTOR_SOURCE(_class_) \
306_class_::_class_(void) \
307{ \
308 assert(_class_::classTypeId != SoType::badType()); \
309 this->values = NULL; \
310} \
311 \
312_class_::~_class_(void) \
313{ \
314 this->enableNotify(FALSE); /* Avoid notifying destructed containers. */ \
315 this->deleteAllValues(); \
316}
317
318
319
320#define SO_MFIELD_DERIVED_CONSTRUCTOR_SOURCE(_class_) \
321_class_::_class_(void) { } \
322_class_::~_class_(void) { }
323
324
325
326#define SO_MFIELD_REQUIRED_SOURCE(_class_) \
327PRIVATE_TYPEID_SOURCE(_class_); \
328PRIVATE_EQUALITY_SOURCE(_class_); \
329const _class_ & \
330_class_::operator=(const _class_ & field) \
331{ \
332 /* The allocValues() call is needed, as setValues() doesn't */ \
333 /* necessarily make the field's getNum() size become the same */ \
334 /* as the second argument (only if it expands on the old size). */ \
335 this->allocValues(field.getNum()); \
336 \
337 this->setValues(0, field.getNum(), field.getValues(0)); \
338 return *this; \
339}
340
341
342
343#define SO_MFIELD_VALUE_SOURCE(_class_, _valtype_, _valref_) \
344int \
345_class_::fieldSizeof(void) const \
346{ \
347 return sizeof(_valtype_); \
348} \
349 \
350void * \
351_class_::valuesPtr(void) \
352{ \
353 return static_cast<void *>(this->values); \
354} \
355 \
356void \
357_class_::setValuesPtr(void * ptr) \
358{ \
359 this->values = static_cast<_valtype_ *>(ptr); \
360} \
361 \
362int \
363_class_::find(_valref_ value, SbBool addifnotfound) \
364{ \
365 evaluate(); \
366 for (int i=0; i < this->num; i++) if (this->values[i] == value) return i; \
367 \
368 if (addifnotfound) this->set1Value(this->num, value); \
369 return -1; \
370} \
371 \
372void \
373_class_::setValues(const int start, const int numarg, const _valtype_ * newvals) \
374{ \
375 if (start+numarg > this->maxNum) this->allocValues(start+numarg); \
376 else if (start+numarg > this->num) this->num = start+numarg; \
377 \
378 for (int i=0; i < numarg; i++) \
379 this->values[i+start] = static_cast<const _valtype_>(newvals[i]); \
380 this->setChangedIndices(start, numarg); \
381 this->valueChanged(); \
382 this->setChangedIndices(); \
383} \
384 \
385void \
386_class_::set1Value(const int idx, _valref_ value) \
387{ \
388 if (idx+1 > this->maxNum) this->allocValues(idx+1); \
389 else if (idx+1 > this->num) this->num = idx+1; \
390 this->values[idx] = value; \
391 this->setChangedIndex(idx); \
392 this->valueChanged(); \
393 this->setChangedIndices(); \
394} \
395 \
396void \
397_class_::setValue(_valref_ value) \
398{ \
399 this->allocValues(1); \
400 this->values[0] = value; \
401 this->setChangedIndex(0); \
402 this->valueChanged(); \
403 this->setChangedIndices(); \
404} \
405 \
406SbBool \
407_class_::operator==(const _class_ & field) const \
408{ \
409 if (this == &field) return TRUE; \
410 if (this->getNum() != field.getNum()) return FALSE; \
411 \
412 const _valtype_ * const lhs = this->getValues(0); \
413 const _valtype_ * const rhs = field.getValues(0); \
414 for (int i = 0; i < this->num; i++) if (lhs[i] != rhs[i]) return FALSE; \
415 return TRUE; \
416} \
417 \
418 \
419void \
420_class_::deleteAllValues(void) \
421{ \
422 this->setNum(0); \
423} \
424 \
425 \
426void \
427_class_::copyValue(int to, int from) \
428{ \
429 this->values[to] = this->values[from]; \
430}
431
432
433#define SO_MFIELD_ALLOC_SOURCE(_class_, _valtype_) \
434void \
435_class_::allocValues(int newnum) \
436{ \
437 /* Important notice: the "malloc-version" of this method is found */ \
438 /* in SoMField.cpp. If you make modifications here, do check whether */ \
439 /* or not they should be matched with modifications in that method */ \
440 /* aswell. */ \
441 \
442 /* these must be declared here as a gcc 4.0.0 bug workaround */ \
443 int i; \
444 int oldmaxnum; \
445 _valtype_ * newblock; \
446 assert(newnum >= 0); \
447 \
448 this->setChangedIndices(); \
449 if (newnum == 0) { \
450 if (!this->userDataIsUsed) delete[] this->values; /* don't fetch pointer through valuesPtr() (avoids void* cast) */ \
451 this->setValuesPtr(NULL); \
452 this->maxNum = 0; \
453 this->userDataIsUsed = FALSE; \
454 } \
455 else if (newnum > this->maxNum || newnum < this->num) { \
456 if (this->valuesPtr()) { \
457 \
458 /* Allocation strategy is to repeatedly double the size of the */ \
459 /* allocated block until it will at least match the requested size. */ \
460 /* (Unless the requested size is less than what we've got, */ \
461 /* then we'll repeatedly halve the allocation size.) */ \
462 /* */ \
463 /* I think this will handle both cases quite gracefully: */ \
464 /* 1) newnum > this->maxNum, 2) newnum < num */ \
465 oldmaxnum = this->maxNum; \
466 while (newnum > this->maxNum) this->maxNum *= 2; \
467 while ((this->maxNum / 2) >= newnum) this->maxNum /= 2; \
468 \
469 if (oldmaxnum != this->maxNum) { \
470 newblock = new _valtype_[this->maxNum]; \
471 \
472 for (i=0; i < SbMin(this->num, newnum); i++) \
473 newblock[i] = this->values[i]; \
474 \
475 delete[] this->values; /* don't fetch pointer through valuesPtr() (avoids void* cast) */ \
476 this->setValuesPtr(newblock); \
477 this->userDataIsUsed = FALSE; \
478 } \
479 } \
480 else { \
481 this->setValuesPtr(new _valtype_[newnum]); \
482 this->userDataIsUsed = FALSE; \
483 this->maxNum = newnum; \
484 } \
485 } \
486 \
487 this->num = newnum; \
488}
489
490
491
492#define SO_MFIELD_MALLOC_SOURCE(_class_, _valtype_) \
493void \
494_class_::allocValues(int number) \
495{ \
496 SoMField::allocValues(number); \
497}
498
499
500
501#define SO_MFIELD_SOURCE_MALLOC(_class_, _valtype_, _valref_) \
502 SO_MFIELD_REQUIRED_SOURCE(_class_); \
503 SO_MFIELD_CONSTRUCTOR_SOURCE(_class_); \
504 SO_MFIELD_MALLOC_SOURCE(_class_, _valtype_); \
505 SO_MFIELD_VALUE_SOURCE(_class_, _valtype_, _valref_)
506
507
508
509#define SO_MFIELD_SOURCE(_class_, _valtype_, _valref_) \
510 SO_MFIELD_REQUIRED_SOURCE(_class_); \
511 SO_MFIELD_CONSTRUCTOR_SOURCE(_class_); \
512 SO_MFIELD_ALLOC_SOURCE(_class_, _valtype_); \
513 SO_MFIELD_VALUE_SOURCE(_class_, _valtype_, _valref_)
514
515
516#define SO_MFIELD_DERIVED_SOURCE(_class_, _valtype_, _valref_) \
517 SO_MFIELD_REQUIRED_SOURCE(_class_); \
518 SO_MFIELD_DERIVED_CONSTRUCTOR_SOURCE(_class_)
519
520#define SO_MFIELD_SETVALUESPOINTER_SOURCE(_class_, _valtype_, _usertype_) \
521void \
522_class_::setValuesPointer(const int numarg, _usertype_ * userdata) \
523{ \
524 this->makeRoom(0); \
525 if (numarg > 0 && userdata) { \
526 this->values = reinterpret_cast<_valtype_*>(userdata); /* reinterpret_cast is needed for certain special uses of this function, such as SoMFColor */ \
527 this->userDataIsUsed = TRUE; \
528 this->num = this->maxNum = numarg; \
529 this->valueChanged(); \
530 } \
531} \
532void \
533_class_::setValuesPointer(const int numarg, const _usertype_ * userdata) \
534{ \
535 this->setValuesPointer(numarg, const_cast<_usertype_*>(userdata)); \
536}
537
538#endif // !COIN_SOSUBFIELD_H