00001
00002
00003
00004
00005
00006
00007
00008
00009
00017
00018
00019 #ifndef EVAL_VAL_H
00020 #define EVAL_VAL_H
00021
00022
00023 #include <string>
00024 #include <stdexcept>
00025 #include <ostream>
00026 #include <sstream>
00027 #include <typeinfo>
00028 #include <limits>
00029 #include <boost/static_assert.hpp>
00030 #include <boost/shared_ptr.hpp>
00031 #include <boost/shared_array.hpp>
00032 #include <boost/type_traits/is_convertible.hpp>
00033 #include <boost/type_traits/is_same.hpp>
00034 #include <boost/type_traits/is_fundamental.hpp>
00035 #include <boost/type_traits/is_integral.hpp>
00036 #include <boost/type_traits/is_const.hpp>
00037 #include <boost/type_traits/is_reference.hpp>
00038 #include <boost/cstdint.hpp>
00039
00040
00041 namespace eval
00042 {
00043 typedef boost::intmax_t large_int;
00044
00045 typedef long double large_double;
00046
00047
00055 class bad_val_cast : public std::bad_cast
00056 {
00057 public:
00058 bad_val_cast(const std::string& type_from, const std::string& type_to)
00059 : std::bad_cast(),
00060 _err("eval::bad_val_cast: from '" + type_from + "' to '" + type_to + "'")
00061 {
00062 }
00063
00064 virtual const char *what() const throw()
00065 {
00066 return _err.c_str();
00067 }
00068
00069 virtual ~bad_val_cast() throw ()
00070 {
00071 }
00072 private:
00073 std::string _err;
00074 };
00075
00076
00080 class non_numeric_exception : public std::bad_cast
00081 {
00082 public:
00083 explicit non_numeric_exception(const std::string& type)
00084 : std::bad_cast(),
00085 _err("eval::non_numeric_exception: cannot convert non-numeric type '" + type + "'")
00086 {
00087 }
00088
00089 virtual const char *what() const throw()
00090 {
00091 return _err.c_str();
00092 }
00093
00094 virtual ~non_numeric_exception() throw()
00095 {
00096 }
00097 private:
00098 std::string _err;
00099 };
00100
00101
00104 class overflow_exception : public std::bad_cast
00105 {
00106 public:
00107 explicit overflow_exception()
00108 : std::bad_cast()
00109 {
00110 }
00111
00112 virtual const char *what() const throw()
00113 {
00114 return "eval::overflow_exception: numeric conversion failed due under/overflow";
00115 }
00116 };
00117
00118
00121 class non_ostreamable_exception : public std::bad_cast
00122 {
00123 public:
00124 explicit non_ostreamable_exception(const std::string& type)
00125 : std::bad_cast(),
00126 _err("eval::non_ostreamable_exception: cannot stringify non-ostreamble type '"
00127 + type + "'")
00128 {
00129 }
00130
00131 virtual const char *what() const throw()
00132 {
00133 return _err.c_str();
00134 }
00135
00136 virtual ~non_ostreamable_exception() throw()
00137 {
00138 }
00139 private:
00140 std::string _err;
00141 };
00142
00145 class empty_exception : public std::logic_error
00146 {
00147 public:
00148 explicit empty_exception(const std::string& err)
00149 : std::logic_error("eval::empty_exception: " + err)
00150 {
00151 }
00152 };
00153
00154
00155
00156
00157 namespace detail
00158 {
00159
00166 template<typename FromT, typename ToT>
00167 inline ToT convert_numeric_helper(const FromT *x, const boost::true_type&)
00168 {
00169
00170
00171
00172
00173
00174
00175 if(std::numeric_limits<ToT>::digits > std::numeric_limits<long double>::digits)
00176 {
00177 if( *x <= static_cast<long double>(std::numeric_limits<ToT>::min())
00178 || *x >= static_cast<long double>(std::numeric_limits<ToT>::max()))
00179 {
00180 throw overflow_exception();
00181 }
00182 }
00183 else
00184 {
00185 if( *x < static_cast<long double>(std::numeric_limits<ToT>::min())
00186 || *x > static_cast<long double>(std::numeric_limits<ToT>::max()))
00187 {
00188 throw overflow_exception();
00189 }
00190 }
00191 return static_cast<ToT>(*x);
00192 }
00193
00200 template<typename FromT, typename ToT>
00201 inline ToT convert_numeric_helper(const FromT *x, const boost::false_type&)
00202 {
00203 if( *x < -std::numeric_limits<ToT>::max()
00204 || *x > std::numeric_limits<ToT>::max())
00205 {
00206 throw overflow_exception();
00207 }
00208 return static_cast<ToT>(*x);
00209 }
00210
00211
00219 template<typename FromT, typename ToT>
00220 inline ToT convert_numeric(const FromT *x, const boost::true_type&)
00221 {
00222 return convert_numeric_helper<FromT, ToT>(x, boost::is_integral<ToT>());
00223 }
00224
00228 template<typename FromT, typename ToT>
00229 inline ToT convert_numeric(const FromT *, const boost::false_type&)
00230 {
00231 throw non_numeric_exception(typeid(FromT).name());
00232 }
00233
00234
00235 namespace overload_backups
00236 {
00238 template<typename CharT, typename TraitsT, typename ValT>
00239 inline std::basic_ostream<CharT, TraitsT>&
00240 operator<<(std::basic_ostream<CharT, TraitsT>&, const ValT&)
00241 {
00242 throw non_ostreamable_exception(typeid(ValT).name());
00243 }
00244 }
00245
00249 template<typename FromT>
00250 inline std::string stringify(const FromT& val)
00251 {
00252 using overload_backups::operator<<;
00253 std::ostringstream temp;
00254 if(!(temp << val))
00255 {
00256 throw non_ostreamable_exception(typeid(FromT).name());
00257 }
00258 return temp.str();
00259 }
00260
00264 template<typename FromT>
00265 inline std::string convert_lexical_non_c_str(const FromT *val)
00266 {
00267 return stringify(*val);
00268 }
00269
00274 template<typename FromT>
00275 inline std::string convert_lexical(const FromT *val)
00276 {
00277 return stringify(*val);
00278 }
00279
00281 template<>
00282 inline std::string convert_lexical<char>(const char *val)
00283 {
00284 return std::string(val);
00285 }
00286
00287
00292 class storage_base_common
00293 {
00294 public:
00295 virtual const void *get_value_const() const = 0;
00296 virtual const storage_base_common *clone() const = 0;
00297 virtual const std::type_info& type() const = 0;
00298 virtual bool will_copy_deeply() const = 0;
00299 virtual bool is_const() const = 0;
00300 virtual large_int coerce_int() const = 0;
00301 virtual large_double coerce_double() const = 0;
00302 virtual std::string coerce_string() const = 0;
00303
00304 virtual ~storage_base_common()
00305 {
00306 }
00307 };
00308
00309 class storage_base_nonconst
00310 {
00311 public:
00312 virtual void *get_value() const = 0;
00313
00314 virtual ~storage_base_nonconst()
00315 {
00316 }
00317 };
00318
00319
00320 template<typename ValT>
00321 class storage_unmanaged_ptr: public storage_base_common
00322 {
00323 public:
00325 explicit storage_unmanaged_ptr(ValT *value)
00326 : storage_base_common(),
00327 _value(value)
00328 {
00329 }
00330
00331 virtual const void *get_value_const() const
00332 {
00333 return _value;
00334 }
00335
00336 virtual const storage_base_common *clone() const
00337 {
00338 return new storage_unmanaged_ptr<ValT>(_value);
00339 }
00340
00341 virtual const std::type_info& type() const
00342 {
00343 return typeid(ValT);
00344 }
00345
00346 virtual bool will_copy_deeply() const
00347 {
00348 return false;
00349 }
00350
00351 virtual bool is_const() const
00352 {
00353 return true;
00354 }
00355
00356 virtual large_int coerce_int() const
00357 {
00358 return convert_numeric<ValT, large_int>(_value,
00359 boost::is_convertible<ValT, large_int>());
00360 }
00361
00362 virtual large_double coerce_double() const
00363 {
00364 return convert_numeric<ValT, large_double>(_value,
00365 boost::is_convertible<ValT, large_double>());
00366 }
00367
00368 virtual std::string coerce_string() const
00369 {
00370 return convert_lexical(_value);
00371 }
00372
00373 protected:
00374 ValT * const _value;
00375 };
00376
00377
00378 template<typename ValT>
00379 class storage_unmanaged_ptr_nonconst : public storage_unmanaged_ptr<ValT>,
00380 public storage_base_nonconst
00381 {
00382 typedef storage_unmanaged_ptr<ValT> Base;
00383
00384 public:
00386 explicit storage_unmanaged_ptr_nonconst(ValT *value)
00387 : Base(value),
00388 storage_base_nonconst()
00389 {
00390 }
00391
00392 virtual void *get_value() const
00393 {
00394 return Base::_value;
00395 }
00396
00397 virtual const storage_base_common *clone() const
00398 {
00399 return new storage_unmanaged_ptr_nonconst<ValT>(Base::_value);
00400 }
00401
00402 virtual bool is_const() const
00403 {
00404 return false;
00405 }
00406 };
00407
00408
00410 template<typename ValT>
00411 class storage_transfer_ownership : public storage_base_common
00412 {
00413 public:
00414 explicit storage_transfer_ownership(const boost::shared_ptr<ValT>& value)
00415 : storage_base_common(),
00416 _value(value)
00417 {
00418 }
00419
00421 explicit storage_transfer_ownership(ValT *value)
00422 : storage_base_common(),
00423 _value(value)
00424 {
00425 }
00426
00427 virtual const void *get_value_const() const
00428 {
00429 return _value.get();
00430 }
00431
00432 virtual const storage_base_common *clone() const
00433 {
00434 return new storage_transfer_ownership<ValT>(_value);
00435 }
00436
00437 virtual const std::type_info& type() const
00438 {
00439 return typeid(ValT);
00440 }
00441
00442 virtual bool will_copy_deeply() const
00443 {
00444 return false;
00445 }
00446
00447 virtual bool is_const() const
00448 {
00449 return true;
00450 }
00451
00452 virtual large_int coerce_int() const
00453 {
00454 return convert_numeric<ValT, large_int>(_value.get(),
00455 boost::is_convertible<ValT, large_int>());
00456 }
00457
00458 virtual large_double coerce_double() const
00459 {
00460 return convert_numeric<ValT, large_double>(_value.get(),
00461 boost::is_convertible<ValT, large_double>());
00462 }
00463
00464 virtual std::string coerce_string() const
00465 {
00466 return convert_lexical(_value.get());
00467 }
00468 protected:
00469 const boost::shared_ptr<ValT> _value;
00470 };
00471
00472
00474 template<typename ValT>
00475 class storage_transfer_ownership_nonconst : public storage_transfer_ownership<ValT>,
00476 public storage_base_nonconst
00477 {
00478 typedef storage_transfer_ownership<ValT> Base;
00479
00480 public:
00481 explicit storage_transfer_ownership_nonconst(const boost::shared_ptr<ValT>& value)
00482 : Base(value),
00483 storage_base_nonconst()
00484 {
00485 }
00486
00488 explicit storage_transfer_ownership_nonconst(ValT *value)
00489 : Base(value),
00490 storage_base_nonconst()
00491 {
00492 }
00493
00494 virtual void *get_value() const
00495 {
00496 return Base::_value.get();
00497 }
00498
00499 virtual const storage_base_common *clone() const
00500 {
00501 return new storage_transfer_ownership_nonconst<ValT>(Base::_value);
00502 }
00503
00504 virtual bool is_const() const
00505 {
00506 return false;
00507 }
00508 };
00509
00511 template<typename ValT>
00512 class storage_transfer_ownership_array : public storage_base_common
00513 {
00514 public:
00515 explicit storage_transfer_ownership_array(const boost::shared_array<ValT>& value)
00516 : storage_base_common(),
00517 _value(value)
00518 {
00519 }
00520
00522 explicit storage_transfer_ownership_array(ValT *value)
00523 : storage_base_common(),
00524 _value(value)
00525 {
00526 }
00527
00528 virtual const void *get_value_const() const
00529 {
00530 return _value.get();
00531 }
00532
00533 virtual const storage_base_common *clone() const
00534 {
00535 return new storage_transfer_ownership_array<ValT>(_value);
00536 }
00537
00538 virtual const std::type_info& type() const
00539 {
00540 return typeid(ValT);
00541 }
00542
00543 virtual bool will_copy_deeply() const
00544 {
00545 return false;
00546 }
00547
00548 virtual bool is_const() const
00549 {
00550 return true;
00551 }
00552
00553 virtual large_int coerce_int() const
00554 {
00555 return convert_numeric<ValT, large_int>(_value.get(),
00556 boost::is_convertible<ValT, large_int>());
00557 }
00558
00559 virtual large_double coerce_double() const
00560 {
00561 return convert_numeric<ValT, large_double>(_value.get(),
00562 boost::is_convertible<ValT, large_double>());
00563 }
00564
00565 virtual std::string coerce_string() const
00566 {
00567 return convert_lexical(_value.get());
00568 }
00569 protected:
00570 const boost::shared_array<ValT> _value;
00571 };
00572
00573
00575 template<typename ValT>
00576 class storage_transfer_ownership_array_nonconst :
00577 public storage_transfer_ownership_array<ValT>,
00578 public storage_base_nonconst
00579 {
00580 typedef storage_transfer_ownership_array<ValT> Base;
00581
00582 public:
00583 explicit storage_transfer_ownership_array_nonconst(
00584 const boost::shared_array<ValT>& value)
00585 : Base(value),
00586 storage_base_nonconst()
00587 {
00588 }
00589
00591 explicit storage_transfer_ownership_array_nonconst(ValT *value)
00592 : Base(value),
00593 storage_base_nonconst()
00594 {
00595 }
00596
00597 virtual void *get_value() const
00598 {
00599 return Base::_value.get();
00600 }
00601
00602 virtual const storage_base_common *clone() const
00603 {
00604 return new storage_transfer_ownership_array_nonconst<ValT>(Base::_value);
00605 }
00606
00607 virtual bool is_const() const
00608 {
00609 return false;
00610 }
00611 };
00612
00613
00614 template<typename ValT>
00615 class storage_copy_value : public storage_base_common
00616 {
00617 public:
00618 explicit storage_copy_value(ValT& value)
00619 : storage_base_common(),
00620 _value(new ValT(value))
00621 {
00622 }
00623
00624 virtual const void *get_value_const() const
00625 {
00626 return _value;
00627 }
00628
00629 virtual const storage_base_common *clone() const
00630 {
00631 return new storage_copy_value<ValT>(*_value);
00632 }
00633
00634 virtual const std::type_info& type() const
00635 {
00636 return typeid(ValT);
00637 }
00638
00639 virtual bool will_copy_deeply() const
00640 {
00641 return true;
00642 }
00643
00644 virtual bool is_const() const
00645 {
00646 return true;
00647 }
00648
00649 virtual large_int coerce_int() const
00650 {
00651 return convert_numeric<ValT, large_int>(_value,
00652 boost::is_convertible<ValT, large_int>());
00653 }
00654
00655 virtual large_double coerce_double() const
00656 {
00657 return convert_numeric<ValT, large_double>(_value,
00658 boost::is_convertible<ValT, large_double>());
00659 }
00660
00661 virtual std::string coerce_string() const
00662 {
00663 return convert_lexical_non_c_str(_value);
00664 }
00665
00666 virtual ~storage_copy_value()
00667 {
00668 delete _value;
00669 }
00670
00671 protected:
00672 ValT * const _value;
00673 };
00674
00675 template<typename ValT>
00676 class storage_copy_value_nonconst : public storage_copy_value<ValT>,
00677 public storage_base_nonconst
00678 {
00679 typedef storage_copy_value<ValT> Base;
00680
00681 public:
00682 explicit storage_copy_value_nonconst(ValT& value)
00683 : Base(value),
00684 storage_base_nonconst()
00685 {
00686 }
00687
00688 virtual void *get_value() const
00689 {
00690 return Base::_value;
00691 }
00692
00693 virtual const storage_base_common *clone() const
00694 {
00695 return new storage_copy_value_nonconst<ValT>(*Base::_value);
00696 }
00697
00698 virtual bool is_const() const
00699 {
00700 return false;
00701 }
00702 };
00703
00704 }
00705
00706
00707
00708
00709 enum ownership_type_nocopy
00710 {
00711 UNMANAGED_PTR = 1,
00712 TRANSFER_OWNERSHIP,
00713 TRANSFER_OWNERSHIP_ARRAY
00714 };
00715
00716 enum ownership_type_shared_ptr
00717 {
00718 SHARED_PTR = 100
00719 };
00720
00721 enum ownership_type_shared_array
00722 {
00723 SHARED_ARRAY = 200
00724 };
00725
00726 enum ownership_type_copy
00727 {
00728 COPY_VALUE = 300
00729 };
00730
00731
00732
00733 namespace detail
00734 {
00735
00737 class val
00738 {
00739 public:
00741 val()
00742 : _store(0)
00743 {
00744 }
00745
00746 template<typename ValT>
00747 val(ValT *value, ownership_type_nocopy ownership_type)
00748 {
00749 if(!value)
00750 {
00751 _store = 0;
00752 }
00753 else
00754 {
00755 switch(ownership_type)
00756 {
00757 case UNMANAGED_PTR:
00758 _store = new storage_unmanaged_ptr_nonconst<ValT>(value);
00759 break;
00760 case TRANSFER_OWNERSHIP:
00761 _store = new storage_transfer_ownership_nonconst<ValT>(value);
00762 break;
00763 case TRANSFER_OWNERSHIP_ARRAY:
00764 _store = new storage_transfer_ownership_array_nonconst<ValT>(value);
00765 break;
00766 }
00767 }
00768 }
00769
00770 template<typename ValT>
00771 val(const ValT *value, ownership_type_nocopy ownership_type)
00772 {
00773 if(!value)
00774 {
00775 _store = 0;
00776 }
00777 else
00778 {
00779 switch(ownership_type)
00780 {
00781 case UNMANAGED_PTR:
00782 _store = new storage_unmanaged_ptr<const ValT>(value);
00783 break;
00784 case TRANSFER_OWNERSHIP:
00785 _store = new storage_transfer_ownership<const ValT>(value);
00786 break;
00787 case TRANSFER_OWNERSHIP_ARRAY:
00788 _store = new storage_transfer_ownership_array<const ValT>(value);
00789 break;
00790 }
00791 }
00792 }
00793
00794
00795 template<typename ValT>
00796 val(const boost::shared_ptr<ValT>& value, ownership_type_shared_ptr)
00797 : _store(value ? new storage_transfer_ownership_nonconst<ValT>(value) : 0)
00798 {
00799 }
00800
00801 template<typename ValT>
00802 val(const boost::shared_ptr<const ValT>& value, ownership_type_shared_ptr)
00803 : _store(value ? new storage_transfer_ownership<const ValT>(value) : 0)
00804 {
00805 }
00806
00807 template<typename ValT>
00808 val(const boost::shared_array<ValT>& value, ownership_type_shared_array)
00809 : _store(value ? new storage_transfer_ownership_array_nonconst<ValT>(value) : 0)
00810 {
00811 }
00812
00813 template<typename ValT>
00814 val(const boost::shared_array<const ValT>& value, ownership_type_shared_array)
00815 : _store(value ? new storage_transfer_ownership_array<const ValT>(value) : 0)
00816 {
00817 }
00818
00819 template<typename ValT>
00820 val(ValT& value, ownership_type_copy)
00821 : _store(new storage_copy_value_nonconst<ValT>(value))
00822 {
00823 }
00824
00825 template<typename ValT>
00826 val(const ValT& value, ownership_type_copy)
00827 : _store(new storage_copy_value<const ValT>(value))
00828 {
00829 }
00830
00834 val(const val& other)
00835 : _store(other._store ? other._store->clone() : 0)
00836 {
00837 }
00838
00839 void swap(val& other)
00840 {
00841 std::swap(_store, other._store);
00842 }
00843
00847 val& operator=(val rhs)
00848 {
00849 rhs.swap(*this);
00850 return *this;
00851 }
00852
00855 bool empty() const
00856 {
00857 return !_store;
00858 }
00859
00860 bool will_copy_deeply() const
00861 {
00862 if(empty())
00863 {
00864 return true;
00865 }
00866 return _store->will_copy_deeply();
00867 }
00868
00869 bool is_const() const
00870 {
00871 if(empty())
00872 {
00873 throw empty_exception("is_const of empty eval::val");
00874 }
00875 return _store->is_const();
00876 }
00877
00881 large_int coerce_int() const
00882 {
00883 if(empty())
00884 {
00885 throw empty_exception("coerce_int of empty eval::val");
00886 }
00887 return _store->coerce_int();
00888 }
00889
00893 double coerce_double() const
00894 {
00895 if(empty())
00896 {
00897 throw empty_exception("coerce_double of empty eval::val");
00898 }
00899 return _store->coerce_double();
00900 }
00901
00904 std::string coerce_string() const
00905 {
00906 if(empty())
00907 {
00908 throw empty_exception("coerce_string of empty eval::val");
00909 }
00910 return _store->coerce_string();
00911 }
00912
00913 const std::type_info& type() const
00914 {
00915 if(empty())
00916 {
00917 return typeid(void);
00918 }
00919 return _store->type();
00920 }
00921
00936 bool points_to_same_object_as(const val &rhs) const
00937 {
00938 if(!_store || !rhs._store)
00939 {
00940 return !_store && !rhs._store;
00941 }
00942 else
00943 {
00944 return _store->get_value_const() == rhs._store->get_value_const();
00945 }
00946 }
00947
00948 ~val()
00949 {
00950 delete _store;
00951 }
00952
00953 private:
00954 const storage_base_common *_store;
00955
00956 template<typename ValT>
00957 friend ValT *val_cast_ptr_helper(const val& v, const boost::true_type&);
00958
00959 template<typename ValT>
00960 friend ValT *val_cast_ptr_helper(const val& v, const boost::false_type&);
00961 };
00963
00964 template<typename DesiredT>
00965 inline void ensure_val_types_match(const val& v)
00966 {
00967 if(v.empty() || (v.type() != typeid(DesiredT) && typeid(DesiredT) != typeid(void)))
00968 {
00969 throw bad_val_cast(v.type().name(), typeid(DesiredT).name());
00970 }
00971 }
00972
00973
00975 template<typename DesiredT>
00976 inline DesiredT *val_cast_ptr_helper(const val& v, const boost::true_type&)
00977 {
00978 return static_cast<DesiredT *>(v._store->get_value_const());
00979 }
00980
00982 template<typename DesiredT>
00983 inline DesiredT *val_cast_ptr_helper(const val& v, const boost::false_type&)
00984 {
00985 const storage_base_nonconst *p;
00986 p = dynamic_cast<const storage_base_nonconst *>(v._store);
00987 if(!p)
00988 {
00989 throw bad_val_cast(std::string("(const) ") + v.type().name(),
00990 typeid(DesiredT).name());
00991 }
00992 return static_cast<DesiredT *>(p->get_value());
00993 }
00994
00995
00996
00997 }
00998
01003 typedef detail::val val;
01004
01010 template<typename DesiredT>
01011 inline const DesiredT *val_cast_ptr(const val &v)
01012 {
01013 BOOST_STATIC_ASSERT(!boost::is_reference<DesiredT>::value);
01014 detail::ensure_val_types_match<DesiredT>(v);
01015 return detail::val_cast_ptr_helper<const DesiredT>(v, boost::true_type());
01016 }
01017
01023 template<typename DesiredT>
01024 inline DesiredT *val_cast_ptr(val &v)
01025 {
01026 BOOST_STATIC_ASSERT(!boost::is_reference<DesiredT>::value);
01027 detail::ensure_val_types_match<DesiredT>(v);
01028 return detail::val_cast_ptr_helper<DesiredT>(v, boost::is_const<DesiredT>());
01029 }
01030
01031
01032 }
01033
01034 #endif