Topic: Comments on n3976 (array_view)
Author: Jeremy Maitin-Shepard <jeremy@jeremyms.com>
Date: Fri, 13 Jun 2014 12:17:39 -0700 (PDT)
Raw View
------=_Part_66_30456423.1402687059594
Content-Type: text/plain; charset=UTF-8
C++ is sorely in need of a "vocabulary type" for representing pointer
ranges. It is also sorely in need of a good, standard library for
multidimensional arrays/containers/ranges. While the design space for a
one-dimensional, unstrided array view is fairly limited, the design space
for a multidimensional array/container/range is very large. Finding the
right design certainly involves numerous design iterations and very
substantial user experience. While the proposed design in n3976 is a very
useful starting point, it would be premature to standardize it at this
point, as it is far from comprehensive and it is difficult to know how well
the proposed interface could be extended to provide a larger set of
functionality on par with the facilities available in many other
languages. Some particular issues with the proposed design include:
- No iterators are provided for array_view or strided_array_view, a clear
omission in the interface. For a multidimensional array, there are two
obvious types of iteration that may be desired:
1. iterating over just the first dimension;
2. iterating over a flat view of all of the elements. For a strided
array, iterating over a flat view cannot be done efficiently without
segmented/hierarchical iterators.
Which of these should be the default (i.e. provided through begin() and
end() rather than through some adaptor) is not clear, but the choice should
be consistent with the definition of the size() member, for compatibility
with existing ranges and containers. (1) would be consistent with
operator[]. The proposal has size() returning the total number of
elements, rather than the size of the first dimension, but this is not
necessarily the best choice.
- No data() access member for strided_array_view. This is presumably
omitted because the memory is non-contiguous, but given that
strided_array_view is a thin wrapper, there has to be a convenient way to
get at the underlying memory. Given the definition of Viewable, the use of
the name data() might be problematic as it would allow the incorrect
(albeit explicit) conversion from strided_array_view to array_view.
Possibly Viewable should be traits-based rather than based only on the
presence of data() and size().
- Slicing is limited: it is not possible to take a slice in a dimension
other than the first.
- operator++ and operator-- on index seem very questionable. The semantics
are rather arbitrary and not that likely to be useful except for a single
dimension anyway.
- It is not clear whether it is really useful to have bounds and index be
separate types (though should probably at least be explicitly convertible
to each other). Furthermore, bounds and index essentially represent a
fixed-size discrete vector type, i.e. an augmented interface for
std::array. Arguably the interface of std::array should just be extended
to add component-wise operators instead. Also, a much more comprehensive
set of component-wise operations should be provided. A statically-sized
vector type is sorely needed in C++, but it does not make sense to
standardize these limited, single-purposes types when they could be, and
should be, much more general. Other omissions from index and bounds
include:
1. no data() access to the components
2. no iterators over components for index or bound
3. the iterators for bounds iterate over positions, but are inefficient
without segment/hierarchical iterators. This position iteration is clearly
useful but the facility at present is very limited: it should likely be
presented as a multidimensional range itself, and support a non-zero origin.
Minor issues:
- The array_view(ArrayType) constructor allows any ArrayType for which
is_convertible<add_pointer_t<remove_all_extents_t<ArrayType>>,
pointer>::value. However, this allows conversions between base and derived
types, which is incorrect.
From my perspective, the only way to properly explore this design space for
multidimensional arrays/containers/ranges is through an actively developed
and widely used open source library.
A much more reasonable target for standardization is a one-dimensional
array_view. Since it would just be a thin wrapper over a pointer and a
size or a pair of pointers, with no ownership, there are no obstacles to
interoperability with other types. If a multi-dimensional array view is
introduced later, its one-dimensional version could be implicitly
convertible to and from the existing one-dimensional array_view. An
array_view might likewise be redundant with iterator_range<pointer>, but
this is not a problem since zero-overhead implicit conversions are possible.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_66_30456423.1402687059594
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">C++ is sorely in need of a "vocabulary type" for represent=
ing pointer ranges. It is also sorely in need of a good, standard lib=
rary for multidimensional arrays/containers/ranges. While the design =
space for a one-dimensional, unstrided array view is fairly limited, the de=
sign space for a multidimensional array/container/range is very large. =
; Finding the right design certainly involves numerous design iterations an=
d very substantial user experience. While the proposed design in n397=
6 is a very useful starting point, it would be premature to standardize it =
at this point, as it is far from comprehensive and it is difficult to know =
how well the proposed interface could be extended to provide a larger set o=
f functionality on par with the facilities available in many other language=
s. Some particular issues with the proposed design include:<br><br>- =
No iterators are provided for array_view or strided_array_view, a clear omi=
ssion in the interface. For a multidimensional array, there are two o=
bvious types of iteration that may be desired:<br> 1. iterating over =
just the first dimension;<br> 2. iterating over a flat view of all of=
the elements. For a strided array, iterating over a flat view cannot=
be done efficiently without segmented/hierarchical iterators.<br> Wh=
ich of these should be the default (i.e. provided through begin() and end()=
rather than through some adaptor) is not clear, but the choice should be c=
onsistent with the definition of the size() member, for compatibility with =
existing ranges and containers. (1) would be consistent with operator=
[]. The proposal has size() returning the total number of elements, r=
ather than the size of the first dimension, but this is not necessarily the=
best choice.<br><br>- No data() access member for strided_array_view. =
; This is presumably omitted because the memory is non-contiguous, but give=
n that strided_array_view is a thin wrapper, there has to be a convenient w=
ay to get at the underlying memory. Given the definition of Viewable,=
the use of the name data() might be problematic as it would allow the inco=
rrect (albeit explicit) conversion from strided_array_view to array_view.&n=
bsp; Possibly Viewable should be traits-based rather than based only on the=
presence of data() and size().<br><br>- Slicing is limited: it is not poss=
ible to take a slice in a dimension other than the first.<br><br>- operator=
++ and operator-- on index seem very questionable. The semantics are =
rather arbitrary and not that likely to be useful except for a single dimen=
sion anyway.<br><br>- It is not clear whether it is really useful to have b=
ounds and index be separate types (though should probably at least be expli=
citly convertible to each other). Furthermore, bounds and=
index essentially represent a fixed-size discrete vector type, i.e. an aug=
mented interface for std::array. Arguably the interface of std::array=
should just be extended to add component-wise operators instead. Als=
o, a much more comprehensive set of component-wise operations should be pro=
vided. A statically-sized vector type is sorely needed in C++, but it=
does not make sense to standardize these limited, single-purposes types wh=
en they could be, and should be, much more general. Other omissions f=
rom index and bounds include:<br> 1. no data() access to the component=
s<br> 2. no iterators over components for index or bound<br> 3. t=
he iterators for bounds iterate over positions, but are inefficient without=
segment/hierarchical iterators. This position iteration is clearly u=
seful but the facility at present is very limited: it should likely be pres=
ented as a multidimensional range itself, and support a non-zero origin.<br=
><br>Minor issues:<br>- The array_view(ArrayType) constructor allows any Ar=
rayType for which is_convertible<add_pointer_t<remove_all_extents_t&l=
t;ArrayType>>, pointer>::value. However, this allows convers=
ions between base and derived types, which is incorrect.<br><br>From my per=
spective, the only way to properly explore this design space for multidimen=
sional arrays/containers/ranges is through an actively developed and widely=
used open source library.<br><br>A much more reasonable target for standar=
dization is a one-dimensional array_view. Since it would just be a th=
in wrapper over a pointer and a size or a pair of pointers, with no ownersh=
ip, there are no obstacles to interoperability with other types. If a=
multi-dimensional array view is introduced later, its one-dimensional vers=
ion could be implicitly convertible to and from the existing one-dimensiona=
l array_view. An array_view might likewise be redundant with iterator=
_range<pointer>, but this is not a problem since zero-overhead implic=
it conversions are possible.<br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_66_30456423.1402687059594--
.
Author: Sean Middleditch <sean.middleditch@gmail.com>
Date: Fri, 13 Jun 2014 14:37:49 -0700 (PDT)
Raw View
------=_Part_166_123350.1402695469665
Content-Type: text/plain; charset=UTF-8
On Friday, June 13, 2014 12:17:40 PM UTC-7, Jeremy Maitin-Shepard wrote:
>
> C++ is sorely in need of a "vocabulary type" for representing pointer
> ranges.
>
There's already a Ranges sub group working on this problem, and looking at
even more general cases of ranges than just pairs of iterators/pointers.
http://www.open-std.org/mailman/listinfo/ranges
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_166_123350.1402695469665
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Friday, June 13, 2014 12:17:40 PM UTC-7, Jeremy Maitin-=
Shepard wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"=
>C++ is sorely in need of a "vocabulary type" for representing pointer rang=
es.<br></div></blockquote><div><br></div><div>There's already a Ranges sub =
group working on this problem, and looking at even more general cases of ra=
nges than just pairs of iterators/pointers.</div><div><br></div><div>http:/=
/www.open-std.org/mailman/listinfo/ranges<br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_166_123350.1402695469665--
.
Author: Jeremy Maitin-Shepard <jeremy@jeremyms.com>
Date: Fri, 13 Jun 2014 15:07:27 -0700 (PDT)
Raw View
------=_Part_185_10928948.1402697247860
Content-Type: text/plain; charset=UTF-8
On Friday, June 13, 2014 2:37:50 PM UTC-7, Sean Middleditch wrote:
>
> On Friday, June 13, 2014 12:17:40 PM UTC-7, Jeremy Maitin-Shepard wrote:
>>
>> C++ is sorely in need of a "vocabulary type" for representing pointer
>> ranges.
>>
>
> There's already a Ranges sub group working on this problem, and looking at
> even more general cases of ranges than just pairs of iterators/pointers.
>
> http://www.open-std.org/mailman/listinfo/ranges
>
Sure, but (pointer, size) ranges are an extremely common and important
case, and devising a comprehensive range library that handles all cases is
much harder than handling just the (pointer, size) case. Also, in the
worst case, a one-dimensional array_view type would become redundant after
a range library is standardized, but it wouldn't cause any interoperability
problems, since the types would surely be implicitly convertible.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_185_10928948.1402697247860
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Friday, June 13, 2014 2:37:50 PM UTC-7, Sean Mi=
ddleditch wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"lt=
r">On Friday, June 13, 2014 12:17:40 PM UTC-7, Jeremy Maitin-Shepard wrote:=
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;borde=
r-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr">C++ is sorely in n=
eed of a "vocabulary type" for representing pointer ranges.<br></div></bloc=
kquote><div><br></div><div>There's already a Ranges sub group working on th=
is problem, and looking at even more general cases of ranges than just pair=
s of iterators/pointers.</div><div><br></div><div><a href=3D"http://www.ope=
n-std.org/mailman/listinfo/ranges" target=3D"_blank" onmousedown=3D"this.hr=
ef=3D'http://www.google.com/url?q\75http%3A%2F%2Fwww.open-std.org%2Fmailman=
%2Flistinfo%2Franges\46sa\75D\46sntz\0751\46usg\75AFQjCNH9nJsY_1zetmYeacjye=
AFzsSFBOA';return true;" onclick=3D"this.href=3D'http://www.google.com/url?=
q\75http%3A%2F%2Fwww.open-std.org%2Fmailman%2Flistinfo%2Franges\46sa\75D\46=
sntz\0751\46usg\75AFQjCNH9nJsY_1zetmYeacjyeAFzsSFBOA';return true;">http://=
www.open-std.org/<wbr>mailman/listinfo/ranges</a><br></div></div></blockquo=
te><div><br>Sure, but (pointer, size) ranges are an extremely common and im=
portant case, and devising a comprehensive range library that handles all c=
ases is much harder than handling just the (pointer, size) case. Also=
, in the worst case, a one-dimensional array_view type would become redunda=
nt after a range library is standardized, but it wouldn't cause any interop=
erability problems, since the types would surely be implicitly convertible.=
<br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_185_10928948.1402697247860--
.
Author: Sean Middleditch <sean@middleditch.us>
Date: Fri, 13 Jun 2014 16:56:46 -0700
Raw View
Adding a bunch of cruft that is planned to be obsoleted with an update
right around the corner seems like a waste of time and needless bloat
to the library for no practical gain. It's not even clear that there's
any point in time we'd even need the interim solution: C++14 is done,
no new library additions are going to be made to it, all work going
forward is for C++17, and it's rather likely that the first version of
comprehensive ranges will either be in C++17 or a TS released around
the same time.
On Fri, Jun 13, 2014 at 3:07 PM, Jeremy Maitin-Shepard
<jeremy@jeremyms.com> wrote:
>
>
> On Friday, June 13, 2014 2:37:50 PM UTC-7, Sean Middleditch wrote:
>>
>> On Friday, June 13, 2014 12:17:40 PM UTC-7, Jeremy Maitin-Shepard wrote:
>>>
>>> C++ is sorely in need of a "vocabulary type" for representing pointer
>>> ranges.
>>
>>
>> There's already a Ranges sub group working on this problem, and looking at
>> even more general cases of ranges than just pairs of iterators/pointers.
>>
>> http://www.open-std.org/mailman/listinfo/ranges
>
>
> Sure, but (pointer, size) ranges are an extremely common and important case,
> and devising a comprehensive range library that handles all cases is much
> harder than handling just the (pointer, size) case. Also, in the worst
> case, a one-dimensional array_view type would become redundant after a range
> library is standardized, but it wouldn't cause any interoperability
> problems, since the types would surely be implicitly convertible.
>
> --
>
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/xzb1d5KUxMU/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/.
--
Sean Middleditch
http://seanmiddleditch.com
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.
Author: David Krauss <potswa@gmail.com>
Date: Sat, 14 Jun 2014 08:52:19 +0800
Raw View
--Apple-Mail=_1A546EF8-3BED-46EE-96FD-6D016888B090
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1
On 2014-06-14, at 7:56 AM, Sean Middleditch <sean@middleditch.us> wrote:
> Adding a bunch of cruft that is planned to be obsoleted with an update
> right around the corner seems like a waste of time and needless bloat
> to the library for no practical gain.
A new way to deal with ranges may be nice, but folks aren't suddenly going =
to cease current practices and rewrite all existing code. "Obsolete" is not=
an apt term.
I'll believe ranges are worth changing for when I see them. I doubt the dif=
ference will be so significant. In that case, at best they'll be an equival=
ent, alternative style used by fans of novelty and half of everyone else, a=
nd at worst they'll be shoved down my throat because the rest of the librar=
y is neglected.
Perhaps I'll be won over. But I've written a lot of iterator code and the c=
urrent style never bothered me.
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
--Apple-Mail=_1A546EF8-3BED-46EE-96FD-6D016888B090
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=ISO-8859-1
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dwindows-1252"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-=
mode: space; -webkit-line-break: after-white-space;"><br><div><div>On 2014&=
ndash;06–14, at 7:56 AM, Sean Middleditch <<a href=3D"mailto:sean@=
middleditch.us">sean@middleditch.us</a>> wrote:</div><br class=3D"Apple-=
interchange-newline"><blockquote type=3D"cite"><div style=3D"font-size: 12p=
x; font-style: normal; font-variant: normal; font-weight: normal; letter-sp=
acing: normal; line-height: normal; orphans: auto; text-align: start; text-=
indent: 0px; text-transform: none; white-space: normal; widows: auto; word-=
spacing: 0px; -webkit-text-stroke-width: 0px;">Adding a bunch of cruft that=
is planned to be obsoleted with an update<br>right around the corner seems=
like a waste of time and needless bloat<br>to the library for no practical=
gain.</div></blockquote><div><br></div><div>A new way to deal with ranges =
may be nice, but folks aren’t suddenly going to cease current practic=
es and rewrite all existing code. “Obsolete” is not an apt term=
..</div></div><br><div>I’ll believe ranges are worth changing for when=
I see them. I doubt the difference will be so significant. In that case, a=
t best they’ll be an equivalent, alternative style used by fans of no=
velty and half of everyone else, and at worst they’ll be shoved down =
my throat because the rest of the library is neglected.</div><div><br></div=
><div>Perhaps I’ll be won over. But I’ve written a lot of itera=
tor code and the current style never bothered me.</div><div><br></div></bod=
y></html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--Apple-Mail=_1A546EF8-3BED-46EE-96FD-6D016888B090--
.
Author: "'Jeffrey Yasskin' via ISO C++ Standard - Future Proposals" <std-proposals@isocpp.org>
Date: Sat, 14 Jun 2014 02:53:59 +0200
Raw View
Thanks for the comments. Lukasz, FYI in case you're not on this list.
On Fri, Jun 13, 2014 at 9:17 PM, Jeremy Maitin-Shepard
<jeremy@jeremyms.com> wrote:
> C++ is sorely in need of a "vocabulary type" for representing pointer
> ranges. It is also sorely in need of a good, standard library for
> multidimensional arrays/containers/ranges. While the design space for a
> one-dimensional, unstrided array view is fairly limited, the design space
> for a multidimensional array/container/range is very large. Finding the
> right design certainly involves numerous design iterations and very
> substantial user experience. While the proposed design in n3976 is a very
> useful starting point, it would be premature to standardize it at this
> point, as it is far from comprehensive and it is difficult to know how well
> the proposed interface could be extended to provide a larger set of
> functionality on par with the facilities available in many other languages.
According to N3851,
http://msdn.microsoft.com/en-us/library/vstudio/hh305260(v=vs.110).aspx
seems to be that user experience. We'll also have a chance to get more
experience while this is in a TS before being standardized.
> Some particular issues with the proposed design include:
>
> - No iterators are provided for array_view or strided_array_view, a clear
> omission in the interface. For a multidimensional array, there are two
> obvious types of iteration that may be desired:
> 1. iterating over just the first dimension;
> 2. iterating over a flat view of all of the elements. For a strided
> array, iterating over a flat view cannot be done efficiently without
> segmented/hierarchical iterators.
> Which of these should be the default (i.e. provided through begin() and
> end() rather than through some adaptor) is not clear,
From the Zen of Python, "In the face of ambiguity, refuse the
temptation to guess."
> - No data() access member for strided_array_view. This is presumably
> omitted because the memory is non-contiguous, but given that
> strided_array_view is a thin wrapper, there has to be a convenient way to
> get at the underlying memory.
Why "has to"?
> Given the definition of Viewable, the use of
> the name data() might be problematic as it would allow the incorrect (albeit
> explicit) conversion from strided_array_view to array_view. Possibly
> Viewable should be traits-based rather than based only on the presence of
> data() and size().
The downside of traits, of course, is that we'd burden users with
marking their types. If nearly all existing contiguous types expose
data()/size(), the library can save people work by using them.
> - Slicing is limited: it is not possible to take a slice in a dimension
> other than the first.
I think that's called "section()".
> - operator++ and operator-- on index seem very questionable. The semantics
> are rather arbitrary and not that likely to be useful except for a single
> dimension anyway.
They're marked with "Requires: Rank == 1." This should be more like
"Ill-formed unless ...", but the goal is there.
> - It is not clear whether it is really useful to have bounds and index be
> separate types (though should probably at least be explicitly convertible to
> each other).
It adds a bit of type safety. Adding two bounds, for instance, doesn't
make a lot of sense.
> Furthermore, bounds and index essentially represent a
> fixed-size discrete vector type, i.e. an augmented interface for std::array.
> Arguably the interface of std::array should just be extended to add
> component-wise operators instead. Also, a much more comprehensive set of
> component-wise operations should be provided. A statically-sized vector
> type is sorely needed in C++, but it does not make sense to standardize
> these limited, single-purposes types when they could be, and should be, much
> more general.
We don't necessarily want to go for the most general possible type all at once.
> Other omissions from index and bounds include:
> 1. no data() access to the components
> 2. no iterators over components for index or bound
How are those related to indexing?
> 3. the iterators for bounds iterate over positions, but are inefficient
> without segment/hierarchical iterators.
Show us your measurements when you make an efficiency claim.
> This position iteration is clearly
> useful but the facility at present is very limited: it should likely be
> presented as a multidimensional range itself, and support a non-zero origin.
What's the use case?
> Minor issues:
> - The array_view(ArrayType) constructor allows any ArrayType for which
> is_convertible<add_pointer_t<remove_all_extents_t<ArrayType>>,
> pointer>::value. However, this allows conversions between base and derived
> types, which is incorrect.
+1. This is related to the problems N4042 is fixing.
> From my perspective, the only way to properly explore this design space for
> multidimensional arrays/containers/ranges is through an actively developed
> and widely used open source library.
>
> A much more reasonable target for standardization is a one-dimensional
> array_view. Since it would just be a thin wrapper over a pointer and a size
> or a pair of pointers, with no ownership, there are no obstacles to
> interoperability with other types. If a multi-dimensional array view is
> introduced later, its one-dimensional version could be implicitly
> convertible to and from the existing one-dimensional array_view. An
> array_view might likewise be redundant with iterator_range<pointer>, but
> this is not a problem since zero-overhead implicit conversions are possible.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.
Author: Jeremy Maitin-Shepard <jeremy@jeremyms.com>
Date: Fri, 13 Jun 2014 20:34:18 -0700 (PDT)
Raw View
------=_Part_369_5498767.1402716858172
Content-Type: text/plain; charset=UTF-8
On Friday, June 13, 2014 4:56:47 PM UTC-7, Sean Middleditch wrote:
>
> Adding a bunch of cruft that is planned to be obsoleted with an update
> right around the corner seems like a waste of time and needless bloat
> to the library for no practical gain. It's not even clear that there's
> any point in time we'd even need the interim solution: C++14 is done,
> no new library additions are going to be made to it, all work going
> forward is for C++17, and it's rather likely that the first version of
> comprehensive ranges will either be in C++17 or a TS released around
> the same time.
>
You may be right, that it would be redundant with some range-related
facility, and any array_view proposal should probably be seen as tentative
pending the results of the range group. However, it is clear that a
one-dimensional array view is a facility that should exist, under some
name, in the standard library. The only real questions are:
1. should it be represented as (begin,size) or (begin,end) [doesn't really
matter, and possibly could be implementation-defined even]
2. what to call it
3. what methods/functions should be defined for it
Note also that it benefits from implicit conversions from types like
std::array, std::vector, std::string, etc.
It is also clear that we need an iterator_range type similar to
boost::iterator_range, regardless of what alternate range models may also
exist. (However, it could be useful to allow the begin and end iterators
to optionally have different types.) Therefore, we can be fairly certain
that any range library proposal will include an iterator_range type, and
iterator_range<pointer> would *almost* make a one-dimensional array_view
redundant. The reason I say almost is that iterator_range<T *> might well
not be implicitly constructible from std::vector and std::string, for
instance, if their iterators are not pointers. It would be possible to
allow that as a special case for iterator_range<T *>, but then we are
effectively just defining array_view<T> but giving it the name
iterator_range<T *>.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_369_5498767.1402716858172
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Friday, June 13, 2014 4:56:47 PM UTC-7, Sean Mi=
ddleditch wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin=
-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Adding a bunch=
of cruft that is planned to be obsoleted with an update
<br>right around the corner seems like a waste of time and needless bloat
<br>to the library for no practical gain. It's not even clear that there's
<br>any point in time we'd even need the interim solution: C++14 is done,
<br>no new library additions are going to be made to it, all work going
<br>forward is for C++17, and it's rather likely that the first version of
<br>comprehensive ranges will either be in C++17 or a TS released around
<br>the same time.
<br></blockquote><div><br>You may be right, that it would be redundant with=
some range-related facility, and any array_view proposal should probably b=
e seen as tentative pending the results of the range group. However, =
it is clear that a one-dimensional array view is a facility that should exi=
st, under some name, in the standard library. The only real questions=
are:<br>1. should it be represented as (begin,size) or (begin,end) [doesn'=
t really matter, and possibly could be implementation-defined even]<br>2. w=
hat to call it<br>3. what methods/functions should be defined for it<br><br=
>Note also that it benefits from implicit conversions from types like std::=
array, std::vector, std::string, etc.<br><br>It is also clear that we need =
an iterator_range type similar to boost::iterator_range, regardless of what=
alternate range models may also exist. (However, it could be useful =
to allow the begin and end iterators to optionally have different types.)&n=
bsp; Therefore, we can be fairly certain that any range library proposal wi=
ll include an iterator_range type, and iterator_range<pointer> would =
*almost* make a one-dimensional array_view redundant. The reason I sa=
y almost is that iterator_range<T *> might well not be implicitly con=
structible from std::vector and std::string, for instance, if their iterato=
rs are not pointers. It would be possible to allow that as a special =
case for iterator_range<T *>, but then we are effectively just defini=
ng array_view<T> but giving it the name iterator_range<T *>.<br=
><br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_369_5498767.1402716858172--
.
Author: Jeremy Maitin-Shepard <jeremy@jeremyms.com>
Date: Fri, 13 Jun 2014 21:30:44 -0700 (PDT)
Raw View
------=_Part_470_4479249.1402720245054
Content-Type: text/plain; charset=UTF-8
On Friday, June 13, 2014 5:54:21 PM UTC-7, Jeffrey Yasskin wrote:
>
> Thanks for the comments. Lukasz, FYI in case you're not on this list.
>
> On Fri, Jun 13, 2014 at 9:17 PM, Jeremy Maitin-Shepard
> <jer...@jeremyms.com <javascript:>> wrote:
> > C++ is sorely in need of a "vocabulary type" for representing pointer
> > ranges. It is also sorely in need of a good, standard library for
> > multidimensional arrays/containers/ranges. While the design space for a
> > one-dimensional, unstrided array view is fairly limited, the design
> space
> > for a multidimensional array/container/range is very large. Finding the
> > right design certainly involves numerous design iterations and very
> > substantial user experience. While the proposed design in n3976 is a
> very
> > useful starting point, it would be premature to standardize it at this
> > point, as it is far from comprehensive and it is difficult to know how
> well
> > the proposed interface could be extended to provide a larger set of
> > functionality on par with the facilities available in many other
> languages.
>
> According to N3851,
> http://msdn.microsoft.com/en-us/library/vstudio/hh305260(v=vs.110).aspx
> <http://www.google.com/url?q=http%3A%2F%2Fmsdn.microsoft.com%2Fen-us%2Flibrary%2Fvstudio%2Fhh305260(v%3Dvs.110).aspx&sa=D&sntz=1&usg=AFQjCNGutdo3UFl--fatoQp9kucVYtiHcg>
> seems to be that user experience. We'll also have a chance to get more
> experience while this is in a TS before being standardized.
>
I saw that, but the fact that it is part of AMP suggests that the focus is
a bit more specialized than a general multidimensional array.
> > Some particular issues with the proposed design include:
> >
> > - No iterators are provided for array_view or strided_array_view, a
> clear
> > omission in the interface. For a multidimensional array, there are two
> > obvious types of iteration that may be desired:
> > 1. iterating over just the first dimension;
> > 2. iterating over a flat view of all of the elements. For a strided
> > array, iterating over a flat view cannot be done efficiently without
> > segmented/hierarchical iterators.
> > Which of these should be the default (i.e. provided through begin()
> and
> > end() rather than through some adaptor) is not clear,
>
> From the Zen of Python, "In the face of ambiguity, refuse the
> temptation to guess."
>
> That's true, but no adaptors to provide the functionality unambiguously
are provided either. For the particular case of a one-dimensional array,
there is no ambiguity, and not being able to easily use array_view with
standard algorithms or range-based for is a serious usability issue. This
will only become worse if/when standard algorithm overloads that take
ranges rather than iterator pairs are added.
> - No data() access member for strided_array_view. This is presumably
> > omitted because the memory is non-contiguous, but given that
> > strided_array_view is a thin wrapper, there has to be a convenient way
> to
> > get at the underlying memory.
>
> Why "has to"?
>
Because the user might want to convert the array to another representation
for use by another piece of code/library, e.g. FFTW or Eigen, CUDA memcpy,
etc. Under the proposed interface, for a 3-dimensional stided array view,
you have to use &arr[0][0][0]. This is even worse than having to do
&vec[0] for std::vector, since the same expression cannot be used
independent of the dimensionality.
>
> > Given the definition of Viewable, the use of
> > the name data() might be problematic as it would allow the incorrect
> (albeit
> > explicit) conversion from strided_array_view to array_view. Possibly
> > Viewable should be traits-based rather than based only on the presence
> of
> > data() and size().
>
> The downside of traits, of course, is that we'd burden users with
> marking their types. If nearly all existing contiguous types expose
> data()/size(), the library can save people work by using them.
>
That's a valid point.
>
> > - Slicing is limited: it is not possible to take a slice in a dimension
> > other than the first.
>
> I think that's called "section()".
>
Well, that takes a "section" but does not reduce the dimensionality like
"slice". For instance, suppose I have a two-dimensional 20x10 array arr
and want to do the equivalent of the numpy:
arr[:,5]
and obtain a 1-dimensional strided_array_view of length 20.
Certainly there is a large design space for general subscripting and it
almost certainly requires a fair amount of template metaprogramming, but
this is very useful functionality.
> > - operator++ and operator-- on index seem very questionable. The
> semantics
> > are rather arbitrary and not that likely to be useful except for a
> single
> > dimension anyway.
>
> They're marked with "Requires: Rank == 1." This should be more like
> "Ill-formed unless ...", but the goal is there.
>
Sorry, I missed that requirement. No problem there then.
>
> > - It is not clear whether it is really useful to have bounds and index
> be
> > separate types (though should probably at least be explicitly
> convertible to
> > each other).
>
> It adds a bit of type safety. Adding two bounds, for instance, doesn't
> make a lot of sense.
>
I agree that type safety is in principle useful, but it is impossible to
predict what relationships might hold in any given program, and so there is
the question of whether the safety it adds is worth the cost of having to
explicitly work around it in the cases that it is too restrictive.
Certainly if they are separate types there needs to be a way to
(explicitly) convert. Right now the only way to convert is to write a
manual loop and use operator[], or possibly use operator[] to obtain
pointers and then call memcpy or std::copy.
As a specific example, consider if we want to compute the bounds of a valid
convolution if we have an array x and a filter k. The bounds of the result
are: x.bounds - k.bounds + 1. None of the arithmetic operators defined in
the proposal help me with that; I'd just have to write a loop. Even if the
arithmetic operators weren't limited by the bounds/index distinction, there
would still be no way to create a constant-valued vector, i.e. to handle
the constant 1.
Another related issue I didn't notice before: the only way to construct an
index or bounds type is from an initializer_list. There is no (explicit)
conversion from std::array, for instance. It is quite likely that an index
or bounds value would be computed by some other code, that may use a
different representation.
>
> > Furthermore, bounds and index essentially represent a
> > fixed-size discrete vector type, i.e. an augmented interface for
> std::array.
> > Arguably the interface of std::array should just be extended to add
> > component-wise operators instead. Also, a much more comprehensive set
> of
> > component-wise operations should be provided. A statically-sized vector
> > type is sorely needed in C++, but it does not make sense to standardize
> > these limited, single-purposes types when they could be, and should be,
> much
> > more general.
>
> We don't necessarily want to go for the most general possible type all at
> once.
>
Certainly there is a large design space, but that is a reason to be
cautious about standardizing anything. Given the long turn around time for
revisions to C++, it doesn't make sense to standardize a partial solution;
better to work out a good, complete interface outside the standard. Given
that there is no standard fixed-length vector, users will be tempted to use
index as one, but will quickly find it to be lacking in important
functionality.
> > Other omissions from index and bounds include:
> > 1. no data() access to the components
> > 2. no iterators over components for index or bound
>
> How are those related to indexing?
>
Maybe I want to print out the index, by iterating over the components.
Maybe I want to convert the index to/from another representation using the
raw array representation. An index is just a value in the program, and
there is no way of knowing what operations the user may want to perform on
it. The philosophy of C++ is to not get in the user's way.
>
> > 3. the iterators for bounds iterate over positions, but are inefficient
> > without segment/hierarchical iterators.
>
> Show us your measurements when you make an efficiency claim.
>
Alright, fair enough. Still, it would be nice to be able to generate code
equivalent to N nested for loops for an N dimensional bounds.
> > This position iteration is clearly
> > useful but the facility at present is very limited: it should likely be
> > presented as a multidimensional range itself, and support a non-zero
> origin.
>
> What's the use case?
This is useful in conjunction with a multdimensional, multiple range
for_each. Suppose we have two multidimensional arrays x_array and y_array
with the same bounds. We then might want:
for_each(x_array, y_array, [&](auto &x, auto &y) { x += y; });
However, we might also want:
for_each(x_array, y_array, x_array.bounds(), [&](auto &x, auto &y, auto
pos) {
if (x != y) std::cout << "mismatch at position " << pos << std::endl;
});
This could also be further improved by the use of macros or a language
extension that allows x and x_array, y and y_array, x_array.bounds() and
pos to be syntactically related.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_470_4479249.1402720245054
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Friday, June 13, 2014 5:54:21 PM UTC-7, Jeffrey=
Yasskin wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-=
left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Thanks for the =
comments. Lukasz, FYI in case you're not on this list.
<br>
<br>On Fri, Jun 13, 2014 at 9:17 PM, Jeremy Maitin-Shepard
<br><<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"=
1fw1SKZdvtgJ" onmousedown=3D"this.href=3D'javascript:';return true;" onclic=
k=3D"this.href=3D'javascript:';return true;">jer...@jeremyms.com</a>> wr=
ote:
<br>> C++ is sorely in need of a "vocabulary type" for representing poin=
ter
<br>> ranges. It is also sorely in need of a good, standard librar=
y for
<br>> multidimensional arrays/containers/ranges. While the design =
space for a
<br>> one-dimensional, unstrided array view is fairly limited, the desig=
n space
<br>> for a multidimensional array/container/range is very large. =
Finding the
<br>> right design certainly involves numerous design iterations and ver=
y
<br>> substantial user experience. While the proposed design in n3=
976 is a very
<br>> useful starting point, it would be premature to standardize it at =
this
<br>> point, as it is far from comprehensive and it is difficult to know=
how well
<br>> the proposed interface could be extended to provide a larger set o=
f
<br>> functionality on par with the facilities available in many other l=
anguages.
<br>
<br>According to N3851,
<br><a href=3D"http://www.google.com/url?q=3Dhttp%3A%2F%2Fmsdn.microsoft.co=
m%2Fen-us%2Flibrary%2Fvstudio%2Fhh305260(v%3Dvs.110).aspx&sa=3DD&sn=
tz=3D1&usg=3DAFQjCNGutdo3UFl--fatoQp9kucVYtiHcg" target=3D"_blank" onmo=
usedown=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fmsdn.mic=
rosoft.com%2Fen-us%2Flibrary%2Fvstudio%2Fhh305260(v%3Dvs.110).aspx\46sa\75D=
\46sntz\0751\46usg\75AFQjCNGutdo3UFl--fatoQp9kucVYtiHcg';return true;" oncl=
ick=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fmsdn.microso=
ft.com%2Fen-us%2Flibrary%2Fvstudio%2Fhh305260(v%3Dvs.110).aspx\46sa\75D\46s=
ntz\0751\46usg\75AFQjCNGutdo3UFl--fatoQp9kucVYtiHcg';return true;">http://m=
sdn.microsoft.com/en-<wbr>us/library/vstudio/hh305260(v=3D<wbr>vs.110).aspx=
</a>
<br>seems to be that user experience. We'll also have a chance to get more
<br>experience while this is in a TS before being standardized.
<br></blockquote><div><br>I saw that, but the fact that it is part of AMP s=
uggests that the focus is a bit more specialized than a general multidimens=
ional array.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>> Some particular issues with the proposed design include:
<br>>
<br>> - No iterators are provided for array_view or strided_array_view, =
a clear
<br>> omission in the interface. For a multidimensional array, the=
re are two
<br>> obvious types of iteration that may be desired:
<br>> 1. iterating over just the first dimension;
<br>> 2. iterating over a flat view of all of the elements.  =
;For a strided
<br>> array, iterating over a flat view cannot be done efficiently witho=
ut
<br>> segmented/hierarchical iterators.
<br>> Which of these should be the default (i.e. provided through=
begin() and
<br>> end() rather than through some adaptor) is not clear,
<br>
<br>From the Zen of Python, "In the face of ambiguity, refuse the
<br>temptation to guess."
<br>
<br></blockquote><div>That's true, but no adaptors to provide the functiona=
lity unambiguously are provided either. For the particular case of a =
one-dimensional array, there is no ambiguity, and not being able to easily =
use array_view with standard algorithms or range-based for is a serious usa=
bility issue. This will only become worse if/when standard algorithm =
overloads that take ranges rather than iterator pairs are added.<br><br></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;">> - No data() access mem=
ber for strided_array_view. This is presumably
<br>> omitted because the memory is non-contiguous, but given that
<br>> strided_array_view is a thin wrapper, there has to be a convenient=
way to
<br>> get at the underlying memory.
<br>
<br>Why "has to"?
<br></blockquote><div><br>Because the user might want to convert the array =
to another representation for use by another piece of code/library, e.g. FF=
TW or Eigen, CUDA memcpy, etc. Under the proposed interface, for a 3-=
dimensional stided array view, you have to use &arr[0][0][0]. Thi=
s is even worse than having to do &vec[0] for std::vector, since the sa=
me expression cannot be used independent of the dimensionality.<br> </=
div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>> Given the definition of Viewable, the use of
<br>> the name data() might be problematic as it would allow the incorre=
ct (albeit
<br>> explicit) conversion from strided_array_view to array_view. =
Possibly
<br>> Viewable should be traits-based rather than based only on the pres=
ence of
<br>> data() and size().
<br>
<br>The downside of traits, of course, is that we'd burden users with
<br>marking their types. If nearly all existing contiguous types expose
<br>data()/size(), the library can save people work by using them.<br></blo=
ckquote><div><br>That's a valid point.<br> </div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;">
<br>> - Slicing is limited: it is not possible to take a slice in a dime=
nsion
<br>> other than the first.
<br>
<br>I think that's called "section()".
<br></blockquote><div><br>Well, that takes a "section" but does not reduce =
the dimensionality like "slice". For instance, suppose I have a two-d=
imensional 20x10 array arr and want to do the equivalent of the numpy:<br><=
br>arr[:,5]<br> <br>and obtain a 1-dimensional strided_array_view of l=
ength 20.<br><br>Certainly there is a large design space for general subscr=
ipting and it almost certainly requires a fair amount of template metaprogr=
amming, but this is very useful functionality.<br><br></div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #=
ccc solid;padding-left: 1ex;">
<br>> - operator++ and operator-- on index seem very questionable.  =
;The semantics
<br>> are rather arbitrary and not that likely to be useful except for a=
single
<br>> dimension anyway.
<br>
<br>They're marked with "Requires: Rank =3D=3D 1." This should be more like
<br>"Ill-formed unless ...", but the goal is there.
<br></blockquote><div>Sorry, I missed that requirement. No problem th=
ere then.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>> - It is not clear whether it is really useful to have bounds and i=
ndex be
<br>> separate types (though should probably at least be explicitly conv=
ertible to
<br>> each other).
<br>
<br>It adds a bit of type safety. Adding two bounds, for instance, doesn't
<br>make a lot of sense.
<br></blockquote><div>I agree that type safety is in principle useful, but =
it is impossible to predict what relationships might hold in any given prog=
ram, and so there is the question of whether the safety it adds is worth th=
e cost of having to explicitly work around it in the cases that it is too r=
estrictive. Certainly if they are separate types there needs to be a =
way to (explicitly) convert. Right now the only way to convert is to =
write a manual loop and use operator[], or possibly use operator[] to obtai=
n pointers and then call memcpy or std::copy.<br><br>As a specific example,=
consider if we want to compute the bounds of a valid convolution if we hav=
e an array x and a filter k. The bounds of the result are: x.bounds -=
k.bounds + 1. None of the arithmetic operators defined in the propos=
al help me with that; I'd just have to write a loop. Even if the arit=
hmetic operators weren't limited by the bounds/index distinction, there wou=
ld still be no way to create a constant-valued vector, i.e. to handle the c=
onstant 1.<br><br>Another related issue I didn't notice before: the only wa=
y to construct an index or bounds type is from an initializer_list. T=
here is no (explicit) conversion from std::array, for instance. It is=
quite likely that an index or bounds value would be computed by some other=
code, that may use a different representation.<br></div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;">
<br>> Furthermore, bounds and index essentially represent a
<br>> fixed-size discrete vector type, i.e. an augmented interface for s=
td::array.
<br>> Arguably the interface of std::array should just be extended to ad=
d
<br>> component-wise operators instead. Also, a much more comprehe=
nsive set of
<br>> component-wise operations should be provided. A statically-s=
ized vector
<br>> type is sorely needed in C++, but it does not make sense to standa=
rdize
<br>> these limited, single-purposes types when they could be, and shoul=
d be, much
<br>> more general.
<br>
<br>We don't necessarily want to go for the most general possible type all =
at once.
<br></blockquote><div><br>Certainly there is a large design space, but that=
is a reason to be cautious about standardizing anything. Given the l=
ong turn around time for revisions to C++, it doesn't make sense to standar=
dize a partial solution; better to work out a good, complete interface outs=
ide the standard. Given that there is no standard fixed-length vector=
, users will be tempted to use index as one, but will quickly find it to be=
lacking in important functionality.<br></div><div> </div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;">> Other omissions from index and bounds=
include:
<br>> 1. no data() access to the components
<br>> 2. no iterators over components for index or bound
<br>
<br>How are those related to indexing?
<br></blockquote><div><br>Maybe I want to print out the index, by iterating=
over the components. Maybe I want to convert the index to/from anoth=
er representation using the raw array representation. An index is jus=
t a value in the program, and there is no way of knowing what operations th=
e user may want to perform on it. The philosophy of C++ is to not get=
in the user's way.<br> </div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;">
<br>> 3. the iterators for bounds iterate over positions, but are =
inefficient
<br>> without segment/hierarchical iterators.
<br>
<br>Show us your measurements when you make an efficiency claim.
<br></blockquote><div><br>Alright, fair enough. Still, it would be ni=
ce to be able to generate code equivalent to N nested for loops for an N di=
mensional bounds. <br></div><div><br> </div><blockquote class=3D"gmail=
_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;p=
adding-left: 1ex;">> This position iteration is clearly
<br>> useful but the facility at present is very limited: it should like=
ly be
<br>> presented as a multidimensional range itself, and support a non-ze=
ro origin.
<br>
<br>What's the use case?</blockquote><div><br>This is useful in conjunction=
with a multdimensional, multiple range for_each. Suppose we have two=
multidimensional arrays x_array and y_array with the same bounds. We=
then might want:<br>for_each(x_array, y_array, [&](auto &x, auto &=
amp;y) { x +=3D y; });<br><br>However, we might also want:<br><br>for_each(=
x_array, y_array, x_array.bounds(), [&](auto &x, auto &y, auto =
pos) {<br> if (x !=3D y) std::cout << "mismatch at position " &=
lt;< pos << std::endl;<br>});<br> <br>This could also be furt=
her improved by the use of macros or a language extension that allows x and=
x_array, y and y_array, x_array.bounds() and pos to be syntactically relat=
ed.<br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_470_4479249.1402720245054--
.
Author: Sean Middleditch <sean@middleditch.us>
Date: Sat, 14 Jun 2014 02:06:10 -0700
Raw View
On Fri, Jun 13, 2014 at 8:34 PM, Jeremy Maitin-Shepard
<jeremy@jeremyms.com> wrote:
> You may be right, that it would be redundant with some range-related
> facility, and any array_view proposal should probably be seen as tentative
> pending the results of the range group. However, it is clear that a
> one-dimensional array view is a facility that should exist, under some name,
> in the standard library. The only real questions are:
Is it? I perhaps am interpreting "array view" fairly narrowly, but is
it really needed as a distinct concept/type from ranges of iterators?
Concrete reasons?
> 1. should it be represented as (begin,size) or (begin,end) [doesn't really
> matter, and possibly could be implementation-defined even]
The latter case seems far better suited since then the type could be
used for any pair of iterators. Why make a type that works just for
contiguous arrays when it could also work for vector, deque, list,
map, and so on? Specializations for ranges over random-access
iterators can of course offer improved performance or small
functionality improvements compared to ranges over other iterator
categories, just like they do for iterators today.
> 2. what to call it
This is a very minor detail that is dependent on several other factors
that are hardly set in stone.
> 3. what methods/functions should be defined for it
Again, this is almost implicit in a range of iterators. The operations
permitted are those allowed on the specified iterator type. If the
iterator is random access, you get - and [] among others. If it's a
forward iterator you get ++. The operations could be in cases renamed
to pop_front, pop_back, at, etc. but those details are relatively
unimportant.
> Note also that it benefits from implicit conversions from types like
> std::array, std::vector, std::string, etc.
That's not at all a given. I for one do not want implicit conversions.
Explicit is good.
> It is also clear that we need an iterator_range type similar to
> boost::iterator_range, regardless of what alternate range models may also
> exist. (However, it could be useful to allow the begin and end iterators to
> optionally have different types.) Therefore, we can be fairly certain that
Eric Niebler has a great series of blog posts on this topic which you
should read. There's also been plenty of discussion at the mailing
list I linked earlier.
> allow that as a special case for iterator_range<T *>, but then we are
Or add conversion operators to vector and string. Or use an adaptor
function instead of implicit conversions, which you need anyway since
certain generic algorithms really want to operate on cheap-to-copy
ranges and not on containers.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
.
Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sat, 14 Jun 2014 03:35:35 -0700 (PDT)
Raw View
------=_Part_48_11403427.1402742135919
Content-Type: text/plain; charset=UTF-8
I would like array_view to cater for the case that one or more dimensions
is fixed size. This can improve performance by a lot and also provies
additional documentation value for functions requiring its data to actually
have a certain bound in a particular dimension. I think that the bounds
representation used by Eigen could work for array_view too:
static const size_t var_dim = -1;
template<typename T, size_t... Ss> class array_view;
The interpretation of this being that for a n dimensional array_view you
mention n sizes as template parameters, any of which may be the marker
value var_dim which indicates a variable dimension and activates a
specialization of the template.
I have suggested this system as an extension of the current array<>
template to n dimensions previously, see thread
https://groups.google.com/a/isocpp.org/forum/#!topicsearch/bengt$20gustafsson/std-proposals/hW2QAvmboqU.
As easily seen the current one dimensional, fixed size case fits nicely
under this umbrella. The idea was that the variable size specializations of
array<> would use a new VLA feature whenever that enters C++. but use the
heap in the meantime.
Part of the motivation for this upgrade of array was that the std::
namespace is becoming quite cluttered with different "array like" data
types, we already have vector, valarray and array and were very close to
getting a dynarray recently...and then we still don't have a proper 2 or
n-d matrix type.
The same reasoning applies to range/view type of classes where there are
numerous such non-owning classes being suggested: string_view, array_view,
iterator_range etc. If we could restrain ourselves to one or two of these I
think this would be a great benefit in the future.
array_views with fixed bounds in some dimensions would be (implcitly,
anynoe?) convertible to array_views with more variable dimensions. This
caters for the case where a non-templated function taking a variable size
array_view is called with a fixed size view that maybe was previsouly used
to call a template function (making use of teh fixed dimensions).
Another comment would be that maybe we could get rid of the
strided_array_view variant by tagging one or none dimensions as the "unit
stride" dimension (typically but not always the last). So far I haven't
figured out how to do this with the "some fixed dimensions" idea I
presented myself but for the original proposal it would be quite simple to
add another template parameter denoting the unit stride dimension or -1 for
none, defaulting to -1 creating a strided_array_view by default, or maybe
to 0 for the current behaviour, altough this limits the set of data
structures that can be passed to a function with a "naive" parameter type.
The lack of a (mathematical) vector type with suitable operations could
possibly be solved by applying the above var_dim possibility to valarray:
template<typename T, size_t Sz> class valarray;
template<typename T> class valarray<T. var_dim>; // The current valarray
is the specialization for var_dim.
valarray provides memberwise operations as well as operations to one scalar
T already. More math stuff can be added as functions of course: dot
product, length or whatever.
I would also prefer if there were specializations for 2 and 3 dimensions
where the elements are named x, y and z (for instance using a union with
the array).
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_48_11403427.1402742135919
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><span style=3D"font-size: 13px;">I would like array_v=
iew to cater for the case that one or more dimensions is fixed size. This c=
an improve performance by a lot and also provies additional documentation v=
alue for functions requiring its data to actually have a certain bound in a=
particular dimension. I think that the bounds representation used by=
Eigen could work for array_view too:</span><br></div><div><span style=3D"f=
ont-size: 13px;"><br></span></div><div>static const size_t var_dim =3D -1;<=
/div><div>template<typename T, size_t... Ss> class array_view;</div><=
div><br></div><div>The interpretation of this being that for a n dimensiona=
l array_view you mention n sizes as template parameters, any of which may b=
e the marker value var_dim which indicates a variable dimension and activat=
es a specialization of the template.</div><div><br></div><div>I have sugges=
ted this system as an extension of the current array<> template to n =
dimensions previously, see thread <a href=3D"https://groups.google.com/a/is=
ocpp.org/forum/#!topicsearch/bengt$20gustafsson/std-proposals/hW2QAvmboqU">=
https://groups.google.com/a/isocpp.org/forum/#!topicsearch/bengt$20gustafss=
on/std-proposals/hW2QAvmboqU</a>. As easily seen the current one dimensiona=
l, fixed size case fits nicely under this umbrella. The idea was that the v=
ariable size specializations of array<> would use a new VLA feature w=
henever that enters C++. but use the heap in the meantime.</div><div><br></=
div><div>Part of the motivation for this upgrade of array was that the std:=
: namespace is becoming quite cluttered with different "array like" data ty=
pes, we already have vector, valarray and array and were very close to gett=
ing a dynarray recently...and then we still don't have a proper 2 or n-d ma=
trix type.</div><div><br></div><div>The same reasoning applies to range/vie=
w type of classes where there are numerous such non-owning classes being su=
ggested: string_view, array_view, iterator_range etc. If we could restrain =
ourselves to one or two of these I think this would be a great benefit in t=
he future.</div><div><br></div><div>array_views with fixed bounds in some d=
imensions would be (implcitly, anynoe?) convertible to array_views with mor=
e variable dimensions. This caters for the case where a non-templated funct=
ion taking a variable size array_view is called with a fixed size view that=
maybe was previsouly used to call a template function (making use of teh f=
ixed dimensions).</div><div><br></div><div>Another comment would be that ma=
ybe we could get rid of the strided_array_view variant by tagging one or no=
ne dimensions as the "unit stride" dimension (typically but not always the =
last). So far I haven't figured out how to do this with the "some fixed dim=
ensions" idea I presented myself but for the original proposal it would be =
quite simple to add another template parameter denoting the unit stride dim=
ension or -1 for none, defaulting to -1 creating a strided_array_view by de=
fault, or maybe to 0 for the current behaviour, altough this limits the set=
of data structures that can be passed to a function with a "naive" paramet=
er type.</div><div><br></div><div>The lack of a (mathematical) vector type =
with suitable operations could possibly be solved by applying the above var=
_dim possibility to valarray:</div><div><br></div><div>template<typename=
T, size_t Sz> class valarray;</div><div><br></div><div>template<type=
name T> class valarray<T. var_dim>; // The current valarray =
is the specialization for var_dim.</div><div><br></div><div>valarray provid=
es memberwise operations as well as operations to one scalar T already. Mor=
e math stuff can be added as functions of course: dot product, length or wh=
atever.</div><div><br></div><div>I would also prefer if there were speciali=
zations for 2 and 3 dimensions where the elements are named x, y and z (for=
instance using a union with the array).</div><div><br></div><div><br></div=
><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div=
></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_48_11403427.1402742135919--
.
Author: Jeremy Maitin-Shepard <jeremy@jeremyms.com>
Date: Sat, 14 Jun 2014 10:29:26 -0700 (PDT)
Raw View
------=_Part_833_17626815.1402766966662
Content-Type: text/plain; charset=UTF-8
On Saturday, June 14, 2014 2:06:12 AM UTC-7, Sean Middleditch wrote:
>
> On Fri, Jun 13, 2014 at 8:34 PM, Jeremy Maitin-Shepard
> <jer...@jeremyms.com <javascript:>> wrote:
> > You may be right, that it would be redundant with some range-related
> > facility, and any array_view proposal should probably be seen as
> tentative
> > pending the results of the range group. However, it is clear that a
> > one-dimensional array view is a facility that should exist, under some
> name,
> > in the standard library. The only real questions are:
>
> Is it? I perhaps am interpreting "array view" fairly narrowly, but is
> it really needed as a distinct concept/type from ranges of iterators?
> Concrete reasons?
>
The only way it is special, as far as I am concerned, is the implicit
conversions. It needs to have a name, rather than just be a concept, so
that it can be used in non-template interfaces. It could just use the same
name as iterator_range but have the implicit conversions added when the
iterator is a pointer. It does seem there is a higher risk of these
implicit conversions causing problems in generic code than if they were
only present on a separate array_view type. I don't have any specific
issue in mind, though.
>
> > 1. should it be represented as (begin,size) or (begin,end) [doesn't
> really
> > matter, and possibly could be implementation-defined even]
>
> The latter case seems far better suited since then the type could be
> used for any pair of iterators. Why make a type that works just for
> contiguous arrays when it could also work for vector, deque, list,
> map, and so on? Specializations for ranges over random-access
> iterators can of course offer improved performance or small
> functionality improvements compared to ranges over other iterator
> categories, just like they do for iterators today.
>
> > 2. what to call it
>
> This is a very minor detail that is dependent on several other factors
> that are hardly set in stone.
I agree.
>
>
> > 3. what methods/functions should be defined for it
>
> Again, this is almost implicit in a range of iterators. The operations
> permitted are those allowed on the specified iterator type. If the
> iterator is random access, you get - and [] among others. If it's a
> forward iterator you get ++. The operations could be in cases renamed
> to pop_front, pop_back, at, etc. but those details are relatively
> unimportant.
>
I agree.
>
> > Note also that it benefits from implicit conversions from types like
> > std::array, std::vector, std::string, etc.
>
> That's not at all a given. I for one do not want implicit conversions.
> Explicit is good.
>
I agree with you in general. However, this doesn't seem to be the general
sentiment for string_view, and it is useful for array_view for the same
reasons as string_view. Most notably, so that it can be conveniently used
as a function parameter type. In that case it really would be no more
dangerous than a reference type.
As you say below, the same can be achieved by adding the conversions to the
source types instead, except for builtin arrays. The one downside is that
it is impossible to gain user experience with the facility as a pure
extension library, e.g. in boost, since the conversions would require
modifying existing standard library components. Also, given the special
case for builtin arrays, it seems you might as well special case some other
standard library types.
> > It is also clear that we need an iterator_range type similar to
> > boost::iterator_range, regardless of what alternate range models may
> also
> > exist. (However, it could be useful to allow the begin and end
> iterators to
> > optionally have different types.) Therefore, we can be fairly certain
> that
>
> Eric Niebler has a great series of blog posts on this topic which you
> should read. There's also been plenty of discussion at the mailing
> list I linked earlier.
>
I did read his blog posts previously. I don't recall them contradicting
the utility of a basic iterator_range type.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_833_17626815.1402766966662
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Saturday, June 14, 2014 2:06:12 AM UTC-7, Sean Middledi=
tch wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On Fri, Jun 13, 2014=
at 8:34 PM, Jeremy Maitin-Shepard
<br><<a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"=
4ed9U-kd_wgJ" onmousedown=3D"this.href=3D'javascript:';return true;" onclic=
k=3D"this.href=3D'javascript:';return true;">jer...@jeremyms.com</a>> wr=
ote:
<br>> You may be right, that it would be redundant with some range-relat=
ed
<br>> facility, and any array_view proposal should probably be seen as t=
entative
<br>> pending the results of the range group. However, it is clear=
that a
<br>> one-dimensional array view is a facility that should exist, under =
some name,
<br>> in the standard library. The only real questions are:
<br>
<br>Is it? I perhaps am interpreting "array view" fairly narrowly, but is
<br>it really needed as a distinct concept/type from ranges of iterators?
<br>Concrete reasons?<br></blockquote><div>The only way it is special, as f=
ar as I am concerned, is the implicit conversions. It needs to have a=
name, rather than just be a concept, so that it can be used in non-templat=
e interfaces. It could just use the same name as iterator_range but h=
ave the implicit conversions added when the iterator is a pointer. It=
does seem there is a higher risk of these implicit conversions causing pro=
blems in generic code than if they were only present on a separate array_vi=
ew type. I don't have any specific issue in mind, though.<br> </=
div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>> 1. should it be represented as (begin,size) or (begin,end) [doesn'=
t really
<br>> matter, and possibly could be implementation-defined even]
<br>
<br>The latter case seems far better suited since then the type could be
<br>used for any pair of iterators. Why make a type that works just for
<br>contiguous arrays when it could also work for vector, deque, list,
<br>map, and so on? Specializations for ranges over random-access
<br>iterators can of course offer improved performance or small
<br>functionality improvements compared to ranges over other iterator
<br>categories, just like they do for iterators today.
<br>
<br>> 2. what to call it
<br>
<br>This is a very minor detail that is dependent on several other factors
<br>that are hardly set in stone.</blockquote><div>I agree. <br></div><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;">
<br>
<br>> 3. what methods/functions should be defined for it
<br>
<br>Again, this is almost implicit in a range of iterators. The operations
<br>permitted are those allowed on the specified iterator type. If the
<br>iterator is random access, you get - and [] among others. If it's a
<br>forward iterator you get ++. The operations could be in cases renamed
<br>to pop_front, pop_back, at, etc. but those details are relatively
<br>unimportant.
<br></blockquote><div>I agree. <br></div><blockquote class=3D"gmail_quote" =
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-l=
eft: 1ex;">
<br>> Note also that it benefits from implicit conversions from types li=
ke
<br>> std::array, std::vector, std::string, etc.
<br>
<br>That's not at all a given. I for one do not want implicit conversions.
<br>Explicit is good.
<br></blockquote><div>I agree with you in general. However, this does=
n't seem to be the general sentiment for string_view, and it is useful for =
array_view for the same reasons as string_view. Most notably, so that=
it can be conveniently used as a function parameter type. In that ca=
se it really would be no more dangerous than a reference type.<br><br>As yo=
u say below, the same can be achieved by adding the conversions to the sour=
ce types instead, except for builtin arrays. The one downside is that=
it is impossible to gain user experience with the facility as a pure exten=
sion library, e.g. in boost, since the conversions would require modifying =
existing standard library components. Also, given the special case fo=
r builtin arrays, it seems you might as well special case some other standa=
rd library types.<br><br></div><blockquote class=3D"gmail_quote" style=3D"m=
argin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"=
>
<br>> It is also clear that we need an iterator_range type similar to
<br>> boost::iterator_range, regardless of what alternate range models m=
ay also
<br>> exist. (However, it could be useful to allow the begin and e=
nd iterators to
<br>> optionally have different types.) Therefore, we can be fairl=
y certain that
<br>
<br>Eric Niebler has a great series of blog posts on this topic which you
<br>should read. There's also been plenty of discussion at the mailing
<br>list I linked earlier.
<br></blockquote><div><br>I did read his blog posts previously. I don=
't recall them contradicting the utility of a basic iterator_range type.</d=
iv><br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_833_17626815.1402766966662--
.
Author: Jeremy Maitin-Shepard <jeremy@jeremyms.com>
Date: Sat, 14 Jun 2014 11:11:06 -0700 (PDT)
Raw View
------=_Part_928_22262662.1402769466742
Content-Type: text/plain; charset=UTF-8
On Saturday, June 14, 2014 3:35:35 AM UTC-7, Bengt Gustafsson wrote:
>
> I would like array_view to cater for the case that one or more dimensions
> is fixed size. This can improve performance by a lot and also provies
> additional documentation value for functions requiring its data to actually
> have a certain bound in a particular dimension. I think that the bounds
> representation used by Eigen could work for array_view too:
>
> static const size_t var_dim = -1;
> template<typename T, size_t... Ss> class array_view;
>
> The interpretation of this being that for a n dimensional array_view you
> mention n sizes as template parameters, any of which may be the marker
> value var_dim which indicates a variable dimension and activates a
> specialization of the template.
>
I agree that it is certainly useful to be able to specify information about
sizes and strides (as you describe later in the message) at compile time.
Potentially it is also useful to specify information about alignment, or
the fact that a size or stride is a multiple of some compile time constant,
etc.
At least if it is the last dimension that is statically sized, you can work
around it by just making it array_view<std::array<T,X>,1>, and you could
provide convenient ways to convert to and from array_view<T,2>. This is
also the case that may be the most useful in terms of optimization.
There is no problem in principle with allowing all of this compile-time
specification, it is just a matter of figuring out the right model for
representing all of it, and figure out a suitable syntax for specifying it
all. The best way to do that is to implement it as a library and see how
things work out.
It might not (probably won't) be possible to stuff all of this
functionality into a single template argument list that is also convenient
for the simple cases, but that isn't a problem given that we have template
aliases. It is, for instance, more convenient to be able to type
MultiDimensionalArray<int,3> rather than
MultiDimensionalArray<int,-1,-1,-1>.
I have suggested this system as an extension of the current array<>
> template to n dimensions previously, see thread
> https://groups.google.com/a/isocpp.org/forum/#!topicsearch/bengt$20gustafsson/std-proposals/hW2QAvmboqU.
> As easily seen the current one dimensional, fixed size case fits nicely
> under this umbrella. The idea was that the variable size specializations of
> array<> would use a new VLA feature whenever that enters C++. but use the
> heap in the meantime.
>
I think something like that should wait until runtime-sized structs are
supported. Otherwise the heap allocation makes it non-POD.
> The lack of a (mathematical) vector type with suitable operations could
> possibly be solved by applying the above var_dim possibility to valarray:
>
> template<typename T, size_t Sz> class valarray;
>
> template<typename T> class valarray<T. var_dim>; // The current valarray
> is the specialization for var_dim.
>
> valarray provides memberwise operations as well as operations to one
> scalar T already. More math stuff can be added as functions of course: dot
> product, length or whatever.
>
I don't know if changing the template argument list of valarray would pose
compatibility problems. There is also the fact that valarray is allowed to
use expression templates, which is probably undesirable for fixed-size
types. In general a fixed-size valarray is a very useful addition, though;
it would probably get used more than the current variable-sized valarray,
which as far as I understand is hardly ever used. Note that the valarray
could be multidimensional as well.
> I would also prefer if there were specializations for 2 and 3 dimensions
> where the elements are named x, y and z (for instance using a union with
> the array).
>
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_928_22262662.1402769466742
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Saturday, June 14, 2014 3:35:35 AM UTC-7, Bengt Gustafs=
son wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><di=
v><span style=3D"font-size:13px">I would like array_view to cater for the c=
ase that one or more dimensions is fixed size. This can improve performance=
by a lot and also provies additional documentation value for functions req=
uiring its data to actually have a certain bound in a particular dimension.=
I think that the bounds representation used by Eigen could work for =
array_view too:</span><br></div><div><span style=3D"font-size:13px"><br></s=
pan></div><div>static const size_t var_dim =3D -1;</div><div>template<ty=
pename T, size_t... Ss> class array_view;</div><div><br></div><div>The i=
nterpretation of this being that for a n dimensional array_view you mention=
n sizes as template parameters, any of which may be the marker value var_d=
im which indicates a variable dimension and activates a specialization of t=
he template.</div></div></blockquote><div><br>I agree that it is certainly =
useful to be able to specify information about sizes and strides (as you de=
scribe later in the message) at compile time. Potentially it is also =
useful to specify information about alignment, or the fact that a size or s=
tride is a multiple of some compile time constant, etc.<br><br>At least if =
it is the last dimension that is statically sized, you can=20
work around it by just making it=20
array_view<std::array<T,X>,1>, and you could provide=20
convenient ways to convert to and from array_view<T,2>. This is=
=20
also the case that may be the most useful in terms of optimization.<br><br>=
There
is no problem in principle with allowing all of this compile-time=20
specification, it is just a matter of figuring out the right model for=20
representing all of it, and figure out a suitable syntax for specifying=20
it all. The best way to do that is to implement it as a library and s=
ee
how things work out.<br><br>It might not (probably won't) be possible=20
to stuff all of this functionality into a single template argument list=20
that is also convenient for the simple cases, but that isn't a problem=20
given that we have template aliases. It is, for instance, more=20
convenient to be able to type MultiDimensionalArray<int,3> rather=20
than MultiDimensionalArray<int,-1,-1,-1>.<br><br></div><div><br></div=
><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bo=
rder-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div>I have =
suggested this system as an extension of the current array<> template=
to n dimensions previously, see thread <a href=3D"https://groups.google.co=
m/a/isocpp.org/forum/#!topicsearch/bengt$20gustafsson/std-proposals/hW2QAvm=
boqU" target=3D"_blank" onmousedown=3D"this.href=3D'https://groups.google.c=
om/a/isocpp.org/forum/#!topicsearch/bengt$20gustafsson/std-proposals/hW2QAv=
mboqU';return true;" onclick=3D"this.href=3D'https://groups.google.com/a/is=
ocpp.org/forum/#!topicsearch/bengt$20gustafsson/std-proposals/hW2QAvmboqU';=
return true;">https://groups.google.com/a/<wbr>isocpp.org/forum/#!<wbr>topi=
csearch/bengt$<wbr>20gustafsson/std-proposals/<wbr>hW2QAvmboqU</a>. As easi=
ly seen the current one dimensional, fixed size case fits nicely under this=
umbrella. The idea was that the variable size specializations of array<=
> would use a new VLA feature whenever that enters C++. but use the heap=
in the meantime.</div></div></blockquote><div><br>I think something like t=
hat should wait until runtime-sized structs are=20
supported. Otherwise the heap allocation makes it non-POD. <br></div>=
<div> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"l=
tr"><div>The lack of a (mathematical) vector type with suitable operations =
could possibly be solved by applying the above var_dim possibility to valar=
ray:</div><div><br></div><div>template<typename T, size_t Sz> class v=
alarray;</div><div><br></div><div>template<typename T> class valarray=
<T. var_dim>; // The current valarray is the specialization for=
var_dim.</div><div><br></div><div>valarray provides memberwise operations =
as well as operations to one scalar T already. More math stuff can be added=
as functions of course: dot product, length or whatever.</div></div></bloc=
kquote><div><br>I don't know if changing the template argument list of vala=
rray would pose compatibility problems. There is also the fact that v=
alarray is allowed to use expression templates, which is probably undesirab=
le for fixed-size types. In general a fixed-size valarray is a very u=
seful addition, though; it would probably get used more than the current va=
riable-sized valarray, which as far as I understand is hardly ever used.&nb=
sp; Note that the valarray could be multidimensional as well.<br></div><div=
><br> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"l=
tr"><div></div><div>I would also prefer if there were specializations for 2=
and 3 dimensions where the elements are named x, y and z (for instance usi=
ng a union with the array).</div></div></blockquote></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_928_22262662.1402769466742--
.
Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sat, 14 Jun 2014 12:43:33 -0700 (PDT)
Raw View
------=_Part_560_8925170.1402775013840
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Den l=C3=B6rdagen den 14:e juni 2014 kl. 20:11:07 UTC+2 skrev Jeremy=20
Maitin-Shepard:
>
> On Saturday, June 14, 2014 3:35:35 AM UTC-7, Bengt Gustafsson wrote:
>>
>> I would like array_view to cater for the case that one or more dimension=
s=20
>> is fixed size. This can improve performance by a lot and also provies=20
>> additional documentation value for functions requiring its data to actua=
lly=20
>> have a certain bound in a particular dimension. I think that the bounds=
=20
>> representation used by Eigen could work for array_view too:
>>
>> static const size_t var_dim =3D -1;
>> template<typename T, size_t... Ss> class array_view;
>>
>> The interpretation of this being that for a n dimensional array_view you=
=20
>> mention n sizes as template parameters, any of which may be the marker=
=20
>> value var_dim which indicates a variable dimension and activates a=20
>> specialization of the template.
>>
>
> I agree that it is certainly useful to be able to specify information=20
> about sizes and strides (as you describe later in the message) at compile=
=20
> time. Potentially it is also useful to specify information about=20
> alignment, or the fact that a size or stride is a multiple of some compil=
e=20
> time constant, etc.
>
> At least if it is the last dimension that is statically sized, you can=20
> work around it by just making it array_view<std::array<T,X>,1>, and you=
=20
> could provide convenient ways to convert to and from array_view<T,2>. Th=
is=20
> is also the case that may be the most useful in terms of optimization.
>
> There is no problem in principle with allowing all of this compile-time=
=20
> specification, it is just a matter of figuring out the right model for=20
> representing all of it, and figure out a suitable syntax for specifying i=
t=20
> all. The best way to do that is to implement it as a library and see how=
=20
> things work out.
>
> It might not (probably won't) be possible to stuff all of this=20
> functionality into a single template argument list that is also convenien=
t=20
> for the simple cases, but that isn't a problem given that we have templat=
e=20
> aliases. It is, for instance, more convenient to be able to type=20
> MultiDimensionalArray<int,3> rather than=20
> MultiDimensionalArray<int,-1,-1,-1>.
>
Yes that could be a good idea, again, however, we need to worry about=20
namespace cluttering and for programmers to be able to remember it all. As=
=20
a detail: Do you see a simple way to actually write the template alias you=
=20
suggest? I see that it is possible using a recursive variadic template=20
helper but is there a simpler way?
=20
>
>
> I have suggested this system as an extension of the current array<>=20
>> template to n dimensions previously, see thread=20
>> https://groups.google.com/a/isocpp.org/forum/#!topicsearch/bengt$20gusta=
fsson/std-proposals/hW2QAvmboqU.=20
>> As easily seen the current one dimensional, fixed size case fits nicely=
=20
>> under this umbrella. The idea was that the variable size specializations=
of=20
>> array<> would use a new VLA feature whenever that enters C++. but use th=
e=20
>> heap in the meantime.
>>
>
> I think something like that should wait until runtime-sized structs are=
=20
> supported. Otherwise the heap allocation makes it non-POD.=20
>
If you mean structs with VLAs in them that is envisioned in the current=20
suggestions such as N4025 and my own reply to this (search this forum for=
=20
N4025 and you will find it as a (long) commentary).
=20
> =20
>
>> The lack of a (mathematical) vector type with suitable operations could=
=20
>> possibly be solved by applying the above var_dim possibility to valarray=
:
>>
>> template<typename T, size_t Sz> class valarray;
>>
>> template<typename T> class valarray<T. var_dim>; // The current valarra=
y=20
>> is the specialization for var_dim.
>>
>> valarray provides memberwise operations as well as operations to one=20
>> scalar T already. More math stuff can be added as functions of course: d=
ot=20
>> product, length or whatever.
>>
>
> I don't know if changing the template argument list of valarray would pos=
e=20
> compatibility problems. =20
>
Yes I think it may be a breaking change if valarray is used as the template=
=20
template argument of something declared like this:
template<template<typename> class V> struct my_stuct;
But I am not really certain whether a valarray<typename T, size_t Sz =3D -1=
>=20
is allowed (given the default value) or not. I suspect it is not... Lets=20
see, a quick test on VS2013 cries out: error C3201: the template parameter=
=20
list for class template 'valarray' does not match the template parameter=20
list for template parameter 'V'
Well, we are working on the standard so it would at least theoretically=20
possible to make a core change simultaneously to allow this. I checked also=
=20
whether the corresponding thing is allowed for function pointer but it is=
=20
not. On the other hand class templates can't be overloaded in contrast with=
=20
functions.
=20
> There is also the fact that valarray is allowed to use expression=20
> templates, which is probably undesirable for fixed-size types. In genera=
l=20
> a fixed-size valarray is a very useful addition, though; it would probabl=
y=20
> get used more than the current variable-sized valarray, which as far as I=
=20
> understand is hardly ever used. Note that the valarray could be=20
> multidimensional as well.
>
> =20
>
I would not be opposed to implementing valarray's operators for array<> and=
=20
make valarray<T> an alias of array<T, -1> . In fact bounds and indices in=
=20
my suggested multi-dimensional array are themselves array<size_t, RANK>.
I agree that it is painful to have different types for bounds and indices,=
=20
and I have tried in an (in house) image processing library for the last 15=
=20
years. It happens far more often than one would think that arithmetic is=20
done like you explain, such as adding the kernel and image size etc.
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
------=_Part_560_8925170.1402775013840
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>Den l=C3=B6rdagen den 14:e juni 2014 kl. 20:11:07 =
UTC+2 skrev Jeremy Maitin-Shepard:<blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div dir=3D"ltr">On Saturday, June 14, 2014 3:35:35 AM UTC-7, Bengt G=
ustafsson wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-=
left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><d=
iv><span style=3D"font-size:13px">I would like array_view to cater for the =
case that one or more dimensions is fixed size. This can improve performanc=
e by a lot and also provies additional documentation value for functions re=
quiring its data to actually have a certain bound in a particular dimension=
.. I think that the bounds representation used by Eigen could work for=
array_view too:</span><br></div><div><span style=3D"font-size:13px"><br></=
span></div><div>static const size_t var_dim =3D -1;</div><div>template<t=
ypename T, size_t... Ss> class array_view;</div><div><br></div><div>The =
interpretation of this being that for a n dimensional array_view you mentio=
n n sizes as template parameters, any of which may be the marker value var_=
dim which indicates a variable dimension and activates a specialization of =
the template.</div></div></blockquote><div><br>I agree that it is certainly=
useful to be able to specify information about sizes and strides (as you d=
escribe later in the message) at compile time. Potentially it is also=
useful to specify information about alignment, or the fact that a size or =
stride is a multiple of some compile time constant, etc.<br><br>At least if=
it is the last dimension that is statically sized, you can=20
work around it by just making it=20
array_view<std::array<T,X>,1>, and you could provide=20
convenient ways to convert to and from array_view<T,2>. This is=
=20
also the case that may be the most useful in terms of optimization.<br><br>=
There
is no problem in principle with allowing all of this compile-time=20
specification, it is just a matter of figuring out the right model for=20
representing all of it, and figure out a suitable syntax for specifying=20
it all. The best way to do that is to implement it as a library and s=
ee
how things work out.<br><br>It might not (probably won't) be possible=20
to stuff all of this functionality into a single template argument list=20
that is also convenient for the simple cases, but that isn't a problem=20
given that we have template aliases. It is, for instance, more=20
convenient to be able to type MultiDimensionalArray<int,3> rather=20
than MultiDimensionalArray<int,-1,-<wbr>1,-1>.<br></div></div></block=
quote><div><br></div><div>Yes that could be a good idea, again, however, we=
need to worry about namespace cluttering and for programmers to be able to=
remember it all. As a detail: Do you see a simple way to actually write th=
e template alias you suggest? I see that it is possible using a recursive v=
ariadic template <span style=3D"font-size: 13px;">helper</span><span s=
tyle=3D"font-size: 13px;"> </span><span style=3D"font-size: 13px;">but=
is there a simpler way?</span></div><div> </div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;"><div dir=3D"ltr"><div><br></div><div><br></div><blo=
ckquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-le=
ft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div>I have suggested =
this system as an extension of the current array<> template to n dime=
nsions previously, see thread <a href=3D"https://groups.google.com/a/isocpp=
..org/forum/#!topicsearch/bengt$20gustafsson/std-proposals/hW2QAvmboqU" targ=
et=3D"_blank" onmousedown=3D"this.href=3D'https://groups.google.com/a/isocp=
p.org/forum/#!topicsearch/bengt$20gustafsson/std-proposals/hW2QAvmboqU';ret=
urn true;" onclick=3D"this.href=3D'https://groups.google.com/a/isocpp.org/f=
orum/#!topicsearch/bengt$20gustafsson/std-proposals/hW2QAvmboqU';return tru=
e;">https://groups.google.com/a/<wbr>isocpp.org/forum/#!<wbr>topicsearch/be=
ngt$<wbr>20gustafsson/std-proposals/<wbr>hW2QAvmboqU</a>. As easily seen th=
e current one dimensional, fixed size case fits nicely under this umbrella.=
The idea was that the variable size specializations of array<> would=
use a new VLA feature whenever that enters C++. but use the heap in the me=
antime.</div></div></blockquote><div><br>I think something like that should=
wait until runtime-sized structs are=20
supported. Otherwise the heap allocation makes it non-POD. <br></div>=
</div></blockquote><div>If you mean structs with VLAs in them that is envis=
ioned in the current suggestions such as N4025 and my own reply to this (se=
arch this forum for N4025 and you will find it as a (long) commentary).</di=
v><div> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;mar=
gin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D=
"ltr"><div></div><div> </div><blockquote class=3D"gmail_quote" style=
=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"=
><div dir=3D"ltr"><div>The lack of a (mathematical) vector type with suitab=
le operations could possibly be solved by applying the above var_dim possib=
ility to valarray:</div><div><br></div><div>template<typename T, size_t =
Sz> class valarray;</div><div><br></div><div>template<typename T> =
class valarray<T. var_dim>; // The current valarray is the spec=
ialization for var_dim.</div><div><br></div><div>valarray provides memberwi=
se operations as well as operations to one scalar T already. More math stuf=
f can be added as functions of course: dot product, length or whatever.</di=
v></div></blockquote><div><br>I don't know if changing the template argumen=
t list of valarray would pose compatibility problems. </div></div></b=
lockquote><div><br></div><div>Yes I think it may be a breaking change if va=
larray is used as the template template argument of something declared like=
this:</div><div><br></div><div>template<template<typename> class =
V> struct my_stuct;</div><div><br></div><div>But I am not really certain=
whether a valarray<typename T, size_t Sz =3D -1> is allowed (given t=
he default value) or not. I suspect it is not... Lets see, a quick test on =
VS2013 cries out: error C3201: the template parameter list for class t=
emplate 'valarray' does not match the template parameter list for template =
parameter 'V'</div><div><br></div><div>Well, we are working on the standard=
so it would at least theoretically possible to make a core change simultan=
eously to allow this. I checked also whether the corresponding thing is all=
owed for function pointer but it is not. On the other hand class templates =
can't be overloaded in contrast with functions.</div><div><br></div><div>&n=
bsp;</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left:=
0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><di=
v>There is also the fact that valarray is allowed to use expression templat=
es, which is probably undesirable for fixed-size types. In general a =
fixed-size valarray is a very useful addition, though; it would probably ge=
t used more than the current variable-sized valarray, which as far as I und=
erstand is hardly ever used. Note that the valarray could be multidim=
ensional as well.<br></div><div><br> </div></div></blockquote><div>I w=
ould not be opposed to implementing valarray's operators for array<> =
and make valarray<T> an alias of array<T, -1> . In fact bounds =
and indices in my suggested multi-dimensional array are themselves array<=
;size_t, RANK>.</div><div><br></div><div>I agree that it is painful to h=
ave different types for bounds and indices, and I have tried in an (in hous=
e) image processing library for the last 15 years. It happens far more ofte=
n than one would think that arithmetic is done like you explain, such as ad=
ding the kernel and image size etc.</div><div><br></div><div><br></div></di=
v>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_560_8925170.1402775013840--
.
Author: =?UTF-8?Q?=C5=81ukasz_Mendakiewicz?= <l.mendakiewicz@live.com>
Date: Sun, 15 Jun 2014 14:07:49 -0700 (PDT)
Raw View
------=_Part_12_18079856.1402866469569
Content-Type: text/plain; charset=UTF-8
I have a slightly different opinion on the matter, and in my view both
array_view and ranges should coexist in the library as they serve different
purposes.
1. array_view guarantees a contiguous memory range. This property can be
used for performance benefit (e.g. leveraged in a vectorized or GPGPU
execution) or for compatibility with C.
In that spirit, I also disagree with the comment below that it should be
possible to create an array_view (ignoring for the moment the obvious
misnomer) over deque, list, etc. as it would conflict with this
basic property. Ranges are likely the proper solution for such scenarios.
Please note that random_access_iterator does not guarantee contiguity in
the memory. It merely gives illusion of such, and this is insufficient to
fully exploit the current hardware, which is more often than in the past
bound by the memory (rather than compute). This however could be partially
alleviated by introducing more specialized iterator category (vide N3884).
2. array_view allows "lifting" a contiguous allocation into a
multidimensional representation. Please correct me if I'm wrong, but I
think ranges by definition do not address this use case. This is not only
matter of indexing using multiple components, but also other convenience
operations like slicing or sectioning.
Having said that, given that neither ranges nor array_view are targeted at
C++14, it is not impossible for ranges to grow their scope and subsume the
design space covered now by the multidimensional array_view. From our
perspective this is a success, as the necessary functionality is added to
the standard C++. However until this happens, the two are effectively
different, despite some commonality for the basic cases.
On Friday, June 13, 2014 4:56:47 PM UTC-7, Sean Middleditch wrote:
> Adding a bunch of cruft that is planned to be obsoleted with an update
> right around the corner seems like a waste of time and needless bloat
> to the library for no practical gain. It's not even clear that there's
> any point in time we'd even need the interim solution: C++14 is done,
> no new library additions are going to be made to it, all work going
> forward is for C++17, and it's rather likely that the first version of
> comprehensive ranges will either be in C++17 or a TS released around
> the same time.
>
> On Fri, Jun 13, 2014 at 3:07 PM, Jeremy Maitin-Shepard
> <jer...@jeremyms.com <javascript:>> wrote:
> >
> >
> > On Friday, June 13, 2014 2:37:50 PM UTC-7, Sean Middleditch wrote:
> >>
> >> On Friday, June 13, 2014 12:17:40 PM UTC-7, Jeremy Maitin-Shepard
> wrote:
> >>>
> >>> C++ is sorely in need of a "vocabulary type" for representing pointer
> >>> ranges.
> >>
> >>
> >> There's already a Ranges sub group working on this problem, and looking
> at
> >> even more general cases of ranges than just pairs of
> iterators/pointers.
> >>
> >> http://www.open-std.org/mailman/listinfo/ranges
> >
> >
> > Sure, but (pointer, size) ranges are an extremely common and important
> case,
> > and devising a comprehensive range library that handles all cases is
> much
> > harder than handling just the (pointer, size) case. Also, in the worst
> > case, a one-dimensional array_view type would become redundant after a
> range
> > library is standardized, but it wouldn't cause any interoperability
> > problems, since the types would surely be implicitly convertible.
> >
> > --
> >
> > ---
> > You received this message because you are subscribed to a topic in the
> > Google Groups "ISO C++ Standard - Future Proposals" group.
> > To unsubscribe from this topic, visit
> >
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/xzb1d5KUxMU/unsubscribe.
>
> > To unsubscribe from this group and all its topics, send an email to
> > std-proposal...@isocpp.org <javascript:>.
> > To post to this group, send email to std-pr...@isocpp.org <javascript:>.
>
> > Visit this group at
> > http://groups.google.com/a/isocpp.org/group/std-proposals/.
>
>
>
> --
> Sean Middleditch
> http://seanmiddleditch.com
>
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_12_18079856.1402866469569
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>I have a slightly different opinion on the matter, an=
d in my view both array_view and ranges should coexist in the library as th=
ey serve different purposes.</div><div><br></div><div>1. array_view guarant=
ees a contiguous memory range. This property can be used for performan=
ce benefit (e.g. leveraged in a vectorized or GPGPU execution) or for compa=
tibility with C.</div><div>In that spirit, I also disagree with the comment=
below that it should be possible to create an array_view (ignoring for the=
moment the obvious misnomer) over deque, list, etc. as it would conflict w=
ith this basic property. Ranges are likely the proper solution for suc=
h scenarios.</div><div>Please note that random_access_iterator does not gua=
rantee contiguity in the memory. It merely gives illusion of such, and this=
is insufficient to fully exploit the current hardware, which is more often=
than in the past bound by the memory (rather than compute). This however&n=
bsp;could be partially alleviated by introducing more specialized iter=
ator category (vide N3884).</div><div><br></div><div>2. array_view allows "=
lifting" a contiguous allocation into a multidimensional representation. Pl=
ease correct me if I'm wrong, but I think ranges by definition do not addre=
ss this use case. This is not only matter of indexing using multiple compon=
ents, but also other convenience operations like slicing or sectioning.</di=
v><div><br></div><div>Having said that, given that neither ranges nor array=
_view are targeted at C++14, it is not impossible for ranges to grow t=
heir scope and subsume the design space covered now by the multidimensional=
array_view. From our perspective this is a success, as the necessary funct=
ionality is added to the standard C++. However until this happens, the two =
are effectively different, despite some commonality for the basic cases.<br=
><br>On Friday, June 13, 2014 4:56:47 PM UTC-7, Sean Middleditch wrote:</di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; pad=
ding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1=
px; border-left-style: solid;">Adding a bunch of cruft that is planned to b=
e obsoleted with an update
<br>right around the corner seems like a waste of time and needless bloat
<br>to the library for no practical gain. It's not even clear that there's
<br>any point in time we'd even need the interim solution: C++14 is done,
<br>no new library additions are going to be made to it, all work going
<br>forward is for C++17, and it's rather likely that the first version of
<br>comprehensive ranges will either be in C++17 or a TS released around
<br>the same time.
<br>
<br>On Fri, Jun 13, 2014 at 3:07 PM, Jeremy Maitin-Shepard
<br><<a onmousedown=3D"this.href=3D'javascript:';return true;" onclick=
=3D"this.href=3D'javascript:';return true;" href=3D"javascript:" target=3D"=
_blank" gdf-obfuscated-mailto=3D"w7bBcQOg12cJ">jer...@jeremyms.com</a>> =
wrote:
<br>>
<br>>
<br>> On Friday, June 13, 2014 2:37:50 PM UTC-7, Sean Middleditch wrote:
<br>>>
<br>>> On Friday, June 13, 2014 12:17:40 PM UTC-7, Jeremy Maitin-Shep=
ard wrote:
<br>>>>
<br>>>> C++ is sorely in need of a "vocabulary type" for represent=
ing pointer
<br>>>> ranges.
<br>>>
<br>>>
<br>>> There's already a Ranges sub group working on this problem, an=
d looking at
<br>>> even more general cases of ranges than just pairs of iterators=
/pointers.
<br>>>
<br>>> <a onmousedown=3D"this.href=3D'http://www.google.com/url?q\75h=
ttp%3A%2F%2Fwww.open-std.org%2Fmailman%2Flistinfo%2Franges\46sa\75D\46sntz\=
0751\46usg\75AFQjCNH9nJsY_1zetmYeacjyeAFzsSFBOA';return true;" onclick=3D"t=
his.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fwww.open-std.org%2Fm=
ailman%2Flistinfo%2Franges\46sa\75D\46sntz\0751\46usg\75AFQjCNH9nJsY_1zetmY=
eacjyeAFzsSFBOA';return true;" href=3D"http://www.open-std.org/mailman/list=
info/ranges" target=3D"_blank">http://www.open-std.org/<wbr>mailman/listinf=
o/ranges</a>
<br>>
<br>>
<br>> Sure, but (pointer, size) ranges are an extremely common and impor=
tant case,
<br>> and devising a comprehensive range library that handles all cases =
is much
<br>> harder than handling just the (pointer, size) case. Also, in=
the worst
<br>> case, a one-dimensional array_view type would become redundant aft=
er a range
<br>> library is standardized, but it wouldn't cause any interoperabilit=
y
<br>> problems, since the types would surely be implicitly convertible.
<br>>
<br>> --
<br>>
<br>> ---
<br>> You received this message because you are subscribed to a topic in=
the
<br>> Google Groups "ISO C++ Standard - Future Proposals" group.
<br>> To unsubscribe from this topic, visit
<br>> <a onmousedown=3D"this.href=3D'https://groups.google.com/a/isocpp.=
org/d/topic/std-proposals/xzb1d5KUxMU/unsubscribe';return true;" onclick=3D=
"this.href=3D'https://groups.google.com/a/isocpp.org/d/topic/std-proposals/=
xzb1d5KUxMU/unsubscribe';return true;" href=3D"https://groups.google.com/a/=
isocpp.org/d/topic/std-proposals/xzb1d5KUxMU/unsubscribe" target=3D"_blank"=
>https://groups.google.com/a/<wbr>isocpp.org/d/topic/std-<wbr>proposals/xzb=
1d5KUxMU/<wbr>unsubscribe</a>.
<br>> To unsubscribe from this group and all its topics, send an email t=
o
<br>> <a onmousedown=3D"this.href=3D'javascript:';return true;" onclick=
=3D"this.href=3D'javascript:';return true;" href=3D"javascript:" target=3D"=
_blank" gdf-obfuscated-mailto=3D"w7bBcQOg12cJ">std-proposal...@<wbr>isocpp.=
org</a>.
<br>> To post to this group, send email to <a onmousedown=3D"this.href=
=3D'javascript:';return true;" onclick=3D"this.href=3D'javascript:';return =
true;" href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"w7bB=
cQOg12cJ">std-pr...@isocpp.org</a>.
<br>> Visit this group at
<br>> <a onmousedown=3D"this.href=3D'http://groups.google.com/a/isocpp.o=
rg/group/std-proposals/';return true;" onclick=3D"this.href=3D'http://group=
s.google.com/a/isocpp.org/group/std-proposals/';return true;" href=3D"http:=
//groups.google.com/a/isocpp.org/group/std-proposals/" target=3D"_blank">ht=
tp://groups.google.com/a/<wbr>isocpp.org/group/std-<wbr>proposals/</a>.
<br>
<br>
<br>
<br>--=20
<br>Sean Middleditch
<br><a onmousedown=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F=
%2Fseanmiddleditch.com\46sa\75D\46sntz\0751\46usg\75AFQjCNHx3WLavT-kbToOv7I=
L4uvcN5l-vg';return true;" onclick=3D"this.href=3D'http://www.google.com/ur=
l?q\75http%3A%2F%2Fseanmiddleditch.com\46sa\75D\46sntz\0751\46usg\75AFQjCNH=
x3WLavT-kbToOv7IL4uvcN5l-vg';return true;" href=3D"http://seanmiddleditch.c=
om" target=3D"_blank">http://seanmiddleditch.com</a>
<br></blockquote></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_12_18079856.1402866469569--
.
Author: =?UTF-8?Q?=C5=81ukasz_Mendakiewicz?= <l.mendakiewicz@live.com>
Date: Sun, 15 Jun 2014 21:38:24 -0700 (PDT)
Raw View
------=_Part_519_6490396.1402893504503
Content-Type: text/plain; charset=UTF-8
Thank you Jeffrey for adding me on the thread and for your initial response
-- which I almost universally agree with.
Jeremy, thank you for your detailed feedback. First, I believe that most of
the disagreement stems from the approach to the proposal. You've
commented that "it doesn't make sense to standardize a partial solution;
better to work out a good, complete interface outside the standard". This
is opposite to the "crawl, walk, run" philosophy we have taken when writing
this document up. We recognize that we have only explored some parts of the
design space, because as you have rightly observed our experience is
limited to C++ AMP, which constitutes only a specific data parallel
approach to algorithms. Of course we believe that this is a solid
foundation that can be generalized and built upon, hence the proposal. But
we deliberately avoided any design decisions which may be controversial or
result in a prolonged tug of war, instead intending for subsequent
proposals (not necessarily authored by us) to fill the gaps. Certainly,
should anything being proposed now be a possible hindrance for any
reasonable extension, it must be addressed sooner than later, however I
think that none of the lacks pointed by you belong to this category.
>>> Some particular issues with the proposed design include:
>>>
>>> - No iterators are provided for array_view or strided_array_view, a
clear
>>> omission in the interface. For a multidimensional array, there are two
>>> obvious types of iteration that may be desired:
>>> 1. iterating over just the first dimension;
>>> 2. iterating over a flat view of all of the elements. For a strided
>>> array, iterating over a flat view cannot be done efficiently without
>>> segmented/hierarchical iterators.
>>> Which of these should be the default (i.e. provided through begin()
and
>>> end() rather than through some adaptor) is not clear,
>>
>> From the Zen of Python, "In the face of ambiguity, refuse the
>> temptation to guess."
>
> That's true, but no adaptors to provide the functionality unambiguously
are provided either. For the particular case of a one-dimensional array,
there is no ambiguity, and not being able to easily use array_view with
standard algorithms or range-based for is a serious usability issue. This
will only become worse if/when standard algorithm overloads that take
ranges rather than iterator pairs are added.
To the list of possible alternatives, I would add an option that was
proposed somewhere in the prior discussion on the proposal --
"hierarchical" array_view/elemental iterator, i.e. an iterator that for
array_view<T, Rank> with Rank > 1 iterates over array_view<T, Rank-1>; and
over T for Rank == 1.
It is however worth pointing out that in the first round of review with
LEWG at Issaquah meeting, the vocal unchallenged feedback for iterators was
"I do not want iterators for the views", thus we did not put much effort
into contemplating adding any. Even though the choice for Rank == 1 is
"obvious", we consider this a corner case for array_view, and would rather
have a holistic approach.
There remains the possibility to add some form of the iterator as a future
extension.
>>> - No data() access member for strided_array_view. This is presumably
>>> omitted because the memory is non-contiguous, but given that
>>> strided_array_view is a thin wrapper, there has to be a convenient way
to
>>> get at the underlying memory.
>>
>> Why "has to"?
>
> Because the user might want to convert the array to another
representation for use by another piece of code/library, e.g. FFTW or
Eigen, CUDA memcpy, etc. Under the proposed interface, for a 3-dimensional
stided array view, you have to use &arr[0][0][0]. This is even worse than
having to do &vec[0] for std::vector, since the same expression cannot be
used independent of the dimensionality.
data() on strided_array_view could be harmful, as there is no guarantee of
contiguity, which a developer / function template might assume. Please note
that for every other case in the Standard, the range [data(),
data()+size()) is valid/safe, thus providing other semantics here would be
dubious.
Granted, one can perform &arr[0][0][0] and run afoul, but that is no
different than e.g. &my_list.front().
It could be possible to provide "unsafe_data()" interface, which would have
to be consumed along with stride(), however I do not see much benefit here
over just using the "proper" interface -- bounds() and operator[]().
>>> - Slicing is limited: it is not possible to take a slice in a dimension
>>> other than the first.
>>
>> I think that's called "section()".
>
> Well, that takes a "section" but does not reduce the dimensionality like
"slice". [...] Certainly there is a large design space for general
subscripting and it almost certainly requires a fair amount of template
metaprogramming, but this is very useful functionality
Yes, slicing and sectioning are slightly different. It is however important
to note that slicing in its current form always guarantees the contiguity
of the result, thus the return type may be array_view. The more general
cases (as you are describing) would result in a potentially strided
resulting view, which would need to be typed strided_array_view. This is
why it is important IMO to distinguish these two cases.
In the current form of the proposal we decided to provide the minimal
design -- only the first version, which in our opinion might be handy for
users used to C-style multidimensional addressing (i.e. arr[3][1][4] v
arr[{3, 1, 4}]), which actually you used above :).
The latter generic case can be trivially added as an extension to the
interface. I agree it may be useful, and if the current design is accepted
for the TS, I encourage you to propose such extension (or nag us for follow
ups :)).
>>> - It is not clear whether it is really useful to have bounds and index
be
>>> separate types (though should probably at least be explicitly
convertible to
>>> each other).
>>
>> It adds a bit of type safety. Adding two bounds, for instance, doesn't
>> make a lot of sense.
>
> I agree that type safety is in principle useful, but it is impossible to
predict what relationships might hold in any given program, and so there is
the question of whether the safety it adds is worth the cost of having to
explicitly work around it in the cases that it is too restrictive.
Certainly if they are separate types there needs to be a way to
(explicitly) convert.
I agree with both of you :).
These are separate types, because their meaning and semantics are
different. It was also discussed in N3851, Appendix, II. The mental model I
use for reasoning about them is: index ~ vector and bounds ~ point (more
specifically: a zero-bound, axis-aligned rectangle described by its maximum
point), which makes the set of available operators apparent.
I understand the explicit conversions between these two types, even though
not theoretically sound, might be handy in practice and should be added.
> As a specific example, consider if we want to compute the bounds of a
valid convolution if we have an array x and a filter k. The bounds of the
result are: x.bounds - k.bounds + 1. None of the arithmetic operators
defined in the proposal help me with that; I'd just have to write a loop.
Even if the arithmetic operators weren't limited by the bounds/index
distinction, there would still be no way to create a constant-valued
vector, i.e. to handle the constant 1.
Explicit conversions would help with the first part, right? I hope you are
also not suggesting any such conversion should be implicit?
However I do not really understand what do you mean in the second part, "a
constant-valued vector". We purposefully allow to create both bounds<1> and
index<1> from a scalar; and disallow such operation for Rank > 1 (mostly
because the semantics are not obvious, e.g. for rank 2, should index<2>{16}
be {0, 16}, {16, 0} or {16, 16}).
So net-net, in your example you should be able to do: x.bounds -
index<2>{k.bounds} + {1, 1}. It a little more long-winded, but IMO easier
to comprehend than the original.
> Another related issue I didn't notice before: the only way to construct
an index or bounds type is from an initializer_list. There is no
(explicit) conversion from std::array, for instance. It is quite likely
that an index or bounds value would be computed by some other code, that
may use a different representation.
Yes, we should add (const value_type* begin, const value_type* end)
constructors for both types. <rant>Or it should be possible to create
initializer_list explicitly from such pair which would solve this issue
universally.</rant>
>>> Furthermore, bounds and index essentially represent a
>>> fixed-size discrete vector type, i.e. an augmented interface for
std::array.
>>> Arguably the interface of std::array should just be extended to add
>>> component-wise operators instead. Also, a much more comprehensive set
of
>>> component-wise operations should be provided. A statically-sized
vector
>>> type is sorely needed in C++, but it does not make sense to standardize
>>> these limited, single-purposes types when they could be, and should be,
much
>>> more general.
>>
>> We don't necessarily want to go for the most general possible type all
at once
>
> Certainly there is a large design space, but that is a reason to be
cautious about standardizing anything. [...]
There are two separate issue raised here:
- Why novel types -- this is primarily to introduce "vocabulary" types and
allow to discriminate index and bounds, as they have different semantics,
as discussed before. This was also touched upon in the previously referred
N3851, Appendix, II.
- Why so little functionality -- I agree with Jeffrey on this, and I have
described more of the philosophy in the introduction. I would be interested
however what exactly you mean by "a much more comprehensive set of
component-wise operations". Having said that, I assume this is something
that can be added later as a pure extension, correct?
> Given the long turn around time for revisions to C++
The Committee is certainly trying to get better at quicker iterations,
let's not be discouraged by the ghosts of the past...
> Other omissions from index and bounds include:
> 1. no data() access to the components
> 2. no iterators over components for index or bound
index and bounds are not containers and should not be used as such. For the
limited number of scenario where I want to use/modify indeterminate number
of components, it was always sufficient for me to use a raw loop, and
operator[]...
In case I'm wrong, these as well should be easy to add later as extensions.
> for_each(x_array, y_array, x_array.bounds(), [&](auto &x, auto &y, auto
pos) {
> if (x != y) std::cout << "mismatch at position " << pos << std::endl;
> });
I assume the idea here is that such "for_each" uses begin(X), end(X) for
all provided arguments, passing dereferenced iterators to the function
object. If so, I do not see how the current semantics of bounds_iterator
would get into way here? It should just work as is, no?
Actually, it should be possible to write the following with just the
current proposal and the current standard for_each:
auto x_av = array_view<N>{x_array};
auto y_av = array_view<N>{y_array};
for_each(begin(x_av.bounds()), end(x_av.bounds()), [&](index<N> pos) {
if(x_av[pos] != y_av[pos]) std::cout << "mismatch at position " << pos <<
std::endl;
});
> From my perspective, the only way to properly explore this design space
for multidimensional arrays/containers/ranges is through an actively
developed and widely used open source library.
Our (Microsoft) prototype implementation is in the pipeline to be published
as an open source project. It should happen really soon, and I hope it will
help to convey the discussed ideas.
On Friday, June 13, 2014 9:30:45 PM UTC-7, Jeremy Maitin-Shepard wrote:
>
>
> On Friday, June 13, 2014 5:54:21 PM UTC-7, Jeffrey Yasskin wrote:
>>
>> Thanks for the comments. Lukasz, FYI in case you're not on this list.
>>
>> On Fri, Jun 13, 2014 at 9:17 PM, Jeremy Maitin-Shepard
>> <jer...@jeremyms.com> wrote:
>> > C++ is sorely in need of a "vocabulary type" for representing pointer
>> > ranges. It is also sorely in need of a good, standard library for
>> > multidimensional arrays/containers/ranges. While the design space for
>> a
>> > one-dimensional, unstrided array view is fairly limited, the design
>> space
>> > for a multidimensional array/container/range is very large. Finding
>> the
>> > right design certainly involves numerous design iterations and very
>> > substantial user experience. While the proposed design in n3976 is a
>> very
>> > useful starting point, it would be premature to standardize it at this
>> > point, as it is far from comprehensive and it is difficult to know how
>> well
>> > the proposed interface could be extended to provide a larger set of
>> > functionality on par with the facilities available in many other
>> languages.
>>
>> According to N3851,
>> http://msdn.microsoft.com/en-us/library/vstudio/hh305260(v=vs.110).aspx
>> <http://www.google.com/url?q=http%3A%2F%2Fmsdn.microsoft.com%2Fen-us%2Flibrary%2Fvstudio%2Fhh305260(v%3Dvs.110).aspx&sa=D&sntz=1&usg=AFQjCNGutdo3UFl--fatoQp9kucVYtiHcg>
>> seems to be that user experience. We'll also have a chance to get more
>> experience while this is in a TS before being standardized.
>>
>
> I saw that, but the fact that it is part of AMP suggests that the focus is
> a bit more specialized than a general multidimensional array.
>
>
>> > Some particular issues with the proposed design include:
>> >
>> > - No iterators are provided for array_view or strided_array_view, a
>> clear
>> > omission in the interface. For a multidimensional array, there are two
>> > obvious types of iteration that may be desired:
>> > 1. iterating over just the first dimension;
>> > 2. iterating over a flat view of all of the elements. For a strided
>> > array, iterating over a flat view cannot be done efficiently without
>> > segmented/hierarchical iterators.
>> > Which of these should be the default (i.e. provided through begin()
>> and
>> > end() rather than through some adaptor) is not clear,
>>
>> From the Zen of Python, "In the face of ambiguity, refuse the
>> temptation to guess."
>>
>> That's true, but no adaptors to provide the functionality unambiguously
> are provided either. For the particular case of a one-dimensional array,
> there is no ambiguity, and not being able to easily use array_view with
> standard algorithms or range-based for is a serious usability issue. This
> will only become worse if/when standard algorithm overloads that take
> ranges rather than iterator pairs are added.
>
> > - No data() access member for strided_array_view. This is presumably
>> > omitted because the memory is non-contiguous, but given that
>> > strided_array_view is a thin wrapper, there has to be a convenient way
>> to
>> > get at the underlying memory.
>>
>> Why "has to"?
>>
>
> Because the user might want to convert the array to another representation
> for use by another piece of code/library, e.g. FFTW or Eigen, CUDA memcpy,
> etc. Under the proposed interface, for a 3-dimensional stided array view,
> you have to use &arr[0][0][0]. This is even worse than having to do
> &vec[0] for std::vector, since the same expression cannot be used
> independent of the dimensionality.
>
>
>>
>> > Given the definition of Viewable, the use of
>> > the name data() might be problematic as it would allow the incorrect
>> (albeit
>> > explicit) conversion from strided_array_view to array_view. Possibly
>> > Viewable should be traits-based rather than based only on the presence
>> of
>> > data() and size().
>>
>> The downside of traits, of course, is that we'd burden users with
>> marking their types. If nearly all existing contiguous types expose
>> data()/size(), the library can save people work by using them.
>>
>
> That's a valid point.
>
>
>>
>> > - Slicing is limited: it is not possible to take a slice in a dimension
>> > other than the first.
>>
>> I think that's called "section()".
>>
>
> Well, that takes a "section" but does not reduce the dimensionality like
> "slice". For instance, suppose I have a two-dimensional 20x10 array arr
> and want to do the equivalent of the numpy:
>
> arr[:,5]
>
> and obtain a 1-dimensional strided_array_view of length 20.
>
> Certainly there is a large design space for general subscripting and it
> almost certainly requires a fair amount of template metaprogramming, but
> this is very useful functionality.
>
>
>> > - operator++ and operator-- on index seem very questionable. The
>> semantics
>> > are rather arbitrary and not that likely to be useful except for a
>> single
>> > dimension anyway.
>>
>> They're marked with "Requires: Rank == 1." This should be more like
>> "Ill-formed unless ...", but the goal is there.
>>
> Sorry, I missed that requirement. No problem there then.
>
>
>>
>> > - It is not clear whether it is really useful to have bounds and index
>> be
>> > separate types (though should probably at least be explicitly
>> convertible to
>> > each other).
>>
>> It adds a bit of type safety. Adding two bounds, for instance, doesn't
>> make a lot of sense.
>>
> I agree that type safety is in principle useful, but it is impossible to
> predict what relationships might hold in any given program, and so there is
> the question of whether the safety it adds is worth the cost of having to
> explicitly work around it in the cases that it is too restrictive.
> Certainly if they are separate types there needs to be a way to
> (explicitly) convert. Right now the only way to convert is to write a
> manual loop and use operator[], or possibly use operator[] to obtain
> pointers and then call memcpy or std::copy.
>
> As a specific example, consider if we want to compute the bounds of a
> valid convolution if we have an array x and a filter k. The bounds of the
> result are: x.bounds - k.bounds + 1. None of the arithmetic operators
> defined in the proposal help me with that; I'd just have to write a loop.
> Even if the arithmetic operators weren't limited by the bounds/index
> distinction, there would still be no way to create a constant-valued
> vector, i.e. to handle the constant 1.
>
> Another related issue I didn't notice before: the only way to construct an
> index or bounds type is from an initializer_list. There is no (explicit)
> conversion from std::array, for instance. It is quite likely that an index
> or bounds value would be computed by some other code, that may use a
> different representation.
>
>>
>> > Furthermore, bounds and index essentially represent a
>> > fixed-size discrete vector type, i.e. an augmented interface for
>> std::array.
>> > Arguably the interface of std::array should just be extended to add
>> > component-wise operators instead. Also, a much more comprehensive set
>> of
>> > component-wise operations should be provided. A statically-sized
>> vector
>> > type is sorely needed in C++, but it does not make sense to standardize
>> > these limited, single-purposes types when they could be, and should be,
>> much
>> > more general.
>>
>> We don't necessarily want to go for the most general possible type all at
>> once.
>>
>
> Certainly there is a large design space, but that is a reason to be
> cautious about standardizing anything. Given the long turn around time for
> revisions to C++, it doesn't make sense to standardize a partial solution;
> better to work out a good, complete interface outside the standard. Given
> that there is no standard fixed-length vector, users will be tempted to use
> index as one, but will quickly find it to be lacking in important
> functionality.
>
>
>> > Other omissions from index and bounds include:
>> > 1. no data() access to the components
>> > 2. no iterators over components for index or bound
>>
>> How are those related to indexing?
>>
>
> Maybe I want to print out the index, by iterating over the components.
> Maybe I want to convert the index to/from another representation using the
> raw array representation. An index is just a value in the program, and
> there is no way of knowing what operations the user may want to perform on
> it. The philosophy of C++ is to not get in the user's way.
>
>
>>
>> > 3. the iterators for bounds iterate over positions, but are
>> inefficient
>> > without segment/hierarchical iterators.
>>
>> Show us your measurements when you make an efficiency claim.
>>
>
> Alright, fair enough. Still, it would be nice to be able to generate code
> equivalent to N nested for loops for an N dimensional bounds.
>
>
>
>> > This position iteration is clearly
>> > useful but the facility at present is very limited: it should likely be
>> > presented as a multidimensional range itself, and support a non-zero
>> origin.
>>
>> What's the use case?
>
>
> This is useful in conjunction with a multdimensional, multiple range
> for_each. Suppose we have two multidimensional arrays x_array and y_array
> with the same bounds. We then might want:
> for_each(x_array, y_array, [&](auto &x, auto &y) { x += y; });
>
> However, we might also want:
>
> for_each(x_array, y_array, x_array.bounds(), [&](auto &x, auto &y, auto
> pos) {
> if (x != y) std::cout << "mismatch at position " << pos << std::endl;
> });
>
> This could also be further improved by the use of macros or a language
> extension that allows x and x_array, y and y_array, x_array.bounds() and
> pos to be syntactically related.
>
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_519_6490396.1402893504503
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><p>Thank you Jeffrey for adding me on the thread and for y=
our initial response -- which I almost universally agree with.</p><p>Jeremy=
, thank you for your detailed feedback. First, I believe that most of the d=
isagreement stems from the approach to the proposal. You've commented =
that "it doesn't make sense to standardize a partial solution; better to wo=
rk out a good, complete interface outside the standard". This is opposite t=
o the "crawl, walk, run" philosophy we have taken when writing this documen=
t up. We recognize that we have only explored some parts of the design spac=
e, because as you have rightly observed our experience is limited to C++ AM=
P, which constitutes only a specific data parallel approach to algorithms. =
Of course we believe that this is a solid foundation that can be generalize=
d and built upon, hence the proposal. But we deliberately avoided any desig=
n decisions which may be controversial or result in a prolonged tug of war,=
instead intending for subsequent proposals (not necessarily authored by us=
) to fill the gaps. Certainly, should anything being proposed now be a poss=
ible hindrance for any reasonable extension, it must be addressed sooner th=
an later, however I think that none of the lacks pointed by you belong to t=
his category.</p><p>>>> Some particular issues with the proposed d=
esign include: <br>>>> <br>>>> - No iterators are provide=
d for array_view or strided_array_view, a clear <br>>>> omission i=
n the interface. For a multidimensional array, there are two <br>>=
>> obvious types of iteration that may be desired: <br>>>>&n=
bsp; 1. iterating over just the first dimension; <br>>>>&nbs=
p; 2. iterating over a flat view of all of the elements. For a =
strided <br>>>> array, iterating over a flat view cannot be done e=
fficiently without <br>>>> segmented/hierarchical iterators. <br>&=
gt;>> Which of these should be the default (i.e. provided=
through begin() and <br>>>> end() rather than through some adapto=
r) is not clear, <br>>><br>>> From the Zen of Python, "In the f=
ace of ambiguity, refuse the <br>>> temptation to guess." <br>><br=
>> That's true, but no adaptors to provide the functionality unambiguous=
ly are provided either. For the particular case of a one-dimensional =
array, there is no ambiguity, and not being able to easily use array_view w=
ith standard algorithms or range-based for is a serious usability issue.&nb=
sp; This will only become worse if/when standard algorithm overloads that t=
ake ranges rather than iterator pairs are added.</p><p>To the list of possi=
ble alternatives, I would add an option that was proposed somewhere in the =
prior discussion on the proposal -- "hierarchical" array_view/elemental ite=
rator, i.e. an iterator that for array_view<T, Rank> with Rank > 1=
iterates over array_view<T, Rank-1>; and over T for Rank =3D=3D 1.<b=
r>It is however worth pointing out that in the first round of review with L=
EWG at Issaquah meeting, the vocal unchallenged feedback for iterators was =
"I do not want iterators for the views", thus we did not put much effort in=
to contemplating adding any. Even though the choice for Rank =3D=3D 1 is "o=
bvious", we consider this a corner case for array_view, and would rather ha=
ve a holistic approach.<br>There remains the possibility to add some form o=
f the iterator as a future extension.</p><p>>>> - No data() access=
member for strided_array_view. This is presumably <br>>>> o=
mitted because the memory is non-contiguous, but given that <br>>>>=
; strided_array_view is a thin wrapper, there has to be a convenient way to=
<br>>>> get at the underlying memory. <br>>><br>>> Wh=
y "has to"? <br>><br>> Because the user might want to convert the arr=
ay to another representation for use by another piece of code/library, e.g.=
FFTW or Eigen, CUDA memcpy, etc. Under the proposed interface, for a=
3-dimensional stided array view, you have to use &arr[0][0][0]. =
This is even worse than having to do &vec[0] for std::vector, since the=
same expression cannot be used independent of the dimensionality.</p><p>da=
ta() on strided_array_view could be harmful, as there is no guarantee of co=
ntiguity, which a developer / function template might assume. Please note t=
hat for every other case in the Standard, the range [data(), data()+size())=
is valid/safe, thus providing other semantics here would be dubious.<br>Gr=
anted, one can perform &arr[0][0][0] and run afoul, but that is no diff=
erent than e.g. &my_list.front().<br>It could be possible to provide "u=
nsafe_data()" interface, which would have to be consumed along with stride(=
), however I do not see much benefit here over just using the "proper" inte=
rface -- bounds() and operator[]().</p><p>>>> - Slicing is limited=
: it is not possible to take a slice in a dimension <br>>>> other =
than the first. <br>>><br>>> I think that's called "section()".=
<br>><br>> Well, that takes a "section" but does not reduce the dime=
nsionality like "slice". [...] Certainly there is a large design space for =
general subscripting and it almost certainly requires a fair amount of temp=
late metaprogramming, but this is very useful functionality</p><p>Yes, slic=
ing and sectioning are slightly different. It is however important to note =
that slicing in its current form always guarantees the contiguity of the re=
sult, thus the return type may be array_view. The more general cases (as yo=
u are describing) would result in a potentially strided resulting view, whi=
ch would need to be typed strided_array_view. This is why it is important I=
MO to distinguish these two cases.<br>In the current form of the proposal w=
e decided to provide the minimal design -- only the first version, which in=
our opinion might be handy for users used to C-style multidimensional addr=
essing (i.e. arr[3][1][4] v arr[{3, 1, 4}]), which actually you used above =
:).<br>The latter generic case can be trivially added as an extension to th=
e interface. I agree it may be useful, and if the current design is accepte=
d for the TS, I encourage you to propose such extension (or nag us for foll=
ow ups :)).</p><p>>>> - It is not clear whether it is really usefu=
l to have bounds and index be <br>>>> separate types (though shoul=
d probably at least be explicitly convertible to <br>>>> each othe=
r). <br>>><br>>> It adds a bit of type safety. Adding two bound=
s, for instance, doesn't <br>>> make a lot of sense. <br>><br>>=
I agree that type safety is in principle useful, but it is impossible to p=
redict what relationships might hold in any given program, and so there is =
the question of whether the safety it adds is worth the cost of having to e=
xplicitly work around it in the cases that it is too restrictive. Cer=
tainly if they are separate types there needs to be a way to (explicitly) c=
onvert.</p><p>I agree with both of you :).<br>These are separate types, bec=
ause their meaning and semantics are different. It was also discussed in N3=
851, Appendix, II. The mental model I use for reasoning about them is: inde=
x ~ vector and bounds ~ point (more specifically: a zero-bound, axis-aligne=
d rectangle described by its maximum point), which makes the set of availab=
le operators apparent.<br>I understand the explicit conversions between the=
se two types, even though not theoretically sound, might be handy in practi=
ce and should be added.</p><p>> As a specific example, consider if we wa=
nt to compute the bounds of a valid convolution if we have an array x and a=
filter k. The bounds of the result are: x.bounds - k.bounds + 1.&nbs=
p; None of the arithmetic operators defined in the proposal help me with th=
at; I'd just have to write a loop. Even if the arithmetic operators w=
eren't limited by the bounds/index distinction, there would still be no way=
to create a constant-valued vector, i.e. to handle the constant 1.</p><p>E=
xplicit conversions would help with the first part, right? I hope you are a=
lso not suggesting any such conversion should be implicit?<br>However I do =
not really understand what do you mean in the second part, "a constant-valu=
ed vector". We purposefully allow to create both bounds<1> and index&=
lt;1> from a scalar; and disallow such operation for Rank > 1 (mostly=
because the semantics are not obvious, e.g. for rank 2, should index<2&=
gt;{16} be {0, 16}, {16, 0} or {16, 16}).<br>So net-net, in your example yo=
u should be able to do: x.bounds - index<2>{k.bounds} + {1, 1}. It a =
little more long-winded, but IMO easier to comprehend than the original.</p=
><p>> Another related issue I didn't notice before: the only way to cons=
truct an index or bounds type is from an initializer_list. There is n=
o (explicit) conversion from std::array, for instance. It is quite li=
kely that an index or bounds value would be computed by some other code, th=
at may use a different representation.</p><p>Yes, we should add (const valu=
e_type* begin, const value_type* end) constructors for both types. <rant=
>Or it should be possible to create initializer_list explicitly from suc=
h pair which would solve this issue universally.</rant></p><p>>>=
;> Furthermore, bounds and index essentially represent a <br>>>>=
; fixed-size discrete vector type, i.e. an augmented interface for std::arr=
ay. <br>>>> Arguably the interface of std::array should just be ex=
tended to add <br>>>> component-wise operators instead. Also=
, a much more comprehensive set of <br>>>> component-wise operatio=
ns should be provided. A statically-sized vector <br>>>> typ=
e is sorely needed in C++, but it does not make sense to standardize <br>&g=
t;>> these limited, single-purposes types when they could be, and sho=
uld be, much <br>>>> more general. <br>>><br>>> We don=
't necessarily want to go for the most general possible type all at once<br=
>><br>> Certainly there is a large design space, but that is a reason=
to be cautious about standardizing anything. [...]</p><p>There are two sep=
arate issue raised here:<br>- Why novel types -- this is primarily to intro=
duce "vocabulary" types and allow to discriminate index and bounds, as they=
have different semantics, as discussed before. This was also touched upon =
in the previously referred N3851, Appendix, II.<br>- Why so little function=
ality -- I agree with Jeffrey on this, and I have described more of the phi=
losophy in the introduction. I would be interested however what exactly you=
mean by "a much more comprehensive set of component-wise operations". Havi=
ng said that, I assume this is something that can be added later as a pure =
extension, correct?</p><p>> Given the long turn around time for revision=
s to C++</p><p>The Committee is certainly trying to get better at quicker i=
terations, let's not be discouraged by the ghosts of the past...</p><p>>=
Other omissions from index and bounds include:<br>> 1. no data() =
access to the components<br>> 2. no iterators over components for =
index or bound</p><p>index and bounds are not containers and should not be =
used as such. For the limited number of scenario where I want to use/modify=
indeterminate number of components, it was always sufficient for me to use=
a raw loop, and operator[]...<br>In case I'm wrong, these as well should b=
e easy to add later as extensions.</p><p>> for_each(x_array, y_array, x_=
array.bounds(), [&](auto &x, auto &y, auto pos) {<br>> =
if (x !=3D y) std::cout << "mismatch at position " << po=
s << std::endl;<br>> });</p><p>I assume the idea here is that such=
"for_each" uses begin(X), end(X) for all provided arguments, passing deref=
erenced iterators to the function object. If so, I do not see how the curre=
nt semantics of bounds_iterator would get into way here? It should just wor=
k as is, no?<br>Actually, it should be possible to write the following with=
just the current proposal and the current standard for_each:<br> auto=
x_av =3D array_view<N>{x_array};<br> auto y_av =3D array_view&l=
t;N>{y_array};<br> for_each(begin(x_av.bounds()), end(x_av.bounds()=
), [&](index<N> pos) {<br> if(x_av[pos] !=3D y_av[pos]) std=
::cout << "mismatch at position " << pos << std::endl;<br=
> });</p><p>> From my perspective, the only way to properly explore=
this design space for multidimensional arrays/containers/ranges is through=
an actively developed and widely used open source library.</p><div>Our (Mi=
crosoft) prototype implementation is in the pipeline to be published as an =
open source project. It should happen really soon, and I hope it will help =
to convey the discussed ideas.</div><div><br></div><div><br><br>On Friday, =
June 13, 2014 9:30:45 PM UTC-7, Jeremy Maitin-Shepard wrote:</div><blockquo=
te class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; padding-left: =
1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-=
left-style: solid;"><div dir=3D"ltr"><br><br>On Friday, June 13, 2014 5:54:=
21 PM UTC-7, Jeffrey Yasskin wrote:<blockquote class=3D"gmail_quote" style=
=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(20=
4, 204, 204); border-left-width: 1px; border-left-style: solid;">Thanks for=
the comments. Lukasz, FYI in case you're not on this list.
<br>
<br>On Fri, Jun 13, 2014 at 9:17 PM, Jeremy Maitin-Shepard
<br><<a>jer...@jeremyms.com</a>> wrote:
<br>> C++ is sorely in need of a "vocabulary type" for representing poin=
ter
<br>> ranges. It is also sorely in need of a good, standard librar=
y for
<br>> multidimensional arrays/containers/ranges. While the design =
space for a
<br>> one-dimensional, unstrided array view is fairly limited, the desig=
n space
<br>> for a multidimensional array/container/range is very large. =
Finding the
<br>> right design certainly involves numerous design iterations and ver=
y
<br>> substantial user experience. While the proposed design in n3=
976 is a very
<br>> useful starting point, it would be premature to standardize it at =
this
<br>> point, as it is far from comprehensive and it is difficult to know=
how well
<br>> the proposed interface could be extended to provide a larger set o=
f
<br>> functionality on par with the facilities available in many other l=
anguages.
<br>
<br>According to N3851,
<br><a onmousedown=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F=
%2Fmsdn.microsoft.com%2Fen-us%2Flibrary%2Fvstudio%2Fhh305260(v%3Dvs.110).as=
px\46sa\75D\46sntz\0751\46usg\75AFQjCNGutdo3UFl--fatoQp9kucVYtiHcg';return =
true;" onclick=3D"this.href=3D'http://www.google.com/url?q\75http%3A%2F%2Fm=
sdn.microsoft.com%2Fen-us%2Flibrary%2Fvstudio%2Fhh305260(v%3Dvs.110).aspx\4=
6sa\75D\46sntz\0751\46usg\75AFQjCNGutdo3UFl--fatoQp9kucVYtiHcg';return true=
;" href=3D"http://www.google.com/url?q=3Dhttp%3A%2F%2Fmsdn.microsoft.com%2F=
en-us%2Flibrary%2Fvstudio%2Fhh305260(v%3Dvs.110).aspx&sa=3DD&sntz=
=3D1&usg=3DAFQjCNGutdo3UFl--fatoQp9kucVYtiHcg" target=3D"_blank">http:/=
/msdn.microsoft.com/en-<wbr>us/library/vstudio/hh305260(v=3D<wbr>vs.110).as=
px</a>
<br>seems to be that user experience. We'll also have a chance to get more
<br>experience while this is in a TS before being standardized.
<br></blockquote><div><br>I saw that, but the fact that it is part of AMP s=
uggests that the focus is a bit more specialized than a general multidimens=
ional array.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 20=
4); border-left-width: 1px; border-left-style: solid;">
<br>> Some particular issues with the proposed design include:
<br>>
<br>> - No iterators are provided for array_view or strided_array_view, =
a clear
<br>> omission in the interface. For a multidimensional array, the=
re are two
<br>> obvious types of iteration that may be desired:
<br>> 1. iterating over just the first dimension;
<br>> 2. iterating over a flat view of all of the elements.  =
;For a strided
<br>> array, iterating over a flat view cannot be done efficiently witho=
ut
<br>> segmented/hierarchical iterators.
<br>> Which of these should be the default (i.e. provided through=
begin() and
<br>> end() rather than through some adaptor) is not clear,
<br>
<br>From the Zen of Python, "In the face of ambiguity, refuse the
<br>temptation to guess."
<br>
<br></blockquote><div>That's true, but no adaptors to provide the functiona=
lity unambiguously are provided either. For the particular case of a =
one-dimensional array, there is no ambiguity, and not being able to easily =
use array_view with standard algorithms or range-based for is a serious usa=
bility issue. This will only become worse if/when standard algorithm =
overloads that take ranges rather than iterator pairs are added.<br><br></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; pa=
dding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: =
1px; border-left-style: solid;">> - No data() access member for strided_=
array_view. This is presumably
<br>> omitted because the memory is non-contiguous, but given that
<br>> strided_array_view is a thin wrapper, there has to be a convenient=
way to
<br>> get at the underlying memory.
<br>
<br>Why "has to"?
<br></blockquote><div><br>Because the user might want to convert the array =
to another representation for use by another piece of code/library, e.g. FF=
TW or Eigen, CUDA memcpy, etc. Under the proposed interface, for a 3-=
dimensional stided array view, you have to use &arr[0][0][0]. Thi=
s is even worse than having to do &vec[0] for std::vector, since the sa=
me expression cannot be used independent of the dimensionality.<br> </=
div><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; p=
adding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width:=
1px; border-left-style: solid;">
<br>> Given the definition of Viewable, the use of
<br>> the name data() might be problematic as it would allow the incorre=
ct (albeit
<br>> explicit) conversion from strided_array_view to array_view. =
Possibly
<br>> Viewable should be traits-based rather than based only on the pres=
ence of
<br>> data() and size().
<br>
<br>The downside of traits, of course, is that we'd burden users with
<br>marking their types. If nearly all existing contiguous types expose
<br>data()/size(), the library can save people work by using them.<br></blo=
ckquote><div><br>That's a valid point.<br> </div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-=
left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: =
solid;">
<br>> - Slicing is limited: it is not possible to take a slice in a dime=
nsion
<br>> other than the first.
<br>
<br>I think that's called "section()".
<br></blockquote><div><br>Well, that takes a "section" but does not reduce =
the dimensionality like "slice". For instance, suppose I have a two-d=
imensional 20x10 array arr and want to do the equivalent of the numpy:<br><=
br>arr[:,5]<br> <br>and obtain a 1-dimensional strided_array_view of l=
ength 20.<br><br>Certainly there is a large design space for general subscr=
ipting and it almost certainly requires a fair amount of template metaprogr=
amming, but this is very useful functionality.<br><br></div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; b=
order-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-s=
tyle: solid;">
<br>> - operator++ and operator-- on index seem very questionable.  =
;The semantics
<br>> are rather arbitrary and not that likely to be useful except for a=
single
<br>> dimension anyway.
<br>
<br>They're marked with "Requires: Rank =3D=3D 1." This should be more like
<br>"Ill-formed unless ...", but the goal is there.
<br></blockquote><div>Sorry, I missed that requirement. No problem th=
ere then.<br> </div><blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204=
); border-left-width: 1px; border-left-style: solid;">
<br>> - It is not clear whether it is really useful to have bounds and i=
ndex be
<br>> separate types (though should probably at least be explicitly conv=
ertible to
<br>> each other).
<br>
<br>It adds a bit of type safety. Adding two bounds, for instance, doesn't
<br>make a lot of sense.
<br></blockquote><div>I agree that type safety is in principle useful, but =
it is impossible to predict what relationships might hold in any given prog=
ram, and so there is the question of whether the safety it adds is worth th=
e cost of having to explicitly work around it in the cases that it is too r=
estrictive. Certainly if they are separate types there needs to be a =
way to (explicitly) convert. Right now the only way to convert is to =
write a manual loop and use operator[], or possibly use operator[] to obtai=
n pointers and then call memcpy or std::copy.<br><br>As a specific example,=
consider if we want to compute the bounds of a valid convolution if we hav=
e an array x and a filter k. The bounds of the result are: x.bounds -=
k.bounds + 1. None of the arithmetic operators defined in the propos=
al help me with that; I'd just have to write a loop. Even if the arit=
hmetic operators weren't limited by the bounds/index distinction, there wou=
ld still be no way to create a constant-valued vector, i.e. to handle the c=
onstant 1.<br><br>Another related issue I didn't notice before: the only wa=
y to construct an index or bounds type is from an initializer_list. T=
here is no (explicit) conversion from std::array, for instance. It is=
quite likely that an index or bounds value would be computed by some other=
code, that may use a different representation.<br></div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; bor=
der-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-sty=
le: solid;">
<br>> Furthermore, bounds and index essentially represent a
<br>> fixed-size discrete vector type, i.e. an augmented interface for s=
td::array.
<br>> Arguably the interface of std::array should just be extended to ad=
d
<br>> component-wise operators instead. Also, a much more comprehe=
nsive set of
<br>> component-wise operations should be provided. A statically-s=
ized vector
<br>> type is sorely needed in C++, but it does not make sense to standa=
rdize
<br>> these limited, single-purposes types when they could be, and shoul=
d be, much
<br>> more general.
<br>
<br>We don't necessarily want to go for the most general possible type all =
at once.
<br></blockquote><div><br>Certainly there is a large design space, but that=
is a reason to be cautious about standardizing anything. Given the l=
ong turn around time for revisions to C++, it doesn't make sense to standar=
dize a partial solution; better to work out a good, complete interface outs=
ide the standard. Given that there is no standard fixed-length vector=
, users will be tempted to use index as one, but will quickly find it to be=
lacking in important functionality.<br></div><div> </div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex=
; border-left-color: rgb(204, 204, 204); border-left-width: 1px; border-lef=
t-style: solid;">> Other omissions from index and bounds include:
<br>> 1. no data() access to the components
<br>> 2. no iterators over components for index or bound
<br>
<br>How are those related to indexing?
<br></blockquote><div><br>Maybe I want to print out the index, by iterating=
over the components. Maybe I want to convert the index to/from anoth=
er representation using the raw array representation. An index is jus=
t a value in the program, and there is no way of knowing what operations th=
e user may want to perform on it. The philosophy of C++ is to not get=
in the user's way.<br> </div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(20=
4, 204, 204); border-left-width: 1px; border-left-style: solid;">
<br>> 3. the iterators for bounds iterate over positions, but are =
inefficient
<br>> without segment/hierarchical iterators.
<br>
<br>Show us your measurements when you make an efficiency claim.
<br></blockquote><div><br>Alright, fair enough. Still, it would be ni=
ce to be able to generate code equivalent to N nested for loops for an N di=
mensional bounds. <br></div><div><br> </div><blockquote class=3D"gmail=
_quote" style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-=
color: rgb(204, 204, 204); border-left-width: 1px; border-left-style: solid=
;">> This position iteration is clearly
<br>> useful but the facility at present is very limited: it should like=
ly be
<br>> presented as a multidimensional range itself, and support a non-ze=
ro origin.
<br>
<br>What's the use case?</blockquote><div><br>This is useful in conjunction=
with a multdimensional, multiple range for_each. Suppose we have two=
multidimensional arrays x_array and y_array with the same bounds. We=
then might want:<br>for_each(x_array, y_array, [&](auto &x, auto &=
amp;y) { x +=3D y; });<br><br>However, we might also want:<br><br>for_each(=
x_array, y_array, x_array.bounds(), [&](auto &x, auto &y, auto =
pos) {<br> if (x !=3D y) std::cout << "mismatch at position " &=
lt;< pos << std::endl;<br>});<br> <br>This could also be furt=
her improved by the use of macros or a language extension that allows x and=
x_array, y and y_array, x_array.bounds() and pos to be syntactically relat=
ed.<br></div></div></blockquote></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_519_6490396.1402893504503--
.
Author: Jeremy Maitin-Shepard <jeremy@jeremyms.com>
Date: Mon, 16 Jun 2014 17:49:37 -0700
Raw View
--047d7b874e5aa5bb4304fbfd84c1
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Sun, Jun 15, 2014 at 9:38 PM, =C5=81ukasz Mendakiewicz <
l.mendakiewicz@live.com> wrote:
> Thank you Jeffrey for adding me on the thread and for your initial
> response -- which I almost universally agree with.
>
> Jeremy, thank you for your detailed feedback. First, I believe that most
> of the disagreement stems from the approach to the proposal. You've
> commented that "it doesn't make sense to standardize a partial solution;
> better to work out a good, complete interface outside the standard". This
> is opposite to the "crawl, walk, run" philosophy we have taken when writi=
ng
> this document up. We recognize that we have only explored some parts of t=
he
> design space, because as you have rightly observed our experience is
> limited to C++ AMP, which constitutes only a specific data parallel
> approach to algorithms. Of course we believe that this is a solid
> foundation that can be generalized and built upon, hence the proposal. Bu=
t
> we deliberately avoided any design decisions which may be controversial o=
r
> result in a prolonged tug of war, instead intending for subsequent
> proposals (not necessarily authored by us) to fill the gaps. Certainly,
> should anything being proposed now be a possible hindrance for any
> reasonable extension, it must be addressed sooner than later, however I
> think that none of the lacks pointed by you belong to this category.
>
I think it is basically impossible to nail down even a "minimal" interface
without considering the design of a complete library. If you looked at 10
different, widely-used C++ multidimensional array libraries and saw that
all of their interfaces shared a given attribute, then standardizing that
attribute of the interface would likely be a safe choice. Obviously that
is not the case here, though.
Some examples of design options:
- Make array_view parameterized by the pointer type, rather than the value
type. This allows it to hold smart pointers of various types, or a pointer
that represents GPU memory, or a smart pointer that represents GPU memory,
etc. If the pointer is to GPU memory, reading and writing won't work (and
won't be allowed at compile-time), but the indexing, slicing, sectioning
and other operations on the array_view representation itself can still be
used. This is the decision I took in my own in-house library. Allowing
array_view to hold a smart pointer means you don't need a separate type to
represent an array_view with ownership. (Sectioning and slicing produces a
result with the pointer decayed to a regular pointer.) You can also use a
__restrict__ pointer for an array_view type used as a function parameter to
indicate lack of aliasing.
- Make bounds and index just generic fixed-size vector types. In this case
iterators on bounds should iterate over the components, rather than iterate
over coordinates within the bounds.
- More generally, the proposal distinguishes between array_view and
strided_array_view, but doesn't allow for more fine-grained information to
be provided at compile time, such as the number of trailing contiguous
dimensions, alignment information, etc.
> >>> Some particular issues with the proposed design include:
> >>>
> >>> - No iterators are provided for array_view or strided_array_view, a
> clear
> >>> omission in the interface. For a multidimensional array, there are
> two
> >>> obvious types of iteration that may be desired:
> >>> 1. iterating over just the first dimension;
> >>> 2. iterating over a flat view of all of the elements. For a stride=
d
> >>> array, iterating over a flat view cannot be done efficiently without
> >>> segmented/hierarchical iterators.
> >>> Which of these should be the default (i.e. provided through begin()
> and
> >>> end() rather than through some adaptor) is not clear,
> >>
> >> From the Zen of Python, "In the face of ambiguity, refuse the
> >> temptation to guess."
> >
> > That's true, but no adaptors to provide the functionality unambiguously
> are provided either. For the particular case of a one-dimensional array,
> there is no ambiguity, and not being able to easily use array_view with
> standard algorithms or range-based for is a serious usability issue. Thi=
s
> will only become worse if/when standard algorithm overloads that take
> ranges rather than iterator pairs are added.
>
> To the list of possible alternatives, I would add an option that was
> proposed somewhere in the prior discussion on the proposal --
> "hierarchical" array_view/elemental iterator, i.e. an iterator that for
> array_view<T, Rank> with Rank > 1 iterates over array_view<T, Rank-1>; an=
d
> over T for Rank =3D=3D 1.
>
Yes, that is a better way of expressing what I meant by "iterating over
just the first dimension". I believe this makes the most sense, but then
it becomes desirable to have size() be the size of the first dimension for
consistency with the iterators, and instead add a num_elements() that
returns the total number of elements. The correct definition of size() is
hard to decide without figuring out how iterators should work.
The other issue is that if the iterators are hierarchical, you need a new
hierarchical for_each that effectively expands to N nested for loops for
N-dimensional arrays and which can operate on multiple arrays (of the same
size). This way you can express element-wise operations without any
overhead.
> It is however worth pointing out that in the first round of review with
> LEWG at Issaquah meeting, the vocal unchallenged feedback for iterators w=
as
> "I do not want iterators for the views", thus we did not put much effort
> into contemplating adding any. Even though the choice for Rank =3D=3D 1 i=
s
> "obvious", we consider this a corner case for array_view, and would rathe=
r
> have a holistic approach.
> There remains the possibility to add some form of the iterator as a futur=
e
> extension.
>
Well, you can take my comments as a challenge to that view. Rank =3D=3D 1 =
may
be a "corner" case, but is likely to be used more frequently than all other
cases combined. A 1-dimensional array view that can't be used with
for-range loops, boost (or std?) range adapters, etc. is a non-starter.
> >>> - No data() access member for strided_array_view. This is presumably
> >>> omitted because the memory is non-contiguous, but given that
> >>> strided_array_view is a thin wrapper, there has to be a convenient wa=
y
> to
> >>> get at the underlying memory.
> >>
> >> Why "has to"?
> >
> > Because the user might want to convert the array to another
> representation for use by another piece of code/library, e.g. FFTW or
> Eigen, CUDA memcpy, etc. Under the proposed interface, for a 3-dimension=
al
> stided array view, you have to use &arr[0][0][0]. This is even worse tha=
n
> having to do &vec[0] for std::vector, since the same expression cannot be
> used independent of the dimensionality.
>
> data() on strided_array_view could be harmful, as there is no guarantee o=
f
> contiguity, which a developer / function template might assume. Please no=
te
> that for every other case in the Standard, the range [data(),
> data()+size()) is valid/safe, thus providing other semantics here would b=
e
> dubious.
> Granted, one can perform &arr[0][0][0] and run afoul, but that is no
> different than e.g. &my_list.front().
> It could be possible to provide "unsafe_data()" interface, which would
> have to be consumed along with stride(), however I do not see much benefi=
t
> here over just using the "proper" interface -- bounds() and operator[]().
>
Calling it noncontiguous_data() is fine, though certainly then array_view
should have an noncontiguous_data() (in addition to data()) as well for
consistency. I don't think unsafe_data is really the right name, though
the functionality is more important than the name. &arr[0][0][0] has the
disadvantage that it is more verbose and doesn't allow for writing generic
code that works with any number of dimensions. Just using the "proper"
interface isn't a solution. A fundamental component like multidimensional
arrays cannot be a "walled garden". The (pointer, bounds, strides)
representation, which numerous other libraries like FFTW use as well,
should be transparent.
> >>> - Slicing is limited: it is not possible to take a slice in a
> dimension
> >>> other than the first.
> >>
> >> I think that's called "section()".
> >
> > Well, that takes a "section" but does not reduce the dimensionality lik=
e
> "slice". [...] Certainly there is a large design space for general
> subscripting and it almost certainly requires a fair amount of template
> metaprogramming, but this is very useful functionality
>
> Yes, slicing and sectioning are slightly different. It is however
> important to note that slicing in its current form always guarantees the
> contiguity of the result, thus the return type may be array_view. The mor=
e
> general cases (as you are describing) would result in a potentially strid=
ed
> resulting view, which would need to be typed strided_array_view. This is
> why it is important IMO to distinguish these two cases.
> In the current form of the proposal we decided to provide the minimal
> design -- only the first version, which in our opinion might be handy for
> users used to C-style multidimensional addressing (i.e. arr[3][1][4] v
> arr[{3, 1, 4}]), which actually you used above :).
> The latter generic case can be trivially added as an extension to the
> interface. I agree it may be useful, and if the current design is accepte=
d
> for the TS, I encourage you to propose such extension (or nag us for foll=
ow
> ups :)).
>
> >>> - It is not clear whether it is really useful to have bounds and inde=
x
> be
> >>> separate types (though should probably at least be explicitly
> convertible to
> >>> each other).
> >>
> >> It adds a bit of type safety. Adding two bounds, for instance, doesn't
> >> make a lot of sense.
> >
> > I agree that type safety is in principle useful, but it is impossible t=
o
> predict what relationships might hold in any given program, and so there =
is
> the question of whether the safety it adds is worth the cost of having to
> explicitly work around it in the cases that it is too restrictive.
> Certainly if they are separate types there needs to be a way to
> (explicitly) convert.
>
> I agree with both of you :).
> These are separate types, because their meaning and semantics are
> different. It was also discussed in N3851, Appendix, II. The mental model=
I
> use for reasoning about them is: index ~ vector and bounds ~ point (more
> specifically: a zero-bound, axis-aligned rectangle described by its maxim=
um
> point), which makes the set of available operators apparent.
> I understand the explicit conversions between these two types, even thoug=
h
> not theoretically sound, might be handy in practice and should be added.
>
If we follow that logic, a point is a vector from the origin. Therefore
index should just be Vector<ptrdiff_t,N> and bounds<N> could have a
Vector<ptrdiff_t,N> member. However, it seems like it would be simpler to
just have bounds be Vector<ptrdiff_t,N> as well and save the trouble of the
explicit conversions. What type of error does the bounds/index distinction
prevent? More generally, I am not sure why we shouldn't think of an index
as a point as well. If we want the last element in an array x, we have :
x.bounds() - 1 (or x.bounds() - {1,1, ...}). We want to use this as an
index, but the current operator definitions would have it be a bounds.
> > As a specific example, consider if we want to compute the bounds of a
> valid convolution if we have an array x and a filter k. The bounds of th=
e
> result are: x.bounds - k.bounds + 1. None of the arithmetic operators
> defined in the proposal help me with that; I'd just have to write a loop.
> Even if the arithmetic operators weren't limited by the bounds/index
> distinction, there would still be no way to create a constant-valued
> vector, i.e. to handle the constant 1.
>
> Explicit conversions would help with the first part, right? I hope you ar=
e
> also not suggesting any such conversion should be implicit?
> However I do not really understand what do you mean in the second part, "=
a
> constant-valued vector". We purposefully allow to create both bounds<1> a=
nd
> index<1> from a scalar; and disallow such operation for Rank > 1 (mostly
> because the semantics are not obvious, e.g. for rank 2, should index<2>{1=
6}
> be {0, 16}, {16, 0} or {16, 16}).
> So net-net, in your example you should be able to do: x.bounds -
> index<2>{k.bounds} + {1, 1}. It a little more long-winded, but IMO easier
> to comprehend than the original.
>
I don't think the explicit conversion to index adds to the clarity. Also,
the problem with {1, 1} is that it depends on the dimensionality. The
interface should be designed to be convenient for generic code. I would
suggest a Scalar<T> type generated by a wrapper function scalar, from which
bounds and index can be implicitly constructed and which can be used in all
of the operators.
> > Another related issue I didn't notice before: the only way to construct
> an index or bounds type is from an initializer_list. There is no
> (explicit) conversion from std::array, for instance. It is quite likely
> that an index or bounds value would be computed by some other code, that
> may use a different representation.
>
> Yes, we should add (const value_type* begin, const value_type* end)
> constructors for both types. <rant>Or it should be possible to create
> initializer_list explicitly from such pair which would solve this issue
> universally.</rant>
>
Okay, though initializer_list is not compile-time sized.
> >>> Furthermore, bounds and index essentially represent a
> >>> fixed-size discrete vector type, i.e. an augmented interface for
> std::array.
> >>> Arguably the interface of std::array should just be extended to add
> >>> component-wise operators instead. Also, a much more comprehensive se=
t
> of
> >>> component-wise operations should be provided. A statically-sized
> vector
> >>> type is sorely needed in C++, but it does not make sense to
> standardize
> >>> these limited, single-purposes types when they could be, and should
> be, much
> >>> more general.
> >>
> >> We don't necessarily want to go for the most general possible type all
> at once
> >
> > Certainly there is a large design space, but that is a reason to be
> cautious about standardizing anything. [...]
>
> There are two separate issue raised here:
> - Why novel types -- this is primarily to introduce "vocabulary" types an=
d
> allow to discriminate index and bounds, as they have different semantics,
> as discussed before. This was also touched upon in the previously referre=
d
> N3851, Appendix, II.
> - Why so little functionality -- I agree with Jeffrey on this, and I have
> described more of the philosophy in the introduction. I would be interest=
ed
> however what exactly you mean by "a much more comprehensive set of
> component-wise operations".
>
Almost anything could be useful (and I am thinking of the perspective of a
general fixed-size vector type, but these all apply to index/bounds as
well), but some particular examples: min, max, <, <=3D, =3D=3D, !=3D, >=3D,=
>. The
relational operations need to return a vector of bool, which isn't
compatible with index/bounds currently since they aren't parameterized by
the type. Obviously, though, it wouldn't make sense to call them index or
bounds if they are parameterized by a type.
> Having said that, I assume this is something that can be added later as a
> pure extension, correct?
>
Some of them, like min and max, could be unintrusive, though neither index
nor bounds would be a particularly meaningful choice as the return type.
> > Given the long turn around time for revisions to C++
>
> The Committee is certainly trying to get better at quicker iterations,
> let's not be discouraged by the ghosts of the past...
>
> > Other omissions from index and bounds include:
> > 1. no data() access to the components
> > 2. no iterators over components for index or bound
>
> index and bounds are not containers and should not be used as such. For
> the limited number of scenario where I want to use/modify indeterminate
> number of components, it was always sufficient for me to use a raw loop,
> and operator[]...
> In case I'm wrong, these as well should be easy to add later as extension=
s.
>
> > for_each(x_array, y_array, x_array.bounds(), [&](auto &x, auto &y, auto
> pos) {
> > if (x !=3D y) std::cout << "mismatch at position " << pos << std::end=
l;
> > });
>
> I assume the idea here is that such "for_each" uses begin(X), end(X) for
> all provided arguments, passing dereferenced iterators to the function
> object. If so, I do not see how the current semantics of bounds_iterator
> would get into way here? It should just work as is, no?
>
The idea is that it would generate N nested for loops for N-dimensional
array views, rather than an less efficient single for loop.
> Actually, it should be possible to write the following with just the
> current proposal and the current standard for_each:
> auto x_av =3D array_view<N>{x_array};
> auto y_av =3D array_view<N>{y_array};
> for_each(begin(x_av.bounds()), end(x_av.bounds()), [&](index<N> pos) {
> if(x_av[pos] !=3D y_av[pos]) std::cout << "mismatch at position " << po=
s
> << std::endl;
> });
>
Yes, but note that the iteration over bounds is more expensive and the
multiplication with all of the strides has to happen for every position.
> > From my perspective, the only way to properly explore this design space
> for multidimensional arrays/containers/ranges is through an actively
> developed and widely used open source library.
> Our (Microsoft) prototype implementation is in the pipeline to be
> published as an open source project. It should happen really soon, and I
> hope it will help to convey the discussed ideas.
>
That's good news. I think the best library is likely to be produced if the
users of the library and the developers of the library are one and the
same. Issues become apparent and the library interface can be tweaked to
correct them very quickly that way.
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
--047d7b874e5aa5bb4304fbfd84c1
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Sun, Jun 15, 2014 at 9:38 PM, =C5=81ukasz Mendakiewicz =
<span dir=3D"ltr"><<a href=3D"mailto:l.mendakiewicz@live.com" target=3D"=
_blank">l.mendakiewicz@live.com</a>></span> wrote:<br><div class=3D"gmai=
l_extra"><div class=3D"gmail_quote">
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div dir=3D"ltr"><p>Thank you Jeffrey for ad=
ding me on the thread and for your initial response -- which I almost unive=
rsally agree with.</p>
<p>Jeremy, thank you for your detailed feedback. First, I believe that most=
of the disagreement stems from the approach to the proposal. You've co=
mmented=C2=A0that "it doesn't make sense to standardize a partial =
solution; better to work out a good, complete interface outside the standar=
d". This is opposite to the "crawl, walk, run" philosophy we=
have taken when writing this document up. We recognize that we have only e=
xplored some parts of the design space, because as you have rightly observe=
d our experience is limited to C++ AMP, which constitutes only a specific d=
ata parallel approach to algorithms. Of course we believe that this is a so=
lid foundation that can be generalized and built upon, hence the proposal. =
But we deliberately avoided any design decisions which may be controversial=
or result in a prolonged tug of war, instead intending for subsequent prop=
osals (not necessarily authored by us) to fill the gaps. Certainly, should =
anything being proposed now be a possible hindrance for any reasonable exte=
nsion, it must be addressed sooner than later, however I think that none of=
the lacks pointed by you belong to this category.</p>
</div></blockquote><div>I think it is basically impossible to nail down eve=
n a "minimal" interface without considering the design of a compl=
ete library.=C2=A0 If you looked at 10 different, widely-used C++ multidime=
nsional array libraries and saw that all of their interfaces shared a given=
attribute, then standardizing that attribute of the interface would likely=
be a safe choice.=C2=A0 Obviously that is not the case here, though.<br>
<br>Some examples of design options:<br></div><div>- Make array_view parame=
terized by the pointer type, rather than the value type.=C2=A0 This allows =
it to hold smart pointers of various types, or a pointer that represents GP=
U memory, or a smart pointer that represents GPU memory, etc.=C2=A0 If the =
pointer is to GPU memory, reading and writing won't work (and won't=
be allowed at compile-time), but the indexing, slicing, sectioning and oth=
er operations on the array_view representation itself can still be used.=C2=
=A0 This is the decision I took in my own in-house library.=C2=A0 Allowing =
array_view to hold a smart pointer means you don't need a separate type=
to represent an array_view with ownership.=C2=A0 (Sectioning and slicing p=
roduces a result with the pointer decayed to a regular pointer.)=C2=A0 You =
can also use a __restrict__ pointer for an array_view type used as a functi=
on parameter to indicate lack of aliasing.<br>
<br></div><div>- Make bounds and index just generic fixed-size vector types=
..=C2=A0 In this case iterators on bounds should iterate over the components=
, rather than iterate over coordinates within the bounds.<br></div><div>=C2=
=A0<br>
</div><div>- More generally, the proposal distinguishes between array_view =
and strided_array_view, but doesn't allow for more fine-grained informa=
tion to be provided at compile time, such as the number of trailing contigu=
ous dimensions, alignment information, etc.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div class=3D""><p>&g=
t;>> Some particular issues with the proposed design include: <br>>=
;>> <br>
>>> - No iterators are provided for array_view or strided_array_vi=
ew, a clear <br>>>> omission in the interface.=C2=A0 For a multidi=
mensional array, there are two <br>>>> obvious types of iteration =
that may be desired: <br>
>>>=C2=A0=C2=A0 1. iterating over just the first dimension; <br>&g=
t;>>=C2=A0=C2=A0 2. iterating over a flat view of all of the elements=
..=C2=A0 For a strided <br>>>> array, iterating over a flat view ca=
nnot be done efficiently without <br>
>>> segmented/hierarchical iterators. <br>>>>=C2=A0=C2=A0=
Which of these should be the default (i.e. provided through begin() and <b=
r>>>> end() rather than through some adaptor) is not clear, <br>&g=
t;><br>
>> From the Zen of Python, "In the face of ambiguity, refuse the=
<br>>> temptation to guess." <br>><br>> That's true, =
but no adaptors to provide the functionality unambiguously are provided eit=
her.=C2=A0 For the particular case of a one-dimensional array, there is no =
ambiguity, and not being able to easily use array_view with standard algori=
thms or range-based for is a serious usability issue.=C2=A0 This will only =
become worse if/when standard algorithm overloads that take ranges rather t=
han iterator pairs are added.</p>
</div><p>To the list of possible alternatives, I would add an option that w=
as proposed somewhere in the prior discussion on the proposal -- "hier=
archical" array_view/elemental iterator, i.e. an iterator that for arr=
ay_view<T, Rank> with Rank > 1 iterates over array_view<T, Rank=
-1>; and over T for Rank =3D=3D 1.<br>
</p></div></blockquote><div>Yes, that is a better way of expressing what I =
meant by "iterating over just the first dimension".=C2=A0 I belie=
ve this makes the most sense, but then it becomes desirable to have size() =
be the size of the first dimension for consistency with the iterators, and =
instead add a num_elements() that returns the total number of elements.=C2=
=A0 The correct definition of size() is hard to decide without figuring out=
how iterators should work.<br>
<br></div><div>The other issue is that if the iterators are hierarchical, y=
ou need a new hierarchical for_each that effectively expands to N nested fo=
r loops for N-dimensional arrays and which can operate on multiple arrays (=
of the same size).=C2=A0 This way you can express element-wise operations w=
ithout any overhead.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><p>It is however wort=
h pointing out that in the first round of review with LEWG at Issaquah meet=
ing, the vocal unchallenged feedback for iterators was "I do not want =
iterators for the views", thus we did not put much effort into contemp=
lating adding any. Even though the choice for Rank =3D=3D 1 is "obviou=
s", we consider this a corner case for array_view, and would rather ha=
ve a holistic approach.<br>
There remains the possibility to add some form of the iterator as a future =
extension.</p></div></blockquote><div>Well, you can take my comments as a c=
hallenge to that view.=C2=A0 Rank =3D=3D 1 may be a "corner" case=
, but is likely to be used more frequently than all other cases combined.=
=C2=A0 A 1-dimensional array view that can't be used with for-range loo=
ps, boost (or std?) range adapters, etc. is a non-starter.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div class=3D""><p>&g=
t;>> - No data() access member for strided_array_view.=C2=A0 This is =
presumably <br>
>>> omitted because the memory is non-contiguous, but given that <=
br>>>> strided_array_view is a thin wrapper, there has to be a con=
venient way to <br>>>> get at the underlying memory. <br>>><=
br>
>> Why "has to"? <br>><br>> Because the user might wa=
nt to convert the array to another representation for use by another piece =
of code/library, e.g. FFTW or Eigen, CUDA memcpy, etc.=C2=A0 Under the prop=
osed interface, for a 3-dimensional stided array view, you have to use &=
;arr[0][0][0].=C2=A0 This is even worse than having to do &vec[0] for s=
td::vector, since the same expression cannot be used independent of the dim=
ensionality.</p>
</div><p>data() on strided_array_view could be harmful, as there is no guar=
antee of contiguity, which a developer / function template might assume. Pl=
ease note that for every other case in the Standard, the range [data(), dat=
a()+size()) is valid/safe, thus providing other semantics here would be dub=
ious.<br>
Granted, one can perform &arr[0][0][0] and run afoul, but that is no di=
fferent than e.g. &my_list.front().<br>It could be possible to provide =
"unsafe_data()" interface, which would have to be consumed along =
with stride(), however I do not see much benefit here over just using the &=
quot;proper" interface -- bounds() and operator[]().</p>
</div></blockquote><div>Calling it noncontiguous_data() is fine, though cer=
tainly then array_view should have an noncontiguous_data() (in addition to =
data()) as well for consistency.=C2=A0 I don't think unsafe_data is rea=
lly the right name, though the functionality is more important than the nam=
e.=C2=A0 &arr[0][0][0] has the disadvantage that it is more verbose and=
doesn't allow for writing generic code that works with any number of d=
imensions.=C2=A0 Just using the "proper" interface isn't a so=
lution.=C2=A0 A fundamental component like multidimensional arrays cannot b=
e a "walled garden".=C2=A0 The (pointer, bounds, strides) represe=
ntation, which numerous other libraries like FFTW use as well, should be tr=
ansparent.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><p></p><div class=3D"=
">>>> - Slicing is limited: it is not possible to take a slice in =
a dimension <br>
>>> other than the first. <br>>><br>>> I think that=
9;s called "section()". <br>><br></div>> Well, that takes a=
"section" but does not reduce the dimensionality like "slic=
e". [...] Certainly there is a large design space for general subscrip=
ting and it almost certainly requires a fair amount of template metaprogram=
ming, but this is very useful functionality<p>
</p><p>Yes, slicing and sectioning are slightly different. It is however im=
portant to note that slicing in its current form always guarantees the cont=
iguity of the result, thus the return type may be array_view. The more gene=
ral cases (as you are describing) would result in a potentially strided res=
ulting view, which would need to be typed strided_array_view. This is why i=
t is important IMO to distinguish these two cases.<br>
In the current form of the proposal we decided to provide the minimal desig=
n -- only the first version, which in our opinion might be handy for users =
used to C-style multidimensional addressing (i.e. arr[3][1][4] v arr[{3, 1,=
4}]), which actually you used above :).<br>
The latter generic case can be trivially added as an extension to the inter=
face. I agree it may be useful, and if the current design is accepted for t=
he TS, I encourage you to propose such extension (or nag us for follow ups =
:)).</p>
<div class=3D""><p>>>> - It is not clear whether it is really usef=
ul to have bounds and index be <br>>>> separate types (though shou=
ld probably at least be explicitly convertible to <br>>>> each oth=
er). <br>
>><br>>> It adds a bit of type safety. Adding two bounds, for i=
nstance, doesn't <br>>> make a lot of sense. <br>><br>> I a=
gree that type safety is in principle useful, but it is impossible to predi=
ct what relationships might hold in any given program, and so there is the =
question of whether the safety it adds is worth the cost of having to expli=
citly work around it in the cases that it is too restrictive.=C2=A0 Certain=
ly if they are separate types there needs to be a way to (explicitly) conve=
rt.</p>
</div><p>I agree with both of you :).<br>These are separate types, because =
their meaning and semantics are different. It was also discussed in N3851, =
Appendix, II. The mental model I use for reasoning about them is: index ~ v=
ector and bounds ~ point (more specifically: a zero-bound, axis-aligned rec=
tangle described by its maximum point), which makes the set of available op=
erators apparent.<br>
I understand the explicit conversions between these two types, even though =
not theoretically sound, might be handy in practice and should be added.</p=
></div></blockquote><div>If we follow that logic, a point is a vector from =
the origin.=C2=A0 Therefore index should just be Vector<ptrdiff_t,N> =
and bounds<N> could have a Vector<ptrdiff_t,N> member.=C2=A0 Ho=
wever, it seems like it would be simpler to just have bounds be Vector<p=
trdiff_t,N> as well and save the trouble of the explicit conversions.=C2=
=A0 What type of error does the bounds/index distinction prevent?=C2=A0 Mor=
e generally, I am not sure why we shouldn't think of an index as a poin=
t as well.=C2=A0 If we want the last element in an array x, we have : x.bou=
nds() - 1=C2=A0 (or x.bounds() - {1,1, ...}).=C2=A0 We want to use this as =
an index, but the current operator definitions would have it be a bounds.<b=
r>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div class=3D""><p>&g=
t; As a specific example, consider if we want to compute the bounds of a va=
lid convolution if we have an array x and a filter k.=C2=A0 The bounds of t=
he result are: x.bounds - k.bounds + 1.=C2=A0 None of the arithmetic operat=
ors defined in the proposal help me with that; I'd just have to write a=
loop.=C2=A0 Even if the arithmetic operators weren't limited by the bo=
unds/index distinction, there would still be no way to create a constant-va=
lued vector, i.e. to handle the constant 1.</p>
</div><p>Explicit conversions would help with the first part, right? I hope=
you are also not suggesting any such conversion should be implicit?<br>How=
ever I do not really understand what do you mean in the second part, "=
a constant-valued vector". We purposefully allow to create both bounds=
<1> and index<1> from a scalar; and disallow such operation for=
Rank > 1 (mostly because the semantics are not obvious, e.g. for rank 2=
, should index<2>{16} be {0, 16}, {16, 0} or {16, 16}).<br>
So net-net, in your example you should be able to do: x.bounds - index<2=
>{k.bounds} + {1, 1}. It a little more long-winded, but IMO easier to co=
mprehend than the original.</p></div></blockquote><div>I don't think th=
e explicit conversion to index adds to the clarity.=C2=A0 Also, the problem=
with {1, 1} is that it depends on the dimensionality.=C2=A0 The interface =
should be designed to be convenient for generic code.=C2=A0 I would suggest=
a Scalar<T> type generated by a wrapper function scalar, from which =
bounds and index can be implicitly constructed and which can be used in all=
of the operators.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l=
eft:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><div class=3D""><p>&g=
t; Another related issue I didn't notice before: the only way to constr=
uct an index or bounds type is from an initializer_list.=C2=A0 There is no =
(explicit) conversion from std::array, for instance.=C2=A0 It is quite like=
ly that an index or bounds value would be computed by some other code, that=
may use a different representation.</p>
</div><p>Yes, we should add (const value_type* begin, const value_type* end=
) constructors for both types. <rant>Or it should be possible to crea=
te initializer_list explicitly from such pair which would solve this issue =
universally.</rant></p>
</div></blockquote><div>Okay, though initializer_list is not compile-time s=
ized.<br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"=
margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"=
ltr"><div class=3D"">
>>> Furthermore, bounds and index essentially represent a <br>>=
>> fixed-size discrete vector type, i.e. an augmented interface for s=
td::array. <br>>>> Arguably the interface of std::array should jus=
t be extended to add <br>
>>> component-wise operators instead.=C2=A0 Also, a much more comp=
rehensive set of <br>>>> component-wise operations should be provi=
ded.=C2=A0 A statically-sized vector <br>>>> type is sorely needed=
in C++, but it does not make sense to standardize <br>
>>> these limited, single-purposes types when they could be, and s=
hould be, much <br>>>> more general. <br>>><br>>> We d=
on't necessarily want to go for the most general possible type all at o=
nce<br>
><br></div>> Certainly there is a large design space, but that is a r=
eason to be cautious about standardizing anything. [...]<p></p><p>There are=
two separate issue raised here:<br>- Why novel types -- this is primarily =
to introduce "vocabulary" types and allow to discriminate index a=
nd bounds, as they have different semantics, as discussed before. This was =
also touched upon in the previously referred N3851, Appendix, II.<br>
- Why so little functionality -- I agree with Jeffrey on this, and I have d=
escribed more of the philosophy in the introduction. I would be interested =
however what exactly you mean by "a much more comprehensive set of com=
ponent-wise operations".</p>
</div></blockquote><div>Almost anything could be useful (and I am thinking =
of the perspective of a general fixed-size vector type, but these all apply=
to index/bounds as well), but some particular examples: min, max, <, &l=
t;=3D, =3D=3D, !=3D, >=3D, >.=C2=A0 The relational operations need to=
return a vector of bool, which isn't compatible with index/bounds curr=
ently since they aren't parameterized by the type.=C2=A0 Obviously, tho=
ugh, it wouldn't make sense to call them index or bounds if they are pa=
rameterized by a type.<br>
</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0 =
0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"><p>H=
aving said that, I assume this is something that can be added later as a pu=
re extension, correct?</p>
</div></blockquote><div></div><div>Some of them, like min and max, could be=
unintrusive, though neither index nor bounds would be a particularly meani=
ngful choice as the return type.<br></div><div>=C2=A0</div><blockquote clas=
s=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;pad=
ding-left:1ex">
<div dir=3D"ltr"><div class=3D""><p>> Given the long turn around time fo=
r revisions to C++</p></div><p>The Committee is certainly trying to get bet=
ter at quicker iterations, let's not be discouraged by the ghosts of th=
e past...</p>
<div class=3D""><p>> Other omissions from index and bounds include:<br>&=
gt;=C2=A0 1. no data() access to the components<br>>=C2=A0 2. no iterato=
rs over components for index or bound</p></div><p>index and bounds are not =
containers and should not be used as such. For the limited number of scenar=
io where I want to use/modify indeterminate number of components, it was al=
ways sufficient for me to use a raw loop, and operator[]...<br>
In case I'm wrong, these as well should be easy to add later as extensi=
ons.</p><div class=3D""><p>> for_each(x_array, y_array, x_array.bounds()=
, [&](auto &x, auto &y, auto pos) {<br>>=C2=A0=C2=A0 if (x !=
=3D y) std::cout << "mismatch at position " << pos &l=
t;< std::endl;<br>
> });</p></div><p>I assume the idea here is that such "for_each&quo=
t; uses begin(X), end(X) for all provided arguments, passing dereferenced i=
terators to the function object. If so, I do not see how the current semant=
ics of bounds_iterator would get into way here? It should just work as is, =
no?<br>
</p></div></blockquote><div>The idea is that it would generate N nested for=
loops for N-dimensional array views, rather than an less efficient single =
for loop.<br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=
=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir=3D"ltr"><p>Actually, it should be possible to write the following =
with just the current proposal and the current standard for_each:<br>=C2=A0=
auto x_av =3D array_view<N>{x_array};<br>=C2=A0auto y_av =3D array_vi=
ew<N>{y_array};<br>
=C2=A0for_each(begin(x_av.bounds()), end(x_av.bounds()), [&](index<N=
> pos) {<br>=C2=A0 if(x_av[pos] !=3D y_av[pos]) std::cout << "=
;mismatch at position " << pos << std::endl;<br>=C2=A0});<=
/p></div></blockquote>
<div>Yes, but note that the iteration over bounds is more expensive and the=
multiplication with all of the strides has to happen for every position.<b=
r></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:=
0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir=3D"ltr"><p>> From my perspective, the only way to properly expl=
ore this design space for multidimensional arrays/containers/ranges is thro=
ugh an actively developed and widely used open source library.</p><div>Our =
(Microsoft) prototype implementation is in the pipeline to be published as =
an open source project. It should happen really soon, and I hope it will he=
lp to convey the discussed ideas.</div>
</div></blockquote><div><br></div><div>That's good news.=C2=A0 I think =
the best library is likely to be produced if the users of the library and t=
he developers of the library are one and the same.=C2=A0 Issues become appa=
rent and the library interface can be tweaked to correct them very quickly =
that way.<br>
</div></div></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--047d7b874e5aa5bb4304fbfd84c1--
.
Author: =?UTF-8?Q?=C5=81ukasz_Mendakiewicz?= <l.mendakiewicz@live.com>
Date: Thu, 26 Jun 2014 22:00:53 -0700 (PDT)
Raw View
------=_Part_372_32744078.1403845253991
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
I do understand your rationale in many of the points you are raising, and I=
=20
am aware of other existing libraries, which in some cases made different=20
design decisions. However many of the choices are mutually exclusive and in=
=20
my opinion it is impossible to converge on the "single best design". Many=
=20
of the design decisions in our proposal are also compromises.
I disagree with your judgment that we should strive to find an ultimate=20
solution before moving forward with any proposal. Lack of array_view or a=
=20
similar type is clearly a gap in C++ Standard, which many libraries are=20
addressing in different ways. We took the first stab in trying to address=
=20
this deficiency with putting forward the type we are familiar with, have=20
worked with successfully for over 2 years, and in the process we were also=
=20
fixing all issues we were aware of. It surely is not rock solid -- nothing=
=20
is -- and many use-cases might have benefit from tailoring details=20
differently to cater each of them, but we have to start somewhere.
Importantly, we are not "standardizing" array_view yet. If it passes LWG=20
voting on the next Committee meeting it will be merely appended to one of=
=20
TSs (unless anything changes, this should be Library Fundamentals TS) and=
=20
on track to be considered for C++17. The three years lead time is intended=
=20
exactly to gather the wider practical experience you are concerned about.
I hope this helps to clarify our position.
On Monday, June 16, 2014 5:49:39 PM UTC-7, Jeremy Maitin-Shepard wrote:
> On Sun, Jun 15, 2014 at 9:38 PM, =C5=81ukasz Mendakiewicz <l.menda...@liv=
e.com=20
> <javascript:>> wrote:
>
>> Thank you Jeffrey for adding me on the thread and for your initial=20
>> response -- which I almost universally agree with.
>>
>> Jeremy, thank you for your detailed feedback. First, I believe that most=
=20
>> of the disagreement stems from the approach to the proposal. You've=20
>> commented that "it doesn't make sense to standardize a partial solution;=
=20
>> better to work out a good, complete interface outside the standard". Thi=
s=20
>> is opposite to the "crawl, walk, run" philosophy we have taken when writ=
ing=20
>> this document up. We recognize that we have only explored some parts of =
the=20
>> design space, because as you have rightly observed our experience is=20
>> limited to C++ AMP, which constitutes only a specific data parallel=20
>> approach to algorithms. Of course we believe that this is a solid=20
>> foundation that can be generalized and built upon, hence the proposal. B=
ut=20
>> we deliberately avoided any design decisions which may be controversial =
or=20
>> result in a prolonged tug of war, instead intending for subsequent=20
>> proposals (not necessarily authored by us) to fill the gaps. Certainly,=
=20
>> should anything being proposed now be a possible hindrance for any=20
>> reasonable extension, it must be addressed sooner than later, however I=
=20
>> think that none of the lacks pointed by you belong to this category.
>>
> I think it is basically impossible to nail down even a "minimal" interfac=
e=20
> without considering the design of a complete library. If you looked at 1=
0=20
> different, widely-used C++ multidimensional array libraries and saw that=
=20
> all of their interfaces shared a given attribute, then standardizing that=
=20
> attribute of the interface would likely be a safe choice. Obviously that=
=20
> is not the case here, though.
>
> Some examples of design options:
> - Make array_view parameterized by the pointer type, rather than the valu=
e=20
> type. This allows it to hold smart pointers of various types, or a point=
er=20
> that represents GPU memory, or a smart pointer that represents GPU memory=
,=20
> etc. If the pointer is to GPU memory, reading and writing won't work (an=
d=20
> won't be allowed at compile-time), but the indexing, slicing, sectioning=
=20
> and other operations on the array_view representation itself can still be=
=20
> used. This is the decision I took in my own in-house library. Allowing=
=20
> array_view to hold a smart pointer means you don't need a separate type t=
o=20
> represent an array_view with ownership. (Sectioning and slicing produces=
a=20
> result with the pointer decayed to a regular pointer.) You can also use =
a=20
> __restrict__ pointer for an array_view type used as a function parameter =
to=20
> indicate lack of aliasing.
>
> - Make bounds and index just generic fixed-size vector types. In this=20
> case iterators on bounds should iterate over the components, rather than=
=20
> iterate over coordinates within the bounds.
> =20
> - More generally, the proposal distinguishes between array_view and=20
> strided_array_view, but doesn't allow for more fine-grained information t=
o=20
> be provided at compile time, such as the number of trailing contiguous=20
> dimensions, alignment information, etc.
>
>> >>> Some particular issues with the proposed design include:=20
>> >>>=20
>> >>> - No iterators are provided for array_view or strided_array_view, a=
=20
>> clear=20
>> >>> omission in the interface. For a multidimensional array, there are=
=20
>> two=20
>> >>> obvious types of iteration that may be desired:=20
>> >>> 1. iterating over just the first dimension;=20
>> >>> 2. iterating over a flat view of all of the elements. For a=20
>> strided=20
>> >>> array, iterating over a flat view cannot be done efficiently without=
=20
>> >>> segmented/hierarchical iterators.=20
>> >>> Which of these should be the default (i.e. provided through begin(=
)=20
>> and=20
>> >>> end() rather than through some adaptor) is not clear,=20
>> >>
>> >> From the Zen of Python, "In the face of ambiguity, refuse the=20
>> >> temptation to guess."=20
>> >
>> > That's true, but no adaptors to provide the functionality unambiguousl=
y=20
>> are provided either. For the particular case of a one-dimensional array=
,=20
>> there is no ambiguity, and not being able to easily use array_view with=
=20
>> standard algorithms or range-based for is a serious usability issue. Th=
is=20
>> will only become worse if/when standard algorithm overloads that take=20
>> ranges rather than iterator pairs are added.
>>
>> To the list of possible alternatives, I would add an option that was=20
>> proposed somewhere in the prior discussion on the proposal --=20
>> "hierarchical" array_view/elemental iterator, i.e. an iterator that for=
=20
>> array_view<T, Rank> with Rank > 1 iterates over array_view<T, Rank-1>; a=
nd=20
>> over T for Rank =3D=3D 1.
>>
> Yes, that is a better way of expressing what I meant by "iterating over=
=20
> just the first dimension". I believe this makes the most sense, but then=
=20
> it becomes desirable to have size() be the size of the first dimension fo=
r=20
> consistency with the iterators, and instead add a num_elements() that=20
> returns the total number of elements. The correct definition of size() i=
s=20
> hard to decide without figuring out how iterators should work.
>
> The other issue is that if the iterators are hierarchical, you need a new=
=20
> hierarchical for_each that effectively expands to N nested for loops for=
=20
> N-dimensional arrays and which can operate on multiple arrays (of the sam=
e=20
> size). This way you can express element-wise operations without any=20
> overhead.
>
>> It is however worth pointing out that in the first round of review with=
=20
>> LEWG at Issaquah meeting, the vocal unchallenged feedback for iterators =
was=20
>> "I do not want iterators for the views", thus we did not put much effort=
=20
>> into contemplating adding any. Even though the choice for Rank =3D=3D 1 =
is=20
>> "obvious", we consider this a corner case for array_view, and would rath=
er=20
>> have a holistic approach.
>> There remains the possibility to add some form of the iterator as a=20
>> future extension.
>>
> Well, you can take my comments as a challenge to that view. Rank =3D=3D =
1 may=20
> be a "corner" case, but is likely to be used more frequently than all oth=
er=20
> cases combined. A 1-dimensional array view that can't be used with=20
> for-range loops, boost (or std?) range adapters, etc. is a non-starter.
>
>> >>> - No data() access member for strided_array_view. This is presumabl=
y=20
>> >>> omitted because the memory is non-contiguous, but given that=20
>> >>> strided_array_view is a thin wrapper, there has to be a convenient=
=20
>> way to=20
>> >>> get at the underlying memory.=20
>> >>
>> >> Why "has to"?=20
>> >
>> > Because the user might want to convert the array to another=20
>> representation for use by another piece of code/library, e.g. FFTW or=20
>> Eigen, CUDA memcpy, etc. Under the proposed interface, for a 3-dimensio=
nal=20
>> stided array view, you have to use &arr[0][0][0]. This is even worse th=
an=20
>> having to do &vec[0] for std::vector, since the same expression cannot b=
e=20
>> used independent of the dimensionality.
>>
>> data() on strided_array_view could be harmful, as there is no guarantee=
=20
>> of contiguity, which a developer / function template might assume. Pleas=
e=20
>> note that for every other case in the Standard, the range [data(),=20
>> data()+size()) is valid/safe, thus providing other semantics here would =
be=20
>> dubious.
>> Granted, one can perform &arr[0][0][0] and run afoul, but that is no=20
>> different than e.g. &my_list.front().
>> It could be possible to provide "unsafe_data()" interface, which would=
=20
>> have to be consumed along with stride(), however I do not see much benef=
it=20
>> here over just using the "proper" interface -- bounds() and operator[]()=
..
>>
> Calling it noncontiguous_data() is fine, though certainly then array_view=
=20
> should have an noncontiguous_data() (in addition to data()) as well for=
=20
> consistency. I don't think unsafe_data is really the right name, though=
=20
> the functionality is more important than the name. &arr[0][0][0] has the=
=20
> disadvantage that it is more verbose and doesn't allow for writing generi=
c=20
> code that works with any number of dimensions. Just using the "proper"=
=20
> interface isn't a solution. A fundamental component like multidimensiona=
l=20
> arrays cannot be a "walled garden". The (pointer, bounds, strides)=20
> representation, which numerous other libraries like FFTW use as well,=20
> should be transparent.
>
>> >>> - Slicing is limited: it is not possible to take a slice in a=20
>> dimension=20
>> >>> other than the first.=20
>> >>
>> >> I think that's called "section()".=20
>> >
>> > Well, that takes a "section" but does not reduce the dimensionality=20
>> like "slice". [...] Certainly there is a large design space for general=
=20
>> subscripting and it almost certainly requires a fair amount of template=
=20
>> metaprogramming, but this is very useful functionality
>>
>> Yes, slicing and sectioning are slightly different. It is however=20
>> important to note that slicing in its current form always guarantees the=
=20
>> contiguity of the result, thus the return type may be array_view. The mo=
re=20
>> general cases (as you are describing) would result in a potentially stri=
ded=20
>> resulting view, which would need to be typed strided_array_view. This is=
=20
>> why it is important IMO to distinguish these two cases.
>> In the current form of the proposal we decided to provide the minimal=20
>> design -- only the first version, which in our opinion might be handy fo=
r=20
>> users used to C-style multidimensional addressing (i.e. arr[3][1][4] v=
=20
>> arr[{3, 1, 4}]), which actually you used above :).
>> The latter generic case can be trivially added as an extension to the=20
>> interface. I agree it may be useful, and if the current design is accept=
ed=20
>> for the TS, I encourage you to propose such extension (or nag us for fol=
low=20
>> ups :)).
>>
>> >>> - It is not clear whether it is really useful to have bounds and=20
>> index be=20
>> >>> separate types (though should probably at least be explicitly=20
>> convertible to=20
>> >>> each other).=20
>> >>
>> >> It adds a bit of type safety. Adding two bounds, for instance, doesn'=
t=20
>> >> make a lot of sense.=20
>> >
>> > I agree that type safety is in principle useful, but it is impossible=
=20
>> to predict what relationships might hold in any given program, and so th=
ere=20
>> is the question of whether the safety it adds is worth the cost of havin=
g=20
>> to explicitly work around it in the cases that it is too restrictive. =
=20
>> Certainly if they are separate types there needs to be a way to=20
>> (explicitly) convert.
>>
>> I agree with both of you :).
>> These are separate types, because their meaning and semantics are=20
>> different. It was also discussed in N3851, Appendix, II. The mental mode=
l I=20
>> use for reasoning about them is: index ~ vector and bounds ~ point (more=
=20
>> specifically: a zero-bound, axis-aligned rectangle described by its maxi=
mum=20
>> point), which makes the set of available operators apparent.
>> I understand the explicit conversions between these two types, even=20
>> though not theoretically sound, might be handy in practice and should be=
=20
>> added.
>>
> If we follow that logic, a point is a vector from the origin. Therefore=
=20
> index should just be Vector<ptrdiff_t,N> and bounds<N> could have a=20
> Vector<ptrdiff_t,N> member. However, it seems like it would be simpler t=
o=20
> just have bounds be Vector<ptrdiff_t,N> as well and save the trouble of t=
he=20
> explicit conversions. What type of error does the bounds/index distincti=
on=20
> prevent? More generally, I am not sure why we shouldn't think of an inde=
x=20
> as a point as well. If we want the last element in an array x, we have :=
=20
> x.bounds() - 1 (or x.bounds() - {1,1, ...}). We want to use this as an=
=20
> index, but the current operator definitions would have it be a bounds.
>
>> > As a specific example, consider if we want to compute the bounds of a=
=20
>> valid convolution if we have an array x and a filter k. The bounds of t=
he=20
>> result are: x.bounds - k.bounds + 1. None of the arithmetic operators=
=20
>> defined in the proposal help me with that; I'd just have to write a loop=
.. =20
>> Even if the arithmetic operators weren't limited by the bounds/index=20
>> distinction, there would still be no way to create a constant-valued=20
>> vector, i.e. to handle the constant 1.
>>
>> Explicit conversions would help with the first part, right? I hope you=
=20
>> are also not suggesting any such conversion should be implicit?
>> However I do not really understand what do you mean in the second part,=
=20
>> "a constant-valued vector". We purposefully allow to create both bounds<=
1>=20
>> and index<1> from a scalar; and disallow such operation for Rank > 1=20
>> (mostly because the semantics are not obvious, e.g. for rank 2, should=
=20
>> index<2>{16} be {0, 16}, {16, 0} or {16, 16}).
>> So net-net, in your example you should be able to do: x.bounds -=20
>> index<2>{k.bounds} + {1, 1}. It a little more long-winded, but IMO easie=
r=20
>> to comprehend than the original.
>>
> I don't think the explicit conversion to index adds to the clarity. Also=
,=20
> the problem with {1, 1} is that it depends on the dimensionality. The=20
> interface should be designed to be convenient for generic code. I would=
=20
> suggest a Scalar<T> type generated by a wrapper function scalar, from whi=
ch=20
> bounds and index can be implicitly constructed and which can be used in a=
ll=20
> of the operators.
>
>> > Another related issue I didn't notice before: the only way to construc=
t=20
>> an index or bounds type is from an initializer_list. There is no=20
>> (explicit) conversion from std::array, for instance. It is quite likely=
=20
>> that an index or bounds value would be computed by some other code, that=
=20
>> may use a different representation.
>>
>> Yes, we should add (const value_type* begin, const value_type* end)=20
>> constructors for both types. <rant>Or it should be possible to create=20
>> initializer_list explicitly from such pair which would solve this issue=
=20
>> universally.</rant>
>>
> Okay, though initializer_list is not compile-time sized.
> =20
>
>> >>> Furthermore, bounds and index essentially represent a=20
>> >>> fixed-size discrete vector type, i.e. an augmented interface for=20
>> std::array.=20
>> >>> Arguably the interface of std::array should just be extended to add=
=20
>> >>> component-wise operators instead. Also, a much more comprehensive=
=20
>> set of=20
>> >>> component-wise operations should be provided. A statically-sized=20
>> vector=20
>> >>> type is sorely needed in C++, but it does not make sense to=20
>> standardize=20
>> >>> these limited, single-purposes types when they could be, and should=
=20
>> be, much=20
>> >>> more general.=20
>> >>
>> >> We don't necessarily want to go for the most general possible type al=
l=20
>> at once
>> >
>> > Certainly there is a large design space, but that is a reason to be=20
>> cautious about standardizing anything. [...]
>>
>> There are two separate issue raised here:
>> - Why novel types -- this is primarily to introduce "vocabulary" types=
=20
>> and allow to discriminate index and bounds, as they have different=20
>> semantics, as discussed before. This was also touched upon in the=20
>> previously referred N3851, Appendix, II.
>> - Why so little functionality -- I agree with Jeffrey on this, and I hav=
e=20
>> described more of the philosophy in the introduction. I would be interes=
ted=20
>> however what exactly you mean by "a much more comprehensive set of=20
>> component-wise operations".
>>
> Almost anything could be useful (and I am thinking of the perspective of =
a=20
> general fixed-size vector type, but these all apply to index/bounds as=20
> well), but some particular examples: min, max, <, <=3D, =3D=3D, !=3D, >=
=3D, >. The=20
> relational operations need to return a vector of bool, which isn't=20
> compatible with index/bounds currently since they aren't parameterized by=
=20
> the type. Obviously, though, it wouldn't make sense to call them index o=
r=20
> bounds if they are parameterized by a type.
> =20
>
>> Having said that, I assume this is something that can be added later as =
a=20
>> pure extension, correct?
>>
> Some of them, like min and max, could be unintrusive, though neither inde=
x=20
> nor bounds would be a particularly meaningful choice as the return type.
> =20
>
>> > Given the long turn around time for revisions to C++
>>
>> The Committee is certainly trying to get better at quicker iterations,=
=20
>> let's not be discouraged by the ghosts of the past...
>>
>> > Other omissions from index and bounds include:
>> > 1. no data() access to the components
>> > 2. no iterators over components for index or bound
>>
>> index and bounds are not containers and should not be used as such. For=
=20
>> the limited number of scenario where I want to use/modify indeterminate=
=20
>> number of components, it was always sufficient for me to use a raw loop,=
=20
>> and operator[]...
>> In case I'm wrong, these as well should be easy to add later as=20
>> extensions.
>>
>> > for_each(x_array, y_array, x_array.bounds(), [&](auto &x, auto &y, aut=
o=20
>> pos) {
>> > if (x !=3D y) std::cout << "mismatch at position " << pos << std::en=
dl;
>> > });
>>
>> I assume the idea here is that such "for_each" uses begin(X), end(X) for=
=20
>> all provided arguments, passing dereferenced iterators to the function=
=20
>> object. If so, I do not see how the current semantics of bounds_iterator=
=20
>> would get into way here? It should just work as is, no?
>>
> The idea is that it would generate N nested for loops for N-dimensional=
=20
> array views, rather than an less efficient single for loop.
> =20
>
>> Actually, it should be possible to write the following with just the=20
>> current proposal and the current standard for_each:
>> auto x_av =3D array_view<N>{x_array};
>> auto y_av =3D array_view<N>{y_array};
>> for_each(begin(x_av.bounds()), end(x_av.bounds()), [&](index<N> pos) {
>> if(x_av[pos] !=3D y_av[pos]) std::cout << "mismatch at position " << p=
os=20
>> << std::endl;
>> });
>>
> Yes, but note that the iteration over bounds is more expensive and the=20
> multiplication with all of the strides has to happen for every position.
> =20
>
>> > From my perspective, the only way to properly explore this design spac=
e=20
>> for multidimensional arrays/containers/ranges is through an actively=20
>> developed and widely used open source library.
>> Our (Microsoft) prototype implementation is in the pipeline to be=20
>> published as an open source project. It should happen really soon, and I=
=20
>> hope it will help to convey the discussed ideas.
>>
>
> That's good news. I think the best library is likely to be produced if=
=20
> the users of the library and the developers of the library are one and th=
e=20
> same. Issues become apparent and the library interface can be tweaked to=
=20
> correct them very quickly that way.
> =20
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
------=_Part_372_32744078.1403845253991
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><p>I do understand your rationale in many of the points yo=
u are raising, and I am aware of other existing libraries, which in some ca=
ses made different design decisions. However many of the choices are mutual=
ly exclusive and in my opinion it is impossible to converge on the "single =
best design". Many of the design decisions in our proposal are also comprom=
ises.</p><p>I disagree with your judgment that we should strive to find an =
ultimate solution before moving forward with any proposal. Lack of array_vi=
ew or a similar type is clearly a gap in C++ Standard, which many libraries=
are addressing in different ways. We took the first stab in trying to addr=
ess this deficiency with putting forward the type we are familiar with, hav=
e worked with successfully for over 2 years, and in the process we were als=
o fixing all issues we were aware of. It surely is not rock solid -- nothin=
g is -- and many use-cases might have benefit from tailoring details differ=
ently to cater each of them, but we have to start somewhere.</p><div>Import=
antly, we are not "standardizing" array_view yet. If it passes LWG voting o=
n the next Committee meeting it will be merely appended to one of TSs (unle=
ss anything changes, this should be Library Fundamentals TS) and on track t=
o be considered for C++17. The three years lead time is intended exactly to=
gather the wider practical experience you are concerned about.</div><div><=
br></div><div>I hope this helps to clarify our position.</div><div><br>On M=
onday, June 16, 2014 5:49:39 PM UTC-7, Jeremy Maitin-Shepard wrote:</div><b=
lockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; padding=
-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px; =
border-left-style: solid;"><div dir=3D"ltr">On Sun, Jun 15, 2014 at 9:38 PM=
, =C5=81ukasz Mendakiewicz <span dir=3D"ltr"><<a onmousedown=3D"this.hre=
f=3D'javascript:';return true;" onclick=3D"this.href=3D'javascript:';return=
true;" href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"ylQ=
7Z_pmbVsJ">l.menda...@live.com</a>></span> wrote:<br><div><div class=3D"=
gmail_quote">
<blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; paddi=
ng-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-width: 1px=
; border-left-style: solid;"><div dir=3D"ltr"><p>Thank you Jeffrey for addi=
ng me on the thread and for your initial response -- which I almost univers=
ally agree with.</p>
<p>Jeremy, thank you for your detailed feedback. First, I believe that most=
of the disagreement stems from the approach to the proposal. You've commen=
ted that "it doesn't make sense to standardize a partial solution; bet=
ter to work out a good, complete interface outside the standard". This is o=
pposite to the "crawl, walk, run" philosophy we have taken when writing thi=
s document up. We recognize that we have only explored some parts of the de=
sign space, because as you have rightly observed our experience is limited =
to C++ AMP, which constitutes only a specific data parallel approach to alg=
orithms. Of course we believe that this is a solid foundation that can be g=
eneralized and built upon, hence the proposal. But we deliberately avoided =
any design decisions which may be controversial or result in a prolonged tu=
g of war, instead intending for subsequent proposals (not necessarily autho=
red by us) to fill the gaps. Certainly, should anything being proposed now =
be a possible hindrance for any reasonable extension, it must be addressed =
sooner than later, however I think that none of the lacks pointed by you be=
long to this category.</p>
</div></blockquote><div>I think it is basically impossible to nail down eve=
n a "minimal" interface without considering the design of a complete librar=
y. If you looked at 10 different, widely-used C++ multidimensional ar=
ray libraries and saw that all of their interfaces shared a given attribute=
, then standardizing that attribute of the interface would likely be a safe=
choice. Obviously that is not the case here, though.<br>
<br>Some examples of design options:<br></div><div>- Make array_view parame=
terized by the pointer type, rather than the value type. This allows =
it to hold smart pointers of various types, or a pointer that represents GP=
U memory, or a smart pointer that represents GPU memory, etc. If the =
pointer is to GPU memory, reading and writing won't work (and won't be allo=
wed at compile-time), but the indexing, slicing, sectioning and other opera=
tions on the array_view representation itself can still be used. This=
is the decision I took in my own in-house library. Allowing array_vi=
ew to hold a smart pointer means you don't need a separate type to represen=
t an array_view with ownership. (Sectioning and slicing produces a re=
sult with the pointer decayed to a regular pointer.) You can also use=
a __restrict__ pointer for an array_view type used as a function parameter=
to indicate lack of aliasing.<br>
<br></div><div>- Make bounds and index just generic fixed-size vector types=
.. In this case iterators on bounds should iterate over the components=
, rather than iterate over coordinates within the bounds.<br></div><div>&nb=
sp;<br>
</div><div>- More generally, the proposal distinguishes between array_view =
and strided_array_view, but doesn't allow for more fine-grained information=
to be provided at compile time, such as the number of trailing contiguous =
dimensions, alignment information, etc.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex;=
padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-widt=
h: 1px; border-left-style: solid;"><div dir=3D"ltr"><div><p>>>> So=
me particular issues with the proposed design include: <br>>>> <br=
>
>>> - No iterators are provided for array_view or strided_array_vi=
ew, a clear <br>>>> omission in the interface. For a multidi=
mensional array, there are two <br>>>> obvious types of iteration =
that may be desired: <br>
>>> 1. iterating over just the first dimension; <br>&g=
t;>> 2. iterating over a flat view of all of the elements=
.. For a strided <br>>>> array, iterating over a flat view ca=
nnot be done efficiently without <br>
>>> segmented/hierarchical iterators. <br>>>> =
Which of these should be the default (i.e. provided through begin() and <b=
r>>>> end() rather than through some adaptor) is not clear, <br>&g=
t;><br>
>> From the Zen of Python, "In the face of ambiguity, refuse the <br>=
>> temptation to guess." <br>><br>> That's true, but no adaptor=
s to provide the functionality unambiguously are provided either. For=
the particular case of a one-dimensional array, there is no ambiguity, and=
not being able to easily use array_view with standard algorithms or range-=
based for is a serious usability issue. This will only become worse i=
f/when standard algorithm overloads that take ranges rather than iterator p=
airs are added.</p>
</div><p>To the list of possible alternatives, I would add an option that w=
as proposed somewhere in the prior discussion on the proposal -- "hierarchi=
cal" array_view/elemental iterator, i.e. an iterator that for array_view<=
;T, Rank> with Rank > 1 iterates over array_view<T, Rank-1>; an=
d over T for Rank =3D=3D 1.<br>
</p></div></blockquote><div>Yes, that is a better way of expressing what I =
meant by "iterating over just the first dimension". I believe this ma=
kes the most sense, but then it becomes desirable to have size() be the siz=
e of the first dimension for consistency with the iterators, and instead ad=
d a num_elements() that returns the total number of elements. The cor=
rect definition of size() is hard to decide without figuring out how iterat=
ors should work.<br>
<br></div><div>The other issue is that if the iterators are hierarchical, y=
ou need a new hierarchical for_each that effectively expands to N nested fo=
r loops for N-dimensional arrays and which can operate on multiple arrays (=
of the same size). This way you can express element-wise operations w=
ithout any overhead.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex;=
padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-widt=
h: 1px; border-left-style: solid;"><div dir=3D"ltr"><p>It is however worth =
pointing out that in the first round of review with LEWG at Issaquah meetin=
g, the vocal unchallenged feedback for iterators was "I do not want iterato=
rs for the views", thus we did not put much effort into contemplating addin=
g any. Even though the choice for Rank =3D=3D 1 is "obvious", we consider t=
his a corner case for array_view, and would rather have a holistic approach=
..<br>
There remains the possibility to add some form of the iterator as a future =
extension.</p></div></blockquote><div>Well, you can take my comments as a c=
hallenge to that view. Rank =3D=3D 1 may be a "corner" case, but is l=
ikely to be used more frequently than all other cases combined. A 1-d=
imensional array view that can't be used with for-range loops, boost (or st=
d?) range adapters, etc. is a non-starter.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex;=
padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-widt=
h: 1px; border-left-style: solid;"><div dir=3D"ltr"><div><p>>>> - =
No data() access member for strided_array_view. This is presumably <b=
r>
>>> omitted because the memory is non-contiguous, but given that <=
br>>>> strided_array_view is a thin wrapper, there has to be a con=
venient way to <br>>>> get at the underlying memory. <br>>><=
br>
>> Why "has to"? <br>><br>> Because the user might want to conv=
ert the array to another representation for use by another piece of code/li=
brary, e.g. FFTW or Eigen, CUDA memcpy, etc. Under the proposed inter=
face, for a 3-dimensional stided array view, you have to use &arr[0][0]=
[0]. This is even worse than having to do &vec[0] for std::vector=
, since the same expression cannot be used independent of the dimensionalit=
y.</p>
</div><p>data() on strided_array_view could be harmful, as there is no guar=
antee of contiguity, which a developer / function template might assume. Pl=
ease note that for every other case in the Standard, the range [data(), dat=
a()+size()) is valid/safe, thus providing other semantics here would be dub=
ious.<br>
Granted, one can perform &arr[0][0][0] and run afoul, but that is no di=
fferent than e.g. &my_list.front().<br>It could be possible to provide =
"unsafe_data()" interface, which would have to be consumed along with strid=
e(), however I do not see much benefit here over just using the "proper" in=
terface -- bounds() and operator[]().</p>
</div></blockquote><div>Calling it noncontiguous_data() is fine, though cer=
tainly then array_view should have an noncontiguous_data() (in addition to =
data()) as well for consistency. I don't think unsafe_data is really =
the right name, though the functionality is more important than the name.&n=
bsp; &arr[0][0][0] has the disadvantage that it is more verbose and doe=
sn't allow for writing generic code that works with any number of dimension=
s. Just using the "proper" interface isn't a solution. A fundam=
ental component like multidimensional arrays cannot be a "walled garden".&n=
bsp; The (pointer, bounds, strides) representation, which numerous other li=
braries like FFTW use as well, should be transparent.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex;=
padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-widt=
h: 1px; border-left-style: solid;"><div dir=3D"ltr"><p></p><div>>>>=
; - Slicing is limited: it is not possible to take a slice in a dimension <=
br>
>>> other than the first. <br>>><br>>> I think that's =
called "section()". <br>><br></div>> Well, that takes a "section" but=
does not reduce the dimensionality like "slice". [...] Certainly there is =
a large design space for general subscripting and it almost certainly requi=
res a fair amount of template metaprogramming, but this is very useful func=
tionality<p>
</p><p>Yes, slicing and sectioning are slightly different. It is however im=
portant to note that slicing in its current form always guarantees the cont=
iguity of the result, thus the return type may be array_view. The more gene=
ral cases (as you are describing) would result in a potentially strided res=
ulting view, which would need to be typed strided_array_view. This is why i=
t is important IMO to distinguish these two cases.<br>
In the current form of the proposal we decided to provide the minimal desig=
n -- only the first version, which in our opinion might be handy for users =
used to C-style multidimensional addressing (i.e. arr[3][1][4] v arr[{3, 1,=
4}]), which actually you used above :).<br>
The latter generic case can be trivially added as an extension to the inter=
face. I agree it may be useful, and if the current design is accepted for t=
he TS, I encourage you to propose such extension (or nag us for follow ups =
:)).</p>
<div><p>>>> - It is not clear whether it is really useful to have =
bounds and index be <br>>>> separate types (though should probably=
at least be explicitly convertible to <br>>>> each other). <br>
>><br>>> It adds a bit of type safety. Adding two bounds, for i=
nstance, doesn't <br>>> make a lot of sense. <br>><br>> I agree=
that type safety is in principle useful, but it is impossible to predict w=
hat relationships might hold in any given program, and so there is the ques=
tion of whether the safety it adds is worth the cost of having to explicitl=
y work around it in the cases that it is too restrictive. Certainly i=
f they are separate types there needs to be a way to (explicitly) convert.<=
/p>
</div><p>I agree with both of you :).<br>These are separate types, because =
their meaning and semantics are different. It was also discussed in N3851, =
Appendix, II. The mental model I use for reasoning about them is: index ~ v=
ector and bounds ~ point (more specifically: a zero-bound, axis-aligned rec=
tangle described by its maximum point), which makes the set of available op=
erators apparent.<br>
I understand the explicit conversions between these two types, even though =
not theoretically sound, might be handy in practice and should be added.</p=
></div></blockquote><div>If we follow that logic, a point is a vector from =
the origin. Therefore index should just be Vector<ptrdiff_t,N> =
and bounds<N> could have a Vector<ptrdiff_t,N> member. Ho=
wever, it seems like it would be simpler to just have bounds be Vector<p=
trdiff_t,N> as well and save the trouble of the explicit conversions.&nb=
sp; What type of error does the bounds/index distinction prevent? Mor=
e generally, I am not sure why we shouldn't think of an index as a point as=
well. If we want the last element in an array x, we have : x.bounds(=
) - 1 (or x.bounds() - {1,1, ...}). We want to use this as an i=
ndex, but the current operator definitions would have it be a bounds.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex;=
padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-widt=
h: 1px; border-left-style: solid;"><div dir=3D"ltr"><div><p>> As a speci=
fic example, consider if we want to compute the bounds of a valid convoluti=
on if we have an array x and a filter k. The bounds of the result are=
: x.bounds - k.bounds + 1. None of the arithmetic operators defined i=
n the proposal help me with that; I'd just have to write a loop. Even=
if the arithmetic operators weren't limited by the bounds/index distinctio=
n, there would still be no way to create a constant-valued vector, i.e. to =
handle the constant 1.</p>
</div><p>Explicit conversions would help with the first part, right? I hope=
you are also not suggesting any such conversion should be implicit?<br>How=
ever I do not really understand what do you mean in the second part, "a con=
stant-valued vector". We purposefully allow to create both bounds<1> =
and index<1> from a scalar; and disallow such operation for Rank >=
1 (mostly because the semantics are not obvious, e.g. for rank 2, should i=
ndex<2>{16} be {0, 16}, {16, 0} or {16, 16}).<br>
So net-net, in your example you should be able to do: x.bounds - index<2=
>{k.bounds} + {1, 1}. It a little more long-winded, but IMO easier to co=
mprehend than the original.</p></div></blockquote><div>I don't think the ex=
plicit conversion to index adds to the clarity. Also, the problem wit=
h {1, 1} is that it depends on the dimensionality. The interface shou=
ld be designed to be convenient for generic code. I would suggest a S=
calar<T> type generated by a wrapper function scalar, from which boun=
ds and index can be implicitly constructed and which can be used in all of =
the operators.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex;=
padding-left: 1ex; border-left-color: rgb(204, 204, 204); border-left-widt=
h: 1px; border-left-style: solid;"><div dir=3D"ltr"><div><p>> Another re=
lated issue I didn't notice before: the only way to construct an index or b=
ounds type is from an initializer_list. There is no (explicit) conver=
sion from std::array, for instance. It is quite likely that an index =
or bounds value would be computed by some other code, that may use a differ=
ent representation.</p>
</div><p>Yes, we should add (const value_type* begin, const value_type* end=
) constructors for both types. <rant>Or it should be possible to crea=
te initializer_list explicitly from such pair which would solve this issue =
universally.</rant></p>
</div></blockquote><div>Okay, though initializer_list is not compile-time s=
ized.<br></div><div> </div><blockquote class=3D"gmail_quote" style=3D"=
margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 2=
04, 204); border-left-width: 1px; border-left-style: solid;"><div dir=3D"lt=
r"><div>
>>> Furthermore, bounds and index essentially represent a <br>>=
>> fixed-size discrete vector type, i.e. an augmented interface for s=
td::array. <br>>>> Arguably the interface of std::array should jus=
t be extended to add <br>
>>> component-wise operators instead. Also, a much more comp=
rehensive set of <br>>>> component-wise operations should be provi=
ded. A statically-sized vector <br>>>> type is sorely needed=
in C++, but it does not make sense to standardize <br>
>>> these limited, single-purposes types when they could be, and s=
hould be, much <br>>>> more general. <br>>><br>>> We d=
on't necessarily want to go for the most general possible type all at once<=
br>
><br></div>> Certainly there is a large design space, but that is a r=
eason to be cautious about standardizing anything. [...]<p></p><p>There are=
two separate issue raised here:<br>- Why novel types -- this is primarily =
to introduce "vocabulary" types and allow to discriminate index and bounds,=
as they have different semantics, as discussed before. This was also touch=
ed upon in the previously referred N3851, Appendix, II.<br>
- Why so little functionality -- I agree with Jeffrey on this, and I have d=
escribed more of the philosophy in the introduction. I would be interested =
however what exactly you mean by "a much more comprehensive set of componen=
t-wise operations".</p>
</div></blockquote><div>Almost anything could be useful (and I am thinking =
of the perspective of a general fixed-size vector type, but these all apply=
to index/bounds as well), but some particular examples: min, max, <, &l=
t;=3D, =3D=3D, !=3D, >=3D, >. The relational operations need to=
return a vector of bool, which isn't compatible with index/bounds currentl=
y since they aren't parameterized by the type. Obviously, though, it =
wouldn't make sense to call them index or bounds if they are parameterized =
by a type.<br>
</div><div> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0=
px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204);=
border-left-width: 1px; border-left-style: solid;"><div dir=3D"ltr"><p>Hav=
ing said that, I assume this is something that can be added later as a pure=
extension, correct?</p>
</div></blockquote><div></div><div>Some of them, like min and max, could be=
unintrusive, though neither index nor bounds would be a particularly meani=
ngful choice as the return type.<br></div><div> </div><blockquote clas=
s=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; bo=
rder-left-color: rgb(204, 204, 204); border-left-width: 1px; border-left-st=
yle: solid;">
<div dir=3D"ltr"><div><p>> Given the long turn around time for revisions=
to C++</p></div><p>The Committee is certainly trying to get better at quic=
ker iterations, let's not be discouraged by the ghosts of the past...</p>
<div><p>> Other omissions from index and bounds include:<br>> 1=
.. no data() access to the components<br>> 2. no iterators over com=
ponents for index or bound</p></div><p>index and bounds are not containers =
and should not be used as such. For the limited number of scenario where I =
want to use/modify indeterminate number of components, it was always suffic=
ient for me to use a raw loop, and operator[]...<br>
In case I'm wrong, these as well should be easy to add later as extensions.=
</p><div><p>> for_each(x_array, y_array, x_array.bounds(), [&](auto =
&x, auto &y, auto pos) {<br>> if (x !=3D y) std::cou=
t << "mismatch at position " << pos << std::endl;<br>
> });</p></div><p>I assume the idea here is that such "for_each" uses be=
gin(X), end(X) for all provided arguments, passing dereferenced iterators t=
o the function object. If so, I do not see how the current semantics of bou=
nds_iterator would get into way here? It should just work as is, no?<br>
</p></div></blockquote><div>The idea is that it would generate N nested for=
loops for N-dimensional array views, rather than an less efficient single =
for loop.<br></div><div> </div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(20=
4, 204, 204); border-left-width: 1px; border-left-style: solid;">
<div dir=3D"ltr"><p>Actually, it should be possible to write the following =
with just the current proposal and the current standard for_each:<br> =
auto x_av =3D array_view<N>{x_array};<br> auto y_av =3D array_vi=
ew<N>{y_array};<br>
for_each(begin(x_av.bounds())<wbr>, end(x_av.bounds()), [&](index=
<N> pos) {<br> if(x_av[pos] !=3D y_av[pos]) std::cout << =
"mismatch at position " << pos << std::endl;<br> });</p></=
div></blockquote>
<div>Yes, but note that the iteration over bounds is more expensive and the=
multiplication with all of the strides has to happen for every position.<b=
r></div><div> </div><blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204=
); border-left-width: 1px; border-left-style: solid;">
<div dir=3D"ltr"><p>> From my perspective, the only way to properly expl=
ore this design space for multidimensional arrays/containers/ranges is thro=
ugh an actively developed and widely used open source library.</p><div>Our =
(Microsoft) prototype implementation is in the pipeline to be published as =
an open source project. It should happen really soon, and I hope it will he=
lp to convey the discussed ideas.</div>
</div></blockquote><div><br></div><div>That's good news. I think the =
best library is likely to be produced if the users of the library and the d=
evelopers of the library are one and the same. Issues become apparent=
and the library interface can be tweaked to correct them very quickly that=
way.<br>
</div></div></div></div>
</blockquote></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_372_32744078.1403845253991--
.
Author: phdofthehouse@gmail.com
Date: Fri, 14 Nov 2014 12:29:57 -0800 (PST)
Raw View
------=_Part_748_1726523670.1415996997569
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
As a small addition, has anyone considered perhaps calling the class=20
buffer_view<typename T, size_type dimensions>
and then leaving the name *array_view* for a compile-time version of this=
=20
class (to match std::array)?
I don't know if a fully constexpr-qualified version of the buffer_view=20
class will have the same benefit as a compile-time defined=20
array_view<typename T, size_type... dimension_sizes>
class (with *strided* variants for buffer_view and array_view).
On Friday, June 27, 2014 1:00:54 AM UTC-4, =C5=81ukasz Mendakiewicz wrote:
>
> I do understand your rationale in many of the points you are raising, and=
=20
> I am aware of other existing libraries, which in some cases made differen=
t=20
> design decisions. However many of the choices are mutually exclusive and =
in=20
> my opinion it is impossible to converge on the "single best design". Many=
=20
> of the design decisions in our proposal are also compromises.
>
> I disagree with your judgment that we should strive to find an ultimate=
=20
> solution before moving forward with any proposal. Lack of array_view or a=
=20
> similar type is clearly a gap in C++ Standard, which many libraries are=
=20
> addressing in different ways. We took the first stab in trying to address=
=20
> this deficiency with putting forward the type we are familiar with, have=
=20
> worked with successfully for over 2 years, and in the process we were als=
o=20
> fixing all issues we were aware of. It surely is not rock solid -- nothin=
g=20
> is -- and many use-cases might have benefit from tailoring details=20
> differently to cater each of them, but we have to start somewhere.
> Importantly, we are not "standardizing" array_view yet. If it passes LWG=
=20
> voting on the next Committee meeting it will be merely appended to one of=
=20
> TSs (unless anything changes, this should be Library Fundamentals TS) and=
=20
> on track to be considered for C++17. The three years lead time is intende=
d=20
> exactly to gather the wider practical experience you are concerned about.
>
> I hope this helps to clarify our position.
>
> On Monday, June 16, 2014 5:49:39 PM UTC-7, Jeremy Maitin-Shepard wrote:
>
>> On Sun, Jun 15, 2014 at 9:38 PM, =C5=81ukasz Mendakiewicz <l.menda...@li=
ve.com
>> > wrote:
>>
>>> Thank you Jeffrey for adding me on the thread and for your initial=20
>>> response -- which I almost universally agree with.
>>>
>>> Jeremy, thank you for your detailed feedback. First, I believe that mos=
t=20
>>> of the disagreement stems from the approach to the proposal. You've=20
>>> commented that "it doesn't make sense to standardize a partial solution=
;=20
>>> better to work out a good, complete interface outside the standard". Th=
is=20
>>> is opposite to the "crawl, walk, run" philosophy we have taken when wri=
ting=20
>>> this document up. We recognize that we have only explored some parts of=
the=20
>>> design space, because as you have rightly observed our experience is=20
>>> limited to C++ AMP, which constitutes only a specific data parallel=20
>>> approach to algorithms. Of course we believe that this is a solid=20
>>> foundation that can be generalized and built upon, hence the proposal. =
But=20
>>> we deliberately avoided any design decisions which may be controversial=
or=20
>>> result in a prolonged tug of war, instead intending for subsequent=20
>>> proposals (not necessarily authored by us) to fill the gaps. Certainly,=
=20
>>> should anything being proposed now be a possible hindrance for any=20
>>> reasonable extension, it must be addressed sooner than later, however I=
=20
>>> think that none of the lacks pointed by you belong to this category.
>>>
>> I think it is basically impossible to nail down even a "minimal"=20
>> interface without considering the design of a complete library. If you=
=20
>> looked at 10 different, widely-used C++ multidimensional array libraries=
=20
>> and saw that all of their interfaces shared a given attribute, then=20
>> standardizing that attribute of the interface would likely be a safe=20
>> choice. Obviously that is not the case here, though.
>>
>> Some examples of design options:
>> - Make array_view parameterized by the pointer type, rather than the=20
>> value type. This allows it to hold smart pointers of various types, or =
a=20
>> pointer that represents GPU memory, or a smart pointer that represents G=
PU=20
>> memory, etc. If the pointer is to GPU memory, reading and writing won't=
=20
>> work (and won't be allowed at compile-time), but the indexing, slicing,=
=20
>> sectioning and other operations on the array_view representation itself =
can=20
>> still be used. This is the decision I took in my own in-house library. =
=20
>> Allowing array_view to hold a smart pointer means you don't need a separ=
ate=20
>> type to represent an array_view with ownership. (Sectioning and slicing=
=20
>> produces a result with the pointer decayed to a regular pointer.) You c=
an=20
>> also use a __restrict__ pointer for an array_view type used as a functio=
n=20
>> parameter to indicate lack of aliasing.
>>
>> - Make bounds and index just generic fixed-size vector types. In this=
=20
>> case iterators on bounds should iterate over the components, rather than=
=20
>> iterate over coordinates within the bounds.
>> =20
>> - More generally, the proposal distinguishes between array_view and=20
>> strided_array_view, but doesn't allow for more fine-grained information =
to=20
>> be provided at compile time, such as the number of trailing contiguous=
=20
>> dimensions, alignment information, etc.
>>
>>> >>> Some particular issues with the proposed design include:=20
>>> >>>=20
>>> >>> - No iterators are provided for array_view or strided_array_view, a=
=20
>>> clear=20
>>> >>> omission in the interface. For a multidimensional array, there are=
=20
>>> two=20
>>> >>> obvious types of iteration that may be desired:=20
>>> >>> 1. iterating over just the first dimension;=20
>>> >>> 2. iterating over a flat view of all of the elements. For a=20
>>> strided=20
>>> >>> array, iterating over a flat view cannot be done efficiently withou=
t=20
>>> >>> segmented/hierarchical iterators.=20
>>> >>> Which of these should be the default (i.e. provided through=20
>>> begin() and=20
>>> >>> end() rather than through some adaptor) is not clear,=20
>>> >>
>>> >> From the Zen of Python, "In the face of ambiguity, refuse the=20
>>> >> temptation to guess."=20
>>> >
>>> > That's true, but no adaptors to provide the functionality=20
>>> unambiguously are provided either. For the particular case of a=20
>>> one-dimensional array, there is no ambiguity, and not being able to eas=
ily=20
>>> use array_view with standard algorithms or range-based for is a serious=
=20
>>> usability issue. This will only become worse if/when standard algorith=
m=20
>>> overloads that take ranges rather than iterator pairs are added.
>>>
>>> To the list of possible alternatives, I would add an option that was=20
>>> proposed somewhere in the prior discussion on the proposal --=20
>>> "hierarchical" array_view/elemental iterator, i.e. an iterator that for=
=20
>>> array_view<T, Rank> with Rank > 1 iterates over array_view<T, Rank-1>; =
and=20
>>> over T for Rank =3D=3D 1.
>>>
>> Yes, that is a better way of expressing what I meant by "iterating over=
=20
>> just the first dimension". I believe this makes the most sense, but the=
n=20
>> it becomes desirable to have size() be the size of the first dimension f=
or=20
>> consistency with the iterators, and instead add a num_elements() that=20
>> returns the total number of elements. The correct definition of size() =
is=20
>> hard to decide without figuring out how iterators should work.
>>
>> The other issue is that if the iterators are hierarchical, you need a ne=
w=20
>> hierarchical for_each that effectively expands to N nested for loops for=
=20
>> N-dimensional arrays and which can operate on multiple arrays (of the sa=
me=20
>> size). This way you can express element-wise operations without any=20
>> overhead.
>>
>>> It is however worth pointing out that in the first round of review with=
=20
>>> LEWG at Issaquah meeting, the vocal unchallenged feedback for iterators=
was=20
>>> "I do not want iterators for the views", thus we did not put much effor=
t=20
>>> into contemplating adding any. Even though the choice for Rank =3D=3D 1=
is=20
>>> "obvious", we consider this a corner case for array_view, and would rat=
her=20
>>> have a holistic approach.
>>> There remains the possibility to add some form of the iterator as a=20
>>> future extension.
>>>
>> Well, you can take my comments as a challenge to that view. Rank =3D=3D=
1=20
>> may be a "corner" case, but is likely to be used more frequently than al=
l=20
>> other cases combined. A 1-dimensional array view that can't be used wit=
h=20
>> for-range loops, boost (or std?) range adapters, etc. is a non-starter.
>>
>>> >>> - No data() access member for strided_array_view. This is=20
>>> presumably=20
>>> >>> omitted because the memory is non-contiguous, but given that=20
>>> >>> strided_array_view is a thin wrapper, there has to be a convenient=
=20
>>> way to=20
>>> >>> get at the underlying memory.=20
>>> >>
>>> >> Why "has to"?=20
>>> >
>>> > Because the user might want to convert the array to another=20
>>> representation for use by another piece of code/library, e.g. FFTW or=
=20
>>> Eigen, CUDA memcpy, etc. Under the proposed interface, for a 3-dimensi=
onal=20
>>> stided array view, you have to use &arr[0][0][0]. This is even worse t=
han=20
>>> having to do &vec[0] for std::vector, since the same expression cannot =
be=20
>>> used independent of the dimensionality.
>>>
>>> data() on strided_array_view could be harmful, as there is no guarantee=
=20
>>> of contiguity, which a developer / function template might assume. Plea=
se=20
>>> note that for every other case in the Standard, the range [data(),=20
>>> data()+size()) is valid/safe, thus providing other semantics here would=
be=20
>>> dubious.
>>> Granted, one can perform &arr[0][0][0] and run afoul, but that is no=20
>>> different than e.g. &my_list.front().
>>> It could be possible to provide "unsafe_data()" interface, which would=
=20
>>> have to be consumed along with stride(), however I do not see much bene=
fit=20
>>> here over just using the "proper" interface -- bounds() and operator[](=
).
>>>
>> Calling it noncontiguous_data() is fine, though certainly then array_vie=
w=20
>> should have an noncontiguous_data() (in addition to data()) as well for=
=20
>> consistency. I don't think unsafe_data is really the right name, though=
=20
>> the functionality is more important than the name. &arr[0][0][0] has th=
e=20
>> disadvantage that it is more verbose and doesn't allow for writing gener=
ic=20
>> code that works with any number of dimensions. Just using the "proper"=
=20
>> interface isn't a solution. A fundamental component like multidimension=
al=20
>> arrays cannot be a "walled garden". The (pointer, bounds, strides)=20
>> representation, which numerous other libraries like FFTW use as well,=20
>> should be transparent.
>>
>>> >>> - Slicing is limited: it is not possible to take a slice in a=20
>>> dimension=20
>>> >>> other than the first.=20
>>> >>
>>> >> I think that's called "section()".=20
>>> >
>>> > Well, that takes a "section" but does not reduce the dimensionality=
=20
>>> like "slice". [...] Certainly there is a large design space for general=
=20
>>> subscripting and it almost certainly requires a fair amount of template=
=20
>>> metaprogramming, but this is very useful functionality
>>>
>>> Yes, slicing and sectioning are slightly different. It is however=20
>>> important to note that slicing in its current form always guarantees th=
e=20
>>> contiguity of the result, thus the return type may be array_view. The m=
ore=20
>>> general cases (as you are describing) would result in a potentially str=
ided=20
>>> resulting view, which would need to be typed strided_array_view. This i=
s=20
>>> why it is important IMO to distinguish these two cases.
>>> In the current form of the proposal we decided to provide the minimal=
=20
>>> design -- only the first version, which in our opinion might be handy f=
or=20
>>> users used to C-style multidimensional addressing (i.e. arr[3][1][4] v=
=20
>>> arr[{3, 1, 4}]), which actually you used above :).
>>> The latter generic case can be trivially added as an extension to the=
=20
>>> interface. I agree it may be useful, and if the current design is accep=
ted=20
>>> for the TS, I encourage you to propose such extension (or nag us for fo=
llow=20
>>> ups :)).
>>>
>>> >>> - It is not clear whether it is really useful to have bounds and=20
>>> index be=20
>>> >>> separate types (though should probably at least be explicitly=20
>>> convertible to=20
>>> >>> each other).=20
>>> >>
>>> >> It adds a bit of type safety. Adding two bounds, for instance,=20
>>> doesn't=20
>>> >> make a lot of sense.=20
>>> >
>>> > I agree that type safety is in principle useful, but it is impossible=
=20
>>> to predict what relationships might hold in any given program, and so t=
here=20
>>> is the question of whether the safety it adds is worth the cost of havi=
ng=20
>>> to explicitly work around it in the cases that it is too restrictive. =
=20
>>> Certainly if they are separate types there needs to be a way to=20
>>> (explicitly) convert.
>>>
>>> I agree with both of you :).
>>> These are separate types, because their meaning and semantics are=20
>>> different. It was also discussed in N3851, Appendix, II. The mental mod=
el I=20
>>> use for reasoning about them is: index ~ vector and bounds ~ point (mor=
e=20
>>> specifically: a zero-bound, axis-aligned rectangle described by its max=
imum=20
>>> point), which makes the set of available operators apparent.
>>> I understand the explicit conversions between these two types, even=20
>>> though not theoretically sound, might be handy in practice and should b=
e=20
>>> added.
>>>
>> If we follow that logic, a point is a vector from the origin. Therefore=
=20
>> index should just be Vector<ptrdiff_t,N> and bounds<N> could have a=20
>> Vector<ptrdiff_t,N> member. However, it seems like it would be simpler =
to=20
>> just have bounds be Vector<ptrdiff_t,N> as well and save the trouble of =
the=20
>> explicit conversions. What type of error does the bounds/index distinct=
ion=20
>> prevent? More generally, I am not sure why we shouldn't think of an ind=
ex=20
>> as a point as well. If we want the last element in an array x, we have =
:=20
>> x.bounds() - 1 (or x.bounds() - {1,1, ...}). We want to use this as an=
=20
>> index, but the current operator definitions would have it be a bounds.
>>
>>> > As a specific example, consider if we want to compute the bounds of a=
=20
>>> valid convolution if we have an array x and a filter k. The bounds of =
the=20
>>> result are: x.bounds - k.bounds + 1. None of the arithmetic operators=
=20
>>> defined in the proposal help me with that; I'd just have to write a loo=
p. =20
>>> Even if the arithmetic operators weren't limited by the bounds/index=20
>>> distinction, there would still be no way to create a constant-valued=20
>>> vector, i.e. to handle the constant 1.
>>>
>>> Explicit conversions would help with the first part, right? I hope you=
=20
>>> are also not suggesting any such conversion should be implicit?
>>> However I do not really understand what do you mean in the second part,=
=20
>>> "a constant-valued vector". We purposefully allow to create both bounds=
<1>=20
>>> and index<1> from a scalar; and disallow such operation for Rank > 1=20
>>> (mostly because the semantics are not obvious, e.g. for rank 2, should=
=20
>>> index<2>{16} be {0, 16}, {16, 0} or {16, 16}).
>>> So net-net, in your example you should be able to do: x.bounds -=20
>>> index<2>{k.bounds} + {1, 1}. It a little more long-winded, but IMO easi=
er=20
>>> to comprehend than the original.
>>>
>> I don't think the explicit conversion to index adds to the clarity. =20
>> Also, the problem with {1, 1} is that it depends on the dimensionality. =
=20
>> The interface should be designed to be convenient for generic code. I=
=20
>> would suggest a Scalar<T> type generated by a wrapper function scalar, f=
rom=20
>> which bounds and index can be implicitly constructed and which can be us=
ed=20
>> in all of the operators.
>>
>>> > Another related issue I didn't notice before: the only way to=20
>>> construct an index or bounds type is from an initializer_list. There i=
s no=20
>>> (explicit) conversion from std::array, for instance. It is quite likel=
y=20
>>> that an index or bounds value would be computed by some other code, tha=
t=20
>>> may use a different representation.
>>>
>>> Yes, we should add (const value_type* begin, const value_type* end)=20
>>> constructors for both types. <rant>Or it should be possible to create=
=20
>>> initializer_list explicitly from such pair which would solve this issue=
=20
>>> universally.</rant>
>>>
>> Okay, though initializer_list is not compile-time sized.
>> =20
>>
>>> >>> Furthermore, bounds and index essentially represent a=20
>>> >>> fixed-size discrete vector type, i.e. an augmented interface for=20
>>> std::array.=20
>>> >>> Arguably the interface of std::array should just be extended to add=
=20
>>> >>> component-wise operators instead. Also, a much more comprehensive=
=20
>>> set of=20
>>> >>> component-wise operations should be provided. A statically-sized=
=20
>>> vector=20
>>> >>> type is sorely needed in C++, but it does not make sense to=20
>>> standardize=20
>>> >>> these limited, single-purposes types when they could be, and should=
=20
>>> be, much=20
>>> >>> more general.=20
>>> >>
>>> >> We don't necessarily want to go for the most general possible type=
=20
>>> all at once
>>> >
>>> > Certainly there is a large design space, but that is a reason to be=
=20
>>> cautious about standardizing anything. [...]
>>>
>>> There are two separate issue raised here:
>>> - Why novel types -- this is primarily to introduce "vocabulary" types=
=20
>>> and allow to discriminate index and bounds, as they have different=20
>>> semantics, as discussed before. This was also touched upon in the=20
>>> previously referred N3851, Appendix, II.
>>> - Why so little functionality -- I agree with Jeffrey on this, and I=20
>>> have described more of the philosophy in the introduction. I would be=
=20
>>> interested however what exactly you mean by "a much more comprehensive =
set=20
>>> of component-wise operations".
>>>
>> Almost anything could be useful (and I am thinking of the perspective of=
=20
>> a general fixed-size vector type, but these all apply to index/bounds as=
=20
>> well), but some particular examples: min, max, <, <=3D, =3D=3D, !=3D, >=
=3D, >. The=20
>> relational operations need to return a vector of bool, which isn't=20
>> compatible with index/bounds currently since they aren't parameterized b=
y=20
>> the type. Obviously, though, it wouldn't make sense to call them index =
or=20
>> bounds if they are parameterized by a type.
>> =20
>>
>>> Having said that, I assume this is something that can be added later as=
=20
>>> a pure extension, correct?
>>>
>> Some of them, like min and max, could be unintrusive, though neither=20
>> index nor bounds would be a particularly meaningful choice as the return=
=20
>> type.
>> =20
>>
>>> > Given the long turn around time for revisions to C++
>>>
>>> The Committee is certainly trying to get better at quicker iterations,=
=20
>>> let's not be discouraged by the ghosts of the past...
>>>
>>> > Other omissions from index and bounds include:
>>> > 1. no data() access to the components
>>> > 2. no iterators over components for index or bound
>>>
>>> index and bounds are not containers and should not be used as such. For=
=20
>>> the limited number of scenario where I want to use/modify indeterminate=
=20
>>> number of components, it was always sufficient for me to use a raw loop=
,=20
>>> and operator[]...
>>> In case I'm wrong, these as well should be easy to add later as=20
>>> extensions.
>>>
>>> > for_each(x_array, y_array, x_array.bounds(), [&](auto &x, auto &y,=20
>>> auto pos) {
>>> > if (x !=3D y) std::cout << "mismatch at position " << pos << std::e=
ndl;
>>> > });
>>>
>>> I assume the idea here is that such "for_each" uses begin(X), end(X) fo=
r=20
>>> all provided arguments, passing dereferenced iterators to the function=
=20
>>> object. If so, I do not see how the current semantics of bounds_iterato=
r=20
>>> would get into way here? It should just work as is, no?
>>>
>> The idea is that it would generate N nested for loops for N-dimensional=
=20
>> array views, rather than an less efficient single for loop.
>> =20
>>
>>> Actually, it should be possible to write the following with just the=20
>>> current proposal and the current standard for_each:
>>> auto x_av =3D array_view<N>{x_array};
>>> auto y_av =3D array_view<N>{y_array};
>>> for_each(begin(x_av.bounds()), end(x_av.bounds()), [&](index<N> pos) {
>>> if(x_av[pos] !=3D y_av[pos]) std::cout << "mismatch at position " << =
pos=20
>>> << std::endl;
>>> });
>>>
>> Yes, but note that the iteration over bounds is more expensive and the=
=20
>> multiplication with all of the strides has to happen for every position.
>> =20
>>
>>> > From my perspective, the only way to properly explore this design=20
>>> space for multidimensional arrays/containers/ranges is through an activ=
ely=20
>>> developed and widely used open source library.
>>> Our (Microsoft) prototype implementation is in the pipeline to be=20
>>> published as an open source project. It should happen really soon, and =
I=20
>>> hope it will help to convey the discussed ideas.
>>>
>>
>> That's good news. I think the best library is likely to be produced if=
=20
>> the users of the library and the developers of the library are one and t=
he=20
>> same. Issues become apparent and the library interface can be tweaked t=
o=20
>> correct them very quickly that way.
>> =20
>
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
------=_Part_748_1726523670.1415996997569
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">As a small addition, has anyone considered perhaps calling=
the class <div class=3D"prettyprint" style=3D"background-color: rgb(250, 2=
50, 250); border-color: rgb(187, 187, 187); border-style: solid; border-wid=
th: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"=
subprettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">b=
uffer_view</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
<</span><span style=3D"color: #008;" class=3D"styled-by-prettify">typena=
me</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> T</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> size_type dimensions</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">></span></d=
iv></code></div><br> and then leaving the name <i>array_view</i> for a comp=
ile-time version of this class (to match std::array)?<br><br>I don't know i=
f a fully constexpr-qualified version of the buffer_view class will have th=
e same benefit as a compile-time defined <div class=3D"prettyprint" style=
=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187);=
border-style: solid; border-width: 1px; word-wrap: break-word;"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;=
" class=3D"styled-by-prettify">array_view</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify"><</span><span style=3D"color: #008;" clas=
s=3D"styled-by-prettify">typename</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> T</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> size_type</span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">...</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
dimension_sizes</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">></span></div></code></div><br>class (with <i>strided</i> variants=
for buffer_view and array_view).<br><br>On Friday, June 27, 2014 1:00:54 A=
M UTC-4, =C5=81ukasz Mendakiewicz wrote:<blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;"><div dir=3D"ltr"><p>I do understand your rationale in many of the=
points you are raising, and I am aware of other existing libraries, which =
in some cases made different design decisions. However many of the choices =
are mutually exclusive and in my opinion it is impossible to converge on th=
e "single best design". Many of the design decisions in our proposal are al=
so compromises.</p><p>I disagree with your judgment that we should strive t=
o find an ultimate solution before moving forward with any proposal. Lack o=
f array_view or a similar type is clearly a gap in C++ Standard, which many=
libraries are addressing in different ways. We took the first stab in tryi=
ng to address this deficiency with putting forward the type we are familiar=
with, have worked with successfully for over 2 years, and in the process w=
e were also fixing all issues we were aware of. It surely is not rock solid=
-- nothing is -- and many use-cases might have benefit from tailoring deta=
ils differently to cater each of them, but we have to start somewhere.</p><=
div>Importantly, we are not "standardizing" array_view yet. If it passes LW=
G voting on the next Committee meeting it will be merely appended to one of=
TSs (unless anything changes, this should be Library Fundamentals TS) and =
on track to be considered for C++17. The three years lead time is intended =
exactly to gather the wider practical experience you are concerned about.</=
div><div><br></div><div>I hope this helps to clarify our position.</div><di=
v><br>On Monday, June 16, 2014 5:49:39 PM UTC-7, Jeremy Maitin-Shepard wrot=
e:</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex=
;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;=
border-left-style:solid"><div dir=3D"ltr">On Sun, Jun 15, 2014 at 9:38 PM, =
=C5=81ukasz Mendakiewicz <span dir=3D"ltr"><<a>l.menda...@live.com</a>&g=
t;</span> wrote:<br><div><div class=3D"gmail_quote">
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;padding=
-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-l=
eft-style:solid"><div dir=3D"ltr"><p>Thank you Jeffrey for adding me on the=
thread and for your initial response -- which I almost universally agree w=
ith.</p>
<p>Jeremy, thank you for your detailed feedback. First, I believe that most=
of the disagreement stems from the approach to the proposal. You've commen=
ted that "it doesn't make sense to standardize a partial solution; bet=
ter to work out a good, complete interface outside the standard". This is o=
pposite to the "crawl, walk, run" philosophy we have taken when writing thi=
s document up. We recognize that we have only explored some parts of the de=
sign space, because as you have rightly observed our experience is limited =
to C++ AMP, which constitutes only a specific data parallel approach to alg=
orithms. Of course we believe that this is a solid foundation that can be g=
eneralized and built upon, hence the proposal. But we deliberately avoided =
any design decisions which may be controversial or result in a prolonged tu=
g of war, instead intending for subsequent proposals (not necessarily autho=
red by us) to fill the gaps. Certainly, should anything being proposed now =
be a possible hindrance for any reasonable extension, it must be addressed =
sooner than later, however I think that none of the lacks pointed by you be=
long to this category.</p>
</div></blockquote><div>I think it is basically impossible to nail down eve=
n a "minimal" interface without considering the design of a complete librar=
y. If you looked at 10 different, widely-used C++ multidimensional ar=
ray libraries and saw that all of their interfaces shared a given attribute=
, then standardizing that attribute of the interface would likely be a safe=
choice. Obviously that is not the case here, though.<br>
<br>Some examples of design options:<br></div><div>- Make array_view parame=
terized by the pointer type, rather than the value type. This allows =
it to hold smart pointers of various types, or a pointer that represents GP=
U memory, or a smart pointer that represents GPU memory, etc. If the =
pointer is to GPU memory, reading and writing won't work (and won't be allo=
wed at compile-time), but the indexing, slicing, sectioning and other opera=
tions on the array_view representation itself can still be used. This=
is the decision I took in my own in-house library. Allowing array_vi=
ew to hold a smart pointer means you don't need a separate type to represen=
t an array_view with ownership. (Sectioning and slicing produces a re=
sult with the pointer decayed to a regular pointer.) You can also use=
a __restrict__ pointer for an array_view type used as a function parameter=
to indicate lack of aliasing.<br>
<br></div><div>- Make bounds and index just generic fixed-size vector types=
.. In this case iterators on bounds should iterate over the components=
, rather than iterate over coordinates within the bounds.<br></div><div>&nb=
sp;<br>
</div><div>- More generally, the proposal distinguishes between array_view =
and strided_array_view, but doesn't allow for more fine-grained information=
to be provided at compile time, such as the number of trailing contiguous =
dimensions, alignment information, etc.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>>>> Some particula=
r issues with the proposed design include: <br>>>> <br>
>>> - No iterators are provided for array_view or strided_array_vi=
ew, a clear <br>>>> omission in the interface. For a multidi=
mensional array, there are two <br>>>> obvious types of iteration =
that may be desired: <br>
>>> 1. iterating over just the first dimension; <br>&g=
t;>> 2. iterating over a flat view of all of the elements=
.. For a strided <br>>>> array, iterating over a flat view ca=
nnot be done efficiently without <br>
>>> segmented/hierarchical iterators. <br>>>> =
Which of these should be the default (i.e. provided through begin() and <b=
r>>>> end() rather than through some adaptor) is not clear, <br>&g=
t;><br>
>> From the Zen of Python, "In the face of ambiguity, refuse the <br>=
>> temptation to guess." <br>><br>> That's true, but no adaptor=
s to provide the functionality unambiguously are provided either. For=
the particular case of a one-dimensional array, there is no ambiguity, and=
not being able to easily use array_view with standard algorithms or range-=
based for is a serious usability issue. This will only become worse i=
f/when standard algorithm overloads that take ranges rather than iterator p=
airs are added.</p>
</div><p>To the list of possible alternatives, I would add an option that w=
as proposed somewhere in the prior discussion on the proposal -- "hierarchi=
cal" array_view/elemental iterator, i.e. an iterator that for array_view<=
;T, Rank> with Rank > 1 iterates over array_view<T, Rank-1>; an=
d over T for Rank =3D=3D 1.<br>
</p></div></blockquote><div>Yes, that is a better way of expressing what I =
meant by "iterating over just the first dimension". I believe this ma=
kes the most sense, but then it becomes desirable to have size() be the siz=
e of the first dimension for consistency with the iterators, and instead ad=
d a num_elements() that returns the total number of elements. The cor=
rect definition of size() is hard to decide without figuring out how iterat=
ors should work.<br>
<br></div><div>The other issue is that if the iterators are hierarchical, y=
ou need a new hierarchical for_each that effectively expands to N nested fo=
r loops for N-dimensional arrays and which can operate on multiple arrays (=
of the same size). This way you can express element-wise operations w=
ithout any overhead.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><p>It is however worth pointing out=
that in the first round of review with LEWG at Issaquah meeting, the vocal=
unchallenged feedback for iterators was "I do not want iterators for the v=
iews", thus we did not put much effort into contemplating adding any. Even =
though the choice for Rank =3D=3D 1 is "obvious", we consider this a corner=
case for array_view, and would rather have a holistic approach.<br>
There remains the possibility to add some form of the iterator as a future =
extension.</p></div></blockquote><div>Well, you can take my comments as a c=
hallenge to that view. Rank =3D=3D 1 may be a "corner" case, but is l=
ikely to be used more frequently than all other cases combined. A 1-d=
imensional array view that can't be used with for-range loops, boost (or st=
d?) range adapters, etc. is a non-starter.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>>>> - No data() ac=
cess member for strided_array_view. This is presumably <br>
>>> omitted because the memory is non-contiguous, but given that <=
br>>>> strided_array_view is a thin wrapper, there has to be a con=
venient way to <br>>>> get at the underlying memory. <br>>><=
br>
>> Why "has to"? <br>><br>> Because the user might want to conv=
ert the array to another representation for use by another piece of code/li=
brary, e.g. FFTW or Eigen, CUDA memcpy, etc. Under the proposed inter=
face, for a 3-dimensional stided array view, you have to use &arr[0][0]=
[0]. This is even worse than having to do &vec[0] for std::vector=
, since the same expression cannot be used independent of the dimensionalit=
y.</p>
</div><p>data() on strided_array_view could be harmful, as there is no guar=
antee of contiguity, which a developer / function template might assume. Pl=
ease note that for every other case in the Standard, the range [data(), dat=
a()+size()) is valid/safe, thus providing other semantics here would be dub=
ious.<br>
Granted, one can perform &arr[0][0][0] and run afoul, but that is no di=
fferent than e.g. &my_list.front().<br>It could be possible to provide =
"unsafe_data()" interface, which would have to be consumed along with strid=
e(), however I do not see much benefit here over just using the "proper" in=
terface -- bounds() and operator[]().</p>
</div></blockquote><div>Calling it noncontiguous_data() is fine, though cer=
tainly then array_view should have an noncontiguous_data() (in addition to =
data()) as well for consistency. I don't think unsafe_data is really =
the right name, though the functionality is more important than the name.&n=
bsp; &arr[0][0][0] has the disadvantage that it is more verbose and doe=
sn't allow for writing generic code that works with any number of dimension=
s. Just using the "proper" interface isn't a solution. A fundam=
ental component like multidimensional arrays cannot be a "walled garden".&n=
bsp; The (pointer, bounds, strides) representation, which numerous other li=
braries like FFTW use as well, should be transparent.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><p></p><div>>>> - Slicing =
is limited: it is not possible to take a slice in a dimension <br>
>>> other than the first. <br>>><br>>> I think that's =
called "section()". <br>><br></div>> Well, that takes a "section" but=
does not reduce the dimensionality like "slice". [...] Certainly there is =
a large design space for general subscripting and it almost certainly requi=
res a fair amount of template metaprogramming, but this is very useful func=
tionality<p>
</p><p>Yes, slicing and sectioning are slightly different. It is however im=
portant to note that slicing in its current form always guarantees the cont=
iguity of the result, thus the return type may be array_view. The more gene=
ral cases (as you are describing) would result in a potentially strided res=
ulting view, which would need to be typed strided_array_view. This is why i=
t is important IMO to distinguish these two cases.<br>
In the current form of the proposal we decided to provide the minimal desig=
n -- only the first version, which in our opinion might be handy for users =
used to C-style multidimensional addressing (i.e. arr[3][1][4] v arr[{3, 1,=
4}]), which actually you used above :).<br>
The latter generic case can be trivially added as an extension to the inter=
face. I agree it may be useful, and if the current design is accepted for t=
he TS, I encourage you to propose such extension (or nag us for follow ups =
:)).</p>
<div><p>>>> - It is not clear whether it is really useful to have =
bounds and index be <br>>>> separate types (though should probably=
at least be explicitly convertible to <br>>>> each other). <br>
>><br>>> It adds a bit of type safety. Adding two bounds, for i=
nstance, doesn't <br>>> make a lot of sense. <br>><br>> I agree=
that type safety is in principle useful, but it is impossible to predict w=
hat relationships might hold in any given program, and so there is the ques=
tion of whether the safety it adds is worth the cost of having to explicitl=
y work around it in the cases that it is too restrictive. Certainly i=
f they are separate types there needs to be a way to (explicitly) convert.<=
/p>
</div><p>I agree with both of you :).<br>These are separate types, because =
their meaning and semantics are different. It was also discussed in N3851, =
Appendix, II. The mental model I use for reasoning about them is: index ~ v=
ector and bounds ~ point (more specifically: a zero-bound, axis-aligned rec=
tangle described by its maximum point), which makes the set of available op=
erators apparent.<br>
I understand the explicit conversions between these two types, even though =
not theoretically sound, might be handy in practice and should be added.</p=
></div></blockquote><div>If we follow that logic, a point is a vector from =
the origin. Therefore index should just be Vector<ptrdiff_t,N> =
and bounds<N> could have a Vector<ptrdiff_t,N> member. Ho=
wever, it seems like it would be simpler to just have bounds be Vector<p=
trdiff_t,N> as well and save the trouble of the explicit conversions.&nb=
sp; What type of error does the bounds/index distinction prevent? Mor=
e generally, I am not sure why we shouldn't think of an index as a point as=
well. If we want the last element in an array x, we have : x.bounds(=
) - 1 (or x.bounds() - {1,1, ...}). We want to use this as an i=
ndex, but the current operator definitions would have it be a bounds.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>> As a specific example,=
consider if we want to compute the bounds of a valid convolution if we hav=
e an array x and a filter k. The bounds of the result are: x.bounds -=
k.bounds + 1. None of the arithmetic operators defined in the propos=
al help me with that; I'd just have to write a loop. Even if the arit=
hmetic operators weren't limited by the bounds/index distinction, there wou=
ld still be no way to create a constant-valued vector, i.e. to handle the c=
onstant 1.</p>
</div><p>Explicit conversions would help with the first part, right? I hope=
you are also not suggesting any such conversion should be implicit?<br>How=
ever I do not really understand what do you mean in the second part, "a con=
stant-valued vector". We purposefully allow to create both bounds<1> =
and index<1> from a scalar; and disallow such operation for Rank >=
1 (mostly because the semantics are not obvious, e.g. for rank 2, should i=
ndex<2>{16} be {0, 16}, {16, 0} or {16, 16}).<br>
So net-net, in your example you should be able to do: x.bounds - index<2=
>{k.bounds} + {1, 1}. It a little more long-winded, but IMO easier to co=
mprehend than the original.</p></div></blockquote><div>I don't think the ex=
plicit conversion to index adds to the clarity. Also, the problem wit=
h {1, 1} is that it depends on the dimensionality. The interface shou=
ld be designed to be convenient for generic code. I would suggest a S=
calar<T> type generated by a wrapper function scalar, from which boun=
ds and index can be implicitly constructed and which can be used in all of =
the operators.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>> Another related issue =
I didn't notice before: the only way to construct an index or bounds type i=
s from an initializer_list. There is no (explicit) conversion from st=
d::array, for instance. It is quite likely that an index or bounds va=
lue would be computed by some other code, that may use a different represen=
tation.</p>
</div><p>Yes, we should add (const value_type* begin, const value_type* end=
) constructors for both types. <rant>Or it should be possible to crea=
te initializer_list explicitly from such pair which would solve this issue =
universally.</rant></p>
</div></blockquote><div>Okay, though initializer_list is not compile-time s=
ized.<br></div><div> </div><blockquote class=3D"gmail_quote" style=3D"=
margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204=
);border-left-width:1px;border-left-style:solid"><div dir=3D"ltr"><div>
>>> Furthermore, bounds and index essentially represent a <br>>=
>> fixed-size discrete vector type, i.e. an augmented interface for s=
td::array. <br>>>> Arguably the interface of std::array should jus=
t be extended to add <br>
>>> component-wise operators instead. Also, a much more comp=
rehensive set of <br>>>> component-wise operations should be provi=
ded. A statically-sized vector <br>>>> type is sorely needed=
in C++, but it does not make sense to standardize <br>
>>> these limited, single-purposes types when they could be, and s=
hould be, much <br>>>> more general. <br>>><br>>> We d=
on't necessarily want to go for the most general possible type all at once<=
br>
><br></div>> Certainly there is a large design space, but that is a r=
eason to be cautious about standardizing anything. [...]<p></p><p>There are=
two separate issue raised here:<br>- Why novel types -- this is primarily =
to introduce "vocabulary" types and allow to discriminate index and bounds,=
as they have different semantics, as discussed before. This was also touch=
ed upon in the previously referred N3851, Appendix, II.<br>
- Why so little functionality -- I agree with Jeffrey on this, and I have d=
escribed more of the philosophy in the introduction. I would be interested =
however what exactly you mean by "a much more comprehensive set of componen=
t-wise operations".</p>
</div></blockquote><div>Almost anything could be useful (and I am thinking =
of the perspective of a general fixed-size vector type, but these all apply=
to index/bounds as well), but some particular examples: min, max, <, &l=
t;=3D, =3D=3D, !=3D, >=3D, >. The relational operations need to=
return a vector of bool, which isn't compatible with index/bounds currentl=
y since they aren't parameterized by the type. Obviously, though, it =
wouldn't make sense to call them index or bounds if they are parameterized =
by a type.<br>
</div><div> </div><blockquote class=3D"gmail_quote" style=3D"margin:0p=
x 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-=
left-width:1px;border-left-style:solid"><div dir=3D"ltr"><p>Having said tha=
t, I assume this is something that can be added later as a pure extension, =
correct?</p>
</div></blockquote><div></div><div>Some of them, like min and max, could be=
unintrusive, though neither index nor bounds would be a particularly meani=
ngful choice as the return type.<br></div><div> </div><blockquote clas=
s=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;padding-left:1ex;border=
-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"=
>
<div dir=3D"ltr"><div><p>> Given the long turn around time for revisions=
to C++</p></div><p>The Committee is certainly trying to get better at quic=
ker iterations, let's not be discouraged by the ghosts of the past...</p>
<div><p>> Other omissions from index and bounds include:<br>> 1=
.. no data() access to the components<br>> 2. no iterators over com=
ponents for index or bound</p></div><p>index and bounds are not containers =
and should not be used as such. For the limited number of scenario where I =
want to use/modify indeterminate number of components, it was always suffic=
ient for me to use a raw loop, and operator[]...<br>
In case I'm wrong, these as well should be easy to add later as extensions.=
</p><div><p>> for_each(x_array, y_array, x_array.bounds(), [&](auto =
&x, auto &y, auto pos) {<br>> if (x !=3D y) std::cou=
t << "mismatch at position " << pos << std::endl;<br>
> });</p></div><p>I assume the idea here is that such "for_each" uses be=
gin(X), end(X) for all provided arguments, passing dereferenced iterators t=
o the function object. If so, I do not see how the current semantics of bou=
nds_iterator would get into way here? It should just work as is, no?<br>
</p></div></blockquote><div>The idea is that it would generate N nested for=
loops for N-dimensional array views, rather than an less efficient single =
for loop.<br></div><div> </div><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204=
,204);border-left-width:1px;border-left-style:solid">
<div dir=3D"ltr"><p>Actually, it should be possible to write the following =
with just the current proposal and the current standard for_each:<br> =
auto x_av =3D array_view<N>{x_array};<br> auto y_av =3D array_vi=
ew<N>{y_array};<br>
for_each(begin(x_av.bounds())<wbr>, end(x_av.bounds()), [&](index=
<N> pos) {<br> if(x_av[pos] !=3D y_av[pos]) std::cout << =
"mismatch at position " << pos << std::endl;<br> });</p></=
div></blockquote>
<div>Yes, but note that the iteration over bounds is more expensive and the=
multiplication with all of the strides has to happen for every position.<b=
r></div><div> </div><blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);borde=
r-left-width:1px;border-left-style:solid">
<div dir=3D"ltr"><p>> From my perspective, the only way to properly expl=
ore this design space for multidimensional arrays/containers/ranges is thro=
ugh an actively developed and widely used open source library.</p><div>Our =
(Microsoft) prototype implementation is in the pipeline to be published as =
an open source project. It should happen really soon, and I hope it will he=
lp to convey the discussed ideas.</div>
</div></blockquote><div><br></div><div>That's good news. I think the =
best library is likely to be produced if the users of the library and the d=
evelopers of the library are one and the same. Issues become apparent=
and the library interface can be tweaked to correct them very quickly that=
way.<br>
</div></div></div></div>
</blockquote></div></blockquote></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_748_1726523670.1415996997569--
.
Author: Jeremy Maitin-Shepard <jeremy@jeremyms.com>
Date: Fri, 14 Nov 2014 12:51:52 -0800
Raw View
--f46d044280b66ef7ac0507d7ccf7
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
If the size is known at compile time, an actual reference to std::array (or
a multi-dimensional static-sized array counterpart) would be much better,
as this eliminates the need for an extra type, and makes reference decay do
the right thing. If the current language rules do not permit the casting
of an arbitrary pointer T *x where [x, x+size) is a valid range, to be a
pointer to std::array<T,size>*, then I think the language rules should be
changed, as this is clearly extremely useful and any loss of optimization
possibilities are probably minimal.
On Fri, Nov 14, 2014 at 12:29 PM, <phdofthehouse@gmail.com> wrote:
> As a small addition, has anyone considered perhaps calling the class
> buffer_view<typename T, size_type dimensions>
>
> and then leaving the name *array_view* for a compile-time version of this
> class (to match std::array)?
>
> I don't know if a fully constexpr-qualified version of the buffer_view
> class will have the same benefit as a compile-time defined
> array_view<typename T, size_type... dimension_sizes>
>
> class (with *strided* variants for buffer_view and array_view).
>
>
> On Friday, June 27, 2014 1:00:54 AM UTC-4, =C5=81ukasz Mendakiewicz wrote=
:
>>
>> I do understand your rationale in many of the points you are raising, an=
d
>> I am aware of other existing libraries, which in some cases made differe=
nt
>> design decisions. However many of the choices are mutually exclusive and=
in
>> my opinion it is impossible to converge on the "single best design". Man=
y
>> of the design decisions in our proposal are also compromises.
>>
>> I disagree with your judgment that we should strive to find an ultimate
>> solution before moving forward with any proposal. Lack of array_view or =
a
>> similar type is clearly a gap in C++ Standard, which many libraries are
>> addressing in different ways. We took the first stab in trying to addres=
s
>> this deficiency with putting forward the type we are familiar with, have
>> worked with successfully for over 2 years, and in the process we were al=
so
>> fixing all issues we were aware of. It surely is not rock solid -- nothi=
ng
>> is -- and many use-cases might have benefit from tailoring details
>> differently to cater each of them, but we have to start somewhere.
>> Importantly, we are not "standardizing" array_view yet. If it passes LWG
>> voting on the next Committee meeting it will be merely appended to one o=
f
>> TSs (unless anything changes, this should be Library Fundamentals TS) an=
d
>> on track to be considered for C++17. The three years lead time is intend=
ed
>> exactly to gather the wider practical experience you are concerned about=
..
>>
>> I hope this helps to clarify our position.
>>
>> On Monday, June 16, 2014 5:49:39 PM UTC-7, Jeremy Maitin-Shepard wrote:
>>
>>> On Sun, Jun 15, 2014 at 9:38 PM, =C5=81ukasz Mendakiewicz <
>>> l.menda...@live.com> wrote:
>>>
>>>> Thank you Jeffrey for adding me on the thread and for your initial
>>>> response -- which I almost universally agree with.
>>>>
>>>> Jeremy, thank you for your detailed feedback. First, I believe that
>>>> most of the disagreement stems from the approach to the proposal. You'=
ve
>>>> commented that "it doesn't make sense to standardize a partial solutio=
n;
>>>> better to work out a good, complete interface outside the standard". T=
his
>>>> is opposite to the "crawl, walk, run" philosophy we have taken when wr=
iting
>>>> this document up. We recognize that we have only explored some parts o=
f the
>>>> design space, because as you have rightly observed our experience is
>>>> limited to C++ AMP, which constitutes only a specific data parallel
>>>> approach to algorithms. Of course we believe that this is a solid
>>>> foundation that can be generalized and built upon, hence the proposal.=
But
>>>> we deliberately avoided any design decisions which may be controversia=
l or
>>>> result in a prolonged tug of war, instead intending for subsequent
>>>> proposals (not necessarily authored by us) to fill the gaps. Certainly=
,
>>>> should anything being proposed now be a possible hindrance for any
>>>> reasonable extension, it must be addressed sooner than later, however =
I
>>>> think that none of the lacks pointed by you belong to this category.
>>>>
>>> I think it is basically impossible to nail down even a "minimal"
>>> interface without considering the design of a complete library. If you
>>> looked at 10 different, widely-used C++ multidimensional array librarie=
s
>>> and saw that all of their interfaces shared a given attribute, then
>>> standardizing that attribute of the interface would likely be a safe
>>> choice. Obviously that is not the case here, though.
>>>
>>> Some examples of design options:
>>> - Make array_view parameterized by the pointer type, rather than the
>>> value type. This allows it to hold smart pointers of various types, or=
a
>>> pointer that represents GPU memory, or a smart pointer that represents =
GPU
>>> memory, etc. If the pointer is to GPU memory, reading and writing won'=
t
>>> work (and won't be allowed at compile-time), but the indexing, slicing,
>>> sectioning and other operations on the array_view representation itself=
can
>>> still be used. This is the decision I took in my own in-house library.
>>> Allowing array_view to hold a smart pointer means you don't need a sepa=
rate
>>> type to represent an array_view with ownership. (Sectioning and slicin=
g
>>> produces a result with the pointer decayed to a regular pointer.) You =
can
>>> also use a __restrict__ pointer for an array_view type used as a functi=
on
>>> parameter to indicate lack of aliasing.
>>>
>>> - Make bounds and index just generic fixed-size vector types. In this
>>> case iterators on bounds should iterate over the components, rather tha=
n
>>> iterate over coordinates within the bounds.
>>>
>>> - More generally, the proposal distinguishes between array_view and
>>> strided_array_view, but doesn't allow for more fine-grained information=
to
>>> be provided at compile time, such as the number of trailing contiguous
>>> dimensions, alignment information, etc.
>>>
>>>> >>> Some particular issues with the proposed design include:
>>>> >>>
>>>> >>> - No iterators are provided for array_view or strided_array_view, =
a
>>>> clear
>>>> >>> omission in the interface. For a multidimensional array, there ar=
e
>>>> two
>>>> >>> obvious types of iteration that may be desired:
>>>> >>> 1. iterating over just the first dimension;
>>>> >>> 2. iterating over a flat view of all of the elements. For a
>>>> strided
>>>> >>> array, iterating over a flat view cannot be done efficiently
>>>> without
>>>> >>> segmented/hierarchical iterators.
>>>> >>> Which of these should be the default (i.e. provided through
>>>> begin() and
>>>> >>> end() rather than through some adaptor) is not clear,
>>>> >>
>>>> >> From the Zen of Python, "In the face of ambiguity, refuse the
>>>> >> temptation to guess."
>>>> >
>>>> > That's true, but no adaptors to provide the functionality
>>>> unambiguously are provided either. For the particular case of a
>>>> one-dimensional array, there is no ambiguity, and not being able to ea=
sily
>>>> use array_view with standard algorithms or range-based for is a seriou=
s
>>>> usability issue. This will only become worse if/when standard algorit=
hm
>>>> overloads that take ranges rather than iterator pairs are added.
>>>>
>>>> To the list of possible alternatives, I would add an option that was
>>>> proposed somewhere in the prior discussion on the proposal --
>>>> "hierarchical" array_view/elemental iterator, i.e. an iterator that fo=
r
>>>> array_view<T, Rank> with Rank > 1 iterates over array_view<T, Rank-1>;=
and
>>>> over T for Rank =3D=3D 1.
>>>>
>>> Yes, that is a better way of expressing what I meant by "iterating over
>>> just the first dimension". I believe this makes the most sense, but th=
en
>>> it becomes desirable to have size() be the size of the first dimension =
for
>>> consistency with the iterators, and instead add a num_elements() that
>>> returns the total number of elements. The correct definition of size()=
is
>>> hard to decide without figuring out how iterators should work.
>>>
>>> The other issue is that if the iterators are hierarchical, you need a
>>> new hierarchical for_each that effectively expands to N nested for loop=
s
>>> for N-dimensional arrays and which can operate on multiple arrays (of t=
he
>>> same size). This way you can express element-wise operations without a=
ny
>>> overhead.
>>>
>>>> It is however worth pointing out that in the first round of review wit=
h
>>>> LEWG at Issaquah meeting, the vocal unchallenged feedback for iterator=
s was
>>>> "I do not want iterators for the views", thus we did not put much effo=
rt
>>>> into contemplating adding any. Even though the choice for Rank =3D=3D =
1 is
>>>> "obvious", we consider this a corner case for array_view, and would ra=
ther
>>>> have a holistic approach.
>>>> There remains the possibility to add some form of the iterator as a
>>>> future extension.
>>>>
>>> Well, you can take my comments as a challenge to that view. Rank =3D=
=3D 1
>>> may be a "corner" case, but is likely to be used more frequently than a=
ll
>>> other cases combined. A 1-dimensional array view that can't be used wi=
th
>>> for-range loops, boost (or std?) range adapters, etc. is a non-starter.
>>>
>>>> >>> - No data() access member for strided_array_view. This is
>>>> presumably
>>>> >>> omitted because the memory is non-contiguous, but given that
>>>> >>> strided_array_view is a thin wrapper, there has to be a convenient
>>>> way to
>>>> >>> get at the underlying memory.
>>>> >>
>>>> >> Why "has to"?
>>>> >
>>>> > Because the user might want to convert the array to another
>>>> representation for use by another piece of code/library, e.g. FFTW or
>>>> Eigen, CUDA memcpy, etc. Under the proposed interface, for a 3-dimens=
ional
>>>> stided array view, you have to use &arr[0][0][0]. This is even worse =
than
>>>> having to do &vec[0] for std::vector, since the same expression cannot=
be
>>>> used independent of the dimensionality.
>>>>
>>>> data() on strided_array_view could be harmful, as there is no guarante=
e
>>>> of contiguity, which a developer / function template might assume. Ple=
ase
>>>> note that for every other case in the Standard, the range [data(),
>>>> data()+size()) is valid/safe, thus providing other semantics here woul=
d be
>>>> dubious.
>>>> Granted, one can perform &arr[0][0][0] and run afoul, but that is no
>>>> different than e.g. &my_list.front().
>>>> It could be possible to provide "unsafe_data()" interface, which would
>>>> have to be consumed along with stride(), however I do not see much ben=
efit
>>>> here over just using the "proper" interface -- bounds() and operator[]=
().
>>>>
>>> Calling it noncontiguous_data() is fine, though certainly then
>>> array_view should have an noncontiguous_data() (in addition to data()) =
as
>>> well for consistency. I don't think unsafe_data is really the right na=
me,
>>> though the functionality is more important than the name. &arr[0][0][0=
]
>>> has the disadvantage that it is more verbose and doesn't allow for writ=
ing
>>> generic code that works with any number of dimensions. Just using the
>>> "proper" interface isn't a solution. A fundamental component like
>>> multidimensional arrays cannot be a "walled garden". The (pointer, bou=
nds,
>>> strides) representation, which numerous other libraries like FFTW use a=
s
>>> well, should be transparent.
>>>
>>>> >>> - Slicing is limited: it is not possible to take a slice in a
>>>> dimension
>>>> >>> other than the first.
>>>> >>
>>>> >> I think that's called "section()".
>>>> >
>>>> > Well, that takes a "section" but does not reduce the dimensionality
>>>> like "slice". [...] Certainly there is a large design space for genera=
l
>>>> subscripting and it almost certainly requires a fair amount of templat=
e
>>>> metaprogramming, but this is very useful functionality
>>>>
>>>> Yes, slicing and sectioning are slightly different. It is however
>>>> important to note that slicing in its current form always guarantees t=
he
>>>> contiguity of the result, thus the return type may be array_view. The =
more
>>>> general cases (as you are describing) would result in a potentially st=
rided
>>>> resulting view, which would need to be typed strided_array_view. This =
is
>>>> why it is important IMO to distinguish these two cases.
>>>> In the current form of the proposal we decided to provide the minimal
>>>> design -- only the first version, which in our opinion might be handy =
for
>>>> users used to C-style multidimensional addressing (i.e. arr[3][1][4] v
>>>> arr[{3, 1, 4}]), which actually you used above :).
>>>> The latter generic case can be trivially added as an extension to the
>>>> interface. I agree it may be useful, and if the current design is acce=
pted
>>>> for the TS, I encourage you to propose such extension (or nag us for f=
ollow
>>>> ups :)).
>>>>
>>>> >>> - It is not clear whether it is really useful to have bounds and
>>>> index be
>>>> >>> separate types (though should probably at least be explicitly
>>>> convertible to
>>>> >>> each other).
>>>> >>
>>>> >> It adds a bit of type safety. Adding two bounds, for instance,
>>>> doesn't
>>>> >> make a lot of sense.
>>>> >
>>>> > I agree that type safety is in principle useful, but it is impossibl=
e
>>>> to predict what relationships might hold in any given program, and so =
there
>>>> is the question of whether the safety it adds is worth the cost of hav=
ing
>>>> to explicitly work around it in the cases that it is too restrictive.
>>>> Certainly if they are separate types there needs to be a way to
>>>> (explicitly) convert.
>>>>
>>>> I agree with both of you :).
>>>> These are separate types, because their meaning and semantics are
>>>> different. It was also discussed in N3851, Appendix, II. The mental mo=
del I
>>>> use for reasoning about them is: index ~ vector and bounds ~ point (mo=
re
>>>> specifically: a zero-bound, axis-aligned rectangle described by its ma=
ximum
>>>> point), which makes the set of available operators apparent.
>>>> I understand the explicit conversions between these two types, even
>>>> though not theoretically sound, might be handy in practice and should =
be
>>>> added.
>>>>
>>> If we follow that logic, a point is a vector from the origin. Therefor=
e
>>> index should just be Vector<ptrdiff_t,N> and bounds<N> could have a
>>> Vector<ptrdiff_t,N> member. However, it seems like it would be simpler=
to
>>> just have bounds be Vector<ptrdiff_t,N> as well and save the trouble of=
the
>>> explicit conversions. What type of error does the bounds/index distinc=
tion
>>> prevent? More generally, I am not sure why we shouldn't think of an in=
dex
>>> as a point as well. If we want the last element in an array x, we have=
:
>>> x.bounds() - 1 (or x.bounds() - {1,1, ...}). We want to use this as a=
n
>>> index, but the current operator definitions would have it be a bounds.
>>>
>>>> > As a specific example, consider if we want to compute the bounds of =
a
>>>> valid convolution if we have an array x and a filter k. The bounds of=
the
>>>> result are: x.bounds - k.bounds + 1. None of the arithmetic operators
>>>> defined in the proposal help me with that; I'd just have to write a lo=
op.
>>>> Even if the arithmetic operators weren't limited by the bounds/index
>>>> distinction, there would still be no way to create a constant-valued
>>>> vector, i.e. to handle the constant 1.
>>>>
>>>> Explicit conversions would help with the first part, right? I hope you
>>>> are also not suggesting any such conversion should be implicit?
>>>> However I do not really understand what do you mean in the second part=
,
>>>> "a constant-valued vector". We purposefully allow to create both bound=
s<1>
>>>> and index<1> from a scalar; and disallow such operation for Rank > 1
>>>> (mostly because the semantics are not obvious, e.g. for rank 2, should
>>>> index<2>{16} be {0, 16}, {16, 0} or {16, 16}).
>>>> So net-net, in your example you should be able to do: x.bounds -
>>>> index<2>{k.bounds} + {1, 1}. It a little more long-winded, but IMO eas=
ier
>>>> to comprehend than the original.
>>>>
>>> I don't think the explicit conversion to index adds to the clarity.
>>> Also, the problem with {1, 1} is that it depends on the dimensionality.
>>> The interface should be designed to be convenient for generic code. I
>>> would suggest a Scalar<T> type generated by a wrapper function scalar, =
from
>>> which bounds and index can be implicitly constructed and which can be u=
sed
>>> in all of the operators.
>>>
>>>> > Another related issue I didn't notice before: the only way to
>>>> construct an index or bounds type is from an initializer_list. There =
is no
>>>> (explicit) conversion from std::array, for instance. It is quite like=
ly
>>>> that an index or bounds value would be computed by some other code, th=
at
>>>> may use a different representation.
>>>>
>>>> Yes, we should add (const value_type* begin, const value_type* end)
>>>> constructors for both types. <rant>Or it should be possible to create
>>>> initializer_list explicitly from such pair which would solve this issu=
e
>>>> universally.</rant>
>>>>
>>> Okay, though initializer_list is not compile-time sized.
>>>
>>>
>>>> >>> Furthermore, bounds and index essentially represent a
>>>> >>> fixed-size discrete vector type, i.e. an augmented interface for
>>>> std::array.
>>>> >>> Arguably the interface of std::array should just be extended to ad=
d
>>>> >>> component-wise operators instead. Also, a much more comprehensive
>>>> set of
>>>> >>> component-wise operations should be provided. A statically-sized
>>>> vector
>>>> >>> type is sorely needed in C++, but it does not make sense to
>>>> standardize
>>>> >>> these limited, single-purposes types when they could be, and shoul=
d
>>>> be, much
>>>> >>> more general.
>>>> >>
>>>> >> We don't necessarily want to go for the most general possible type
>>>> all at once
>>>> >
>>>> > Certainly there is a large design space, but that is a reason to be
>>>> cautious about standardizing anything. [...]
>>>>
>>>> There are two separate issue raised here:
>>>> - Why novel types -- this is primarily to introduce "vocabulary" types
>>>> and allow to discriminate index and bounds, as they have different
>>>> semantics, as discussed before. This was also touched upon in the
>>>> previously referred N3851, Appendix, II.
>>>> - Why so little functionality -- I agree with Jeffrey on this, and I
>>>> have described more of the philosophy in the introduction. I would be
>>>> interested however what exactly you mean by "a much more comprehensive=
set
>>>> of component-wise operations".
>>>>
>>> Almost anything could be useful (and I am thinking of the perspective o=
f
>>> a general fixed-size vector type, but these all apply to index/bounds a=
s
>>> well), but some particular examples: min, max, <, <=3D, =3D=3D, !=3D, >=
=3D, >. The
>>> relational operations need to return a vector of bool, which isn't
>>> compatible with index/bounds currently since they aren't parameterized =
by
>>> the type. Obviously, though, it wouldn't make sense to call them index=
or
>>> bounds if they are parameterized by a type.
>>>
>>>
>>>> Having said that, I assume this is something that can be added later a=
s
>>>> a pure extension, correct?
>>>>
>>> Some of them, like min and max, could be unintrusive, though neither
>>> index nor bounds would be a particularly meaningful choice as the retur=
n
>>> type.
>>>
>>>
>>>> > Given the long turn around time for revisions to C++
>>>>
>>>> The Committee is certainly trying to get better at quicker iterations,
>>>> let's not be discouraged by the ghosts of the past...
>>>>
>>>> > Other omissions from index and bounds include:
>>>> > 1. no data() access to the components
>>>> > 2. no iterators over components for index or bound
>>>>
>>>> index and bounds are not containers and should not be used as such. Fo=
r
>>>> the limited number of scenario where I want to use/modify indeterminat=
e
>>>> number of components, it was always sufficient for me to use a raw loo=
p,
>>>> and operator[]...
>>>> In case I'm wrong, these as well should be easy to add later as
>>>> extensions.
>>>>
>>>> > for_each(x_array, y_array, x_array.bounds(), [&](auto &x, auto &y,
>>>> auto pos) {
>>>> > if (x !=3D y) std::cout << "mismatch at position " << pos <<
>>>> std::endl;
>>>> > });
>>>>
>>>> I assume the idea here is that such "for_each" uses begin(X), end(X)
>>>> for all provided arguments, passing dereferenced iterators to the func=
tion
>>>> object. If so, I do not see how the current semantics of bounds_iterat=
or
>>>> would get into way here? It should just work as is, no?
>>>>
>>> The idea is that it would generate N nested for loops for N-dimensional
>>> array views, rather than an less efficient single for loop.
>>>
>>>
>>>> Actually, it should be possible to write the following with just the
>>>> current proposal and the current standard for_each:
>>>> auto x_av =3D array_view<N>{x_array};
>>>> auto y_av =3D array_view<N>{y_array};
>>>> for_each(begin(x_av.bounds()), end(x_av.bounds()), [&](index<N> pos) =
{
>>>> if(x_av[pos] !=3D y_av[pos]) std::cout << "mismatch at position " <<
>>>> pos << std::endl;
>>>> });
>>>>
>>> Yes, but note that the iteration over bounds is more expensive and the
>>> multiplication with all of the strides has to happen for every position=
..
>>>
>>>
>>>> > From my perspective, the only way to properly explore this design
>>>> space for multidimensional arrays/containers/ranges is through an acti=
vely
>>>> developed and widely used open source library.
>>>> Our (Microsoft) prototype implementation is in the pipeline to be
>>>> published as an open source project. It should happen really soon, and=
I
>>>> hope it will help to convey the discussed ideas.
>>>>
>>>
>>> That's good news. I think the best library is likely to be produced if
>>> the users of the library and the developers of the library are one and =
the
>>> same. Issues become apparent and the library interface can be tweaked =
to
>>> correct them very quickly that way.
>>>
>> --
>
> ---
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/xzb1d5KUxMU/=
unsubscribe
> .
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> Visit this group at
> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
--f46d044280b66ef7ac0507d7ccf7
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">If the size is known at compile time, an actual reference =
to std::array (or a multi-dimensional static-sized array counterpart) would=
be much better, as this eliminates the need for an extra type, and makes r=
eference decay do the right thing.=C2=A0 If the current language rules do n=
ot permit the casting of an arbitrary pointer T *x where [x, x+size) is a v=
alid range, to be a pointer to std::array<T,size>*, then I think the =
language rules should be changed, as this is clearly extremely useful and a=
ny loss of optimization possibilities are probably minimal.<br></div><div c=
lass=3D"gmail_extra"><br><div class=3D"gmail_quote">On Fri, Nov 14, 2014 at=
12:29 PM, <span dir=3D"ltr"><<a href=3D"mailto:phdofthehouse@gmail.com=
" target=3D"_blank">phdofthehouse@gmail.com</a>></span> wrote:<br><block=
quote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc=
solid;padding-left:1ex"><div dir=3D"ltr">As a small addition, has anyone c=
onsidered perhaps calling the class <div style=3D"background-color:rgb(250,=
250,250);border-color:rgb(187,187,187);border-style:solid;border-width:1px;=
word-wrap:break-word"><code><div><span style=3D"color:#000">buffer_view</sp=
an><span style=3D"color:#660"><</span><span style=3D"color:#008">typenam=
e</span><span style=3D"color:#000"> T</span><span style=3D"color:#660">,</s=
pan><span style=3D"color:#000"> size_type dimensions</span><span style=3D"c=
olor:#660">></span></div></code></div><br> and then leaving the name <i>=
array_view</i> for a compile-time version of this class (to match std::arra=
y)?<br><br>I don't know if a fully constexpr-qualified version of the b=
uffer_view class will have the same benefit as a compile-time defined <div =
style=3D"background-color:rgb(250,250,250);border-color:rgb(187,187,187);bo=
rder-style:solid;border-width:1px;word-wrap:break-word"><code><div><span st=
yle=3D"color:#000">array_view</span><span style=3D"color:#660"><</span><=
span style=3D"color:#008">typename</span><span style=3D"color:#000"> T</spa=
n><span style=3D"color:#660">,</span><span style=3D"color:#000"> size_type<=
/span><span style=3D"color:#660">...</span><span style=3D"color:#000"> dime=
nsion_sizes</span><span style=3D"color:#660">></span></div></code></div>=
<br>class (with <i>strided</i> variants for buffer_view and array_view).<di=
v><div class=3D"h5"><br><br>On Friday, June 27, 2014 1:00:54 AM UTC-4, =C5=
=81ukasz Mendakiewicz wrote:<blockquote class=3D"gmail_quote" style=3D"marg=
in:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div di=
r=3D"ltr"><p>I do understand your rationale in many of the points you are r=
aising, and I am aware of other existing libraries, which in some cases mad=
e different design decisions. However many of the choices are mutually excl=
usive and in my opinion it is impossible to converge on the "single be=
st design". Many of the design decisions in our proposal are also comp=
romises.</p><p>I disagree with your judgment that we should strive to find =
an ultimate solution before moving forward with any proposal. Lack of array=
_view or a similar type is clearly a gap in C++ Standard, which many librar=
ies are addressing in different ways. We took the first stab in trying to a=
ddress this deficiency with putting forward the type we are familiar with, =
have worked with successfully for over 2 years, and in the process we were =
also fixing all issues we were aware of. It surely is not rock solid -- not=
hing is -- and many use-cases might have benefit from tailoring details dif=
ferently to cater each of them, but we have to start somewhere.</p><div>Imp=
ortantly, we are not "standardizing" array_view yet. If it passes=
LWG voting on the next Committee meeting it will be merely appended to one=
of TSs (unless anything changes, this should be Library Fundamentals TS) a=
nd on track to be considered for C++17. The three years lead time is intend=
ed exactly to gather the wider practical experience you are concerned about=
..</div><div><br></div><div>I hope this helps to clarify our position.</div>=
<div><br>On Monday, June 16, 2014 5:49:39 PM UTC-7, Jeremy Maitin-Shepard w=
rote:</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.=
8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1=
px;border-left-style:solid"><div dir=3D"ltr">On Sun, Jun 15, 2014 at 9:38 P=
M, =C5=81ukasz Mendakiewicz <span dir=3D"ltr"><<a>l.menda...@live.com</a=
>></span> wrote:<br><div><div class=3D"gmail_quote">
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;padding=
-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-l=
eft-style:solid"><div dir=3D"ltr"><p>Thank you Jeffrey for adding me on the=
thread and for your initial response -- which I almost universally agree w=
ith.</p>
<p>Jeremy, thank you for your detailed feedback. First, I believe that most=
of the disagreement stems from the approach to the proposal. You've co=
mmented=C2=A0that "it doesn't make sense to standardize a partial =
solution; better to work out a good, complete interface outside the standar=
d". This is opposite to the "crawl, walk, run" philosophy we=
have taken when writing this document up. We recognize that we have only e=
xplored some parts of the design space, because as you have rightly observe=
d our experience is limited to C++ AMP, which constitutes only a specific d=
ata parallel approach to algorithms. Of course we believe that this is a so=
lid foundation that can be generalized and built upon, hence the proposal. =
But we deliberately avoided any design decisions which may be controversial=
or result in a prolonged tug of war, instead intending for subsequent prop=
osals (not necessarily authored by us) to fill the gaps. Certainly, should =
anything being proposed now be a possible hindrance for any reasonable exte=
nsion, it must be addressed sooner than later, however I think that none of=
the lacks pointed by you belong to this category.</p>
</div></blockquote><div>I think it is basically impossible to nail down eve=
n a "minimal" interface without considering the design of a compl=
ete library.=C2=A0 If you looked at 10 different, widely-used C++ multidime=
nsional array libraries and saw that all of their interfaces shared a given=
attribute, then standardizing that attribute of the interface would likely=
be a safe choice.=C2=A0 Obviously that is not the case here, though.<br>
<br>Some examples of design options:<br></div><div>- Make array_view parame=
terized by the pointer type, rather than the value type.=C2=A0 This allows =
it to hold smart pointers of various types, or a pointer that represents GP=
U memory, or a smart pointer that represents GPU memory, etc.=C2=A0 If the =
pointer is to GPU memory, reading and writing won't work (and won't=
be allowed at compile-time), but the indexing, slicing, sectioning and oth=
er operations on the array_view representation itself can still be used.=C2=
=A0 This is the decision I took in my own in-house library.=C2=A0 Allowing =
array_view to hold a smart pointer means you don't need a separate type=
to represent an array_view with ownership.=C2=A0 (Sectioning and slicing p=
roduces a result with the pointer decayed to a regular pointer.)=C2=A0 You =
can also use a __restrict__ pointer for an array_view type used as a functi=
on parameter to indicate lack of aliasing.<br>
<br></div><div>- Make bounds and index just generic fixed-size vector types=
..=C2=A0 In this case iterators on bounds should iterate over the components=
, rather than iterate over coordinates within the bounds.<br></div><div>=C2=
=A0<br>
</div><div>- More generally, the proposal distinguishes between array_view =
and strided_array_view, but doesn't allow for more fine-grained informa=
tion to be provided at compile time, such as the number of trailing contigu=
ous dimensions, alignment information, etc.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>>>> Some particula=
r issues with the proposed design include: <br>>>> <br>
>>> - No iterators are provided for array_view or strided_array_vi=
ew, a clear <br>>>> omission in the interface.=C2=A0 For a multidi=
mensional array, there are two <br>>>> obvious types of iteration =
that may be desired: <br>
>>>=C2=A0=C2=A0 1. iterating over just the first dimension; <br>&g=
t;>>=C2=A0=C2=A0 2. iterating over a flat view of all of the elements=
..=C2=A0 For a strided <br>>>> array, iterating over a flat view ca=
nnot be done efficiently without <br>
>>> segmented/hierarchical iterators. <br>>>>=C2=A0=C2=A0=
Which of these should be the default (i.e. provided through begin() and <b=
r>>>> end() rather than through some adaptor) is not clear, <br>&g=
t;><br>
>> From the Zen of Python, "In the face of ambiguity, refuse the=
<br>>> temptation to guess." <br>><br>> That's true, =
but no adaptors to provide the functionality unambiguously are provided eit=
her.=C2=A0 For the particular case of a one-dimensional array, there is no =
ambiguity, and not being able to easily use array_view with standard algori=
thms or range-based for is a serious usability issue.=C2=A0 This will only =
become worse if/when standard algorithm overloads that take ranges rather t=
han iterator pairs are added.</p>
</div><p>To the list of possible alternatives, I would add an option that w=
as proposed somewhere in the prior discussion on the proposal -- "hier=
archical" array_view/elemental iterator, i.e. an iterator that for arr=
ay_view<T, Rank> with Rank > 1 iterates over array_view<T, Rank=
-1>; and over T for Rank =3D=3D 1.<br>
</p></div></blockquote><div>Yes, that is a better way of expressing what I =
meant by "iterating over just the first dimension".=C2=A0 I belie=
ve this makes the most sense, but then it becomes desirable to have size() =
be the size of the first dimension for consistency with the iterators, and =
instead add a num_elements() that returns the total number of elements.=C2=
=A0 The correct definition of size() is hard to decide without figuring out=
how iterators should work.<br>
<br></div><div>The other issue is that if the iterators are hierarchical, y=
ou need a new hierarchical for_each that effectively expands to N nested fo=
r loops for N-dimensional arrays and which can operate on multiple arrays (=
of the same size).=C2=A0 This way you can express element-wise operations w=
ithout any overhead.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><p>It is however worth pointing out=
that in the first round of review with LEWG at Issaquah meeting, the vocal=
unchallenged feedback for iterators was "I do not want iterators for =
the views", thus we did not put much effort into contemplating adding =
any. Even though the choice for Rank =3D=3D 1 is "obvious", we co=
nsider this a corner case for array_view, and would rather have a holistic =
approach.<br>
There remains the possibility to add some form of the iterator as a future =
extension.</p></div></blockquote><div>Well, you can take my comments as a c=
hallenge to that view.=C2=A0 Rank =3D=3D 1 may be a "corner" case=
, but is likely to be used more frequently than all other cases combined.=
=C2=A0 A 1-dimensional array view that can't be used with for-range loo=
ps, boost (or std?) range adapters, etc. is a non-starter.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>>>> - No data() ac=
cess member for strided_array_view.=C2=A0 This is presumably <br>
>>> omitted because the memory is non-contiguous, but given that <=
br>>>> strided_array_view is a thin wrapper, there has to be a con=
venient way to <br>>>> get at the underlying memory. <br>>><=
br>
>> Why "has to"? <br>><br>> Because the user might wa=
nt to convert the array to another representation for use by another piece =
of code/library, e.g. FFTW or Eigen, CUDA memcpy, etc.=C2=A0 Under the prop=
osed interface, for a 3-dimensional stided array view, you have to use &=
;arr[0][0][0].=C2=A0 This is even worse than having to do &vec[0] for s=
td::vector, since the same expression cannot be used independent of the dim=
ensionality.</p>
</div><p>data() on strided_array_view could be harmful, as there is no guar=
antee of contiguity, which a developer / function template might assume. Pl=
ease note that for every other case in the Standard, the range [data(), dat=
a()+size()) is valid/safe, thus providing other semantics here would be dub=
ious.<br>
Granted, one can perform &arr[0][0][0] and run afoul, but that is no di=
fferent than e.g. &my_list.front().<br>It could be possible to provide =
"unsafe_data()" interface, which would have to be consumed along =
with stride(), however I do not see much benefit here over just using the &=
quot;proper" interface -- bounds() and operator[]().</p>
</div></blockquote><div>Calling it noncontiguous_data() is fine, though cer=
tainly then array_view should have an noncontiguous_data() (in addition to =
data()) as well for consistency.=C2=A0 I don't think unsafe_data is rea=
lly the right name, though the functionality is more important than the nam=
e.=C2=A0 &arr[0][0][0] has the disadvantage that it is more verbose and=
doesn't allow for writing generic code that works with any number of d=
imensions.=C2=A0 Just using the "proper" interface isn't a so=
lution.=C2=A0 A fundamental component like multidimensional arrays cannot b=
e a "walled garden".=C2=A0 The (pointer, bounds, strides) represe=
ntation, which numerous other libraries like FFTW use as well, should be tr=
ansparent.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><p></p><div>>>> - Slicing =
is limited: it is not possible to take a slice in a dimension <br>
>>> other than the first. <br>>><br>>> I think that=
9;s called "section()". <br>><br></div>> Well, that takes a=
"section" but does not reduce the dimensionality like "slic=
e". [...] Certainly there is a large design space for general subscrip=
ting and it almost certainly requires a fair amount of template metaprogram=
ming, but this is very useful functionality<p>
</p><p>Yes, slicing and sectioning are slightly different. It is however im=
portant to note that slicing in its current form always guarantees the cont=
iguity of the result, thus the return type may be array_view. The more gene=
ral cases (as you are describing) would result in a potentially strided res=
ulting view, which would need to be typed strided_array_view. This is why i=
t is important IMO to distinguish these two cases.<br>
In the current form of the proposal we decided to provide the minimal desig=
n -- only the first version, which in our opinion might be handy for users =
used to C-style multidimensional addressing (i.e. arr[3][1][4] v arr[{3, 1,=
4}]), which actually you used above :).<br>
The latter generic case can be trivially added as an extension to the inter=
face. I agree it may be useful, and if the current design is accepted for t=
he TS, I encourage you to propose such extension (or nag us for follow ups =
:)).</p>
<div><p>>>> - It is not clear whether it is really useful to have =
bounds and index be <br>>>> separate types (though should probably=
at least be explicitly convertible to <br>>>> each other). <br>
>><br>>> It adds a bit of type safety. Adding two bounds, for i=
nstance, doesn't <br>>> make a lot of sense. <br>><br>> I a=
gree that type safety is in principle useful, but it is impossible to predi=
ct what relationships might hold in any given program, and so there is the =
question of whether the safety it adds is worth the cost of having to expli=
citly work around it in the cases that it is too restrictive.=C2=A0 Certain=
ly if they are separate types there needs to be a way to (explicitly) conve=
rt.</p>
</div><p>I agree with both of you :).<br>These are separate types, because =
their meaning and semantics are different. It was also discussed in N3851, =
Appendix, II. The mental model I use for reasoning about them is: index ~ v=
ector and bounds ~ point (more specifically: a zero-bound, axis-aligned rec=
tangle described by its maximum point), which makes the set of available op=
erators apparent.<br>
I understand the explicit conversions between these two types, even though =
not theoretically sound, might be handy in practice and should be added.</p=
></div></blockquote><div>If we follow that logic, a point is a vector from =
the origin.=C2=A0 Therefore index should just be Vector<ptrdiff_t,N> =
and bounds<N> could have a Vector<ptrdiff_t,N> member.=C2=A0 Ho=
wever, it seems like it would be simpler to just have bounds be Vector<p=
trdiff_t,N> as well and save the trouble of the explicit conversions.=C2=
=A0 What type of error does the bounds/index distinction prevent?=C2=A0 Mor=
e generally, I am not sure why we shouldn't think of an index as a poin=
t as well.=C2=A0 If we want the last element in an array x, we have : x.bou=
nds() - 1=C2=A0 (or x.bounds() - {1,1, ...}).=C2=A0 We want to use this as =
an index, but the current operator definitions would have it be a bounds.<b=
r>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>> As a specific example,=
consider if we want to compute the bounds of a valid convolution if we hav=
e an array x and a filter k.=C2=A0 The bounds of the result are: x.bounds -=
k.bounds + 1.=C2=A0 None of the arithmetic operators defined in the propos=
al help me with that; I'd just have to write a loop.=C2=A0 Even if the =
arithmetic operators weren't limited by the bounds/index distinction, t=
here would still be no way to create a constant-valued vector, i.e. to hand=
le the constant 1.</p>
</div><p>Explicit conversions would help with the first part, right? I hope=
you are also not suggesting any such conversion should be implicit?<br>How=
ever I do not really understand what do you mean in the second part, "=
a constant-valued vector". We purposefully allow to create both bounds=
<1> and index<1> from a scalar; and disallow such operation for=
Rank > 1 (mostly because the semantics are not obvious, e.g. for rank 2=
, should index<2>{16} be {0, 16}, {16, 0} or {16, 16}).<br>
So net-net, in your example you should be able to do: x.bounds - index<2=
>{k.bounds} + {1, 1}. It a little more long-winded, but IMO easier to co=
mprehend than the original.</p></div></blockquote><div>I don't think th=
e explicit conversion to index adds to the clarity.=C2=A0 Also, the problem=
with {1, 1} is that it depends on the dimensionality.=C2=A0 The interface =
should be designed to be convenient for generic code.=C2=A0 I would suggest=
a Scalar<T> type generated by a wrapper function scalar, from which =
bounds and index can be implicitly constructed and which can be used in all=
of the operators.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>> Another related issue =
I didn't notice before: the only way to construct an index or bounds ty=
pe is from an initializer_list.=C2=A0 There is no (explicit) conversion fro=
m std::array, for instance.=C2=A0 It is quite likely that an index or bound=
s value would be computed by some other code, that may use a different repr=
esentation.</p>
</div><p>Yes, we should add (const value_type* begin, const value_type* end=
) constructors for both types. <rant>Or it should be possible to crea=
te initializer_list explicitly from such pair which would solve this issue =
universally.</rant></p>
</div></blockquote><div>Okay, though initializer_list is not compile-time s=
ized.<br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"=
margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204=
);border-left-width:1px;border-left-style:solid"><div dir=3D"ltr"><div>
>>> Furthermore, bounds and index essentially represent a <br>>=
>> fixed-size discrete vector type, i.e. an augmented interface for s=
td::array. <br>>>> Arguably the interface of std::array should jus=
t be extended to add <br>
>>> component-wise operators instead.=C2=A0 Also, a much more comp=
rehensive set of <br>>>> component-wise operations should be provi=
ded.=C2=A0 A statically-sized vector <br>>>> type is sorely needed=
in C++, but it does not make sense to standardize <br>
>>> these limited, single-purposes types when they could be, and s=
hould be, much <br>>>> more general. <br>>><br>>> We d=
on't necessarily want to go for the most general possible type all at o=
nce<br>
><br></div>> Certainly there is a large design space, but that is a r=
eason to be cautious about standardizing anything. [...]<p></p><p>There are=
two separate issue raised here:<br>- Why novel types -- this is primarily =
to introduce "vocabulary" types and allow to discriminate index a=
nd bounds, as they have different semantics, as discussed before. This was =
also touched upon in the previously referred N3851, Appendix, II.<br>
- Why so little functionality -- I agree with Jeffrey on this, and I have d=
escribed more of the philosophy in the introduction. I would be interested =
however what exactly you mean by "a much more comprehensive set of com=
ponent-wise operations".</p>
</div></blockquote><div>Almost anything could be useful (and I am thinking =
of the perspective of a general fixed-size vector type, but these all apply=
to index/bounds as well), but some particular examples: min, max, <, &l=
t;=3D, =3D=3D, !=3D, >=3D, >.=C2=A0 The relational operations need to=
return a vector of bool, which isn't compatible with index/bounds curr=
ently since they aren't parameterized by the type.=C2=A0 Obviously, tho=
ugh, it wouldn't make sense to call them index or bounds if they are pa=
rameterized by a type.<br>
</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0p=
x 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-=
left-width:1px;border-left-style:solid"><div dir=3D"ltr"><p>Having said tha=
t, I assume this is something that can be added later as a pure extension, =
correct?</p>
</div></blockquote><div></div><div>Some of them, like min and max, could be=
unintrusive, though neither index nor bounds would be a particularly meani=
ngful choice as the return type.<br></div><div>=C2=A0</div><blockquote clas=
s=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;padding-left:1ex;border=
-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"=
>
<div dir=3D"ltr"><div><p>> Given the long turn around time for revisions=
to C++</p></div><p>The Committee is certainly trying to get better at quic=
ker iterations, let's not be discouraged by the ghosts of the past...</=
p>
<div><p>> Other omissions from index and bounds include:<br>>=C2=A0 1=
.. no data() access to the components<br>>=C2=A0 2. no iterators over com=
ponents for index or bound</p></div><p>index and bounds are not containers =
and should not be used as such. For the limited number of scenario where I =
want to use/modify indeterminate number of components, it was always suffic=
ient for me to use a raw loop, and operator[]...<br>
In case I'm wrong, these as well should be easy to add later as extensi=
ons.</p><div><p>> for_each(x_array, y_array, x_array.bounds(), [&](a=
uto &x, auto &y, auto pos) {<br>>=C2=A0=C2=A0 if (x !=3D y) std:=
:cout << "mismatch at position " << pos << std:=
:endl;<br>
> });</p></div><p>I assume the idea here is that such "for_each&quo=
t; uses begin(X), end(X) for all provided arguments, passing dereferenced i=
terators to the function object. If so, I do not see how the current semant=
ics of bounds_iterator would get into way here? It should just work as is, =
no?<br>
</p></div></blockquote><div>The idea is that it would generate N nested for=
loops for N-dimensional array views, rather than an less efficient single =
for loop.<br></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204=
,204);border-left-width:1px;border-left-style:solid">
<div dir=3D"ltr"><p>Actually, it should be possible to write the following =
with just the current proposal and the current standard for_each:<br>=C2=A0=
auto x_av =3D array_view<N>{x_array};<br>=C2=A0auto y_av =3D array_vi=
ew<N>{y_array};<br>
=C2=A0for_each(begin(x_av.bounds())<u></u>, end(x_av.bounds()), [&](ind=
ex<N> pos) {<br>=C2=A0 if(x_av[pos] !=3D y_av[pos]) std::cout <<=
; "mismatch at position " << pos << std::endl;<br>=C2=
=A0});</p></div></blockquote>
<div>Yes, but note that the iteration over bounds is more expensive and the=
multiplication with all of the strides has to happen for every position.<b=
r></div><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);borde=
r-left-width:1px;border-left-style:solid">
<div dir=3D"ltr"><p>> From my perspective, the only way to properly expl=
ore this design space for multidimensional arrays/containers/ranges is thro=
ugh an actively developed and widely used open source library.</p><div>Our =
(Microsoft) prototype implementation is in the pipeline to be published as =
an open source project. It should happen really soon, and I hope it will he=
lp to convey the discussed ideas.</div>
</div></blockquote><div><br></div><div>That's good news.=C2=A0 I think =
the best library is likely to be produced if the users of the library and t=
he developers of the library are one and the same.=C2=A0 Issues become appa=
rent and the library interface can be tweaked to correct them very quickly =
that way.<br>
</div></div></div></div>
</blockquote></div></blockquote></div></div></div><div class=3D"HOEnZb"><di=
v class=3D"h5">
<p></p>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/xzb1d5KUxMU/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/isocpp.org/d/topic/std-proposals/xzb1d5KUxMU=
/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank">http://groups.google.com/a/isocpp.org/gro=
up/std-proposals/</a>.<br>
</div></div></blockquote></div><br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--f46d044280b66ef7ac0507d7ccf7--
.
Author: phdofthehouse@gmail.com
Date: Fri, 14 Nov 2014 13:17:17 -0800 (PST)
Raw View
------=_Part_716_988142105.1415999837544
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
I think that's convoluting the idea I'm trying to present here; the casting=
=20
point your making... seems to be orthognal to what I'm trying to say (not=
=20
to mention... dangerous/broken to implement? Changing the way a *std::array=
*=20
dereferences would break code everywhere, especially code that takes a=20
pointer to an array of std::array's (e.g., a vector of specifically-sized=
=20
*std::array*s) that suddenly behaved as if it was calling operator[] inside=
=20
of the pointed-to T? That's not a very good idea, I don't think).
That aside, the use case here is being able to nail down as many pieces of=
=20
computation to the compiler as possible: array_view<T, ...> and=20
strided_array_view<T, ...> are analogous to a c-style or std::array-style=
=20
declarations, with the benefit of providing the dimensions at compile-time.=
=20
This allows a constexpr operator[] to throw out all of the multiplication=
=20
and index caluclations to get to exact target index exactly before the=20
program runs and instead becomes direct access to the memory of interest;=
=20
this becomes a particularly interesting case for me as any special=20
optimizations like SIMD can be seen ahead of time by the compiler and=20
substituted in, since it can view those indices ahead of time and know the=
=20
offsets.
However, I'm not sure if that's already possible with just a=20
constexpr-enabled array_view that takes its dimensions, strides and bounds=
=20
at runtime. I have already written a buffer_view<T, dimension> in my own=20
code based on the proposal paper presented, and then also wrote an=20
array_view and strided_array_view with compile-time strides and bounds. My=
=20
current compiler (VC++) chokes on constexpr, so I mostly wanted to ask=20
about it here, if anyone else had a similar idea.
On Friday, November 14, 2014 3:51:54 PM UTC-5, Jeremy Maitin-Shepard wrote:
>
> If the size is known at compile time, an actual reference to std::array=
=20
> (or a multi-dimensional static-sized array counterpart) would be much=20
> better, as this eliminates the need for an extra type, and makes referenc=
e=20
> decay do the right thing. If the current language rules do not permit th=
e=20
> casting of an arbitrary pointer T *x where [x, x+size) is a valid range, =
to=20
> be a pointer to std::array<T,size>*, then I think the language rules shou=
ld=20
> be changed, as this is clearly extremely useful and any loss of=20
> optimization possibilities are probably minimal.
>
> On Fri, Nov 14, 2014 at 12:29 PM, <phdoft...@gmail.com <javascript:>>=20
> wrote:
>
>> As a small addition, has anyone considered perhaps calling the class=20
>> buffer_view<typename T, size_type dimensions>
>>
>> and then leaving the name *array_view* for a compile-time version of=20
>> this class (to match std::array)?
>>
>> I don't know if a fully constexpr-qualified version of the buffer_view=
=20
>> class will have the same benefit as a compile-time defined=20
>> array_view<typename T, size_type... dimension_sizes>
>>
>> class (with *strided* variants for buffer_view and array_view).
>>
>>
>> On Friday, June 27, 2014 1:00:54 AM UTC-4, =C5=81ukasz Mendakiewicz wrot=
e:
>>>
>>> I do understand your rationale in many of the points you are raising,=
=20
>>> and I am aware of other existing libraries, which in some cases made=20
>>> different design decisions. However many of the choices are mutually=20
>>> exclusive and in my opinion it is impossible to converge on the "single=
=20
>>> best design". Many of the design decisions in our proposal are also=20
>>> compromises.
>>>
>>> I disagree with your judgment that we should strive to find an ultimate=
=20
>>> solution before moving forward with any proposal. Lack of array_view or=
a=20
>>> similar type is clearly a gap in C++ Standard, which many libraries are=
=20
>>> addressing in different ways. We took the first stab in trying to addre=
ss=20
>>> this deficiency with putting forward the type we are familiar with, hav=
e=20
>>> worked with successfully for over 2 years, and in the process we were a=
lso=20
>>> fixing all issues we were aware of. It surely is not rock solid -- noth=
ing=20
>>> is -- and many use-cases might have benefit from tailoring details=20
>>> differently to cater each of them, but we have to start somewhere.
>>> Importantly, we are not "standardizing" array_view yet. If it passes LW=
G=20
>>> voting on the next Committee meeting it will be merely appended to one =
of=20
>>> TSs (unless anything changes, this should be Library Fundamentals TS) a=
nd=20
>>> on track to be considered for C++17. The three years lead time is inten=
ded=20
>>> exactly to gather the wider practical experience you are concerned abou=
t.
>>>
>>> I hope this helps to clarify our position.
>>>
>>> On Monday, June 16, 2014 5:49:39 PM UTC-7, Jeremy Maitin-Shepard wrote:
>>>
>>>> On Sun, Jun 15, 2014 at 9:38 PM, =C5=81ukasz Mendakiewicz <
>>>> l.menda...@live.com> wrote:
>>>>
>>>>> Thank you Jeffrey for adding me on the thread and for your initial=20
>>>>> response -- which I almost universally agree with.
>>>>>
>>>>> Jeremy, thank you for your detailed feedback. First, I believe that=
=20
>>>>> most of the disagreement stems from the approach to the proposal. You=
've=20
>>>>> commented that "it doesn't make sense to standardize a partial soluti=
on;=20
>>>>> better to work out a good, complete interface outside the standard". =
This=20
>>>>> is opposite to the "crawl, walk, run" philosophy we have taken when w=
riting=20
>>>>> this document up. We recognize that we have only explored some parts =
of the=20
>>>>> design space, because as you have rightly observed our experience is=
=20
>>>>> limited to C++ AMP, which constitutes only a specific data parallel=
=20
>>>>> approach to algorithms. Of course we believe that this is a solid=20
>>>>> foundation that can be generalized and built upon, hence the proposal=
.. But=20
>>>>> we deliberately avoided any design decisions which may be controversi=
al or=20
>>>>> result in a prolonged tug of war, instead intending for subsequent=20
>>>>> proposals (not necessarily authored by us) to fill the gaps. Certainl=
y,=20
>>>>> should anything being proposed now be a possible hindrance for any=20
>>>>> reasonable extension, it must be addressed sooner than later, however=
I=20
>>>>> think that none of the lacks pointed by you belong to this category.
>>>>>
>>>> I think it is basically impossible to nail down even a "minimal"=20
>>>> interface without considering the design of a complete library. If yo=
u=20
>>>> looked at 10 different, widely-used C++ multidimensional array librari=
es=20
>>>> and saw that all of their interfaces shared a given attribute, then=20
>>>> standardizing that attribute of the interface would likely be a safe=
=20
>>>> choice. Obviously that is not the case here, though.
>>>>
>>>> Some examples of design options:
>>>> - Make array_view parameterized by the pointer type, rather than the=
=20
>>>> value type. This allows it to hold smart pointers of various types, o=
r a=20
>>>> pointer that represents GPU memory, or a smart pointer that represents=
GPU=20
>>>> memory, etc. If the pointer is to GPU memory, reading and writing won=
't=20
>>>> work (and won't be allowed at compile-time), but the indexing, slicing=
,=20
>>>> sectioning and other operations on the array_view representation itsel=
f can=20
>>>> still be used. This is the decision I took in my own in-house library=
.. =20
>>>> Allowing array_view to hold a smart pointer means you don't need a sep=
arate=20
>>>> type to represent an array_view with ownership. (Sectioning and slici=
ng=20
>>>> produces a result with the pointer decayed to a regular pointer.) You=
can=20
>>>> also use a __restrict__ pointer for an array_view type used as a funct=
ion=20
>>>> parameter to indicate lack of aliasing.
>>>>
>>>> - Make bounds and index just generic fixed-size vector types. In this=
=20
>>>> case iterators on bounds should iterate over the components, rather th=
an=20
>>>> iterate over coordinates within the bounds.
>>>> =20
>>>> - More generally, the proposal distinguishes between array_view and=20
>>>> strided_array_view, but doesn't allow for more fine-grained informatio=
n to=20
>>>> be provided at compile time, such as the number of trailing contiguous=
=20
>>>> dimensions, alignment information, etc.
>>>>
>>>>> >>> Some particular issues with the proposed design include:=20
>>>>> >>>=20
>>>>> >>> - No iterators are provided for array_view or strided_array_view,=
=20
>>>>> a clear=20
>>>>> >>> omission in the interface. For a multidimensional array, there=
=20
>>>>> are two=20
>>>>> >>> obvious types of iteration that may be desired:=20
>>>>> >>> 1. iterating over just the first dimension;=20
>>>>> >>> 2. iterating over a flat view of all of the elements. For a=20
>>>>> strided=20
>>>>> >>> array, iterating over a flat view cannot be done efficiently=20
>>>>> without=20
>>>>> >>> segmented/hierarchical iterators.=20
>>>>> >>> Which of these should be the default (i.e. provided through=20
>>>>> begin() and=20
>>>>> >>> end() rather than through some adaptor) is not clear,=20
>>>>> >>
>>>>> >> From the Zen of Python, "In the face of ambiguity, refuse the=20
>>>>> >> temptation to guess."=20
>>>>> >
>>>>> > That's true, but no adaptors to provide the functionality=20
>>>>> unambiguously are provided either. For the particular case of a=20
>>>>> one-dimensional array, there is no ambiguity, and not being able to e=
asily=20
>>>>> use array_view with standard algorithms or range-based for is a serio=
us=20
>>>>> usability issue. This will only become worse if/when standard algori=
thm=20
>>>>> overloads that take ranges rather than iterator pairs are added.
>>>>>
>>>>> To the list of possible alternatives, I would add an option that was=
=20
>>>>> proposed somewhere in the prior discussion on the proposal --=20
>>>>> "hierarchical" array_view/elemental iterator, i.e. an iterator that f=
or=20
>>>>> array_view<T, Rank> with Rank > 1 iterates over array_view<T, Rank-1>=
; and=20
>>>>> over T for Rank =3D=3D 1.
>>>>>
>>>> Yes, that is a better way of expressing what I meant by "iterating ove=
r=20
>>>> just the first dimension". I believe this makes the most sense, but t=
hen=20
>>>> it becomes desirable to have size() be the size of the first dimension=
for=20
>>>> consistency with the iterators, and instead add a num_elements() that=
=20
>>>> returns the total number of elements. The correct definition of size(=
) is=20
>>>> hard to decide without figuring out how iterators should work.
>>>>
>>>> The other issue is that if the iterators are hierarchical, you need a=
=20
>>>> new hierarchical for_each that effectively expands to N nested for loo=
ps=20
>>>> for N-dimensional arrays and which can operate on multiple arrays (of =
the=20
>>>> same size). This way you can express element-wise operations without =
any=20
>>>> overhead.
>>>>
>>>>> It is however worth pointing out that in the first round of review=20
>>>>> with LEWG at Issaquah meeting, the vocal unchallenged feedback for=20
>>>>> iterators was "I do not want iterators for the views", thus we did no=
t put=20
>>>>> much effort into contemplating adding any. Even though the choice for=
Rank=20
>>>>> =3D=3D 1 is "obvious", we consider this a corner case for array_view,=
and would=20
>>>>> rather have a holistic approach.
>>>>> There remains the possibility to add some form of the iterator as a=
=20
>>>>> future extension.
>>>>>
>>>> Well, you can take my comments as a challenge to that view. Rank =3D=
=3D 1=20
>>>> may be a "corner" case, but is likely to be used more frequently than =
all=20
>>>> other cases combined. A 1-dimensional array view that can't be used w=
ith=20
>>>> for-range loops, boost (or std?) range adapters, etc. is a non-starter=
..
>>>>
>>>>> >>> - No data() access member for strided_array_view. This is=20
>>>>> presumably=20
>>>>> >>> omitted because the memory is non-contiguous, but given that=20
>>>>> >>> strided_array_view is a thin wrapper, there has to be a convenien=
t=20
>>>>> way to=20
>>>>> >>> get at the underlying memory.=20
>>>>> >>
>>>>> >> Why "has to"?=20
>>>>> >
>>>>> > Because the user might want to convert the array to another=20
>>>>> representation for use by another piece of code/library, e.g. FFTW or=
=20
>>>>> Eigen, CUDA memcpy, etc. Under the proposed interface, for a 3-dimen=
sional=20
>>>>> stided array view, you have to use &arr[0][0][0]. This is even worse=
than=20
>>>>> having to do &vec[0] for std::vector, since the same expression canno=
t be=20
>>>>> used independent of the dimensionality.
>>>>>
>>>>> data() on strided_array_view could be harmful, as there is no=20
>>>>> guarantee of contiguity, which a developer / function template might=
=20
>>>>> assume. Please note that for every other case in the Standard, the ra=
nge=20
>>>>> [data(), data()+size()) is valid/safe, thus providing other semantics=
here=20
>>>>> would be dubious.
>>>>> Granted, one can perform &arr[0][0][0] and run afoul, but that is no=
=20
>>>>> different than e.g. &my_list.front().
>>>>> It could be possible to provide "unsafe_data()" interface, which woul=
d=20
>>>>> have to be consumed along with stride(), however I do not see much be=
nefit=20
>>>>> here over just using the "proper" interface -- bounds() and operator[=
]().
>>>>>
>>>> Calling it noncontiguous_data() is fine, though certainly then=20
>>>> array_view should have an noncontiguous_data() (in addition to data())=
as=20
>>>> well for consistency. I don't think unsafe_data is really the right n=
ame,=20
>>>> though the functionality is more important than the name. &arr[0][0][=
0]=20
>>>> has the disadvantage that it is more verbose and doesn't allow for wri=
ting=20
>>>> generic code that works with any number of dimensions. Just using the=
=20
>>>> "proper" interface isn't a solution. A fundamental component like=20
>>>> multidimensional arrays cannot be a "walled garden". The (pointer, bo=
unds,=20
>>>> strides) representation, which numerous other libraries like FFTW use =
as=20
>>>> well, should be transparent.
>>>>
>>>>> >>> - Slicing is limited: it is not possible to take a slice in a=20
>>>>> dimension=20
>>>>> >>> other than the first.=20
>>>>> >>
>>>>> >> I think that's called "section()".=20
>>>>> >
>>>>> > Well, that takes a "section" but does not reduce the dimensionality=
=20
>>>>> like "slice". [...] Certainly there is a large design space for gener=
al=20
>>>>> subscripting and it almost certainly requires a fair amount of templa=
te=20
>>>>> metaprogramming, but this is very useful functionality
>>>>>
>>>>> Yes, slicing and sectioning are slightly different. It is however=20
>>>>> important to note that slicing in its current form always guarantees =
the=20
>>>>> contiguity of the result, thus the return type may be array_view. The=
more=20
>>>>> general cases (as you are describing) would result in a potentially s=
trided=20
>>>>> resulting view, which would need to be typed strided_array_view. This=
is=20
>>>>> why it is important IMO to distinguish these two cases.
>>>>> In the current form of the proposal we decided to provide the minimal=
=20
>>>>> design -- only the first version, which in our opinion might be handy=
for=20
>>>>> users used to C-style multidimensional addressing (i.e. arr[3][1][4] =
v=20
>>>>> arr[{3, 1, 4}]), which actually you used above :).
>>>>> The latter generic case can be trivially added as an extension to the=
=20
>>>>> interface. I agree it may be useful, and if the current design is acc=
epted=20
>>>>> for the TS, I encourage you to propose such extension (or nag us for =
follow=20
>>>>> ups :)).
>>>>>
>>>>> >>> - It is not clear whether it is really useful to have bounds and=
=20
>>>>> index be=20
>>>>> >>> separate types (though should probably at least be explicitly=20
>>>>> convertible to=20
>>>>> >>> each other).=20
>>>>> >>
>>>>> >> It adds a bit of type safety. Adding two bounds, for instance,=20
>>>>> doesn't=20
>>>>> >> make a lot of sense.=20
>>>>> >
>>>>> > I agree that type safety is in principle useful, but it is=20
>>>>> impossible to predict what relationships might hold in any given prog=
ram,=20
>>>>> and so there is the question of whether the safety it adds is worth t=
he=20
>>>>> cost of having to explicitly work around it in the cases that it is t=
oo=20
>>>>> restrictive. Certainly if they are separate types there needs to be =
a way=20
>>>>> to (explicitly) convert.
>>>>>
>>>>> I agree with both of you :).
>>>>> These are separate types, because their meaning and semantics are=20
>>>>> different. It was also discussed in N3851, Appendix, II. The mental m=
odel I=20
>>>>> use for reasoning about them is: index ~ vector and bounds ~ point (m=
ore=20
>>>>> specifically: a zero-bound, axis-aligned rectangle described by its m=
aximum=20
>>>>> point), which makes the set of available operators apparent.
>>>>> I understand the explicit conversions between these two types, even=
=20
>>>>> though not theoretically sound, might be handy in practice and should=
be=20
>>>>> added.
>>>>>
>>>> If we follow that logic, a point is a vector from the origin. =20
>>>> Therefore index should just be Vector<ptrdiff_t,N> and bounds<N> could=
have=20
>>>> a Vector<ptrdiff_t,N> member. However, it seems like it would be simp=
ler=20
>>>> to just have bounds be Vector<ptrdiff_t,N> as well and save the troubl=
e of=20
>>>> the explicit conversions. What type of error does the bounds/index=20
>>>> distinction prevent? More generally, I am not sure why we shouldn't t=
hink=20
>>>> of an index as a point as well. If we want the last element in an arr=
ay x,=20
>>>> we have : x.bounds() - 1 (or x.bounds() - {1,1, ...}). We want to us=
e=20
>>>> this as an index, but the current operator definitions would have it b=
e a=20
>>>> bounds.
>>>>
>>>>> > As a specific example, consider if we want to compute the bounds of=
=20
>>>>> a valid convolution if we have an array x and a filter k. The bounds=
of=20
>>>>> the result are: x.bounds - k.bounds + 1. None of the arithmetic oper=
ators=20
>>>>> defined in the proposal help me with that; I'd just have to write a l=
oop. =20
>>>>> Even if the arithmetic operators weren't limited by the bounds/index=
=20
>>>>> distinction, there would still be no way to create a constant-valued=
=20
>>>>> vector, i.e. to handle the constant 1.
>>>>>
>>>>> Explicit conversions would help with the first part, right? I hope yo=
u=20
>>>>> are also not suggesting any such conversion should be implicit?
>>>>> However I do not really understand what do you mean in the second=20
>>>>> part, "a constant-valued vector". We purposefully allow to create bot=
h=20
>>>>> bounds<1> and index<1> from a scalar; and disallow such operation for=
Rank=20
>>>>> > 1 (mostly because the semantics are not obvious, e.g. for rank 2, s=
hould=20
>>>>> index<2>{16} be {0, 16}, {16, 0} or {16, 16}).
>>>>> So net-net, in your example you should be able to do: x.bounds -=20
>>>>> index<2>{k.bounds} + {1, 1}. It a little more long-winded, but IMO ea=
sier=20
>>>>> to comprehend than the original.
>>>>>
>>>> I don't think the explicit conversion to index adds to the clarity. =
=20
>>>> Also, the problem with {1, 1} is that it depends on the dimensionality=
.. =20
>>>> The interface should be designed to be convenient for generic code. I=
=20
>>>> would suggest a Scalar<T> type generated by a wrapper function scalar,=
from=20
>>>> which bounds and index can be implicitly constructed and which can be =
used=20
>>>> in all of the operators.
>>>>
>>>>> > Another related issue I didn't notice before: the only way to=20
>>>>> construct an index or bounds type is from an initializer_list. There=
is no=20
>>>>> (explicit) conversion from std::array, for instance. It is quite lik=
ely=20
>>>>> that an index or bounds value would be computed by some other code, t=
hat=20
>>>>> may use a different representation.
>>>>>
>>>>> Yes, we should add (const value_type* begin, const value_type* end)=
=20
>>>>> constructors for both types. <rant>Or it should be possible to create=
=20
>>>>> initializer_list explicitly from such pair which would solve this iss=
ue=20
>>>>> universally.</rant>
>>>>>
>>>> Okay, though initializer_list is not compile-time sized.
>>>> =20
>>>>
>>>>> >>> Furthermore, bounds and index essentially represent a=20
>>>>> >>> fixed-size discrete vector type, i.e. an augmented interface for=
=20
>>>>> std::array.=20
>>>>> >>> Arguably the interface of std::array should just be extended to=
=20
>>>>> add=20
>>>>> >>> component-wise operators instead. Also, a much more comprehensiv=
e=20
>>>>> set of=20
>>>>> >>> component-wise operations should be provided. A statically-sized=
=20
>>>>> vector=20
>>>>> >>> type is sorely needed in C++, but it does not make sense to=20
>>>>> standardize=20
>>>>> >>> these limited, single-purposes types when they could be, and=20
>>>>> should be, much=20
>>>>> >>> more general.=20
>>>>> >>
>>>>> >> We don't necessarily want to go for the most general possible type=
=20
>>>>> all at once
>>>>> >
>>>>> > Certainly there is a large design space, but that is a reason to be=
=20
>>>>> cautious about standardizing anything. [...]
>>>>>
>>>>> There are two separate issue raised here:
>>>>> - Why novel types -- this is primarily to introduce "vocabulary" type=
s=20
>>>>> and allow to discriminate index and bounds, as they have different=20
>>>>> semantics, as discussed before. This was also touched upon in the=20
>>>>> previously referred N3851, Appendix, II.
>>>>> - Why so little functionality -- I agree with Jeffrey on this, and I=
=20
>>>>> have described more of the philosophy in the introduction. I would be=
=20
>>>>> interested however what exactly you mean by "a much more comprehensiv=
e set=20
>>>>> of component-wise operations".
>>>>>
>>>> Almost anything could be useful (and I am thinking of the perspective=
=20
>>>> of a general fixed-size vector type, but these all apply to index/boun=
ds as=20
>>>> well), but some particular examples: min, max, <, <=3D, =3D=3D, !=3D, =
>=3D, >. The=20
>>>> relational operations need to return a vector of bool, which isn't=20
>>>> compatible with index/bounds currently since they aren't parameterized=
by=20
>>>> the type. Obviously, though, it wouldn't make sense to call them inde=
x or=20
>>>> bounds if they are parameterized by a type.
>>>> =20
>>>>
>>>>> Having said that, I assume this is something that can be added later=
=20
>>>>> as a pure extension, correct?
>>>>>
>>>> Some of them, like min and max, could be unintrusive, though neither=
=20
>>>> index nor bounds would be a particularly meaningful choice as the retu=
rn=20
>>>> type.
>>>> =20
>>>>
>>>>> > Given the long turn around time for revisions to C++
>>>>>
>>>>> The Committee is certainly trying to get better at quicker iterations=
,=20
>>>>> let's not be discouraged by the ghosts of the past...
>>>>>
>>>>> > Other omissions from index and bounds include:
>>>>> > 1. no data() access to the components
>>>>> > 2. no iterators over components for index or bound
>>>>>
>>>>> index and bounds are not containers and should not be used as such.=
=20
>>>>> For the limited number of scenario where I want to use/modify indeter=
minate=20
>>>>> number of components, it was always sufficient for me to use a raw lo=
op,=20
>>>>> and operator[]...
>>>>> In case I'm wrong, these as well should be easy to add later as=20
>>>>> extensions.
>>>>>
>>>>> > for_each(x_array, y_array, x_array.bounds(), [&](auto &x, auto &y,=
=20
>>>>> auto pos) {
>>>>> > if (x !=3D y) std::cout << "mismatch at position " << pos <<=20
>>>>> std::endl;
>>>>> > });
>>>>>
>>>>> I assume the idea here is that such "for_each" uses begin(X), end(X)=
=20
>>>>> for all provided arguments, passing dereferenced iterators to the fun=
ction=20
>>>>> object. If so, I do not see how the current semantics of bounds_itera=
tor=20
>>>>> would get into way here? It should just work as is, no?
>>>>>
>>>> The idea is that it would generate N nested for loops for N-dimensiona=
l=20
>>>> array views, rather than an less efficient single for loop.
>>>> =20
>>>>
>>>>> Actually, it should be possible to write the following with just the=
=20
>>>>> current proposal and the current standard for_each:
>>>>> auto x_av =3D array_view<N>{x_array};
>>>>> auto y_av =3D array_view<N>{y_array};
>>>>> for_each(begin(x_av.bounds()), end(x_av.bounds()), [&](index<N> pos)=
=20
>>>>> {
>>>>> if(x_av[pos] !=3D y_av[pos]) std::cout << "mismatch at position " <=
<=20
>>>>> pos << std::endl;
>>>>> });
>>>>>
>>>> Yes, but note that the iteration over bounds is more expensive and the=
=20
>>>> multiplication with all of the strides has to happen for every positio=
n.
>>>> =20
>>>>
>>>>> > From my perspective, the only way to properly explore this design=
=20
>>>>> space for multidimensional arrays/containers/ranges is through an act=
ively=20
>>>>> developed and widely used open source library.
>>>>> Our (Microsoft) prototype implementation is in the pipeline to be=20
>>>>> published as an open source project. It should happen really soon, an=
d I=20
>>>>> hope it will help to convey the discussed ideas.
>>>>>
>>>>
>>>> That's good news. I think the best library is likely to be produced i=
f=20
>>>> the users of the library and the developers of the library are one and=
the=20
>>>> same. Issues become apparent and the library interface can be tweaked=
to=20
>>>> correct them very quickly that way.
>>>> =20
>>> --=20
>>
>> ---=20
>> You received this message because you are subscribed to a topic in the=
=20
>> Google Groups "ISO C++ Standard - Future Proposals" group.
>> To unsubscribe from this topic, visit=20
>> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/xzb1d5KUxMU=
/unsubscribe
>> .
>> To unsubscribe from this group and all its topics, send an email to=20
>> std-proposal...@isocpp.org <javascript:>.
>> To post to this group, send email to std-pr...@isocpp.org <javascript:>.
>> Visit this group at=20
>> http://groups.google.com/a/isocpp.org/group/std-proposals/.
>>
>
>
--=20
---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.
------=_Part_716_988142105.1415999837544
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">I think that's convoluting the idea I'm trying to present =
here; the casting point your making... seems to be orthognal to what I'm tr=
ying to say (not to mention... dangerous/broken to implement? Changing the =
way a <i>std::array</i> dereferences would break code everywhere, especiall=
y code that takes a pointer to an array of std::array's (e.g., a vector of =
specifically-sized <i>std::array</i>s) that suddenly behaved as if it was c=
alling operator[] inside of the pointed-to T? That's not a very good idea, =
I don't think).<br><br>That aside, the use case here is being able to nail =
down as many pieces of computation to the compiler as possible: array_view&=
lt;T, ...> and strided_array_view<T, ...> are analogous to a c-sty=
le or std::array-style declarations, with the benefit of providing the dime=
nsions at compile-time. This allows a constexpr operator[] to throw out all=
of the multiplication and index caluclations to get to exact target index =
exactly before the program runs and instead becomes direct access to the me=
mory of interest; this becomes a particularly interesting case for me as an=
y special optimizations like SIMD can be seen ahead of time by the compiler=
and substituted in, since it can view those indices ahead of time and know=
the offsets.<br><br>However, I'm not sure if that's already possible with =
just a constexpr-enabled array_view that takes its dimensions, strides and =
bounds at runtime. I have already written a buffer_view<T, dimension>=
in my own code based on the proposal paper presented, and then also wrote =
an array_view and strided_array_view with compile-time strides and bounds. =
My current compiler (VC++) chokes on constexpr, so I mostly wanted to ask a=
bout it here, if anyone else had a similar idea.<br><br>On Friday, November=
14, 2014 3:51:54 PM UTC-5, Jeremy Maitin-Shepard wrote:<blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"><div dir=3D"ltr">If the size is known at compil=
e time, an actual reference to std::array (or a multi-dimensional static-si=
zed array counterpart) would be much better, as this eliminates the need fo=
r an extra type, and makes reference decay do the right thing. If the=
current language rules do not permit the casting of an arbitrary pointer T=
*x where [x, x+size) is a valid range, to be a pointer to std::array<T,=
size>*, then I think the language rules should be changed, as this is cl=
early extremely useful and any loss of optimization possibilities are proba=
bly minimal.<br></div><div><br><div class=3D"gmail_quote">On Fri, Nov 14, 2=
014 at 12:29 PM, <span dir=3D"ltr"><<a href=3D"javascript:" target=3D"_=
blank" gdf-obfuscated-mailto=3D"EY36l3K-ekcJ" onmousedown=3D"this.href=3D'j=
avascript:';return true;" onclick=3D"this.href=3D'javascript:';return true;=
">phdoft...@gmail.com</a>></span> wrote:<br><blockquote class=3D"gmail_q=
uote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1e=
x"><div dir=3D"ltr">As a small addition, has anyone considered perhaps call=
ing the class <div style=3D"background-color:rgb(250,250,250);border-color:=
rgb(187,187,187);border-style:solid;border-width:1px;word-wrap:break-word">=
<code><div><span style=3D"color:#000">buffer_view</span><span style=3D"colo=
r:#660"><</span><span style=3D"color:#008">typename</span><span style=3D=
"color:#000"> T</span><span style=3D"color:#660">,</span><span style=3D"col=
or:#000"> size_type dimensions</span><span style=3D"color:#660">></span>=
</div></code></div><br> and then leaving the name <i>array_view</i> for a c=
ompile-time version of this class (to match std::array)?<br><br>I don't kno=
w if a fully constexpr-qualified version of the buffer_view class will have=
the same benefit as a compile-time defined <div style=3D"background-color:=
rgb(250,250,250);border-color:rgb(187,187,187);border-style:solid;border-wi=
dth:1px;word-wrap:break-word"><code><div><span style=3D"color:#000">array_v=
iew</span><span style=3D"color:#660"><</span><span style=3D"color:#008">=
typename</span><span style=3D"color:#000"> T</span><span style=3D"color:#66=
0">,</span><span style=3D"color:#000"> size_type</span><span style=3D"color=
:#660">...</span><span style=3D"color:#000"> dimension_sizes</span><span st=
yle=3D"color:#660">></span></div></code></div><br>class (with <i>strided=
</i> variants for buffer_view and array_view).<div><div><br><br>On Friday, =
June 27, 2014 1:00:54 AM UTC-4, =C5=81ukasz Mendakiewicz wrote:<blockquote =
class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;border-left:1px #=
ccc solid;padding-left:1ex"><div dir=3D"ltr"><p>I do understand your ration=
ale in many of the points you are raising, and I am aware of other existing=
libraries, which in some cases made different design decisions. However ma=
ny of the choices are mutually exclusive and in my opinion it is impossible=
to converge on the "single best design". Many of the design decisions in o=
ur proposal are also compromises.</p><p>I disagree with your judgment that =
we should strive to find an ultimate solution before moving forward with an=
y proposal. Lack of array_view or a similar type is clearly a gap in C++ St=
andard, which many libraries are addressing in different ways. We took the =
first stab in trying to address this deficiency with putting forward the ty=
pe we are familiar with, have worked with successfully for over 2 years, an=
d in the process we were also fixing all issues we were aware of. It surely=
is not rock solid -- nothing is -- and many use-cases might have benefit f=
rom tailoring details differently to cater each of them, but we have to sta=
rt somewhere.</p><div>Importantly, we are not "standardizing" array_view ye=
t. If it passes LWG voting on the next Committee meeting it will be merely =
appended to one of TSs (unless anything changes, this should be Library Fun=
damentals TS) and on track to be considered for C++17. The three years lead=
time is intended exactly to gather the wider practical experience you are =
concerned about.</div><div><br></div><div>I hope this helps to clarify our =
position.</div><div><br>On Monday, June 16, 2014 5:49:39 PM UTC-7, Jeremy M=
aitin-Shepard wrote:</div><blockquote class=3D"gmail_quote" style=3D"margin=
:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);bord=
er-left-width:1px;border-left-style:solid"><div dir=3D"ltr">On Sun, Jun 15,=
2014 at 9:38 PM, =C5=81ukasz Mendakiewicz <span dir=3D"ltr"><<a>l.menda=
....@live.com</a>></span> wrote:<br><div><div class=3D"gmail_quote">
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;padding=
-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-l=
eft-style:solid"><div dir=3D"ltr"><p>Thank you Jeffrey for adding me on the=
thread and for your initial response -- which I almost universally agree w=
ith.</p>
<p>Jeremy, thank you for your detailed feedback. First, I believe that most=
of the disagreement stems from the approach to the proposal. You've commen=
ted that "it doesn't make sense to standardize a partial solution; bet=
ter to work out a good, complete interface outside the standard". This is o=
pposite to the "crawl, walk, run" philosophy we have taken when writing thi=
s document up. We recognize that we have only explored some parts of the de=
sign space, because as you have rightly observed our experience is limited =
to C++ AMP, which constitutes only a specific data parallel approach to alg=
orithms. Of course we believe that this is a solid foundation that can be g=
eneralized and built upon, hence the proposal. But we deliberately avoided =
any design decisions which may be controversial or result in a prolonged tu=
g of war, instead intending for subsequent proposals (not necessarily autho=
red by us) to fill the gaps. Certainly, should anything being proposed now =
be a possible hindrance for any reasonable extension, it must be addressed =
sooner than later, however I think that none of the lacks pointed by you be=
long to this category.</p>
</div></blockquote><div>I think it is basically impossible to nail down eve=
n a "minimal" interface without considering the design of a complete librar=
y. If you looked at 10 different, widely-used C++ multidimensional ar=
ray libraries and saw that all of their interfaces shared a given attribute=
, then standardizing that attribute of the interface would likely be a safe=
choice. Obviously that is not the case here, though.<br>
<br>Some examples of design options:<br></div><div>- Make array_view parame=
terized by the pointer type, rather than the value type. This allows =
it to hold smart pointers of various types, or a pointer that represents GP=
U memory, or a smart pointer that represents GPU memory, etc. If the =
pointer is to GPU memory, reading and writing won't work (and won't be allo=
wed at compile-time), but the indexing, slicing, sectioning and other opera=
tions on the array_view representation itself can still be used. This=
is the decision I took in my own in-house library. Allowing array_vi=
ew to hold a smart pointer means you don't need a separate type to represen=
t an array_view with ownership. (Sectioning and slicing produces a re=
sult with the pointer decayed to a regular pointer.) You can also use=
a __restrict__ pointer for an array_view type used as a function parameter=
to indicate lack of aliasing.<br>
<br></div><div>- Make bounds and index just generic fixed-size vector types=
.. In this case iterators on bounds should iterate over the components=
, rather than iterate over coordinates within the bounds.<br></div><div>&nb=
sp;<br>
</div><div>- More generally, the proposal distinguishes between array_view =
and strided_array_view, but doesn't allow for more fine-grained information=
to be provided at compile time, such as the number of trailing contiguous =
dimensions, alignment information, etc.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>>>> Some particula=
r issues with the proposed design include: <br>>>> <br>
>>> - No iterators are provided for array_view or strided_array_vi=
ew, a clear <br>>>> omission in the interface. For a multidi=
mensional array, there are two <br>>>> obvious types of iteration =
that may be desired: <br>
>>> 1. iterating over just the first dimension; <br>&g=
t;>> 2. iterating over a flat view of all of the elements=
.. For a strided <br>>>> array, iterating over a flat view ca=
nnot be done efficiently without <br>
>>> segmented/hierarchical iterators. <br>>>> =
Which of these should be the default (i.e. provided through begin() and <b=
r>>>> end() rather than through some adaptor) is not clear, <br>&g=
t;><br>
>> From the Zen of Python, "In the face of ambiguity, refuse the <br>=
>> temptation to guess." <br>><br>> That's true, but no adaptor=
s to provide the functionality unambiguously are provided either. For=
the particular case of a one-dimensional array, there is no ambiguity, and=
not being able to easily use array_view with standard algorithms or range-=
based for is a serious usability issue. This will only become worse i=
f/when standard algorithm overloads that take ranges rather than iterator p=
airs are added.</p>
</div><p>To the list of possible alternatives, I would add an option that w=
as proposed somewhere in the prior discussion on the proposal -- "hierarchi=
cal" array_view/elemental iterator, i.e. an iterator that for array_view<=
;T, Rank> with Rank > 1 iterates over array_view<T, Rank-1>; an=
d over T for Rank =3D=3D 1.<br>
</p></div></blockquote><div>Yes, that is a better way of expressing what I =
meant by "iterating over just the first dimension". I believe this ma=
kes the most sense, but then it becomes desirable to have size() be the siz=
e of the first dimension for consistency with the iterators, and instead ad=
d a num_elements() that returns the total number of elements. The cor=
rect definition of size() is hard to decide without figuring out how iterat=
ors should work.<br>
<br></div><div>The other issue is that if the iterators are hierarchical, y=
ou need a new hierarchical for_each that effectively expands to N nested fo=
r loops for N-dimensional arrays and which can operate on multiple arrays (=
of the same size). This way you can express element-wise operations w=
ithout any overhead.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><p>It is however worth pointing out=
that in the first round of review with LEWG at Issaquah meeting, the vocal=
unchallenged feedback for iterators was "I do not want iterators for the v=
iews", thus we did not put much effort into contemplating adding any. Even =
though the choice for Rank =3D=3D 1 is "obvious", we consider this a corner=
case for array_view, and would rather have a holistic approach.<br>
There remains the possibility to add some form of the iterator as a future =
extension.</p></div></blockquote><div>Well, you can take my comments as a c=
hallenge to that view. Rank =3D=3D 1 may be a "corner" case, but is l=
ikely to be used more frequently than all other cases combined. A 1-d=
imensional array view that can't be used with for-range loops, boost (or st=
d?) range adapters, etc. is a non-starter.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>>>> - No data() ac=
cess member for strided_array_view. This is presumably <br>
>>> omitted because the memory is non-contiguous, but given that <=
br>>>> strided_array_view is a thin wrapper, there has to be a con=
venient way to <br>>>> get at the underlying memory. <br>>><=
br>
>> Why "has to"? <br>><br>> Because the user might want to conv=
ert the array to another representation for use by another piece of code/li=
brary, e.g. FFTW or Eigen, CUDA memcpy, etc. Under the proposed inter=
face, for a 3-dimensional stided array view, you have to use &arr[0][0]=
[0]. This is even worse than having to do &vec[0] for std::vector=
, since the same expression cannot be used independent of the dimensionalit=
y.</p>
</div><p>data() on strided_array_view could be harmful, as there is no guar=
antee of contiguity, which a developer / function template might assume. Pl=
ease note that for every other case in the Standard, the range [data(), dat=
a()+size()) is valid/safe, thus providing other semantics here would be dub=
ious.<br>
Granted, one can perform &arr[0][0][0] and run afoul, but that is no di=
fferent than e.g. &my_list.front().<br>It could be possible to provide =
"unsafe_data()" interface, which would have to be consumed along with strid=
e(), however I do not see much benefit here over just using the "proper" in=
terface -- bounds() and operator[]().</p>
</div></blockquote><div>Calling it noncontiguous_data() is fine, though cer=
tainly then array_view should have an noncontiguous_data() (in addition to =
data()) as well for consistency. I don't think unsafe_data is really =
the right name, though the functionality is more important than the name.&n=
bsp; &arr[0][0][0] has the disadvantage that it is more verbose and doe=
sn't allow for writing generic code that works with any number of dimension=
s. Just using the "proper" interface isn't a solution. A fundam=
ental component like multidimensional arrays cannot be a "walled garden".&n=
bsp; The (pointer, bounds, strides) representation, which numerous other li=
braries like FFTW use as well, should be transparent.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><p></p><div>>>> - Slicing =
is limited: it is not possible to take a slice in a dimension <br>
>>> other than the first. <br>>><br>>> I think that's =
called "section()". <br>><br></div>> Well, that takes a "section" but=
does not reduce the dimensionality like "slice". [...] Certainly there is =
a large design space for general subscripting and it almost certainly requi=
res a fair amount of template metaprogramming, but this is very useful func=
tionality<p>
</p><p>Yes, slicing and sectioning are slightly different. It is however im=
portant to note that slicing in its current form always guarantees the cont=
iguity of the result, thus the return type may be array_view. The more gene=
ral cases (as you are describing) would result in a potentially strided res=
ulting view, which would need to be typed strided_array_view. This is why i=
t is important IMO to distinguish these two cases.<br>
In the current form of the proposal we decided to provide the minimal desig=
n -- only the first version, which in our opinion might be handy for users =
used to C-style multidimensional addressing (i.e. arr[3][1][4] v arr[{3, 1,=
4}]), which actually you used above :).<br>
The latter generic case can be trivially added as an extension to the inter=
face. I agree it may be useful, and if the current design is accepted for t=
he TS, I encourage you to propose such extension (or nag us for follow ups =
:)).</p>
<div><p>>>> - It is not clear whether it is really useful to have =
bounds and index be <br>>>> separate types (though should probably=
at least be explicitly convertible to <br>>>> each other). <br>
>><br>>> It adds a bit of type safety. Adding two bounds, for i=
nstance, doesn't <br>>> make a lot of sense. <br>><br>> I agree=
that type safety is in principle useful, but it is impossible to predict w=
hat relationships might hold in any given program, and so there is the ques=
tion of whether the safety it adds is worth the cost of having to explicitl=
y work around it in the cases that it is too restrictive. Certainly i=
f they are separate types there needs to be a way to (explicitly) convert.<=
/p>
</div><p>I agree with both of you :).<br>These are separate types, because =
their meaning and semantics are different. It was also discussed in N3851, =
Appendix, II. The mental model I use for reasoning about them is: index ~ v=
ector and bounds ~ point (more specifically: a zero-bound, axis-aligned rec=
tangle described by its maximum point), which makes the set of available op=
erators apparent.<br>
I understand the explicit conversions between these two types, even though =
not theoretically sound, might be handy in practice and should be added.</p=
></div></blockquote><div>If we follow that logic, a point is a vector from =
the origin. Therefore index should just be Vector<ptrdiff_t,N> =
and bounds<N> could have a Vector<ptrdiff_t,N> member. Ho=
wever, it seems like it would be simpler to just have bounds be Vector<p=
trdiff_t,N> as well and save the trouble of the explicit conversions.&nb=
sp; What type of error does the bounds/index distinction prevent? Mor=
e generally, I am not sure why we shouldn't think of an index as a point as=
well. If we want the last element in an array x, we have : x.bounds(=
) - 1 (or x.bounds() - {1,1, ...}). We want to use this as an i=
ndex, but the current operator definitions would have it be a bounds.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>> As a specific example,=
consider if we want to compute the bounds of a valid convolution if we hav=
e an array x and a filter k. The bounds of the result are: x.bounds -=
k.bounds + 1. None of the arithmetic operators defined in the propos=
al help me with that; I'd just have to write a loop. Even if the arit=
hmetic operators weren't limited by the bounds/index distinction, there wou=
ld still be no way to create a constant-valued vector, i.e. to handle the c=
onstant 1.</p>
</div><p>Explicit conversions would help with the first part, right? I hope=
you are also not suggesting any such conversion should be implicit?<br>How=
ever I do not really understand what do you mean in the second part, "a con=
stant-valued vector". We purposefully allow to create both bounds<1> =
and index<1> from a scalar; and disallow such operation for Rank >=
1 (mostly because the semantics are not obvious, e.g. for rank 2, should i=
ndex<2>{16} be {0, 16}, {16, 0} or {16, 16}).<br>
So net-net, in your example you should be able to do: x.bounds - index<2=
>{k.bounds} + {1, 1}. It a little more long-winded, but IMO easier to co=
mprehend than the original.</p></div></blockquote><div>I don't think the ex=
plicit conversion to index adds to the clarity. Also, the problem wit=
h {1, 1} is that it depends on the dimensionality. The interface shou=
ld be designed to be convenient for generic code. I would suggest a S=
calar<T> type generated by a wrapper function scalar, from which boun=
ds and index can be implicitly constructed and which can be used in all of =
the operators.<br>
</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;p=
adding-left:1ex;border-left-color:rgb(204,204,204);border-left-width:1px;bo=
rder-left-style:solid"><div dir=3D"ltr"><div><p>> Another related issue =
I didn't notice before: the only way to construct an index or bounds type i=
s from an initializer_list. There is no (explicit) conversion from st=
d::array, for instance. It is quite likely that an index or bounds va=
lue would be computed by some other code, that may use a different represen=
tation.</p>
</div><p>Yes, we should add (const value_type* begin, const value_type* end=
) constructors for both types. <rant>Or it should be possible to crea=
te initializer_list explicitly from such pair which would solve this issue =
universally.</rant></p>
</div></blockquote><div>Okay, though initializer_list is not compile-time s=
ized.<br></div><div> </div><blockquote class=3D"gmail_quote" style=3D"=
margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204=
);border-left-width:1px;border-left-style:solid"><div dir=3D"ltr"><div>
>>> Furthermore, bounds and index essentially represent a <br>>=
>> fixed-size discrete vector type, i.e. an augmented interface for s=
td::array. <br>>>> Arguably the interface of std::array should jus=
t be extended to add <br>
>>> component-wise operators instead. Also, a much more comp=
rehensive set of <br>>>> component-wise operations should be provi=
ded. A statically-sized vector <br>>>> type is sorely needed=
in C++, but it does not make sense to standardize <br>
>>> these limited, single-purposes types when they could be, and s=
hould be, much <br>>>> more general. <br>>><br>>> We d=
on't necessarily want to go for the most general possible type all at once<=
br>
><br></div>> Certainly there is a large design space, but that is a r=
eason to be cautious about standardizing anything. [...]<p></p><p>There are=
two separate issue raised here:<br>- Why novel types -- this is primarily =
to introduce "vocabulary" types and allow to discriminate index and bounds,=
as they have different semantics, as discussed before. This was also touch=
ed upon in the previously referred N3851, Appendix, II.<br>
- Why so little functionality -- I agree with Jeffrey on this, and I have d=
escribed more of the philosophy in the introduction. I would be interested =
however what exactly you mean by "a much more comprehensive set of componen=
t-wise operations".</p>
</div></blockquote><div>Almost anything could be useful (and I am thinking =
of the perspective of a general fixed-size vector type, but these all apply=
to index/bounds as well), but some particular examples: min, max, <, &l=
t;=3D, =3D=3D, !=3D, >=3D, >. The relational operations need to=
return a vector of bool, which isn't compatible with index/bounds currentl=
y since they aren't parameterized by the type. Obviously, though, it =
wouldn't make sense to call them index or bounds if they are parameterized =
by a type.<br>
</div><div> </div><blockquote class=3D"gmail_quote" style=3D"margin:0p=
x 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);border-=
left-width:1px;border-left-style:solid"><div dir=3D"ltr"><p>Having said tha=
t, I assume this is something that can be added later as a pure extension, =
correct?</p>
</div></blockquote><div></div><div>Some of them, like min and max, could be=
unintrusive, though neither index nor bounds would be a particularly meani=
ngful choice as the return type.<br></div><div> </div><blockquote clas=
s=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;padding-left:1ex;border=
-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"=
>
<div dir=3D"ltr"><div><p>> Given the long turn around time for revisions=
to C++</p></div><p>The Committee is certainly trying to get better at quic=
ker iterations, let's not be discouraged by the ghosts of the past...</p>
<div><p>> Other omissions from index and bounds include:<br>> 1=
.. no data() access to the components<br>> 2. no iterators over com=
ponents for index or bound</p></div><p>index and bounds are not containers =
and should not be used as such. For the limited number of scenario where I =
want to use/modify indeterminate number of components, it was always suffic=
ient for me to use a raw loop, and operator[]...<br>
In case I'm wrong, these as well should be easy to add later as extensions.=
</p><div><p>> for_each(x_array, y_array, x_array.bounds(), [&](auto =
&x, auto &y, auto pos) {<br>> if (x !=3D y) std::cou=
t << "mismatch at position " << pos << std::endl;<br>
> });</p></div><p>I assume the idea here is that such "for_each" uses be=
gin(X), end(X) for all provided arguments, passing dereferenced iterators t=
o the function object. If so, I do not see how the current semantics of bou=
nds_iterator would get into way here? It should just work as is, no?<br>
</p></div></blockquote><div>The idea is that it would generate N nested for=
loops for N-dimensional array views, rather than an less efficient single =
for loop.<br></div><div> </div><blockquote class=3D"gmail_quote" style=
=3D"margin:0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204=
,204);border-left-width:1px;border-left-style:solid">
<div dir=3D"ltr"><p>Actually, it should be possible to write the following =
with just the current proposal and the current standard for_each:<br> =
auto x_av =3D array_view<N>{x_array};<br> auto y_av =3D array_vi=
ew<N>{y_array};<br>
for_each(begin(x_av.bounds())<u></u><wbr>, end(x_av.bounds()), [&=
](index<N> pos) {<br> if(x_av[pos] !=3D y_av[pos]) std::cout &l=
t;< "mismatch at position " << pos << std::endl;<br> })=
;</p></div></blockquote>
<div>Yes, but note that the iteration over bounds is more expensive and the=
multiplication with all of the strides has to happen for every position.<b=
r></div><div> </div><blockquote class=3D"gmail_quote" style=3D"margin:=
0px 0px 0px 0.8ex;padding-left:1ex;border-left-color:rgb(204,204,204);borde=
r-left-width:1px;border-left-style:solid">
<div dir=3D"ltr"><p>> From my perspective, the only way to properly expl=
ore this design space for multidimensional arrays/containers/ranges is thro=
ugh an actively developed and widely used open source library.</p><div>Our =
(Microsoft) prototype implementation is in the pipeline to be published as =
an open source project. It should happen really soon, and I hope it will he=
lp to convey the discussed ideas.</div>
</div></blockquote><div><br></div><div>That's good news. I think the =
best library is likely to be produced if the users of the library and the d=
evelopers of the library are one and the same. Issues become apparent=
and the library interface can be tweaked to correct them very quickly that=
way.<br>
</div></div></div></div>
</blockquote></div></blockquote></div></div></div><div><div>
<p></p>
-- <br>
<br>
--- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/xzb1d5KUxMU/unsubscribe" target=3D"_blan=
k" onmousedown=3D"this.href=3D'https://groups.google.com/a/isocpp.org/d/top=
ic/std-proposals/xzb1d5KUxMU/unsubscribe';return true;" onclick=3D"this.hre=
f=3D'https://groups.google.com/a/isocpp.org/d/topic/std-proposals/xzb1d5KUx=
MU/unsubscribe';return true;">https://groups.google.com/a/<wbr>isocpp.org/d=
/topic/std-<wbr>proposals/xzb1d5KUxMU/<wbr>unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"EY36l3K-ekcJ" o=
nmousedown=3D"this.href=3D'javascript:';return true;" onclick=3D"this.href=
=3D'javascript:';return true;">std-proposal...@<wbr>isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"javascript:" target=3D"_bla=
nk" gdf-obfuscated-mailto=3D"EY36l3K-ekcJ" onmousedown=3D"this.href=3D'java=
script:';return true;" onclick=3D"this.href=3D'javascript:';return true;">s=
td-pr...@isocpp.org</a>.<br>
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/" target=3D"_blank" onmousedown=3D"this.href=3D'http://groups=
..google.com/a/isocpp.org/group/std-proposals/';return true;" onclick=3D"thi=
s.href=3D'http://groups.google.com/a/isocpp.org/group/std-proposals/';retur=
n true;">http://groups.google.com/a/<wbr>isocpp.org/group/std-<wbr>proposal=
s/</a>.<br>
</div></div></blockquote></div><br></div>
</blockquote></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
------=_Part_716_988142105.1415999837544--
.
Author: Jeremy Maitin-Shepard <jeremy@jeremyms.com>
Date: Fri, 14 Nov 2014 13:35:49 -0800
Raw View
--001a1135ed8e93e41b0507d8692f
Content-Type: text/plain; charset=UTF-8
On Fri, Nov 14, 2014 at 1:17 PM, <phdofthehouse@gmail.com> wrote:
> I think that's convoluting the idea I'm trying to present here; the
> casting point your making... seems to be orthognal to what I'm trying to
> say (not to mention... dangerous/broken to implement? Changing the way a
> *std::array* dereferences would break code everywhere, especially code
> that takes a pointer to an array of std::array's (e.g., a vector of
> specifically-sized *std::array*s) that suddenly behaved as if it was
> calling operator[] inside of the pointed-to T? That's not a very good idea,
> I don't think).
>
I think I may not have stated my point very clearly. I am not suggesting
any change to std::array. This is what I am proposing:
int *ptr = new int[100];
int stack_arr[100];
std::array<int,50> &arr_ref = *reinterpret_cast<std::array<int,50> *>(ptr +
20);
// arr_ref refers to [ptr+20, ptr+70).
std::array<int,50> &arr_ref2 = *reinterpret_cast<std::array<int,50>
*>(stack_arr + 20);
// arr_ref2 refers to [stack_arr+20, stack_arr+70).
This will of course compile with current compilers and will almost
certainly do the right thing, but I think it may be undefined behavior
under current language rules. If indeed current compilers don't optimize
accesses to arrays in such a way that potentially break this, then making
it defined behavior would require no actual implementation changes.
> That aside, the use case here is being able to nail down as many pieces of
> computation to the compiler as possible: array_view<T, ...> and
> strided_array_view<T, ...> are analogous to a c-style or std::array-style
> declarations, with the benefit of providing the dimensions at compile-time.
> This allows a constexpr operator[] to throw out all of the multiplication
> and index caluclations to get to exact target index exactly before the
> program runs and instead becomes direct access to the memory of interest;
> this becomes a particularly interesting case for me as any special
> optimizations like SIMD can be seen ahead of time by the compiler and
> substituted in, since it can view those indices ahead of time and know the
> offsets.
>
> However, I'm not sure if that's already possible with just a
> constexpr-enabled array_view that takes its dimensions, strides and bounds
> at runtime. I have already written a buffer_view<T, dimension> in my own
> code based on the proposal paper presented, and then also wrote an
> array_view and strided_array_view with compile-time strides and bounds. My
> current compiler (VC++) chokes on constexpr, so I mostly wanted to ask
> about it here, if anyone else had a similar idea.
>
Indeed casting to a std::array reference (or reference to similar
multi-dimensional type, or possibly nested std::array) only makes sense in
the unit stride/standard row-major stride case, though for fixed-size
arrays unit stride is an extremely common and useful case. I agree that
potentially it is useful to support non-unit strides, but then you quickly
get into the complexity of supporting some sizes and some strides being
fixed at compile time and some being determined at run time.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
--001a1135ed8e93e41b0507d8692f
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Fri, Nov 14, 2014 at 1:17 PM, <span dir=3D"ltr"><<a=
href=3D"mailto:phdofthehouse@gmail.com" target=3D"_blank">phdofthehouse@gm=
ail.com</a>></span> wrote:<br><div class=3D"gmail_extra"><div class=3D"g=
mail_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"l=
tr">I think that's convoluting the idea I'm trying to present here;=
the casting point your making... seems to be orthognal to what I'm try=
ing to say (not to mention... dangerous/broken to implement? Changing the w=
ay a <i>std::array</i> dereferences would break code everywhere, especially=
code that takes a pointer to an array of std::array's (e.g., a vector =
of specifically-sized <i>std::array</i>s) that suddenly behaved as if it wa=
s calling operator[] inside of the pointed-to T? That's not a very good=
idea, I don't think).<br></div></blockquote><div><br></div><div>I thin=
k I may not have stated my point very clearly.=C2=A0 I am not suggesting an=
y change to std::array.=C2=A0 This is what I am proposing:<br><br></div><di=
v>int *ptr =3D new int[100];<br></div><div>int stack_arr[100];<br></div><di=
v>std::array<int,50> &arr_ref =3D *reinterpret_cast<std::array=
<int,50> *>(ptr + 20);<br></div><div><div>// arr_ref refers to [pt=
r+20, ptr+70).<br></div>std::array<int,50> &arr_ref2 =3D *reinter=
pret_cast<std::array<int,50> *>(stack_arr + 20);<br></div>// ar=
r_ref2 refers to [stack_arr+20, stack_arr+70).<br><div><br>This will of cou=
rse compile with current compilers and will almost certainly do the right t=
hing, but I think it may be undefined behavior under current language rules=
..=C2=A0 If indeed current compilers don't optimize accesses to arrays i=
n such a way that potentially break this, then making it defined behavior w=
ould require no actual implementation changes.</div><br><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex"><div dir=3D"ltr"><br>That aside, the use c=
ase here is being able to nail down as many pieces of computation to the co=
mpiler as possible: array_view<T, ...> and strided_array_view<T, .=
...> are analogous to a c-style or std::array-style declarations, with th=
e benefit of providing the dimensions at compile-time. This allows a conste=
xpr operator[] to throw out all of the multiplication and index caluclation=
s to get to exact target index exactly before the program runs and instead =
becomes direct access to the memory of interest; this becomes a particularl=
y interesting case for me as any special optimizations like SIMD can be see=
n ahead of time by the compiler and substituted in, since it can view those=
indices ahead of time and know the offsets.<br></div></blockquote><div>=C2=
=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8e=
x;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"=
>However, I'm not sure if that's already possible with just a const=
expr-enabled array_view that takes its dimensions, strides and bounds at ru=
ntime. I have already written a buffer_view<T, dimension> in my own c=
ode based on the proposal paper presented, and then also wrote an array_vie=
w and strided_array_view with compile-time strides and bounds. My current c=
ompiler (VC++) chokes on constexpr, so I mostly wanted to ask about it here=
, if anyone else had a similar idea.<span class=3D""><br></span></div></blo=
ckquote><div><br></div><div>Indeed casting to a std::array reference (or re=
ference to similar multi-dimensional type, or possibly nested std::array) o=
nly makes sense in the unit stride/standard row-major stride case, though f=
or fixed-size arrays unit stride is an extremely common and useful case.=C2=
=A0 I agree that potentially it is useful to support non-unit strides, but =
then you quickly get into the complexity of supporting some sizes and some =
strides being fixed at compile time and some being determined at run time.<=
br></div><div>=C2=A0</div></div><br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />
--001a1135ed8e93e41b0507d8692f--
.