pqc/external/flint-2.4.3/flintxx/forwarding.h
2014-05-24 23:16:06 +02:00

235 lines
7.0 KiB
C++

/*=============================================================================
This file is part of FLINT.
FLINT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
FLINT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FLINT; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=============================================================================*/
/******************************************************************************
Copyright (C) 2013 Tom Bachmann
******************************************************************************/
#ifndef CXX_FORWARDING_H
#define CXX_FORWARDING_H
#include <iosfwd>
#include <string>
#include "evaluation_tools.h"
#include "mp.h"
#include "rules.h"
#include "tuple.h"
// XXX This file is UNFINISHED. It is/was meant to use for extending flintxx by
// compisition, in particular for the NTL wrapper.
// Ask Tom (e_mc_h2@web.de) if you want to use it.
namespace flint {
namespace forwarding {
// Specialise this to enable forwarding of your class.
template<class T>
struct enable : mp::false_ { };
} // forwarding
namespace rules {
template<class T>
struct print<T, typename mp::enable_if<traits::is_implemented<
print<typename forwarding::enable<T>::underlying_t> > >::type>
{
static void doit(const T& t, std::ostream& o)
{
typedef typename forwarding::enable<T> et;
print<typename et::underlying_t>::doit(et::get_underlying(t), o);
}
};
template<class T>
struct to_string<T, typename mp::enable_if<traits::is_implemented<
to_string<typename forwarding::enable<T>::underlying_t> > >::type>
{
static std::string get(const T& t, int base)
{
typedef typename forwarding::enable<T> et;
return to_string<typename et::underlying_t>::get(
et::get_underlying(t), base);
}
};
namespace rdetail {
template<class T, class Enable = void>
struct maybe_forward
{
typedef T underlying_t;
static const T& get_underlying(const T& t) {return t;}
static T& get_underlying(T& t) {return t;}
};
template<class T>
struct maybe_forward<T, typename mp::enable_if<forwarding::enable<T> >::type>
: forwarding::enable<T> { };
template<template<class, class, class> class Wrapped, class T, class U>
struct fwd_enable2
: mp::enable_if<mp::and_<
traits::is_implemented<Wrapped<
typename maybe_forward<T>::underlying_t,
typename maybe_forward<U>::underlying_t,
void> >,
mp::or_<
typename forwarding::enable<T>,
typename forwarding::enable<U> > > >
{
typedef Wrapped<
typename maybe_forward<T>::underlying_t,
typename maybe_forward<U>::underlying_t,
void> wrapped_t;
};
} // rdetail
template<class T, class U>
struct assignment<T, U, typename rdetail::fwd_enable2<rules::assignment, T, U>::type>
{
static void doit(T& t, const U& u)
{
rdetail::fwd_enable2<rules::assignment, T, U>::wrapped_t::doit(
rdetail::maybe_forward<T>::get_underlying(t),
rdetail::maybe_forward<U>::get_underlying(u));
}
};
template<class T, class U>
struct cmp<T, U, typename rdetail::fwd_enable2<rules::cmp, T, U>::type>
{
static int get(const T& t, const U& u)
{
return rdetail::fwd_enable2<rules::cmp, T, U>::wrapped_t::get(
rdetail::maybe_forward<T>::get_underlying(t),
rdetail::maybe_forward<U>::get_underlying(u));
}
};
template<class T, class U>
struct equals<T, U, typename rdetail::fwd_enable2<rules::equals, T, U>::type>
{
static bool get(const T& t, const U& u)
{
return rdetail::fwd_enable2<rules::equals, T, U>::wrapped_t::get(
rdetail::maybe_forward<T>::get_underlying(t),
rdetail::maybe_forward<U>::get_underlying(u));
}
};
template<class T, class U>
struct conversion<T, U, typename mp::enable_if<traits::is_implemented<
conversion<T, typename forwarding::enable<U>::underlying_t> > >::type>
{
static T get(const U& u)
{
return conversion<T, typename forwarding::enable<U>::underlying_t>::get(
forwarding::enable<U>::get_underlying(u));
}
};
// TODO automatically convert fwd<U> to fwd<T> ?
// TODO instantiate_temporaries ?
namespace rdetail {
template<class Data>
struct needs_forwarding : mp::false_ { };
template<class Data>
struct needs_forwarding<const Data&> : forwarding::enable<Data> { };
template<class Head, class Tail>
struct needs_forwarding<tuple<Head, Tail> >
: mp::or_<needs_forwarding<Head>, needs_forwarding<Tail> > { };
template<class Data>
struct translate
{
typedef Data type;
static type doit(const Data& d) {return d;}
};
template<class Wrapped>
struct translate<const Wrapped&>
{
typedef maybe_forward<Wrapped> fw;
typedef typename fw::underlying_t type;
static type doit(const Wrapped& d)
{
return fw::get_underlying(d);
}
};
template<class Head, class Tail>
struct translate<tuple<Head, Tail> >
{
typedef translate<Head> htranslator;
typedef translate<Tail> ttranslator;
typedef tuple<typename htranslator::type, typename ttranslator::type> type;
static type doit(const tuple<Head, Tail>& d)
{
return type(htranslator::doit(d.head), ttranslator::doit(d.tail));
}
};
template<class Op, class Data, bool result_is_temporary, class Enable = void>
struct can_forward
{
typedef rdetail::translate<Data> translator;
typedef typename translator::type translated_t;
typedef typename mp::find_evaluation<
Op, translated_t, result_is_temporary>::type rule_t;
static const bool val = traits::is_implemented<rule_t>::val;
};
template<class Op, class Data, bool result_is_temporary>
struct can_forward<Op, Data, result_is_temporary,
typename mp::disable_if<needs_forwarding<Data> >::type>
{
static const bool val = false;
};
}
template<class Op, class Data, bool result_is_temporary>
struct evaluation<Op, Data, result_is_temporary, 1,
typename mp::enable_if<
rdetail::can_forward<Op, Data, result_is_temporary> >::type>
{
typedef rdetail::translate<Data> translator;
typedef typename translator::type translated_t;
typedef typename mp::find_evaluation<
Op, translated_t, result_is_temporary>::type rule_t;
typedef typename rule_t::temporaries_t temporaries_t;
// TODO repackaging
typedef typename rule_t::return_t return_t;
static void doit(const Data& input, temporaries_t temps, return_t* output)
{
rule_t::doit(translator::doit(input), temps, output);
}
};
} //rules
} // flint
#endif