00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef __PATTERN_UTILS_HH
00018 # define __PATTERN_UTILS_HH
00019
00020 # include "pattern.hh"
00021 # include "../terms/term_concept.hh"
00022
00023 namespace aurelia {
00024
00025 template <typename T, typename Constr, size_t N,
00026 typename tuple, typename... SubPatterns>
00027 struct build_real_type;
00028
00029 template <typename Constructor, typename ...SubPatterns>
00030 struct pattern;
00031
00032 template <typename Pattern>
00033 struct builder;
00034
00035 template <typename Constructor, typename ...SubPatterns>
00036 struct builder<pattern<Constructor, SubPatterns...> > {
00037 pattern<Constructor, SubPatterns...> p;
00038 builder(const pattern<Constructor, SubPatterns...>& p): p(p) {}
00039 builder(pattern<Constructor, SubPatterns...>&& p): p(std::move(p)) {}
00040
00041 template <typename T,
00042 typename M = typename term_model<T>::model,
00043 typename = typename
00044 std::enable_if<std::is_convertible<
00045 typename build_type<T, Constructor>::type,
00046 T>::value>::type>
00047 operator T() {
00048 return build_real_type<T, Constructor, 0, std::tuple<SubPatterns...>,
00049 SubPatterns...>::build(p.subpatterns);
00050 }
00051 };
00052
00053 template <typename LHS, typename RHS, size_t N = 0,
00054 size_t Last = std::tuple_size<LHS>::value>
00055 struct assign_build {
00056 static void do_it(LHS& lhs, const RHS& rhs) {
00057 static_assert(std::tuple_size<LHS>::value == Last,
00058 "Wrong size");
00059 static_assert(std::tuple_size<RHS>::value == Last,
00060 "Wrong size");
00061 std::get<N>(lhs) = *std::get<N>(rhs);
00062 assign_build<LHS, RHS, N+1, Last>::do_it(lhs, rhs);
00063 }
00064 };
00065
00066 template <typename LHS, typename RHS, size_t N>
00067 struct assign_build<LHS, RHS, N, N> {
00068 static void do_it(LHS&, const RHS&) {
00069 static_assert(std::tuple_size<LHS>::value == N,
00070 "Wrong size");
00071 static_assert(std::tuple_size<RHS>::value == N,
00072 "Wrong size");
00073 }
00074 };
00075
00076 template <typename T, typename U,
00077 typename = decltype(std::declval<T>() =
00078 *(std::declval<const U>()))>
00079 std::true_type has_assign_build_helper(type_traits::try_first, T, U) {
00080 return 0;
00081 }
00082
00083 template <typename T, typename U>
00084 std::false_type has_assign_build_helper(type_traits::try_second, T, U) {
00085 return 0;
00086 }
00087
00088 template <typename T, typename U>
00089 struct can_match:
00090 type_traits::itself<
00091 decltype(has_assign_build_helper(type_traits::try_first(),
00092 std::declval<T>(),
00093 std::declval<U>()))>::type {
00094 };
00095
00096 template <typename T, typename U, typename... TS, typename... US>
00097 struct can_match<std::tuple<T, TS...>, std::tuple<U, US...> >
00098 {
00099 enum: bool { value = can_match<T,U>::value &&
00100 can_match<std::tuple<TS...>, std::tuple<US...> >::value };
00101 };
00102
00103 template <>
00104 struct can_match<std::tuple<>, std::tuple<> >: public std::true_type {
00105 };
00106
00107 template <typename Constructor, typename ...SubPatterns>
00108 struct pattern {
00109 Constructor constructor;
00110 std::tuple<SubPatterns...> subpatterns;
00111
00112 pattern(const Constructor& constructor, SubPatterns... p):
00113 constructor(constructor), subpatterns(p...) {}
00114
00115 template <typename Term,
00116 typename M = typename term_model<Term>::model>
00117 Term
00118 operator=(const Term& t) throw (failure) {
00119 typedef typename term_concept<M>::check require;
00120 t.match(*this);
00121 return t;
00122 }
00123
00124 template <typename... OtherSubPatterns,
00125 typename = typename
00126 std::enable_if<can_match<std::tuple<SubPatterns...>,
00127 std::tuple<OtherSubPatterns...> >
00128 ::value>::type>
00129 const builder<pattern<Constructor, OtherSubPatterns...> >&
00130 operator=(const builder<pattern<Constructor, OtherSubPatterns...> >& b)
00131 throw (failure) {
00132 static_assert(sizeof...(SubPatterns)==sizeof...(OtherSubPatterns),
00133 "Number of children in patterns not corresponding");
00134 assign_build<std::tuple<SubPatterns...>,
00135 std::tuple<OtherSubPatterns...> >
00136 ::do_it(subpatterns, b.p.subpatterns);
00137 return b;
00138 }
00139
00140 builder<pattern> operator*() const {
00141 return builder<pattern>(*this);
00142 }
00143
00144 };
00145
00146 template <typename Constructor, typename ...SubPatterns>
00147 struct pattern_model<pattern<Constructor, SubPatterns...> > {
00148 struct model {
00149 typedef pattern<Constructor, SubPatterns...> type;
00150 typedef builder<pattern<Constructor, SubPatterns...> > build_type;
00151 };
00152 };
00153
00154 template <typename Constructor>
00155 struct pattern_generator {
00156 Constructor constructor;
00157
00158 pattern_generator() {}
00159
00160 pattern_generator(const Constructor& constructor):
00161 constructor(constructor) {}
00162
00163 pattern_generator(const pattern_generator& other):
00164 constructor(other.constructor) {}
00165
00166 template <typename ...A>
00167 pattern<Constructor, A...> operator()(A... a) const {
00168 return pattern<Constructor, A...>(constructor, std::forward<A>(a)...);
00169 }
00170 };
00171
00172 }
00173
00174 #endif