1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 module tanya.range.tests.primitive; 5 6 import tanya.range; 7 import tanya.test.stub; 8 9 private struct AssertPostblit 10 { 11 this(this) @nogc nothrow pure @safe 12 { 13 assert(false); 14 } 15 } 16 17 @nogc nothrow pure @safe unittest 18 { 19 static struct Range1(T) 20 { 21 mixin InputRangeStub; 22 23 T empty() const 24 { 25 return true; 26 } 27 } 28 static assert(!isInputRange!(Range1!int)); 29 static assert(!isInputRange!(Range1!(const bool))); 30 31 static struct Range2 32 { 33 mixin InputRangeStub; 34 35 int popFront() @nogc nothrow pure @safe 36 { 37 return 100; 38 } 39 } 40 static assert(isInputRange!Range2); 41 42 static struct Range3 43 { 44 mixin InputRangeStub; 45 46 void front() @nogc nothrow pure @safe 47 { 48 } 49 } 50 static assert(!isInputRange!Range3); 51 52 static struct Range4 53 { 54 mixin InputRangeStub; 55 56 enum bool empty = false; 57 } 58 static assert(isInputRange!Range4); 59 } 60 61 // Ranges with non-copyable elements can be input ranges 62 @nogc nothrow pure @safe unittest 63 { 64 @WithLvalueElements 65 static struct R 66 { 67 mixin InputRangeStub!NonCopyable; 68 } 69 static assert(isInputRange!R); 70 } 71 72 // Ranges with const non-copyable elements can be input ranges 73 @nogc nothrow pure @safe unittest 74 { 75 @WithLvalueElements 76 static struct R 77 { 78 mixin InputRangeStub!(const(NonCopyable)); 79 } 80 static assert(isInputRange!R); 81 } 82 83 @nogc nothrow pure @safe unittest 84 { 85 static struct Range1 86 { 87 } 88 static struct Range2 89 { 90 mixin InputRangeStub; 91 92 Range1 save() @nogc nothrow pure @safe 93 { 94 return Range1(); 95 } 96 } 97 static assert(!isForwardRange!Range2); 98 99 static struct Range3 100 { 101 mixin InputRangeStub; 102 103 const(typeof(this)) save() const @nogc nothrow pure @safe 104 { 105 return this; 106 } 107 } 108 static assert(!isForwardRange!Range3); 109 } 110 111 @nogc nothrow pure @safe unittest 112 { 113 static struct Range(T, U) 114 { 115 mixin BidirectionalRangeStub; 116 117 @property T front() @nogc nothrow pure @safe 118 { 119 return T.init; 120 } 121 122 @property U back() @nogc nothrow pure @safe 123 { 124 return U.init; 125 } 126 } 127 static assert(!isBidirectionalRange!(Range!(int, uint))); 128 static assert(!isBidirectionalRange!(Range!(int, const int))); 129 } 130 131 // Ranges with non-copyable elements can be bidirectional ranges 132 @nogc nothrow pure @safe unittest 133 { 134 @WithLvalueElements 135 static struct R 136 { 137 mixin BidirectionalRangeStub!NonCopyable; 138 } 139 static assert(isBidirectionalRange!R); 140 } 141 142 @nogc nothrow pure @safe unittest 143 { 144 static struct Range1 145 { 146 mixin BidirectionalRangeStub; 147 mixin RandomAccessRangeStub; 148 } 149 static assert(!isRandomAccessRange!Range1); 150 151 @Length 152 static struct Range2(Args...) 153 { 154 mixin BidirectionalRangeStub; 155 156 int opIndex(Args) @nogc nothrow pure @safe 157 { 158 return 0; 159 } 160 } 161 static assert(isRandomAccessRange!(Range2!size_t)); 162 static assert(!isRandomAccessRange!(Range2!())); 163 static assert(!isRandomAccessRange!(Range2!(size_t, size_t))); 164 165 @Length 166 static struct Range3 167 { 168 mixin BidirectionalRangeStub; 169 170 int opIndex(const size_t pos1, const size_t pos2 = 0) 171 @nogc nothrow pure @safe 172 { 173 return 0; 174 } 175 } 176 static assert(isRandomAccessRange!Range3); 177 178 static struct Range4 179 { 180 mixin BidirectionalRangeStub; 181 mixin RandomAccessRangeStub; 182 183 size_t opDollar() const @nogc nothrow pure @safe 184 { 185 return 0; 186 } 187 } 188 static assert(!isRandomAccessRange!Range4); 189 } 190 191 // Ranges with non-copyable elements can be random-access ranges 192 @nogc nothrow pure @safe unittest 193 { 194 @WithLvalueElements @Infinite 195 static struct R 196 { 197 mixin RandomAccessRangeStub!NonCopyable; 198 } 199 static assert(isRandomAccessRange!R); 200 } 201 202 @nogc nothrow pure @safe unittest 203 { 204 @Infinite 205 static struct StaticConstRange 206 { 207 mixin InputRangeStub; 208 209 static bool empty = false; 210 } 211 static assert(!isInfinite!StaticConstRange); 212 213 @Infinite 214 static struct TrueRange 215 { 216 mixin InputRangeStub; 217 218 static const bool empty = true; 219 } 220 static assert(!isInfinite!TrueRange); 221 } 222 223 @nogc nothrow pure @safe unittest 224 { 225 @Infinite 226 static struct InfiniteRange 227 { 228 mixin ForwardRangeStub; 229 private int i; 230 231 void popFront() @nogc nothrow pure @safe 232 { 233 ++this.i; 234 } 235 236 void popBack() @nogc nothrow pure @safe 237 { 238 --this.i; 239 } 240 241 @property int front() const @nogc nothrow pure @safe 242 { 243 return this.i; 244 } 245 246 @property int back() const @nogc nothrow pure @safe 247 { 248 return this.i; 249 } 250 } 251 { 252 InfiniteRange range; 253 popFrontExactly(range, 2); 254 assert(range.front == 2); 255 popFrontN(range, 2); 256 assert(range.front == 4); 257 } 258 { 259 InfiniteRange range; 260 popBackExactly(range, 2); 261 assert(range.back == -2); 262 popBackN(range, 2); 263 assert(range.back == -4); 264 } 265 } 266 267 @nogc nothrow pure @safe unittest 268 { 269 static struct Range 270 { 271 private int[5] a = [1, 2, 3, 4, 5]; 272 private size_t begin = 0, end = 5; 273 274 Range save() @nogc nothrow pure @safe 275 { 276 return this; 277 } 278 279 void popFront() @nogc nothrow pure @safe 280 { 281 ++this.begin; 282 } 283 284 void popBack() @nogc nothrow pure @safe 285 { 286 --this.end; 287 } 288 289 @property int front() const @nogc nothrow pure @safe 290 { 291 return this.a[this.begin]; 292 } 293 294 @property int back() const @nogc nothrow pure @safe 295 { 296 return this.a[this.end - 1]; 297 } 298 299 @property bool empty() const @nogc nothrow pure @safe 300 { 301 return this.begin >= this.end; 302 } 303 } 304 { 305 Range range; 306 307 popFrontN(range, 3); 308 assert(range.front == 4); 309 assert(range.back == 5); 310 311 popFrontN(range, 20); 312 assert(range.empty); 313 } 314 { 315 Range range; 316 317 popBackN(range, 3); 318 assert(range.front == 1); 319 assert(range.back == 2); 320 321 popBackN(range, 20); 322 assert(range.empty); 323 } 324 } 325 326 @nogc nothrow pure @safe unittest 327 { 328 // Returns its elements by reference. 329 @Infinite @WithLvalueElements 330 static struct R1 331 { 332 mixin InputRangeStub!AssertPostblit; 333 } 334 static assert(is(typeof(moveFront(R1())))); 335 336 // Returns elements with a postblit constructor by value. moveFront fails. 337 @Infinite 338 static struct R2 339 { 340 mixin InputRangeStub!AssertPostblit; 341 } 342 static assert(!is(typeof(moveFront(R2())))); 343 } 344 345 @nogc nothrow pure @safe unittest 346 { 347 // Returns its elements by reference. 348 @Infinite @WithLvalueElements 349 static struct R1 350 { 351 mixin BidirectionalRangeStub!AssertPostblit; 352 } 353 static assert(is(typeof(moveBack(R1())))); 354 355 // Returns elements with a postblit constructor by value. moveBack fails. 356 @Infinite 357 static struct R2 358 { 359 mixin BidirectionalRangeStub!AssertPostblit; 360 } 361 static assert(!is(typeof(moveBack(R2())))); 362 } 363 364 @nogc nothrow pure @safe unittest 365 { 366 // Returns its elements by reference. 367 @Infinite @WithLvalueElements 368 static struct R1 369 { 370 mixin RandomAccessRangeStub!AssertPostblit; 371 } 372 static assert(is(typeof(moveAt(R1(), 0)))); 373 374 // Returns elements with a postblit constructor by value. moveAt fails. 375 @Infinite 376 static struct R2 377 { 378 mixin RandomAccessRangeStub!AssertPostblit; 379 } 380 static assert(!is(typeof(moveAt(R2(), 0)))); 381 } 382 383 // Works with non-copyable elements 384 @nogc nothrow pure @safe unittest 385 { 386 static assert(hasLvalueElements!(NonCopyable[])); 387 }