
Hi, The current shared_array doesn't keep track of size. This greatly decreases it's usefulness. So I wrote a variant that does: http://pastebin.com/wkdLVqM1 Any interest in such a variant? Olaf

Hi Olaf,
The current shared_array doesn't keep track of size. This greatly decreases it's usefulness. So I wrote a variant that does:
I like the concept of combining a shared_array with an iterator_range. In my own work I can see an instance knowing its length, type erasure, and possibly providing custom deleter semantics being handy. I'd personally call it a shared_range. - Rhys

On Sun, Oct 16, 2011 at 4:57 AM, Rhys Ulerich <rhys.ulerich@gmail.com> wrote:
Hi Olaf,
The current shared_array doesn't keep track of size. This greatly decreases it's usefulness. So I wrote a variant that does:
I like the concept of combining a shared_array with an iterator_range. In my own work I can see an instance knowing its length, type erasure, and possibly providing custom deleter semantics being handy.
A custom deleter is supported already via shared_array2(T* b, T* e, shared_ptr<void> const& n) This would also allow you to construct a shared_array2 from a memory mapped file, for example.
I'd personally call it a shared_range.
Why? The class owns the content. A range does not own the content. Olaf

The current shared_array doesn't keep track of size. This greatly decreases it's usefulness. So I wrote a variant that does: http://pastebin.com/wkdLVqM1
I'd personally call it a shared_range.
Why? The class owns the content. A range does not own the content.
Because the class knows its end. A shared_array does not know its end. And because your implementation is-an iterator_range. Re: Peter Dimov's comment that:
One question you'll invariably get from people is why you don't store begin into the shared_ptr, eliminating one pointer...
shared_ptr<T> begin_; size_t size_;
If one thinks of the class as a resource-owning iterator_range, I think a three member (shared_ptr/iterator_range) implementation gives more flexibility (e.g. sub range instances could track resource ownership against the same shared_ptr). If one thinks of the class as a shared_array with a length function, the two member (shared_ptr/size_t) implementation is definitely more space efficient. In that case, I'd personally not publicly inherit from iterator_range and would follow Peter's implementation suggestion (possibly using a shared_array instead of a shared_ptr). - Rhys

On Sun, Oct 16, 2011 at 6:22 PM, Rhys Ulerich <rhys.ulerich@gmail.com> wrote:
Why? The class owns the content. A range does not own the content.
Because the class knows its end. A shared_array does not know its end. And because your implementation is-an iterator_range.
That's because shared_array is handicapped. ;) boost/std::array knows it's size. Even the size of a C array can be determined.
Re: Peter Dimov's comment that:
One question you'll invariably get from people is why you don't store begin into the shared_ptr, eliminating one pointer...
shared_ptr<T> begin_; size_t size_;
If one thinks of the class as a resource-owning iterator_range, I think a three member (shared_ptr/iterator_range) implementation gives more flexibility (e.g. sub range instances could track resource ownership against the same shared_ptr).
If one thinks of the class as a shared_array with a length function, the two member (shared_ptr/size_t) implementation is definitely more space efficient. In that case, I'd personally not publicly inherit from iterator_range and would follow Peter's implementation suggestion (possibly using a shared_array instead of a shared_ptr).
Both allow sub ranges. But yeah, a 3 ptr class (begin, end and counter) is ideal. Olaf

The current shared_array doesn't keep track of size. This greatly decreases it's usefulness. So I wrote a variant that does: http://pastebin.com/wkdLVqM1
If one thinks of the class as a resource-owning iterator_range, I think a three member (shared_ptr/iterator_range) implementation gives more flexibility (e.g. sub range instances could track resource ownership against the same shared_ptr).
I extended the spirit of Olaf's shared_array2 implementation quite a bit so that it really is a smart resource-managing iterator_range called shared_range. The implementation (with documentation) and tests are up at https://github.com/RhysU/shared_range. I've opted to move resource allocating operation's like Olaf's shared_array2(size_t) constructor into free functions in the spirit of make_shared and allocate_shared. Olaf, I've added your name to the implementation header in shared_range.hpp. Please let me know if that's not okay with you. Any feedback (or edge cases I've missed) greatly appreciated, Rhys

On Wed, Oct 19, 2011 at 8:00 PM, Rhys Ulerich <rhys.ulerich@gmail.com> wrote:
The current shared_array doesn't keep track of size. This greatly decreases it's usefulness. So I wrote a variant that does: http://pastebin.com/wkdLVqM1
If one thinks of the class as a resource-owning iterator_range, I think a three member (shared_ptr/iterator_range) implementation gives more flexibility (e.g. sub range instances could track resource ownership against the same shared_ptr).
I extended the spirit of Olaf's shared_array2 implementation quite a bit so that it really is a smart resource-managing iterator_range called shared_range. The implementation (with documentation) and
Hmm, I thought mine was really smart already. :p Where did the (size_t) and (..., shared_ptr<void>) constructors go?
tests are up at https://github.com/RhysU/shared_range. I've opted to move resource allocating operation's like Olaf's shared_array2(size_t) constructor into free functions in the spirit of make_shared and allocate_shared.
Ah. Why? shared_array<char> v(10) (like vector) would be neater.
Olaf, I've added your name to the implementation header in shared_range.hpp. Please let me know if that's not okay with you.
That's fine.
typedef T element_type; advance_begin()
Doesn't iterator_range take care of that? Where did data() go? Olaf -- Olaf

Hi Olaf, First, thanks for checking out the implementation.
The current shared_array doesn't keep track of size. This greatly decreases it's usefulness. So I wrote a variant that does: http://pastebin.com/wkdLVqM1
I extended the spirit of Olaf's shared_array2 implementation quite a bit so that it really is a smart resource-managing iterator_range called shared_range. The implementation (with documentation) and tests are up at https://github.com/RhysU/shared_range.
Hmm, I thought mine was really smart already. :p
It was, but it seemed like you wanted a shared_array and that you subclassed iterator_range as only an implementation detail. This implementation is intended as a public descendent of iterator_range moreso than a shared_array.
Where did the (size_t) and (..., shared_ptr<void>) constructors go?
// Free function template< class T > shared_range<T> make_shared_range(::std::size_t sz); // Constructor shared_range(const ::boost::shared_array<T>& p, ::std::size_t sz)
I've opted to move resource allocating operation's like Olaf's shared_array2(size_t) constructor into free functions in the spirit of make_shared and allocate_shared.
Ah. Why? shared_array<char> v(10) (like vector) would be neater.
I agree, but it seems that boost::smart_XXX constructors don't allocate memory. That functionality gets left to free functions. Just following the existing pattern.
Olaf, I've added your name to the implementation header in shared_range.hpp. Please let me know if that's not okay with you.
That's fine.
Great.
typedef T element_type; advance_begin()
Doesn't iterator_range take care of that?
It does, but it returns a reference to iterator_range. I wanted shared_range::advance_begin() to return a reference to shared_range.
Where did data() go?
This is the biggest departure from your implementation and one that stems from wanting a "shared iterator_range" more than a "shared_array with a length". iterator_range has an operator= taking any ForwardRange. To have shared_range::operator= logically accomplish the same thing, I opted for it copy a ForwardRange but not to perform any shared resource ownership. In that case, the shared_array shared_range::p_ has no well-defined semantic (since nothing's managed) which makes data() (among other things) not well-defined concepts. Consequently, no data() member nor any access to the implementation's private smart pointer. The choice is documented in the third paragraph under "IMPLEMENTATION COMMENTS". - Rhys

On Wed, Oct 19, 2011 at 9:05 PM, Rhys Ulerich <rhys.ulerich@gmail.com> wrote:
Hmm, I thought mine was really smart already. :p
It was, but it seemed like you wanted a shared_array and that you
I do.
subclassed iterator_range as only an implementation detail. This implementation is intended as a public descendent of iterator_range moreso than a shared_array.
Ranges don't own anything. A shared_range still sounds wrong.
Where did the (size_t) and (..., shared_ptr<void>) constructors go?
// Free function template< class T > shared_range<T> make_shared_range(::std::size_t sz);
// Constructor shared_range(const ::boost::shared_array<T>& p, ::std::size_t sz)
I've opted to move resource allocating operation's like Olaf's shared_array2(size_t) constructor into free functions in the spirit of make_shared and allocate_shared.
Ah. Why? shared_array<char> v(10) (like vector) would be neater.
I agree, but it seems that boost::smart_XXX constructors don't allocate memory. That functionality gets left to free functions. Just following the existing pattern.
That's not a good reason. ;)
typedef T element_type; advance_begin()
Doesn't iterator_range take care of that?
It does, but it returns a reference to iterator_range. I wanted shared_range::advance_begin() to return a reference to shared_range.
Ah.
Where did data() go?
This is the biggest departure from your implementation and one that stems from wanting a "shared iterator_range" more than a "shared_array with a length". iterator_range has an operator= taking any
Isn't it more like a ptr_range anyway?
ForwardRange. To have shared_range::operator= logically accomplish the same thing, I opted for it copy a ForwardRange but not to perform any shared resource ownership. In that case, the shared_array shared_range::p_ has no well-defined semantic (since nothing's managed) which makes data() (among other things) not well-defined concepts. Consequently, no data() member nor any access to the
data() would just return empty() ? NULL : &front();
implementation's private smart pointer. The choice is documented in the third paragraph under "IMPLEMENTATION COMMENTS".
Will have a look. -- Olaf

This implementation is intended as a public descendent of iterator_range moreso than a shared_array.
Ranges don't own anything. A shared_range still sounds wrong.
Dunno what more to say. It's a mashup of a shared_array and an iterator_range. The options were shared_iterator (wrong), shared_range (eh), array_iterator (wrong), and array_range (wrong). "shared_block" sounds better but "block" is tremendously ambiguous. And the concept implemented really is a range. So, "shared_range".
Where did data() go?
This is the biggest departure from your implementation and one that stems from wanting a "shared iterator_range" more than a "shared_array with a length". iterator_range has an operator= taking any
Isn't it more like a ptr_range anyway?
I don't follow this comment. Is there a ptr_range somewhere that I can neither Google nor grep? My coffee's wearing off...
ForwardRange. To have shared_range::operator= logically accomplish the same thing, I opted for it copy a ForwardRange but not to perform any shared resource ownership. In that case, the shared_array shared_range::p_ has no well-defined semantic (since nothing's managed) which makes data() (among other things) not well-defined concepts. Consequently, no data() member nor any access to the
data() would just return empty() ? NULL : &front();
You just implemented begin(). It's a range. :) - Rhys

On Wed, Oct 19, 2011 at 11:42 PM, Rhys Ulerich <rhys.ulerich@gmail.com> wrote:
ForwardRange. To have shared_range::operator= logically accomplish the same thing, I opted for it copy a ForwardRange but not to perform any shared resource ownership. In that case, the shared_array shared_range::p_ has no well-defined semantic (since nothing's managed) which makes data() (among other things) not well-defined concepts. Consequently, no data() member nor any access to the
data() would just return empty() ? NULL : &front();
You just implemented begin(). It's a range. :)
No, data() returns a pointer, while begin() returns an iterator (which might be, but doesn't have to be, a pointer). -- Olaf

On Wed, Oct 19, 2011 at 4:47 PM, Olaf van der Spek <ml@vdspek.org> wrote:
On Wed, Oct 19, 2011 at 11:42 PM, Rhys Ulerich <rhys.ulerich@gmail.com> wrote:
ForwardRange. To have shared_range::operator= logically accomplish the same thing, I opted for it copy a ForwardRange but not to perform any shared resource ownership. In that case, the shared_array shared_range::p_ has no well-defined semantic (since nothing's managed) which makes data() (among other things) not well-defined concepts. Consequently, no data() member nor any access to the
data() would just return empty() ? NULL : &front();
You just implemented begin(). It's a range. :)
No, data() returns a pointer, while begin() returns an iterator (which might be, but doesn't have to be, a pointer).
True in general. This implementation publicly inherits from iterator_range<T*>. Are there cases where iterator_range<T*>::begin() could return anything but a pointer? - Rhys

On Wed, Oct 19, 2011 at 11:56 PM, Rhys Ulerich <rhys.ulerich@gmail.com> wrote:
No, data() returns a pointer, while begin() returns an iterator (which might be, but doesn't have to be, a pointer).
True in general. This implementation publicly inherits from iterator_range<T*>. Are there cases where iterator_range<T*>::begin() could return anything but a pointer?
No, but my request is for data() -- Olaf

Olaf van der Spek wrote:
Hi,
The current shared_array doesn't keep track of size. This greatly decreases it's usefulness. So I wrote a variant that does:
One question you'll invariably get from people is why you don't store begin into the shared_ptr, eliminating one pointer: shared_ptr<T> begin_; size_t size_;

On Sun, Oct 16, 2011 at 4:31 PM, Peter Dimov <pdimov@pdimov.com> wrote:
One question you'll invariably get from people is why you don't store begin into the shared_ptr, eliminating one pointer:
shared_ptr<T> begin_; size_t size_;
That's just an implementation detail. You can't use iterator_range that way. Instead of shared_ptr you could store just a pointer to the counter. Olaf
participants (3)
-
Olaf van der Spek
-
Peter Dimov
-
Rhys Ulerich