00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
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
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
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
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