How to easily construct objects with multi-param constructors from lazy ranges?

Rene Zwanenburg via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Aug 5 08:13:36 PDT 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.


More information about the Digitalmars-d-learn mailing list