functors.h

Go to the documentation of this file.
00001 
00004 
00005 //
00006 // Copyright (c) 2001-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: Fri Sep  7 15:07:16 2001
00011 // commit: $Id: functors.h 10065 2007-04-12 05:54:56Z rjpeters $
00012 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/rutz/functors.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_RUTZ_FUNCTORS_H_UTC20050626084020_DEFINED
00036 #define GROOVX_RUTZ_FUNCTORS_H_UTC20050626084020_DEFINED
00037 
00038 namespace rutz
00039 {
00040   //  #######################################################
00041   //  =======================================================
00042   //
00043   //  func_traits
00044   //
00045   //  =======================================================
00046 
00047   struct null_t;
00048 
00050   template <class R = void,
00051             class A1 = null_t, class A2 = null_t, class A3 = null_t,
00052             class A4 = null_t, class A5 = null_t, class A6 = null_t,
00053             class A7 = null_t, class A8 = null_t>
00054   struct func_args
00055   {
00056     typedef R  retn_t;
00057     typedef A1 arg1_t;
00058     typedef A2 arg2_t;
00059     typedef A3 arg3_t;
00060     typedef A4 arg4_t;
00061     typedef A5 arg5_t;
00062     typedef A6 arg6_t;
00063     typedef A7 arg7_t;
00064     typedef A8 arg8_t;
00065   };
00066 
00068   template <class func>
00069   struct func_traits
00070   {
00071     typedef typename func::retn_t retn_t;
00072   };
00073 
00074   //  =======================================================
00075   //
00076   //  func_traits specializations for free functions
00077   //
00078   //  =======================================================
00079 
00081   template <class R>
00082   struct func_traits<R (*)()>
00083     :
00084     public func_args<R>
00085   {
00086     enum { num_args = 0 };
00087   };
00088 
00090   template <class R, class P1>
00091   struct func_traits<R (*)(P1)>
00092     :
00093     public func_args<R, P1>
00094   {
00095     enum { num_args = 1 };
00096   };
00097 
00099   template <class R, class P1, class P2>
00100   struct func_traits<R (*)(P1, P2)>
00101     :
00102     public func_args<R, P1, P2>
00103   {
00104     enum { num_args = 2 };
00105   };
00106 
00108   template <class R, class P1, class P2, class P3>
00109   struct func_traits<R (*)(P1, P2, P3)>
00110     :
00111     public func_args<R, P1, P2, P3>
00112   {
00113     enum { num_args = 3 };
00114   };
00115 
00117   template <class R, class P1, class P2, class P3, class P4>
00118   struct func_traits<R (*)(P1, P2, P3, P4)>
00119     :
00120     public func_args<R, P1, P2, P3, P4>
00121   {
00122     enum { num_args = 4 };
00123   };
00124 
00126   template <class R, class P1, class P2, class P3, class P4, class P5>
00127   struct func_traits<R (*)(P1, P2, P3, P4, P5)>
00128     :
00129     public func_args<R, P1, P2, P3, P4, P5>
00130   {
00131     enum { num_args = 5 };
00132   };
00133 
00135   template <class R, class P1, class P2, class P3, class P4, class P5,
00136             class P6>
00137   struct func_traits<R (*)(P1, P2, P3, P4, P5, P6)>
00138     :
00139     public func_args<R, P1, P2, P3, P3, P4, P5, P6>
00140   {
00141     enum { num_args = 6 };
00142   };
00143 
00144   //  =======================================================
00145   //
00146   //  func_traits specializations for member functions
00147   //
00148   //  We treat the "this" pointer as an implicit first-argument to the
00149   //  function.
00150   //
00151   //  =======================================================
00152 
00154   template <class R, class C>
00155   struct func_traits<R (C::*)()>
00156     :
00157     public func_args<R, null_t>
00158   {
00159     enum { num_args = 1 };
00160     typedef C class_t;
00161   };
00162 
00164   template <class R, class C>
00165   struct func_traits<R (C::*)() const>
00166     :
00167     public func_args<R, null_t>
00168   {
00169     enum { num_args = 1 };
00170     typedef C class_t;
00171   };
00172 
00174   template <class R, class C, class P1>
00175   struct func_traits<R (C::*)(P1)>
00176     :
00177     public func_args<R, null_t, P1>
00178   {
00179     enum { num_args = 2 };
00180     typedef C class_t;
00181   };
00182 
00184   template <class R, class C, class P1>
00185   struct func_traits<R (C::*)(P1) const>
00186     :
00187     public func_args<R, null_t, P1>
00188   {
00189     enum { num_args = 2 };
00190     typedef C class_t;
00191   };
00192 
00194   template <class R, class C, class P1, class P2>
00195   struct func_traits<R (C::*)(P1, P2)>
00196     :
00197     public func_args<R, null_t, P1, P2>
00198   {
00199     enum { num_args = 3 };
00200     typedef C class_t;
00201   };
00202 
00204   template <class R, class C, class P1, class P2>
00205   struct func_traits<R (C::*)(P1, P2) const>
00206     :
00207     public func_args<R, null_t, P1, P2>
00208   {
00209     enum { num_args = 3 };
00210     typedef C class_t;
00211   };
00212 
00214   template <class R, class C, class P1, class P2, class P3>
00215   struct func_traits<R (C::*)(P1, P2, P3)>
00216     :
00217     public func_args<R, null_t, P1, P2, P3>
00218   {
00219     enum { num_args = 4 };
00220     typedef C class_t;
00221   };
00222 
00224   template <class R, class C, class P1, class P2, class P3>
00225   struct func_traits<R (C::*)(P1, P2, P3) const>
00226     :
00227     public func_args<R, null_t, P1, P2, P3>
00228   {
00229     enum { num_args = 4 };
00230     typedef C class_t;
00231   };
00232 
00234   template <class R, class C, class P1, class P2, class P3, class P4>
00235   struct func_traits<R (C::*)(P1, P2, P3, P4)>
00236     :
00237     public func_args<R, null_t, P1, P2, P3, P4>
00238   {
00239     enum { num_args = 5 };
00240     typedef C class_t;
00241   };
00242 
00244   template <class R, class C, class P1, class P2, class P3, class P4>
00245   struct func_traits<R (C::*)(P1, P2, P3, P4) const>
00246     :
00247     public func_args<R, null_t, P1, P2, P3, P4>
00248   {
00249     enum { num_args = 5 };
00250     typedef C class_t;
00251   };
00252 
00254   template <class R, class C, class P1, class P2, class P3, class P4,
00255             class P5>
00256   struct func_traits<R (C::*)(P1, P2, P3, P4, P5)>
00257     :
00258     public func_args<R, null_t, P1, P2, P3, P4, P5>
00259   {
00260     enum { num_args = 6 };
00261     typedef C class_t;
00262   };
00263 
00265   template <class R, class C, class P1, class P2, class P3, class P4,
00266             class P5>
00267   struct func_traits<R (C::*)(P1, P2, P3, P4, P5) const>
00268     :
00269     public func_args<R, null_t, P1, P2, P3, P4, P5>
00270   {
00271     enum { num_args = 6 };
00272     typedef C class_t;
00273   };
00274 
00276   template <class R, class C, class P1, class P2, class P3, class P4,
00277             class P5, class P6>
00278   struct func_traits<R (C::*)(P1, P2, P3, P4, P5, P6)>
00279     :
00280     public func_args<R, null_t, P1, P2, P3, P4, P5, P6>
00281   {
00282     enum { num_args = 7 };
00283     typedef C class_t;
00284   };
00285 
00287   template <class R, class C, class P1, class P2, class P3, class P4,
00288             class P5, class P6>
00289   struct func_traits<R (C::*)(P1, P2, P3, P4, P5, P6) const>
00290     :
00291     public func_args<R, null_t, P1, P2, P3, P4, P5, P6>
00292   {
00293     enum { num_args = 7 };
00294     typedef C class_t;
00295   };
00296 
00297   //  #######################################################
00298   //  =======================================================
00299 
00300   template <class F>
00301   class mem_functor_base;
00302 
00304   template <class MF>
00305   struct func_traits<mem_functor_base<MF> > : public func_traits<MF>
00306   {};
00307 
00309 
00312   template <class mem_func>
00313   class mem_functor_base
00314     :
00315     public func_traits<mem_functor_base<mem_func> >
00316   {
00317   private:
00318     mem_func m_held_func;
00319 
00320   public:
00321     typedef typename func_traits<mem_func>::retn_t R;
00322     typedef typename func_traits<mem_func>::class_t C;
00323 
00324     mem_functor_base(mem_func f) : m_held_func(f) {}
00325 
00327     template <class ptr>
00328     R operator()(ptr obj)
00329     {
00330       return ((*obj).*m_held_func)();
00331     }
00332 
00334     template <class ptr, class P1>
00335     R operator()(ptr obj, P1 p1)
00336     {
00337       return ((*obj).*m_held_func)(p1);
00338     }
00339 
00341     template <class ptr, class P1, class P2>
00342     R operator()(ptr obj, P1 p1, P2 p2)
00343     {
00344       return ((*obj).*m_held_func)(p1, p2);
00345     }
00346 
00348     template <class ptr, class P1, class P2, class P3>
00349     R operator()(ptr obj, P1 p1, P2 p2, P3 p3)
00350     {
00351       return ((*obj).*m_held_func)(p1, p2, p3);
00352     }
00353 
00355     template <class ptr, class P1, class P2, class P3, class P4>
00356     R operator()(ptr obj, P1 p1, P2 p2, P3 p3, P4 p4)
00357     {
00358       return ((*obj).*m_held_func)(p1, p2, p3, p4);
00359     }
00360 
00362     template <class ptr, class P1, class P2, class P3, class P4,
00363               class P5>
00364     R operator()(ptr obj, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
00365     {
00366       return ((*obj).*m_held_func)(p1, p2, p3, p4, p5);
00367     }
00368 
00370     template <class ptr, class P1, class P2, class P3, class P4,
00371               class P5, class P6>
00372     R operator()(ptr obj, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
00373     {
00374       return ((*obj).*m_held_func)(p1, p2, p3, p4, p5, p6);
00375     }
00376   };
00377 
00378   //  #######################################################
00379   //  =======================================================
00380 
00382 
00383   //  =======================================================
00384 
00385   template <class mem_func>
00386   struct mem_functor : public mem_functor_base<mem_func>
00387   {
00388     mem_functor(mem_func f) : mem_functor_base<mem_func>(f) {}
00389 
00390     // operator()'s inherited from mem_functor_base
00391   };
00392 
00394   template <class MF>
00395   inline mem_functor<MF> mem_func(MF mf)
00396   {
00397     return mf;
00398   }
00399 
00400 
00401   //  #######################################################
00402   //  =======================================================
00403 
00405   template <class fptr>
00406   struct functor_of
00407   {
00408     typedef fptr type;
00409   };
00410 
00412   template <class R, class C>
00413   struct functor_of< R (C::*)() >
00414   {
00415     typedef rutz::mem_functor<R (C::*)()> type;
00416   };
00417 
00419   template <class R, class C>
00420   struct functor_of< R (C::*)() const >
00421   {
00422     typedef rutz::mem_functor<R (C::*)() const> type;
00423   };
00424 
00426   template <class R, class C, class P1>
00427   struct functor_of< R (C::*)(P1) >
00428   {
00429     typedef rutz::mem_functor<R (C::*)(P1)> type;
00430   };
00431 
00433   template <class R, class C, class P1>
00434   struct functor_of< R (C::*)(P1) const >
00435   {
00436     typedef rutz::mem_functor<R (C::*)(P1) const> type;
00437   };
00438 
00440   template <class R, class C, class P1, class P2>
00441   struct functor_of< R (C::*)(P1, P2) >
00442   {
00443     typedef rutz::mem_functor<R (C::*)(P1, P2)> type;
00444   };
00445 
00447   template <class R, class C, class P1, class P2>
00448   struct functor_of< R (C::*)(P1, P2) const >
00449   {
00450     typedef rutz::mem_functor<R (C::*)(P1, P2) const> type;
00451   };
00452 
00454   template <class R, class C, class P1, class P2, class P3>
00455   struct functor_of< R (C::*)(P1, P2, P3) >
00456   {
00457     typedef rutz::mem_functor<R (C::*)(P1, P2, P3)> type;
00458   };
00459 
00461   template <class R, class C, class P1, class P2, class P3>
00462   struct functor_of< R (C::*)(P1, P2, P3) const >
00463   {
00464     typedef rutz::mem_functor<R (C::*)(P1, P2, P3) const> type;
00465   };
00466 
00468   template <class R, class C, class P1, class P2, class P3, class P4>
00469   struct functor_of< R (C::*)(P1, P2, P3, P4) >
00470   {
00471     typedef rutz::mem_functor<R (C::*)(P1, P2, P3, P4)> type;
00472   };
00473 
00475   template <class R, class C, class P1, class P2, class P3, class P4>
00476   struct functor_of< R (C::*)(P1, P2, P3, P4) const >
00477   {
00478     typedef rutz::mem_functor<R (C::*)(P1, P2, P3, P4) const> type;
00479   };
00480 
00482   template <class R, class C, class P1, class P2, class P3, class P4,
00483             class P5>
00484   struct functor_of< R (C::*)(P1, P2, P3, P4, P5) >
00485   {
00486     typedef rutz::mem_functor<R (C::*)(P1, P2, P3, P4, P5)> type;
00487   };
00488 
00490   template <class R, class C, class P1, class P2, class P3, class P4,
00491             class P5>
00492   struct functor_of< R (C::*)(P1, P2, P3, P4, P5) const >
00493   {
00494     typedef rutz::mem_functor<R (C::*)(P1, P2, P3, P4, P5) const> type;
00495   };
00496 
00498   template <class R, class C, class P1, class P2, class P3, class P4,
00499             class P5, class P6>
00500   struct functor_of< R (C::*)(P1, P2, P3, P4, P5, P6) >
00501   {
00502     typedef rutz::mem_functor<R (C::*)(P1, P2, P3, P4, P5, P6)> type;
00503   };
00504 
00506   template <class R, class C, class P1, class P2, class P3, class P4,
00507             class P5, class P6>
00508   struct functor_of< R (C::*)(P1, P2, P3, P4, P5, P6) const >
00509   {
00510     typedef rutz::mem_functor<R (C::*)(P1, P2, P3, P4, P5, P6) const> type;
00511   };
00512 
00513 
00514   // ########################################################
00515   //  =======================================================
00516 
00518   template <class fptr>
00519   inline typename functor_of<fptr>::type
00520   build_functor(fptr f)
00521   {
00522     typedef typename functor_of<fptr>::type functor_t;
00523     return functor_t(f);
00524   }
00525 
00526   //  #######################################################
00527   //  =======================================================
00528 
00529   template <class base_functor, class bound_t>
00530   class bound_first;
00531 
00533   template <class base_functor, class bound_t>
00534   struct func_traits<bound_first<base_functor, bound_t> >
00535   {
00536     enum { num_args = (func_traits<base_functor>::num_args-1) };
00537 
00538     typedef typename func_traits<base_functor>::retn_t   retn_t;
00539     typedef typename func_traits<base_functor>::arg2_t   arg1_t;
00540     typedef typename func_traits<base_functor>::arg3_t   arg2_t;
00541     typedef typename func_traits<base_functor>::arg4_t   arg3_t;
00542     typedef typename func_traits<base_functor>::arg5_t   arg4_t;
00543     typedef typename func_traits<base_functor>::arg6_t   arg5_t;
00544     typedef typename func_traits<base_functor>::arg7_t   arg6_t;
00545     typedef typename func_traits<base_functor>::arg8_t   arg7_t;
00546     typedef                                     null_t   arg8_t;
00547   };
00548 
00550 
00553   template <class base_functor, class bound_t>
00554   class bound_first
00555     :
00556     public func_traits<bound_first<base_functor, bound_t> >
00557   {
00558   private:
00559     base_functor m_held_func;
00560     bound_t m_bound;
00561 
00562   public:
00563     bound_first(base_functor base, bound_t bound) :
00564       m_held_func(base),
00565       m_bound(bound)
00566     {}
00567 
00568     bound_first(const bound_first& other) :
00569       m_held_func(other.m_held_func),
00570       m_bound(other.m_bound)
00571     {}
00572 
00573     typedef func_traits<bound_first<base_functor, bound_t> > traits;
00574     typedef typename traits::retn_t   retn_t;
00575     typedef typename traits::arg1_t   arg1_t;
00576     typedef typename traits::arg2_t   arg2_t;
00577     typedef typename traits::arg3_t   arg3_t;
00578     typedef typename traits::arg4_t   arg4_t;
00579     typedef typename traits::arg5_t   arg5_t;
00580     typedef typename traits::arg6_t   arg6_t;
00581     typedef typename traits::arg7_t   arg7_t;
00582     typedef typename traits::arg8_t   arg8_t;
00583 
00584     //
00585     // All versions of operator() are provided, but only the one that
00586     // involves the correct call to m_held_func() will compile
00587     // successfully
00588     //
00589 
00590     retn_t operator()()
00591     {
00592       return m_held_func(m_bound);
00593     }
00594     retn_t operator()(arg1_t p1)
00595     {
00596       return m_held_func(m_bound, p1);
00597     }
00598     retn_t operator()(arg1_t p1, arg2_t p2)
00599     {
00600       return m_held_func(m_bound, p1, p2);
00601     }
00602     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3)
00603     {
00604       return m_held_func(m_bound, p1, p2, p3);
00605     }
00606     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3, arg4_t p4)
00607     {
00608       return m_held_func(m_bound, p1, p2, p3, p4);
00609     }
00610     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3, arg4_t p4,
00611                       arg5_t p5)
00612     {
00613       return m_held_func(m_bound, p1, p2, p3, p4, p5);
00614     }
00615     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3, arg4_t p4,
00616                       arg5_t p5, arg6_t p6)
00617     {
00618       return m_held_func(m_bound, p1, p2, p3, p4, p5, p6);
00619     }
00620     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3, arg4_t p4,
00621                       arg5_t p5, arg6_t p6, arg7_t p7)
00622     {
00623       return m_held_func(m_bound, p1, p2, p3, p4, p5, p6, p7);
00624     }
00625 
00626   private:
00627     bound_first& operator=(const bound_first&);
00628   };
00629 
00631   template <class base_functor, class bound_t>
00632   bound_first<base_functor, bound_t> bind_first(base_functor base,
00633                                                 bound_t bound)
00634   {
00635     return bound_first<base_functor, bound_t>(base, bound);
00636   }
00637 
00638 
00639   //  #######################################################
00640   //  =======================================================
00641 
00642   template <class base_functor, class bound_t>
00643   class bound_last;
00644 
00646   template <class base_functor, class bound_t>
00647   struct func_traits<bound_last<base_functor, bound_t> >
00648   {
00649     enum { num_args = (func_traits<base_functor>::num_args-1) };
00650 
00651     typedef typename func_traits<base_functor>::retn_t   retn_t;
00652     typedef typename func_traits<base_functor>::arg1_t   arg1_t;
00653     typedef typename func_traits<base_functor>::arg2_t   arg2_t;
00654     typedef typename func_traits<base_functor>::arg3_t   arg3_t;
00655     typedef typename func_traits<base_functor>::arg4_t   arg4_t;
00656     typedef typename func_traits<base_functor>::arg5_t   arg5_t;
00657     typedef typename func_traits<base_functor>::arg6_t   arg6_t;
00658     typedef typename func_traits<base_functor>::arg7_t   arg7_t;
00659     typedef typename func_traits<base_functor>::arg8_t   arg8_t;
00660   };
00661 
00663 
00666   template <class base_functor, class bound_t>
00667   class bound_last
00668     :
00669     public func_traits<bound_last<base_functor, bound_t> >
00670   {
00671   private:
00672     base_functor m_held_func;
00673     bound_t m_bound;
00674 
00675   public:
00676     bound_last(base_functor base, bound_t bound) :
00677       m_held_func(base),
00678       m_bound(bound)
00679     {}
00680 
00681     bound_last(const bound_last& other) :
00682       m_held_func(other.m_held_func),
00683       m_bound(other.m_bound)
00684     {}
00685 
00686     typedef func_traits<bound_last<base_functor, bound_t> > traits;
00687     typedef typename traits::retn_t   retn_t;
00688     typedef typename traits::arg1_t   arg1_t;
00689     typedef typename traits::arg2_t   arg2_t;
00690     typedef typename traits::arg3_t   arg3_t;
00691     typedef typename traits::arg4_t   arg4_t;
00692     typedef typename traits::arg5_t   arg5_t;
00693     typedef typename traits::arg6_t   arg6_t;
00694     typedef typename traits::arg7_t   arg7_t;
00695     typedef typename traits::arg8_t   arg8_t;
00696 
00697     //
00698     // Multiple versions of operator() are provided, but only the one
00699     // that involves the correct call to m_held_func() will compile
00700     // successfully
00701     //
00702 
00703     retn_t operator()()
00704     {
00705       return m_held_func(m_bound);
00706     }
00707     retn_t operator()(arg1_t p1)
00708     {
00709       return m_held_func(p1, m_bound);
00710     }
00711     retn_t operator()(arg1_t p1, arg2_t p2)
00712     {
00713       return m_held_func(p1, p2, m_bound);
00714     }
00715     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3)
00716     {
00717       return m_held_func(p1, p2, p3, m_bound);
00718     }
00719     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3, arg4_t p4)
00720     {
00721       return m_held_func(p1, p2, p3, p4, m_bound);
00722     }
00723     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3, arg4_t p4,
00724                       arg5_t p5)
00725     {
00726       return m_held_func(p1, p2, p3, p4, p5, m_bound);
00727     }
00728     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3, arg4_t p4,
00729                       arg5_t p5, arg6_t p6)
00730     {
00731       return m_held_func(p1, p2, p3, p4, p5, p6, m_bound);
00732     }
00733     retn_t operator()(arg1_t p1, arg2_t p2, arg3_t p3, arg4_t p4,
00734                       arg5_t p5, arg6_t p6, arg7_t p7)
00735     {
00736       return m_held_func(p1, p2, p3, p4, p5, p6, p7, m_bound);
00737     }
00738 
00739   private:
00740     bound_last& operator=(const bound_last&);
00741   };
00742 
00744   template <class base_functor, class bound_t>
00745   bound_last<base_functor, bound_t> bind_last(base_functor base,
00746                                               bound_t bound)
00747   {
00748     return bound_last<base_functor, bound_t>(base, bound);
00749   }
00750 
00751 } // end namespace rutz
00752 
00753 static const char __attribute__((used)) vcid_groovx_rutz_functors_h_utc20050626084020[] = "$Id: functors.h 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00754 #endif // !GROOVX_RUTZ_FUNCTORS_H_UTC20050626084020_DEFINED

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