Boost logo

Boost :

From: Ivan Vecerina (ivec_at_[hidden])
Date: 2006-04-23 04:26:52


Hi,
I wanted to give this a shot, as some others have agreed that the
member-interface of ptree should be simplified - to being more like
that of a container.

I would plainly take out all the member functions labeled as
"Ptree-specific operations" (see basic_ptree in the Synopsis in the
main doc page: http://kaalus.atspace.com/ptree/doc/index.html ).
A first step would be to convert them into a set of non-member
functions (preferably in a separate header file).

Another issue is that we have a multitude of functions because
orthogonal features/concepts are being mixed together:
 - get, optional-get, default-get, put, and set (to be added)
 - own-data, child, and any-path access
 - for paths, custom or default separators
 - actual conversion of a value to/from a data string (or a ptree)
 - features such as first-class support for indexing an array
   also might be desirable
Also what about:
 - stricter error checks: what happens if two children have
   the same name, making a path ambiguous? what about "hybrid"
   record/array tree nodes?
 - customization points: how do I specialize the conversion
   of a UDT to/from a ptree ?

I would like to suggest as a starting point for this decomposition,
to make the ptree library more flexible/adaptable to individual
needs.
How about the following building blocks: ?

1) value <-> ptree conversion templates

void set( const Value& v, ptree& storage );
void get( Value& v, ptree const& storage ); //throws if conv. fails
bool tryget( Value& v, ptree const& storage ) //ret. false if fails
  { try{ get(v,storage); return true; }catch(...){} return false; }

The default implementation of these functions would use
lexical_cast to store/retrieve a value to/from a ptree
with only an 'own' value set.
The template could of course be specialized for user-defined types.
For example, I could implement these functions for a struct
used as a member in various locations, and convert it into
a ptree with a child for each struct data member.

Which of get/tryget (throwing and non-throwing functions) is
implemented in terms of the other is TBD.

2) Child access (direct child only)

ptree const& getField( ptree const& tree, string childName );
 // gets a field, throws in case of failure or ambiguity
ptree const& trygetField( ptree const& tree, string childName );
 // returns empty_ptree if the field is not found or ambiguous
ptree& makeField( ptree& tree, string childName );
 // accesses the field, creates it if needed ( like std::map::op[] )

+ Do we want an "addField" function that always creates a new
  child even if one already exists? Or should we provide
  array-indexing functions ?

3) getoptional etc
Shall be defined in terms of a sequence of calls to the
previous functions.
Exact set to be defined as discussed elsewhere.

4) path access
TBD. I'll find it acceptable if existing get/put functions
are preserved as non-member functions, but left outside of
the class, and maybe preferably in a sub-namespace
(ptree_stringpath, or whatever).
Various proposals have been discussed in these review posts,
and again could be implementable in terms of the above.

Comments/opinions ?
Ideas for using operator overloading?

Ivan

-- 
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk