behavior.hh

00001 // Copyright (C) 2001, 2002, 2003, 2004  EPITA Research and Development Laboratory
00002 //
00003 // This file is part of the Olena Library.  This library is free
00004 // software; you can redistribute it and/or modify it under the terms
00005 // of the GNU General Public License version 2 as published by the
00006 // Free Software Foundation.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this library; see the file COPYING.  If not, write to
00015 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
00016 // MA 02111-1307, USA.
00017 //
00018 // As a special exception, you may use this file as part of a free
00019 // software library without restriction.  Specifically, if other files
00020 // instantiate templates or use macros or inline functions from this
00021 // file, or you compile this file and link it with other files to
00022 // produce an executable, this file does not by itself cause the
00023 // resulting executable to be covered by the GNU General Public
00024 // License.  This exception does not however invalidate any other
00025 // reasons why the executable file might be covered by the GNU General
00026 // Public License.
00027 
00028 #ifndef NTG_REAL_BEHAVIOUR_HH
00029 # define NTG_REAL_BEHAVIOUR_HH
00030 
00031 /*
00032   Behaviors for real datatypes int_u, int_s, etc ...
00033 
00034   <WARNING> Don't forget that behaviors are checked on assignements
00035   and contruction of types, and use comparison, so create only vars
00036   with unsafe behaviors in comparison operators implementation.
00037 */
00038 
00039 # include <mlc/bool.hh>
00040 # include <mlc/contract.hh>
00041 # include <mlc/is_a.hh>
00042 
00043 # include <ntg/core/contract.hh>
00044 # include <ntg/core/macros.hh>
00045 # include <ntg/core/type_traits.hh>
00046 # include <ntg/core/value.hh>
00047 # include <ntg/core/internal/macros.hh>
00048 # include <ntg/real/optraits_real.hh>
00049 # include <ntg/real/real_value.hh>
00050 # include <ntg/utils/debug.hh>
00051 # include <ntg/utils/cast.hh>
00052 
00053 # include <string>
00054 # include <sstream>
00055 
00056 // FIXME: there is maybe simpler a way to write that, but we want it
00057 // to be compatible with icc, so the behaviors must stay classes, not
00058 // meta classes.
00059 // FIXME: are these considerations still accurate?
00060 
00061 namespace ntg
00062 {
00063 
00064   /*
00065     Behaviors work by callbacks. When an operator has some side effect
00066     to apply, it calls the corresponding behavior functions to wrap
00067     the new value to be assigned.
00068 
00069     Example in the constructor of int_u taking an unsigned in parameter:
00070     real_data_value = behavior_type<get<int_u> >::check(value_to_assign);
00071   */
00072 
00073   /*-------.
00074   | unsafe |
00075   `-------*/
00077 
00080   struct unsafe
00081   {
00082     template <class T>
00083     struct get
00084     {
00085       typedef ntgi_storage_type(T) storage_type;
00086 
00087       template <class T1, class T2>
00088       static T
00089       check_plus (T1 lhs, T2 rhs)
00090       { return lhs + rhs; }
00091 
00092       template <class T1, class T2>
00093       static T
00094       check_minus (T1 lhs, T2 rhs)
00095       { return lhs - rhs; }
00096 
00097       template <class T1, class T2>
00098       static T
00099       check_times (T1 lhs, T2 rhs)
00100       { return lhs * rhs; }
00101 
00102       template <class T1, class T2>
00103       static T
00104       check_div (T1 lhs, T2 rhs)
00105       { return lhs / rhs; }
00106 
00107       template <class P>
00108       static storage_type
00109       check (const P& p)
00110       { return storage_type(p); }
00111     };
00112 
00113     static std::string
00114     name()
00115     { return "unsafe"; }
00116   };
00117 
00118   /*------.
00119   | force |
00120   `------*/
00122 
00137   struct force
00138   {
00139     template <class T>
00140     struct get
00141     {
00142       typedef ntgi_storage_type(T) storage_type;
00143 
00144       template <class T1, class T2>
00145       static T
00146       check_plus (T1 lhs, T2 rhs)
00147       { return cast::force<T>(lhs + rhs); }
00148 
00149       template <class T1, class T2>
00150       static T
00151       check_minus (T1 lhs, T2 rhs)
00152       { return cast::force<T>(lhs - rhs); }
00153 
00154       template <class T1, class T2>
00155       static T
00156       check_times (T1 lhs, T2 rhs)
00157       { return cast::force<T>(lhs * rhs); }
00158 
00159       template <class T1, class T2>
00160       static T
00161       check_div (T1 lhs, T2 rhs)
00162       { return cast::force<T>(lhs / rhs); }
00163 
00164       template <class P>
00165       static storage_type
00166       check (const P& p)
00167       { return cast::force<T>(p); }
00168     };
00169 
00170     static std::string
00171     name()
00172     { return "force"; }
00173   };
00174 
00175   /*-------.
00176   | strict |
00177   `-------*/
00179   struct strict
00180   {
00181     template <class T>
00182     struct get
00183     {
00184       typedef ntgi_storage_type(T) storage_type;
00185 
00186       // FIXME: These checks are not always useful. We can determine
00187       // in advance the types which can raise overflow
00188       // (eg. int_u<32>), the tests should be performed only in those
00189       // cases!
00190 
00191       // FIXME: check that conditions lead to empty code when
00192       // -DNDEBUG is defined does not have any runtime cost.
00193 
00194       template <class T1, class T2>
00195       static T
00196       check_plus (T1 lhs, T2 rhs)
00197       {
00198         T ret = lhs + rhs;
00199         if (rhs > 0)
00200           ntg_assert(ntg_cast(ret) > lhs);
00201         else
00202           ntg_assert(ntg_cast(ret) <= lhs);
00203         return ret;
00204       }
00205 
00206       template <class T1, class T2>
00207       static T
00208       check_minus (T1 lhs, T2 rhs)
00209       {
00210         T ret = lhs - rhs;
00211         if (rhs > 0)
00212           ntg_assert(ntg_cast(ret) < lhs);
00213         else
00214           ntg_assert(ntg_cast(ret) >= lhs);
00215         return ret;
00216       }
00217 
00218       // FIXME: this check is very slow! Find another solution.
00219       template <class T1, class T2>
00220       static T
00221       check_times (T1 lhs, T2 rhs)
00222       {
00223         T ret = lhs * rhs;
00224         if (rhs != 0)
00225           ntg_assert((ret / rhs) == lhs);
00226         return ret;
00227       }
00228 
00229       template <class T1, class T2>
00230       static T
00231       check_div (T1 lhs, T2 rhs)
00232       { return lhs / rhs; }
00233 
00234       template <class P>
00235       static storage_type
00236       check (const P& p)
00237       {
00238         ntg_assert(ntg_cast(p) <= ntg_max_val(T));
00239         ntg_assert(ntg_cast(p) >= ntg_min_val(T));
00240 
00241         return static_cast<storage_type>(p);
00242       }
00243     };
00244 
00245     static std::string
00246     name()
00247     { return "strict"; }
00248   };
00249 
00250   /*---------.
00251   | saturate |
00252   `---------*/
00254   struct saturate
00255   {
00256     template <class T>
00257     struct get
00258     {
00259       typedef ntgi_storage_type(T) storage_type;
00260 
00261       template <class T1, class T2>
00262       static T
00263       check_plus (T1 lhs, T2 rhs)
00264       {
00265         T ret = lhs + rhs;
00266         if (rhs > 0)
00267           {
00268             if (ntg_cast(ret) <= lhs)
00269               ret = ntg_max_val(T);
00270           }
00271         else if (ntg_cast(ret) > lhs)
00272           ret = ntg_min_val(T);
00273         return ret;
00274       }
00275 
00276       template <class T1, class T2>
00277       static T
00278       check_minus (T1 lhs, T2 rhs)
00279       {
00280         T ret = lhs - rhs;
00281         if (rhs > 0)
00282           {
00283             if (ntg_cast(ret) > lhs)
00284               ret = ntg_min_val(T);
00285           }
00286         else if (rhs != 0 && ntg_cast(ret) <= lhs)
00287           ret = ntg_max_val(T);
00288         return ret;
00289       }
00290 
00291       // FIXME: this check is very slow ! find another solution ...
00292       template <class T1, class T2>
00293       static T
00294       check_times (T1 lhs, T2 rhs)
00295       {
00296         T ret = lhs * rhs;
00297         if ((ret / rhs) != lhs)
00298           {
00299             // if lhs and rhs signs are equal, we wanted to grow
00300             if ((lhs > 0 && rhs > 0) || (-lhs > 0 && -rhs > 0))
00301               ret = ntg_max_val(T);
00302             else
00303               ret = ntg_min_val(T);
00304           }
00305         return ret;
00306       }
00307 
00308       template <class T1, class T2>
00309       static T
00310       check_div (T1 lhs, T2 rhs)
00311       { return lhs / rhs; }
00312 
00313       template <class P>
00314       static storage_type
00315       check (const P& p)
00316       {
00317         if (ntg_cast(p) > ntg_max_val(T))
00318           return ntg_max_val(T);
00319 
00320         if (ntg_cast(p) < ntg_min_val(T))
00321           return ntg_min_val(T);
00322 
00323         return static_cast<storage_type>(p);
00324       }
00325     };
00326 
00327     static std::string
00328     name()
00329     { return "saturate"; }
00330   };
00331 
00332   /*---------------.
00333   | cycle_behavior |
00334   `---------------*/
00336 
00342   struct cycle_behavior
00343   {
00344     template <class T>
00345     struct get
00346     {
00347       typedef ntgi_storage_type(T) storage_type;
00348 
00349       // FIXME: calculate real values!
00350 
00351       template <class T1, class T2>
00352       static T check_plus (T1 lhs, T2 rhs)
00353       { return lhs + rhs; }
00354 
00355       template <class T1, class T2>
00356       static T check_minus (T1 lhs, T2 rhs)
00357       { return lhs - rhs; }
00358 
00359       template <class T1, class T2>
00360       static T check_times (T1 lhs, T2 rhs)
00361       { return lhs * rhs; }
00362 
00363       template <class T1, class T2>
00364       static T check_div (T1 lhs, T2 rhs)
00365       { return lhs / rhs; }
00366 
00367       // float modulus
00368       struct cycle_fmod
00369       {
00370         static double
00371         exec(double lhs, double rhs)
00372         { return fmod(lhs, rhs); }
00373       };
00374 
00375       // integer modulus
00376       struct cycle_mod
00377       {
00378         template <class T1, class T2>
00379         static T1
00380         exec(const T1& lhs, const T2& rhs)
00381         { return lhs % rhs; }
00382       };
00383 
00384       // FIXME: optimize!
00385       template <class P>
00386       static storage_type
00387       check (const P& rhs)
00388       {
00389         typedef typename mlc::if_<ntg_is_a(P, decimal)::ret,
00390           cycle_fmod,
00391           cycle_mod>::ret cycle_op;
00392 
00393         ntg_type(P) tmp = cycle_op::exec(std::abs(ntg_signed_cast(rhs)),
00394                                          ntg_max_val(T) - ntg_min_val(T));
00395 
00396         if (to_ntg(rhs) < 0)
00397           tmp = -tmp;
00398 
00399         if (tmp < ntg_min_val(T))
00400           return ntg_max_val(T) - ntg_min_val(T) + tmp;
00401         else if (tmp >= ntg_max_val(T))
00402           return ntg_min_val(T) - ntg_max_val(T) + tmp;
00403 
00404         return tmp;
00405       }
00406     };
00407 
00408     static std::string
00409     name() { return "cycle_behavior"; }
00410   };
00411 
00412   namespace internal {
00413 
00414     /*-------------------.
00415     | deduce_op_behavior |
00416     `-------------------*/
00417 
00419 
00424     template <class B1, class B2>
00425     struct deduce_op_behavior
00426     { typedef strict ret; };
00427 
00428     template <class B>
00429     struct deduce_op_behavior<B, B>
00430     { typedef B ret; };
00431 
00432     /*----------------.
00433     | ret_behavior_if |
00434     `----------------*/
00435 
00437 
00446     template <bool need_check, class Ret>
00447     struct ret_behavior_if
00448     {
00449       typedef typename typetraits<Ret>::abstract_behavior_type ret;
00450     };
00451 
00452     template <class Ret>
00453     struct ret_behavior_if<false, Ret>
00454     {
00455       typedef ntg::force ret;
00456     };
00457 
00458   } // end of internal.
00459 
00460 } // end of ntg.
00461 
00462 #endif // !NTG_REAL_BEHAVIOUR_HH

Generated on Thu Apr 15 20:13:06 2004 for Olena by doxygen 1.3.6-20040222