[Issue 5233] [patch] std.range.put accepts *any* element type when putting to an array.

d-bugmail at puremagic.com d-bugmail at puremagic.com
Sat Apr 2 22:26:39 PDT 2011


http://d.puremagic.com/issues/show_bug.cgi?id=5233



--- Comment #5 from Rob Jacques <sandford at jhu.edu> 2011-04-02 22:22:59 PDT ---
Patch version 6.
*sigh* Naturally, new ideas come immediately after my previous post.

*** API Addition ***
ER or R's ElementEncodingType allows user-defined-types to specify a preferred
encoding type. The principal point is to prevent the duplication of
dchar->char[] conversions in every single output range. i.e. My example from
patch 5 didn't handle strings and chars in a UTF correct manner. Now, by
setting ER to T, it properly supports chars and strings.

struct Stack(T) {
    put(U item) if( isOutputRange!(T[],U) ) {
        static if( is(U:T) ) {
            // put one item onto the stack
        } else {
            .put!(typeof(this),U,true,T)(this,item);
        }
    }
}

* Simplification of string handling, which necessitated 3 new code snippets:
  * The index assign and slice advance
  * The slice assign and slice advance
  * The foreach(ER v) put(r,v); 
* Additional of the r ~= e code snippet. I found I needed to protect this with
some additional constraints to prevent the char<->ubyte implicit conversion.
Also, this allows put-ing to arrays with const elements. Personally, I think
this snippet should take precedence over the input-range snippets, but that
would be a major change in behavior. Currently,

    auto str = "Hello ".dup;
    auto str2 = str;           // Note the need for second of the array
    put(str2,"World");
    assert(str == "World ");

Where as with ~= 

    auto str3 = "Hello ";
    put(str3,"World");
    assert(str3 == "Hello World");

I think that viewing arrays as containers first and input-ranges second is more
intuitive and useful.

[Patch]

/** Outputs $(D e) to $(D r). The exact effect is dependent upon the two types.
    Several cases are accepted, as described below. The code snippets are
    attempted in order, and the first to compile "wins" and gets evaluated.
    Setting $(D asArray) to true will skip code snippets using user defined
    $(D put) and $(D opCall) methods, allowing templated user defined $(D put)
    methods to reuse some of $(D put)'s code snippets. Furthermore, $(D ER)
    allows the caller to set a prefered conversion type, enabling put to
    perform the correct UTF conversions for character and string inputs.

$(BOOKTABLE ,

$(TR $(TH Code Snippet) $(TH Scenario))

$(TR $(TD $(D r.put(e);))
     $(TD $(D R) defines a method $(D put) accepting an $(D E).))

$(TR $(TD $(D r.put([ e ]);))
     $(TD $(D R) defines a method $(D put) accepting an $(D E[]).))

$(TR $(TD $(D r.front = e; r.popFront();))
     $(TD $(D R) is an input range and $(D e) is assignable to $(D r.front).))

$(TR $(TD $(D r[0] = e; r = r[1..$];))
     $(TD $(D R) supports slicing and $(D e) is index assignable to $(D r).))

$(TR $(TD $(D r[0..e.length] = e[0..$]; r = r[e.length..$];))
     $(TD $(D R) supports slicing and $(D e) is slice assignable to $(D r).))

$(TR $(TD $(D foreach(ER v; e) put(r,v)))
     $(TD String safe copying of a range $(D E) to range $(D R).))

$(TR $(TD $(D foreach(v; e) put(r,v)))
     $(TD General copying of a range $(D E) to range $(D R).))

$(TR $(TD $(D foreach(i;0..e.length) put(r,e[i])))
     $(TD Copying range $(D E) to range $(D R).))

$(TR $(TD $(D r ~= e;))
     $(TD $(D R) supports concatenation with $(D e).))

$(TR $(TD $(D r(e);))
     $(TD $(D R) is e.g. a delegate accepting an $(D E).))

$(TR $(TD $(D r([ e ]);))
     $(TD $(D R) is e.g. a $(D delegate) accepting an $(D E[]).))

)
 */

void put(R, E, bool asArray=isArray!R, ER=ElementEncodingType!R)(ref R r, E e){
    static if(isSomeChar!ER && isSomeChar!E && ER.sizeof < E.sizeof ) {
        // Transcoding is required to support r.put(dchar)
        ER[ER.sizeof == 1 ? 4 : 2] encoded;
        auto len = std.utf.encode(encoded, e);
        put(r,encoded[0 .. len]);
    } else static if( !asArray && __traits(compiles,  r.put(  e          ))  ){
                                                      r.put(  e          );
    } else static if( !asArray && __traits(compiles,  r.put((&e)[0..1]   ))  ){
                                                      r.put((&e)[0..1]   );
    } else static if (isInputRange!R && is(typeof(r.front = e) )) {
        r.front = e;
        r.popFront();
    } else static if(__traits(compiles, {r[0] = e; r = r[1..r.length];}     )){
        r[0] = e;
        r    = r[1..r.length];
    } else static if(__traits(compiles, {r[0..e.length] = e[0..e.length];
                                                      r = r[1..r.length];  })){
        r[0..e.length] = e[0..e.length];
        r              = r[e.length..r.length];
    } else static if(__traits(compiles,{foreach(ER v; e)       put(r,  v );})){
                                        foreach(ER v; e)       put(r,  v );
    } else static if(__traits(compiles,{foreach(   v; e)       put(r,  v );})){
                                        foreach(   v; e)       put(r,  v );
    } else static if(__traits(compiles,{foreach(i;0..e.length) put(r,e[i]);})){
                                        foreach(i;0..e.length) put(r,e[i]);
    } else static if(__traits(compiles,r~=e) && (is(ER==void)||
                                               !(isSomeChar!ER^isSomeChar!E))){
        r ~= e;
    } else static if( _putCall!(R,E,asArray) && is(typeof( r( e          )) )){
                                                           r( e          );
    } else static if( _putCall!(R,E,asArray) && is(typeof( r( (&e)[0..1] )) )){
                                                           r( (&e)[0..1] );
    } else {
        // @@@BUG@@@ Static asserts can't be combined with is(typeof(put(r,e)))
        "Can't put a "~E.stringof~" into a "~R.stringof ;
    }
}

// Helper template for put(): filters out opCall from ctors
private template _putCall(R, E, bool asArray = false) {
    static if(asArray)    enum _putCall = false;
    else static if( is(R==class) || is(R==struct) || is(R==union) )
         enum _putCall = is(typeof( (R r, E e){r.opCall(   e        );}))||
                         is(typeof( (R r, E e){r.opCall( (&e)[0..1] );}));
    else enum _putCall = is(typeof( (R r, E e){r(          e        );}))||
                         is(typeof( (R r, E e){r(        (&e)[0..1] );}));
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list