fields.h

Go to the documentation of this file.
00001 
00004 
00005 //
00006 // Copyright (c) 2000-2004 California Institute of Technology
00007 // Copyright (c) 2004-2007 University of Southern California
00008 // Rob Peters <rjpeters at usc dot edu>
00009 //
00010 // created: Sat Nov 11 15:25:00 2000
00011 // commit: $Id: fields.h 10065 2007-04-12 05:54:56Z rjpeters $
00012 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/io/fields.h $
00013 //
00014 // --------------------------------------------------------------------
00015 //
00016 // This file is part of GroovX.
00017 //   [http://ilab.usc.edu/rjpeters/groovx/]
00018 //
00019 // GroovX is free software; you can redistribute it and/or modify it
00020 // under the terms of the GNU General Public License as published by
00021 // the Free Software Foundation; either version 2 of the License, or
00022 // (at your option) any later version.
00023 //
00024 // GroovX is distributed in the hope that it will be useful, but
00025 // WITHOUT ANY WARRANTY; without even the implied warranty of
00026 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00027 // General Public License for more details.
00028 //
00029 // You should have received a copy of the GNU General Public License
00030 // along with GroovX; if not, write to the Free Software Foundation,
00031 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00032 //
00034 
00035 #ifndef GROOVX_IO_FIELDS_H_UTC20051109000918_DEFINED
00036 #define GROOVX_IO_FIELDS_H_UTC20051109000918_DEFINED
00037 
00038 #include "io/reader.h"
00039 #include "io/writer.h"
00040 
00041 #include "nub/object.h"
00042 
00043 #include "rutz/algo.h"
00044 #include "rutz/fileposition.h"
00045 #include "rutz/fstring.h"
00046 #include "rutz/shared_ptr.h"
00047 #include "rutz/stderror.h"
00048 #include "rutz/traits.h"
00049 #include "rutz/value.h"
00050 
00051 #include <limits>
00052 
00053 namespace rutz
00054 {
00055   template <class T> class fwd_iter;
00056 }
00057 
00058 namespace io
00059 {
00060   class reader;
00061   class writer;
00062 }
00063 
00064 namespace nub
00065 {
00066   class signal0;
00067 }
00068 
00069 class FieldContainer;
00070 
00071 namespace FieldAux
00072 {
00074 
00077   template <class C, class F>
00078   inline C& cast(F& p);
00079 
00080   void throwNotAllowed(const char* what, const rutz::file_pos& pos);
00081 }
00082 
00084 
00090 
00091 
00092 class FieldImpl
00093 {
00094 public:
00096   virtual ~FieldImpl();
00097 
00099   virtual void readValueFrom(FieldContainer* obj,
00100                              io::reader& reader,
00101                              const rutz::fstring& name) const = 0;
00103   virtual void writeValueTo(const FieldContainer* obj,
00104                             io::writer& writer,
00105                             const rutz::fstring& name) const = 0;
00106 };
00107 
00108 namespace
00109 {
00110   template <class C, class T>
00111   struct MatchConst
00112   {
00113     typedef T Type;
00114   };
00115 
00116   template <class C, class T>
00117   struct MatchConst<const C, T>
00118   {
00119     typedef const T Type;
00120   };
00121 
00122   template <class C, class T>
00123   struct Deref
00124   {
00125     typedef typename MatchConst<C,T>::Type Type;
00126 
00127     static Type& get(C& obj, T C::* mptr) { return (obj.*mptr); }
00128   };
00129 
00130   template <class C, class T>
00131   struct Deref<C, T*>
00132   {
00133     typedef typename MatchConst<C,T>::Type Type;
00134 
00135     static Type& get(C& obj, T* C::* mptr) { return *(obj.*mptr); }
00136   };
00137 
00138   template <class C, class T>
00139   typename Deref<C,T>::Type&
00140   dereference(C& obj, T C::* mptr)
00141   {
00142     return Deref<C,T>::get(obj, mptr);
00143   }
00144 
00145   template <class C, class T>
00146   typename Deref<const C,T>::Type&
00147   const_dereference(const C& obj, T C::* mptr)
00148   {
00149     return Deref<const C,T>::get(obj, mptr);
00150   }
00151 
00152   template <class PM>
00153   struct PmTraits;
00154 
00155   template <class C, class T>
00156   struct PmTraits<T C::*>
00157   {
00158     typedef C ClassType;
00159     typedef T MemType;
00160   };
00161 }
00162 
00163 
00164 
00166 template <class PM>
00167 class DataMemberFieldImpl : public FieldImpl
00168 {
00169 public:
00170   // PM is a pointer-to-member-type of the form "T C::*"
00171   typedef typename PmTraits<PM>::ClassType C;
00172   typedef typename PmTraits<PM>::MemType T;
00173 
00175   typedef typename rutz::type_traits<T>::deref_t deref_t;
00176 
00178   DataMemberFieldImpl(T C::* memptr) : itsDataMember(memptr) {}
00179 
00180   static rutz::shared_ptr<FieldImpl>
00181   make(T C::* memptr)
00182   {
00183     return rutz::shared_ptr<FieldImpl> (new DataMemberFieldImpl(memptr));
00184   }
00185 
00187   virtual void readValueFrom(FieldContainer* obj,
00188                              io::reader& reader,
00189                              const rutz::fstring& name) const
00190   {
00191     C& cobj = FieldAux::cast<C>(*obj);
00192 
00193     reader.read_value(name, dereference(cobj, itsDataMember));
00194   }
00195 
00197   virtual void writeValueTo(const FieldContainer* obj,
00198                             io::writer& writer,
00199                             const rutz::fstring& name) const
00200   {
00201     const C& cobj = FieldAux::cast<const C>(*obj);
00202 
00203     writer.write_value(name.c_str(), const_dereference(cobj, itsDataMember));
00204   }
00205 
00206 private:
00207   DataMemberFieldImpl& operator=(const DataMemberFieldImpl&);
00208   DataMemberFieldImpl(const DataMemberFieldImpl&);
00209 
00210   T C::* itsDataMember;
00211 };
00212 
00214 template <class PM>
00215 class CheckedDataMemberFieldImpl : public FieldImpl
00216 {
00217 public:
00218   // PM is a pointer-to-member-type of the form "T C::*"
00219   typedef typename PmTraits<PM>::ClassType C;
00220   typedef typename PmTraits<PM>::MemType T;
00221 
00223   typedef typename rutz::type_traits<T>::deref_t deref_t;
00224 
00226   CheckedDataMemberFieldImpl(T C::* memptr,
00227                              const deref_t& min,
00228                              const deref_t& max) :
00229     itsDataMember(memptr),
00230     itsMin(min),
00231     itsMax(max)
00232   {}
00233 
00234   static rutz::shared_ptr<FieldImpl>
00235   make(T C::* memptr, const deref_t& min, const deref_t& max)
00236   {
00237     return rutz::shared_ptr<FieldImpl>
00238       (new CheckedDataMemberFieldImpl(memptr, min, max));
00239   }
00240 
00242   virtual void readValueFrom(FieldContainer* obj,
00243                              io::reader& reader,
00244                              const rutz::fstring& name) const
00245   {
00246     C& cobj = FieldAux::cast<C>(*obj);
00247 
00248     deref_t temp;
00249 
00250     reader.read_value(name, temp);
00251 
00252     dereference(cobj, itsDataMember) = this->limit(temp);
00253   }
00254 
00256   virtual void writeValueTo(const FieldContainer* obj,
00257                             io::writer& writer,
00258                             const rutz::fstring& name) const
00259   {
00260     const C& cobj = FieldAux::cast<const C>(*obj);
00261 
00262     writer.write_value(name.c_str(), const_dereference(cobj, itsDataMember));
00263   }
00264 
00265 private:
00266   CheckedDataMemberFieldImpl(const CheckedDataMemberFieldImpl&);
00267   CheckedDataMemberFieldImpl& operator=(const CheckedDataMemberFieldImpl&);
00268 
00269   deref_t limit(const deref_t& raw) const
00270   {
00271     return rutz::clamp(raw, itsMin, itsMax);
00272   }
00273 
00274   T C::* itsDataMember;
00275   const deref_t itsMin;
00276   const deref_t itsMax;
00277 };
00278 
00280 template <class C, class V>
00281 class ValueFieldImpl : public FieldImpl
00282 {
00283 public:
00285   ValueFieldImpl(V C::* memptr) : itsValueMember(memptr) {}
00286 
00287   virtual void readValueFrom(FieldContainer* obj,
00288                              io::reader& reader,
00289                              const rutz::fstring& name) const
00290   {
00291     C& cobj = FieldAux::cast<C>(*obj);
00292 
00293     reader.read_value_obj(name, dereference(cobj, itsValueMember));
00294   }
00295 
00296   virtual void writeValueTo(const FieldContainer* obj,
00297                             io::writer& writer,
00298                             const rutz::fstring& name) const
00299   {
00300     const C& cobj = FieldAux::cast<const C>(*obj);
00301 
00302     writer.write_value_obj(name.c_str(), const_dereference(cobj, itsValueMember));
00303   }
00304 
00305 private:
00306   ValueFieldImpl& operator=(const ValueFieldImpl&);
00307   ValueFieldImpl(const ValueFieldImpl&);
00308 
00309   V C::* itsValueMember;
00310 };
00311 
00313 template <class C, class T>
00314 class FuncMemberFieldImpl : public FieldImpl
00315 {
00316   typedef T (C::* Getter)() const;
00317   typedef void (C::* Setter)(T);
00318 
00319   Getter itsGetter;
00320   Setter itsSetter;
00321 
00322   FuncMemberFieldImpl& operator=(const FuncMemberFieldImpl&);
00323   FuncMemberFieldImpl(const FuncMemberFieldImpl&);
00324 
00325 public:
00327   FuncMemberFieldImpl(Getter g, Setter s) : itsGetter(g), itsSetter(s) {}
00328 
00329   virtual void readValueFrom(FieldContainer* obj,
00330                              io::reader& reader,
00331                              const rutz::fstring& name) const
00332   {
00333     if (itsSetter == 0) FieldAux::throwNotAllowed("read", SRC_POS);
00334 
00335     C& cobj = FieldAux::cast<C>(*obj);
00336 
00337     typedef typename rutz::type_traits<T>::stack_t stack_t;
00338 
00339     stack_t temp;
00340     reader.read_value(name, temp);
00341     (cobj.*itsSetter)(temp);
00342   }
00343 
00344   virtual void writeValueTo(const FieldContainer* obj,
00345                             io::writer& writer,
00346                             const rutz::fstring& name) const
00347   {
00348     if (itsGetter == 0) FieldAux::throwNotAllowed("write", SRC_POS);
00349 
00350     const C& cobj = FieldAux::cast<const C>(*obj);
00351 
00352     writer.write_value(name.c_str(), (cobj.*itsGetter)());
00353   }
00354 };
00355 
00357 
00364 
00365 
00366 class Field
00367 {
00368 private:
00369   const rutz::fstring               itsName;
00370   const rutz::shared_ptr<FieldImpl> itsFieldImpl;
00371   const rutz::fstring               itsDefaultValue;
00372   const rutz::fstring               itsMin;
00373   const rutz::fstring               itsMax;
00374   const rutz::fstring               itsRes;
00375   const unsigned int                itsFlags;
00376   io::version_id                     itsMinVersion;
00377   io::version_id                     itsMaxVersion;
00378 
00379 public:
00380 
00381   //
00382   // Attribute flags
00383   //
00384 
00385   static const unsigned int NEW_GROUP = 1 << 0; 
00386   static const unsigned int TRANSIENT = 1 << 1; 
00387   static const unsigned int STRING    = 1 << 2; 
00388   static const unsigned int MULTI     = 1 << 3; 
00389   static const unsigned int CHECKED   = 1 << 4; 
00390   static const unsigned int NO_GET    = 1 << 5; 
00391   static const unsigned int NO_SET    = 1 << 6; 
00392   static const unsigned int PRIVATE   = 1 << 7; 
00393   static const unsigned int BOOLEAN   = 1 << 8; 
00394 
00396   unsigned int flags()    const { return itsFlags; }
00397 
00399   bool startsNewGroup()   const { return   itsFlags & NEW_GROUP; }
00400 
00402   bool isTransient()      const { return   itsFlags & TRANSIENT ; }
00404   bool isPersistent()     const { return !(itsFlags & TRANSIENT); }
00405 
00407   bool isString()         const { return   itsFlags & STRING ; }
00409   bool isNumeric()        const { return !(itsFlags & STRING); }
00410 
00412   bool isMultiValued()    const { return   itsFlags & MULTI ; }
00414   bool isSingleValued()   const { return !(itsFlags & MULTI); }
00415 
00417   bool isChecked()        const { return   itsFlags & CHECKED ; }
00419   bool isUnchecked()      const { return !(itsFlags & CHECKED); }
00420 
00422   bool allowGet()         const { return !(itsFlags & NO_GET); }
00424   bool allowSet()         const { return !(itsFlags & NO_SET); }
00425 
00427   bool isPrivate()        const { return   itsFlags & PRIVATE ; }
00429   bool isPublic()         const { return !(itsFlags & PRIVATE); }
00430 
00432   bool isBoolean()        const { return   itsFlags & BOOLEAN; }
00433 
00435   struct ValueType {};
00436 
00438   template <class C, class V>
00439   Field(const rutz::fstring& name, ValueType, V C::* value_ptr,
00440         const rutz::fstring& def, const rutz::fstring& min,
00441         const rutz::fstring& max, const rutz::fstring& res,
00442         unsigned int flags=0) :
00443     itsName(name),
00444     itsFieldImpl(new ValueFieldImpl<C,V>(value_ptr)),
00445     itsDefaultValue(def),
00446     itsMin(min),
00447     itsMax(max),
00448     itsRes(res),
00449     itsFlags(flags),
00450     itsMinVersion(0),
00451     itsMaxVersion(std::numeric_limits<io::version_id>::max())
00452   {}
00453 
00455   template <class T, class PM>
00456   Field(const rutz::fstring& name, PM memptr,
00457         const T& def, const T& min, const T& max, const T& res,
00458         unsigned int flags=0) :
00459     itsName(name),
00460     itsFieldImpl((flags & CHECKED)
00461                  ? CheckedDataMemberFieldImpl<PM>::make(memptr, min, max)
00462                  : DataMemberFieldImpl<PM>::make(memptr)
00463                  ),
00464     itsDefaultValue(rutz::sconvert(def)),
00465     itsMin(rutz::sconvert(min)),
00466     itsMax(rutz::sconvert(max)),
00467     itsRes(rutz::sconvert(res)),
00468     itsFlags(flags),
00469     itsMinVersion(0),
00470     itsMaxVersion(std::numeric_limits<io::version_id>::max())
00471   {}
00472 
00474   template <class C, class T>
00475   Field(const rutz::fstring& name,
00476         T (C::* getter)() const,
00477         void (C::* setter)(T),
00478         const T& def, const T& min, const T& max, const T& res,
00479         unsigned int flags=0) :
00480     itsName(name),
00481     itsFieldImpl(new FuncMemberFieldImpl<C,T>(getter, setter)),
00482     itsDefaultValue(rutz::sconvert(def)),
00483     itsMin(rutz::sconvert(min)),
00484     itsMax(rutz::sconvert(max)),
00485     itsRes(rutz::sconvert(res)),
00486     itsFlags(flags),
00487     itsMinVersion(0),
00488     itsMaxVersion(std::numeric_limits<io::version_id>::max())
00489   {}
00490 
00491   Field& versions(io::version_id lo,
00492                   io::version_id hi
00493                   = std::numeric_limits<io::version_id>::max())
00494   {
00495     itsMinVersion = lo;
00496     itsMaxVersion = hi;
00497     return *this;
00498   }
00499 
00501   const rutz::fstring& name() const { return itsName; }
00503   const rutz::fstring& defaultValue() const { return itsDefaultValue; }
00504 
00506   const rutz::fstring& min() const { return itsMin; }
00508   const rutz::fstring& max() const { return itsMax; }
00510   const rutz::fstring& res() const { return itsRes; }
00511 
00513   io::version_id minVersion() const { return itsMinVersion; }
00515   io::version_id maxVersion() const { return itsMaxVersion; }
00516 
00517   bool shouldSerialize(io::version_id svid) const
00518   {
00519     return (svid >= itsMinVersion && svid <= itsMaxVersion);
00520   }
00521 
00523   void readValueFrom(FieldContainer* obj,
00524                      io::reader& reader) const
00525   {
00526     itsFieldImpl->readValueFrom(obj, reader, itsName);
00527   }
00528 
00530   void writeValueTo(const FieldContainer* obj,
00531                     io::writer& writer) const
00532   {
00533     itsFieldImpl->writeValueTo(obj, writer, itsName);
00534   }
00535 };
00536 
00538 
00545 
00546 
00547 class FieldMap
00548 {
00549 private:
00550   class Impl;
00551   Impl* rep;
00552 
00553   FieldMap(const FieldMap&);
00554   FieldMap& operator=(const FieldMap&);
00555 
00556   void init(const Field* begin, const Field* end,
00557             const FieldMap* parent);
00558 
00559 public:
00561   FieldMap(const Field* begin, const Field* end,
00562            const FieldMap* parent=0) :
00563     rep(0)
00564   {
00565     init(begin, end, parent);
00566   }
00567 
00569   template<unsigned int N>
00570   FieldMap(Field const (&array)[N], const FieldMap* parent=0) :
00571     rep(0)
00572   {
00573     init(&array[0], &array[0]+N, parent);
00574   }
00575 
00577   ~FieldMap();
00578 
00580   static const FieldMap* emptyFieldMap();
00581 
00583   bool hasParent() const throw();
00584 
00586   const FieldMap* parent() const throw();
00587 
00589 
00591   const Field& field(const rutz::fstring& name) const;
00592 
00594   typedef rutz::fwd_iter<const Field> Iterator;
00595 
00597   Iterator alphaFields() const;
00598 
00600 
00602   Iterator ioFields() const;
00603 };
00604 
00606 
00614 
00615 
00616 class FieldContainer : public virtual nub::object
00617 {
00618 private:
00619   const FieldMap* itsFieldMap;
00620 public:
00621   nub::signal0* itsSignal;
00622 private:
00623   FieldContainer(const FieldContainer&);
00624   FieldContainer& operator=(const FieldContainer&);
00625 
00626 public:
00628   FieldContainer(nub::signal0* sig);
00629 
00631   virtual ~FieldContainer() throw();
00632 
00634   void setFieldMap(const FieldMap& fields);
00635 
00637 
00638   const Field& field(const rutz::fstring& name) const;
00639 
00641   void touch() const;
00642 
00644   void readFieldsFrom(io::reader& reader, const FieldMap& fields);
00646   void writeFieldsTo(io::writer& writer, const FieldMap& fields,
00647                      io::version_id svid) const;
00648 
00650   const FieldMap& fields() const { return *itsFieldMap; }
00651 
00653   virtual FieldContainer* child() const;
00654 };
00655 
00656 template <class C, class F>
00657 inline C& FieldAux::cast(F& p)
00658 {
00659   C* result = dynamic_cast<C*>(&p);
00660 
00661   if (result == 0)
00662     {
00663       F* child = p.child();
00664       if (child != 0)
00665         result = &(FieldAux::cast<C>(*child));
00666       else
00667         rutz::throw_bad_cast(typeid(C), typeid(F), SRC_POS);
00668     }
00669 
00670   return *result;
00671 }
00672 
00673 static const char __attribute__((used)) vcid_groovx_io_fields_h_utc20051109000918[] = "$Id: fields.h 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00674 #endif // !GROOVX_IO_FIELDS_H_UTC20051109000918DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:39 2008 by Doxygen version 1.5.5.