Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
plist Namespace ReferenceA collection of classes to implement the Propery List data storage format, a XML standard used by Apple and others. More...
Detailed DescriptionA collection of classes to implement the Propery List data storage format, a XML standard used by Apple and others. The plist namespace provides convenient serialization for persistent storage, dynamic introspection, and polymorphic primitive values. The classes happen to use Apple's XML-based "property list" format for serialization, using libxml2 for the low level parsing. The choice of storage format was based on a desire for human readability, including per-value comments and inline documentation, as well as the desire to make use of syntax hilighting or high-level editing tools. Individual values are based on templated instances of the Primitive<T> class, while groups of values are based on the Collection interface. Currently, the concrete collections available are Array (one dimensional ordered list of mixed primitive types), ArrayOf<T> (ordered list of a single type), or Dictionary (unordered mapping from string names to mixed primitives). Generally, there are two ways you might use the functionality contained within this namespace. One is as an external storage interface, such as the STL vector and map classes are used. This might be only a intermediary instance for conversion to and from existing data structures, as a higher-level interface than directly accessing libxml. However, to fully benefit from this namespace's functionality, you will generally want your classes to inherit from plist::Dictionary, define your members as public plist Primitives and Collections, and register listeners for notification when these values are modified (either by loading from file or programmatic modification.) Example usage is shown below, you can find this code and more in Tekkotsu/tools/test/plist/. #include "Shared/plist.h" using namespace std; // you might want to 'using namespace plist'... // we'll be using plist:: scoping everywhere below just for clarity /* Generic base class for "shapes"... we specify a generic Collection, * as its base, allows either Dictionary or Array-based! */ class Shape : virtual public plist::Collection {}; /* We will use a float for coordinates, wrapped by a plist::Primitive<> * The Primitive class provides transparent conversions and operations, * so we can usually pretend this is just a regular float! */ typedef plist::Primitive<float> coord_t; /* A point is defined as an array of coordinates, one for each dimension. * We'll assume 2D points unless otherwise directed. * An alternative definition could use explicit 'x' and 'y' members, and/or * use a Dictionary with labels instead of an Array with subscripts... */ class Point : public Shape, virtual public plist::ArrayOf<coord_t> { public: explicit Point(size_t n=2) : plist::ArrayOf<coord_t>(n,0), Shape() { } Point(float xVal, float yVal) : plist::ArrayOf<coord_t>(2,0), Shape() { getEntry(0)=xVal; getEntry(1)=yVal; } }; /* We'll define a rectangle by the lower-left point and the upper-right point. * Further, we'll set up an accessor to maintain this invariant. */ class Rectangle : public Shape, public virtual plist::DictionaryOf<Point> { public: Rectangle() : plist::DictionaryOf<Point>(), Shape(), lower(), upper(), xm(lower[0],upper[0]), ym(lower[1],upper[1]) { /* The next line 'fixes' the entries during load, save, or assignment. * The default is to allow dynamic resizing, so you should call this when * you expect the entry structure to be immutable. (e.g. if you are using * members as collection entries.) */ setLoadSavePolicy(FIXED,SYNC); addEntry("lower",lower); // still can always 'explicitly' add or remove entries addEntry("upper",upper); // ... the LoadSavePolicy only restricts 'implicit' changes } /* Can provide public access to members, the Monitor will provide * the flexibility usually provided by get/set accessor functions. */ Point lower, upper; /* Note automatic conversion to value type, will never be negative due to our Monitor */ float getWidth() const { return upper[0] - lower[0]; } float getHeight() const { return upper[1] - lower[1]; } protected: /* Implements plist::PrimitiveListener to receive notification when * a member's value is changed. We could also do this by having * rectangle itself be the listener instead of an inner class. */ class Monitor : public plist::PrimitiveListener { public: Monitor(coord_t& low, coord_t& high) : _low(low), _high(high) { _low.addPrimitiveListener(this); _high.addPrimitiveListener(this); } virtual void plistValueChanged(const plist::PrimitiveBase&) { if(_low>_high) std::swap(_low,_high); } protected: coord_t &_low, &_high; } xm, ym; }; /* Here's an example of a purely dynamic class... just a resizeable list * of points! For a "real" implementation, you'd probably want to use * a dictionary, add a few more properties (e.g. 'isClosed'), and have * the point list as a member variable... */ class Polygon : public Shape, public virtual plist::ArrayOf<Point> {}; // Here's some sample usage... int main(int argc, const char** argv) { Point p; p[0] = 1; // transparent conversion from value type to plist::Primitive p[1] = 2.5; p.saveFile("point.plist"); Rectangle r; r.upper = Point(4,5); // we can assign to directly to member... r["lower"] = p; // ... or dynamically via operator[] lookup r.saveFile("rectangle.plist"); // test the low/high invariant cout << "Original r, width: " << r.getWidth() << '\n' << r; /* Original r, width: 3 * lower.0 = 1 * lower.1 = 2.5 * upper.0 = 4 * upper.1 = 5 */ r.upper[0] = -4; // note we assign to upper.x, but it's lower.x that will be -4 // (because of the PrimitiveListener added by Rectangle's constructor) cout << "Negated r, width: " << r.getWidth() << '\n' << r; /* Negated r, width: 5 * lower.0 = -4 * lower.1 = 2.5 * upper.0 = 1 * upper.1 = 5 */ // dynamic resizing: Polygon poly; /* Notice we are adding pointers here, vs. references in Rectangle, * vs. float values in Point. (De)allocation from pointers or converted * values is handled by the collection, whereas entries added from * references are *not* deallocated. */ poly.addEntry(new Point(1,2)); poly.addEntry(new Point(3,4)); poly.addEntry(new Point(5,0)); poly.saveFile("poly.plist"); return 0; } Typedef Documentation
plist::Array can handle any mixture of types, whereas plist::ArrayOf<PO> will only accept the plist objects of type PO (or their subclasses). This typedef is simply for convenience and passes ObjectBase for the template parameter. Definition at line 1345 of file plistCollections.h.
plist::Dictionary can handle any mixture of types, whereas plist::DictionaryOf<PO> will only accept the plist objects of type PO (or their subclasses). This typedef is simply for convenience and passes ObjectBase for the template parameter. Definition at line 641 of file plistCollections.h.
Definition at line 14 of file plistSpecialty.h. Function Documentation
template<class T >
allocates a new T instance, unless T is a known abstract type (ObjectBase, PrimitiveBase, Collection), in which case will throw a bad_cast via template specialization Definition at line 15 of file plistCollections.h.
template<>
SensorInfo::sensorType.set() could still lead to trouble, although with a little work we could probably find a way to support it... not supported Definition at line 36 of file PlannerObstacles.h.
template<class T >
assigns one T to another using operator=, unless T is ObjectBase, in which case set() is used via template specialization Definition at line 17 of file plistCollections.h. Referenced by plist::ArrayOf< PO, Alloc >::operator=(), and plist::DictionaryOf< PO, Alloc >::operator=().
template<>
template<>
take a compiled regex and maximum depth for display
take a regex and maximum depth for display (displays entries whos names match the filter sel
Referenced by operator<<().
template<typename T >
returns a string indicating the plist entry type to use for the specified type some primitives (bool, char) aren't handled because they require a specialization of Primitive and won't use this function. If you want to use a plist Primitive of some custom type, you might be able to just define a new specialization of this function and provide iostream <</>> operators for your type...
Attempts to parse the buffer found at buf, using plist::loadXML().
Attempts to parse the file found at file, using plist::loadXML().
template<class T >
attempts to load a new T instance from the specified xmlNode Definition at line 27 of file plistCollections.h.
template<>
This specialization looks for the SensorInfo::sensorType, then has the factory construct the correct subtype before loading the node into and returning that. From the name of node, will instantiate a new ObjectBase subclass to load it. supports use of plist::ArrayOf<PlannerObstacle> for polymorphic load/save The mapping from node names to actual instantiated types is:
If successful, returns a pointer to a newly allocated region, which the caller is responsible for freeing. If an error occurs, NULL is returned. Definition at line 28 of file PlannerObstacles.cc.
provides textual output Definition at line 1581 of file plistCollections.h.
provides textual output Definition at line 1578 of file plistCollections.h.
output stringified value (from PrimitiveBase::get()) to stream Definition at line 290 of file plistBase.h.
output of an ObjectBase to a stream Definition at line 208 of file plistBase.h.
input value from next word in is, via PrimitiveBase::set() Definition at line 294 of file plistBase.h. |
Tekkotsu v5.1CVS |
Generated Mon May 9 04:59:24 2016 by Doxygen 1.6.3 |