Thread overview
How to easily construct objects with multi-param constructors from lazy ranges?
Aug 05, 2014
Rene Zwanenburg
Aug 05, 2014
Rene Zwanenburg
Aug 05, 2014
Philippe Sigaud
Aug 06, 2014
Rene Zwanenburg
Aug 06, 2014
Philippe Sigaud
Aug 06, 2014
Rene Zwanenburg
August 05, 2014
Here's something which I've run into a few times now without finding a pretty solution. When parsing a text file using lazy ranges and algorithms you will have to convert a string range to an object at some point.

In this particular case I was curious to see if I could write clean looking code to parse Wavefont OBJ files [0]. A simple OBJ file could look like this:

v 0 1 0
v 1 1 0
v 1 0 0
v 0 0 0

vn 0 0 1

f 3//1 2//1 1//1
f 3//1 4//1 2//1

Now, to parse the vertex positions (the lines beginning with 'v') I use:

struct vec3
{
  float[3] v;

  this(float x, float y, float z){ ... }
}

void foo()
{

auto lines =
  File("SomeFile.obj")
  .byLine
  .map!(a => a.strip)
  .filter!(a => !a.empty)
  .filter!(a => !a.startsWith('#'));

auto vertices =
  lines
  .filter!(a => a.startsWith('v'))
  .map!(a => a.splitter)
  // Now what?
}

What is a nice way to convert the forward range ["v", "0", "1", "0"] to a vec3, without unneccessary allocations? Creating a constructor function like

vec3 parseVec(R)(R range)
{
  vec3 v;
  v.v[0] = range.front.to!float;
  range.popFront();
  // Etc.
  return v;
}

seems terribly awkward to me.

Some range which takes an at compile time known number of elements from an input range and provides opIndex seems perfect to me, but as far as I know there's no such thing in Phobos. It would allow

auto vertices =
	lines
	.filter!(a => a.startsWith('v'))
	.map!(a => a.splitter)
	.map!(a => a.staticChunks!4)
	.map!(a => vec3(a[1].to!float, a[2].to!float, a[3].to!float));

without heap allocations. Anyone know if Phobos has something like this? Or another approach?

If not I'm willing to create something like staticChunks if there's interest to add it to std.range.
August 05, 2014
On Tuesday, 5 August 2014 at 15:13:37 UTC, Rene Zwanenburg wrote:
> clean looking code to parse Wavefont OBJ files [0].

[0] http://en.wikipedia.org/wiki/Wavefront_.obj_file
August 05, 2014
> Some range which takes an at compile time known number of elements from an input range and provides opIndex seems perfect to me, but as far as I know there's no such thing in Phobos.

There is chunks:

http://dlang.org/phobos/std_range.html#chunks
August 06, 2014
On Tuesday, 5 August 2014 at 19:21:44 UTC, Philippe Sigaud via Digitalmars-d-learn wrote:
>> Some range which takes an at compile time known number of elements from an
>> input range and provides opIndex seems perfect to me, but as far as I know
>> there's no such thing in Phobos.
>
> There is chunks:
>
> http://dlang.org/phobos/std_range.html#chunks

Yea, but that won't work for forward ranges. It only provides opIndex if the underlying range provides it. Since the chunk size is a runtime parameter it can't implement opIndex efficiently for non-random access ranges.

staticChunks was a bit of a misnomer. staticTake would be a better name. The range would contains a static array and pops that number of elements from the input range. Then, opIndex can easily be defined.
August 06, 2014
> Yea, but that won't work for forward ranges. It only provides opIndex if the underlying range provides it. Since the chunk size is a runtime parameter it can't implement opIndex efficiently for non-random access ranges.

But in your case, your range is random-access, no?

Or else, you can always map array on the chunks...

>
> staticChunks was a bit of a misnomer. staticTake would be a better name. The range would contains a static array and pops that number of elements from the input range. Then, opIndex can easily be defined.

What about takeExactly?
August 06, 2014
On Wednesday, 6 August 2014 at 08:00:32 UTC, Philippe Sigaud via Digitalmars-d-learn wrote:
>> Yea, but that won't work for forward ranges. It only provides opIndex if the
>> underlying range provides it. Since the chunk size is a runtime parameter it
>> can't implement opIndex efficiently for non-random access ranges.
>
> But in your case, your range is random-access, no?
Nope, splitter returns a forward range.

>
> Or else, you can always map array on the chunks...
Sure. But that would be a completely unnecessary allocation. I'm trying to avoid those, it's what ranges are supposed to be good at ;)

>
>>
>> staticChunks was a bit of a misnomer. staticTake would be a better name. The
>> range would contains a static array and pops that number of elements from
>> the input range. Then, opIndex can easily be defined.
>
> What about takeExactly?

Same problem. As long as the 'count' parameter is a runtime value instead of a compile time value, it's impossible to define opIndex efficiently. Therefore the Phobos ranges don't do it.