www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Void pointers

reply Alex <sascha.orlov gmail.com> writes:
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
next sibling parent reply ag0aep6g <anonymous example.com> writes:
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
next sibling parent reply Alex <sascha.orlov gmail.com> writes:
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
parent reply ag0aep6g <anonymous example.com> writes:
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.
May 16 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Monday, 16 May 2016 at 22:30:38 UTC, ag0aep6g wrote:
 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.
Yeah, the b variable is contained in the E objects and is unavoidable, as the E object has to save the region he is at and some number has to be reported by the E object to the describing objects in case of an action. The point is, that the slice of numbers, contained in the E object is done from nothing. Well, from a void pointer. So, I get ordinal numbers from void and not from a list. Just as the reality (in my head) is: you can count something without having written the natural numbers before you start to count... Especially, I don't have to create some strange structs containing just a number, as I expect to have some millions of them.
May 16 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 05/17/2016 12:53 AM, Alex wrote:
 Just as the reality (in my head) is: you can count something without
 having written the natural numbers before you start to count...
iota does that, too. A iota struct doesn't store all the numbers it will emit. Just like a slice, a iota struct stores two numbers: the first and the amount of numbers. Iterating over it means counting, not reading pre-generated numbers from a list.
 Especially, I don't have to create some strange structs containing just
 a number, as I expect to have some millions of them.
Some million slices will take just as much space as some million iota structs. Storing a slice isn't free. If you create the slices on the fly, you can do that with iota too. No need to store them beforehand.
May 16 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Monday, 16 May 2016 at 23:01:44 UTC, ag0aep6g wrote:
 On 05/17/2016 12:53 AM, Alex wrote:
 Just as the reality (in my head) is: you can count something 
 without
 having written the natural numbers before you start to count...
iota does that, too. A iota struct doesn't store all the numbers it will emit. Just like a slice, a iota struct stores two numbers: the first and the amount of numbers. Iterating over it means counting, not reading pre-generated numbers from a list.
 Especially, I don't have to create some strange structs 
 containing just
 a number, as I expect to have some millions of them.
Some million slices will take just as much space as some million iota structs. Storing a slice isn't free. If you create the slices on the fly, you can do that with iota too. No need to store them beforehand.
the space is the same, yes... Added this to my test: import std.conv : to; import std.datetime; size_t aM = 5; size_t bM = 80; void f1() {auto io = iota(aM,bM);} void f2() {auto sl = testFunc(arr, aM ,bM);} auto r = benchmark!(f1, f2)(100_000); auto f0Result = to!Duration(r[0]); // time f1 took to run 10,000 times auto f1Result = to!Duration(r[1]); // time f2 took to run 10,000 times writeln("f1: ", f0Result); writeln("f2: ", f1Result); with dmd test44.d -release the results are: f1: 692 μs and 7 hnsecs f2: 379 μs and 1 hnsec
May 16 2016
next sibling parent Alex <sascha.orlov gmail.com> writes:
On Tuesday, 17 May 2016 at 06:55:35 UTC, Alex wrote:
 import std.conv : to;
 import std.datetime;
 size_t aM = 5; size_t bM = 80;
 void f1() {auto io = iota(aM,bM);}
 void f2() {auto sl = testFunc(arr, aM ,bM);}
 auto r = benchmark!(f1, f2)(100_000);
 auto f0Result = to!Duration(r[0]); // time f1 took to run 
 10,000 times
 auto f1Result = to!Duration(r[1]); // time f2 took to run 
 10,000 times
 writeln("f1: ", f0Result);
 writeln("f2: ", f1Result);

 with dmd test44.d -release
 the results are:
 f1: 692 μs and 7 hnsecs
 f2: 379 μs and 1 hnsec
testFunc is the getSlice method... sorry... and the functions are run 100000 times
May 17 2016
prev sibling parent reply Rene Zwanenburg <renezwanenburg gmail.com> writes:
On Tuesday, 17 May 2016 at 06:55:35 UTC, Alex wrote:
 with dmd test44.d -release
 the results are:
You may want to pass '-O -inline' as well. -O enables general optimizations, -inline enables function inlining. -release is for disabling bounds checks, invariants, asserts.. The -debug and -release switches influence the language's behavior. -O and -inline are optimization switches and should not change the behavior of your program, codegen bugs aside ^^ Additionally, some people recommend never using -release. It depends on that type of program you're writing, but the performance gain is often not worth the loss in safety. Think of the number of exploits enabled by C's lack of bounds checking.
May 17 2016
next sibling parent reply Alex <sascha.orlov gmail.com> writes:
On Tuesday, 17 May 2016 at 08:16:15 UTC, Rene Zwanenburg wrote:
 On Tuesday, 17 May 2016 at 06:55:35 UTC, Alex wrote:
 with dmd test44.d -release
 the results are:
You may want to pass '-O -inline' as well. -O enables general optimizations, -inline enables function inlining. -release is for disabling bounds checks, invariants, asserts.. The -debug and -release switches influence the language's behavior. -O and -inline are optimization switches and should not change the behavior of your program, codegen bugs aside ^^ Additionally, some people recommend never using -release. It depends on that type of program you're writing, but the performance gain is often not worth the loss in safety. Think of the number of exploits enabled by C's lack of bounds checking.
ok... now the speed results are exact the same... so... besides void*, ubyte*, a pointer to a strange, not constructible struct, I could take a iota too...
May 17 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Tuesday, 17 May 2016 at 08:45:44 UTC, Alex wrote:
 so...
 besides
 void*, ubyte*, a pointer to a strange, not constructible 
 struct, I could take a iota too...
a comment on my own: even every type of the above mentioned is possible, there are slightly differences between them: 1. As I don't want to be able to instantiate the type itself, I would like to drop ubyte*. 2. If I want to be able to slice a iota, I have to initialize it with the last number. But the object, which stores the pointer does not need to know anything about this number. So, I rather would not like to pass this number only for being able to instantiate the iota struct. So this leave me again with the void* and a pointer to a strange, not constructible struct...
May 17 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 05/17/2016 12:53 PM, Alex wrote:
 2. If I want to be able to slice a iota, I have to initialize it with
 the last number. But the object, which stores the pointer does not need
 to know anything about this number. So, I rather would not like to pass
 this number only for being able to instantiate the iota struct.
How do you make a slice without the last number? You need two numbers for iota, and you need two numbers for a slice.
May 17 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Tuesday, 17 May 2016 at 12:24:58 UTC, ag0aep6g wrote:
 On 05/17/2016 12:53 PM, Alex wrote:
 2. If I want to be able to slice a iota, I have to initialize 
 it with
 the last number. But the object, which stores the pointer does 
 not need
 to know anything about this number. So, I rather would not 
 like to pass
 this number only for being able to instantiate the iota struct.
How do you make a slice without the last number? You need two numbers for iota, and you need two numbers for a slice.
For a slice I surely need two numbers. But this should all be, what I need for a slice. For a iota, I need a maximum, which is not provided (at least at this moment) to the object containing the pointer/iota thing. On the other hand, I can't live without a "real" object which I slice, so I need either a iota or a pointer. This is due that all the slices I have are totally ordered.
May 17 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 05/17/2016 03:14 PM, Alex wrote:
 For a slice I surely need two numbers. But this should all be, what I
 need for a slice. For a iota, I need a maximum, which is not provided
 (at least at this moment) to the object containing the pointer/iota thing.
The slice's length is practically the same as iota's maximum. For slicing a pointer you need the minimum and the maximum, just as with iota. I don't see the difference. ptr[5 .. 10] vs iota(5, 10) - Surely you need the number 10 in both cases?
May 17 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Tuesday, 17 May 2016 at 13:25:34 UTC, ag0aep6g wrote:
 On 05/17/2016 03:14 PM, Alex wrote:
 For a slice I surely need two numbers. But this should all be, 
 what I
 need for a slice. For a iota, I need a maximum, which is not 
 provided
 (at least at this moment) to the object containing the 
 pointer/iota thing.
The slice's length is practically the same as iota's maximum. For slicing a pointer you need the minimum and the maximum, just as with iota. I don't see the difference. ptr[5 .. 10] vs iota(5, 10) - Surely you need the number 10 in both cases?
Ok cool, maybe I oversee something myself. But let think in an example: There are some objects which make slices. How they make a slice is unimportant here, so it makes either ptr[5 .. 10] or iota(5, 10). But, if the slicing is made by means of iota, there is no (at least no explicit) dependence between the slices, which could be made by different objects. I'm ready to admit, that the process will work with independent slicing... In this case, I can omit my void* at all. So, the objects, which make slices, don't do this from some object, they do this just by calling iota. But this is little bit contra intuitive, as I imply a relationship between the sliced parts. So... at the end of the day this implication exists in my head only...
May 17 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 05/17/2016 05:33 PM, Alex wrote:
 But, if the slicing is made by means of iota, there is no (at least no
 explicit) dependence between the slices, which could be made by
 different objects.
How is this dependency expressed with slices?
 I'm ready to admit, that the process will work with independent
 slicing... In this case, I can omit my void* at all. So, the objects,
 which make slices, don't do this from some object, they do this just by
 calling iota. But this is little bit contra intuitive, as I imply a
 relationship between the sliced parts.
I'm not sure if I understand. Is the object the void pointer of the slice? If so, you start the slicing from a null pointer, right? There is no real relationship or dependency between the slices then. Or is the object some class/struct instance that creates a slice? If so, how does it leave a reference to itself in the slice?
 So... at the end of the day this implication exists in my head only...
May 17 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Tuesday, 17 May 2016 at 17:25:48 UTC, ag0aep6g wrote:
 On 05/17/2016 05:33 PM, Alex wrote:
 But, if the slicing is made by means of iota, there is no (at 
 least no
 explicit) dependence between the slices, which could be made by
 different objects.
How is this dependency expressed with slices?
By using the single source of slicing, which is the void* or a pre-instantiated iota with the maximum number.
 I'm ready to admit, that the process will work with independent
 slicing... In this case, I can omit my void* at all. So, the 
 objects,
 which make slices, don't do this from some object, they do 
 this just by
 calling iota. But this is little bit contra intuitive, as I 
 imply a
 relationship between the sliced parts.
I'm not sure if I understand. Is the object the void pointer of the slice? If so, you start the slicing from a null pointer, right? There is no real relationship or dependency between the slices then. Or is the object some class/struct instance that creates a slice? If so, how does it leave a reference to itself in the slice?
Here, I'm not sure if I understand the question. The relation is: some object A contains the pointer/iota/(if at all) some object B makes slices of the thing, which is in A.
May 17 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 05/17/2016 07:43 PM, Alex wrote:
 The relation is: some object A contains the pointer/iota/(if at all)
 some object B makes slices of the thing, which is in A.
Ok, so you have some object that stores a void pointer. The pointer is going to be null at all times. Then you slice that pointer. Is that right? In code: ---- class C { void* ptr = null; /* always going to stay null */ void[] getSlice(size_t a, size_t b) { return ptr[a .. b]; } } void main() { auto c = new C; void[] slice1 = c.getSlice(5, 10); void[] slice2 = c.getSlice(7, 21); } ---- Now you see a relation/dependency between slice1 and slice2, because the pointer they slice is the same, and it's stored in the same C object, right? But when slicing a pointer what matters is the value of the pointer, not where it resides. Where the pointer is stored is completely irrelevant. Like when adding two ints it doesn't matter where they came from; only their values matter. Calling getSlice(5, 10) on two different C objects will return the exactly same slice (as long as ptr stays null): ---- /* ... class C as above ... */ void main() { auto c1 = new C; auto c2 = new C; assert(c1 !is c2); /* not the same object */ assert(c1.getSlice(5, 10) is c2.getSlice(5, 10)); /* but the exact same slice */ } ---- There is no relationship between the slices or between a slice and the object that created it. You can have a free function that returns the exact same slices again: ---- /* ... class C as above */ void[] freeGetSlice(size_t a, size_t b) { void* ptr = null; return ptr[a .. b]; } void main() { auto c = new C; assert(c.getSlice(5, 10) is freeGetSlice(5, 10)); } ---- A note on iota: If you use iota instead, you don't need to store the result in the object either. You can call iota on the spot just like you call getSlice.
May 17 2016
parent Alex <sascha.orlov gmail.com> writes:
On Tuesday, 17 May 2016 at 18:25:46 UTC, ag0aep6g wrote:
 On 05/17/2016 07:43 PM, Alex wrote:
 The relation is: some object A contains the pointer/iota/(if 
 at all)
 some object B makes slices of the thing, which is in A.
Ok, so you have some object that stores a void pointer. The pointer is going to be null at all times. Then you slice that pointer. Is that right?
Yes.
 In code:
 ----
 class C
 {
     void* ptr = null; /* always going to stay null */
     void[] getSlice(size_t a, size_t b) { return ptr[a .. b]; }
 }

 void main()
 {
     auto c = new C;
     void[] slice1 = c.getSlice(5, 10);
     void[] slice2 = c.getSlice(7, 21);
 }
 ----

 Now you see a relation/dependency between slice1 and slice2, 
 because the pointer they slice is the same, and it's stored in 
 the same C object, right?
Yes.
 But when slicing a pointer what matters is the value of the 
 pointer, not where it resides. Where the pointer is stored is 
 completely irrelevant. Like when adding two ints it doesn't 
 matter where they came from; only their values matter.

 Calling getSlice(5, 10) on two different C objects will return 
 the exactly same slice (as long as ptr stays null):
Yes. This is the point where my error in reasoning resides...
 ----
 /* ... class C as above ... */

 void main()
 {
     auto c1 = new C;
     auto c2 = new C;
     assert(c1 !is c2); /* not the same object */
     assert(c1.getSlice(5, 10) is c2.getSlice(5, 10)); /* but 
 the exact same slice */
 }
 ----

 There is no relationship between the slices or between a slice 
 and the object that created it. You can have a free function 
 that returns the exact same slices again:

 ----
 /* ... class C as above */

 void[] freeGetSlice(size_t a, size_t b)
 {
     void* ptr = null;
     return ptr[a .. b];
 }

 void main()
 {
     auto c = new C;
     assert(c.getSlice(5, 10) is freeGetSlice(5, 10));
 }
 ----
Yeah... now I see this...
 A note on iota: If you use iota instead, you don't need to 
 store the result in the object either. You can call iota on the 
 spot just like you call getSlice.
Thanks for disillusioning :)
May 17 2016
prev sibling parent ag0aep6g <anonymous example.com> writes:
On 05/17/2016 10:16 AM, Rene Zwanenburg wrote:
 Additionally, some people recommend never using -release. It depends on
 that type of program you're writing, but the performance gain is often
 not worth the loss in safety. Think of the number of exploits enabled by
 C's lack of bounds checking.
Some more details on this: -release doesn't affect bounds checking in safe code. It will still be done there. There is another switch that disables bounds checks even in safe code: -boundscheck=off
May 17 2016
prev sibling parent reply Alex <sascha.orlov gmail.com> writes:
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
parent reply ag0aep6g <anonymous example.com> writes:
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 16 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Monday, 16 May 2016 at 22:28:04 UTC, ag0aep6g wrote:
 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?
Maybe. I should test this...
 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.
:) The point is, that in my model the slice has a meaning itself. So, the language provides one of a needed constructs...
May 16 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 05/17/2016 12:43 AM, Alex wrote:
 The point is, that in my model the slice has a meaning itself. So, the
 language provides one of a needed constructs...
Huh? As far as I understand, the pointer of the slice is invalid, and you never dereference it. What kind of additional meaning can the slice carry then? It's practically just a struct of two `size_t`s.
May 16 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Monday, 16 May 2016 at 22:54:31 UTC, ag0aep6g wrote:
 On 05/17/2016 12:43 AM, Alex wrote:
 The point is, that in my model the slice has a meaning itself. 
 So, the
 language provides one of a needed constructs...
Huh? As far as I understand, the pointer of the slice is invalid, and you never dereference it. What kind of additional meaning can the slice carry then? It's practically just a struct of two `size_t`s.
the elements of the slice are accessible just for reading, right, but with them I reference the data in other objects.
May 16 2016
parent ag0aep6g <anonymous example.com> writes:
On 05/17/2016 08:53 AM, Alex wrote:
 the elements of the slice are accessible just for reading, right, but
 with them I reference the data in other objects.
If the slice's pointer is invalid, then its elements are not accessible at all.
May 17 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
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
parent reply Alex <sascha.orlov gmail.com> writes:
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
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
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
parent Alex <sascha.orlov gmail.com> writes:
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 16 2016