@@ -2731,7 +2731,7 @@ Note:
27312731Params:
27322732 fun = One or more functions.
27332733See_Also:
2734- $(LREF cached), $(LREF vmap), $(LREF indexed),
2734+ $(LREF cached), $(LREF vmap), $(LREF rcmap), $(LREF indexed),
27352735 $(LREF pairwise), $(LREF subSlices), $(LREF slide), $(LREF zip),
27362736 $(HTTP en.wikipedia.org/wiki/Map_(higher-order_function), Map (higher-order function))
27372737+/
@@ -3041,7 +3041,7 @@ Params:
30413041 slice = ndslice
30423042 callable = callable object, structure, delegate, or function pointer.
30433043See_Also:
3044- $(LREF cached), $(LREF map), $(LREF indexed),
3044+ $(LREF cached), $(LREF map), $(LREF rcmap), $(LREF indexed),
30453045 $(LREF pairwise), $(LREF subSlices), $(LREF slide), $(LREF zip),
30463046 $(HTTP en.wikipedia.org/wiki/Map_(higher-order_function), Map (higher-order function))
30473047+/
@@ -3181,7 +3181,7 @@ version(none) version(mir_test) unittest
31813181 }
31823182}
31833183
3184- // / Use map with byDim/alongDim to apply functions to each dimension
3184+ // / Use vmap with byDim/alongDim to apply functions to each dimension
31853185version (mir_test)
31863186@safe pure
31873187unittest
@@ -3214,7 +3214,7 @@ unittest
32143214}
32153215
32163216/+ +
3217- Use map with a lambda and with byDim/alongDim, but may need to allocate result.
3217+ Use vmap with a lambda and with byDim/alongDim, but may need to allocate result.
32183218This example uses fuse, which allocates. Note: fuse!1 will transpose the result.
32193219+/
32203220version (mir_test)
@@ -3291,6 +3291,168 @@ private auto unhideStride
32913291 return slice;
32923292}
32933293
3294+ /+ +
3295+ Implements the homonym function (also known as `transform`) present
3296+ in many languages of functional flavor. The call `rmap!(fun)(slice)`
3297+ returns an RC array (1D) or RC slice (ND) of which elements are obtained by applying `fun`
3298+ for all elements in `slice`. The original slices are
3299+ not changed. Evaluation is done eagerly.
3300+
3301+ Note:
3302+ $(SUBREF dynamic, transposed) and
3303+ $(SUBREF topology, pack) can be used to specify dimensions.
3304+ Params:
3305+ fun = One or more functions.
3306+ See_Also:
3307+ $(LREF cached), $(LREF map), $(LREF vmap), $(LREF indexed),
3308+ $(LREF pairwise), $(LREF subSlices), $(LREF slide), $(LREF zip),
3309+ $(HTTP en.wikipedia.org/wiki/Map_(higher-order_function), Map (higher-order function))
3310+ +/
3311+ template rcmap (fun... )
3312+ if (fun.length)
3313+ {
3314+ import mir.functional: adjoin, naryFun, pipe;
3315+ static if (fun.length == 1 )
3316+ {
3317+ static if (__traits(isSame, naryFun! (fun[0 ]), fun[0 ]))
3318+ {
3319+ alias f = fun[0 ];
3320+ @optmath:
3321+ /+ +
3322+ Params:
3323+ slice = An ndslice, array, or an input range.
3324+ Returns:
3325+ ndslice or an input range with each fun applied to all the elements. If there is more than one
3326+ fun, the element type will be `Tuple` containing one element for each fun.
3327+ +/
3328+ auto rcmap (Iterator, size_t N, SliceKind kind)
3329+ (Slice! (Iterator, N, kind) slice)
3330+ {
3331+ import core.lifetime : move;
3332+ auto shape = slice.shape;
3333+ auto r = slice.move.flattened;
3334+ if (false )
3335+ {
3336+ auto e = f(r.front);
3337+ r.popFront;
3338+ auto d = r.empty;
3339+ }
3340+ return () @trusted
3341+ {
3342+ import mir.rc.array: RCArray;
3343+ import std.traits : Unqual;
3344+ import mir.conv: emplaceRef;
3345+
3346+ alias T = typeof (f(r.front));
3347+ auto ret = RCArray! T(r.length);
3348+ auto next = ret.ptr;
3349+ while (! r.empty)
3350+ {
3351+ emplaceRef(* cast (Unqual! T* )next++ , f (r.front));
3352+ r.popFront;
3353+ }
3354+ static if (N == 1 )
3355+ {
3356+ return ret;
3357+ }
3358+ else
3359+ {
3360+ return ret.moveToSlice.sliced(shape);
3361+ }
3362+ } ();
3363+ }
3364+
3365+ // / ditto
3366+ auto rcmap (T)(T[] array)
3367+ {
3368+ return rcmap (array.sliced);
3369+ }
3370+
3371+ // / ditto
3372+ auto rcmap (T)(T withAsSlice)
3373+ if (hasAsSlice! T)
3374+ {
3375+ static if (__traits(hasMember, T, " moveToSlice" ))
3376+ return rcmap (withAsSlice.moveToSlice);
3377+ else
3378+ return rcmap (withAsSlice.asSlice);
3379+ }
3380+
3381+ // / ditto
3382+ auto rcmap (Range )(Range r)
3383+ if (! hasAsSlice! Range && ! isSlice! Range && ! is (Range : T[], T))
3384+ {
3385+ import core.lifetime : forward;
3386+ import std.range.primitives : isInputRange;
3387+ import mir.rc.array: RCArray;
3388+
3389+ if (false )
3390+ {
3391+ auto e = f(r.front);
3392+ r.popFront;
3393+ auto d = r.empty;
3394+ }
3395+ return () @trusted
3396+ {
3397+ import mir.appender: ScopedBuffer;
3398+ alias T = typeof (f(r.front));
3399+ ScopedBuffer! T buffer = void ;
3400+ buffer.initialize;
3401+ while (! r.empty)
3402+ {
3403+ buffer.put(f(r.front));
3404+ r.popFront;
3405+ }
3406+ auto ret = RCArray! T(buffer.length, false );
3407+ buffer.moveDataAndEmplaceTo(ret[]);
3408+ return ret;
3409+ } ();
3410+ }
3411+ }
3412+ else alias rcmap = .rcmap! (staticMap! (naryFun, fun));
3413+ }
3414+ else alias rcmap = .rcmap! (adjoin! fun);
3415+ }
3416+
3417+ // / Returns RCArray for input ranges and one-dimensional slices.
3418+ @safe pure nothrow @nogc
3419+ version (mir_test) unittest
3420+ {
3421+ import mir.algorithm.iteration: filter, equal;
3422+ auto factor = 10 ;
3423+ auto step = 20 ;
3424+ assert (3. iota.rcmap! (a => a * factor).moveToSlice.equal(3. iota * factor));
3425+ assert (6. iota.filter! " a % 2" .rcmap! (a => a * factor).moveToSlice.equal([3 ].iota(factor, step)));
3426+ }
3427+
3428+ // / For multidimensional case returns `Slice!(RCI!T, N)`.
3429+ @safe pure nothrow @nogc
3430+ version (mir_test) unittest
3431+ {
3432+ import mir.ndslice.topology : iota;
3433+ auto factor = 3 ;
3434+ auto s = iota(2 , 3 ).rcmap! (a => a * factor);
3435+ assert (s == iota(2 , 3 ) * factor);
3436+ }
3437+
3438+ // / String lambdas
3439+ @safe pure nothrow
3440+ version (mir_test) unittest
3441+ {
3442+ import mir.ndslice.topology : iota;
3443+ assert (iota(2 , 3 ).rcmap! " a * 2" == iota(2 , 3 ) * 2 );
3444+ }
3445+
3446+ @safe pure nothrow @nogc
3447+ version (mir_test) unittest
3448+ {
3449+ import mir.algorithm.iteration: filter, equal;
3450+ auto factor = 10 ;
3451+ auto step = 20 ;
3452+ assert (3. iota.as! (const int ).rcmap! (a => a * factor).moveToSlice.equal(3. iota * factor));
3453+ assert (6. iota.filter! " a % 2" .as! (immutable int ).rcmap! (a => a * factor).moveToSlice.equal([3 ].iota(factor, step)));
3454+ }
3455+
32943456/+ +
32953457Creates a random access cache for lazyly computed elements.
32963458Params:
0 commit comments