1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
|
/* -*-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 <osgIntrospection/Export>
#include <osgIntrospection/Reflection>
#include <osgIntrospection/type_traits>
#include <vector>
#include <memory>
#include <string>
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<typename T> 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<typename T> 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<typename T> 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<typename T> friend T variant_cast(const Value& v);
template<typename T> friend bool requires_conversion(const Value& v);
template<typename T> friend T *extract_raw_data(Value& v);
template<typename T> 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<typename T>
struct Instance: Instance_base
{
Instance(T data): _data(data) {}
virtual Instance_base *clone() const { return new Instance<T>(*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 nullptr() const = 0;
Instance_base *inst_;
Instance_base *_ref_inst;
Instance_base *_const_ref_inst;
};
// Generic instance box for non-pointer values.
template<typename T>
struct Instance_box: Instance_box_base
{
Instance_box(): Instance_box_base(), nullptr_(false) {}
Instance_box(const T &d, bool nullptr = false)
: Instance_box_base(),
nullptr_(nullptr)
{
Instance<T> *vl = new Instance<T>(d);
inst_ = vl;
_ref_inst = new Instance<T &>(vl->_data);
_const_ref_inst = new Instance<const T &>(vl->_data);
}
virtual Instance_box_base *clone() const
{
Instance_box<T> *new_inbox = new Instance_box<T>();
// ??? this static_cast<> shouldn't be necessary, but the
// MSVC++ compiler complains about invalid casting without it!
Instance<T> *vl = static_cast<Instance<T> *>(inst_->clone());
new_inbox->inst_ = vl;
new_inbox->_ref_inst = new Instance<T &>(vl->_data);
new_inbox->_const_ref_inst = new Instance<const T &>(vl->_data);
new_inbox->nullptr_ = nullptr_;
return new_inbox;
}
virtual const Type* type() const
{
return &typeof(T);
}
virtual bool nullptr() const
{
return nullptr_;
}
private:
bool nullptr_;
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<typename T>
struct Ptr_instance_box: Instance_box_base
{
Ptr_instance_box(): Instance_box_base() {}
Ptr_instance_box(const T &d)
: Instance_box_base()
{
Instance<T> *vl = new Instance<T>(d);
inst_ = vl;
_ref_inst = new Instance<T &>(vl->_data);
_const_ref_inst = new Instance<const T &>(vl->_data);
}
virtual Instance_box_base *clone() const
{
Ptr_instance_box<T> *new_inbox = new Ptr_instance_box<T>();
// ??? this static_cast<> shouldn't be necessary, but the
// MSVC++ compiler complains about invalid casting without it!
Instance<T> *vl = static_cast<Instance<T> *>(inst_->clone());
new_inbox->inst_ = vl;
new_inbox->_ref_inst = new Instance<T &>(vl->_data);
new_inbox->_const_ref_inst = new Instance<const T &>(vl->_data);
return new_inbox;
}
virtual const Type* type() const
{
return &typeof(T);
}
virtual const Type* ptype() const
{
if (!static_cast<Instance<T> *>(inst_)->_data) return 0;
return &typeofvalue(*static_cast<Instance<T> *>(inst_)->_data);
}
virtual bool nullptr() const
{
return static_cast<Instance<T> *>(inst_)->_data == 0;
}
};
Instance_box_base *_inbox;
const Type* _type;
const Type* _ptype;
};
/// A vector of values.
typedef std::vector<Value> ValueList;
// INLINE METHODS
inline Value::Value()
: _inbox(0),
_type(&Reflection::type_void()),
_ptype(0)
{
}
template<typename T> Value::Value(const T &v)
: _ptype(0)
{
_inbox = new Instance_box<T>(v);
_type = _inbox->type();
}
inline Value::Value(const void *v)
: _ptype(0)
{
_inbox = new Instance_box<const void *>(v, v == 0);
_type = _inbox->type();
}
inline Value::Value(void *v)
: _ptype(0)
{
_inbox = new Instance_box<void *>(v, v == 0);
_type = _inbox->type();
}
template<typename T> Value::Value(const T *v)
{
_inbox = new Ptr_instance_box<const T *>(v);
_type = _inbox->type();
_ptype = _inbox->ptype();
}
template<typename T> Value::Value(T *v)
{
_inbox = new Ptr_instance_box<T *>(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<Instance_box_base> 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->nullptr();
}
}
#endif
|