/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ //osgIntrospection - Copyright (C) 2005 Marco Jez #ifndef OSGINTROSPECTION_VALUE_ #define OSGINTROSPECTION_VALUE_ #include #include #include #include #include #include namespace osgIntrospection { class Type; class OSGINTROSPECTION_EXPORT Value { public: /// Default constructor. Initializes internal structures /// so that the Type returned by getType() is typeof(void), /// and the value is empty so that isEmpty() returns true. /// Be careful when using empty values, as some operations /// on them may throw an exception. inline Value(); /// Direct initialization constructor for void pointers. /// Although one of the constructor templates below could /// certainly handle void pointers as well, we need to treat /// them separately because void* can't be dereferenced. inline Value(void *v); /// Direct initialization constructor for const void pointers. /// Although one of the constructor templates below could /// certainly handle void pointers as well, we need to treat /// them separately because void* can't be dereferenced. inline Value(const void *v); /// Direct initialization constructor template for non-const /// pointers. By initializing an instance of Value through /// this constructor, internal structures will be configured /// to handle polymorphic types. This means you'll be able to /// call getInstanceType() to get the actual type of the /// dereferenced value. template Value(T *v); /// Direct initialization constructor template for non-const /// pointers. By initializing an instance of Value through /// this constructor, internal structures will be configured /// to handle polymorphic types. This means you'll be able to /// call getInstanceType() to get the actual type of the /// dereferenced value. template Value(const T *v); /// Direct initialization constructor template for all types /// that are not handled by any of the constructors above. /// Calling getInstanceType() on an instance constructed /// this way returns the same as getType(). template Value(const T &v); /// Copy constructor. The underlying value's type must have /// consistent copy semantics. inline Value(const Value& copy); /// Destructor. Frees internal resources but it does NOT delete /// the value held. For example, this function will produce a /// memory leak: void f() { Value v(new int); } inline ~Value(); /// Assignment operator. Behaves like the copy constructor. inline Value& operator=(const Value& copy); /// Returns whether the value is a pointer and it points to /// something whose type is different than void. inline bool isTypedPointer() const; /// Returns whether this Value is empty. inline bool isEmpty() const; /// Returns whether the value is a null pointer. inline bool isNullPointer() const; /// Returns the exact type of the value held. inline const Type& getType() const; /// If the value is a pointer to a non-void type, this method /// returns the actual type of the dereferenced pointer. Please /// note it is not the same as getType().getPointedType(), /// because the latter would return the non-polymorphic type. /// If the value is not a pointer, this method behaves like /// getType(). inline const Type& getInstanceType() const; /// Equal to operator. bool operator==(const Value& other) const; /// Less than or equal to operator. bool operator<=(const Value& other) const; /// Inequality test operator. Returns !operator==(other). bool operator!=(const Value& other) const; /// Greater than operator. Returns !operator<=(other). bool operator>(const Value& other) const; /// Less than operator. Returns !operator==(other) && operator<=(other). bool operator<(const Value& other) const; /// Greater than or equal to operator. Returns operator==(other) || !operator<=(other) bool operator>=(const Value& other) const; /// Tries to convert this instance to a Value of the given type. /// The conversion is performed by rendering to a temporary stream /// in the source format and trying to read back from the stream /// in the destination format. If either the source or destination /// types, or both, don't have a ReaderWriter object, the conversion /// fails and an exception is thrown. If the conversion can't be /// completed for other reasons, other exceptions may be thrown. Value convertTo(const Type& outtype) const; /// Tries to convert this instance to a Value of the given type. /// The conversion is performed by rendering to a temporary stream /// in the source format and trying to read back from the stream /// in the destination format. If either the source or destination /// types, or both, don't have a ReaderWriter object, the conversion /// fails and an empty Value is returned. /// Please note that unlike convertTo(), this method does not /// intentionally throw any exceptions. Value tryConvertTo(const Type& outtype) const; /// Tries to get a string representation of the underlying value. /// This requires the value's type to have a ReaderWriter object /// associated to it. If the conversion can't be completed, an /// exception is thrown. std::string toString() const; std::wstring toWString() const; /// Swaps the content of this Value with another Value void swap(Value& v); private: // It's good to have friends! template friend T variant_cast(const Value& v); template friend bool requires_conversion(const Value& v); template friend T *extract_raw_data(Value& v); template friend const T *extract_raw_data(const Value& v); // throw an exception if the value is empty void check_empty() const; // Base class for holding values. Provides a clone() method // which must be overriden in descendant classes. struct Instance_base { virtual Instance_base *clone() const = 0; virtual ~Instance_base() {} }; // Generic descendant of Instance_base for holding values of // type T. Note that values are created on the stack. template struct Instance: Instance_base { Instance(T data): _data(data) {} virtual Instance_base *clone() const { return new Instance(*this); } virtual ~Instance() {} T _data; protected: Instance& operator = (const Instance& rhs) { if (&rhs!=this) { _data = rhs._data; } return *this; } }; // Base class for storage of Instance objects. Actually three // instances are created: the main instance which keeps the // desired value, an additional instance that keeps a reference // to that value, and another instance that keeps a const // reference to that value. These additional instances are queried // when casting the Value to a reference type. struct Instance_box_base { Instance_box_base() : inst_(0), _ref_inst(0), _const_ref_inst(0) { } virtual ~Instance_box_base() { delete inst_; delete _ref_inst; delete _const_ref_inst; } // clones the instance box virtual Instance_box_base *clone() const = 0; // returns the type of the value held virtual const Type* type() const = 0; // returns the actual pointed type if applicable virtual const Type* ptype() const { return 0; } // returns whether the data is a null pointer virtual bool isNullPointer() const = 0; Instance_base *inst_; Instance_base *_ref_inst; Instance_base *_const_ref_inst; }; // Generic instance box for non-pointer values. template struct Instance_box: Instance_box_base { Instance_box(): Instance_box_base(), _isNullPointer(false) {} Instance_box(const T &d, bool isNullPointer = false) : Instance_box_base(), _isNullPointer(isNullPointer) { Instance *vl = new Instance(d); inst_ = vl; _ref_inst = new Instance(vl->_data); _const_ref_inst = new Instance(vl->_data); } virtual Instance_box_base *clone() const { Instance_box *new_inbox = new Instance_box(); // ??? this static_cast<> shouldn't be necessary, but the // MSVC++ compiler complains about invalid casting without it! Instance *vl = static_cast *>(inst_->clone()); new_inbox->inst_ = vl; new_inbox->_ref_inst = new Instance(vl->_data); new_inbox->_const_ref_inst = new Instance(vl->_data); new_inbox->_isNullPointer = _isNullPointer; return new_inbox; } virtual const Type* type() const { return &typeof(T); } virtual bool isNullPointer() const { return _isNullPointer; } private: bool _isNullPointer; Instance_box& operator = (const Instance_box&) { return *this; } }; // Generic instance box for pointer values. Unlike Instance_box<>, // this struct template provides a ptype() method that unreferences // the pointer (T is supposed to be a pointer) and gets its actual // type. template struct Ptr_instance_box: Instance_box_base { Ptr_instance_box(): Instance_box_base() {} Ptr_instance_box(const T &d) : Instance_box_base() { Instance *vl = new Instance(d); inst_ = vl; _ref_inst = new Instance(vl->_data); _const_ref_inst = new Instance(vl->_data); } virtual Instance_box_base *clone() const { Ptr_instance_box *new_inbox = new Ptr_instance_box(); // ??? this static_cast<> shouldn't be necessary, but the // MSVC++ compiler complains about invalid casting without it! Instance *vl = static_cast *>(inst_->clone()); new_inbox->inst_ = vl; new_inbox->_ref_inst = new Instance(vl->_data); new_inbox->_const_ref_inst = new Instance(vl->_data); return new_inbox; } virtual const Type* type() const { return &typeof(T); } virtual const Type* ptype() const { if (!static_cast *>(inst_)->_data) return 0; return &typeofvalue(*static_cast *>(inst_)->_data); } virtual bool isNullPointer() const { return static_cast *>(inst_)->_data == 0; } }; Instance_box_base *_inbox; const Type* _type; const Type* _ptype; }; /// A vector of values. typedef std::vector ValueList; // INLINE METHODS inline Value::Value() : _inbox(0), _type(&Reflection::type_void()), _ptype(0) { } template Value::Value(const T &v) : _ptype(0) { _inbox = new Instance_box(v); _type = _inbox->type(); } inline Value::Value(const void *v) : _ptype(0) { _inbox = new Instance_box(v, v == 0); _type = _inbox->type(); } inline Value::Value(void *v) : _ptype(0) { _inbox = new Instance_box(v, v == 0); _type = _inbox->type(); } template Value::Value(const T *v) { _inbox = new Ptr_instance_box(v); _type = _inbox->type(); _ptype = _inbox->ptype(); } template Value::Value(T *v) { _inbox = new Ptr_instance_box(v); _type = _inbox->type(); _ptype = _inbox->ptype(); } inline Value::Value(const Value& copy) : _inbox(copy._inbox? copy._inbox->clone(): 0), _type(copy._type), _ptype(copy._ptype) { } inline Value& Value::operator=(const Value& copy) { std::auto_ptr new_inbox(copy._inbox? copy._inbox->clone(): 0); delete _inbox; _inbox = new_inbox.release(); _type = copy._type; _ptype = copy._ptype; return *this; } inline Value::~Value() { delete _inbox; } inline const Type& Value::getType() const { return *_type; } inline const Type& Value::getInstanceType() const { if (_ptype) return *_ptype; return *_type; } inline bool Value::isTypedPointer() const { return _ptype != 0; } inline bool Value::isEmpty() const { return _inbox == 0; } inline bool Value::isNullPointer() const { return _inbox->isNullPointer(); } } #endif