www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Casts and trusted

reply "Anonymous" <a a.com> writes:
This seems to work from quick testing, but it has casts in 
get_ref that I want to avoid.
cast(T*) refs[i] is obviously not  safe.
cast(T*) _buffer[read].ptr doesn't seem necessary, since 
_buffer[read] is conceivably a T so _buffer[read].ptr should be a 
T*. But without it I get "Error: cannot implicitly convert 
expression (&this._buffer[read]) of type const(char)* to char[5]*"
I do want to pass in a preallocated buffer to store some 
pointers, at least as one get option. I also want to disallow 
modification to the ring buffer through those pointers. How might 
I rework things to enable that usage while being  safe?

enum TakeStrategy { cyclic, once }
alias TS = TakeStrategy;
struct StaticRingBuffer(T, size_t cap) {
	static assert (cap > 1);
	private T[cap] _buffer;
	private size_t _index = cap-1;
	private size_t _fill = 0;
	 property size_t extra() nothrow const {
		return cap-fill;
	}
	 property size_t index() nothrow const {
		return _index;
	}
	 property size_t fill() nothrow const {
		return _fill;
	}

	 property const ref front() nothrow const {
		return _buffer[index];
	}

	void put(T ele) pure nothrow {
		if (index == cap-1) _index = 0;
		else ++_index;
		_buffer[index] = ele;
		
		if (fill < cap) ++_fill;
	}

	void put(T[] eles) pure nothrow {
		foreach(e; eles) put(e);
	}

	 trusted void get_ref(TS strat=TS.cyclic)(size_t n, const(T*)[] 
refs) const nothrow
	{
		assert(refs.length == n);
		static if (strat==TS.once) size_t numreads = fixNToFill(n);
		else size_t numreads = n;

		size_t read = index;
		foreach(i;0..numreads) {
			cast(T*) refs[i] = cast(T*) _buffer[read].ptr;
			if (read == 0) read = fill-1;
			else --read;
		}

	}

	private size_t fixNToFill(size_t n) const nothrow {
		return (n > fill) ? fill : n;
	}
}
Jun 13 2014
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/13/2014 06:56 PM, Anonymous wrote:

       trusted void get_ref(TS strat=TS.cyclic)(size_t n, const(T*)[]
 refs) const nothrow
      {
[...]
              cast(T*) refs[i] = cast(T*) _buffer[read].ptr;
The left-hand side violates a promise: The function takes a slice where the elemenst are const. So, the function says that it will not modify the elements. Also, _buffer[read] is an element, not a slice: private T[cap] _buffer; So, there is no .ptr property. However, perhaps my test code fails to demonstrate your problem: auto s = StaticRingBuffer!(int, 10)(); int i; int*[] arr; arr ~= &i; s.get_ref(0, arr); Please show us complete code. :) Ali
Jun 13 2014
parent "Anonymous" <a a.com> writes:
That really is it. The other methods are just other gets to the 
buffer, like this:

T[] get_dup(TS strat=TS.cyclic)(size_t n) const {
	static if (strat==TS.once) size_t numreads = fixNToFill(n);
	else size_t numreads = n;
	auto ret = new T[](numreads);
	
	size_t read = index;
	foreach(i;0..numreads) {
		ret[i] = _buffer[read].dup;
		if (read == 0) read = fill-1;
		else --read;
	}

	return ret;
}

But ah, the .ptr property is not supposed to work for array 
element? In any case it still works as cast(T*) &(_buffer[read]). 
Here's the unittest I slapped together:

unittest {
	char[5] hello = "hello";
	char[5] world = "world";
	char[5] forty = "forty";
	char[5] three = "three";
	char[5] gdbye = "gdbye";
	alias chars_t = char[5];
	chars_t[] foo = [hello,world,forty,three];
	chars_t[] oob = foo.dup.reverse;
	StaticRingBuffer!(chars_t,4) bar;
	bar.put(foo);
	assert(bar.index==3);
	const(chars_t)*[4] ptrs;
	bar.get_ref(4,ptrs);
	assert(bar.get_dup(4) == oob);
	foreach(i,ptr; ptrs) assert(*ptr == oob[i]);
	assert(bar.get_dup(7) == 
[three,forty,world,hello,three,forty,world]);
	bar.put("gdbye");
	assert(bar.index==0);
	assert(bar.get_dup(4) == [gdbye,three,forty,world]);
	assert(bar.get_dup(7) == 
[gdbye,three,forty,world,gdbye,three,forty]);
}

But now I see my problem is that a simple const(T*)[N] already 
initializes its elements to null, so nothing past that should 
modify them. And without the casts, the type on &(_buffer[read]) 
is a const(T*) instead of something else which finally makes 
sense. Somehow I thought .ptr was a property of everything.

And now I realize that I can just put the ptr array within the 
get scope, and return it, to initialize a lhs const(T*)[] by 
value. I was making things hard on myself by trying to modify a 
passed-in buffer.
Jun 14 2014