|
| 1 | +// -*- mode: c++; coding: utf-8 -*- |
| 2 | +// ra-ra/box - Refactor Views (WIP) |
| 3 | + |
| 4 | +// (c) Daniel Llorens - 2026 |
| 5 | +// This library is free software; you can redistribute it and/or modify it under |
| 6 | +// the terms of the GNU Lesser 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 | + |
| 10 | +#include <iostream> |
| 11 | +#include <iterator> |
| 12 | +#include "ra/test.hh" |
| 13 | + |
| 14 | +using std::cout, std::endl, std::flush; |
| 15 | + |
| 16 | +// TODO |
| 17 | +// fix deduction of f(view); once viewbig is an alias R isn't deduced anymore. Handle viewsmall & viewbig together. |
| 18 | + |
| 19 | +namespace ra { |
| 20 | + |
| 21 | +template <class Dimv> |
| 22 | +struct ViewBase |
| 23 | +{ |
| 24 | + constexpr static Dimv const simv = {}; |
| 25 | + [[no_unique_address]] Dimv dimv; // FIXME const after init |
| 26 | +}; |
| 27 | + |
| 28 | +template <is_ctype Dimv> |
| 29 | +struct ViewBase<Dimv> |
| 30 | +{ |
| 31 | + constexpr static auto simv = Dimv::value; |
| 32 | + constexpr static auto dimv = simv; |
| 33 | +}; |
| 34 | + |
| 35 | +template <class P, class Dimv> |
| 36 | +struct View: public ViewBase<Dimv> |
| 37 | +{ |
| 38 | + static_assert(has_len<P> || std::bidirectional_iterator<P>); |
| 39 | + P cp; |
| 40 | + using ViewBase<Dimv>::simv, ViewBase<Dimv>::dimv; |
| 41 | + constexpr static bool CT = is_ctype<Dimv>; |
| 42 | +// exclude T and sub constructors by making T & sub noarg |
| 43 | + constexpr static bool have_braces = CT && std::is_reference_v<decltype(*cp)>; |
| 44 | + using T = std::conditional_t<have_braces, std::remove_reference_t<decltype(*cp)>, noarg<>>; |
| 45 | +// --------- |
| 46 | +// on dimv |
| 47 | + constexpr static rank_t R = rank_frame(size_s<decltype(simv)>(), 0); |
| 48 | + consteval static rank_t rank() requires (ANY!=R) { return R; } |
| 49 | + constexpr rank_t rank() const requires (ANY==R) { return rank_t(dimv.size()); } |
| 50 | +#define RAC(k, f) is_ctype<decltype(simv[k].f)> |
| 51 | + constexpr static dim_t len_s(auto k) { if constexpr (CT || RAC(k, len)) return len(k); else return ANY; } |
| 52 | + constexpr static dim_t len(auto k) requires (CT || RAC(k, len)) { return simv[k].len; } |
| 53 | + constexpr dim_t len(int k) const requires (!(CT || RAC(k, len))) { return dimv[k].len; } |
| 54 | + constexpr static dim_t step(auto k) requires (CT || RAC(k, step)) { return k<rank() ? simv[k].step : 0; } |
| 55 | + constexpr dim_t step(int k) const requires (!(CT || RAC(k, step))) { return k<rank() ? dimv[k].step : 0; } |
| 56 | +#undef RAC |
| 57 | +// --------- |
| 58 | +// maybe remove entirely |
| 59 | + constexpr dim_t size() const requires (!CT) { return ra::size(*this); } |
| 60 | + constexpr bool empty() const requires (!CT) { return any(0==map(&Dim::len, dimv)); } |
| 61 | + consteval static dim_t size() requires (CT) { return std::apply([](auto ... i){ return (i.len * ... * 1); }, dimv); } |
| 62 | + consteval static dim_t slen() { if constexpr (CT) return size(); else return ANY; } // FIXME maybe do without |
| 63 | + consteval bool empty() const requires (CT) { return any(0==map(&Dim::len, dimv)); } |
| 64 | +// --------- |
| 65 | +// common constructors |
| 66 | + constexpr explicit View(P cp_): cp(cp_) {} // empty dimv, but also uninit by slicers, esp. has_len<P> |
| 67 | + constexpr View(View const & s) = default; |
| 68 | +// --------- |
| 69 | +// constructors for CT |
| 70 | + template <class PP> constexpr View(View<PP, Dimv> const & x) requires (CT): View(x.cp) {} // FIXME Slice |
| 71 | + constexpr View const & |
| 72 | + operator=(T (&&x)[have_braces ? slen() : 0]) const |
| 73 | + requires (CT && have_braces && R>1 && slen()>1) |
| 74 | + { |
| 75 | + std::ranges::copy(std::ranges::subrange(x), begin()); return *this; |
| 76 | + } |
| 77 | + constexpr View const & |
| 78 | + operator=(typename nested_arg<T, Dimv>::sub (&&x)[have_braces ? (R>0 ? len_s(0) : 0) : 0]) const |
| 79 | + requires (CT && have_braces && 0<R && 0<len_s(0) && (1!=R || 1!=len_s(0))) |
| 80 | + { |
| 81 | + ra::iter<-1>(*this) = x; |
| 82 | + if !consteval { asm volatile("" ::: "memory"); } // patch for [ra01] |
| 83 | + return *this; |
| 84 | + } |
| 85 | +// --------- |
| 86 | +// constructors for !CT |
| 87 | + constexpr View() requires (!CT) {} // used by Container constructors |
| 88 | + constexpr View(Slice auto const & x) requires (!CT): View(x.dimv, x.cp) {} |
| 89 | + constexpr View(auto const & s, P cp_) requires (!CT && requires { [](dim_t){}(VAL(s)); }): cp(cp_) { filldimv(ra::iter(s), dimv); } |
| 90 | + constexpr View(auto const & s, P cp_) requires (!CT && requires { [](Dim){}(VAL(s)); }): cp(cp_) { resize(dimv, ra::size(s)); ra::iter(dimv) = s; } // [ra37] |
| 91 | + template <class D> using dimbraces = std::conditional_t<R==ANY, std::initializer_list<D>, D (&&)[R==ANY?0:R]>; |
| 92 | + constexpr View(std::conditional_t<!CT, dimbraces<dim_t>, noarg<dim_t>> s, P cp_) requires (!CT): View(ra::iter(s), cp_) {} |
| 93 | + constexpr View(std::conditional_t<!CT, dimbraces<Dim>, noarg<Dim>> s, P cp_) requires (!CT): View(ra::iter(s), cp_) {} |
| 94 | +// --------- |
| 95 | +// row-major & nested braces for !CT |
| 96 | + constexpr View const & operator=(std::initializer_list<T> x) const requires (!CT && 1!=R) |
| 97 | + { |
| 98 | + RA_CK(size()==ssize(x), "Mismatched sizes ", size(), " ", ssize(x), "."); |
| 99 | + std::ranges::copy(std::ranges::subrange(x), begin()); return *this; |
| 100 | + } |
| 101 | + constexpr View const & operator=(braces<T, R> x) const requires (!CT && R!=ANY) { iter<-1>() = x; return *this; } |
| 102 | +#define RA_BRACES(N) \ |
| 103 | + constexpr View const & operator=(braces<T, N> x) const requires (!CT && R==ANY) { iter<-1>() = x; return *this; } |
| 104 | + RA_FE(RA_BRACES, 2, 3, 4); |
| 105 | +#undef RA_BRACES |
| 106 | +// --------- |
| 107 | +// CT |
| 108 | + template <dim_t s, dim_t o=0> constexpr auto as() const requires (CT) { return from(*this, ra::iota(ic<s>, o)); } |
| 109 | + template <rank_t c=0> constexpr auto iter() const requires (CT) { return Cell<P, Dimv, ic_t<c>>(cp); } |
| 110 | + constexpr auto iter(rank_t c) const requires (CT) { return Cell<P, decltype(dimv) const &, dim_t>(cp, dimv, c); } |
| 111 | + constexpr auto begin() const requires (CT) { if constexpr (c_order(dimv)) return cp; else return STLIterator(iter()); } |
| 112 | + constexpr auto end() const requires (CT && c_order(dimv)) { return cp+size(); } |
| 113 | + constexpr static auto end() requires (CT && !c_order(dimv)) { return std::default_sentinel; } |
| 114 | + constexpr decltype(auto) back() const requires (CT) { static_assert(size()>0, "Bad back()."); return cp[size()-1]; } |
| 115 | +// --------- |
| 116 | +// !CT |
| 117 | + template <rank_t c=0> constexpr auto iter() const && requires (!CT) { return Cell<P, Dimv, ic_t<c>>(cp, std::move(dimv)); } |
| 118 | + template <rank_t c=0> constexpr auto iter() const & requires (!CT) { return Cell<P, Dimv const &, ic_t<c>>(cp, dimv); } |
| 119 | + constexpr auto iter(rank_t c) const && requires (!CT) { return Cell<P, Dimv, dim_t>(cp, std::move(dimv), c); } |
| 120 | + constexpr auto iter(rank_t c) const & requires (!CT) { return Cell<P, Dimv const &, dim_t>(cp, dimv, c); } |
| 121 | + constexpr auto begin() const requires (!CT) { return STLIterator(iter<0>()); } |
| 122 | + constexpr decltype(auto) static end() requires (!CT) { return std::default_sentinel; } |
| 123 | + constexpr decltype(auto) back() const requires (!CT) { dim_t s=size(); RA_CK(s>0, "Bad back()."); return cp[s-1]; } |
| 124 | +// conversion to const, used by Container::view(). FIXME cf CT cases |
| 125 | + constexpr operator View<T const *, Dimv> const & () const requires (!CT && !std::is_const_v<T>) |
| 126 | + { |
| 127 | + return *reinterpret_cast<View<T const *, Dimv> const *>(this); |
| 128 | + } |
| 129 | +// --------- |
| 130 | +// either |
| 131 | +// T not is_scalar [ra44] |
| 132 | + constexpr View const & operator=(T const & t) const { ra::iter(*this) = ra::scalar(t); return *this; } |
| 133 | +// cf RA_ASSIGNOPS_ITER [ra38][ra34] |
| 134 | + View const & operator=(View const & x) const { ra::iter(*this) = x; return *this; } |
| 135 | +#define RA_ASSIGNOPS(OP) \ |
| 136 | + constexpr View const & operator OP(auto const & x) const { ra::iter(*this) OP x; return *this; } \ |
| 137 | + constexpr View const & operator OP(Iterator auto && x) const { ra::iter(*this) OP RA_FW(x); return *this; } |
| 138 | + RA_FE(RA_ASSIGNOPS, =, *=, +=, -=, /=) |
| 139 | +#undef RA_ASSIGNOPS |
| 140 | + constexpr decltype(auto) operator()(this auto && self, auto && ... i) { return from(RA_FW(self), RA_FW(i) ...); } |
| 141 | + constexpr decltype(auto) operator[](this auto && self, auto && ... i) { return from(RA_FW(self), RA_FW(i) ...); } |
| 142 | + constexpr decltype(auto) at(auto const & i) const { return *indexer(*this, cp, ra::iter(i)); } |
| 143 | + constexpr operator decltype(*cp) () const { return to_scalar(*this); } |
| 144 | + constexpr auto data() const { return cp; } |
| 145 | +}; |
| 146 | + |
| 147 | +template <class P, rank_t R> using ViewB = View<P, std::conditional_t<ANY==R, vector_default_init<Dim>, std::array<Dim, ANY==R ? 0 : R>>>; |
| 148 | +template <class P, class Dimv> using ViewS = View<P, Dimv>; |
| 149 | + |
| 150 | +} // namespace ra |
| 151 | + |
| 152 | +int main() |
| 153 | +{ |
| 154 | + ra::TestRecorder tr; |
| 155 | + |
| 156 | + return tr.summary(); |
| 157 | +} |
0 commit comments