side_effect_strategy.hh

00001 // This file is a part of Aurelia.
00002 // Copyright (C) 2010  Valentin David
00003 // Copyright (C) 2010  University of Bergen
00004 //
00005 // This program is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 #ifndef __SIDE_EFFECT_STRATEGY_HH
00018 # define __SIDE_EFFECT_STRATEGY_HH
00019 
00020 # include "../strategies.hh"
00021 # include <memory>
00022 
00023 namespace aurelia {
00024 
00031   template <typename Model>
00032   struct side_effect_strategy_concept {
00033     typedef typename Model::strat strat;
00034     typedef typename Model::input input;
00035     typedef typename Model::output output;
00037 #ifdef DOC_GEN
00038     output operator()(strat&, input);
00039 #else
00040     static_assert(std::is_same<decltype(std::declval<strat&>()
00041                                         (std::declval<input>())),
00042                   output>::value,
00043                   "operator() does not return the right type");
00044 
00045     typedef void check;
00046 #endif
00047   };
00056   template <typename S, typename I>
00057   struct default_side_effect_strategy_model {
00058     typedef S strat;
00059     typedef I input;
00060     typedef decltype(std::declval<strat&>()(std::declval<input>())) output;
00061   };
00064   template <typename S, typename I>
00065   struct side_effect_strategy_model {
00066     typedef default_side_effect_strategy_model<S, I> model;
00067   };
00068 
00072   template <typename Kernel>
00073   struct side_effect_strategy {
00074   private:
00075     std::shared_ptr<Kernel> k;
00076 
00077   public:
00078     side_effect_strategy(const Kernel& k): k(new Kernel(k)) {}
00079     side_effect_strategy(const side_effect_strategy& other): k(other.k) {}
00080 
00081     void swap(side_effect_strategy& other) {
00082       std::swap(k, other.k);
00083     }
00084 
00085     side_effect_strategy& operator=(side_effect_strategy other) {
00086       this->swap(other);
00087       return *this;
00088     }
00089 
00090     template <typename T,
00091               typename M =
00092         typename side_effect_strategy_model<Kernel, T>::model>
00093     typename M::output
00094     operator()(const T& t) const {
00095       typedef typename side_effect_strategy_concept<M>::check requires;
00096       return (*k)(t);
00097     }
00098 
00099     const Kernel* operator->() const {
00100       return k.operator->();
00101     }
00102 
00103     Kernel* operator->() {
00104       return k.operator->();
00105     }
00106 
00107     Kernel& operator*() {
00108       return *k;
00109     }
00110 
00111     const Kernel& operator*() const {
00112       return *k;
00113     }
00114   };
00115 
00125   template <typename Kernel>
00126   side_effect_strategy<Kernel> side_effect(const Kernel& k) {
00127     return side_effect_strategy<Kernel>(k);
00128   }
00129 
00130 }
00131 
00132 #endif