utils/black_box_equal.hh

00001 // This file is a part of Catsfoot.
00002 // Copyright (C) 2011  Uni Research
00003 //
00004 // This program is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU Lesser Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #ifndef BLACK_BOX_EQUAL_HH
00018 # define BLACK_BOX_EQUAL_HH
00019 
00020 # include <functional>
00021 # include "../dataset/dataset.hh"
00022 # include "../concept/concepts.hh"
00023 # include "../wrappers/function_wrappers.hh"
00024 
00025 namespace catsfoot {
00026 
00027   namespace details {
00028     template <typename T, typename Op>
00029     struct try_all_compare;
00030 
00031     template <typename T, typename Ret, typename... Args>
00032     struct try_all_compare<T, std::function<Ret(Args...)> > {
00033       template <typename Generator, typename... OtherArgs>
00034       static bool doit(Generator& g,
00035                        const selector<const T&>&,
00036                        const std::function<Ret(Args...)>& f,
00037                        const T& a, const T& b,
00038                        const std::tuple<OtherArgs, OtherArgs>&... args...) {
00039         return doit(g, f, a, b, args..., std::tuple<const T&, const T&>(a, b));
00040       }
00041 
00042       template <typename Generator, typename U, typename... OtherArgs>
00043       static bool doit(Generator& g,
00044                        const selector<U>&,
00045                        const std::function<Ret(Args...)>& f,
00046                        const T& a, const T& b,
00047                        const std::tuple<OtherArgs, OtherArgs>&... args...) {
00048         auto gen = g.get(selector<U>{});
00049         for (auto i = gen.begin();
00050              i != gen.end(); ++i) {
00051           if (!doit(g, f, a, b, args..., std::tuple<U, U>(*i, *i)))
00052             return false;
00053         }
00054         return true;
00055       }
00056 
00057       template <typename Generator, typename... OtherArgs>
00058       static bool doit(Generator& g,
00059                        const std::function<Ret(Args...)>& f,
00060                        const T& a, const T& b,
00061                        const std::tuple<OtherArgs, OtherArgs>&... args...) {
00062         typedef typename std::
00063           tuple_element<sizeof...(OtherArgs), std::tuple<Args...> >::type type;
00064 
00065         return doit(g, selector<type>(), f, a, b, args...);
00066       }
00067 
00069       template <typename Generator>
00070       static bool doit(Generator&,
00071                        const std::function<Ret(Args...)>& f,
00072                        const T&, const T&, const std::tuple<Args, Args>&...
00073                        args...) {
00074         return f(std::get<0>(args)...) ==
00075           f(std::get<1>(args)...);
00076       }
00077 
00078     };
00079   }
00080 
00081   namespace details {
00083     template <typename Generator, typename T, typename... Ops>
00084     struct compare;
00085 
00087     template <typename Generator, typename T>
00088     struct compare<Generator, T> {
00089       compare() = default;
00090 
00091       bool operator()(Generator&, const T&, const T&) const {
00092         return true;
00093       }
00094     };
00095 
00097     template <typename Generator, typename T, typename Op, typename... Ops>
00098     struct compare<Generator, T, Op, Ops...>:
00099       public compare<Generator, T, Ops...> {
00100     private:
00101       typedef compare<Generator, T, Ops...> super;
00102       Op op;
00103     public:
00104       compare(Op&& op,
00105               Ops&&... ops...):
00106         compare<Generator, T, Ops...>(std::move(ops)...),
00107         op(std::move(op))
00108       {}
00109 
00110       bool operator()(Generator &g, const T& a, const T& b) const {
00111         if (!this->super::operator()(g, a, b))
00112           return false;
00113         return details::try_all_compare<T, Op>::doit(g, op, a, b);
00114       }
00115     };
00116 
00118     template <typename Generator, typename T, typename... Ops>
00119     struct compare_top: public compare<Generator, T, Ops...> {
00120     private:
00121       Generator g;
00122     public:
00123       compare_top(const Generator& g,
00124                   Ops&&... ops...):
00125         compare<Generator, T, Ops...>(std::move(ops)...),
00126         g(g)
00127       {}
00128 
00129       compare_top(Generator&& g,
00130                   Ops&&... ops...):
00131         compare<Generator, T, Ops...>(std::move(ops)...),
00132         g(std::move(g))
00133       {}
00134 
00135       bool operator()(const T& a, const T& b) const {
00136         return this->compare<Generator, T, Ops...>::operator()
00137           (*const_cast<Generator*>(&g), a, b);
00138       }
00139     };
00140 
00141   }
00142 
00146   template <typename T>
00147   struct build_comparer {
00148     template <typename Generator, typename... Functions,
00149               typename G = typename std::decay<Generator>::type>
00150     details::compare_top<G, T, typename wrapped<Functions>::type...>
00151     operator()(Generator g, Functions&&... functions...) const {
00152       return details::compare_top<G, T, typename wrapped<Functions>::type...>
00153         (std::forward<Generator>(g),
00154          wrap(std::forward<Functions>(functions))...);
00155     }
00156   };
00157 }
00158 
00159 #endif