Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changeset 2373

Show
Ignore:
Timestamp:
01/23/11 15:44:03 (14 years ago)
Author:
andrei
Message:

findSplit, findSplitBefore, findSplitAfter

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/phobos/std/algorithm.d

    r2368 r2373  
    29822982assert(findSkip("abcdef", "cd") && s == "ef"); 
    29832983s = "abcdef"; 
    29842984assert(!findSkip("abcdef", "cxd") && s == "abcdef"); 
    29852985assert(findSkip("abcdef", "def") && s.empty); 
    29862986---- 
    29872987 */ 
    29882988bool findSkip(alias pred = "a == b", R1, R2)(ref R1 haystack, R2 needle) 
    29892989if (isForwardRange!R1 && isForwardRange!R2 
    29902990        && is(typeof(binaryFun!pred(haystack.front, needle.front)))) 
    29912991{ 
    2992     auto parts = findParts!pred(haystack, needle); 
     2992    auto parts = findSplit!pred(haystack, needle); 
    29932993    if (parts[1].empty) return false; 
    29942994    // found 
    29952995    haystack = parts[2]; 
    29962996    return true; 
    29972997} 
    29982998 
    29992999unittest 
    30003000{ 
    30013001    string s = "abcdef"; 
    30023002    assert(findSkip(s, "cd") && s == "ef"); 
    30033003    s = "abcdef"; 
    30043004    assert(!findSkip(s, "cxd") && s == "abcdef"); 
    30053005    s = "abcdef"; 
    30063006    assert(findSkip(s, "def") && s.empty); 
    30073007} 
    30083008 
    30093009/** 
    3010 Given a $(D haystack) and a $(D needle), returns a tuple $(D result) 
    3011 containing three ranges: $(D result[0]) is the portion of $(D 
    3012 haystack) before $(D needle), $(D result[1]) is the portion of $(D 
    3013 haystack) that matches $(D needle), and $(D result[2]) is the portion 
    3014 of $(D haystack) after the match. 
     3010These functions find the first occurrence of $(D needle) in $(D 
     3011haystack) and then split $(D haystack) as follows. 
     3012 
     3013$(D findSplit) returns a tuple $(D result) containing $(I three) 
     3014ranges. $(D result[0]) is the portion of $(D haystack) before $(D 
     3015needle), $(D result[1]) is the portion of $(D haystack) that matches 
     3016$(D needle), and $(D result[2]) is the portion of $(D haystack) after 
     3017the match. 
    30153018  
     3019$(D findSplitBefore) returns a tuple $(D result) containing two 
     3020ranges. $(D result[0]) is the portion of $(D haystack) before $(D 
     3021needle), and $(D result[1]) is the balance of $(D haystack) starting 
     3022with the match. If $(D needle) was not found, $(D result[0]) 
     3023comprehends $(D haystack) entirely and $(D result[1]) is empty. 
     3024 
     3025$(D findSplitAfter) returns a tuple $(D result) containing two ranges. 
     3026$(D result[0]) is the portion of $(D haystack) up to and including the 
     3027match, and $(D result[1]) is the balance of $(D haystack) starting 
     3028after the match. If $(D needle) was not found, $(D result[0]) is empty 
     3029and $(D result[1]) is $(D haystack). 
     3030 
     3031In all cases, the concatenation of the returned ranges spans the 
     3032entire $(D haystack). 
     3033 
    30163034If $(D haystack) is a random-access range, all three components of the 
    30173035tuple have the same type as $(D haystack). Otherwise, $(D haystack) 
    30183036must be a forward range and the type of $(D result[0]) and $(D 
    30193037result[1]) is the same as $(XREF range,takeExactly). 
    30203038 
    30213039Example: 
    30223040---- 
    30233041auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; 
    3024 auto r = findParts(a, [9, 1]); 
     3042auto r = findSplit(a, [9, 1]); 
    30253043assert(r[0] == a); 
    30263044assert(r[1].empty); 
    30273045assert(r[2].empty); 
    3028 r = findParts(a, [3]); 
     3046r = findSplit(a, [ 3, 4 ]); 
    30293047assert(r[0] == a[0 .. 2]); 
    3030 assert(r[1] == a[2 .. 3]); 
    3031 assert(r[2] == a[3 .. $]); 
     3048assert(r[1] == a[2 .. 4]); 
     3049assert(r[2] == a[4 .. $]); 
     3050auto r1 = findSplitBefore(a, [ 7, 8 ]); 
     3051assert(r1[0] == a[0 .. 6]); 
     3052assert(r1[1] == a[6 .. $]); 
     3053auto r1 = findSplitAfter(a, [ 7, 8 ]); 
     3054assert(r1[0] == a); 
     3055assert(r1[1].empty); 
    30323056---- 
    30333057 */ 
    3034 auto findParts(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) 
     3058auto findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) 
    30353059if (isForwardRange!R1 && isForwardRange!R2) 
    30363060{ 
    30373061    static if (isSomeString!R1 && isSomeString!R2 
    30383062            || isRandomAccessRange!R1 && hasLength!R2) 
    30393063    { 
    30403064        auto balance = find!pred(haystack, needle); 
    30413065        immutable pos1 = haystack.length - balance.length; 
    3042         immutable pos2 = balance.length ? pos1 + needle.length : pos1
     3066        immutable pos2 = balance.empty ? pos1 : pos1 + needle.length
    30433067        return tuple(haystack[0 .. pos1], 
    30443068                haystack[pos1 .. pos2], 
    30453069                haystack[pos2 .. haystack.length]); 
    30463070    } 
    30473071    else 
    30483072    { 
    30493073        auto original = haystack.save; 
    30503074        auto h = haystack.save; 
    30513075        auto n = needle.save; 
    30523076        size_t pos1, pos2; 
     
    30603084            } 
    30613085            else 
    30623086            { 
    30633087                haystack.popFront(); 
    30643088                n = needle.save; 
    30653089                h = haystack.save; 
    30663090                pos2 = ++pos1; 
    30673091            } 
    30683092        } 
    30693093        return tuple(takeExactly(original, pos1), 
    3070                 takeExactly(haystack, pos2), 
     3094                takeExactly(haystack, pos2 - pos1), 
    30713095                h); 
    30723096    } 
    30733097} 
    30743098 
     3099/// Ditto 
     3100auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) 
     3101if (isForwardRange!R1 && isForwardRange!R2) 
     3102{ 
     3103    static if (isSomeString!R1 && isSomeString!R2 
     3104            || isRandomAccessRange!R1 && hasLength!R2) 
     3105    { 
     3106        auto balance = find!pred(haystack, needle); 
     3107        immutable pos = haystack.length - balance.length; 
     3108        return tuple(haystack[0 .. pos], haystack[pos .. haystack.length]); 
     3109    } 
     3110    else 
     3111    { 
     3112        auto original = haystack.save; 
     3113        auto h = haystack.save; 
     3114        auto n = needle.save; 
     3115        size_t pos; 
     3116        while (!n.empty && !h.empty) 
     3117        { 
     3118            if (binaryFun!pred(h.front, n.front)) 
     3119            { 
     3120                h.popFront(); 
     3121                n.popFront(); 
     3122            } 
     3123            else 
     3124            { 
     3125                haystack.popFront(); 
     3126                n = needle.save; 
     3127                h = haystack.save; 
     3128                ++pos; 
     3129            } 
     3130        } 
     3131        return tuple(takeExactly(original, pos), haystack); 
     3132    } 
     3133} 
     3134 
     3135/// Ditto 
     3136auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) 
     3137if (isForwardRange!R1 && isForwardRange!R2) 
     3138{ 
     3139    static if (isSomeString!R1 && isSomeString!R2 
     3140            || isRandomAccessRange!R1 && hasLength!R2) 
     3141    { 
     3142        auto balance = find!pred(haystack, needle); 
     3143        immutable pos = balance.empty ? 0 : haystack.length - balance.length + needle.length; 
     3144        return tuple(haystack[0 .. pos], haystack[pos .. haystack.length]); 
     3145    } 
     3146    else 
     3147    { 
     3148        auto original = haystack.save; 
     3149        auto h = haystack.save; 
     3150        auto n = needle.save; 
     3151        size_t pos1, pos2; 
     3152        while (!n.empty) 
     3153        { 
     3154            if (h.empty) 
     3155            { 
     3156                // Failed search 
     3157                return tuple(takeExactly(original, 0), original); 
     3158            } 
     3159            if (binaryFun!pred(h.front, n.front)) 
     3160            { 
     3161                h.popFront(); 
     3162                n.popFront(); 
     3163                ++pos2; 
     3164            } 
     3165            else 
     3166            { 
     3167                haystack.popFront(); 
     3168                n = needle.save; 
     3169                h = haystack.save; 
     3170                pos2 = ++pos1; 
     3171            } 
     3172        } 
     3173        return tuple(takeExactly(original, pos2), h); 
     3174    } 
     3175} 
     3176 
    30753177unittest 
    30763178{ 
    30773179    auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; 
    3078     auto r = findParts(a, [9, 1]); 
     3180    auto r = findSplit(a, [9, 1]); 
     3181    assert(r[0] == a); 
     3182    assert(r[1].empty); 
     3183    assert(r[2].empty); 
     3184    r = findSplit(a, [3]); 
     3185    assert(r[0] == a[0 .. 2]); 
     3186    assert(r[1] == a[2 .. 3]); 
     3187    assert(r[2] == a[3 .. $]); 
     3188 
     3189    auto r1 = findSplitBefore(a, [9, 1]); 
     3190    assert(r1[0] == a); 
     3191    assert(r1[1].empty); 
     3192    r1 = findSplitBefore(a, [3, 4]); 
     3193    assert(r1[0] == a[0 .. 2]); 
     3194    assert(r1[1] == a[2 .. $]); 
     3195 
     3196    r1 = findSplitAfter(a, [9, 1]); 
     3197    assert(r1[0].empty); 
     3198    assert(r1[1] == a); 
     3199    r1 = findSplitAfter(a, [3, 4]); 
     3200    assert(r1[0] == a[0 .. 4]); 
     3201    assert(r1[1] == a[4 .. $]); 
     3202
     3203 
     3204unittest 
     3205
     3206    auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; 
     3207    auto fwd = filter!"a > 0"(a); 
     3208    auto r = findSplit(fwd, [9, 1]); 
    30793209    assert(equal(r[0], a)); 
    30803210    assert(r[1].empty); 
    30813211    assert(r[2].empty); 
    3082     r = findParts(a, [3]); 
    3083     assert(r[0] == a[0 .. 2]); 
    3084     assert(r[1] == a[2 .. 3]); 
    3085     assert(r[2] == a[3 .. $]); 
     3212    r = findSplit(fwd, [3]); 
     3213    assert(equal(r[0],  a[0 .. 2])); 
     3214    assert(equal(r[1], a[2 .. 3])); 
     3215    assert(equal(r[2], a[3 .. $])); 
     3216     
     3217    auto r1 = findSplitBefore(fwd, [9, 1]); 
     3218    assert(equal(r1[0], a)); 
     3219    assert(r1[1].empty); 
     3220    r1 = findSplitBefore(fwd, [3, 4]); 
     3221    assert(equal(r1[0], a[0 .. 2])); 
     3222    assert(equal(r1[1], a[2 .. $])); 
     3223 
     3224    r1 = findSplitAfter(fwd, [9, 1]); 
     3225    assert(r1[0].empty); 
     3226    assert(equal(r1[1], a)); 
     3227    r1 = findSplitAfter(fwd, [3, 4]); 
     3228    assert(equal(r1[0], a[0 .. 4])); 
     3229    assert(equal(r1[1], a[4 .. $])); 
    30863230} 
    30873231 
    30883232/** 
    30893233If $(D haystack) supports slicing, returns the smallest number $(D n) 
    30903234such that $(D haystack[n .. $].startsWith!pred(needle)). Oherwise, 
    30913235returns the smallest $(D n) such that after $(D n) calls to $(D 
    30923236haystack.popFront), $(D haystack.startsWith!pred(needle)). If no such 
    30933237number could be found, return $(D -1). 
    30943238 */ 
    30953239sizediff_t countUntil(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)