CppUnit project page CppUnit home page

value.h

Go to the documentation of this file.
00001 #ifndef CPPTL_VALUE_H_INCLUDED
00002 # define CPPTL_VALUE_H_INCLUDED
00003 # include "forwards.h"
00004 # include "typetraits.h"
00005 
00006 
00007 /*
00008 * need a new Any supporting feature required for unit testing:
00009   - toString (toJson?)
00010   - type to text (for conversion error message)
00011   - equality comparison test (input fixture)
00012   - support for basic types
00013   - support for string types
00014   - support for unknown aggregate types.
00015   - conversion between type (int, uint, const char *, std::string...)
00016   - type comparison
00017 
00018 Implemented:
00019 - framework to expose any service for Value
00020 - framework for comparison
00021 
00022 To do:
00023 - type identification, comparison and hashing
00024 - type to string
00025 - conversion
00026 
00027 To think:
00028 - pointer and cast support
00029 - smart-pointer ? Notes: requires dynamic allocation of target object
00030 
00031 About type identification:
00032 - we already force the creation of a static to identify type.
00033 - it can be used to replace type_info and all its bug & portability issues.
00034 - but still need to be able to identify that two types are similar
00035 Problems:
00036 dll / static linking:
00037 type info are not shared. Solution: use a single registry held in a dll.
00038 thread-safe registration:
00039 static variable stored in getValueType is a pointer on type in the registry.
00040 ValueType is copied by value in the registry ensuring a single pointer is always returned.
00041 Registry is synchronized to ensure type safety.
00042 
00043 
00044 */
00045 
00046 namespace CppTL {
00047 
00048 class Value;
00049 class ValueType;
00050 class ValueTypeRegistry;
00051 
00052 // //////////////////////////////////////////////////////////////////
00053 // //////////////////////////////////////////////////////////////////
00054 // class ValueType
00055 // //////////////////////////////////////////////////////////////////
00056 // //////////////////////////////////////////////////////////////////
00057 
00058 class ValueType
00059 {
00060 public:
00061    static ValueType typeInt;
00062    static ValueType typeUInt;
00063    static ValueType typeDouble;
00064    static ValueType typeString;
00065    static ValueType typeCString;
00066 
00067    void clear()
00068    {
00069       memset( this, 0, sizeof(ValueType) );
00070    }
00071 
00072    // Notes: clone & initialize seems similar
00073    void (*initialize_)( const void *data, Value &target );
00076    void (*clone_)( const Value &source, Value &target );
00077    void (*destroy_)( Value &target );
00078    ConstCharView (*typeToString_)();
00079    ConstCharView (*valueToString_)();
00080    void (*convertTo_)( const Value &source, Value &target );
00081 
00085    int (*compare_)( const Value &a, const Value &b, bool &canCompare );
00086 
00090    bool (*less_)( const Value &a, const Value &b, bool &canCompare );
00091 
00095    bool (*equal_)( const Value &a, const Value &b, bool &canCompare );
00096 
00097    // ? was used for conversion I think.
00098    void (*rawData_)( Value &value );
00099 };
00100 
00101 // //////////////////////////////////////////////////////////////////
00102 // //////////////////////////////////////////////////////////////////
00103 // class Value
00104 // //////////////////////////////////////////////////////////////////
00105 // //////////////////////////////////////////////////////////////////
00106 
00107 
00108 typedef LargestInt ValueInt;
00109 typedef LargestUnsignedInt ValueUInt;
00110 
00111 typedef char ValueDataBuffer[24];
00112 
00113 union ValueData
00114 {
00115    //ValueInt int_;
00116    //ValueUInt uint_;
00117    //double double_;
00118    ValueDataBuffer string_;
00119    void *other_;
00120 };
00121 
00122 struct NoneValueTypeTag
00123 {
00124 };
00125 
00126 class ValueException : public std::runtime_error
00127 {
00128 public:
00129    enum Cause
00130    {
00131       notSameType = 1
00132    };
00133    ValueException( Cause cause, const char *message,
00134                    const ValueType *lhs, const ValueType *rhs )
00135       : std::runtime_error( "Can not proceed. ValueType are not compatible" )
00136       , lhs_( lhs )
00137       , rhs_( rhs )
00138    {
00139    }
00140 
00141    const ValueType * const lhs_;
00142    const ValueType * const rhs_;
00143 };
00144 
00147 class Value
00148 {
00149 public:
00150    typedef ValueInt Int;
00151    typedef ValueUInt UInt;
00152 
00153    Value();
00154 
00155    Value( const ValueType &type, const void *data );
00156 
00157    Value( const Value &other )
00158    {
00159       type_ = other.type_;
00160       type_->clone_( other, *this );
00161    }
00162 
00163    ~Value()
00164    {
00165       if ( type_->destroy_ )
00166          type_->destroy_( *this );
00167    }
00168 
00169    Value &operator =( const Value &other )
00170    {
00171       if( &other != this )
00172       {
00173          if ( type_->destroy_ )
00174             type_->destroy_( *this );
00175          type_ = other.type_;
00176          type_->clone_( other, *this );
00177       }
00178       return *this;
00179    }
00180 
00181    bool isNone() const;
00182    bool isInt() const;
00183    bool isUInt() const;
00184    bool isDouble() const;
00185    bool isString() const;
00186 
00187    Int asInt() const;
00188    UInt asUInt() const;
00189    double asDouble() const;
00190    ConstCharView asString() const;
00191 
00192    bool convertTo( const ValueType &targetType, Value &other ) const
00193    {
00194       return false;
00195    }
00196 
00218    int compare( const Value &other, bool &canCompare, bool allowAutoConvert = true ) const
00219    {
00220       if ( type_ != other.type_ )
00221       {
00222          Value otherSameType;
00223          if ( other.convertTo( *type_, otherSameType ) )
00224             return compare( otherSameType, canCompare );
00225       }
00226       else if ( type_->compare_ )
00227       {
00228          canCompare = true;
00229          return type_->compare_( *this, other, canCompare );
00230       }
00231       else if ( type_->less_ )
00232       {
00233          canCompare = true;
00234          bool lhsLessThanRhs = type_->less_( *this, other, canCompare );
00235          if ( lhsLessThanRhs )
00236             return -1;
00237          if ( canCompare  &&  type_->equal_ )
00238             return type_->equal_( *this, other, canCompare ) ? 0 : 1;
00239          if ( canCompare )
00240             return type_->less_( other, *this, canCompare ) ? 1 : 0;
00241          return 0;
00242       }
00243       canCompare = false;
00244       return 0;
00245    }
00246 
00248    bool operator <( const Value &other ) const;
00250    bool operator <=( const Value &other ) const;
00252    bool operator ==( const Value &other ) const;
00254    bool operator !=( const Value &other ) const;
00256    bool operator >=( const Value &other ) const;
00258    bool operator >( const Value &other ) const;
00259 
00260 public:
00262    ValueData data_;
00263 
00264 private:
00265    const ValueType *type_;
00266 };
00267 
00268 // //////////////////////////////////////////////////////////////////
00269 // //////////////////////////////////////////////////////////////////
00270 // Value, free functions
00271 // //////////////////////////////////////////////////////////////////
00272 // //////////////////////////////////////////////////////////////////
00273 
00274 /*
00275  * Notes: user can provides a specific implementation by overloding getValueType() for a given
00276  * type.
00277  * inline const ValueType &getValueType( const Type<T> & )
00278  */
00279 
00280 #ifdef CPPTL_NO_FUNCTION_TEMPLATE_ORDERING
00281    struct HasDefaultValueTypeHelper
00282    {
00283    };
00284 
00285    inline HasDefaultValueTypeHelper getValueType( ... )
00286    {
00287       return HasDefaultValueTypeHelper();
00288    }
00289 
00290    template<class T>
00291    inline const ValueType &getValueTypeHelper( const ValueType &valueType, 
00292                                                const Type<T> &type )
00293    {
00294       return valueType;
00295    }
00296 
00297    template<class T>
00298    inline const ValueType &getValueTypeSelector( const Type<T> &type )
00299    {
00300       return getValueTypeHelper( getValueType(type), type );
00301    }
00302 
00303 #  define CPPTL_GET_VALUE_TYPE( AType ) ::CppTL::getValueTypeSelector( ::CppTL::Type<AType>() )
00304 
00305 # else
00306 
00307 #  define CPPTL_GET_VALUE_TYPE( AType ) ::CppTL::getValueType( ::CppTL::Type<AType>() )
00308 
00309 # endif
00310 
00311 
00312 template<typename TargetValueType>
00313 void initialize( Value &value, Type<TargetValueType> )
00314 {
00315 }
00316 
00317 template<typename TargetValueType>
00318 Value initialize( Type<TargetValueType> )
00319 {
00320 }
00321 
00322 
00323 template<typename TargetValueType>
00324 Value makeValue( const TargetValueType &value )
00325 {
00326    const ValueType &type = CPPTL_GET_VALUE_TYPE( TargetValueType );
00327    return Value( type, &value );
00328 }
00329 
00330 template<typename TargetValueType>
00331 void makeValue( Value &value, const TargetValueType &initialValue )
00332 {
00333 }
00334 
00335 
00336 template<typename TargetValueType>
00337 const TargetValueType &any_cast( const Value &value, Type<TargetValueType> )
00338 {
00339 }
00340 
00341 template<typename TargetValueType>
00342 TargetValueType &any_cast( Value &value, Type<TargetValueType> )
00343 {
00344 }
00345 
00346 template<typename TargetValueType>
00347 const TargetValueType *any_cast( const Value *value, Type<TargetValueType> )
00348 {
00349 }
00350 
00351 template<typename TargetValueType>
00352 TargetValueType *any_cast( Value *value, Type<TargetValueType> )
00353 {
00354 }
00355 
00356 
00357 // //////////////////////////////////////////////////////////////////
00358 // //////////////////////////////////////////////////////////////////
00359 // namespace ValueTypeHelper
00360 // //////////////////////////////////////////////////////////////////
00361 // //////////////////////////////////////////////////////////////////
00362 
00363 namespace ValueTypeHelper {
00364 
00365 
00367 template<typename DataType>
00368 class LargeTypeStorageHelper
00369 {
00370 public:
00371    static DataType &data( Value &value )
00372    {
00373       return *static_cast<DataType *>( value.data_.other_ );
00374    }
00375 
00376    static const DataType &data( const Value &value )
00377    {
00378       return *static_cast<const DataType *>( value.data_.other_ );
00379    }
00380 
00381    static void initialize( const void *data, Value &target )
00382    {
00383       target.data_.other_ = new DataType( *static_cast<const DataType *>( data ) );
00384    }
00385 
00386    static void clone( const Value &source, Value &target )
00387    {
00388       target.data_.other_ = new DataType( data(source) );
00389    }
00390    
00391    static void destroy( Value &target )
00392    {
00393       delete target.data_.other_;
00394    }
00395 };
00396 
00397 
00399 template<typename DataType>
00400 class SmallTypeStorageHelper
00401 {
00402 public:
00403    static DataType &data( Value &value )
00404    {
00405       return *(DataType *)( value.data_.string_ );
00406    }
00407 
00408    static const DataType &data( const Value &value )
00409    {
00410       return *(const DataType *)( value.data_.string_ );
00411    }
00412 
00413    static void initialize( const void *sourceData, Value &target )
00414    {
00415       DataType *targetData = &data(target);
00416       new (targetData) DataType( *static_cast<const DataType *>( sourceData ) ); // placement new
00417    }
00418 
00419    static void clone( const Value &source, Value &target )
00420    {
00421       DataType *targetData = &data(target);
00422       new (targetData) DataType( data(source) ); // placement new
00423    }
00424    
00425    static void destroy( Value &target )
00426    {
00427       data(target).~DataType();
00428    }
00429 };
00430 
00431 
00433 template<typename DataType>
00434 class StoragePolicySelector
00435 {
00436 public:
00437    typedef CPPTL_TYPENAME IfType<LargeTypeStorageHelper<DataType>
00438                                 ,SmallTypeStorageHelper<DataType>
00439                                 ,(sizeof(DataType) > sizeof(ValueDataBuffer)) 
00440                                 >::type type;
00441 };
00442 
00443 
00444 template<typename DataType>
00445 class CommonLifeCycle
00446 {
00447 public:
00448    typedef CommonLifeCycle<DataType> SelfType;
00449    typedef CPPTL_TYPENAME StoragePolicySelector<DataType>::type StoragePolicy;
00450 
00451    static void registerFunctions( ValueType &type )
00452    {
00453       type.initialize_ = &StoragePolicy::initialize;
00454       type.clone_ = &StoragePolicy::clone;
00455       type.destroy_ = &StoragePolicy::destroy;
00456    }
00457 };
00458 
00459 
00460 
00463 template<typename DataType>
00464 class Compare
00465 {
00466 public:
00467    typedef Compare<DataType> SelfType;
00468    typedef CPPTL_TYPENAME StoragePolicySelector<DataType>::type StoragePolicy;
00469 
00470    static void registerFunctions( ValueType &type )
00471    {
00472       type.compare_ = &SelfType::compare;
00473       type.less_ = &SelfType::less;
00474       type.equal_ = &SelfType::equal;
00475    }
00476 
00477    static int compare( const Value &aData, const Value &bData, bool &canCompare )
00478    {
00479       const DataType &a = StoragePolicy::data(aData);
00480       const DataType &b = StoragePolicy::data(bData);
00481       if ( a < b )
00482          return -1;
00483       if ( a == b )
00484          return 0;
00485       return 1;
00486    }
00487 
00488    static bool less( const Value &aData, const Value &bData, bool &canCompare )
00489    {
00490       const DataType &a = StoragePolicy::data(aData);
00491       const DataType &b = StoragePolicy::data(bData);
00492       return a < b;
00493    }
00494 
00495    static bool equal( const Value &aData, const Value &bData, bool &canCompare )
00496    {
00497       const DataType &a = StoragePolicy::data(aData);
00498       const DataType &b = StoragePolicy::data(bData);
00499       return a == b;
00500    }
00501 };
00502 
00503 
00506 template<typename DataType>
00507 class LessCompare
00508 {
00509 public:
00510    typedef Compare<DataType> SelfType;
00511    typedef CPPTL_TYPENAME StoragePolicySelector<DataType>::type StoragePolicy;
00512 
00513    static void registerFunctions( ValueType &type )
00514    {
00515       type.compare_ = &SelfType::compare;
00516       type.less_ = &SelfType::less;
00517       type.equal_ = &SelfType::equal;
00518    }
00519 
00520    static int compare( const Value &aData, const Value &bData, bool &canCompare )
00521    {
00522       const DataType &a = StoragePolicy::data(aData);
00523       const DataType &b = StoragePolicy::data(bData);
00524       if ( a < b )
00525          return -1;
00526       if ( b < a )
00527          return 1;
00528       return 0;
00529    }
00530 
00531    static bool less( const Value &aData, const Value &bData, bool &canCompare )
00532    {
00533       const DataType &a = StoragePolicy::data(aData);
00534       const DataType &b = StoragePolicy::data(bData);
00535       return a < b;
00536    }
00537 
00538    static bool equal( const Value &aData, const Value &bData, bool &canCompare )
00539    {
00540       const DataType &a = StoragePolicy::data(aData);
00541       const DataType &b = StoragePolicy::data(bData);
00542       return (a < b)  &&  !(b < a);
00543    }
00544 };
00545 
00546 
00547 template<class DataType>
00548 class CommonValueType : public ValueType
00549 {
00550 public:
00551    CommonValueType()
00552    {
00553       clear();
00554       CommonLifeCycle<DataType>::registerFunctions( *this );
00555    }
00556 };
00557 
00558 
00559 template<class DataType>
00560 class ComparableValueType : public ValueType
00561 {
00562 public:
00563    ComparableValueType()
00564    {
00565       clear();
00566       CommonLifeCycle<DataType>::registerFunctions( *this );
00567       Compare<DataType>::registerFunctions( *this );
00568    }
00569 };
00570 
00571 
00572 } // end of namespace ValueTypeHelper
00573 
00574 
00575 
00576 // default implementation of getValueType
00577 # ifdef CPPTL_NO_FUNCTION_TEMPLATE_ORDERING
00578    template<class DataType>
00579    inline const ValueType &getValueTypeSelector( const HasDefaultValueTypeHelper &, 
00580                                                  const Type<DataType> & )
00581    {
00582 # else
00583    template<class DataType>
00584    inline const ValueType &getValueType( const Type<DataType> & )
00585    {
00586 # endif
00587       // Notes: if static within a template function is an issue, then
00588       // it can be moved to a dynamic allocation in a "type" registry. Requires TypeInfo.
00589       static ValueTypeHelper::CommonValueType<DataType> type;
00590       return type;
00591    }
00592 
00593 
00594 struct NoneValueType : public ValueType
00595 {
00596    NoneValueType()
00597    {
00598       clear();
00599       clone_ = &NoneValueType::clone;
00600       compare_ = &NoneValueType::compare;
00601    }
00602 
00603    static void clone( const Value &, Value & )
00604    {
00605    }
00606 
00607    static int compare( const Value &aData, const Value &bData, bool &canCompare )
00608    {
00609       return 0;
00610    }
00611 };
00612 
00613    
00614 inline const ValueType &getValueType( Type<NoneValueTypeTag> )
00615 {
00616    static NoneValueType type; // @todo thread safety issue => move to .cpp with static init
00617    return type;
00618 }
00619 
00620    
00621 inline const ValueType &getValueType( Type<int> )
00622 {
00623    static ValueTypeHelper::ComparableValueType<int> type; // @todo thread safety issue => move to .cpp with static init
00624    return type;
00625 }
00626 
00627 
00628 
00629 
00630 
00631 // //////////////////////////////////////////////////////////////////
00632 // //////////////////////////////////////////////////////////////////
00633 // class Value, inlines
00634 // //////////////////////////////////////////////////////////////////
00635 // //////////////////////////////////////////////////////////////////
00636 
00637 
00638 inline 
00639 Value::Value()
00640 {
00641    type_ = &CPPTL_GET_VALUE_TYPE( NoneValueTypeTag );
00642 }
00643 
00644 
00645 inline
00646 Value::Value( const ValueType &type, const void *data )
00647    : type_( &type )
00648 {
00649    type.initialize_( data, *this );
00650 }
00651 
00652 
00653 inline bool 
00654 Value::isNone() const
00655 {
00656    return type_ == &CPPTL_GET_VALUE_TYPE( NoneValueTypeTag );
00657 }
00658 
00659 
00660 inline bool 
00661 Value::operator <( const Value &other ) const
00662 {
00663    bool canCompare;
00664    bool result = compare( other, canCompare ) < 0;
00665    if ( !canCompare )
00666       throw ValueException( ValueException::notSameType, "Value::operator <", type_, other.type_ );
00667    return result;
00668 }
00669 
00670 
00671 inline bool 
00672 Value::operator <=( const Value &other ) const
00673 {
00674    bool canCompare;
00675    bool result = compare( other, canCompare ) <= 0;
00676    if ( !canCompare )
00677       throw ValueException( ValueException::notSameType, "Value::operator <=", type_, other.type_ );
00678    return result;
00679 }
00680 
00681 
00682 inline bool 
00683 Value::operator ==( const Value &other ) const
00684 {
00685    bool canCompare;
00686    bool result = compare( other, canCompare ) == 0;
00687    if ( !canCompare )
00688       throw ValueException( ValueException::notSameType, "Value::operator ==", type_, other.type_ );
00689    return result;
00690 }
00691 
00692 
00693 inline bool 
00694 Value::operator !=( const Value &other ) const
00695 {
00696    bool canCompare;
00697    bool result = compare( other, canCompare ) != 0;
00698    if ( !canCompare )
00699       throw ValueException( ValueException::notSameType, "Value::operator !=", type_, other.type_ );
00700    return result;
00701 }
00702 
00703 
00704 inline bool 
00705 Value::operator >=( const Value &other ) const
00706 {
00707    bool canCompare;
00708    bool result = compare( other, canCompare ) >= 0;
00709    if ( !canCompare )
00710       throw ValueException( ValueException::notSameType, "Value::operator >=", type_, other.type_ );
00711    return result;
00712 }
00713 
00714 
00715 inline bool 
00716 Value::operator >( const Value &other ) const
00717 {
00718    bool canCompare;
00719    bool result = compare( other, canCompare ) > 0;
00720    if ( !canCompare )
00721       throw ValueException( ValueException::notSameType, "Value::operator >", type_, other.type_ );
00722    return result;
00723 }
00724 
00725 
00726 
00727 
00728 
00729 } // end namespace CppTL
00730 
00731 #endif // CPPTL_VALUE_H_INCLUDED

SourceForge Logo hosts this site. Send comments to:
CppUnit Developers