X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fprops%2Fprops.hxx;h=8cf38e6da7954becd375207277a69e56381e837f;hb=708ae35068499af33329f9db91f55441f4956acb;hp=a74b89c28165309decb7df7fc50a0837f04e832a;hpb=6935baba5b9a66bbf1dd2557fc9cc45f0f6768fd;p=simgear.git diff --git a/simgear/props/props.hxx b/simgear/props/props.hxx index a74b89c2..8cf38e6d 100644 --- a/simgear/props/props.hxx +++ b/simgear/props/props.hxx @@ -17,31 +17,63 @@ #endif #include - -#if PROPS_STANDALONE - #include #include +#include -using std::string; -using std::vector; -using std::istream; -using std::ostream; +#include +#if PROPS_STANDALONE #else - #include #include -#include STL_STRING -#include STL_IOSTREAM -SG_USING_STD(string); -SG_USING_STD(vector); -SG_USING_STD(istream); -SG_USING_STD(ostream); - #endif +#include +#include +#include + +// XXX This whole file should be in the simgear namespace, but I don't +// have the guts yet... + +namespace simgear +{ +template +std::istream& readFrom(std::istream& stream, T& result) +{ + stream >> result; + return stream; +} + +/** + * Parse a string as an object of a given type. + * XXX no error behavior yet. + * + * @tparam T the return type + * @param str the string + * @return the object. + */ +template +inline T parseString(const std::string& str) +{ + std::istringstream stream(str); + T result; + readFrom(stream, result); + return result; +} + +// Extended properties +template<> +std::istream& readFrom(std::istream& stream, SGVec3d& result); +template<> +std::istream& readFrom(std::istream& stream, SGVec4d& result); + + +/** + * Property value types. + */ + #ifdef NONE #pragma warn A sloppy coder has defined NONE as a macro! #undef NONE @@ -87,6 +119,68 @@ SG_USING_STD(ostream); #undef STRING #endif +namespace props +{ +/** + * The possible types of an SGPropertyNode. Types that appear after + * EXTENDED are not stored in the SGPropertyNode itself. + */ +enum Type { + NONE = 0, /**< The node hasn't been assigned a value yet. */ + ALIAS, /**< The node "points" to another node. */ + BOOL, + INT, + LONG, + FLOAT, + DOUBLE, + STRING, + UNSPECIFIED, + EXTENDED, /**< The node's value is not stored in the property; + * the actual value and type is retrieved from an + * SGRawValue node. This type is never returned by @see + * SGPropertyNode::getType. + */ + // Extended properties + VEC3D, + VEC4D +}; + +template struct PropertyTraits; + +#define DEFINTERNALPROP(TYPE, PROP) \ +template<> \ +struct PropertyTraits \ +{ \ + static const Type type_tag = PROP; \ + enum { Internal = 1 }; \ +} + +DEFINTERNALPROP(bool, BOOL); +DEFINTERNALPROP(int, INT); +DEFINTERNALPROP(long, LONG); +DEFINTERNALPROP(float, FLOAT); +DEFINTERNALPROP(double, DOUBLE); +DEFINTERNALPROP(const char *, STRING); +DEFINTERNALPROP(const char[], STRING); +#undef DEFINTERNALPROP + +template<> +struct PropertyTraits +{ + static const Type type_tag = VEC3D; + enum { Internal = 0 }; +}; + +template<> +struct PropertyTraits +{ + static const Type type_tag = VEC4D; + enum { Internal = 0 }; +}; +} +} + + //////////////////////////////////////////////////////////////////////// @@ -101,6 +195,74 @@ SG_USING_STD(ostream); // a small performance hit for that. //////////////////////////////////////////////////////////////////////// +/** + * Base class for SGRawValue classes that holds no type + * information. This allows some generic manipulation of the + * SGRawValue object. + */ +class SGRaw +{ +public: + /** + * Get the type enumeration for the raw value. + * + * @return the type. + */ + virtual simgear::props::Type getType() const = 0; + virtual ~SGRaw() {} + + /** + * Create a new deep copy of this raw value. + * + * The copy will contain its own version of the underlying value + * as well, and will be the same type. + * + * @return A deep copy of the current object. + */ + virtual SGRaw* clone() const = 0; + +}; + +class SGRawExtended : public SGRaw +{ +public: + /** + * Make an SGRawValueContainer from the SGRawValue. + * + * This is a virtual function of SGRawExtended so that + * SGPropertyNode::untie doesn't need to know the type of an + * extended property. + */ + virtual SGRawExtended* makeContainer() const = 0; + /** + * Write value out to a stream + */ + virtual std::ostream& printOn(std::ostream& stream) const = 0; + /** + * Read value from a stream and store it. + */ + virtual std::istream& readFrom(std::istream& stream) = 0; +}; + +// Choose between different base classes based on whether the value is +// stored internal to the property node. This frees us from defining +// the virtual functions in the SGRawExtended interface where they +// don't make sense, e.g. readFrom for the const char* type. +template::Internal> +class SGRawBase; + +template +class SGRawBase : public SGRaw +{ +}; + +template +class SGRawBase : public SGRawExtended +{ + virtual SGRawExtended* makeContainer() const; + virtual std::ostream& printOn(std::ostream& stream) const; + virtual std::istream& readFrom(std::istream& stream); +}; /** * Abstract base class for a raw value. @@ -119,10 +281,7 @@ SG_USING_STD(ostream); * set, and clone the underlying value. The SGRawValue may change * frequently during a session as a value is retyped or bound and * unbound to various data source, but the abstract SGPropertyNode - * layer insulates the application from those changes. The raw value - * contains no facilities for data binding or for type conversion: it - * is simply the abstraction of a primitive data type (or a compound - * data type, in the case of a string).

+ * layer insulates the application from those changes. * *

The SGPropertyNode class always keeps a *copy* of a raw value, * not the original one passed to it; if you override a derived class @@ -138,9 +297,10 @@ SG_USING_STD(ostream); * @see SGRawValueFunctionsIndexed * @see SGRawValueMethods * @see SGRawValueMethodsIndexed + * @see SGRawValueContainer */ template -class SGRawValue +class SGRawValue : public SGRawBase { public: @@ -153,7 +313,10 @@ public: * may need different kinds of default values (such as epoch for a * date type). The default value is used when creating new values. */ - static const T DefaultValue; // Default for this kind of raw value. + static T DefaultValue() + { + return T(); + } /** @@ -195,17 +358,30 @@ public: /** - * Create a new deep copy of this raw value. - * - * The copy will contain its own version of the underlying value - * as well. - * - * @return A deep copy of the current object. + * Return the type tag for this raw value type. */ - virtual SGRawValue * clone () const = 0; + virtual simgear::props::Type getType() const + { + return simgear::props::PropertyTraits::type_tag; + } }; + +//////////////////////////////////////////////////////////////////////// +// Default values for every type. +//////////////////////////////////////////////////////////////////////// + +template<> inline bool SGRawValue::DefaultValue() +{ + return false; +} + +template<> inline const char * SGRawValue::DefaultValue() +{ + return ""; +} + /** * A raw value bound to a pointer. * @@ -258,8 +434,8 @@ public: * * The copy will use the same external pointer as the original. */ - virtual SGRawValue * clone () const { - return new SGRawValuePointer(_ptr); + virtual SGRaw* clone () const { + return new SGRawValuePointer(_ptr); } private: @@ -282,13 +458,11 @@ public: * The template type of a static getter function. */ typedef T (*getter_t)(); - typedef T (*getter_td)(void*); /** * The template type of a static setter function. */ typedef void (*setter_t)(T); - typedef void (*setter_td)(T,void*); /** * Explicit constructor. @@ -301,26 +475,7 @@ public: * to write-disable the value. */ SGRawValueFunctions (getter_t getter = 0, setter_t setter = 0) - : _getter(getter), _setter(setter), - _getter_d(0), _setter_d(0), _data(0) {} - - /** - * Explicit constructor. - * - * Create a new raw value bound to the getter and setter supplied. - * - * @param getter A static function for getting a value, or 0 - * to read-disable the value. - * @param setter A static function for setting a value, or 0 - * to write-disable the value. - * @param data A pointer to user data which gets passed to the - * getter and setter functions. This could be used to pass the this - * pointer to the callback function. - */ - SGRawValueFunctions (getter_td getter = 0, setter_td setter = 0, - void *data = NULL) - : _setter(0), _getter(0), - _getter_d(getter), _setter_d(setter), _data(data) {} + : _getter(getter), _setter(setter) {} /** * Destructor. @@ -335,9 +490,8 @@ public: * return the default value for the type. */ virtual T getValue () const { - if (_getter_d) return (*_getter_d)(_data); - else if (_getter) return (*_getter)(); - else return SGRawValue::DefaultValue; + if (_getter) return (*_getter)(); + else return SGRawValue::DefaultValue(); } /** @@ -348,27 +502,20 @@ public: * method will return false. */ virtual bool setValue (T value) { - if (_setter_d) { (*_setter_d)(value,_data); return true; } - else if (_setter) { (*_setter)(value); return true; } + if (_setter) { (*_setter)(value); return true; } else return false; } /** * Create a copy of this raw value, bound to the same functions. */ - virtual SGRawValue * clone () const { - if (_getter_d) - return new SGRawValueFunctions(_getter_d,_setter_d,_data); - else - return new SGRawValueFunctions(_getter,_setter); + virtual SGRaw* clone () const { + return new SGRawValueFunctions(_getter,_setter); } private: getter_t _getter; setter_t _setter; - getter_td _getter_d; - setter_td _setter_d; - void *_data; }; @@ -387,40 +534,25 @@ class SGRawValueFunctionsIndexed : public SGRawValue { public: typedef T (*getter_t)(int); - typedef T (*getter_td)(int,void*); typedef void (*setter_t)(int,T); - typedef void (*setter_td)(int,T,void*); - SGRawValueFunctionsIndexed (int index, getter_t getter = 0, setter_t setter = -0) - : _index(index), _getter(getter), _setter(setter), - _getter_d(0), _setter_d(0),_data(0) {} - SGRawValueFunctionsIndexed (int index, getter_td getter = 0, setter_td setter = 0, void *data = NULL) - : _index(index), _setter(0), _getter(0), - _getter_d(getter), _setter_d(setter), _data(data) {} + SGRawValueFunctionsIndexed (int index, getter_t getter = 0, setter_t setter = 0) + : _index(index), _getter(getter), _setter(setter) {} virtual ~SGRawValueFunctionsIndexed () {} virtual T getValue () const { - if (_getter_d) return (*_getter_d)(_index,_data); - else if (_getter) return (*_getter)(_index); - else return SGRawValue::DefaultValue; + if (_getter) return (*_getter)(_index); + else return SGRawValue::DefaultValue(); } virtual bool setValue (T value) { - if (_setter_d) { (*_setter_d)(_index, value, _data); return true; } - else if (_setter) { (*_setter)(_index, value); return true; } + if (_setter) { (*_setter)(_index, value); return true; } else return false; } - virtual SGRawValue * clone () const { - if (_getter_d) - return new SGRawValueFunctionsIndexed(_index,_getter_d,_setter_d,_data); - else - return new SGRawValueFunctionsIndexed(_index,_getter,_setter); + virtual SGRaw* clone () const { + return new SGRawValueFunctionsIndexed(_index, _getter, _setter); } private: int _index; getter_t _getter; setter_t _setter; - getter_td _getter_d; - setter_td _setter_d; - void *_data; }; @@ -441,14 +573,14 @@ public: virtual ~SGRawValueMethods () {} virtual T getValue () const { if (_getter) { return (_obj.*_getter)(); } - else { return SGRawValue::DefaultValue; } + else { return SGRawValue::DefaultValue(); } } virtual bool setValue (T value) { if (_setter) { (_obj.*_setter)(value); return true; } else return false; } - virtual SGRawValue * clone () const { - return new SGRawValueMethods(_obj, _getter, _setter); + virtual SGRaw* clone () const { + return new SGRawValueMethods(_obj, _getter, _setter); } private: C &_obj; @@ -475,14 +607,14 @@ public: virtual ~SGRawValueMethodsIndexed () {} virtual T getValue () const { if (_getter) { return (_obj.*_getter)(_index); } - else { return SGRawValue::DefaultValue; } + else { return SGRawValue::DefaultValue(); } } virtual bool setValue (T value) { if (_setter) { (_obj.*_setter)(_index, value); return true; } else return false; } - virtual SGRawValue * clone () const { - return new SGRawValueMethodsIndexed(_obj, _index, _getter, _setter); + virtual SGRaw* clone () const { + return new SGRawValueMethodsIndexed(_obj, _index, _getter, _setter); } private: C &_obj; @@ -491,75 +623,89 @@ private: setter_t _setter; }; - /** - * The smart pointer that manage reference counting + * A raw value that contains its value. This provides a way for + * property nodes to contain values that shouldn't be stored in the + * property node itself. */ -class SGPropertyNode; -class SGPropertyNode_ptr +template +class SGRawValueContainer : public SGRawValue { public: - /** - * Default constructor - */ - SGPropertyNode_ptr(); - - /** - * Copy constructor - */ - SGPropertyNode_ptr( const SGPropertyNode_ptr &r ); - - /** - * Constructor from a pointer to a node - */ - SGPropertyNode_ptr( SGPropertyNode *p ); + /** + * Explicit constructor. + */ + SGRawValueContainer(const T& obj) : _obj(obj) {} - /** - * Destructor - */ - ~SGPropertyNode_ptr(); + /** + * Destructor. + */ + virtual ~SGRawValueContainer() {} - /** - * Assignement operator - */ - SGPropertyNode_ptr &operator=( const SGPropertyNode_ptr &r ); + /** + * Get the underlying value. + */ + virtual T getValue() const { return _obj; } - /** - * Pointer access operator - */ - SGPropertyNode *operator->(); + /** + * Set the underlying value. + * + * This method will dereference the pointer and change the + * variable's value. + */ + virtual bool setValue (T value) { _obj = value; return true; } - /** - * Pointer access operator (const) - */ - const SGPropertyNode *operator->() const; + /** + * Create a copy of this raw value. + */ + virtual SGRaw* clone () const { + return new SGRawValueContainer(_obj); + } - /** - * Conversion to SGPropertyNode * operator - */ - operator SGPropertyNode *(); +private: + T _obj; +}; - /** - * Conversion to const SGPropertyNode * operator - */ - operator const SGPropertyNode *() const; +template +SGRawExtended* SGRawBase::makeContainer() const +{ + return new SGRawValueContainer(static_cast*>(this) + ->getValue()); +} - /** - * Return the pointer. - */ - SGPropertyNode * ptr () { return _ptr; } +template +std::ostream& SGRawBase::printOn(std::ostream& stream) const +{ + return stream << static_cast*>(this)->getValue(); +} - /** - * Validity test - */ - bool valid() const; +template +std::istream& SGRawBase::readFrom(std::istream& stream) +{ + T value; + simgear::readFrom(stream, value); + static_cast*>(this)->setValue(value); + return stream; +} -private: +template<> +std::ostream& SGRawBase::printOn(std::ostream& stream) const; +template<> +std::ostream& SGRawBase::printOn(std::ostream& stream) const; - SGPropertyNode *_ptr; -}; + +/** + * The smart pointer that manage reference counting + */ +class SGPropertyNode; +typedef SGSharedPtr SGPropertyNode_ptr; +typedef SGSharedPtr SGConstPropertyNode_ptr; +namespace simgear +{ +typedef std::vector PropertyList; +} /** @@ -582,7 +728,7 @@ protected: virtual void unregister_property (SGPropertyNode * node); private: - vector _properties; + std::vector _properties; }; @@ -590,7 +736,7 @@ private: /** * A node in a property tree. */ -class SGPropertyNode +class SGPropertyNode : public SGReferenced { public: @@ -601,22 +747,6 @@ public: MAX_STRING_LEN = 1024 }; - /** - * Property value types. - */ - enum Type { - NONE, - ALIAS, - BOOL, - INT, - LONG, - FLOAT, - DOUBLE, - STRING, - UNSPECIFIED - }; - - /** * Access mode attributes. * @@ -629,7 +759,11 @@ public: ARCHIVE = 4, REMOVED = 8, TRACE_READ = 16, - TRACE_WRITE = 32 + TRACE_WRITE = 32, + USERARCHIVE = 64, + PRESERVE = 128 + // beware: if you add another attribute here, + // also update value of "LAST_USED_ATTRIBUTE". }; @@ -666,19 +800,23 @@ public: /** * Test whether this node contains a primitive leaf value. */ - bool hasValue () const { return (_type != NONE); } + bool hasValue () const { return (_type != simgear::props::NONE); } /** * Get the node's simple (XML) name. */ - const char * getName () const { return _name; } + const char * getName () const { return _name.c_str(); } + /** + * Get the node's simple name as a string. + */ + const std::string& getNameString () const { return _name; } /** * Get the node's pretty display name, with subscript when needed. */ - const char * getDisplayName (bool simplify = false) const; + std::string getDisplayName (bool simplify = false) const; /** @@ -707,7 +845,7 @@ public: /** * Get the number of child nodes. */ - int nChildren () const { return _children.size(); } + int nChildren () const { return (int)_children.size(); } /** @@ -730,24 +868,53 @@ public: return (getChild(name, index) != 0); } - /** - * Get a child node by name and index. + * Test whether a named child exists. */ - SGPropertyNode * getChild (const char * name, int index = 0, - bool create = false); + bool hasChild (const std::string& name, int index = 0) const + { + return (getChild(name, index) != 0); + } + /** + * Create a child node after the last node with the same name. + */ + SGPropertyNode * addChild (const char * name); + /** + * Get a child node by name and index. + */ + SGPropertyNode * getChild (const char* name, int index = 0, + bool create = false); + SGPropertyNode * getChild (const std::string& name, int index = 0, + bool create = false); /** * Get a const child node by name and index. */ const SGPropertyNode * getChild (const char * name, int index = 0) const; + /** + * Get a const child node by name and index. + */ + const SGPropertyNode * getChild (const std::string& name, int index = 0) const + { return getChild(name.c_str(), index); } + + + /** + * Get a vector of all children with the specified name. + */ + simgear::PropertyList getChildren (const char * name) const; /** * Get a vector of all children with the specified name. */ - vector getChildren (const char * name) const; + simgear::PropertyList getChildren (const std::string& name) const + { return getChildren(name.c_str()); } + + /** + * Remove child by position. + */ + SGPropertyNode_ptr removeChild (int pos, bool keep = true); /** @@ -756,6 +923,24 @@ public: SGPropertyNode_ptr removeChild (const char * name, int index = 0, bool keep = true); + /** + * Remove a child node + */ + SGPropertyNode_ptr removeChild (const std::string& name, int index = 0, + bool keep = true) + { return removeChild(name.c_str(), index, keep); } + + /** + * Remove all children with the specified name. + */ + simgear::PropertyList removeChildren (const char * name, bool keep = true); + + /** + * Remove all children with the specified name. + */ + simgear::PropertyList removeChildren (const std::string& name, + bool keep = true) + { return removeChildren(name.c_str(), keep); } // // Alias support. @@ -773,6 +958,12 @@ public: */ bool alias (const char * path); + /** + * Alias this node's leaf value to another's by relative path. + */ + bool alias (const std::string& path) + { return alias(path.c_str()); } + /** * Remove any alias for this node. @@ -783,7 +974,7 @@ public: /** * Test whether the node's leaf value is aliased to another's. */ - bool isAlias () const { return (_type == ALIAS); } + bool isAlias () const { return (_type == simgear::props::ALIAS); } /** @@ -806,7 +997,7 @@ public: /** * Get the path to this node from the root. */ - const char * getPath (bool simplify = false) const; + std::string getPath (bool simplify = false) const; /** @@ -826,6 +1017,11 @@ public: */ SGPropertyNode * getNode (const char * relative_path, bool create = false); + /** + * Get a pointer to another node by relative path. + */ + SGPropertyNode * getNode (const std::string& relative_path, bool create = false) + { return getNode(relative_path.c_str(), create); } /** * Get a pointer to another node by relative path. @@ -840,12 +1036,31 @@ public: SGPropertyNode * getNode (const char * relative_path, int index, bool create = false); + /** + * Get a pointer to another node by relative path. + * + * This method leaves the index off the last member of the path, + * so that the user can specify it separately (and save some + * string building). For example, getNode("/bar[1]/foo", 3) is + * exactly equivalent to getNode("bar[1]/foo[3]"). The index + * provided overrides any given in the path itself for the last + * component. + */ + SGPropertyNode * getNode (const std::string& relative_path, int index, + bool create = false) + { return getNode(relative_path.c_str(), index, create); } /** * Get a const pointer to another node by relative path. */ const SGPropertyNode * getNode (const char * relative_path) const; + /** + * Get a const pointer to another node by relative path. + */ + const SGPropertyNode * getNode (const std::string& relative_path) const + { return getNode(relative_path.c_str()); } + /** * Get a const pointer to another node by relative path. @@ -856,6 +1071,15 @@ public: const SGPropertyNode * getNode (const char * relative_path, int index) const; + /** + * Get a const pointer to another node by relative path. + * + * This method leaves the index off the last member of the path, + * so that the user can specify it separate. + */ + const SGPropertyNode * getNode (const std::string& relative_path, + int index) const + { return getNode(relative_path.c_str(), index); } // // Access Mode. @@ -895,7 +1119,7 @@ public: /** * Get the type of leaf value, if any, for this node. */ - Type getType () const; + simgear::props::Type getType () const; /** @@ -933,7 +1157,17 @@ public: */ const char * getStringValue () const; - + /** + * Get a value from a node. If the actual type of the node doesn't + * match the desired type, a conversion isn't guaranteed. + */ + template + T getValue(typename boost::enable_if_c::Internal> + ::type* dummy = 0) const; + // Getter for extended property + template + T getValue(typename boost::disable_if_c::Internal> + ::type* dummy = 0) const; /** * Set a bool value for this node. @@ -970,13 +1204,39 @@ public: */ bool setStringValue (const char * value); + /** + * Set a string value for this node. + */ + bool setStringValue (const std::string& value) + { return setStringValue(value.c_str()); } + /** * Set a value of unspecified type for this node. */ bool setUnspecifiedValue (const char * value); + template + bool setValue(const T& val, + typename boost::enable_if_c::Internal> + ::type* dummy = 0); + + template + bool setValue(const T& val, + typename boost::disable_if_c::Internal> + ::type* dummy = 0); + template + bool setValue(const char (&val)[N]) + { + return setValue(&val[0]); + } + + /** + * Print the value of the property to a stream. + */ + std::ostream& printOn(std::ostream& stream) const; + // // Data binding. // @@ -987,42 +1247,11 @@ public: */ bool isTied () const { return _tied; } - - /** - * Bind this node to an external bool source. - */ - bool tie (const SGRawValue &rawValue, bool useDefault = true); - - - /** - * Bind this node to an external int source. - */ - bool tie (const SGRawValue &rawValue, bool useDefault = true); - - - /** - * Bind this node to an external long int source. - */ - bool tie (const SGRawValue &rawValue, bool useDefault = true); - - - /** - * Bind this node to an external float source. - */ - bool tie (const SGRawValue &rawValue, bool useDefault = true); - - - /** - * Bind this node to an external double source. - */ - bool tie (const SGRawValue &rawValue, bool useDefault = true); - - - /** - * Bind this node to an external string source. - */ - bool tie (const SGRawValue &rawValue, bool useDefault = true); - + /** + * Bind this node to an external source. + */ + template + bool tie(const SGRawValue &rawValue, bool useDefault = true); /** * Unbind this node from any external data source. @@ -1039,14 +1268,24 @@ public: /** * Get another node's type. */ - Type getType (const char * relative_path) const; + simgear::props::Type getType (const char * relative_path) const; + /** + * Get another node's type. + */ + simgear::props::Type getType (const std::string& relative_path) const + { return getType(relative_path.c_str()); } /** * Test whether another node has a leaf value. */ bool hasValue (const char * relative_path) const; + /** + * Test whether another node has a leaf value. + */ + bool hasValue (const std::string& relative_path) const + { return hasValue(relative_path.c_str()); } /** * Get another node's value as a bool. @@ -1054,6 +1293,12 @@ public: bool getBoolValue (const char * relative_path, bool defaultValue = false) const; + /** + * Get another node's value as a bool. + */ + bool getBoolValue (const std::string& relative_path, + bool defaultValue = false) const + { return getBoolValue(relative_path.c_str(), defaultValue); } /** * Get another node's value as an int. @@ -1061,6 +1306,13 @@ public: int getIntValue (const char * relative_path, int defaultValue = 0) const; + /** + * Get another node's value as an int. + */ + int getIntValue (const std::string& relative_path, + int defaultValue = 0) const + { return getIntValue(relative_path.c_str(), defaultValue); } + /** * Get another node's value as a long int. @@ -1068,20 +1320,39 @@ public: long getLongValue (const char * relative_path, long defaultValue = 0L) const; + /** + * Get another node's value as a long int. + */ + long getLongValue (const std::string& relative_path, + long defaultValue = 0L) const + { return getLongValue(relative_path.c_str(), defaultValue); } /** * Get another node's value as a float. */ float getFloatValue (const char * relative_path, - float defaultValue = 0.0) const; + float defaultValue = 0.0f) const; + + /** + * Get another node's value as a float. + */ + float getFloatValue (const std::string& relative_path, + float defaultValue = 0.0f) const + { return getFloatValue(relative_path.c_str(), defaultValue); } /** * Get another node's value as a double. */ double getDoubleValue (const char * relative_path, - double defaultValue = 0.0L) const; + double defaultValue = 0.0) const; + /** + * Get another node's value as a double. + */ + double getDoubleValue (const std::string& relative_path, + double defaultValue = 0.0) const + { return getDoubleValue(relative_path.c_str(), defaultValue); } /** * Get another node's value as a string. @@ -1090,41 +1361,90 @@ public: const char * defaultValue = "") const; + /** + * Get another node's value as a string. + */ + const char * getStringValue (const std::string& relative_path, + const char * defaultValue = "") const + { return getStringValue(relative_path.c_str(), defaultValue); } + + /** * Set another node's value as a bool. */ bool setBoolValue (const char * relative_path, bool value); + /** + * Set another node's value as a bool. + */ + bool setBoolValue (const std::string& relative_path, bool value) + { return setBoolValue(relative_path.c_str(), value); } + /** * Set another node's value as an int. */ bool setIntValue (const char * relative_path, int value); + /** + * Set another node's value as an int. + */ + bool setIntValue (const std::string& relative_path, int value) + { return setIntValue(relative_path.c_str(), value); } + /** * Set another node's value as a long int. */ bool setLongValue (const char * relative_path, long value); + /** + * Set another node's value as a long int. + */ + bool setLongValue (const std::string& relative_path, long value) + { return setLongValue(relative_path.c_str(), value); } + /** * Set another node's value as a float. */ bool setFloatValue (const char * relative_path, float value); + /** + * Set another node's value as a float. + */ + bool setFloatValue (const std::string& relative_path, float value) + { return setFloatValue(relative_path.c_str(), value); } + /** * Set another node's value as a double. */ bool setDoubleValue (const char * relative_path, double value); + /** + * Set another node's value as a double. + */ + bool setDoubleValue (const std::string& relative_path, double value) + { return setDoubleValue(relative_path.c_str(), value); } + /** * Set another node's value as a string. */ bool setStringValue (const char * relative_path, const char * value); + bool setStringValue(const char * relative_path, const std::string& value) + { return setStringValue(relative_path, value.c_str()); } + /** + * Set another node's value as a string. + */ + bool setStringValue (const std::string& relative_path, const char * value) + { return setStringValue(relative_path.c_str(), value); } + + bool setStringValue (const std::string& relative_path, + const std::string& value) + { return setStringValue(relative_path.c_str(), value.c_str()); } /** * Set another node's value with no specified type. @@ -1137,6 +1457,11 @@ public: */ bool isTied (const char * relative_path) const; + /** + * Test whether another node is bound to an external data source. + */ + bool isTied (const std::string& relative_path) const + { return isTied(relative_path.c_str()); } /** * Bind another node to an external bool source. @@ -1144,6 +1469,13 @@ public: bool tie (const char * relative_path, const SGRawValue &rawValue, bool useDefault = true); + /** + * Bind another node to an external bool source. + */ + bool tie (const std::string& relative_path, const SGRawValue &rawValue, + bool useDefault = true) + { return tie(relative_path.c_str(), rawValue, useDefault); } + /** * Bind another node to an external int source. @@ -1151,6 +1483,13 @@ public: bool tie (const char * relative_path, const SGRawValue &rawValue, bool useDefault = true); + /** + * Bind another node to an external int source. + */ + bool tie (const std::string& relative_path, const SGRawValue &rawValue, + bool useDefault = true) + { return tie(relative_path.c_str(), rawValue, useDefault); } + /** * Bind another node to an external long int source. @@ -1158,6 +1497,13 @@ public: bool tie (const char * relative_path, const SGRawValue &rawValue, bool useDefault = true); + /** + * Bind another node to an external long int source. + */ + bool tie (const std::string& relative_path, const SGRawValue &rawValue, + bool useDefault = true) + { return tie(relative_path.c_str(), rawValue, useDefault); } + /** * Bind another node to an external float source. @@ -1165,6 +1511,13 @@ public: bool tie (const char * relative_path, const SGRawValue &rawValue, bool useDefault = true); + /** + * Bind another node to an external float source. + */ + bool tie (const std::string& relative_path, const SGRawValue &rawValue, + bool useDefault = true) + { return tie(relative_path.c_str(), rawValue, useDefault); } + /** * Bind another node to an external double source. @@ -1172,6 +1525,13 @@ public: bool tie (const char * relative_path, const SGRawValue &rawValue, bool useDefault = true); + /** + * Bind another node to an external double source. + */ + bool tie (const std::string& relative_path, const SGRawValue &rawValue, + bool useDefault = true) + { return tie(relative_path.c_str(), rawValue, useDefault); } + /** * Bind another node to an external string source. @@ -1179,17 +1539,32 @@ public: bool tie (const char * relative_path, const SGRawValue &rawValue, bool useDefault = true); + /** + * Bind another node to an external string source. + */ + bool tie (const std::string& relative_path, const SGRawValue &rawValue, + bool useDefault = true) + { return tie(relative_path.c_str(), rawValue, useDefault); } + /** * Unbind another node from any external data source. */ bool untie (const char * relative_path); + /** + * Unbind another node from any external data source. + */ + bool untie (const std::string& relative_path) + { return untie(relative_path.c_str()); } + /** - * Add a change listener to the property. + * Add a change listener to the property. If "initial" is set call the + * listener initially. */ - void addChangeListener (SGPropertyChangeListener * listener); + void addChangeListener (SGPropertyChangeListener * listener, + bool initial = false); /** @@ -1198,6 +1573,12 @@ public: void removeChangeListener (SGPropertyChangeListener * listener); + /** + * Get the number of listeners. + */ + int nListeners () const { return _listeners ? (int)_listeners->size() : 0; } + + /** * Fire a value change event to all listeners. */ @@ -1216,6 +1597,22 @@ public: void fireChildRemoved (SGPropertyNode * child); + /** + * Clear any existing value and set the type to NONE. + */ + void clearValue (); + + /** + * Compare two property trees. The property trees are equal if: 1) + * They have no children, and have the same type and the values are + * equal, or 2) have the same number of children, and the + * corresponding children in each tree are equal. "corresponding" + * means have the same name and index. + * + * Attributes, removed children, and aliases aren't considered. + */ + static bool compare (const SGPropertyNode& lhs, const SGPropertyNode& rhs); + protected: void fireValueChanged (SGPropertyNode * node); @@ -1225,12 +1622,13 @@ protected: /** * Protected constructor for making new nodes on demand. */ - SGPropertyNode (const char * name, int index, SGPropertyNode * parent); - + SGPropertyNode (const std::string& name, int index, SGPropertyNode * parent); + template + SGPropertyNode (Itr begin, Itr end, int index, SGPropertyNode * parent); private: - // Get the raw value + // Get the raw value bool get_bool () const; int get_int () const; long get_long () const; @@ -1238,7 +1636,7 @@ private: double get_double () const; const char * get_string () const; - // Set the raw value + // Set the raw value bool set_bool (bool value); bool set_int (int value); bool set_long (long value); @@ -1247,18 +1645,11 @@ private: bool set_string (const char * value); - /** - * Clear any existing value and set the type to NONE. - */ - void clear_value (); - - /** * Get the value as a string. */ const char * make_string () const; - /** * Trace a read access. */ @@ -1270,46 +1661,22 @@ private: */ void trace_write () const; - - /** - * Increment reference counter - */ - void incrementRef(); - - /** - * Decrement reference counter - */ - int decrementRef(); - - friend class SGPropertyNode_ptr; - - - mutable char _buffer[MAX_STRING_LEN+1]; - - class hash_table; - - char * _name; - mutable char * _display_name; int _index; + std::string _name; + /// To avoid cyclic reference counting loops this shall not be a reference + /// counted pointer SGPropertyNode * _parent; - vector _children; - vector _removedChildren; - mutable char * _path; - hash_table * _path_cache; - Type _type; + simgear::PropertyList _children; + simgear::PropertyList _removedChildren; + mutable std::string _buffer; + simgear::props::Type _type; bool _tied; int _attr; - int _count; - // The right kind of pointer... + // The right kind of pointer... union { SGPropertyNode * alias; - SGRawValue * bool_val; - SGRawValue * int_val; - SGRawValue * long_val; - SGRawValue * float_val; - SGRawValue * double_val; - SGRawValue * string_val; + SGRaw* val; } _value; union { @@ -1321,61 +1688,256 @@ private: char * string_val; } _local_val; - vector * _listeners; - + std::vector * _listeners; - /** - * A very simple hash table with no remove functionality. - */ - class hash_table { - public: + // Pass name as a pair of iterators + template + SGPropertyNode * getChildImpl (Itr begin, Itr end, int index = 0, bool create = false); + // very internal method + template + SGPropertyNode* getExistingChild (Itr begin, Itr end, int index, bool create); + // very internal path parsing function + template + friend SGPropertyNode* find_node_aux(SGPropertyNode * current, SplitItr& itr, + bool create, int last_index); + // For boost + friend size_t hash_value(const SGPropertyNode& node); +}; - /** - * An entry in a bucket in a hash table. - */ - class entry { - public: - entry (); - virtual ~entry (); - virtual const char * get_key () { return _key; } - virtual void set_key (const char * key); - virtual SGPropertyNode * get_value () { return _value; } - virtual void set_value (SGPropertyNode * value); - private: - char * _key; - SGPropertyNode * _value; - }; +// Convenience functions for use in templates +template +T getValue(const SGPropertyNode*); +template<> +inline bool getValue(const SGPropertyNode* node) { return node->getBoolValue(); } - /** - * A bucket in a hash table. - */ - class bucket { - public: - bucket (); - virtual ~bucket (); - virtual entry * get_entry (const char * key, bool create = false); - private: - int _length; - entry ** _entries; - }; - - friend class bucket; - - hash_table (); - virtual ~hash_table (); - virtual SGPropertyNode * get (const char * key); - virtual void put (const char * key, SGPropertyNode * value); - - private: - unsigned int hashcode (const char * key); - unsigned int _data_length; - bucket ** _data; - }; +template<> +inline int getValue(const SGPropertyNode* node) { return node->getIntValue(); } + +template<> +inline long getValue(const SGPropertyNode* node) { return node->getLongValue(); } + +template<> +inline float getValue(const SGPropertyNode* node) +{ + return node->getFloatValue(); +} + +template<> +inline double getValue(const SGPropertyNode* node) +{ + return node->getDoubleValue(); +} + +template<> +inline const char * getValue(const SGPropertyNode* node) +{ + return node->getStringValue (); +} + +inline bool setValue(SGPropertyNode* node, bool value) +{ + return node->setBoolValue(value); +} + +inline bool setValue(SGPropertyNode* node, int value) +{ + return node->setIntValue(value); +} + +inline bool setValue(SGPropertyNode* node, long value) +{ + return node->setLongValue(value); +} + +inline bool setValue(SGPropertyNode* node, float value) +{ + return node->setFloatValue(value); +} + +inline bool setValue(SGPropertyNode* node, double value) +{ + return node->setDoubleValue(value); +} + +inline bool setValue(SGPropertyNode* node, const char* value) +{ + return node->setStringValue(value); +} +inline bool setValue (SGPropertyNode* node, const std::string& value) +{ + return node->setStringValue(value.c_str()); +} + +template +bool SGPropertyNode::tie(const SGRawValue &rawValue, bool useDefault) +{ + using namespace simgear::props; + if (_type == ALIAS || _tied) + return false; + + useDefault = useDefault && hasValue(); + T old_val = SGRawValue::DefaultValue(); + if (useDefault) + old_val = getValue(this); + clearValue(); + if (PropertyTraits::Internal) + _type = PropertyTraits::type_tag; + else + _type = EXTENDED; + _tied = true; + _value.val = rawValue.clone(); + if (useDefault) { + int save_attributes = getAttributes(); + setAttribute( WRITE, true ); + setValue(old_val); + setAttributes( save_attributes ); + } + return true; +} + +template<> +bool SGPropertyNode::tie (const SGRawValue &rawValue, + bool useDefault); + +template +T SGPropertyNode::getValue(typename boost::disable_if_c::Internal>::type* dummy) const +{ + using namespace simgear::props; + if (_attr == (READ|WRITE) && _type == EXTENDED + && _value.val->getType() == PropertyTraits::type_tag) { + return static_cast*>(_value.val)->getValue(); + } + if (getAttribute(TRACE_READ)) + trace_read(); + if (!getAttribute(READ)) + return SGRawValue::DefaultValue(); + switch (_type) { + case EXTENDED: + if (_value.val->getType() == PropertyTraits::type_tag) + return static_cast*>(_value.val)->getValue(); + break; + case STRING: + case UNSPECIFIED: + return simgear::parseString(make_string()); + break; + default: // avoid compiler warning + break; + } + return SGRawValue::DefaultValue(); +} + +template +inline T SGPropertyNode::getValue(typename boost::enable_if_c::Internal>::type* dummy) const +{ + return ::getValue(this); +} + +template +bool SGPropertyNode::setValue(const T& val, + typename boost::disable_if_c::Internal>::type* dummy) +{ + using namespace simgear::props; + if (_attr == (READ|WRITE) && _type == EXTENDED + && _value.val->getType() == PropertyTraits::type_tag) { + static_cast*>(_value.val)->setValue(val); + return true; + } + if (getAttribute(WRITE) + && ((_type == EXTENDED + && _value.val->getType() == PropertyTraits::type_tag) + || _type == NONE || _type == UNSPECIFIED)) { + if (_type == NONE || _type == UNSPECIFIED) { + clearValue(); + _type = EXTENDED; + _value.val = new SGRawValueContainer(val); + } else { + static_cast*>(_value.val)->setValue(val); + } + if (getAttribute(TRACE_WRITE)) + trace_write(); + return true; + } + return false; +} + +template +inline bool SGPropertyNode::setValue(const T& val, + typename boost::enable_if_c::Internal>::type* dummy) +{ + return ::setValue(this, val); +} + +/** + * Utility function for creation of a child property node. + */ +inline SGPropertyNode* makeChild(SGPropertyNode* parent, const char* name, + int index = 0) +{ + return parent->getChild(name, index, true); +} + +/** + * Utility function for creation of a child property node using a + * relative path. + */ +namespace simgear +{ +template +inline SGPropertyNode* makeNode(SGPropertyNode* parent, const StringType& name) +{ + return parent->getNode(name, true); +} +} + +// For boost::hash +size_t hash_value(const SGPropertyNode& node); + +// Helper comparison and hash functions for common cases + +namespace simgear +{ +namespace props +{ +struct Compare +{ + bool operator()(const SGPropertyNode* lhs, const SGPropertyNode* rhs) const + { + return SGPropertyNode::compare(*lhs, *rhs); + } + bool operator()(SGPropertyNode_ptr lhs, const SGPropertyNode* rhs) const + { + return SGPropertyNode::compare(*lhs, *rhs); + } + bool operator()(const SGPropertyNode* lhs, SGPropertyNode_ptr rhs) const + { + return SGPropertyNode::compare(*lhs, *rhs); + } + bool operator()(SGPropertyNode_ptr lhs, SGPropertyNode_ptr rhs) const + { + return SGPropertyNode::compare(*lhs, *rhs); + } }; +struct Hash +{ + size_t operator()(const SGPropertyNode* node) const + { + return hash_value(*node); + } + size_t operator()(SGPropertyNode_ptr node) const + { + return hash_value(*node); + } +}; +} +} #endif // __PROPS_HXX // end of props.hxx