www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - getNext

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
I think I figured out a comfortable and all-encompassing means to define 
a simplified interface for an input range.

Currently input ranges need to define empty, front, and popFront. That 
works but it's a bit heavy for simple input ranges. We've been 
discussing simplified interfaces in this group but couldn't find one 
that satisfied all use cases.

Consider this:

T* getNext(R, T)(ref R range, ref T item);

Semantics: if the range wants to expose addresses of its elements, it 
returns a pointer to the current element and also advances to the next 
element. Otherwise (i.e. the range does not have or does not want to 
expose addresses of its elements), the range fills "item" with the 
current value, again moves on to the next value, and returns &item.

In all cases, when there are no more elements in the range, getNext 
returns null.

getNext is easy to define for e.g. arrays and files. How does it sound? 
Does it bring significant simplification?


Andrei
Jul 12 2010
next sibling parent reply Jonathan M Davis <jmdavisprog gmail.com> writes:
On Monday 12 July 2010 20:48:05 Andrei Alexandrescu wrote:
 I think I figured out a comfortable and all-encompassing means to define
 a simplified interface for an input range.
 
 Currently input ranges need to define empty, front, and popFront. That
 works but it's a bit heavy for simple input ranges. We've been
 discussing simplified interfaces in this group but couldn't find one
 that satisfied all use cases.
 
 Consider this:
 
 T* getNext(R, T)(ref R range, ref T item);
 
 Semantics: if the range wants to expose addresses of its elements, it
 returns a pointer to the current element and also advances to the next
 element. Otherwise (i.e. the range does not have or does not want to
 expose addresses of its elements), the range fills "item" with the
 current value, again moves on to the next value, and returns &item.
 
 In all cases, when there are no more elements in the range, getNext
 returns null.
 
 getNext is easy to define for e.g. arrays and files. How does it sound?
 Does it bring significant simplification?
 
 
 Andrei

What happens to empty, front, and popFront then? Is this a case where something must define either empty, front, and popFront or getNext to be an input range? Or is this something else? Personally, I find empty, front, and popFront quite useful and simple for anything that I've done, and I'd find getNext to be a lot more verbose. getNext may be great if you're using empty, front, and popFront pretty much simultaneously, but if you don't want to use all of them for whatever you're doing, then getNext is overkill. So, essentially, I suppose the issue is that I don't see what you intend to do to front, popFront, and empty if you add getNext into the mix. I do not want to see front, popFront, or empty go away. Having getNext as an additional function to make it easier to iterate over a range and do something with each element as you iterate wouldn't hurt my feelings any, but I definitely don't want to lose popFront, empty, or front. As for simplification, it strikes me as more complicated in every case except where you are iterating over a range and processing each element as you iterate. Granted, that's a common use case, but there are plenty of other cases, where if you were forced to use getNext instead of having popFront, empty, and front, that would be a major problem. - Jonathan M Davis
Jul 12 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 07/12/2010 11:21 PM, Jonathan M Davis wrote:
 On Monday 12 July 2010 20:48:05 Andrei Alexandrescu wrote:
 I think I figured out a comfortable and all-encompassing means to define
 a simplified interface for an input range.

 Currently input ranges need to define empty, front, and popFront. That
 works but it's a bit heavy for simple input ranges. We've been
 discussing simplified interfaces in this group but couldn't find one
 that satisfied all use cases.

 Consider this:

 T* getNext(R, T)(ref R range, ref T item);

 Semantics: if the range wants to expose addresses of its elements, it
 returns a pointer to the current element and also advances to the next
 element. Otherwise (i.e. the range does not have or does not want to
 expose addresses of its elements), the range fills "item" with the
 current value, again moves on to the next value, and returns&item.

 In all cases, when there are no more elements in the range, getNext
 returns null.

 getNext is easy to define for e.g. arrays and files. How does it sound?
 Does it bring significant simplification?


 Andrei

What happens to empty, front, and popFront then? Is this a case where something must define either empty, front, and popFront or getNext to be an input range? Or is this something else? Personally, I find empty, front, and popFront quite useful and simple for anything that I've done, and I'd find getNext to be a lot more verbose. getNext may be great if you're using empty, front, and popFront pretty much simultaneously, but if you don't want to use all of them for whatever you're doing, then getNext is overkill.

An input range could either define the troika empty/front/popFront or getNext. In the former case, getNext detects the presence of the troika and uses it transparently. That's great because client code can simply use getNext throughout.
 So, essentially, I suppose the issue is that I don't see what you intend to do
 to front, popFront, and empty if you add getNext into the mix.

There is no aggravation brought to the current definitions.
 I do not want to
 see front, popFront, or empty go away. Having getNext as an additional function
 to make it easier to iterate over a range and do something with each element as
 you iterate wouldn't hurt my feelings any, but I definitely don't want to lose
 popFront, empty, or front.

My feelings too. The troika is here to stay, and definitely necessary for any range richer than an input range.
 As for simplification, it strikes me as more complicated in every case except
 where you are iterating over a range and processing each element as you
iterate.
 Granted, that's a common use case, but there are plenty of other cases, where
if
 you were forced to use getNext instead of having popFront, empty, and front,
 that would be a major problem.

Yah, truth be told getNext won't win a prize for brevity. You need to define both a variable and a pointer to use it: T meh; T * neh; while ((neh = getNext(r, meh))) { ... process *neh ... } I've just had an idea that is so dark and devious, I was almost afraid to try it. But it works like a charm. Consider: T * getNext(R, E)(ref R range, ref E store = *(cast(E*) alloca(E.sizeof)) { ... } With this, allocating a dummy buffer on caller's stack is automated, so client code can just write: for (T * p; (p = getNext(r)); ) { ... process *p ... } I feel dirty. Andrei
Jul 12 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 T * getNext(R, E)(ref R range,
                    ref E store = *(cast(E*) alloca(E.sizeof))
 {

Time ago I have filed bug http://d.puremagic.com/issues/show_bug.cgi?id=3822 on alloca(), but I think this code is not hit by it. I have recently written some C99 code and I have appreciated its Variable Length Arrays both in syntax, safety and performance gain. Compared to alloca() the VLAs have some advantages: - Their syntax is shorter and nicer, and it's natural for a C programmer; - no imports needed; - the semantics is more clear, because they define a new variable, so the size of their scope is the same as the in all other variables, while alloca() seems to have two possible different implementations; - VLAs are more typesafe, there is no need to use a cast. While the cast needed by alloca() may forbid it in SafeD code. - VLAs don't need sizeof(T), you just specify a type. The result is that the usage of alloca() feels dirty in both C and D, but Variable Length Arrays (VLA) of C99 don't feel dirty at all. On the other hand VLAs (and alloca) can produce a stack overflow, they are not so commonly useful (as alloca), and they can become essentially a third kind of arrays for D (this is not good). In D I'd like something like alloca() that needs no casts and is able to find the size by itself, avoiding the bug prone usage of T.sizeof. A way to do it is to use the same syntax used by C99 and allow a variable in the definition of a stack array: auto foo(int n) { int[n] arr; return arr; } The main difference is that in D when you return arr it gets copied by value. Currently this code works: int foo(int n) { return 3 * n + 1; } auto bar() { immutable int n = 5; int[foo(n)] arr; return arr; } void main() {} because dmd runs foo() at compile time, so arr is allocated on the stack with a statically known size. If VLAs get introduced in D, then in this case the compiler has to do what it currently it doesn't do: to run a function at compile-time if possible (and create a fixed length array) and run it at runtime if that's impossible (and create a VLA). To avoid that in some cases you can use something like: int[StaticValue!(n)] arr; Where StaticValue is a template that makes sure n is a value always known at compile-time. But this is a little messy, and I don't like it too much. Keep in mind that currently this gives an error: int[] bar() { int[2] arr; return arr; } void main() {} You have to use the auto return type or: int[2] bar() { int[2] arr; return arr; } void main() {} With VLAs you are forced to use auto, but it can't work anyway at the return point. So I think the normal C99 syntax for VLAs is not good for D2. On the other hand alloca() semantics and syntax are bad. So D alloca() can be replaced by something better like: T* ptr = StackAlloc!T(n); Or: T* ptr = Alloca!T(n); Or: T[] arr = VLA!T(n); But this created an array that looks like a dynamic array, but its memory is on the stack so it must not escape the function. So it can be a bug-prone, similar to this that currently compiles: int[] foo() { int[1] stackArray; int[] dynArray = stackArray[0 .. 1]; return dynArray; } void main() {} See enhancement request http://d.puremagic.com/issues/show_bug.cgi?id=4451 So with the syntax T[] arr=VLA!T(n); the compiler has to disallow the return of arr and its slices. Whith those three syntaxes your signature becomes: T* getNext(R, E)(ref R range, ref E store = *StackAlloc!E(1)) { T* getNext(R, E)(ref R range, ref E store = *Alloca!E(1)) { T* getNext(R, E)(ref R range, ref E store = *(VLA!E(1).ptr)) { Bye, bearophile
Jul 13 2010
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-07-13 00:38:55 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 Yah, truth be told getNext won't win a prize for brevity. You need to 
 define both a variable and a pointer to use it:
 
 T meh;
 T * neh;
 while ((neh = getNext(r, meh))) {
     ... process *neh ...
 }

At this point what you want is to use a foreach loop. In fact, if foreach could be made to work with getNext (and it should), you'd rarely need to write that boilerplate code yourself. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jul 13 2010
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 07/13/2010 05:09 AM, Shin Fujishiro wrote:
 Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>  wrote:
 I've just had an idea that is so dark and devious, I was almost afraid
 to try it. But it works like a charm. Consider:

 T * getNext(R, E)(ref R range,
                     ref E store = *(cast(E*) alloca(E.sizeof))
 {
       ...
 }

 With this, allocating a dummy buffer on caller's stack is automated, so
 client code can just write:

 for (T * p; (p = getNext(r)); )  {
      ... process *p ...
 }

 I feel dirty.

How about a TLS variable? template temporary(T) { static T temporary; } E* getNext(R, E)(ref R range, ref E store = temporary!E);

There's the classic problem of reusing the same temporary. Consider: Range r1, r2; ElementType!Range * p1, p2; while ((p1 = getNext(r1)) && (p2 = getNext(r2))) { ... oops ... } You need one temporary for each static occurrence of getNext. Andrei
Jul 13 2010
prev sibling parent FeepingCreature <default_357-line yahoo.de> writes:
On 13.07.2010 06:38, Andrei Alexandrescu wrote:
 Yah, truth be told getNext won't win a prize for brevity. You need to
 define both a variable and a pointer to use it:
 
 T meh;
 T * neh;
 while ((neh = getNext(r, meh))) {
    ... process *neh ...
 }
 

One way to make this slightly easier would be allowing auto in loop bodies, same as it works in if - ie. T meh; while (auto neh = getNext(r, meh)) { }
Jul 13 2010
prev sibling next sibling parent Jesse Phillips <jessekphillips+D gmail.com> writes:
Andrei Alexandrescu Wrote:

 getNext is easy to define for e.g. arrays and files. How does it sound? 
 Does it bring significant simplification?
 
 
 Andrei

I'm with Jonathan on this. I don't really see much of a benefit. popFront, empty, front are very easy to define and simple to use. Java uses getNext for its iterators. Though it calls it 'next' and throws an exception when trying to call without any elements. This leads it to also provide a hasNext function.
Jul 12 2010
prev sibling next sibling parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 07/12/2010 10:48 PM, Andrei Alexandrescu wrote:
 I think I figured out a comfortable and all-encompassing means to define
 a simplified interface for an input range.

 Currently input ranges need to define empty, front, and popFront. That
 works but it's a bit heavy for simple input ranges. We've been
 discussing simplified interfaces in this group but couldn't find one
 that satisfied all use cases.

 Consider this:

 T* getNext(R, T)(ref R range, ref T item);

 Semantics: if the range wants to expose addresses of its elements, it
 returns a pointer to the current element and also advances to the next
 element. Otherwise (i.e. the range does not have or does not want to
 expose addresses of its elements), the range fills "item" with the
 current value, again moves on to the next value, and returns &item.

 In all cases, when there are no more elements in the range, getNext
 returns null.

let's see here Range AhmAStream; ubyte[] buf = new ubyte[4]; ubyte[]* ruf = AhmAStream.getNext(buf); assert(ruf && ruf.length == 4); int i = * (cast(int*) ruf.ptr) buf = new ubyte[i]; ruf = AhmAStream.getNext(buf); assert(ruf && ruf.length == i); Something like this could work within this interface, couldn't it? Think you might be on to something
 getNext is easy to define for e.g. arrays and files. How does it sound?
 Does it bring significant simplification?


 Andrei

Jul 12 2010
prev sibling next sibling parent "Rory McGuire" <rmcguire neonova.co.za> writes:
On Tue, 13 Jul 2010 06:38:55 +0200, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 07/12/2010 11:21 PM, Jonathan M Davis wrote:
 On Monday 12 July 2010 20:48:05 Andrei Alexandrescu wrote:
 I think I figured out a comfortable and all-encompassing means to  
 define
 a simplified interface for an input range.

 Currently input ranges need to define empty, front, and popFront. That
 works but it's a bit heavy for simple input ranges. We've been
 discussing simplified interfaces in this group but couldn't find one
 that satisfied all use cases.

 Consider this:

 T* getNext(R, T)(ref R range, ref T item);

 Semantics: if the range wants to expose addresses of its elements, it
 returns a pointer to the current element and also advances to the next
 element. Otherwise (i.e. the range does not have or does not want to
 expose addresses of its elements), the range fills "item" with the
 current value, again moves on to the next value, and returns&item.

 In all cases, when there are no more elements in the range, getNext
 returns null.

 getNext is easy to define for e.g. arrays and files. How does it sound?
 Does it bring significant simplification?


 Andrei

What happens to empty, front, and popFront then? Is this a case where something must define either empty, front, and popFront or getNext to be an input range? Or is this something else? Personally, I find empty, front, and popFront quite useful and simple for anything that I've done, and I'd find getNext to be a lot more verbose. getNext may be great if you're using empty, front, and popFront pretty much simultaneously, but if you don't want to use all of them for whatever you're doing, then getNext is overkill.

An input range could either define the troika empty/front/popFront or getNext. In the former case, getNext detects the presence of the troika and uses it transparently. That's great because client code can simply use getNext throughout.
 So, essentially, I suppose the issue is that I don't see what you  
 intend to do
 to front, popFront, and empty if you add getNext into the mix.

There is no aggravation brought to the current definitions.
 I do not want to
 see front, popFront, or empty go away. Having getNext as an additional  
 function
 to make it easier to iterate over a range and do something with each  
 element as
 you iterate wouldn't hurt my feelings any, but I definitely don't want  
 to lose
 popFront, empty, or front.

My feelings too. The troika is here to stay, and definitely necessary for any range richer than an input range.
 As for simplification, it strikes me as more complicated in every case  
 except
 where you are iterating over a range and processing each element as you  
 iterate.
 Granted, that's a common use case, but there are plenty of other cases,  
 where if
 you were forced to use getNext instead of having popFront, empty, and  
 front,
 that would be a major problem.

Yah, truth be told getNext won't win a prize for brevity. You need to define both a variable and a pointer to use it: T meh; T * neh; while ((neh = getNext(r, meh))) { ... process *neh ... } I've just had an idea that is so dark and devious, I was almost afraid to try it. But it works like a charm. Consider: T * getNext(R, E)(ref R range, ref E store = *(cast(E*) alloca(E.sizeof)) { ... } With this, allocating a dummy buffer on caller's stack is automated, so client code can just write: for (T * p; (p = getNext(r)); ) { ... process *p ... } I feel dirty. Andrei

:) I like it. But then looking at the alloca man page... yikes
Jul 12 2010
prev sibling next sibling parent Shin Fujishiro <rsinfu gmail.com> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 I've just had an idea that is so dark and devious, I was almost afraid 
 to try it. But it works like a charm. Consider:
 
 T * getNext(R, E)(ref R range,
                    ref E store = *(cast(E*) alloca(E.sizeof))
 {
      ...
 }
 
 With this, allocating a dummy buffer on caller's stack is automated, so 
 client code can just write:
 
 for (T * p; (p = getNext(r)); )  {
     ... process *p ...
 }
 
 I feel dirty.

How about a TLS variable? template temporary(T) { static T temporary; } E* getNext(R, E)(ref R range, ref E store = temporary!E); Shin
Jul 13 2010
prev sibling next sibling parent Shin Fujishiro <rsinfu gmail.com> writes:
Shin Fujishiro <rsinfu gmail.com> wrote:
 How about a TLS variable?
 
 template temporary(T)
 {
     static T temporary;
 }
 E* getNext(R, E)(ref R range, ref E store = temporary!E);

Yeah, I just missed it. TLS is not usable. I had spoken carelessly... Shin
Jul 13 2010
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 12 Jul 2010 23:48:05 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 I think I figured out a comfortable and all-encompassing means to define  
 a simplified interface for an input range.

 Currently input ranges need to define empty, front, and popFront. That  
 works but it's a bit heavy for simple input ranges. We've been  
 discussing simplified interfaces in this group but couldn't find one  
 that satisfied all use cases.

 Consider this:

 T* getNext(R, T)(ref R range, ref T item);

 Semantics: if the range wants to expose addresses of its elements, it  
 returns a pointer to the current element and also advances to the next  
 element. Otherwise (i.e. the range does not have or does not want to  
 expose addresses of its elements), the range fills "item" with the  
 current value, again moves on to the next value, and returns &item.

 In all cases, when there are no more elements in the range, getNext  
 returns null.

 getNext is easy to define for e.g. arrays and files. How does it sound?  
 Does it bring significant simplification?

Yes, yes, yes! A question though -- whenever a pointer occurs, we always cringe, especially in safeD. will getNext be unsafe? BTW, I like the alloca thingy, that's really cool. One thing I just thought of, getNext should be split into two functions, the one you have, and: ElementType!R *getNext(R)(ref R range) To avoid having to supply the item or use alloca when the range is going to give you back a pointer to its internals anyways (tested with a template constraint). -Steve
Jul 13 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 07/13/2010 07:39 AM, Steven Schveighoffer wrote:
 On Mon, 12 Jul 2010 23:48:05 -0400, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 I think I figured out a comfortable and all-encompassing means to
 define a simplified interface for an input range.

 Currently input ranges need to define empty, front, and popFront. That
 works but it's a bit heavy for simple input ranges. We've been
 discussing simplified interfaces in this group but couldn't find one
 that satisfied all use cases.

 Consider this:

 T* getNext(R, T)(ref R range, ref T item);

 Semantics: if the range wants to expose addresses of its elements, it
 returns a pointer to the current element and also advances to the next
 element. Otherwise (i.e. the range does not have or does not want to
 expose addresses of its elements), the range fills "item" with the
 current value, again moves on to the next value, and returns &item.

 In all cases, when there are no more elements in the range, getNext
 returns null.

 getNext is easy to define for e.g. arrays and files. How does it
 sound? Does it bring significant simplification?

Yes, yes, yes! A question though -- whenever a pointer occurs, we always cringe, especially in safeD. will getNext be unsafe?

I need to discuss this with Walter, he mentioned that it wouldn't be difficult to allow certain uses of pointers in SafeD.
 BTW, I like the alloca thingy, that's really cool.

 One thing I just thought of, getNext should be split into two functions,
 the one you have, and:

 ElementType!R *getNext(R)(ref R range)

 To avoid having to supply the item or use alloca when the range is going
 to give you back a pointer to its internals anyways (tested with a
 template constraint).

Yup, good point. Andrei
Jul 13 2010
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-07-12 23:48:05 -0400, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 T* getNext(R, T)(ref R range, ref T item);
 
 Semantics: if the range wants to expose addresses of its elements, it 
 returns a pointer to the current element and also advances to the next 
 element. Otherwise (i.e. the range does not have or does not want to 
 expose addresses of its elements), the range fills "item" with the 
 current value, again moves on to the next value, and returns &item.
 
 In all cases, when there are no more elements in the range, getNext 
 returns null.

This can't be safe. getNext would need to take a pointer out of the item reference, which isn't allowed in SafeD. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jul 13 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 13 Jul 2010 08:54:07 -0400, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2010-07-13 00:38:55 -0400, Andrei Alexandrescu  
 <SeeWebsiteForEmail erdani.org> said:

 Yah, truth be told getNext won't win a prize for brevity. You need to  
 define both a variable and a pointer to use it:
  T meh;
 T * neh;
 while ((neh = getNext(r, meh))) {
     ... process *neh ...
 }

At this point what you want is to use a foreach loop. In fact, if foreach could be made to work with getNext (and it should), you'd rarely need to write that boilerplate code yourself.

struct InputForeach(R) if(isInputRangeThatUsesGetNext!R) { private R* range; this(ref R range) {this.range = &range;} int opApply(scope int delegate(ref ElementType!R) dg) { ElementType!R buf; ElementType!R *e; int result = 0; while(!result && (e = getNext(*range, buf))) { result = dg(*e); } return result; } } InputForeach!R inputForeach(R)(ref R r) if(isInputRangeThatUsesGetNext!R) { return InputForeach!R(r); } foreach(e; inputForeach(r)) { ... } opApply to the rescue :) Of course, native support would be better, unless the compiler decides to start inlining opApply. -Steve
Jul 13 2010
prev sibling next sibling parent Shin Fujishiro <rsinfu gmail.com> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 There's the classic problem of reusing the same temporary. Consider:
 
 Range r1, r2;
 ElementType!Range * p1, p2;
 while ((p1 = getNext(r1)) && (p2 = getNext(r2)))
 {
     ... oops ...
 }
 
 You need one temporary for each static occurrence of getNext.

To my shame, I missed it! Anyways, I like getNext(). LockingTextReader definitely needs it. Shin
Jul 13 2010
prev sibling next sibling parent Shin Fujishiro <rsinfu gmail.com> writes:
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:
 I think I figured out a comfortable and all-encompassing means to define 
 a simplified interface for an input range.
 
 Currently input ranges need to define empty, front, and popFront. That 
 works but it's a bit heavy for simple input ranges. We've been 
 discussing simplified interfaces in this group but couldn't find one 
 that satisfied all use cases.
 
 Consider this:
 
 T* getNext(R, T)(ref R range, ref T item);
 
 Semantics: if the range wants to expose addresses of its elements, it 
 returns a pointer to the current element and also advances to the next 
 element. Otherwise (i.e. the range does not have or does not want to 
 expose addresses of its elements), the range fills "item" with the 
 current value, again moves on to the next value, and returns &item.
 
 In all cases, when there are no more elements in the range, getNext 
 returns null.
 
 getNext is easy to define for e.g. arrays and files. How does it sound? 
 Does it bring significant simplification?

I gave it a try, and it fairly simplified range implementation. http://gist.github.com/474562 I think it's good. (1) But how does it represent an infinite range? (2) Should user code use getNext for input ranges (like put for output ranges)? For example: void doSomething(R)(R input) { // read first character if any dchar* p = getNext!dchar(input); if (p == null) return; dchar a = *p; // read subsequent characters... dchar b = *enforce( getNext!dchar(input) ); ... } Shin
Jul 14 2010
prev sibling parent =?iso-8859-2?B?VG9tZWsgU293afFza2k=?= <just ask.me> writes:
Dnia 13-07-2010 o 06:38:55 Andrei Alexandrescu  =

<SeeWebsiteForEmail erdani.org> napisa=B3(a):

 I've just had an idea that is so dark and devious, I was almost afraid=

 to try it. But it works like a charm. Consider:
  T * getNext(R, E)(ref R range,
                   ref E store =3D *(cast(E*) alloca(E.sizeof))
 {
     ...
 }
  With this, allocating a dummy buffer on caller's stack is automated, =

 client code can just write:
  for (T * p; (p =3D getNext(r)); )  {
    ... process *p ...
 }
  I feel dirty.

What's wrong with foreach(e; r) that you want to play dirty? The compile= r = is here to help. Tomek
Jul 23 2010