Thread overview | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 16, 2016 Void pointers | ||||
---|---|---|---|---|
| ||||
Hi all! Let's talk about void pointers a little bit. Found this already http://forum.dlang.org/thread/codoixfeqstvqswirsax@forum.dlang.org?page=1 but my question/problem differs from the above, so maybe, I have found a useful application for void pointers... Form of the posting: I have some questions about the usage of void pointers in some expressions, but I'm not even sure, if void pointers should be used. For the latter part, I found at least two other possibilities, which goes further below. Say I have something like that: // This function is intentionally templated, as it should take slices and return something // boundchecked only @nogc T[] getSlice(T)(T* ptr, size_t a, size_t b) { return T[a .. b]; } void main() { void* ptr; // this will stay uninitialized during the whole program run // something that works as desired: writeln(&ptr[4]); // prints '4' auto b = getSlice(ptr, 5, 10); writeln("b first: ", &b[0]); // prints '5'. This is the most useful feature. assert(b.capacity == 0); // holds always. So, getSlice returns always a slice, not an array. // arr[3] = ... // fails. It is intended to do so. // something that does not worked as expected: // how to rewrite a for loop for(auto i = 0; i < b.length; i++) writeln(&b[i]); // into a foreach loop? // a question about usability: is there a trait, which can semantically check, if a type // (void, or something else) behaves in the described manner? } Something, which also could be used to achieve the same behavior: using ubyte* instead of void* using something like this: struct M { @disable this(); @disable this(this); } The important thing, as I found out is: the underlying type has to be only as large as a byte. Background: is already written and could be provided :) Thanks in advance :) |
May 16, 2016 Re: Void pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | On 05/16/2016 10:39 PM, Alex wrote: > // This function is intentionally templated, as it should take slices > and return something > // boundchecked only > @nogc T[] getSlice(T)(T* ptr, size_t a, size_t b) > { > return T[a .. b]; Typo here. Should be `ptr[a .. b]`. > } > > void main() > { > void* ptr; // this will stay uninitialized during the whole program > run The pointer is being initialized, though. To null, which is why your shenanigans below work reliably. > // something that works as desired: > writeln(&ptr[4]); // prints '4' > auto b = getSlice(ptr, 5, 10); > writeln("b first: ", &b[0]); // prints '5'. This is the most useful > feature. > assert(b.capacity == 0); // holds always. So, getSlice returns > always a slice, not an array. > // arr[3] = ... // fails. It is intended to do so. > > // something that does not worked as expected: > // how to rewrite a for loop > for(auto i = 0; i < b.length; i++) writeln(&b[i]); > // into a foreach loop? Not, I guess, since you can't have a void variable, not even if it's marked `ref`. I have to say that I don't see the point in all this. You can't access the elements of b in any way, since they're in memory that you don't own. So all you got here is a fancy way of counting, no? Looping over a range of numbers: ---- foreach (i; 5 .. 10) writeln(i); ---- Or if you want to store it in a variable: ---- import std.range: iota; auto b = iota(5, 10); foreach (i; b) writeln(i); ---- > // a question about usability: is there a trait, which can > semantically check, if a type > // (void, or something else) behaves in the described manner? Not sure what you mean here. What's the described manner? Not being able to have a variable of the type? I think void is the only type with that property. So maybe checking if the type is exactly void is enough: `is(T == void)`. Or you can check if some operation works on the type or a value of it: `__traits(compiles, writeln(T.init))` > } |
May 16, 2016 Re: Void pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | On 5/16/16 4:39 PM, Alex wrote:
> // something that does not worked as expected:
> // how to rewrite a for loop
> for(auto i = 0; i < b.length; i++) writeln(&b[i]);
> // into a foreach loop?
>
What you need is a range that produces void * instead element itself.
This would probably work:
struct VoidRange
{
void[] arr;
auto front() { return arr.ptr; }
void popFront() { arr.popFront; }
bool empty() { return arr.empty; }
}
foreach(p; VoidRange(b)) writeln(p);
-Steve
|
May 16, 2016 Re: Void pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | On Monday, 16 May 2016 at 21:04:32 UTC, ag0aep6g wrote: > > Typo here. Should be `ptr[a .. b]`. Thanks >> >> void main() >> { >> void* ptr; // this will stay uninitialized during the whole program >> run > > The pointer is being initialized, though. To null, which is why your shenanigans below work reliably. Ok, this is a cool hint, especially about the reliability. Thanks! > >> // something that works as desired: >> writeln(&ptr[4]); // prints '4' >> auto b = getSlice(ptr, 5, 10); >> writeln("b first: ", &b[0]); // prints '5'. This is the most useful >> feature. >> assert(b.capacity == 0); // holds always. So, getSlice returns >> always a slice, not an array. >> // arr[3] = ... // fails. It is intended to do so. >> >> // something that does not worked as expected: >> // how to rewrite a for loop >> for(auto i = 0; i < b.length; i++) writeln(&b[i]); >> // into a foreach loop? > > Not, I guess, since you can't have a void variable, not even if it's marked `ref`. Yes, this is something what I was surprised about, but, seems logical on the other hand... So, I get a slice, which is not foreachable, but still able to be iterated over... > I have to say that I don't see the point in all this. You can't access the elements of b in any way, since they're in memory that you don't own. So all you got here is a fancy way of counting, no? Yes! This is important and this is the place, where I have to provide background. (Following post) > > Not sure what you mean here. What's the described manner? Not being able to have a variable of the type? Well... not wanting to have a variable, which stores numbers, which are natural numbers, beginning with zero, used for counting only. > > I think void is the only type with that property. So maybe checking if the type is exactly void is enough: `is(T == void)`. OK... > Or you can check if some operation works on the type or a value of it: `__traits(compiles, writeln(T.init))` > |
May 16, 2016 Re: Void pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | Background: Say, I have objects of kind E, which operate on structs of kind M. The problem: if an action is done on a struct, say M42, there should be also some action done on other structs, which have some relation to M42, but neither the operating object, nor M42 is aware of them (and the action which is required), as this would break encapsulation. So, I choosed another approach: There are some describing objects, say of kind B and G, which hold a specific information (a single property) of all existent M structs. These objects know which "neighbors" are also affected in case of some action of E on the struct M42 and can perform appropriate actions on them, at least on the contained property. The problem which is still unsolved: objects of kind E operates on structs M randomly. For this goal, they have to save the information between their actions, on which structs they are interested in, to report the ordinal number to the describing objects. The saving of ordinal numbers with minimum computational costs (nogc, even no construction of iota-structs, etc) is crucial. |
May 16, 2016 Re: Void pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Monday, 16 May 2016 at 21:15:16 UTC, Steven Schveighoffer wrote:
> On 5/16/16 4:39 PM, Alex wrote:
>> // something that does not worked as expected:
>> // how to rewrite a for loop
>> for(auto i = 0; i < b.length; i++) writeln(&b[i]);
>> // into a foreach loop?
>>
>
> What you need is a range that produces void * instead element itself.
>
> This would probably work:
>
> struct VoidRange
> {
> void[] arr;
> auto front() { return arr.ptr; }
> void popFront() { arr.popFront; }
> bool empty() { return arr.empty; }
> }
>
> foreach(p; VoidRange(b)) writeln(p);
>
> -Steve
Yes... I could do this... but then, I would construct millions of structs to hold just ordinal numbers... Using a iota would also be a possibility... but I want something even less perceptible...
|
May 16, 2016 Re: Void pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | On 5/16/16 5:38 PM, Alex wrote:
> On Monday, 16 May 2016 at 21:15:16 UTC, Steven Schveighoffer wrote:
>> On 5/16/16 4:39 PM, Alex wrote:
>>> // something that does not worked as expected:
>>> // how to rewrite a for loop
>>> for(auto i = 0; i < b.length; i++) writeln(&b[i]);
>>> // into a foreach loop?
>>>
>>
>> What you need is a range that produces void * instead element itself.
>>
>> This would probably work:
>>
>> struct VoidRange
>> {
>> void[] arr;
>> auto front() { return arr.ptr; }
>> void popFront() { arr.popFront; }
>> bool empty() { return arr.empty; }
>> }
>>
>> foreach(p; VoidRange(b)) writeln(p);
>>
>> -Steve
>
> Yes... I could do this... but then, I would construct millions of
> structs to hold just ordinal numbers... Using a iota would also be a
> possibility... but I want something even less perceptible...
Hey, there's nothing wrong with for-loops. Just trying to answer the question :)
You could also do something like:
foreach(i; 0 .. b.length) writeln(&b[i]);
-Steve
|
May 16, 2016 Re: Void pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Monday, 16 May 2016 at 21:41:20 UTC, Steven Schveighoffer wrote: > > Hey, there's nothing wrong with for-loops. Just trying to answer the question :) > > You could also do something like: > > foreach(i; 0 .. b.length) writeln(&b[i]); Ha! Yes! :) Thanks :) > -Steve |
May 17, 2016 Re: Void pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | On 05/16/2016 11:35 PM, Alex wrote:
> Background:
> Say, I have objects of kind E, which operate on structs of kind M. The
> problem: if an action is done on a struct, say M42, there should be also
> some action done on other structs, which have some relation to M42, but
> neither the operating object, nor M42 is aware of them (and the action
> which is required), as this would break encapsulation.
> So, I choosed another approach:
> There are some describing objects, say of kind B and G, which hold a
> specific information (a single property) of all existent M structs.
> These objects know which "neighbors" are also affected in case of some
> action of E on the struct M42 and can perform appropriate actions on
> them, at least on the contained property.
> The problem which is still unsolved:
> objects of kind E operates on structs M randomly. For this goal, they
> have to save the information between their actions, on which structs
> they are interested in, to report the ordinal number to the describing
> objects.
> The saving of ordinal numbers with minimum computational costs (nogc,
> even no construction of iota-structs, etc) is crucial.
I can't say that I understand the setup you describe. But are you sure that iota has a higher cost than (ab)using a slice?
I mean, they're pretty much exactly the same: an offset, a length, and an increment operation. If inlining doesn't fail, they should perform the same, no?
And if iota does perform worse for some reason, I feel like there must be a way to implement something that matches the speed of the slice without inheriting its ugliness.
|
May 17, 2016 Re: Void pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | On 05/16/2016 11:33 PM, Alex wrote:
> Well... not wanting to have a variable, which stores numbers, which are
> natural numbers, beginning with zero, used for counting only.
But you have such a variable: b. I may still be missing the point.
|
Copyright © 1999-2021 by the D Language Foundation