| 2982 | 2982 | assert(findSkip("abcdef", "cd") && s == "ef"); |
|---|
| 2983 | 2983 | s = "abcdef"; |
|---|
| 2984 | 2984 | assert(!findSkip("abcdef", "cxd") && s == "abcdef"); |
|---|
| 2985 | 2985 | assert(findSkip("abcdef", "def") && s.empty); |
|---|
| 2986 | 2986 | ---- |
|---|
| 2987 | 2987 | */ |
|---|
| 2988 | 2988 | bool findSkip(alias pred = "a == b", R1, R2)(ref R1 haystack, R2 needle) |
|---|
| 2989 | 2989 | if (isForwardRange!R1 && isForwardRange!R2 |
|---|
| 2990 | 2990 | && is(typeof(binaryFun!pred(haystack.front, needle.front)))) |
|---|
| 2991 | 2991 | { |
|---|
| 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. |
|---|
| | 3010 | These functions find the first occurrence of $(D needle) in $(D |
|---|
| | 3011 | haystack) and then split $(D haystack) as follows. |
|---|
| | 3012 | |
|---|
| | 3013 | $(D findSplit) returns a tuple $(D result) containing $(I three) |
|---|
| | 3014 | ranges. $(D result[0]) is the portion of $(D haystack) before $(D |
|---|
| | 3015 | needle), $(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 |
|---|
| | 3017 | the match. |
|---|
| | 3019 | $(D findSplitBefore) returns a tuple $(D result) containing two |
|---|
| | 3020 | ranges. $(D result[0]) is the portion of $(D haystack) before $(D |
|---|
| | 3021 | needle), and $(D result[1]) is the balance of $(D haystack) starting |
|---|
| | 3022 | with the match. If $(D needle) was not found, $(D result[0]) |
|---|
| | 3023 | comprehends $(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 |
|---|
| | 3027 | match, and $(D result[1]) is the balance of $(D haystack) starting |
|---|
| | 3028 | after the match. If $(D needle) was not found, $(D result[0]) is empty |
|---|
| | 3029 | and $(D result[1]) is $(D haystack). |
|---|
| | 3030 | |
|---|
| | 3031 | In all cases, the concatenation of the returned ranges spans the |
|---|
| | 3032 | entire $(D haystack). |
|---|
| | 3033 | |
|---|
| 3016 | 3034 | If $(D haystack) is a random-access range, all three components of the |
|---|
| 3017 | 3035 | tuple have the same type as $(D haystack). Otherwise, $(D haystack) |
|---|
| 3018 | 3036 | must be a forward range and the type of $(D result[0]) and $(D |
|---|
| 3019 | 3037 | result[1]) is the same as $(XREF range,takeExactly). |
|---|
| 3020 | 3038 | |
|---|
| 3021 | 3039 | Example: |
|---|
| 3022 | 3040 | ---- |
|---|
| 3023 | 3041 | auto a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; |
|---|
| 3030 | | assert(r[1] == a[2 .. 3]); |
|---|
| 3031 | | assert(r[2] == a[3 .. $]); |
|---|
| | 3048 | assert(r[1] == a[2 .. 4]); |
|---|
| | 3049 | assert(r[2] == a[4 .. $]); |
|---|
| | 3050 | auto r1 = findSplitBefore(a, [ 7, 8 ]); |
|---|
| | 3051 | assert(r1[0] == a[0 .. 6]); |
|---|
| | 3052 | assert(r1[1] == a[6 .. $]); |
|---|
| | 3053 | auto r1 = findSplitAfter(a, [ 7, 8 ]); |
|---|
| | 3054 | assert(r1[0] == a); |
|---|
| | 3055 | assert(r1[1].empty); |
|---|
| | 3099 | /// Ditto |
|---|
| | 3100 | auto findSplitBefore(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) |
|---|
| | 3101 | if (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 |
|---|
| | 3136 | auto findSplitAfter(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) |
|---|
| | 3137 | if (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 | |
|---|
| 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 | |
|---|
| | 3204 | unittest |
|---|
| | 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]); |
|---|
| 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 .. $])); |
|---|
| 3086 | 3230 | } |
|---|
| 3087 | 3231 | |
|---|
| 3088 | 3232 | /** |
|---|
| 3089 | 3233 | If $(D haystack) supports slicing, returns the smallest number $(D n) |
|---|
| 3090 | 3234 | such that $(D haystack[n .. $].startsWith!pred(needle)). Oherwise, |
|---|
| 3091 | 3235 | returns the smallest $(D n) such that after $(D n) calls to $(D |
|---|
| 3092 | 3236 | haystack.popFront), $(D haystack.startsWith!pred(needle)). If no such |
|---|
| 3093 | 3237 | number could be found, return $(D -1). |
|---|
| 3094 | 3238 | */ |
|---|
| 3095 | 3239 | sizediff_t countUntil(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) |
|---|