Skip to content

Commit 98c120d

Browse files
committed
Partially normalize View/Container constructors and assignment ops
* ra/arrays.hh (ViewBig): Prefer array arg for braces instead of initializer_list for the ravel constructor. Simplify constraints. (ViewSmall): Deduce braces size and fail if needed rather than overload on it. (ViewSmall/ViewBig/SmallArray/Container): Normalize assignment ops. (Container::init): Rely on filldimv to support 0-rank shape instead of repeating the branch here.
1 parent b632e26 commit 98c120d

File tree

4 files changed

+47
-62
lines changed

4 files changed

+47
-62
lines changed

box/view.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ struct View: public ViewBase<Dimv>
9999
std::ranges::copy(std::ranges::subrange(x), begin()); return *this;
100100
}
101101
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; }
102+
#define RA_BRACES(N) constexpr View const & operator=(braces<T, N> x) const requires (!CT && R==ANY) { iter<-1>() = x; return *this; }
104103
RA_FE(RA_BRACES, 2, 3, 4);
105104
#undef RA_BRACES
106105
// ---------
@@ -130,9 +129,8 @@ struct View: public ViewBase<Dimv>
130129
// either
131130
// T not is_scalar [ra44]
132131
constexpr View const & operator=(T const & t) const { ra::iter(*this) = ra::scalar(t); return *this; }
133-
// cf RA_ASSIGNOPS_ITER [ra38][ra34]
134132
View const & operator=(View const & x) const { ra::iter(*this) = x; return *this; }
135-
#define RA_ASSIGNOPS(OP) \
133+
#define RA_ASSIGNOPS(OP) \
136134
constexpr View const & operator OP(auto const & x) const { ra::iter(*this) OP x; return *this; } \
137135
constexpr View const & operator OP(Iterator auto && x) const { ra::iter(*this) OP RA_FW(x); return *this; }
138136
RA_FE(RA_ASSIGNOPS, =, *=, +=, -=, /=)
@@ -152,6 +150,5 @@ template <class P, class Dimv> using ViewS = View<P, Dimv>;
152150
int main()
153151
{
154152
ra::TestRecorder tr;
155-
156153
return tr.summary();
157154
}

ra/arrays.hh

Lines changed: 38 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ c_order(auto const & dimv, bool step1=true)
3636
// Views
3737
// ---------------------
3838

39-
// for ViewBig
39+
// for ViewSmall
4040

4141
template <class T, class Dimv> struct nested_arg { using sub = noarg<>; };
4242
template <class T, class Dimv> struct small_args { using nested = std::tuple<>; };
@@ -54,7 +54,7 @@ struct nested_arg<T, Dimv>
5454
using sub = std::conditional_t<0==n, T, SmallArray<T, ic_t<c_dimv(s)>>>;
5555
};
5656

57-
// for ViewSmall. FIXME Let any expr = braces.
57+
// for ViewBig. FIXME Let any expr = braces.
5858

5959
template <class T, rank_t R> struct braces_ { using type = noarg<>; };
6060
template <class T, rank_t R> using braces = braces_<T, R>::type;
@@ -100,26 +100,23 @@ struct ViewSmall
100100
constexpr explicit ViewSmall(P cp_): cp(cp_) {}
101101
constexpr ViewSmall(ViewSmall const & s) = default;
102102
template <class Q> constexpr ViewSmall(ViewSmall<Q, Dimv> const & x) requires (requires { ViewSmall(x.cp); }): ViewSmall(x.cp) {} // FIXME Slice
103+
constexpr ViewSmall const & operator=(ViewSmall const & x) const { iter() = x; return *this; }
103104
// braces, row major and nested
104-
constexpr ViewSmall const & operator=(T (&&x)[size()>1 ? size() : 0]) const
105-
requires (rank()>1 && size()>1)
105+
template <int N> constexpr ViewSmall const & operator=(T (&&x)[N]) const requires (1!=rank())
106106
{
107+
static_assert(size()==N, "Mismatched sizes.");
107108
std::ranges::copy(std::ranges::subrange(x), begin()); return *this;
108109
}
109-
constexpr ViewSmall const & operator=(typename nested_arg<T, Dimv>::sub (&&x)[0<rank() && 0<len(0) ? len(0) : 0]) const
110-
requires (0<rank() && 0<len(0) && (1!=rank() || 1!=len(0)))
110+
template <int N> constexpr ViewSmall const & operator=(typename nested_arg<T, Dimv>::sub (&&x)[N]) const requires (1!=rank() || 1!=len(0))
111111
{
112112
ra::iter<-1>(*this) = x;
113113
if !consteval { asm volatile("" ::: "memory"); } // patch for [ra01]
114114
return *this;
115115
}
116-
// T not is_scalar [ra44]
117-
constexpr ViewSmall const & operator=(T const & t) const { ra::iter(*this) = ra::scalar(t); return *this; }
118-
// cf RA_ASSIGNOPS_ITER [ra38][ra34]
119-
ViewSmall const & operator=(ViewSmall const & x) const { ra::iter(*this) = x; return *this; }
120116
#define RA_ASSIGNOPS(OP) \
121-
constexpr ViewSmall const & operator OP(auto const & x) const { ra::iter(*this) OP x; return *this; } \
122-
constexpr ViewSmall const & operator OP(Iterator auto && x) const { ra::iter(*this) OP RA_FW(x); return *this; }
117+
constexpr decltype(auto) operator OP(T const & t) const { iter() OP ra::scalar(t); return *this; } /* [ra44] */ \
118+
constexpr decltype(auto) operator OP(auto const & x) const { iter() OP x; return *this; } \
119+
constexpr decltype(auto) operator OP(Iterator auto && x) const { iter() OP RA_FW(x); return *this; }
123120
RA_FE(RA_ASSIGNOPS, =, *=, +=, -=, /=)
124121
#undef RA_ASSIGNOPS
125122
template <dim_t s, dim_t o=0> constexpr auto as() const { return from(*this, ra::iota(ic<s>, o)); }
@@ -161,27 +158,23 @@ struct ViewBig
161158
constexpr ViewBig(Slice auto const & x) requires (requires { ViewBig(x.dimv, x.cp); }): ViewBig(x.dimv, x.cp) {}
162159
constexpr ViewBig(auto const & s, P cp) requires (requires { [](dim_t){}(VAL(s)); }): cp(cp) { filldimv(ra::iter(s), dimv); }
163160
constexpr ViewBig(auto const & s, P cp) requires (requires { [](Dim){}(VAL(s)); }): cp(cp) { resize(dimv, ra::size(s)); ra::iter(dimv) = s; } // [ra37]
164-
template <class D> using dimbraces = std::conditional_t<R==ANY, std::initializer_list<D>, D (&&)[R==ANY?0:R]>;
165-
constexpr ViewBig(dimbraces<dim_t> s, P cp): ViewBig(ra::iter(s), cp) {}
166-
constexpr ViewBig(dimbraces<Dim> s, P cp): ViewBig(ra::iter(s), cp) {}
161+
template <int N> constexpr ViewBig(dim_t (&&s)[N], P cp): ViewBig(ra::iter(s), cp) {}
162+
template <int N> constexpr ViewBig(Dim (&&s)[N], P cp): ViewBig(ra::iter(s), cp) {}
163+
constexpr ViewBig const & operator=(ViewBig const & x) const { iter() = x; return *this; }
167164
// braces, row major and nested
168-
constexpr ViewBig const & operator=(std::initializer_list<T> x) const requires (1!=R)
165+
template <int N> constexpr ViewBig const & operator=(T (&&x)[N]) const requires (1!=R)
169166
{
170-
RA_CK(size()==ssize(x), "Mismatched sizes ", size(), " ", ssize(x), ".");
167+
RA_CK(size()==N, "Mismatched sizes ", size(), " ", N, ".");
171168
std::ranges::copy(std::ranges::subrange(x), begin()); return *this;
172169
}
173170
constexpr ViewBig const & operator=(braces<T, R> x) const requires (R!=ANY) { iter<-1>() = x; return *this; }
174-
#define RA_BRACES(N) \
175-
constexpr ViewBig const & operator=(braces<T, N> x) const requires (R==ANY) { iter<-1>() = x; return *this; }
171+
#define RA_BRACES(N) constexpr ViewBig const & operator=(braces<T, N> x) const requires (R==ANY) { iter<-1>() = x; return *this; }
176172
RA_FE(RA_BRACES, 2, 3, 4);
177173
#undef RA_BRACES
178-
// T not is_scalar [ra44]
179-
constexpr ViewBig const & operator=(T const & t) const { iter() = ra::scalar(t); return *this; }
180-
// cf RA_ASSIGNOPS_ITER [ra38][ra34]
181-
ViewBig const & operator=(ViewBig const & x) const { iter() = x; return *this; }
182174
#define RA_ASSIGNOPS(OP) \
183-
constexpr ViewBig const & operator OP (auto const & x) const { ra::iter(*this) OP x; return *this; } \
184-
constexpr ViewBig const & operator OP (Iterator auto && x) const { ra::iter(*this) OP RA_FW(x); return *this; }
175+
constexpr decltype(auto) operator OP(T const & t) const { iter() OP ra::scalar(t); return *this; } /* [ra44] */ \
176+
constexpr decltype(auto) operator OP(auto const & x) const { iter() OP x; return *this; } \
177+
constexpr decltype(auto) operator OP(Iterator auto && x) const { iter() OP RA_FW(x); return *this; }
185178
RA_FE(RA_ASSIGNOPS, =, *=, +=, -=, /=)
186179
#undef RA_ASSIGNOPS
187180
template <rank_t c=0> constexpr auto iter() const && { return Cell<P, Dimv, ic_t<c>>(cp, std::move(dimv)); }
@@ -256,23 +249,18 @@ SmallArray<T, Dimv_, std::tuple<nested_args ...>>
256249
constexpr SmallArray() {}
257250
// T not is_scalar [ra44]
258251
constexpr SmallArray(T const & t) { std::ranges::fill(cp, t); }
259-
// row-major ravel braces
260-
constexpr SmallArray(T const & x0, std::convertible_to<T> auto const & ... x)
261-
requires (rank()>1 && size()>1 && (1+sizeof...(x))==size())
252+
// braces, row-major and nested
253+
constexpr SmallArray(T const & x0, std::convertible_to<T> auto const & ... x) requires (1!=rank())
262254
{
263255
view() = { static_cast<T>(x0), static_cast<T>(x) ... };
264256
}
265-
// nested braces FIXME p1219??
266-
constexpr SmallArray(nested_args const & ... x)
267-
requires (0<rank() && 0<len(0) && (1!=rank() || 1!=len(0)))
268-
{
269-
view() = { x ... };
270-
}
257+
constexpr SmallArray(nested_args const & ... x) requires (1!=rank() || 1!=len(0)) { view() = { x ... }; } // FIXME p1219??
271258
constexpr SmallArray(auto const & x) { view() = x; }
272259
constexpr SmallArray(Iterator auto && x) { view() = RA_FW(x); }
273260
#define RA_ASSIGNOPS(OP) \
274-
constexpr SmallArray & operator OP(auto const & x) { view() OP x; return *this; } \
275-
constexpr SmallArray & operator OP(Iterator auto && x) { view() OP RA_FW(x); return *this; }
261+
constexpr decltype(auto) operator OP(T const & x) { iter() OP ra::scalar(x); return *this; } /* [ra44] */ \
262+
constexpr decltype(auto) operator OP(auto const & x) { iter() OP x; return *this; } \
263+
constexpr decltype(auto) operator OP(Iterator auto && x) { iter() OP RA_FW(x); return *this; }
276264
RA_FE(RA_ASSIGNOPS, =, *=, +=, -=, /=)
277265
#undef RA_ASSIGNOPS
278266
template <int s, int o=0> constexpr decltype(auto) as(this auto && self) { return RA_FW(self).view().template as<s, o>(); }
@@ -300,7 +288,7 @@ from_ravel(auto && b)
300288
{
301289
A a;
302290
RA_CK(1==ra::rank(b) && ra::size(b)==ra::size(a),
303-
"Cannot ravel shape [", fmt(nstyle, ra::shape(b)), "] into [", ra::size(a), "].");
291+
"Cannot ravel shape [", fmt(nstyle, ra::shape(b)), "] to [", ra::size(a), "].");
304292
std::ranges::copy(RA_FW(b), a.begin());
305293
return a;
306294
}
@@ -372,46 +360,43 @@ struct Container: public ViewBig<typename storage_traits<Store>::T *, R>
372360
cp = storage_traits<Store>::data(store);
373361
}
374362
#define RA_ASSIGNOPS(OP) \
375-
constexpr Container & operator OP (auto const & x) { view() OP x; return *this; } \
376-
constexpr Container & operator OP (Iterator auto && x) { view() OP RA_FW(x); return *this; }
363+
constexpr decltype(auto) operator OP(T const & x) { iter() OP ra::scalar(x); return *this; } /* [ra44] */ \
364+
constexpr decltype(auto) operator OP(auto const & x) { iter() OP x; return *this; } \
365+
constexpr decltype(auto) operator OP(Iterator auto && x) { iter() OP RA_FW(x); return *this; }
377366
RA_FE(RA_ASSIGNOPS, =, *=, +=, -=, /=)
378367
#undef RA_ASSIGNOPS
379-
constexpr Container & operator=(std::initializer_list<T> const x) requires (1!=R) { view() = x; return *this; }
368+
template <int N> constexpr Container & operator=(T (&&x)[N]) requires (1!=R) { view() = RA_FW(x); return *this; }
380369
constexpr Container & operator=(braces<T, R> x) requires (ANY!=R) { view() = x; return *this; }
381-
#define RA_BRACES(N) \
382-
constexpr Container & operator=(braces<T, N> x) requires (ANY==R) { view() = x; return *this; }
370+
#define RA_BRACES(N) constexpr Container & operator=(braces<T, N> x) requires (ANY==R) { view() = x; return *this; }
383371
RA_FE(RA_BRACES, 2, 3, 4);
384372
#undef RA_BRACES
385373

386374
constexpr void
387-
init(auto const & s) requires (1==rank_s(s) || ANY==rank_s(s))
375+
init(auto const & s) requires (0==rank_s(s) || 1==rank_s(s) || ANY==rank_s(s))
388376
{
389377
static_assert(!std::is_convertible_v<value_t<decltype(s)>, Dim>);
390-
RA_CK(1==ra::rank(s), "Rank mismatch for init shape ", ra::rank(s), ".");
378+
RA_CK(0==ra::rank(s) || 1==ra::rank(s), "Rank mismatch for init shape ", ra::rank(s), ".");
391379
static_assert(ANY==R || ANY==size_s(s) || R==size_s(s) || UNB==size_s(s), "Bad shape for rank.");
392380
store = storage_traits<Store>::create(filldimv(ra::iter(s), dimv));
393381
cp = storage_traits<Store>::data(store);
394382
}
395-
constexpr void init(dim_t s) { init(std::array {s}); } // allow scalar if rank is 1.
396383

397384
// provided so that {} calls sharg constructor below.
398385
constexpr static auto zdims = std::apply([](auto ... i){ return std::array<Dim, (R==ANY)?1:R>{Dim{i*0, 1} ... }; }, mp::iota<(R==ANY)?1:R>{});
399386
constexpr Container(): View(zdims, nullptr) {}
400387
constexpr Container() requires (R==0): Container({}, none) {}
388+
constexpr Container(auto const & x): Container(ra::shape(x), none) { view() = x; }
389+
constexpr Container(braces<T, R> x) requires (R!=ANY): Container(braces_shape<T, R>(x), none) { view() = x; }
390+
#define RA_BRACES(N) constexpr Container(braces<T, N> x) requires (R==ANY): Container(braces_shape<T, N>(x), none) { view() = x; }
391+
RA_FE(RA_BRACES, 1, 2, 3, 4)
392+
#undef RA_BRACES
401393

402394
using sharg = decltype(shape(std::declval<View>().iter()));
403395
// sharg overloads handle {...} arguments. Size check is at conversion if sharg is Small.
404396
constexpr Container(sharg const & s, none_t) { init(s); }
405-
constexpr Container(sharg const & s, auto && x): Container(s, none) { view() = x; }
397+
constexpr Container(sharg const & s, auto const & x): Container(s, none) { view() = x; }
406398
constexpr Container(sharg const & s, braces<T, R> x) requires (1==R): Container(s, none) { view() = x; }
407399

408-
constexpr Container(auto const & x): Container(ra::shape(x), none) { view() = x; }
409-
constexpr Container(braces<T, R> x) requires (R!=ANY): Container(braces_shape<T, R>(x), none) { view() = x; }
410-
#define RA_BRACES(N) \
411-
constexpr Container(braces<T, N> x) requires (R==ANY): Container(braces_shape<T, N>(x), none) { view() = x; }
412-
RA_FE(RA_BRACES, 1, 2, 3, 4)
413-
#undef RA_BRACES
414-
415400
// FIXME requires copyable Y, which conflicts with semantics of view_.operator=. store(x) avoids the conflict for Big, but not for Unique. Should construct in place like std::vector.
416401
constexpr void
417402
fill1(auto && xbegin, dim_t xsize)

ra/expr.hh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ namespace ra {
5151
for_each([](auto && y, auto && x){ /* [ra5] */ RA_FW(y) OP RA_FW(x); }, *this, RA_FW(x))
5252
#define RA_ASSIGNOPS_DEFAULT(OP) \
5353
constexpr void operator OP(auto && x) { RA_ASSIGNOPS_LINE(OP); }
54-
// Restate for expression classes since a template doesn't replace the copy assignment op.
54+
// Restate for iterator classes since a template doesn't replace the copy assignment. Cf RA_ASSIGNOPS on views [ra34][ra38].
5555
#define RA_ASSIGNOPS_ITER(TYPE) \
5656
constexpr TYPE & operator=(TYPE && x) { RA_ASSIGNOPS_LINE(=); return *this; } \
5757
constexpr TYPE & operator=(TYPE const & x) { RA_ASSIGNOPS_LINE(=); return *this; } \
@@ -60,13 +60,13 @@ namespace ra {
6060
RA_FE(RA_ASSIGNOPS_DEFAULT, =, *=, +=, -=, /=)
6161

6262
template <class N> constexpr auto
63-
maybe_any = []{ if constexpr (is_ctype<N>) { return N::value; } else { return ANY; } }();
63+
maybe_any = []{ if constexpr (is_ctype<N>) return N::value; else return ANY; }();
6464

6565
template <class S> constexpr S
66-
maybe_step = []{ if constexpr (is_ctype<S>) { static_assert(1==S::value); return S{}; } else { return 1; } }();
66+
maybe_step = []{ if constexpr (is_ctype<S>) { static_assert(1==S::value); return S{}; } else return 1; }();
6767

6868
template <class K> constexpr auto
69-
clen(auto const & v, K k) { if constexpr (is_ctype<K> && (ANY!=v.len_s(k))) return ic<v.len_s(k)>; else return v.len(k); }
69+
clen(auto const & v, K k) { if constexpr (is_ctype<K> && ANY!=v.len_s(k)) return ic<v.len_s(k)>; else return v.len(k); }
7070

7171
template <class A, class B> constexpr auto
7272
cadd(A a, B b) { if constexpr (is_ctype<A> && is_ctype<B>) return ic<a+b>; else return a+b; }

test/ra-0.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,8 +481,11 @@ int main()
481481
tr.section("row-major assignment from initializer_list, rank 2");
482482
{
483483
ra::Unique<double, 2> a({3, 2}, ra::none);
484+
std::cout << "A00" << std::endl;
484485
a = { 2, 3, 1, 4, 8, 9 };
486+
std::cout << "A01" << std::endl;
485487
tr.test_eq(2, a(0, 0));
488+
std::cout << "A02" << std::endl;
486489
tr.test_eq(3, a(0, 1));
487490
tr.test_eq(1, a(1, 0));
488491
tr.test_eq(4, a(1, 1));

0 commit comments

Comments
 (0)