bootstrap.hh 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // -*- mode: c++; coding: utf-8 -*-
  2. /// @file bootstrap.hh
  3. /// @brief Before all other ra:: includes.
  4. // (c) Daniel Llorens - 2013-2015, 2017, 2019
  5. // This library is free software; you can redistribute it and/or modify it under
  6. // the terms of the GNU General Public License as published by the Free
  7. // Software Foundation; either version 3 of the License, or (at your option) any
  8. // later version.
  9. #pragma once
  10. #include <sys/types.h> // ssize_t
  11. #include "ra/tuples.hh"
  12. namespace ra {
  13. constexpr int VERSION = 12; // to force or prevent upgrades on dependents
  14. static_assert(sizeof(int)>=4, "bad assumption on int");
  15. using rank_t = int;
  16. using dim_t = ssize_t;
  17. constexpr dim_t DIM_ANY = -1099999444;
  18. constexpr dim_t DIM_BAD = -1099999888;
  19. constexpr rank_t RANK_ANY = -1099999444;
  20. constexpr rank_t RANK_BAD = -1099999888;
  21. static_assert(std::is_signed_v<rank_t> && std::is_signed_v<dim_t>, "bad dim types");
  22. constexpr dim_t dim_prod(dim_t const a, dim_t const b)
  23. {
  24. return (a==DIM_ANY) ? DIM_ANY : ((b==DIM_ANY) ? DIM_ANY : a*b);
  25. }
  26. constexpr rank_t rank_sum(rank_t const a, rank_t const b)
  27. {
  28. return (a==RANK_ANY) ? RANK_ANY : ((b==RANK_ANY) ? RANK_ANY : a+b);
  29. }
  30. constexpr rank_t rank_diff(rank_t const a, rank_t const b)
  31. {
  32. return (a==RANK_ANY) ? RANK_ANY : ((b==RANK_ANY) ? RANK_ANY : a-b);
  33. }
  34. constexpr bool inside(dim_t const i, dim_t const b)
  35. {
  36. return i>=0 && i<b;
  37. }
  38. constexpr bool inside(dim_t const i, dim_t const a, dim_t const b)
  39. {
  40. return i>=a && i<b;
  41. }
  42. // ---------------------
  43. // concepts (WIP)
  44. // ---------------------
  45. template <class P, class S>
  46. concept RaFlat = requires (P p, S d)
  47. {
  48. { *p };
  49. { p += d };
  50. };
  51. template <class A>
  52. concept RaIterator = requires (A a, rank_t k, dim_t d, rank_t i, rank_t j)
  53. {
  54. { a.rank() } -> std::convertible_to<rank_t>;
  55. { a.size(k) } -> std::same_as<dim_t>;
  56. { a.adv(k, d) } -> std::same_as<void>;
  57. { a.stride(k) };
  58. { a.keep_stride(d, i, j) } -> std::same_as<bool>;
  59. { a.flat() } -> RaFlat<decltype(a.stride(k))>;
  60. };
  61. // ---------------------
  62. // other types, forward decl
  63. // ---------------------
  64. enum none_t { none }; // used in array constructors to mean ‘don't initalize’.
  65. struct no_arg {}; // used in array constructors to mean ‘don't instantiate’
  66. // Order of decl issues.
  67. template <class C> struct Scalar; // for type predicates
  68. template <std::random_access_iterator P, rank_t RANK=RANK_ANY> struct View; // for cell_iterator. // FIXME [ra27]
  69. template <class V> struct ra_traits_def;
  70. template <class S> struct default_strides_ {};
  71. template <class tend> struct default_strides_<std::tuple<tend>> { using type = mp::int_list<1>; };
  72. template <> struct default_strides_<std::tuple<>> { using type = mp::int_list<>; };
  73. template <class t0, class t1, class ... ti>
  74. struct default_strides_<std::tuple<t0, t1, ti ...>>
  75. {
  76. using rest = typename default_strides_<std::tuple<t1, ti ...>>::type;
  77. static int const stride0 = t1::value * mp::first<rest>::value;
  78. using type = mp::cons<mp::int_t<stride0>, rest>;
  79. };
  80. template <class S> using default_strides = typename default_strides_<S>::type;
  81. template <int n> struct dots_t
  82. {
  83. static_assert(n>=0);
  84. constexpr static rank_t rank_s() { return n; }
  85. };
  86. template <int n> constexpr dots_t<n> dots = dots_t<n>();
  87. constexpr auto all = dots<1>;
  88. template <int n> struct insert_t
  89. {
  90. static_assert(n>=0);
  91. constexpr static rank_t rank_s() { return n; }
  92. };
  93. template <int n=1> constexpr insert_t<n> insert = insert_t<n>();
  94. // Used by cell_iterator / cell_iterator_small.
  95. template <class C>
  96. struct CellFlat
  97. {
  98. C c;
  99. constexpr void operator+=(dim_t const s) { c.p += s; }
  100. constexpr C & operator*() { return c; }
  101. };
  102. // Common to View / SmallBase.
  103. template <int cell_rank, class A> inline constexpr auto
  104. iter(A && a) { return std::forward<A>(a).template iter<cell_rank>(); }
  105. // Defined in wrank.hh but used in big.hh (selectors, etc).
  106. template <class A, class ... I> inline constexpr auto from(A && a, I && ... i);
  107. // Extended by operators.hh and repeated in global.hh.
  108. // TODO All users be int, then this take int.
  109. inline constexpr bool any(bool const x) { return x; }
  110. inline constexpr bool every(bool const x) { return x; }
  111. inline constexpr bool odd(unsigned int N) { return N & 1; }
  112. // This logically belongs in ra/small.hh, but it's here so that we can return ra:: types from shape().
  113. // ---------------------
  114. // nested braces for Small initializers
  115. // ---------------------
  116. // The general SmallArray has 4 constructors,
  117. // 1. The empty constructor.
  118. // 2. The scalar constructor. This is needed when T isn't registered as ra::scalar, which isn't required purely for container use.
  119. // 3. The ravel constructor.
  120. // 4. The nested constructor.
  121. // When SmallArray has rank 1, or the first dimension is empty, or the shape is [1] or [], several of the constructors above become ambiguous. We solve this by defining the constructor arguments to variants of no_arg.
  122. template <class T, class sizes>
  123. struct nested_tuple;
  124. // ambiguity with empty constructor and scalar constructor.
  125. // if size(0) is 0, then prefer the empty constructor.
  126. // if size(0) is 1...
  127. template <class sizes> constexpr bool no_nested = (mp::first<sizes>::value<1);
  128. template <> constexpr bool no_nested<mp::nil> = true;
  129. template <> constexpr bool no_nested<mp::int_list<1>> = true;
  130. template <class T, class sizes>
  131. using nested_arg = std::conditional_t<no_nested<sizes>,
  132. std::tuple<no_arg>, // match the template for SmallArray.
  133. typename nested_tuple<T, sizes>::list>;
  134. // ambiguity with scalar constructors (for rank 0) and nested_tuple (for rank 1).
  135. template <class sizes> constexpr bool no_ravel = ((mp::len<sizes> <=1) || (mp::apply<mp::prod, sizes>::value <= 1));
  136. template <class T, class sizes>
  137. using ravel_arg = std::conditional_t<no_ravel<sizes>,
  138. std::tuple<no_arg, no_arg>, // match the template for SmallArray.
  139. mp::makelist<mp::apply<mp::prod, sizes>::value, T>>;
  140. template <class T, class sizes, class strides = default_strides<sizes>> struct SmallView; // for cell_iterator_small
  141. template <class T, class sizes, class strides = default_strides<sizes>,
  142. class nested_arg_ = nested_arg<T, sizes>, class ravel_arg_ = ravel_arg<T, sizes>>
  143. struct SmallArray;
  144. template <class T, dim_t ... sizes> using Small = SmallArray<T, mp::int_list<sizes ...>>;
  145. template <class T>
  146. struct nested_tuple<T, mp::nil>
  147. {
  148. using sub = no_arg;
  149. using list = std::tuple<no_arg>; // match the template for SmallArray.
  150. };
  151. template <class T, int S0>
  152. struct nested_tuple<T, mp::int_list<S0>>
  153. {
  154. using sub = T;
  155. using list = mp::makelist<S0, T>;
  156. };
  157. template <class T, int S0, int S1, int ... S>
  158. struct nested_tuple<T, mp::int_list<S0, S1, S ...>>
  159. {
  160. using sub = Small<T, S1, S ...>;
  161. using list = mp::makelist<S0, sub>;
  162. };
  163. } // namespace ra