Re: Returning an empty range of a given type

2015-05-17 Thread Idan Arye via Digitalmars-d-learn

On Friday, 15 May 2015 at 03:47:46 UTC, rcorre wrote:

On Friday, 15 May 2015 at 03:22:43 UTC, rcorre wrote:

On Thursday, 14 May 2015 at 14:57:26 UTC, Idan Arye wrote:


How about a more flexible solution?

http://dpaste.dzfl.pl/2f99cc270651


Neat, thanks!



The range I don't pick may be an expression that would fail, so 
I tweaked it to:

SelectRange!T selectRange(T...)(size_t index, lazy T ranges)

Other than that, it seems to be just what I needed. Thanks 
again!


Keep in mind that lazy arguments are actually delegates, which 
means they need the GC. If using the GC doesn't bother you you 
can use std.range.interfaces to wrap things up in an object: 
http://dlang.org/phobos/std_range_interfaces.html#InputRange


Re: Returning an empty range of a given type

2015-05-15 Thread Steven Schveighoffer via Digitalmars-d-learn

On 5/14/15 11:22 PM, rcorre wrote:

On Thursday, 14 May 2015 at 18:44:58 UTC, Steven Schveighoffer wrote:


It depends on the guts of MyContainer.Range.

I'm assuming MyContainer.Range has SOME sort of references (i.e.
pointers) to the data in the container, so why not just have:

bool empty() { return someRef == null || yourCurrentTest; }



In this case, I want to return an empty range when the container
instance itself is null. I could have a static method
MyContainer.emptySlice, but I feel like I've seen this general situation
crop up a lot with small variations.


I'd have to see the code, but it seems like your situation is different 
from what I think, or you are not understanding what I'm saying :)


As an example:

struct MyContainer
{
  private int[] data;
  struct Range
  {
 private int *curData;
 private int *endOfData;
 int front() { return *curData; }
 bool empty() { return curData == endOfData; }
 void popFront() { ++curData; }
  }

  Range opSlice() {return Range(data.ptr, data.ptr + data.length);}
}

Range.init would be a valid empty range in this case. But I have no idea 
what your situation is. That's why I said it depends on the guts of the 
Range.


-Steve


Re: Returning an empty range of a given type

2015-05-14 Thread rcorre via Digitalmars-d-learn

So I thought this might work:

struct MaybeEmpty(R) if (isInputRange!R) {
  private bool _isEmpty;
  private R_input;

  alias _input this;

  this(bool isEmpty, R input) {
_input = input;
_isEmpty = isEmpty;
  }

  @property bool empty() {
return _isEmpty || _input.empty;
  }
}

auto maybeEmpty(R)(bool empty, R input = R.init) if 
(isInputRange!R) {

  return MaybeEmpty!R(empty, input);
}

It's kind of ugly, but it can be used like:

  auto a = maybeEmpty!MyRange(true);
  auto b = maybeEmpty!MyRange(false, actualRange);
  static assert(is(typeof(a) == typeof(b)));

However, it fails the input range test:

static assert(isInputRange!MyRange); //pass
static assert(isInputRange!(typeof(a))); // fail

But it seems to be something weird with cross-module template 
instantiation. If I replace `import std.range` with a copy-paste 
of `isInputRange`, the above passes.


Either that or I'm doing something stupid because I'vebeen 
staring at this too long.


I'm wondering if the isInputRange thing is a bug, so here's a 
gist if anyone wants to play with it:

https://gist.github.com/rcorre/7a62395c53baf3c0bfbc


Re: Returning an empty range of a given type

2015-05-14 Thread Steven Schveighoffer via Digitalmars-d-learn

On 5/13/15 10:58 PM, rcorre wrote:

Actually, this doesn't even seem to work with a custom range:

import std.range;
import std.stdio;
import std.algorithm;

 struct MyContainer {
   @nogc auto opSlice() {
 struct Range {
   @property bool empty() { return true; }
   @property int front() { return 9; }
   void popFront() { }
 }

 return Range();
   }
 }

 /// Return a slice of aa[key], or an empty slice if not found
 @nogc auto maybeGetRange(MyContainer[string] aa, string key) {
   alias RangeType = typeof(MyContainer.init[]);
   auto val = key in aa;
   return (val is null) ? takeNone!RangeType :
(*val)[].take(size_t.max);
 }

Is there any way to create an empty MyContainer.Range() without creating
a new container?


It depends on the guts of MyContainer.Range.

I'm assuming MyContainer.Range has SOME sort of references (i.e. 
pointers) to the data in the container, so why not just have:


bool empty() { return someRef == null || yourCurrentTest; }

-Steve


Re: Returning an empty range of a given type

2015-05-14 Thread Idan Arye via Digitalmars-d-learn

On Thursday, 14 May 2015 at 12:40:57 UTC, rcorre wrote:

So I thought this might work:

struct MaybeEmpty(R) if (isInputRange!R) {
  private bool _isEmpty;
  private R_input;

  alias _input this;

  this(bool isEmpty, R input) {
_input = input;
_isEmpty = isEmpty;
  }

  @property bool empty() {
return _isEmpty || _input.empty;
  }
}

auto maybeEmpty(R)(bool empty, R input = R.init) if 
(isInputRange!R) {

  return MaybeEmpty!R(empty, input);
}

It's kind of ugly, but it can be used like:

  auto a = maybeEmpty!MyRange(true);
  auto b = maybeEmpty!MyRange(false, actualRange);
  static assert(is(typeof(a) == typeof(b)));

However, it fails the input range test:

static assert(isInputRange!MyRange); //pass
static assert(isInputRange!(typeof(a))); // fail

But it seems to be something weird with cross-module template 
instantiation. If I replace `import std.range` with a 
copy-paste of `isInputRange`, the above passes.


Either that or I'm doing something stupid because I'vebeen 
staring at this too long.


I'm wondering if the isInputRange thing is a bug, so here's a 
gist if anyone wants to play with it:

https://gist.github.com/rcorre/7a62395c53baf3c0bfbc


How about a more flexible solution?

http://dpaste.dzfl.pl/2f99cc270651


Re: Returning an empty range of a given type

2015-05-14 Thread rcorre via Digitalmars-d-learn

On Thursday, 14 May 2015 at 06:41:45 UTC, Ali Çehreli wrote:


I am lucky because although the returned type is opaque to me, 
I know that it is constructed by a void lambda.


Yeah, in this case I control the container so I may just add an 
emptySlice property, but it does seem like it might be a common 
need (to return an empty range of a given type without having 
that range constructed beforehand).


Re: Returning an empty range of a given type

2015-05-14 Thread Ali Çehreli via Digitalmars-d-learn

On 05/13/2015 07:47 PM, rcorre wrote:

I've run into this situation a lot:
I have a function that returns a range (in this case, a slice of a
custom container).
In some cases, the function needs to return an empty range.

It sounded like takeNone was what I wanted:

@nogc auto fun() {
return (some_condition) ? getRange() : getRange.takeNone;
}

but there is a return type ambiguity. I finally ended up doing this:

@nogc auto fun() {
return (some_condition) ? getRange().take(size_t.max) :
getRange.takeNone;
}

I'm not sure if this is clever or insane.
It works, but just looks a bit crazy to me.
Does anyone else run into this situation? Have any cool ways to solve it?
MyRange is an inputRange, and I can't use a wrapper (InputRange) and
keep the @nogc.


I needed the same thing in a code example of this chapter:

  http://ddili.org/ders/d.en/fibers.html

There is this function that returns a range:

auto byNode(const(Node) * node)
{
return new FiberRange!(const(Node)*)(
() = nextNode(node));
}

I am lucky because although the returned type is opaque to me, I know 
that it is constructed by a void lambda. So, I could pass (){} to the 
constructor to make an empty range:


auto byNode(const(Tree) tree)
{
alias RangeType = typeof(byNode(tree.root));

return (tree.root
? byNode(tree.root)
: new RangeType(() {}));// ← Empty range
}

Ali



Re: Returning an empty range of a given type

2015-05-14 Thread rcorre via Digitalmars-d-learn

On Thursday, 14 May 2015 at 14:57:26 UTC, Idan Arye wrote:


How about a more flexible solution?

http://dpaste.dzfl.pl/2f99cc270651


Neat, thanks!

On Thursday, 14 May 2015 at 18:44:58 UTC, Steven Schveighoffer 
wrote:



It depends on the guts of MyContainer.Range.

I'm assuming MyContainer.Range has SOME sort of references 
(i.e. pointers) to the data in the container, so why not just 
have:


bool empty() { return someRef == null || yourCurrentTest; }

-Steve


In this case, I want to return an empty range when the container 
instance itself is null. I could have a static method 
MyContainer.emptySlice, but I feel like I've seen this general 
situation crop up a lot with small variations.


Re: Returning an empty range of a given type

2015-05-14 Thread rcorre via Digitalmars-d-learn

On Friday, 15 May 2015 at 03:22:43 UTC, rcorre wrote:

On Thursday, 14 May 2015 at 14:57:26 UTC, Idan Arye wrote:


How about a more flexible solution?

http://dpaste.dzfl.pl/2f99cc270651


Neat, thanks!



The range I don't pick may be an expression that would fail, so I 
tweaked it to:

SelectRange!T selectRange(T...)(size_t index, lazy T ranges)

Other than that, it seems to be just what I needed. Thanks again!


Re: Returning an empty range of a given type

2015-05-13 Thread rcorre via Digitalmars-d-learn

Actually, this doesn't even seem to work with a custom range:

import std.range;
import std.stdio;
import std.algorithm;

struct MyContainer {
  @nogc auto opSlice() {
struct Range {
  @property bool empty() { return true; }
  @property int front() { return 9; }
  void popFront() { }
}

return Range();
  }
}

/// Return a slice of aa[key], or an empty slice if not found
@nogc auto maybeGetRange(MyContainer[string] aa, string key) {
  alias RangeType = typeof(MyContainer.init[]);
  auto val = key in aa;
  return (val is null) ? takeNone!RangeType : 
(*val)[].take(size_t.max);

}

Is there any way to create an empty MyContainer.Range() without 
creating a new container?


Re: Returning an empty range of a given type

2015-05-13 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, May 14, 2015 02:47:22 rcorre via Digitalmars-d-learn wrote:
 I've run into this situation a lot:
 I have a function that returns a range (in this case, a slice of
 a custom container).
 In some cases, the function needs to return an empty range.

 It sounded like takeNone was what I wanted:

 @nogc auto fun() {
 return (some_condition) ? getRange() : getRange.takeNone;
 }

 but there is a return type ambiguity. I finally ended up doing
 this:

 @nogc auto fun() {
 return (some_condition) ? getRange().take(size_t.max) :
 getRange.takeNone;
 }

 I'm not sure if this is clever or insane.
 It works, but just looks a bit crazy to me.
 Does anyone else run into this situation? Have any cool ways to
 solve it?
 MyRange is an inputRange, and I can't use a wrapper (InputRange)
 and keep the @nogc.

takeNone is as close as you can get in O(1) in the general case, because
there's no well-defined way to get an empty range from a range other than to
keep calling popFront on it until it's empty (which would be O(n)). So,
takeNone gives you an empty range of the same type if it can, and if it
can't then the best that it can do is to use takeExactly with 0.

It looks like what you're trying to do is to force the return type to be
Take!R in all cases (or the original type if that's what Take!R is able to
alias itself to). I don't know if that will work in all cases or not, but I
don't see how you have much choice. The only way that you could keep the
original range type in all cases would be if we had a standard way to make a
range empty that takeNone could use, and we don't.

- Jonathan M Davis