00001
00002
00003 #ifndef DUNE_COMMON_HYBRIDUTILITIES_HH
00004 #define DUNE_COMMON_HYBRIDUTILITIES_HH
00005
00006 #include <tuple>
00007 #include <utility>
00008
00009 #include <dune/common/typeutilities.hh>
00010 #include <dune/common/fvector.hh>
00011 #include <dune/common/indices.hh>
00012
00013
00014
00015 namespace Dune {
00016 namespace Hybrid {
00017
00018 namespace Impl {
00019
00020
00021 template<class T, int i>
00022 constexpr auto size(const Dune::FieldVector<T, i>*, const PriorityTag<5>&)
00023 -> decltype(std::integral_constant<std::size_t,i>())
00024 {
00025 return {};
00026 }
00027
00028
00029 template<class T, T... t, class Index>
00030 constexpr auto size(std::integer_sequence<T, t...>, PriorityTag<4>)
00031 {
00032 using sizeAsType = std::tuple_size<decltype(std::make_tuple(t...))>;
00033 return std::integral_constant<std::size_t, sizeAsType::value>();
00034 }
00035
00036
00037 template<class T>
00038 constexpr auto size(const T*, const PriorityTag<3>&)
00039 -> decltype(std::integral_constant<std::size_t,std::tuple_size<T>::value>())
00040 {
00041 return {};
00042 }
00043
00044
00045 template<class T>
00046 constexpr auto size(const T*, const PriorityTag<1>&)
00047 -> decltype(std::integral_constant<std::size_t,T::size()>())
00048 {
00049 return {};
00050 }
00051
00052
00053 template<class T>
00054 constexpr auto size(const T* t, const PriorityTag<0>&)
00055 {
00056 return t->size();
00057 }
00058
00059 }
00060
00061
00062
00084 template<class T>
00085 constexpr auto size(const T& t)
00086 {
00087 return Impl::size(&t, PriorityTag<42>());
00088 }
00089
00090
00091
00092 namespace Impl {
00093
00094 template<class Container, class Index,
00095 std::enable_if_t<IsTuple<std::decay_t<Container>>::value, int> = 0>
00096 constexpr decltype(auto) elementAt(Container&& c, Index&&, PriorityTag<2>)
00097 {
00098 return std::get<std::decay_t<Index>::value>(c);
00099 }
00100
00101 template<class T, T... t, class Index>
00102 constexpr decltype(auto) elementAt(std::integer_sequence<T, t...> c, Index&&, PriorityTag<1>)
00103 {
00104 return std::get<std::decay_t<Index>::value>(std::make_tuple(std::integral_constant<T, t>()...));
00105 }
00106
00107 template<class Container, class Index>
00108 constexpr decltype(auto) elementAt(Container&& c, Index&& i, PriorityTag<0>)
00109 {
00110 return c[i];
00111 }
00112
00113 }
00114
00115
00116
00137 template<class Container, class Index>
00138 constexpr decltype(auto) elementAt(Container&& c, Index&& i)
00139 {
00140 return Impl::elementAt(std::forward<Container>(c), std::forward<Index>(i), PriorityTag<42>());
00141 }
00142
00143
00144
00145 namespace Impl {
00146
00147 template<class Begin, class End>
00148 class StaticIntegralRange
00149 {
00150 public:
00151
00152 template<std::size_t i>
00153 constexpr auto operator[](Dune::index_constant<i>) const
00154 {
00155 return std::integral_constant<typename Begin::value_type, Begin::value+i>();
00156 }
00157
00158 static constexpr auto size()
00159 {
00160 return std::integral_constant<typename Begin::value_type, End::value - Begin::value>();
00161 }
00162 };
00163
00164 template<class T>
00165 class DynamicIntegralRange
00166 {
00167 public:
00168 constexpr DynamicIntegralRange(const T& begin, const T& end):
00169 begin_(begin),
00170 end_(end)
00171 {}
00172
00173 constexpr auto size() const
00174 {
00175 return end_ - begin_;
00176 }
00177
00178 constexpr T operator[](const T&i) const
00179 { return begin_+i; }
00180
00181 private:
00182 T begin_;
00183 T end_;
00184 };
00185
00186 template<class Begin, class End,
00187 std::enable_if_t<IsIntegralConstant<Begin>::value and IsIntegralConstant<End>::value, int> = 0>
00188 constexpr auto integralRange(const Begin& begin, const End& end, const PriorityTag<1>&)
00189 {
00190 static_assert(Begin::value <= End::value, "You cannot create an integralRange where end<begin");
00191 return Impl::StaticIntegralRange<Begin,End>();
00192 }
00193
00194
00195
00196
00197
00198 template<class Begin, class End>
00199 auto integralRange(const Begin& begin, const End& end, const PriorityTag<0>&)
00200 {
00201 assert(begin <= end);
00202 return Impl::DynamicIntegralRange<End>(begin, end);
00203 }
00204
00205 }
00206
00207
00208
00226 template<class Begin, class End>
00227 constexpr auto integralRange(const Begin& begin, const End& end)
00228 {
00229 return Impl::integralRange(begin, end, PriorityTag<42>());
00230 }
00231
00245 template<class End>
00246 constexpr auto integralRange(const End& end)
00247 {
00248 return Impl::integralRange(Dune::Indices::_0, end, PriorityTag<42>());
00249 }
00250
00251
00252
00253 namespace Impl {
00254
00255 template<class T>
00256 void evaluateFoldExpression(std::initializer_list<T>&&)
00257 {}
00258
00259 template<class Range, class F, class Index, Index... i>
00260 constexpr void forEachIndex(Range&& range, F&& f, std::integer_sequence<Index, i...>)
00261 {
00262 evaluateFoldExpression<int>({(f(Hybrid::elementAt(range, std::integral_constant<Index,i>())), 0)...});
00263 }
00264
00265 template<class F, class Index, Index... i>
00266 constexpr void forEach(std::integer_sequence<Index, i...> range, F&& f, PriorityTag<2>)
00267 {
00268 evaluateFoldExpression<int>({(f(std::integral_constant<Index,i>()), 0)...});
00269 }
00270
00271
00272 template<class Range, class F,
00273 std::enable_if_t<IsIntegralConstant<decltype(Hybrid::size(std::declval<Range>()))>::value, int> = 0>
00274 constexpr void forEach(Range&& range, F&& f, PriorityTag<1>)
00275 {
00276 auto size = Hybrid::size(range);
00277 auto indices = std::make_index_sequence<size>();
00278 forEachIndex(std::forward<Range>(range), std::forward<F>(f), indices);
00279 }
00280
00281 template<class Range, class F>
00282 constexpr void forEach(Range&& range, F&& f, PriorityTag<0>)
00283 {
00284 for(std::size_t i=0; i<range.size(); ++i)
00285 f(range[i]);
00286
00287
00288
00289 }
00290
00291 }
00292
00293
00294
00313 template<class Range, class F>
00314 constexpr void forEach(Range&& range, F&& f)
00315 {
00316 Impl::forEach(std::forward<Range>(range), std::forward<F>(f), PriorityTag<42>());
00317 }
00318
00319
00320
00336 template<class Range, class T, class F>
00337 T accumulate(Range&& range, T value, F&& f)
00338 {
00339 forEach(std::forward<Range>(range), [&](auto&& entry) {
00340 value = f(value, entry);
00341 });
00342 return value;
00343 }
00344
00345
00346
00347 namespace Impl {
00348
00349 template<class IfFunc, class ElseFunc>
00350 constexpr decltype(auto) ifElse(std::true_type, IfFunc&& ifFunc, ElseFunc&& elseFunc)
00351 {
00352 return ifFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
00353 }
00354
00355 template<class IfFunc, class ElseFunc>
00356 constexpr decltype(auto) ifElse(std::false_type, IfFunc&& ifFunc, ElseFunc&& elseFunc)
00357 {
00358 return elseFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
00359 }
00360
00361 template<class IfFunc, class ElseFunc>
00362 decltype(auto) ifElse(const bool& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
00363 {
00364 if (condition)
00365 return ifFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
00366 else
00367 return elseFunc([](auto&& x) -> decltype(auto) { return std::forward<decltype(x)>(x);});
00368 }
00369
00370 }
00371
00372
00373
00394 template<class Condition, class IfFunc, class ElseFunc>
00395 decltype(auto) ifElse(const Condition& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc)
00396 {
00397 return Impl::ifElse(condition, std::forward<IfFunc>(ifFunc), std::forward<ElseFunc>(elseFunc));
00398 }
00399
00407 template<class Condition, class IfFunc>
00408 void ifElse(const Condition& condition, IfFunc&& ifFunc)
00409 {
00410 ifElse(condition, std::forward<IfFunc>(ifFunc), [](auto&& i) {});
00411 }
00412
00413
00414
00415 namespace Impl {
00416
00417 template<class T1, class T2>
00418 constexpr auto equals(const T1& t1, const T2& t2, PriorityTag<1>) -> decltype(T1::value, T2::value, std::integral_constant<bool,T1::value == T2::value>())
00419 { return {}; }
00420
00421 template<class T1, class T2>
00422 constexpr auto equals(const T1& t1, const T2& t2, PriorityTag<0>)
00423 {
00424 return t1==t2;
00425 }
00426
00427 }
00428
00429
00430
00440 template<class T1, class T2>
00441 constexpr auto equals(T1&& t1, T2&& t2)
00442 {
00443 return Impl::equals(std::forward<T1>(t1), std::forward<T2>(t2), PriorityTag<1>());
00444 }
00445
00446
00447
00448 namespace Impl {
00449
00450 template<class Result, class T, class Value, class Branches, class ElseBranch>
00451 constexpr Result switchCases(std::integer_sequence<T>, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
00452 {
00453 return elseBranch();
00454 }
00455
00456 template<class Result, class T, T t0, T... tt, class Value, class Branches, class ElseBranch>
00457 constexpr Result switchCases(std::integer_sequence<T, t0, tt...>, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
00458 {
00459 return ifElse(
00460 Hybrid::equals(std::integral_constant<T, t0>(), value),
00461 [&](auto id) -> decltype(auto) {
00462 return id(branches)(std::integral_constant<T, t0>());
00463 }, [&](auto id) -> decltype(auto) {
00464 return Impl::switchCases<Result>(id(std::integer_sequence<T, tt...>()), value, branches, elseBranch);
00465 });
00466 }
00467
00468 }
00469
00470
00471
00499 template<class Cases, class Value, class Branches, class ElseBranch>
00500 constexpr decltype(auto) switchCases(const Cases& cases, const Value& value, Branches&& branches, ElseBranch&& elseBranch)
00501 {
00502 return Impl::switchCases<decltype(elseBranch())>(cases, value, std::forward<Branches>(branches), std::forward<ElseBranch>(elseBranch));
00503 }
00504
00525 template<class Cases, class Value, class Branches>
00526 constexpr void switchCases(const Cases& cases, const Value& value, Branches&& branches)
00527 {
00528 return Impl::switchCases<void>(cases, value, std::forward<Branches>(branches), []() {});
00529 }
00530
00531
00532 }
00533 }
00534
00535
00536 #endif // #ifndef DUNE_COMMON_HYBRIDUTILITIES_HH