Skip to content

Commit 4348be3

Browse files
committed
Format specifier for separators
* ra/ply.hh (std::formatter<...>)::parse: As stated. * doc/ra-ra.texi (Formatted I/O): Document. * ra/arrays.hh (SmallArray): Add iter(rank). * test/iterator-small.cc: Excercise the new specifers, and also var rank cell iteration. * test/ra-0.cc: Test for shape_s<>.
1 parent cca2b94 commit 4348be3

File tree

7 files changed

+54
-39
lines changed

7 files changed

+54
-39
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ The test suite in [test/](test/) runs under either SCons (`CXXFLAGS=-O3 scons`)
6868
#### Notes
6969
7070
* Both index and size types are signed. Index base is 0.
71-
* The default array order is C or row-major (last dimension changes fastest). You can make array views with other orders.
71+
* The default array order is C or row-major (last dimension changes first). You can make array views with other orders.
7272
* The subscripting operator is `()` or `[]`, indistinctly.
7373
* Indices are checked by default. Checks can be disabled with a compilation flag.
7474

docs/index.html

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/ra-ra.texi

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1384,7 +1384,7 @@ case d:
13841384
@cindex @code{lstyle}
13851385
@cindex @code{pstyle}
13861386

1387-
The following predefined styles are named after popular languages: @code{jstyle}, @code{nstyle}, @code{cstyle}, @code{lstyle}, and @code{pstyle}. The default is @code{jstyle}; @code{nstyle} is like @code{jstyle} but with @code{.shape=noshape}.
1387+
The following predefined styles are named after popular languages: @code{jstyle} (the default), @code{cstyle}, @code{lstyle}, and @code{pstyle}. There is also @code{nstyle} which is like @code{jstyle} but with @code{.shape=noshape}.
13881388

13891389
@example
13901390
@verbatim
@@ -1424,6 +1424,8 @@ Like @code{.shape=withshape}.
14241424
Like @code{.shape=noshape}.
14251425
@item @code{d} --
14261426
Like @code{.shape=default}.
1427+
@item @code{@verb{|S{a}{b}|}} --
1428+
Like @code{.sep0=a} and @code{.sepn=b}. Both strings must be given. These strings cannot contain the character @verb{|}|}.
14271429
@end itemize
14281430

14291431
After a colon, the remainder of the format string is applied to the type of the element. For example:

ra/arrays.hh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ struct ViewSmall
9999

100100
constexpr explicit ViewSmall(P cp_): cp(cp_) {}
101101
constexpr ViewSmall(ViewSmall const & s) = default;
102-
template <class PP> constexpr ViewSmall(ViewSmall<PP, Dimv> const & x) requires (requires { ViewSmall(x.cp); }): ViewSmall(x.cp) {} // FIXME Slice
102+
template <class Q> constexpr ViewSmall(ViewSmall<Q, Dimv> const & x) requires (requires { ViewSmall(x.cp); }): ViewSmall(x.cp) {} // FIXME Slice
103103
// braces, row major and nested
104104
constexpr ViewSmall const & operator=(T (&&x)[size()>1 ? size() : 0]) const
105105
requires (rank()>1 && size()>1)
@@ -277,6 +277,7 @@ SmallArray<T, Dimv_, std::tuple<nested_args ...>>
277277
#undef RA_ASSIGNOPS
278278
template <int s, int o=0> constexpr decltype(auto) as(this auto && self) { return RA_FW(self).view().template as<s, o>(); }
279279
template <rank_t c=0> constexpr auto iter(this auto && self) { return RA_FW(self).view().template iter<c>(); }
280+
constexpr auto iter(this auto && self, rank_t c) { return RA_FW(self).view().template iter(c); }
280281
constexpr auto begin(this auto && self) { return self.view().begin(); }
281282
constexpr auto end(this auto && self) { return self.view().end(); }
282283
constexpr decltype(auto) back(this auto && self) { return RA_FW(self).view().back(); }
@@ -336,13 +337,13 @@ template <class Store, rank_t R>
336337
struct Container: public ViewBig<typename storage_traits<Store>::T *, R>
337338
{
338339
Store store;
339-
constexpr auto data(this auto && self) { return self.view().data(); }
340340
using T = typename storage_traits<Store>::T;
341341
using View = ViewBig<T *, R>;
342342
using ViewConst = ViewBig<T const *, R>;
343343
constexpr ViewConst const & view() const { return *this; }
344344
constexpr View & view() { return *this; }
345345
using View::size, View::rank, View::dimv, View::cp;
346+
constexpr auto data(this auto && self) { return self.view().data(); }
346347

347348
// A(shape 2 3) = A-type [1 2 3] initializes, so it doesn't behave as A(shape 2 3) = not-A-type [1 2 3] which uses View::operator=. This is used by operator>>(std::istream &, Container &). See test/ownership.cc [ra20].
348349
// TODO don't require copyable T in constructors, see fill1. That requires operator= to initialize, not update.
@@ -411,7 +412,7 @@ struct Container: public ViewBig<typename storage_traits<Store>::T *, R>
411412
RA_FE(RA_BRACES, 1, 2, 3, 4)
412413
#undef RA_BRACES
413414

414-
// 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.
415+
// 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.
415416
constexpr void
416417
fill1(auto && xbegin, dim_t xsize)
417418
{

ra/ply.hh

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -650,16 +650,24 @@ struct std::formatter<A>
650650
case 's': fmt.shape = ra::withshape; break;
651651
case 'n': fmt.shape = ra::noshape; break;
652652
case 'd': fmt.shape = ra::defaultshape; break;
653-
default: throw std::format_error("Bad format for ra:: object.");
653+
case 'S': {
654+
auto nexti = [&]{
655+
if (i==ctx.end()) { throw format_error("Format string ends early."); }
656+
return ++i;
657+
};
658+
auto read = [&]{
659+
if ('{'!=*nexti()) { throw std::format_error("Bad args for format :m."); }
660+
std::string s; while ('}'!=*nexti()) s+=*i; return s;
661+
};
662+
fmt.sep0 = read();
663+
fmt.sepn = read();
664+
break;
665+
}
666+
default: throw std::format_error("Bad format specifier.");
654667
}
655668
}
656-
if (i!=ctx.end() && ':'==*i) {
657-
ctx.advance_to(i+1);
658-
i = under.parse(ctx);
659-
}
660-
if (i!=ctx.end() && '}'!=*i) {
661-
throw std::format_error("Bad input while parsing format for ra:: object.");
662-
}
669+
if (i!=ctx.end() && ':'==*i) { ctx.advance_to(i+1); i = under.parse(ctx); }
670+
if (i==ctx.end() || '}'!=*i) { throw std::format_error("Bad format."); }
663671
return i;
664672
}
665673
constexpr auto
@@ -675,21 +683,19 @@ struct std::formatter<A>
675683
out = std::format_to(out, "{:d}\n", ra::iter(sha));
676684
}
677685
ra::rank_t const rank = ra::rank(a);
678-
auto goin = [&](int k, auto & goin) -> void
679-
{
680-
using std::ranges::copy;
686+
auto goin = [&](int k, auto & goin) -> void {
681687
if (k==rank) {
682688
ctx.advance_to(under.format(*a, ctx));
683689
out = ctx.out();
684690
} else {
685-
out = copy(fmt.open, out).out;
691+
out = std::ranges::copy(fmt.open, out).out;
686692
for (int i=0; i<sha[k]; ++i) {
687693
goin(k+1, goin);
688694
if (i+1<sha[k]) {
689695
a.adv(k, 1);
690-
out = copy((k==rank-1 ? fmt.sep0 : fmt.sepn), out).out;
696+
out = std::ranges::copy((k==rank-1 ? fmt.sep0 : fmt.sepn), out).out;
691697
for (int i=0; i<std::max(0, rank-2-k); ++i) {
692-
out = copy(fmt.rep, out).out;
698+
out = std::ranges::copy(fmt.rep, out).out;
693699
}
694700
if (fmt.align && k<rank-1) {
695701
for (int i=0; i<(k+1)*ra::size(fmt.open); ++i) {
@@ -701,13 +707,13 @@ struct std::formatter<A>
701707
break;
702708
}
703709
}
704-
out = copy(fmt.close, out).out;
710+
out = std::ranges::copy(fmt.close, out).out;
705711
}
706712
};
707713
goin(0, goin);
708714
return out;
709715
}
710-
constexpr auto format(A const & a_, auto & ctx) const { return format(a_, ctx, fmt); }
716+
constexpr auto format(A const & a, auto & ctx) const { return format(a, ctx, fmt); }
711717
};
712718

713719
template <class A>

test/iterator-small.cc

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,27 +60,23 @@ int main()
6060
++i;
6161
}
6262
}
63-
tr.section("rank>0");
63+
tr.section("cell rank");
6464
{
65-
auto test_over
66-
= [&](auto && a)
67-
{
68-
auto test = [&](std::string ref, auto cr)
69-
{
70-
std::ostringstream o;
71-
for_each([&o](auto && a) { o << a << "|"; }, ra::iter<cr()>(a));
72-
tr.test_eq(ra::scalar(ref), ra::scalar(o.str()));
73-
};
74-
test("1|2|3|4|5|6|", ra::int_c<-2>());
75-
test("1 2 3|4 5 6|", ra::int_c<-1>());
76-
test("1|2|3|4|5|6|", ra::int_c<0>());
77-
test("1 2 3|4 5 6|", ra::int_c<1>());
78-
test("1 2 3\n4 5 6|", ra::int_c<2>());
79-
};
65+
auto test_over = [&](auto && a){
66+
auto test = [&](std::string ref, auto cr){
67+
tr.test_eq(ra::scalar(ref), ra::scalar(std::format("{:nS{|}{-}}", ra::iter<cr()>(a))));
68+
tr.test_eq(ra::scalar(ref), ra::scalar(std::format("{:nS{|}{-}:n}", a.iter(cr))));
69+
};
70+
test("1|2|3-4|5|6", ra::int_c<-2>());
71+
test("1 2 3|4 5 6", ra::int_c<-1>());
72+
test("1|2|3-4|5|6", ra::int_c<0>());
73+
test("1 2 3|4 5 6", ra::int_c<1>());
74+
test("1 2 3\n4 5 6", ra::int_c<2>());
75+
};
8076
tr.section("default steps");
8177
test_over(ra::Small<int, 2, 3> {{1, 2, 3}, {4, 5, 6}});
8278
tr.section("non-default steps");
83-
test_over(ra::transpose(ra::Small<int, 3, 2> {{1, 4}, {2, 5}, {3, 6}}, ilist_t<1, 0>{}));
79+
test_over(ra::transpose(ra::Small<int, 3, 2> {{1, 4}, {2, 5}, {3, 6}}, ra::ilist<1, 0>));
8480
}
8581
}
8682
return tr.summary();

test/ra-0.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,5 +796,13 @@ int main()
796796
tr.test_eq(-2, v[0].a);
797797
tr.test_eq(-4, v[1].a);
798798
}
799+
tr.section("shape_s");
800+
{
801+
ra::Big<int, 1> x = { 99, 99 };
802+
constexpr auto xshas = ra::shape_s<decltype(x)>;
803+
auto xshad = ra::shape(x);
804+
tr.strict().test_eq(ra::iter({ra::ANY}), xshas);
805+
tr.strict().test_eq(ra::iter({2}), xshad);
806+
}
799807
return tr.summary();
800808
}

0 commit comments

Comments
 (0)