1 /**
2 	Mutable @nogc @safe string struct using `std.experimental.allocator` for allocations.
3 
4 	License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
5 	Authors:   Adam Búš
6 */
7 module btl..string;
8 
9 
10 import std.traits : Unqual, Unconst, CopyTypeQualifiers, isSomeChar, isSomeString, isIntegral;
11 import std.meta : AliasSeq;
12 
13 import btl.traits.common;
14 
15 import btl.internal.allocator;
16 import btl.internal.traits;
17 
18 import btl.string.encoding;
19 import btl.string.storage;
20 
21 
22 
23 /**
24 	Type used in forward constructors.
25 */
26 alias Forward = btl.traits.common.Forward;
27 
28 
29 /**
30 	Default allcoator for `BasicString`.
31 */
32 public alias DefaultAllocator = Mallocator;
33 
34 
35 /**
36 	True if `T` is a `BasicString` or implicitly converts to one, otherwise false.
37 */
38 template isBasicString(T){
39 	import std.traits : isInstanceOf;
40 
41 	enum bool isBasicString = isInstanceOf!(BasicString, T);
42 }
43 
44 
45 /**
46 	The `BasicString` is the generalization of struct string for character of type `char`, `wchar` or `dchar`.
47 
48 	`BasicString` use utf-8, utf-16 or utf-32 encoding.
49 
50 	`BasicString` use SSO (Small String Optimization).
51 
52 	Template parameters:
53 
54 		`_Char` Character type. (`char`, `wchar` or `dchar`).
55 
56 		`_Allocator` Type of the allocator object used to define the storage allocation model. By default `DefaultAllocator` is used.
57 
58 		`N` Minimal capacity of `BasicString` (increase max length of small string).
59 
60 */
61 template BasicString(
62 	_Char,
63 	size_t N = 1,
64 	_Allocator = DefaultAllocator
65 )
66 if(isSomeChar!_Char && is(Unqual!_Char == _Char)){
67 	import std.range : empty, ElementEncodingType, isInputRange, isRandomAccessRange, hasLength;
68 	import std.traits : Unqual, isIntegral, hasMember, isArray, isSafe;
69 	import core.lifetime: forward, move;
70 
71 	enum bool _allowHeap = !is(immutable _Allocator == immutable void);
72 
73 	alias Storage = .Storage!(_Char, N, size_t, _allowHeap);
74 
75 	struct BasicString{
76 
77 		/**
78 			True if allocator doesn't have state.
79 		*/
80 		public enum bool hasStatelessAllocator = isStatelessAllocator!_Allocator;
81 
82 
83 
84 		/**
85 			Character type. (`char`, `wchar` or  `dchar`).
86 		*/
87 		public alias CharType = _Char;
88 
89 
90 
91 		/**
92 			Type of the allocator object used to define the storage allocation model. By default `DefaultAllocator` is used.
93 		*/
94 		public alias AllocatorType = _Allocator;
95 
96 
97 
98 		/**
99 			Allow heap (`false` only if `Allcoator` is void)
100 		*/
101 		public alias allowHeap = _allowHeap;
102 
103 
104 
105 		/**
106 			Maximal capacity of string, in terms of number of characters (utf code units).
107 		*/
108 		public alias maximalCapacity = Storage.maximalCapacity;
109 
110 
111 
112 		/**
113 			Minimal capacity of string (same as maximum capacity of small string), in terms of number of characters (utf code units).
114 
115 			Examples:
116 				--------------------
117 				BasicString!char str;
118 				assert(str.empty);
119 				assert(str.capacity == BasicString!char.minimalCapacity);
120 				assert(str.capacity > 0);
121 				--------------------
122 		*/
123 		public alias minimalCapacity = Storage.minimalCapacity;
124 
125 
126 
127 		/**
128 			Returns allocator.
129 		*/
130 		static if(!allowHeap)
131 			public alias allocator = statelessAllcoator!NullAllocator;
132 		else static if(hasStatelessAllocator)
133 			public alias allocator = statelessAllcoator!AllocatorType;
134 		else
135 			public @property auto allocator()inout{
136 				return this._allocator;
137 			}
138 
139 
140 
141 		/**
142 			Returns whether the string is empty (i.e. whether its length is 0).
143 
144 			Examples:
145 				--------------------
146 				BasicString!char str;
147 				assert(str.empty);
148 
149 				str = "123";
150 				assert(!str.empty);
151 				--------------------
152 		*/
153 		public @property bool empty()const scope pure nothrow @safe @nogc{
154 			return (this.length == 0);
155 		}
156 
157 
158 
159 		/**
160 			Returns whether the string is full (i.e. whether its length is equal to maximalCapacity).
161 
162 			Examples:
163 				--------------------
164 				BasicString!(char, 1, void) str;	//FixedString
165 				assert(str.empty);
166 				assert(str.minimalCapacity > 0);
167 				assert(!str.full);
168 
169 				str.resize(str.maximalCapacity);
170 				assert(str.full);
171 				--------------------
172 		*/
173 		public @property bool full()const scope pure nothrow @safe @nogc{
174 			return (this.length == maximalCapacity);
175 		}
176 
177 
178 
179 		/**
180 			Returns the length of the string, in terms of number of characters (utf code units).
181 
182 			This is the number of actual characters that conform the contents of the `BasicString`, which is not necessarily equal to its storage capacity.
183 
184 			Examples:
185 				--------------------
186 				BasicString!char str = "123";
187 				assert(str.length == 3);
188 
189 				BasicString!wchar wstr = "123";
190 				assert(wstr.length == 3);
191 
192 				BasicString!dchar dstr = "123";
193 				assert(dstr.length == 3);
194 
195 				--------------------
196 		*/
197 		public @property size_t length()const scope pure nothrow @trusted @nogc{
198 			return this.storage.length;
199 		}
200 
201 
202 
203 		/**
204 			Returns the size of the storage space currently allocated for the `BasicString`, expressed in terms of characters (utf code units).
205 
206 			This capacity is not necessarily equal to the string length. It can be equal or greater, with the extra space allowing the object to optimize its operations when new characters are added to the `BasicString`.
207 
208 			Notice that this capacity does not suppose a limit on the length of the `BasicString`. When this capacity is exhausted and more is needed, it is automatically expanded by the object (reallocating it storage space).
209 
210 			The capacity of a `BasicString` can be altered any time the object is modified, even if this modification implies a reduction in size.
211 
212 			The capacity of a `BasicString` can be explicitly altered by calling member `reserve`.
213 
214 			Examples:
215 				--------------------
216 				BasicString!char str;
217 				assert(str.capacity == BasicString!char.minimalCapacity);
218 
219 				str.reserve(str.capacity + 1);
220 				assert(str.capacity > BasicString!char.minimalCapacity);
221 				--------------------
222 		*/
223 		public @property size_t capacity()const scope pure nothrow @trusted @nogc{
224 			return this.storage.capacity;
225 		}
226 
227 
228 
229 		/**
230 			Return pointer to the first element.
231 
232 			The pointer  returned may be invalidated by further calls to other member functions that modify the object.
233 
234 			Examples:
235 				--------------------
236 				BasicString!char str = "123";
237 				char* ptr = str.ptr;
238 				assert(ptr[0 .. 3] == "123");
239 				--------------------
240 
241 		*/
242         static if(allowHeap)
243 		    public @property inout(CharType)* ptr()inout return pure nothrow @system @nogc{
244 			    return this.storage.ptr;
245 		    }
246         else
247             public @property inout(CharType)* ptr()inout return pure nothrow @trusted @nogc{
248                 return this.storage.ptr;
249             }
250 
251 
252 
253 		/**
254 			Return `true` if string is small (Small String Optimization)
255 		*/
256 		public @property bool small()const scope pure nothrow @safe @nogc{
257 			return this.storage.small;
258 		}
259 
260 
261 
262 		/**
263 			Return `true` if string is valid utf string.
264 		*/
265 		public @property bool valid()const scope pure nothrow @safe @nogc{
266 			return validate(this.storage.chars);
267 		}
268 
269 
270 
271 		/**
272 			Returns first utf code point(`dchar`) of the `BasicString`.
273 
274 			This function shall not be called on empty strings.
275 
276 			Examples:
277 				--------------------
278 				BasicString!char str = "á123";
279 
280 				assert(str.frontCodePoint == 'á');
281 				--------------------
282 		*/
283 		public @property dchar frontCodePoint()const scope pure nothrow @trusted @nogc{
284 			auto chars = this.storage.allocatedChars;
285 			return decode(chars);
286 		}
287 
288 
289 
290 		/**
291 			Returns the first character(utf8: `char`, utf16: `wchar`, utf32: `dchar`) of the `BasicString`.
292 
293 			This function shall not be called on empty strings.
294 
295 			Examples:
296 				--------------------
297 				{
298 					BasicString!char str = "123";
299 
300 					assert(str.frontCodeUnit == '1');
301 				}
302 
303 				{
304 					BasicString!char str = "á23";
305 
306 					immutable(char)[2] a = "á";
307 					assert(str.frontCodeUnit == a[0]);
308 				}
309 
310 				{
311 					BasicString!char str = "123";
312 
313 					str.frontCodeUnit = 'x';
314 
315 					assert(str == "x23");
316 				}
317 				--------------------
318 		*/
319 		public @property CharType frontCodeUnit()const scope pure nothrow @trusted @nogc{
320 			return *this.ptr;
321 		}
322 
323 		/// ditto
324 		public @property CharType frontCodeUnit(const CharType val)scope pure nothrow @trusted @nogc{
325 			return *this.ptr = val;
326 		}
327 
328 
329 
330 		/**
331 			Returns last utf code point(`dchar`) of the `BasicString`.
332 
333 			This function shall not be called on empty strings.
334 
335 			Examples:
336 				--------------------
337 				{
338 					BasicString!char str = "123á";
339 
340 					assert(str.backCodePoint == 'á');
341 				}
342 
343 				{
344 					BasicString!char str = "123á";
345 					str.backCodePoint = '4';
346 					assert(str == "1234");
347 				}
348 				--------------------
349 		*/
350 		public @property dchar backCodePoint()const scope pure nothrow @trusted @nogc{
351 
352 			static if(is(CharType == dchar)){
353 				return this.backCodeUnit();
354 			}
355 			else{
356 				auto chars = this.storage.chars;
357 
358 				if(chars.length == 0)
359 					return dchar.init;
360 
361 				const ubyte len = strideBack(chars);
362 				if(len == 0)
363 					return dchar.init;
364 
365 				chars = chars[$ - len .. $];
366 				return decode(chars);
367 			}
368 		}
369 
370 		/// ditto
371 		public @property dchar backCodePoint()(const dchar val)scope{
372 
373 			static if(is(CharType == dchar)){
374 				return this.backCodeUnit(val);
375 			}
376 			else{
377 				auto chars = this.storage.chars;
378 
379 				if(chars.length == 0)
380 					return dchar.init;
381 
382 				const ubyte len = strideBack(chars);
383 				if(len == 0)
384 					return dchar.init;
385 
386 				this.storage.length = (chars.length - len);
387 				this.append(val);
388 				return val;
389 			}
390 		}
391 
392 
393 		/**
394 			Returns the last character(utf8: `char`, utf16: `wchar`, utf32: `dchar`) of the `BasicString`.
395 
396 			This function shall not be called on empty strings.
397 
398 			Examples:
399 				--------------------
400 				{
401 					BasicString!char str = "123";
402 
403 					assert(str.backCodeUnit == '3');
404 				}
405 
406 				{
407 					BasicString!char str = "12á";
408 
409 					immutable(char)[2] a = "á";
410 					assert(str.backCodeUnit == a[1]);
411 				}
412 
413 				{
414 					BasicString!char str = "123";
415 
416 					str.backCodeUnit = 'x';
417 					assert(str == "12x");
418 				}
419 				--------------------
420 		*/
421 		public @property CharType backCodeUnit()const scope pure nothrow @trusted @nogc{
422 			auto chars = this.storage.chars;
423 
424 			return (chars.length == 0)
425 				? CharType.init
426 				: chars[$ - 1];
427 		}
428 
429 		/// ditto
430 		public @property CharType backCodeUnit(const CharType val)scope pure nothrow @trusted @nogc{
431 			auto chars = this.storage.chars;
432 
433 			return (chars.length == 0)
434 				? CharType.init
435 				: (chars[$ - 1] = val);
436 		}
437 
438 
439 
440 		/**
441 			Erases the last utf code point of the `BasicString`, effectively reducing its length by code point length.
442 
443 			Return number of erased characters, 0 if string is empty or if last character is not valid code point.
444 
445 			Examples:
446 				--------------------
447 				{
448 					BasicString!char str = "á1";    //'á' is encoded as 2 chars
449 
450 					assert(str.popBackCodePoint == 1);
451 					assert(str == "á");
452 
453 					assert(str.popBackCodePoint == 2);
454 					assert(str.empty);
455 
456 					assert(str.popBackCodePoint == 0);
457 					assert(str.empty);
458 				}
459 
460 				{
461 					BasicString!char str = "1á";    //'á' is encoded as 2 chars
462 					assert(str.length == 3);
463 
464 					str.erase(str.length - 1);
465 					assert(str.length == 2);
466 
467 					assert(str.popBackCodePoint == 0);   //popBackCodePoint cannot remove invalid code points
468 					assert(str.length == 2);
469 				}
470 				--------------------
471 		*/
472 		public ubyte popBackCodePoint()scope pure nothrow @trusted @nogc{
473 			if(this.empty)
474 				return 0;
475 
476 			const ubyte n = strideBack(this.storage.chars);
477 
478 			this.storage.length = (this.length - n);
479 
480 			return n;
481 		}
482 
483 
484 
485 		/**
486 			Erases the last code unit of the `BasicString`, effectively reducing its length by 1.
487 
488 			Return number of erased characters, `false` if string is empty or `true` if is not.
489 
490 			Examples:
491 				--------------------
492 				BasicString!char str = "á1";    //'á' is encoded as 2 chars
493 				assert(str.length == 3);
494 
495 				assert(str.popBackCodeUnit);
496 				assert(str.length == 2);
497 
498 				assert(str.popBackCodeUnit);
499 				assert(str.length == 1);
500 
501 				assert(str.popBackCodeUnit);
502 				assert(str.empty);
503 
504 				assert(!str.popBackCodeUnit);
505 				assert(str.empty);
506 				--------------------
507 		*/
508 		public bool popBackCodeUnit()scope pure nothrow @trusted @nogc{
509 			if(this.empty)
510 				return false;
511 
512 			this.storage.length = (this.storage.length - 1);
513 
514 			return true;
515 		}
516 
517 
518 
519 		/**
520 			Erases the contents of the `BasicString`, which becomes an empty string (with a length of 0 characters).
521 
522 			Doesn't change capacity of string.
523 
524 			Examples:
525 				--------------------
526 				BasicString!char str = "123";
527 
528 				str.reserve(str.capacity * 2);
529 				assert(str.length == 3);
530 
531 				const size_t cap = str.capacity;
532 				str.clear();
533 				assert(str.capacity == cap);
534 				--------------------
535 		*/
536 		public void clear()scope pure nothrow @trusted @nogc{
537 			this.storage.length = 0;
538 		}
539 
540 
541 
542 		/**
543 			Erases and deallocate the contents of the `BasicString`, which becomes an empty string (with a length of 0 characters).
544 
545 			Examples:
546 				--------------------
547 				BasicString!char str = "123";
548 
549 				str.reserve(str.capacity * 2);
550 				assert(str.length == 3);
551 
552 				const size_t cap = str.capacity;
553 				str.clear();
554 				assert(str.capacity == cap);
555 
556 				str.release();
557 				assert(str.capacity < cap);
558 				assert(str.capacity == BasicString!char.minimalCapacity);
559 				--------------------
560 		*/
561 		public void release()scope{
562 			if(this.storage.external){
563 				//this._deallocate(this.storage.heap.allocatedChars);
564 				this._deallocate_heap(this.storage.heap);
565 			}
566 			this.storage.reset();
567 		}
568 
569 
570 
571 		/**
572 			Requests that the string capacity be adapted to a planned change in size to a length of up to n characters (utf code units).
573 
574 			If n is greater than the current string capacity, the function causes the container to increase its capacity to n characters (or greater).
575 
576 			In all other cases, it do nothing.
577 
578 			This function has no effect on the string length and cannot alter its content.
579 
580 			Examples:
581 				--------------------
582 				BasicString!char str = "123";
583 				assert(str.capacity == BasicString!char.minimalCapacity);
584 
585 				const size_t cap = (str.capacity * 2);
586 				str.reserve(cap);
587 				assert(str.capacity > BasicString!char.minimalCapacity);
588 				assert(str.capacity >= cap);
589 				--------------------
590 		*/
591 		public void reserve(const size_t n)scope{
592 
593 			void _reserve_short(const size_t n)scope{
594 				assert(this.storage.small);
595 
596 				const size_t old_capacity = this.storage.capacity;
597 
598 				if(n <= old_capacity)
599 					return;// old_capacity;
600 
601 				const size_t length = this.storage.length;
602 				//const size_t new_capacity = max(old_capacity * 2, (n + 1)) & ~0x1;
603 				const size_t new_capacity = _grow_capacity(old_capacity, n);
604 
605 				//assert(new_capacity >= max(old_capacity * 2, n));
606 				//assert(new_capacity % 2 == 0);
607 
608 
609 				Storage.Heap heap;
610 				this._allocate_heap(heap, new_capacity);
611 
612 				memCopy(heap.ptr, this.storage.ptr, length);
613 				assert(this.storage.chars == heap.chars);
614 
615 				this.storage.heap = heap;
616 
617 				//return new_capacity;
618 			}
619 
620 			void _reserve_long(const size_t n)scope{
621 				assert(this.storage.external);
622 
623 				const size_t old_capacity = this.storage.heap.capacity;
624 
625 				if(n <= old_capacity)
626 					return;// old_capacity;
627 
628 				const size_t length = this.storage.heap.length;
629 				//const size_t new_capacity = max(old_capacity * 2, (n + 1)) & ~0x1;
630 				const size_t new_capacity = _grow_capacity(old_capacity, n);
631 
632 				//assert(new_capacity >= max(old_capacity * 2, n));
633 				//assert(new_capacity % 2 == 0);
634 
635 				this._reallocate_heap(this.storage.heap, new_capacity);
636 			}
637 
638 			return (this.storage.small)
639 				? _reserve_short(n)
640 				: _reserve_long(n);
641 		}
642 
643 
644 
645 		/**
646 			Resizes the string to a length of `n` characters (utf code units).
647 
648 			If `n` is smaller than the current string length, the current value is shortened to its first `n` character, removing the characters beyond the nth.
649 
650 			If `n` is greater than the current string length, the current content is extended by inserting at the end as many characters as needed to reach a size of n.
651 
652 			If `ch` is specified, the new elements are initialized as copies of `ch`, otherwise, they are `_`.
653 
654 			Examples:
655 				--------------------
656 				BasicString!char str = "123";
657 
658 				str.resize(5, 'x');
659 				assert(str == "123xx");
660 
661 				str.resize(2);
662 				assert(str == "12");
663 				--------------------
664 		*/
665         public void resize(const size_t n, const CharType ch = '_')scope{
666             const size_t old_length = this.length;
667 
668             if(old_length > n){
669                 this.storage.length = n;
670             }
671             else if(old_length < n){
672                 this.append(ch, n - old_length);
673             }
674         }
675 
676 
677 
678         /**
679             Downsizes the string to a length of `n` characters (utf code units).
680 
681             If `n` is smaller than the current string length, the current value is shortened to its first `n` character, removing the characters beyond the nth.
682 
683             If `n` is greater or equal than the current string length, the nothing happend.
684 
685             Examples:
686                 --------------------
687                 BasicString!char str = "123";
688 
689                 str.downsize(5);
690                 assert(str == "123");
691 
692                 str.downsize(2);
693                 assert(str == "12");
694                 --------------------
695         */
696         public void downsize(const size_t n)scope pure nothrow @safe @nogc{
697             const size_t old_length = this.length;
698 
699             if(old_length > n){
700                 this.storage.length = n;
701             }
702         }
703 
704 
705 
706         /**
707             Upsizes the string to a length of `n` characters (utf code units).
708 
709             If `n` is smaller or equal than the current string length, the current value doesn't change.
710 
711             If `n` is greater than the current string length, the current content is extended by inserting at the end as many characters as needed to reach a size of n.
712 
713             If `ch` is specified, the new elements are initialized as copies of `ch`, otherwise, they are `_`.
714 
715             Examples:
716                 --------------------
717                 BasicString!char str = "123";
718 
719                 str.upsize(5, 'x');
720                 assert(str == "123xx");
721 
722                 str.upsize(2);
723                 assert(str == "123xx");
724                 --------------------
725         */
726         public void upsize(const size_t n, const CharType ch = '_')scope{
727             const size_t old_length = this.length;
728 
729             if(old_length < n){
730                 this.append(ch, n - old_length);
731             }
732         }
733 
734 
735 
736 		/**
737 			Requests the `BasicString` to reduce its capacity to fit its length.
738 
739 			The request is non-binding.
740 
741 			This function has no effect on the string length and cannot alter its content.
742 
743 			Examples:
744 				--------------------
745 				BasicString!char str = "123";
746 				assert(str.capacity == BasicString!char.minimalCapacity);
747 
748 				str.reserve(str.capacity * 2);
749 				assert(str.capacity > BasicString!char.minimalCapacity);
750 
751 				str.shrinkToFit();
752 				assert(str.capacity == BasicString!char.minimalCapacity);
753 				--------------------
754 		*/
755 		public void shrinkToFit(bool realloc = true)()scope{
756 			if(!this.storage.external)
757 				return;
758 
759 			const size_t old_capacity = this.storage.heap.capacity;
760 			const size_t length = this.storage.heap.length;
761 
762 
763 			if(length == old_capacity)
764 				return;
765 
766 
767 			if(length <= minimalCapacity){
768 				auto heap = this.storage.heap;
769 
770 				this.storage.reset(length);
771 				memCopy(this.storage.inline.ptr, heap.ptr, length);
772 
773 				this._deallocate_heap(heap);
774 
775 				assert(!this.storage.external);
776 				return;
777 			}
778 
779 			if(realloc == false){
780 				return;
781 			}
782 
783 			const size_t new_capacity = length;
784 
785 			if(new_capacity >= old_capacity)
786 				return;
787 
788 			assert(new_capacity >= length);
789 			//assert(new_capacity % 2 == 0);
790 
791 			this._reallocate_heap!(!realloc)(this.storage.heap, new_capacity);
792 		}
793 
794 
795 
796 		/*
797 			Checks if `this` is not empty`.
798 
799 			Examples:
800 				--------------------
801 				BasicString!char str;
802 				assert(false == cast(bool)x);    //explicit cast
803 				assert(!x);              //implicit cast
804 				x = "\t";
805 				assert(cast(bool)x);   //explicit cast
806 				assert(x);             //implicit cast
807 				--------------------
808 		*/
809 		/+public bool opCast(To : bool)()const scope pure nothrow @safe @nogc
810 		if(is(To : bool)){ //docs
811 			return !this.empty;
812 		}+/
813 
814 
815 
816 		/**
817 			Support for quelifier cast.
818 		*/
819 		public ref To opCast(To, this This)()return scope pure nothrow @nogc
820 		if(is(immutable To : immutable typeof(this))){
821 			static if(is(This : To)){
822 				return *(()@trusted => cast(To*)&this )();
823 			}
824 			else{
825 				return *(()@system => cast(To*)&this )();
826 			}
827 		}
828 
829 
830 
831 		/**
832 			Destroys the `BasicString` object.
833 
834 			This deallocates all the storage capacity allocated by the `BasicString` using its allocator.
835 		*/
836 		public ~this()scope{
837 			if(this.storage.external){
838 				this._deallocate_heap(this.storage.heap);
839 				debug this.storage.reset();
840 			}
841 		}
842 
843 
844 
845 		/**
846 			Constructs a empty `BasicString` object.
847 
848 			Examples:
849 				--------------------
850 				{
851 					BasicString!char str = null;
852 					assert(str.empty);
853 				}
854 				--------------------
855 		*/
856 		public this(typeof(null) nil, Forward = Forward.init)scope pure nothrow @safe @nogc{
857 		}
858 
859 
860 
861 		/**
862 			Constructs a empty `BasicString` object with `allocator`.
863 
864 			Parameters:
865 				`allocator` allocator parameter.
866 
867 			Examples:
868 				--------------------
869 				{
870 					BasicString!(char, DefaultAllocator) str = DefaultAllocator.init;
871 					assert(str.empty);
872 				}
873 				--------------------
874 		*/
875 		static if(allowHeap)
876 		public this(AllocatorType allocator)scope{
877 			static if(!hasStatelessAllocator)
878 				this._allocator = forward!allocator;
879 		}
880 
881 
882 
883 		/**
884 			Constructs a `BasicString` object, initializing its value to char value `character`.
885 
886 			Parameters:
887 				`character` can by type char|wchar|dchar.
888 
889 			Examples:
890 				--------------------
891 				{
892 					BasicString!char str = 'x';
893 					assert(str == "x");
894 				}
895 
896 				{
897 					BasicString!char str = '読';
898 					assert(str == "読");
899 				}
900 				--------------------
901 		*/
902 		public this(C)(const C character, Forward = Forward.init)scope
903 		if(isSomeChar!C){
904 			this._ctor(character);
905 		}
906 
907 
908 
909 		/**
910 			Constructs a `BasicString` object, initializing its value to char value `character`.
911 
912 			Parameters:
913 				`character` can by type char|wchar|dchar.
914 
915 				`allocator` allocator parameter.
916 
917 			Examples:
918 				--------------------
919 				{
920 					auto str = BasicString!(char, DefaultAllocator)('読', DefaultAllocator.init);
921 					assert(str == "読");
922 				}
923 				--------------------
924 		*/
925 		public this(C)(const C character, AllocatorType allocator)scope
926 		if(isSomeChar!C){
927 			this(forward!allocator);
928 			this._ctor(character);
929 		}
930 
931 
932 
933 		/**
934 			Constructs a `BasicString` object from char slice `slice`.
935 
936 			Parameters:
937 				`slice` is slice of characters (`const char[]`, `const wchar[]`, `const dchar[]`).
938 
939 			Examples:
940 				--------------------
941 				{
942 					BasicString!char str = "test";
943 					assert(str == "test");
944 				}
945 
946 				{
947 					BasicString!char str = "test 読"d;
948 					assert(str == "test 読");
949 				}
950 
951 				{
952 					wchar[3] data = [cast(wchar)'1', '2', '3'];
953 					BasicString!char str = data[];
954 					assert(str == "123");
955 				}
956 				--------------------
957 		*/
958 		public this(this This)(scope const CharType[] slice, Forward = Forward.init)scope{
959 			this._ctor(slice);
960 		}
961 
962 		/// ditto
963 		public this(this This, C)(scope const C[] slice, Forward = Forward.init)scope
964 		if(isSomeChar!C && !is(immutable C == immutable CharType)){
965 			this._ctor(slice);
966 		}
967 
968 
969 
970 		/**
971 			Constructs a `BasicString` object from char slice `slice`.
972 
973 			Parameters:
974 				`slice` is slice of characters (`const char[]`, `const wchar[]`, `const dchar[]`).
975 
976 				`allocator` allocator parameter.
977 
978 			Examples:
979 				--------------------
980 				{
981 					auto str = BasicString!(char, DefaultAllocator)("test", DefaultAllocator.init);
982 					assert(str == "test");
983 				}
984 
985 				{
986 					auto str = BasicString!(char, DefaultAllocator)("test 読"d, DefaultAllocator.init);
987 					assert(str == "test 読");
988 				}
989 
990 				{
991 
992 					wchar[3] data = [cast(wchar)'1', '2', '3'];
993 					auto str = BasicString!(char, DefaultAllocator)(data[], DefaultAllocator.init);
994 					assert(str == "123");
995 				}
996 				--------------------
997 		*/
998 		public this(this This)(scope const CharType[] slice, AllocatorType allocator)scope{
999 			this(forward!allocator);
1000 			this._ctor(slice);
1001 		}
1002 
1003 		/// ditto
1004 		public this(this This, C)(scope const C[] slice, AllocatorType allocator)scope
1005 		if(isSomeChar!C && !is(immutable C == immutable CharType)){
1006 			this(forward!allocator);
1007 			this._ctor(slice);
1008 		}
1009 
1010 
1011 
1012 		/**
1013 			Constructs a `BasicString` object, initializing its value from integer `integer`.
1014 
1015 			Parameters:
1016 
1017 				`integer` integers value.
1018 
1019 			Examples:
1020 				--------------------
1021 				{
1022 					BasicString!char str = 123uL;
1023 					assert(str == "123");
1024 				}
1025 
1026 				{
1027 					BasicString!dchar str = -123;
1028 					assert(str == "-123");
1029 				}
1030 				--------------------
1031 		*/
1032 		public this(I)(I integer, Forward = Forward.init)scope
1033 		if(isIntegral!I){
1034 			this._ctor(integer);
1035 		}
1036 
1037 
1038 
1039 		/**
1040 			Constructs a `BasicString` object, initializing its value from integer `integer`.
1041 
1042 			Parameters:
1043 
1044 				`integer` integers value.
1045 
1046 				`allocator` allocator parameter.
1047 
1048 			Examples:
1049 				--------------------
1050 				{
1051 					auto str = BasicString!(char, DefaultAllocator)(123uL, DefaultAllocator.init);
1052 					assert(str == "123");
1053 				}
1054 
1055 				{
1056 					auto str = BasicString!(dchar, DefaultAllocator)(-123, DefaultAllocator.init);
1057 					assert(str == "-123");
1058 				}
1059 				--------------------
1060 		*/
1061 		public this(I)(I integer, AllocatorType allocator)scope
1062 		if(isIntegral!I){
1063 			this(forward!allocator);
1064 			this._ctor(integer);
1065 		}
1066 
1067 
1068 
1069 		/**
1070 			Constructs a `BasicString` object from other `BasicString` object.
1071 
1072 			Parameters:
1073 
1074 				`rhs` `BasicString` rvalue/lvalue
1075 
1076 				`allocator` optional allocator parameter.
1077 
1078 			Examples:
1079 				--------------------
1080 				{
1081 					BasicString!char a = "123";
1082 					BasicString!char b = a;
1083 					assert(b == "123");
1084 				}
1085 
1086 				{
1087 					BasicString!dchar a = "123";
1088 					BasicString!char b = a;
1089 					assert(b == "123");
1090 				}
1091 
1092 				{
1093 					BasicString!dchar a = "123";
1094 					auto b = BasicString!char(a, DefaultAllocator.init);
1095 					assert(b == "123");
1096 				}
1097 
1098 				import core.lifetime : move;
1099 				{
1100 					BasicString!char a = "123";
1101 					BasicString!char b = move(a);
1102 					assert(b == "123");
1103 				}
1104 				--------------------
1105 		*/
1106 		public this(this This, Rhs)(scope auto ref Rhs rhs)scope
1107 		if(    isBasicString!Rhs
1108 			&& isConstructable!(Rhs, This)
1109 			&& (isRef!rhs || !is(immutable This == immutable Rhs))
1110 		){
1111 			this(forward!rhs, Forward.init);
1112 		}
1113 
1114 		/// ditto
1115 		public this(this This, Rhs)(scope auto ref const Rhs rhs, AllocatorType allocator)scope
1116 		if(isBasicString!Rhs){
1117 			this(forward!allocator);
1118 			this._ctor(rhs.storage.chars);
1119 		}
1120 
1121 
1122 
1123 		/**
1124 			Forward constructor.
1125 		*/
1126 		public this(this This, Rhs)(scope auto ref Rhs rhs, Forward)scope
1127 		if(isBasicString!Rhs && isConstructable!(Rhs, This)){
1128 
1129 			static if(isMoveConstructable!(rhs, This)){
1130 
1131 				if(rhs.storage.external){
1132 					//heap -> heap:
1133 					if(minimalCapacity <= Rhs.minimalCapacity || minimalCapacity < rhs.length){
1134 						static if(!hasStatelessAllocator)
1135 							this._allocator = move(rhs._allocator);
1136 
1137 						this.storage.heap = rhs.storage.heap; //this.storage.setHeap(rhs.storage.heap);
1138 						rhs.storage.reset();
1139 					}
1140 					//heap -> inline:
1141 					else{
1142 						assert(rhs.length <= minimalCapacity);
1143 
1144 						this._ctor(rhs.storage.heap.chars);
1145 
1146 						rhs.release();
1147 
1148 						static if(!hasStatelessAllocator)
1149 							this._allocator = move(rhs._allocator);
1150 					}
1151 				}
1152 				else{
1153 					static if(!hasStatelessAllocator)
1154 						this._allocator = move(rhs._allocator);
1155 
1156 					//inline -> inline:
1157 					//inline -> heap:
1158 					this._ctor(rhs.storage.inline.chars);
1159 				}
1160 			}
1161 			else{
1162 				static if(!hasStatelessAllocator)
1163 					this._allocator = rhs._allocator;
1164 
1165 				this._ctor(rhs.storage.chars);
1166 			}
1167 		}
1168 
1169 
1170 
1171 		/**
1172 			Copy constructor if `AllocatorType` is statless.
1173 
1174 			Parameter `rhs` is const.
1175 		*/
1176 		static if(hasStatelessAllocator)
1177 		public this(ref scope const typeof(this) rhs)scope{
1178 			this(rhs.storage.chars);
1179 		}
1180 
1181 
1182 
1183 		/**
1184 			Copy constructor if `AllocatorType` has state.
1185 
1186 			Parameter `rhs` is mutable.
1187 		*/
1188 		static if(!hasStatelessAllocator)
1189 		public this(ref scope typeof(this) rhs)scope{
1190 			this(rhs.storage.chars, rhs.allocator);
1191 		}
1192 
1193 
1194 
1195 
1196 		private void _ctor(this This, C)(const C character)scope
1197 		if(isSomeChar!C){
1198 			auto self = (()@trusted => cast(Unqual!This*)&this )();
1199 
1200 			assert(minimalCapacity >= encodedLength!CharType(character));
1201 			self.storage.inline.length = character.encodeTo(self.storage.inline.allocatedChars);
1202 		}
1203 
1204 		private void _ctor(this This, C)(scope const C[] str)scope
1205 		if(isSomeChar!C){
1206 			auto self = (()@trusted => cast(Unqual!This*)&this )();
1207 
1208 			const size_t len = encodedLength!CharType(str);
1209 
1210 			self.reserve(len);
1211 			self.storage.length = str[].encodeTo(self.storage.allocatedChars);
1212 		}
1213 
1214 		private void _ctor(this This, I)(const I integer)scope
1215 		if(isIntegral!I){
1216 			auto self = (()@trusted => cast(Unqual!This*)&this )();
1217 
1218 			const size_t len = encodedLength!CharType(integer);
1219 
1220 			self.reserve(len);
1221 			self.storage.length = integer.encodeTo(self.storage.allocatedChars);
1222 		}
1223 
1224 
1225 
1226 		/**
1227 			Assigns a new value `rhs` to the string, replacing its current contents.
1228 
1229 			Parameter `rhs` can by type of `null`, `BasicString!(...)`, `char|wchar|dchar` array/slice/character or integer (integer is transformed to string).
1230 
1231 			Return referece to `this`.
1232 
1233 			Examples:
1234 				--------------------
1235 				BasicString!char str = "123";
1236 				assert(!str.empty);
1237 
1238 				str = null;
1239 				assert(str.empty);
1240 
1241 				str = 'X';
1242 				assert(str == "X");
1243 
1244 				str = "abc"w;
1245 				assert(str == "abc");
1246 
1247 				str = -123;
1248 				assert(str == "-123");
1249 
1250 				str = BasicString!char("42");
1251 				assert(str == "42");
1252 
1253 				str = BasicString!wchar("abc");
1254 				assert(str == "abc");
1255 				--------------------
1256 		*/
1257 		public void opAssign(typeof(null) nil)scope pure nothrow @safe @nogc{
1258 			this.clear();
1259 		}
1260 
1261 		/// ditto
1262 		public void opAssign(scope const CharType[] slice)scope{
1263 			this.clear();
1264 
1265 			this.reserve(encodedLength!CharType(slice));
1266 			this.storage.length = slice.encodeTo(this.storage.allocatedChars);
1267 		}
1268 
1269 		/// ditto
1270 		public void opAssign(C)(scope const C[] slice)scope
1271 		if(isSomeChar!C){
1272 			this.clear();
1273 
1274 			this.reserve(encodedLength!CharType(slice));
1275 			this.storage.length = slice.encodeTo(this.storage.allocatedChars);
1276 		}
1277 
1278 		/// ditto
1279 		public void opAssign(C)(const C character)scope
1280 		if(isSomeChar!C){
1281 			this.clear();
1282 
1283 			assert(character.encodedLength!CharType <= minimalCapacity);
1284 			this.storage.length = character.encodeTo(this.storage.allocatedChars);
1285 		}
1286 
1287 		/// ditto
1288 		public void opAssign(I)(const I integer)scope
1289 		if(isIntegral!I){
1290 			this.clear();
1291 
1292 			assert(integer.encodedLength!CharType <= minimalCapacity);
1293 			this.storage.length = integer.encodeTo(this.storage.allocatedChars);
1294 		}
1295 
1296 		/// ditto
1297 		public void opAssign(scope typeof(this) rhs)scope{
1298 			this.proxySwap(rhs);
1299 		}
1300 
1301 		/// ditto
1302 		public void opAssign(Rhs)(scope auto ref Rhs rhs)scope
1303 		if(isBasicString!Rhs && isAssignable!(Rhs, typeof(this))){
1304 			static if(isMoveAssignable!(rhs, typeof(this))){
1305 
1306 				if(rhs.storage.external){
1307 					if(minimalCapacity <= Rhs.minimalCapacity || minimalCapacity < rhs.length){
1308 						static if(!hasStatelessAllocator)
1309 							this._allocator = move(rhs._allocator);
1310 
1311 						this.release();
1312 						this.storage.heap = rhs.storage.heap; //this.storage.setHeap(rhs.storage.heap);
1313 						rhs.storage.reset();
1314 						return;
1315 					}
1316 				}
1317 			}
1318 			else{
1319 				return this.opAssign(rhs.storage.chars);
1320 			}
1321 		}
1322 
1323 
1324 
1325 		/**
1326 			Extends the `BasicString` by appending additional characters at the end of its current value.
1327 
1328 			This is alias to `append`
1329 		*/
1330 		public template opOpAssign(string op)
1331 		if(op == "+" || op == "~"){
1332 			alias opOpAssign = append;
1333 		}
1334 
1335 
1336 
1337 		/**
1338 			Returns a newly constructed `BasicString` object with its value being the concatenation of the characters in `this` followed by those of `rhs`.
1339 
1340 			Parameter `rhs` can by type of `BasicString!(...)`, `char|wchar|dchar` array/slice/character.
1341 
1342 			Examples:
1343 				--------------------
1344 				BasicString!char str = null;
1345 				assert(str.empty);
1346 
1347 				str = str + '1';
1348 				assert(str == "1");
1349 
1350 				str = str + "23"d;
1351 				assert(str == "123");
1352 
1353 				str = str + BasicString!dchar("456");
1354 				assert(str == "123456");
1355 				--------------------
1356 		*/
1357 		public typeof(this) opBinary(string op)(scope const CharType[] rhs)scope
1358 		if(op == "+" || op == "~"){
1359 			static if(hasStatelessAllocator)
1360 				return this.build(this.storage.chars, rhs);
1361 			else
1362 				return this.build(this._allocator, this.storage.chars, rhs);
1363 		}
1364 
1365 		/// ditto
1366 		public typeof(this) opBinary(string op, Rhs)(scope auto ref const Rhs rhs)scope
1367 		if((op == "+" || op == "~")
1368 			&& (isBasicString!Rhs || isSomeChar!Rhs || isSomeString!Rhs || isCharArray!Rhs || isIntegral!Rhs)
1369 		){
1370 			static if(hasStatelessAllocator)
1371 				return this.build(this.storage.chars, forward!rhs);
1372 			else
1373 				return this.build(this._allocator, this.storage.chars, forward!rhs);
1374 		}
1375 
1376 
1377 
1378 		/**
1379 			Returns a newly constructed `BasicString` object with its value being the concatenation of the characters in `lhs` followed by those of `this`.
1380 
1381 			Parameter `lhs` can by type of `BasicString!(...)`, `char|wchar|dchar` array/slice/character.
1382 
1383 			Examples:
1384 				--------------------
1385 				BasicString!char str = null;
1386 				assert(str.empty);
1387 
1388 				str = '1' + str;
1389 				assert(str == "1");
1390 
1391 				str = "32"d + str;
1392 				assert(str == "321");
1393 
1394 				str = BasicString!dchar("654") + str;
1395 				assert(str == "654321");
1396 				--------------------
1397 		*/
1398 		public typeof(this) opBinaryRight(string op)(scope const CharType[] lhs)scope
1399 		if(op == "+" || op == "~"){
1400 			static if(hasStatelessAllocator)
1401 				return this.build(lhs, this.storage.chars);
1402 			else
1403 				return this.build(this._allocator, lhs, this.storage.chars);
1404 		}
1405 
1406 		/// ditto
1407 		public typeof(this) opBinaryRight(string op, Lhs)(scope auto ref const Lhs lhs)scope
1408 		if((op == "+" || op == "~")
1409 			&& (isSomeChar!Lhs || isSomeString!Lhs || isCharArray!Lhs || isIntegral!Lhs)
1410 		){
1411 			static if(hasStatelessAllocator)
1412 				return this.build(forward!lhs, this.storage.chars);
1413 			else
1414 				return this.build(this._allocator, forward!lhs, this.storage.chars);
1415 		}
1416 
1417 
1418 
1419 		/**
1420 			Same as operator `in`
1421 
1422 
1423 			Examples:
1424 				--------------------
1425 				BasicString!char str = "a123読";
1426 
1427 				assert(str.contains('a'));
1428 				assert(!str.contains('b'));
1429 				assert(str.contains('3'));
1430 				assert(str.contains('読'));
1431 				--------------------
1432 		*/
1433 		public bool contains(Elm)(scope auto ref Elm elm)scope const{
1434 			static if(isSomeChar!Elm){
1435 				static if(Elm.sizeof <= CharType.sizeof){
1436 					auto chars = this.storage.chars;
1437 					foreach(c; chars){
1438 						if(elm == c)
1439 							return true;
1440 					}
1441 
1442 					return false;
1443 
1444 				}
1445 				else{
1446 					auto chars = this.storage.chars;
1447 					if(chars.length == 0)
1448 						return false;
1449 
1450 					do{
1451 						if(decode(chars) == elm)
1452 							return true;
1453 					}while(chars.length);
1454 
1455 					return false;
1456 				}
1457 			}
1458 			else{
1459 				static assert(0, "TODO");
1460 			}
1461 		}
1462 
1463 
1464 
1465 		/**
1466 			Operator `in`
1467 
1468 
1469 			Examples:
1470 				--------------------
1471 				BasicString!char str = "a123読";
1472 
1473 				assert('a' in str);
1474 				assert('b' !in str);
1475 				assert('3' in str);
1476 				assert('読' in str);
1477 				--------------------
1478 		*/
1479 		public bool opBinaryRight(string op, Elm)(scope auto ref Elm elm)scope const
1480 		if(op == "in"){
1481 			return this.contains(forward!elm);
1482 		}
1483 
1484 
1485 
1486 		/**
1487 			Calculates the hash value of string.
1488 		*/
1489 		public size_t toHash()const pure nothrow @safe @nogc{
1490 			return hashOf(this.storage.chars);
1491 		}
1492 
1493 
1494 
1495 		/**
1496 			Compares the contents of a string with another string, range, char/wchar/dchar or integer.
1497 
1498 			Returns `true` if they are equal, `false` otherwise
1499 
1500 			Examples:
1501 				--------------------
1502 				BasicString!char str = "123";
1503 
1504 				assert(str == "123");
1505 				assert("123" == str);
1506 
1507 				assert(str == "123"w);
1508 				assert("123"w == str);
1509 
1510 				assert(str == "123"d);
1511 				assert("123"d == str);
1512 
1513 				assert(str == BasicString!wchar("123"));
1514 				assert(BasicString!wchar("123") == str);
1515 
1516 				assert(str == 123);
1517 				assert(123 == str);
1518 
1519 				import std.range : only;
1520 				assert(str == only('1', '2', '3'));
1521 				assert(only('1', '2', '3') == str);
1522 				--------------------
1523 		*/
1524 		public bool opEquals(scope const CharType[] rhs)const scope pure nothrow @safe @nogc{
1525 			return this._op_equals(rhs[]);
1526 		}
1527 
1528 		/// ditto
1529 		public bool opEquals(Rhs)(scope auto ref Rhs rhs)const scope
1530 		if(isBasicString!Rhs || isSomeChar!Rhs || isSomeString!Rhs || isCharArray!Rhs || isIntegral!Rhs || isInputCharRange!Rhs){
1531 
1532 			static if(isBasicString!Rhs){
1533 				return this._op_equals(rhs.storage.chars);
1534 			}
1535 			else static if(isSomeString!Rhs || isCharArray!Rhs){
1536 				return this._op_equals(rhs[]);
1537 			}
1538 			else static if(isSomeChar!Rhs){
1539 				import std.range : only;
1540 				return this._op_equals(only(rhs));
1541 			}
1542 			else static if(isIntegral!Rhs){
1543 				import std.conv : toChars;
1544 				return  this._op_equals(toChars(rhs + 0));
1545 			}
1546 			else static if(isInputRange!Rhs){
1547 				return this._op_equals(rhs);
1548 			}
1549 			else{
1550 				static assert(0, "invalid type '" ~ Rhs.stringof ~ "'");
1551 			}
1552 		}
1553 
1554 		//
1555 		private bool _op_equals(Range)(scope auto ref Range rhs)const scope
1556 		if(isInputCharRange!Range){
1557 			alias RhsChar = Unqual!(ElementEncodingType!Range);
1558 			auto lhs = this.storage.chars;
1559 
1560 			enum bool lengthComperable = hasLength!Range && is(Unqual!CharType == RhsChar);
1561 
1562 			static if(lengthComperable){
1563 				if(lhs.length != rhs.length)
1564 					return false;
1565 			}
1566 			/+TODO: else static if(hasLength!Range){ //TODO
1567 				static if(CharType.sizeof < RhsChar.sizeof){
1568 					if(lhs.length * (RhsChar.sizeof / CharType.sizeof) < rhs.length)
1569 						return false;
1570 				}
1571 				else static if(CharType.sizeof > RhsChar.sizeof){
1572 					if(lhs.length > rhs.length * (CharType.sizeof / RhsChar.sizeof))
1573 						return false;
1574 
1575 				}
1576 				else static assert(0, "no impl")
1577 			}+/
1578 
1579 			while(true){
1580 				static if(lengthComperable){
1581 					if(lhs.length == 0){
1582 						assert(rhs.empty);
1583 						return true;
1584 					}
1585 				}
1586 				else{
1587 					if(lhs.length == 0)
1588 						return rhs.empty;
1589 
1590 					if(rhs.empty)
1591 						return false;
1592 				}
1593 
1594 				static if(is(Unqual!CharType == RhsChar)){
1595 
1596 					const a = lhs.frontCodeUnit;
1597 					lhs.popFrontCodeUnit();
1598 
1599 					const b = rhs.frontCodeUnit;
1600 					rhs.popFrontCodeUnit();
1601 
1602 					static assert(is(Unqual!(typeof(a)) == Unqual!(typeof(b))));
1603 				}
1604 				else{
1605 					const a = decode(lhs);
1606 					const b = decode(rhs);
1607 				}
1608 
1609 				if(a != b)
1610 					return false;
1611 
1612 			}
1613 		}
1614 
1615 
1616 		/**
1617 			Compares the contents of a string with another string, range, char/wchar/dchar or integer.
1618 		*/
1619 		public int opCmp(scope const CharType[] rhs)const scope pure nothrow @safe @nogc{
1620 			return this._op_cmp(rhs[]);
1621 		}
1622 
1623 		/// ditto
1624 		public int opCmp(Rhs)(scope auto ref Rhs rhs)const scope
1625 		if(isBasicString!Rhs || isSomeChar!Rhs || isSomeString!Rhs || isCharArray!Rhs || isIntegral!Rhs || isInputCharRange!Rhs){
1626 
1627 			static if(isBasicString!Rhs){
1628 				return this._op_cmp(rhs.storage.chars);
1629 			}
1630 			else static if(isSomeString!Rhs || isCharArray!Rhs){
1631 				return this._op_cmp(rhs[]);
1632 			}
1633 			else static if(isSomeChar!Rhs){
1634 				import std.range : only;
1635 				return this._op_cmp(only(rhs));
1636 			}
1637 			else static if(isIntegral!Rhs){
1638 				import std.conv : toChars;
1639 				return this._op_cmp(toChars(rhs + 0));
1640 			}
1641 			else static if(isInputRange!Rhs){
1642 				return this._op_cmp(val);
1643 			}
1644 			else{
1645 				static assert(0, "invalid type '" ~ Rhs.stringof ~ "'");
1646 			}
1647 		}
1648 
1649 		//
1650 		private int _op_cmp(Range)(Range rhs)const scope
1651 		if(isInputCharRange!Range){
1652 			import std.range : empty, ElementEncodingType;
1653 
1654 			auto lhs = this.storage.chars;
1655 			alias RhsChar = Unqual!(ElementEncodingType!Range);
1656 
1657 			while(true){
1658 				if(lhs.empty)
1659 					return rhs.empty ? 0 : -1;
1660 
1661 				if(rhs.empty)
1662 					return 1;
1663 
1664 				static if(is(Unqual!CharType == RhsChar)){
1665 
1666 					const a = lhs.frontCodeUnit;
1667 					lhs.popFrontCodeUnit();
1668 
1669 					const b = rhs.frontCodeUnit;
1670 					rhs.popFrontCodeUnit();
1671 
1672 					static assert(is(Unqual!(typeof(a)) == Unqual!(typeof(b))));
1673 				}
1674 				else{
1675 					const a = decode(lhs);
1676 					const b = decode(rhs);
1677 				}
1678 
1679 				if(a < b)
1680 					return -1;
1681 
1682 				if(a > b)
1683 					return 1;
1684 			}
1685 		}
1686 
1687 
1688 
1689 		/**
1690 			Return slice of all character.
1691 
1692 			The slice returned may be invalidated by further calls to other member functions that modify the object.
1693 
1694 			Examples:
1695 				--------------------
1696                 ()@system{
1697                     BasicString!char str = "123";
1698 
1699                     char[] slice = str[];
1700                     assert(slice.length == str.length);
1701                     assert(slice.ptr is str.ptr);
1702 
1703                     str.reserve(str.capacity * 2);
1704                     assert(slice.length == str.length);
1705                     assert(slice.ptr !is str.ptr);  // slice contains dangling pointer.
1706                 }();
1707                 ()@safe{
1708                     FixedString!(char, 20) str = "123";
1709 
1710                     char[] slice = str[];
1711                     assert(slice.length == str.length);
1712                     assert(slice.ptr is str.ptr);
1713 
1714                     assert(slice == "123");
1715                 }();
1716 				--------------------
1717 		*/
1718         static if(allowHeap)
1719 		    public inout(CharType)[] opIndex()inout return pure nothrow @system @nogc{
1720 			    return this.storage.chars;
1721 		    }
1722         else
1723             public inout(CharType)[] opIndex()inout return pure nothrow @trusted @nogc{
1724                 return this.storage.chars;
1725             }
1726 
1727 
1728 
1729 		/**
1730 			Returns character at specified location `pos`.
1731 
1732 			Examples:
1733 				--------------------
1734 				BasicString!char str = "abcd";
1735 
1736 				assert(str[1] == 'b');
1737 				--------------------
1738 		*/
1739 		public CharType opIndex(const size_t pos)const scope pure nothrow @trusted @nogc{
1740 			this._bounds_check(pos);
1741 
1742 			return *(this.ptr + pos);
1743 		}
1744 
1745 
1746 
1747 		/**
1748 			Returns a slice [begin .. end]. If the requested substring extends past the end of the string, the returned slice is [begin .. length()].
1749 
1750 			The slice returned may be invalidated by further calls to other member functions that modify the object.
1751 
1752 			Examples:
1753 				--------------------
1754                 ()@system{
1755                     BasicString!char str = "123456";
1756                     assert(str[1 .. $-1] == "2345");
1757                 }();
1758                 ()@safe{
1759                     FixedString!(char, 20) str = "123456";
1760                     assert(str[1 .. $-1] == "2345");
1761                 }();
1762 				--------------------
1763 		*/
1764         static if(allowHeap)
1765 		    public inout(CharType)[] opSlice(const size_t begin, const size_t end)inout return pure nothrow @system @nogc{
1766 			    this._bounds_check([begin, end]);
1767 			    const len = this.length;
1768 
1769 			    return this.ptr[min(len, begin) .. min(len, end)];
1770 		    }
1771         else
1772             public inout(CharType)[] opSlice(const size_t begin, const size_t end)inout return pure nothrow @trusted @nogc{
1773                 this._bounds_check([begin, end]);
1774                 const len = this.length;
1775 
1776                 return this.ptr[min(len, begin) .. min(len, end)];
1777             }
1778 
1779 
1780 
1781 		/**
1782 			Assign character at specified location `pos` to value `val`.
1783 
1784 			Returns 'val'.
1785 
1786 			Examples:
1787 				--------------------
1788 				BasicString!char str = "abcd";
1789 
1790 				str[1] = 'x';
1791 
1792 				assert(str == "axcd");
1793 				--------------------
1794 		*/
1795 		public CharType opIndexAssign(const CharType val, const size_t pos)scope pure nothrow @trusted @nogc{
1796 			this._bounds_check(pos);
1797 
1798 			return *(this.ptr + pos) = val;
1799 		}
1800 
1801 
1802 
1803 		/**
1804 			Returns the length of the string, in terms of number of characters.
1805 
1806 			Same as `length()`.
1807 		*/
1808 		public size_t opDollar()const scope pure nothrow @safe @nogc{
1809 			return this.length;
1810 		}
1811 
1812 
1813 
1814 		/**
1815 			Swaps the contents of `this` and `rhs`.
1816 
1817 			Examples:
1818 				--------------------
1819 				BasicString!char a = "1";
1820 				BasicString!char b = "2";
1821 
1822 				a.proxySwap(b);
1823 				assert(a == "2");
1824 				assert(b == "1");
1825 
1826 				import std.algorithm.mutation : swap;
1827 
1828 				swap(a, b);
1829 				assert(a == "1");
1830 				assert(b == "2");
1831 				--------------------
1832 		*/
1833 		public void proxySwap(scope ref typeof(this) rhs)scope pure nothrow @trusted @nogc{
1834 			import std.algorithm.mutation : swap;
1835 			swap(
1836 				*(()@trusted => &this.storage )(),
1837 				*(()@trusted => &rhs.storage )()
1838 			);
1839 
1840 			static if(!hasStatelessAllocator)
1841 				swap(
1842 					*(()@trusted => &this._allocator )(),
1843 					*(()@trusted => &rhs._allocator )()
1844 				);
1845 
1846 		}
1847 
1848 
1849 
1850 
1851 		/+public size_t appendMore(Params...)(scope auto ref Params params)scope{
1852 			size_t result = 0;
1853 
1854 			static foreach(alias param; params){
1855 				result += this.append(param);
1856 			}
1857 
1858 			return result;
1859 		}+/
1860 
1861 
1862 
1863 		/**
1864 			Extends the `BasicString` by appending additional characters at the end of string.
1865 
1866 			Return number of inserted characters.
1867 
1868 			Parameters:
1869 				`val` appended value.
1870 
1871 				`count` Number of times `val` is appended.
1872 
1873 			Examples:
1874 				--------------------
1875 				{
1876 					BasicString!char str = "123456";
1877 
1878 					str.append('x', 2);
1879 					assert(str == "123456xx");
1880 				}
1881 
1882 				{
1883 					BasicString!char str = "123456";
1884 
1885 					str.append("abc");
1886 					assert(str == "123456abc");
1887 				}
1888 
1889 				{
1890 					BasicString!char str = "123456";
1891 					BasicString!char str2 = "xyz";
1892 
1893 					str.append(str2);
1894 					assert(str == "123456xyz");
1895 				}
1896 
1897 				{
1898 					BasicString!char str = "12";
1899 
1900 					str.append(+34);
1901 					assert(str == "1234");
1902 				}
1903 				--------------------
1904 		*/
1905 		public size_t append(const CharType[] val, const size_t count = 1)scope{
1906 			return this._append_impl(val, count);
1907 		}
1908 
1909 		/// ditto
1910 		public size_t append(Val)(scope auto ref Val val, const size_t count = 1)scope
1911 		if(isBasicString!Val || isSomeChar!Val || isSomeString!Val || isCharArray!Val || isIntegral!Val){
1912 			static if(isBasicString!Val){
1913 				return this._append_impl(val.storage.chars, count);
1914 			}
1915 			else static if(isSomeString!Val || isCharArray!Val){
1916 				return this._append_impl(val[], count);
1917 			}
1918 			else static if(isSomeChar!Val || isIntegral!Val){
1919 				return this._append_impl(val, count);
1920 			}
1921 			else{
1922 				static assert(0, "invalid type '" ~ Val.stringof ~ "'");
1923 			}
1924 		}
1925 
1926 		/// ditto
1927 		public size_t append(Val)(scope Val val)scope
1928 		if(!isArray!Val && isInputCharRange!Val){
1929 			size_t result = 0;
1930 
1931 			static if(hasLength!Val){
1932 				this.reserve(this.length + val.length);
1933 			}
1934 
1935 			while(!val.empty){
1936 				result += this._append_impl(val.front, 1);
1937 				val.popFront();
1938 			}
1939 
1940 			return result;
1941 		}
1942 
1943 		private size_t _append_impl(Val)(const Val val, const size_t count)scope
1944 		if(isSomeChar!Val || isSomeString!Val || isIntegral!Val){
1945 			if(count == 0)
1946 				return 0;
1947 
1948 			const size_t old_length = this.length;
1949 			const size_t new_count = count * encodedLength!CharType(val);
1950 
1951 			CharType[] new_chars = this._expand(new_count);
1952 			const size_t tmp = val.encodeTo(new_chars, count);
1953 			assert(tmp == new_count);
1954 
1955 			return tmp;
1956 		}
1957 
1958 
1959 
1960 		/**
1961 			Inserts additional characters into the `BasicString` right before the character indicated by `pos` or `ptr`.
1962 
1963 			Return number of inserted characters.
1964 
1965 			If parameters are out of range then there is no inserted value and in debug mode assert throw error.
1966 
1967 			Parameters are out of range if `pos` is larger then `.length` or `ptr` is smaller then `this.ptr` or `ptr` point to address larger then `this.ptr + this.length`
1968 
1969 			Parameters:
1970 				`pos` Insertion point, the new contents are inserted before the character at position `pos`.
1971 
1972 				`ptr` Pointer pointing to the insertion point, the new contents are inserted before the character pointed by ptr.
1973 
1974 				`val` Value inserted before insertion point `pos` or `ptr`.
1975 
1976 				`count` Number of times `val` is inserted.
1977 
1978 			Examples:
1979 				--------------------
1980 				{
1981 					BasicString!char str = "123456";
1982 
1983 					str.insert(2, 'x', 2);
1984 					assert(str == "12xx3456");
1985 				}
1986 
1987 				{
1988 					BasicString!char str = "123456";
1989 
1990 					str.insert(2, "abc");
1991 					assert(str == "12abc3456");
1992 				}
1993 
1994 				{
1995 					BasicString!char str = "123456";
1996 					BasicString!char str2 = "abc";
1997 
1998 					str.insert(2, str2);
1999 					assert(str == "12abc3456");
2000 				}
2001 
2002 				{
2003 					BasicString!char str = "123456";
2004 
2005 					str.insert(str.ptr + 2, 'x', 2);
2006 					assert(str == "12xx3456");
2007 				}
2008 
2009 				{
2010 					BasicString!char str = "123456";
2011 
2012 					str.insert(str.ptr + 2, "abc");
2013 					assert(str == "12abc3456");
2014 				}
2015 
2016 				{
2017 					BasicString!char str = "123456";
2018 					BasicString!char str2 = "abc";
2019 
2020 					str.insert(str.ptr + 2, str2);
2021 					assert(str == "12abc3456");
2022 				}
2023 				--------------------
2024 
2025 		*/
2026 		public size_t insert(const size_t pos, const scope CharType[] val, const size_t count = 1)scope{
2027 			return this._insert(pos, val, count);
2028 		}
2029 
2030 		/// ditto
2031 		public size_t insert(Val)(const size_t pos, auto ref const scope Val val, const size_t count = 1)scope
2032 		if(isBasicString!Val || isSomeChar!Val || isSomeString!Val || isIntegral!Val){
2033 
2034 			static if(isBasicString!Val || isSomeString!Val){
2035 				return this._insert(pos, val[], count);
2036 			}
2037 			else static if(isSomeChar!Val || isIntegral!Val){
2038 				return this._insert(pos, val, count);
2039 			}
2040 			else{
2041 				static assert(0, "invalid type '" ~ Val.stringof ~ "'");
2042 			}
2043 		}
2044 
2045 		/// ditto
2046 		public size_t insert(const CharType* ptr, const scope CharType[] val, const size_t count = 1)scope{
2047 			const size_t pos = this._insert_ptr_to_pos(ptr);
2048 
2049 			return this._insert(pos, val, count);
2050 		}
2051 
2052 		/// ditto
2053 		public size_t insert(Val)(const CharType* ptr, auto ref const scope Val val, const size_t count = 1)scope
2054 		if(isBasicString!Val || isSomeChar!Val || isSomeString!Val || isIntegral!Val){
2055 			const size_t pos = this._insert_ptr_to_pos(ptr);
2056 
2057 			static if(isBasicString!Val || isSomeString!Val){
2058 				return this._insert(pos, val[], count);
2059 			}
2060 			else static if(isSomeChar!Val || isIntegral!Val){
2061 				return this._insert(pos, val, count);
2062 			}
2063 			else{
2064 				static assert(0, "invalid type '" ~ Val.stringof ~ "'");
2065 			}
2066 		}
2067 
2068 		//
2069 		private size_t _insert(Val)(const size_t pos, const Val val, const size_t count)scope
2070 		if(isSomeChar!Val || isSomeString!Val || isIntegral!I){
2071 
2072 			const size_t new_count = count * encodedLength!CharType(val);
2073 			if(new_count == 0)
2074 				return 0;
2075 
2076 			CharType[] new_chars = this._expand_move(pos, new_count);
2077 
2078 			return val.encodeTo(new_chars, count);
2079 		}
2080 
2081 		//
2082 		private size_t _insert_ptr_to_pos(const CharType* ptr)scope const pure nothrow @trusted @nogc{
2083 			return (ptr > this.ptr)
2084 				? (ptr - this.ptr)
2085 				: 0;
2086 		}
2087 
2088 
2089 
2090 		/**
2091 			Removes specified characters from the string.
2092 
2093 			Parameters:
2094 				`pos` position of first character to be removed.
2095 
2096 				`n` number of character to be removed.
2097 
2098 				`ptr` pointer to character to be removed.
2099 
2100 				`slice` sub-slice to be removed, `slice` must be subset of `this`
2101 
2102 			Examples:
2103 				--------------------
2104 				{
2105 					BasicString!char str = "123456";
2106 
2107 					str.erase(2);
2108 					assert(str == "12");
2109 				}
2110 
2111 				{
2112 					BasicString!char str = "123456";
2113 
2114 					str.erase(1, 2);
2115 					assert(str == "1456");
2116 				}
2117 
2118 				{
2119 					BasicString!char str = "123456";
2120 
2121 					str.erase(str.ptr + 2);
2122 					assert(str == "12");
2123 				}
2124 
2125 				{
2126 					BasicString!char str = "123456";
2127 
2128 					str.erase(str[1 .. $-1]);
2129 					assert(str == "16");
2130 				}
2131 				--------------------
2132 		*/
2133 		public void erase(const size_t pos)scope pure nothrow @trusted @nogc{
2134 			this.storage.length = min(this.length, pos);
2135 		}
2136 
2137 		/// ditto
2138 		public void erase(const size_t pos, const size_t n)scope pure nothrow @trusted @nogc{
2139 			const chars = this.storage.chars;
2140 
2141 			if(pos >= this.length)
2142 				return;
2143 
2144 			this._erase(pos, n);
2145 		}
2146 
2147 		/// ditto
2148 		public void erase(scope const CharType* ptr)scope pure nothrow @trusted @nogc{
2149 			const chars = this.storage.chars;
2150 
2151 			if(ptr <= chars.ptr)
2152 				this.storage.length = 0;
2153 			else
2154 				this.storage.length = min(chars.length, ptr - chars.ptr);
2155 		}
2156 
2157 		/// ditto
2158 		public void erase(scope const CharType[] slice)scope pure nothrow @trusted @nogc{
2159 			const chars = this.storage.chars;
2160 
2161 			if(slice.ptr <= chars.ptr){
2162 				const size_t offset = (chars.ptr - slice.ptr);
2163 
2164 				if(slice.length <= offset)
2165 					return;
2166 
2167 				enum size_t pos = 0;
2168 				const size_t len = (slice.length - offset);
2169 
2170 				this._erase(pos, len);
2171 			}
2172 			else{
2173 				const size_t offset = (slice.ptr - chars.ptr);
2174 
2175 				if(chars.length <= offset)
2176 					return;
2177 
2178 				alias pos = offset;
2179 				const size_t len = slice.length;
2180 
2181 				this._erase(pos, len);
2182 
2183 			}
2184 		}
2185 
2186 		//
2187 		private void _erase(const size_t pos, const size_t n)scope pure nothrow @trusted @nogc{
2188 			const len = this.length;
2189 			assert(pos < len);
2190 
2191 			const size_t top = (pos + n);
2192 
2193 			if(top >= len)
2194 				this.storage.length = pos;
2195 			else if(n != 0)
2196 				this._reduce_move(top, n);
2197 		}
2198 
2199 
2200 
2201 		/**
2202 			Replaces the portion of the string that begins at character `pos` and spans `len` characters (or the part of the string in the slice `slice`) by new contents.
2203 
2204 			Parameters:
2205 				`pos` position of the first character to be replaced.
2206 
2207 				`len` number of characters to replace (if the string is shorter, as many characters as possible are replaced).
2208 
2209 				`slice` sub-slice to be removed, `slice` must be subset of `this`
2210 
2211 				`val` inserted value.
2212 
2213 				`count` number of times `val` is inserted.
2214 
2215 			Examples:
2216 				--------------------
2217 				{
2218 					BasicString!char str = "123456";
2219 
2220 					str.replace(2, 2, 'x', 5);
2221 					assert(str == "12xxxxx56");
2222 				}
2223 
2224 				{
2225 					BasicString!char str = "123456";
2226 
2227 					str.replace(2, 2, "abcdef");
2228 					assert(str == "12abcdef56");
2229 				}
2230 
2231 				{
2232 					BasicString!char str = "123456";
2233 					BasicString!char str2 = "xy";
2234 
2235 					str.replace(2, 3, str2);
2236 					assert(str == "12xy56");
2237 				}
2238 
2239 				{
2240 					BasicString!char str = "123456";
2241 
2242 					str.replace(str[2 .. 4], 'x', 5);
2243 					assert(str == "12xxxxx56");
2244 				}
2245 
2246 				{
2247 					BasicString!char str = "123456";
2248 
2249 					str.replace(str[2 .. 4], "abcdef");
2250 					assert(str == "12abcdef56");
2251 				}
2252 
2253 				{
2254 					BasicString!char str = "123456";
2255 					BasicString!char str2 = "xy";
2256 
2257 					str.replace(str[2 .. $], str2);
2258 					assert(str == "12xy56");
2259 				}
2260 				--------------------
2261 		*/
2262 		public ref typeof(this) replace(const size_t pos, const size_t len, scope const CharType[] val, const size_t count = 1)return{
2263 			this._replace(pos, len, val, count);
2264 			return this;
2265 		}
2266 
2267 		/// ditto
2268 		public ref typeof(this) replace(Val)(const size_t pos, const size_t len, scope auto ref const Val val, const size_t count = 1)return
2269 		if(isBasicString!Val || isSomeChar!Val || isSomeString!Val || isIntegral!Val || isCharArray!Val){
2270 
2271 			static if(isBasicString!Val || isSomeString!Val || isCharArray!Val){
2272 				this._replace(pos, len, val[], count);
2273 			}
2274 			else static if(isSomeChar!Val || isIntegral!Val){
2275 				this._replace(pos, len, val, count);
2276 			}
2277 			else{
2278 				static assert(0, "invalid type '" ~ Val.stringof ~ "'");
2279 			}
2280 
2281 			return this;
2282 		}
2283 
2284 		/// ditto
2285 		public ref typeof(this) replace(scope const CharType[] slice, scope const CharType[] val, const size_t count = 1)return{
2286 			this._replace(slice, val, count);
2287 			return this;
2288 		}
2289 
2290 		/// ditto
2291 		public ref typeof(this) replace(Val)(scope const CharType[] slice, scope auto ref const Val val, const size_t count = 1)return
2292 		if(isBasicString!Val || isSomeChar!Val || isSomeString!Val || isIntegral!Val || isCharArray!Val){
2293 
2294 			static if(isBasicString!Val || isSomeString!Val || isCharArray!Val){
2295 				this._replace(slice, val[], count);
2296 			}
2297 			else static if(isSomeChar!Val || isIntegral!Val){
2298 				this._replace(slice, val, count);
2299 			}
2300 			else{
2301 				static assert(0, "invalid type '" ~ Val.stringof ~ "'");
2302 			}
2303 
2304 			return this;
2305 		}
2306 
2307 		//
2308 		private void _replace(Val)(scope const CharType[] slice, scope const Val val, const size_t count)scope
2309 		if(isSomeChar!Val || isSomeString!Val || isIntegral!Val){
2310 			const chars = this.storage.chars;
2311 
2312 			if(slice.ptr < chars.ptr){
2313 				const size_t offset = (()@trusted => chars.ptr - slice.ptr)();
2314 				const size_t pos = 0;
2315 				const size_t len = (slice.length > offset)
2316 					? (slice.length - offset)
2317 					: 0;
2318 
2319 				this.replace(pos, len, val, count);
2320 			}
2321 			else{
2322 				const size_t offset = (()@trusted => slice.ptr - chars.ptr)();
2323 				const size_t pos = offset;
2324 				const size_t len = slice.length;
2325 
2326 				this.replace(pos, len, val, count);
2327 			}
2328 		}
2329 
2330 		//
2331 		private void _replace(Val)(const size_t pos, const size_t len, scope const Val val, const size_t count)scope
2332 		if(isSomeChar!Val || isSomeString!Val || isIntegral!Val){
2333 
2334 			const size_t new_count = count * encodedLength!CharType(val);
2335 			if(new_count == 0){
2336 				if(pos < this.length)
2337 					this.erase(pos, len);
2338 
2339 				return;
2340 			}
2341 
2342 			assert(new_count != 0);
2343 
2344 			auto chars = this.storage.chars;
2345 			const size_t old_length = chars.length;
2346 			const size_t begin = min(pos, chars.length);    //alias begin = pos;
2347 
2348 			const size_t end = min(chars.length, (pos + len));
2349 			const size_t new_len = min(end - begin, new_count);
2350 			//const size_t new_len = min(len, new_count);
2351 			//const size_t end = (begin + new_len);
2352 
2353 
2354 			if(begin == end){
2355 				///insert:
2356 				CharType[] new_chars = this._expand_move(begin, new_count);
2357 				const x = val.encodeTo(new_chars, count);
2358 				assert(x == new_count);
2359 
2360 			}
2361 			else if(new_count == new_len){
2362 				///exact assign:
2363 				const x = val.encodeTo(chars[begin .. end], count);
2364 				assert(x == new_count);
2365 			}
2366 			else if(new_count < new_len){
2367 				///asign + erase:
2368 				const x = val.encodeTo(chars[begin .. end], count);
2369 				assert(x == new_count);
2370 
2371 				()@trusted{
2372 					this._reduce_move(end, (new_len - new_count));
2373 				}();
2374 			}
2375 			else{
2376 				///asing + expand(insert):
2377 				assert(new_count > new_len);
2378 
2379 				const size_t expand_len = (new_count - new_len);
2380 
2381 				CharType[] new_chars = this._expand_move(end, expand_len);
2382 
2383 				const x = val.encodeTo((()@trusted => (new_chars.ptr - new_len)[0 .. new_count])(), count);
2384 				assert(x == new_count);
2385 			}
2386 		}
2387 
2388 
2389 		///Alias to append.
2390 		public alias put = append;
2391 
2392 		///Alias to `popBackCodeUnit`.
2393 		public alias popBack = popBackCodeUnit;
2394 
2395 		///Alias to `frontCodeUnit`.
2396 		public alias front = frontCodeUnit;
2397 
2398 		///Alias to `backCodeUnit`.
2399 		public alias back = backCodeUnit;
2400 
2401 
2402 		/**
2403 			Static function which return `BasicString` construct from arguments `args`.
2404 
2405 			Parameters:
2406 				`allocator` exists only if template parameter `_Allocator` has state.
2407 
2408 				`args` values of type `char|wchar|dchar` array/slice/character or `BasicString`.
2409 
2410 			Examples:
2411 				--------------------
2412 				BasicString!char str = BasicString!char.build('1', cast(dchar)'2', "345"d, BasicString!wchar("678"));
2413 
2414 				assert(str == "12345678");
2415 				--------------------
2416 		*/
2417 		public static typeof(this) build(Args...)(scope auto ref const Args args)
2418 		if(Args.length > 0 && !is(immutable Args[0] == immutable AllocatorType)){
2419 			import core.lifetime : forward;
2420 
2421 			auto result = BasicString.init;
2422 
2423 			result._build_impl(forward!args);
2424 
2425 			//return move(result);
2426 			return (()@trusted => move(*&result) )();
2427 		}
2428 
2429 		/// ditto
2430 		public static typeof(this) build(Args...)(AllocatorType allocator, scope auto ref const Args args){
2431 			import core.lifetime : forward;
2432 
2433 			auto result = BasicString(forward!allocator);
2434 
2435 			result._build_impl(forward!args);
2436 
2437 			//return move(result);
2438 			return (()@trusted => move(*&result) )();
2439 		}
2440 
2441 		private void _build_impl(Args...)(scope auto ref const Args args)scope{
2442 			import std.traits : isArray;
2443 
2444 			assert(this.empty);
2445 			//this.clear();
2446 			size_t new_length = 0;
2447 
2448 			static foreach(enum I, alias Arg; Args){
2449 				static if(isBasicString!Arg)
2450 					new_length += encodedLength!CharType(args[I].storage.chars);
2451 				else static if(isArray!Arg &&  isSomeChar!(ElementEncodingType!Arg))
2452 					new_length += encodedLength!CharType(args[I][]);
2453                 else static if(isSomeChar!Arg)
2454                     new_length += encodedLength!CharType(args[I]);
2455                 else static if(isIntegral!Arg)
2456                     new_length += encodedLength!CharType(args[I]);
2457 				else static assert(0, "wrong type '" ~ typeof(args[I]).stringof ~ "'");
2458 			}
2459 
2460 			if(new_length == 0)
2461 				return;
2462 
2463 
2464 			alias result = this;
2465 
2466 			result.reserve(new_length);
2467 
2468 			CharType[] data = result.storage.allocatedChars;
2469 
2470 			static foreach(enum I, alias Arg; Args){
2471 				static if(isBasicString!Arg)
2472 					data = data[args[I].storage.chars.encodeTo(data) .. $];
2473 				else static if(isArray!Arg)
2474 					data = data[args[I][].encodeTo(data) .. $];
2475                 else static if(isSomeChar!Arg)
2476                     data = data[args[I].encodeTo(data) .. $];
2477                 else static if(isIntegral!Arg)
2478                     data = data[args[I].encodeTo(data) .. $];
2479 				else static assert(0, "wrong type '" ~ Arg.stringof ~ "'");
2480 			}
2481 
2482 			result.storage.length = new_length;
2483 		}
2484 
2485 
2486 
2487 		public immutable(CharType)[] toGcString()scope const pure nothrow @trusted{
2488 			return this[].idup;
2489 		}
2490 
2491 
2492 
2493 		static if(!allowHeap){
2494 			private alias _allocator = statelessAllcoator!NullAllocator;
2495 			private enum safeAllocate = true;
2496 		}
2497 		else static if(hasStatelessAllocator){
2498 			public alias _allocator = statelessAllcoator!AllocatorType;
2499 
2500 			private enum safeAllocate = isSafe!((){
2501 				size_t capacity = size_t.max;
2502 
2503 				cast(void)_allocator.allocate(capacity);
2504 			});
2505 		}
2506 		else{
2507 			public AllocatorType _allocator;
2508 
2509 			private enum safeAllocate = isSafe!((ref AllocatorType a){
2510 				size_t capacity = size_t.max;
2511 
2512 				cast(void)a.allocate(capacity);
2513 			});
2514 		}
2515 
2516 		private Storage storage;
2517 
2518 		//grow:
2519 		private static size_t _grow_capacity(size_t old_capacity, size_t new_capacity)pure nothrow @safe @nogc{
2520 			static if(minimalCapacity == 0)
2521 				return max(2, old_capacity * 2, new_capacity);
2522 			else
2523 				return max(old_capacity * 2, new_capacity);
2524 		}
2525 
2526 		//enforce:
2527 		private void _enforce(bool con, string msg)const pure nothrow @safe @nogc{
2528 			if(!con)assert(0, msg);
2529 		}
2530 
2531 		//allocation:
2532 		private void _allocate_heap()(ref Storage.Heap heap, size_t new_capacity){
2533 			new_capacity = Storage.heapCapacity(new_capacity);  //assert(new_capacity == storage.heapCapacity(new_capacity));
2534 
2535 			void[] data = this._allocator.allocate(new_capacity * CharType.sizeof);
2536 
2537 			_enforce(data.length != 0, "allocation fail");
2538 
2539 			heap.ptr = (()@trusted => cast(CharType*)data.ptr )();
2540 			heap.capacity = new_capacity;
2541 			heap.length = length;
2542 		}
2543 
2544 		private void _deallocate_heap()(const ref Storage.Heap heap){
2545 			void[] data = (()@trusted => cast(void[])heap.data )();
2546 
2547 			static if(N == 0){
2548 				if(data.length == 0)
2549 					return;
2550 			}
2551 
2552 			static if(safeAllocate)
2553 				const d = ()@trusted{
2554 					return this._allocator.deallocate(data);
2555 				}();
2556 			else
2557 				const d = this._allocator.deallocate(data);
2558 
2559 			_enforce(d, "deallocation fail");
2560 		}
2561 
2562 		private void _reallocate_heap(bool optional = false)(ref Storage.Heap heap, size_t new_capacity){
2563 			new_capacity = Storage.heapCapacity(new_capacity);  //assert(new_capacity == storage.heapCapacity(new_capacity));
2564 			void[] data = heap.data;
2565 
2566 			static if(hasMember!(typeof(_allocator), "reallocate")){
2567 				static if(safeAllocate)
2568 					const bool reallocated = ()@trusted{
2569 						return this._allocator.reallocate(data, new_capacity * CharType.sizeof);
2570 					}();
2571 				else
2572 					const bool reallocated = this._allocator.reallocate(data, new_capacity * CharType.sizeof);
2573 			}
2574 			else{
2575 				const bool reallocated = false;
2576 			}
2577 
2578 			if(reallocated){
2579 				()@trusted{
2580 					heap.ptr = cast(CharType*)data.ptr;
2581 					heap.capacity = new_capacity;
2582 
2583 				}();
2584 				assert(data.length / CharType.sizeof == new_capacity);
2585 				return;
2586 			}
2587 
2588 			static if(!optional){
2589 				Storage.Heap heap_new;
2590 
2591 				{
2592 					this._allocate_heap(heap_new, new_capacity);
2593 
2594 					memCopy(heap_new.ptr, heap.ptr, heap.length);
2595 					heap_new.length = heap.length;
2596 				}
2597 
2598 				this._deallocate_heap(heap);
2599 
2600 				heap = heap_new;
2601 			}
2602 		}
2603 
2604 		//reduce/expand:
2605 		private void _reduce_move(const size_t pos, const size_t n)scope pure nothrow @system @nogc{
2606 			assert(pos  <= this.length);
2607 			assert(pos >= n);
2608 			assert(n > 0);
2609 
2610 			auto chars = this.storage.chars;
2611 			const size_t len = (chars.length - pos);
2612 
2613 			memMove(
2614 				chars.ptr + (pos - n),
2615 				(chars.ptr + pos),
2616 				len
2617 			);
2618 
2619 			this.storage.length = (chars.length - n);
2620 		}
2621 
2622 		private CharType[] _expand_move(const size_t pos, const size_t n)scope return {
2623 			assert(n > 0);
2624 
2625 			auto chars = this.storage.chars;
2626 			if(pos >= chars.length)
2627 				return this._expand(n);
2628 
2629 			const size_t new_length = (chars.length + n);
2630 			this.reserve(new_length);
2631 
2632 
2633 			return ()@trusted{
2634 				auto chars = this.storage.chars;
2635 				this.storage.length = new_length;
2636 
2637 				const size_t len = (chars.length - pos);
2638 
2639 				memMove(
2640 					(chars.ptr + pos + n),
2641 					(chars.ptr + pos),
2642 					len
2643 				);
2644 
2645 				return (chars.ptr + pos)[0 .. n];
2646 			}();
2647 		}
2648 
2649 		private CharType[] _expand(const size_t n)scope return{
2650 			const size_t old_length = this.length;
2651 			const size_t new_length = (old_length + n);
2652 
2653 			this.reserve(new_length);
2654 
2655 			return ()@trusted{
2656 				this.storage.length = new_length;
2657 				return this.storage.ptr[old_length .. new_length];
2658 			}();
2659 		}
2660 
2661 		//bounds check:
2662 		private pragma(inline, true) void _bounds_check(const size_t pos)const pure nothrow @safe @nogc{
2663 			assert(pos < this.length);
2664 
2665 			version(BTL_STRING_BOUNDS_CHECK){
2666 				if(pos >= this.length){
2667 					assert(0, "btl.string bounds check error");
2668 				}
2669 			}
2670 		}
2671 
2672 		private pragma(inline, true) void _bounds_check(const size_t pos, const size_t len)const pure nothrow @safe @nogc{
2673 			assert(pos < this.length);
2674 			assert((pos + len) <= this.length);
2675 
2676 			version(BTL_STRING_BOUNDS_CHECK){
2677 				if(pos >= this.length){
2678 					assert(0, "btl.string bounds check error");
2679 				}
2680 				if((pos + len) > this.length){
2681 					assert(0, "btl.string bounds check error");
2682 				}
2683 			}
2684 		}
2685 
2686 		private pragma(inline, true) void _bounds_check(const size_t[2] index)const pure nothrow @safe @nogc{
2687 			assert(index[0] < this.length);
2688 			assert(index[1] <= this.length);
2689 
2690 			version(BTL_STRING_BOUNDS_CHECK){
2691 				if(index[0] >= this.length){
2692 					assert(0, "btl.string bounds check error");
2693 				}
2694 				if(index[1] > this.length){
2695 					assert(0, "btl.string bounds check error");
2696 				}
2697 			}
2698 		}
2699 
2700 	}
2701 }
2702 
2703 
2704 ///
2705 pure nothrow @safe @nogc unittest {
2706 	alias String = BasicString!(
2707 		char,               //character type
2708 		32,                 //additional padding to increas max size of small string (small string does not allocate memory).
2709 		DefaultAllocator    //allocator type (can be stateless or with state)
2710 	);
2711 
2712 
2713 	//copy:
2714 	{
2715 		String a = "123";
2716 		String b = a;
2717 
2718 		a = "456"d;
2719 
2720 		assert(a == "456");
2721 		assert(b == "123");
2722 	}
2723 
2724 
2725 	//append:
2726 	{
2727 		String str = "12";
2728 
2729 		str.append("34");   //same as str += "34"
2730 		str.append("56"w);  //same as str += "56"w
2731 		str.append(7);      //same as str += 7;
2732 		str.append('8');
2733 
2734 		assert(str == "12345678");
2735 
2736 		str.clear();
2737 
2738 		assert(str.empty);
2739 	}
2740 
2741 	//erase:
2742 	{
2743 		String str = "123456789";
2744 
2745 		str.erase(2, 2);
2746 
2747 		assert(str == "1256789");
2748 	}
2749 
2750 	//insert:
2751 	{
2752 		String str = "123456789";
2753 
2754 		str.insert(1, "xyz");
2755 
2756 		assert(str == "1xyz23456789");
2757 	}
2758 
2759 	//replace:
2760 	{
2761 		String str = "123456789";
2762 
2763 		str.replace(1, 2, "xyz");
2764 
2765 		assert(str == "1xyz456789");
2766 	}
2767 
2768 	//slice to string:
2769 	()@trusted{
2770 		String str = "123456789";
2771 
2772 		const(char)[] dstr = str[];
2773 
2774 		assert(str == dstr);
2775 	}();
2776 }
2777 
2778 
2779 /**
2780 	Alias to `BasicString` with different order of template parameters
2781 */
2782 template BasicString(
2783 	_Char,
2784 	_Allocator,
2785 	size_t N = 1
2786 )
2787 if(isSomeChar!_Char && is(Unqual!_Char == _Char)){
2788 	alias BasicString = .BasicString!(_Char, N, _Allocator);
2789 }
2790 
2791 
2792 
2793 
2794 
2795 /**
2796 	Alias to `BasicString` with `void` allcoator (fixed capacity to `N` characters).
2797 */
2798 alias FixedString(Char, size_t N) = BasicString!(Char, N, void);
2799 
2800 
2801 
2802 /**
2803 	Alias to `BasicString` with forced small string optimization fot min `N` characters.
2804 */
2805 alias SmallString(Char, size_t N, _Allocator = DefaultAllocator) = BasicString!(Char, max(N, 1), _Allocator);
2806 
2807 
2808 
2809 /**
2810 	Alias to `BasicString` without small string optimization (`N` == 0).
2811 */
2812 alias LargeString(Char, _Allocator = DefaultAllocator) = BasicString!(Char, 0, _Allocator);
2813 
2814 
2815 
2816 /**
2817 	Standard string type (alias to `BasicString!char`).
2818 */
2819 alias String = BasicString!char;
2820 
2821 
2822 
2823 //local traits:
2824 private {
2825 
2826 	//copy ctor: (TODO not in use for now)
2827 	template hasCopyConstructor(From, To)
2828 	if(is(immutable From == immutable To)){
2829 
2830 		enum bool hasCopyConstructor = true
2831 			&& !is(From == shared)
2832 			&& isConstructable!(From, To)
2833 			&& (From.hasStatelessAllocator 
2834 				|| isCopyConstructableElement!(
2835 					GetAllocatorType!From,
2836 					GetAllocatorType!To
2837 				)
2838 			)
2839 			&& (From.hasStatelessAllocator 
2840 				|| isCopyConstructableElement!(
2841 					GetAllocatorType!From,
2842 					To.AllocatorType
2843 				)
2844 			);
2845 	}
2846 
2847 	//Move Constructable:
2848 	template isMoveConstructable(alias from, To){
2849 		alias From = typeof(from);
2850 
2851 		enum bool isMoveConstructable = true
2852 			&& !isRef!from
2853 			&& isConstructable!(From, To)
2854 			&& is(GetCharType!From*: GetCharType!To*)
2855 			//&& (From.minimalCapacity == To.minimalCapacity)	//TODO remove
2856 			&& is(immutable From.AllocatorType == immutable To.AllocatorType)
2857 			&& (From.hasStatelessAllocator 
2858 				|| isMoveConstructableElement!(
2859 						GetAllocatorType!From,
2860 						GetAllocatorType!To
2861 				)
2862 			);
2863 	}
2864 
2865 	//Move Assignable:
2866 	template isMoveAssignable(alias from, To){
2867 		alias From = typeof(from);
2868 
2869 		enum isMoveAssignable = true
2870 			&& !isRef!from
2871 			&& isAssignable!(From, To)   
2872 			&& is(GetCharType!From*: GetCharType!To*)
2873 			//&& (From.minimalCapacity == To.minimalCapacity)	//TODO remove
2874 			&& is(immutable From.AllocatorType == immutable To.AllocatorType)
2875 			&& (From.hasStatelessAllocator 
2876 				|| isMoveAssignableElement!(
2877 						GetAllocatorType!From,
2878 						GetAllocatorType!To
2879 				)
2880 			);
2881 	}
2882 	
2883 	//Constructable:
2884 	template isConstructable(From, To){
2885 
2886 		enum isConstructable = true
2887 			&& !is(From == shared)
2888 			&& (From.hasStatelessAllocator
2889 				? is(immutable From.AllocatorType == immutable To.AllocatorType)
2890 				: is(immutable From.AllocatorType : immutable To.AllocatorType)
2891 			);
2892 	}
2893 
2894 	//Assignable:
2895 	template isAssignable(From, To){
2896 		import std.traits : isMutable;
2897 
2898 		enum bool isAssignable = true
2899 			&& isMutable!To
2900 			&& !is(From == shared) && !is(To == shared);
2901 	}
2902 
2903 
2904 	template GetCharType(Vec){
2905 		alias GetCharType = CopyTypeQualifiers!(Vec, Vec.CharType);
2906 	}
2907 
2908 	template GetAllocatorType(Vec){
2909 		alias GetAllocatorType = CopyTypeQualifiers!(Vec, Vec.AllocatorType);
2910 	}
2911 
2912 }
2913 
2914 //encoding:
2915 private{
2916 
2917 	size_t encodedLength(_Char, From)(const scope From from)pure nothrow @nogc @safe
2918 	if(isSomeChar!_Char && isSomeChar!From){
2919 		return codeLength!_Char(from);
2920 	}
2921 
2922 	size_t encodedLength(_Char, From)(scope const(From)[] from)pure nothrow @nogc @safe
2923 	if(isSomeChar!_Char && isSomeChar!From){
2924 		static if(_Char.sizeof == From.sizeof){
2925 			return from.length;
2926 		}
2927 		else static if(_Char.sizeof < From.sizeof){
2928 			size_t result = 0;
2929 
2930 			foreach(const From c; from[]){
2931 				result += c.encodedLength!_Char;
2932 			}
2933 
2934 			return result;
2935 		}
2936 		else{
2937 			static assert(_Char.sizeof > From.sizeof);
2938 
2939 			size_t result = 0;
2940 
2941 			while(from.length){
2942 				result += decode(from).encodedLength!_Char;
2943 			}
2944 
2945 			return result;
2946 		}
2947 
2948 	}
2949 
2950 	size_t encodedLength(_Char, From)(const From from)pure nothrow @nogc @safe
2951 	if(isSomeChar!_Char && isIntegral!From){
2952 		import std.math : log10, abs;
2953 
2954 		if(from == 0)
2955 			return 1;
2956 
2957 		return cast(size_t)(cast(int)(log10(abs(from))+1) + (from < 0 ? 1 : 0));
2958 
2959 	}
2960 
2961 
2962 
2963 	size_t encodeTo(_Char, From)(scope const(From)[] from, scope _Char[] to, const size_t count = 1)pure nothrow @nogc
2964 	if(isSomeChar!_Char && isSomeChar!From){
2965 
2966 		if(count == 0)
2967 			return 0;
2968 
2969 		assert(from.encodedLength!_Char * count <= to.length);
2970 
2971 		debug const predictedEncodedLength = encodedLength!_Char(from);
2972 
2973 		static if(_Char.sizeof == From.sizeof){
2974 
2975 			const size_t len = from.length;
2976 			()@trusted{
2977 				assert(to.length >= len);
2978 				assert(from.length <= len);
2979 				memCopy(to.ptr, from.ptr, len); //to[0 .. len] = from[];
2980 			}();
2981 
2982 		}
2983 		else{
2984 
2985 			size_t len = 0;
2986 			while(from.length){
2987 				len += decode(from).encode(to[len .. $]);
2988 			}
2989 		}
2990 
2991 		debug assert(predictedEncodedLength == len);
2992 
2993 		for(size_t i = 1; i < count; ++i){
2994 			//to[len .. len * 2] = to[0 .. len];
2995 			()@trusted{
2996 				assert(to.length >= (len * 2));
2997 				memCopy(to.ptr + len, to.ptr, len); //to[0 .. len] = from[];
2998 			}();
2999 			to = to[len .. $];
3000 		}
3001 
3002 		return (len * count);
3003 	}
3004 
3005 	size_t encodeTo(_Char, From)(const From from, scope _Char[] to, const size_t count = 1)pure nothrow @nogc
3006 	if(isSomeChar!_Char && isSomeChar!From){
3007 
3008 		if(count == 0)
3009 			return 0;
3010 
3011 		assert(from.encodedLength!_Char * count <= to.length);
3012 
3013 		debug const predictedEncodedLength = encodedLength!_Char(from);
3014 
3015 		static if(_Char.sizeof == From.sizeof){
3016 			enum size_t len = 1;
3017 
3018 			assert(count <= to.length);
3019 			for(size_t i = 0; i < count; ++i){
3020 				to[i] = from;
3021 			}
3022 		}
3023 		else{
3024 			const size_t len = dchar(from).encode(to[]);
3025 
3026 			for(size_t i = 1; i < count; ++i){
3027 				//to[len .. len * 2] = to[0 .. len];
3028 				()@trusted{
3029 					assert(to.length >= (len * 2));
3030 					memCopy(to.ptr + len, to.ptr, len); //to[0 .. len] = from[];
3031 				}();
3032 				to = to[len .. $];
3033 			}
3034 
3035 			assert(encodedLength!_Char(from) == len);
3036 		}
3037 
3038 		debug assert(predictedEncodedLength == len);
3039 
3040 		return (len * count);
3041 	}
3042 
3043 	size_t encodeTo(_Char, From)(const From from, scope _Char[] to, const size_t count = 1)pure nothrow @nogc @safe
3044 	if(isSomeChar!_Char && isIntegral!From){
3045 		import std.conv : toChars;
3046 
3047 		if(count == 0)
3048 			return 0;
3049 
3050 		auto ichars = toChars(from + 0);
3051 
3052 		assert(encodedLength!_Char(from) == ichars.length);
3053 
3054 		for(size_t c = 0; c < count; ++c){
3055 			for(size_t i = 0; i < ichars.length; ++i)
3056 				to[c+i] = ichars[i];
3057 		}
3058 
3059 		return (ichars.length * count);
3060 
3061 
3062 	}
3063 }
3064 
3065 
3066 //mem[move|copy]
3067 private{
3068 	void memMove(T)(scope T* target, scope const(T)* source, size_t length)@trusted{
3069 		import core.stdc.string : memmove;
3070 
3071 		memmove(target, source, length * T.sizeof);
3072 		/+version(D_BetterC){
3073 			import core.stdc.string : memmove;
3074 
3075 			memmove(target, source, length * T.sizeof);
3076 		}
3077 		else{
3078 			target[0 .. length] = source[0 .. length];
3079 		}+/
3080 	}
3081 
3082 	void memCopy(T)(scope T* target, scope const(T)* source, size_t length)@trusted{
3083 		import core.stdc.string : memcpy;
3084 
3085 		memcpy(target, source, length * T.sizeof);
3086 		/+
3087 		version(D_BetterC){
3088 			import core.stdc.string : memcpy;
3089 
3090 			memcpy(target, source, length * T.sizeof);
3091 		}
3092 		else{
3093 			target[0 .. length] = source[0 .. length];
3094 		}+/
3095 	}
3096 }
3097 
3098 //range frontCodeUnit & popFrontCodeUnit:
3099 private{
3100 	auto frontCodeUnit(Range)(auto ref Range r){
3101 		import std.traits : isAutodecodableString;
3102 
3103 		static if(isAutodecodableString!Range){
3104 			assert(r.length > 0);
3105 			return r[0];
3106 		}
3107 		else{
3108 			import std.range.primitives : front;
3109 			return  r.front;
3110 		}
3111 	}
3112 
3113 	void popFrontCodeUnit(Range)(ref Range r){
3114 		import std.traits : isAutodecodableString;
3115 
3116 		static if(isAutodecodableString!Range){
3117 			assert(r.length > 0);
3118 			r = r[1 .. $];
3119 		}
3120 		else{
3121 			import std.range.primitives : popFront;
3122 			return  r.popFront;
3123 		}
3124 	}
3125 }
3126 
3127 
3128 //doc:
3129 version(unittest){
3130 	//doc.minimalCapacity:
3131 	pure nothrow @safe @nogc unittest{
3132 		BasicString!char str;
3133 		assert(str.empty);
3134 		assert(str.capacity == BasicString!char.minimalCapacity);
3135 		assert(str.capacity > 0);
3136 	}
3137 
3138 	//doc.empty:
3139 	pure nothrow @safe @nogc unittest{
3140 		BasicString!char str;
3141 		assert(str.empty);
3142 
3143 		str = "123";
3144 		assert(!str.empty);
3145 	}
3146 
3147 	//doc.full:
3148 	pure nothrow @safe @nogc unittest{
3149 		BasicString!(char, 1, void) str;	//FixedString
3150 		assert(str.empty);
3151 		assert(str.minimalCapacity > 0);
3152 		assert(!str.full);
3153 
3154 		str.resize(str.maximalCapacity);
3155 		assert(str.full);
3156 	}
3157 
3158 	//doc.length:
3159 	pure nothrow @safe @nogc unittest{
3160 		BasicString!char str = "123";
3161 		assert(str.length == 3);
3162 
3163 		BasicString!wchar wstr = "123";
3164 		assert(wstr.length == 3);
3165 
3166 		BasicString!dchar dstr = "123";
3167 		assert(dstr.length == 3);
3168 	}
3169 
3170 	//doc.capacity:
3171 	pure nothrow @safe @nogc unittest{
3172 		BasicString!char str;
3173 		assert(str.capacity == BasicString!char.minimalCapacity);
3174 
3175 		str.reserve(str.capacity + 1);
3176 		assert(str.capacity > BasicString!char.minimalCapacity);
3177 	}
3178 
3179 	//doc.ptr:
3180 	pure nothrow @system @nogc unittest{
3181 		BasicString!char str = "123";
3182 		char* ptr = str.ptr;
3183 		assert(ptr[0 .. 3] == "123");
3184 	}
3185 
3186 	//doc.frontCodePoint:
3187 	pure nothrow @safe @nogc unittest{
3188 		BasicString!char str = "á123";
3189 
3190 		assert(str.frontCodePoint == 'á');
3191 	}
3192 
3193 	//doc.frontCodeUnit:
3194 	pure nothrow @safe @nogc unittest{
3195 		{
3196 			BasicString!char str = "123";
3197 
3198 			assert(str.frontCodeUnit == '1');
3199 		}
3200 
3201 		{
3202 			BasicString!char str = "á23";
3203 
3204 			immutable(char)[2] a = "á";
3205 			assert(str.frontCodeUnit == a[0]);
3206 		}
3207 
3208 		{
3209 			BasicString!char str = "123";
3210 
3211 			str.frontCodeUnit = 'x';
3212 
3213 			assert(str == "x23");
3214 		}
3215 	}
3216 
3217 	//doc.backCodePoint:
3218 	pure nothrow @safe @nogc unittest{
3219 		{
3220 			BasicString!char str = "123á";
3221 
3222 			assert(str.backCodePoint == 'á');
3223 		}
3224 
3225 		{
3226 			BasicString!char str = "123á";
3227 			str.backCodePoint = '4';
3228 			assert(str == "1234");
3229 		}
3230 	}
3231 
3232 	//doc.backCodeUnit:
3233 	pure nothrow @safe @nogc unittest{
3234 		{
3235 			BasicString!char str = "123";
3236 
3237 			assert(str.backCodeUnit == '3');
3238 		}
3239 
3240 		{
3241 			BasicString!char str = "12á";
3242 
3243 			immutable(char)[2] a = "á";
3244 			assert(str.backCodeUnit == a[1]);
3245 		}
3246 
3247 		{
3248 			BasicString!char str = "123";
3249 
3250 			str.backCodeUnit = 'x';
3251 			assert(str == "12x");
3252 		}
3253 	}
3254 
3255 	//doc.popBackCodePoint:
3256 	pure nothrow @safe @nogc unittest{
3257 		{
3258 			BasicString!char str = "á1";    //'á' is encoded as 2 chars
3259 
3260 			assert(str.popBackCodePoint == 1);
3261 			assert(str == "á");
3262 
3263 			assert(str.popBackCodePoint == 2);
3264 			assert(str.empty);
3265 
3266 			assert(str.popBackCodePoint == 0);
3267 			assert(str.empty);
3268 		}
3269 
3270 		{
3271 			BasicString!char str = "1á";    //'á' is encoded as 2 chars
3272 			assert(str.length == 3);
3273 
3274 			str.erase(str.length - 1);
3275 			assert(str.length == 2);
3276 
3277 			assert(str.popBackCodePoint == 0);   //popBackCodePoint cannot remove invalid code points
3278 			assert(str.length == 2);
3279 		}
3280 	}
3281 
3282 	//doc.popBackCodeUnit:
3283 	pure nothrow @safe @nogc unittest{
3284 		BasicString!char str = "á1";    //'á' is encoded as 2 chars
3285 		assert(str.length == 3);
3286 
3287 		assert(str.popBackCodeUnit);
3288 		assert(str.length == 2);
3289 
3290 		assert(str.popBackCodeUnit);
3291 		assert(str.length == 1);
3292 
3293 		assert(str.popBackCodeUnit);
3294 		assert(str.empty);
3295 
3296 		assert(!str.popBackCodeUnit);
3297 		assert(str.empty);
3298 
3299 	}
3300 
3301 	//doc.clear:
3302 	pure nothrow @safe @nogc unittest{
3303 		BasicString!char str = "123";
3304 
3305 		str.reserve(str.capacity * 2);
3306 		assert(str.length == 3);
3307 
3308 		const size_t cap = str.capacity;
3309 		str.clear();
3310 		assert(str.capacity == cap);
3311 
3312 	}
3313 
3314 	//doc.release:
3315 	pure nothrow @safe @nogc unittest{
3316 		BasicString!char str = "123";
3317 
3318 		str.reserve(str.capacity * 2);
3319 		assert(str.length == 3);
3320 
3321 		const size_t cap = str.capacity;
3322 		str.clear();
3323 		assert(str.capacity == cap);
3324 
3325 		str.release();
3326 		assert(str.capacity < cap);
3327 		assert(str.capacity == BasicString!char.minimalCapacity);
3328 
3329 	}
3330 
3331 	//doc.reserve:
3332 	pure nothrow @safe @nogc unittest{
3333 		BasicString!char str = "123";
3334 		assert(str.capacity == BasicString!char.minimalCapacity);
3335 
3336 		const size_t cap = (str.capacity * 2);
3337 		str.reserve(cap);
3338 		assert(str.capacity > BasicString!char.minimalCapacity);
3339 		assert(str.capacity >= cap);
3340 
3341 	}
3342 
3343 	//doc.reserve:
3344 	pure nothrow @safe @nogc unittest{
3345 		BasicString!char str = "123";
3346 		assert(str.capacity == BasicString!char.minimalCapacity);
3347 
3348 		const size_t cap = (str.capacity * 2);
3349 		str.reserve(cap);
3350 		assert(str.capacity > BasicString!char.minimalCapacity);
3351 		assert(str.capacity >= cap);
3352 	}
3353 
3354 	//doc.resize:
3355 	pure nothrow @safe @nogc unittest{
3356 		BasicString!char str = "123";
3357 
3358 		str.resize(5, 'x');
3359 		assert(str == "123xx");
3360 
3361 		str.resize(2);
3362 		assert(str == "12");
3363 	}
3364 
3365     //doc.downsize:
3366     pure nothrow @safe @nogc unittest{
3367         BasicString!char str = "123";
3368 
3369         str.downsize(5);
3370         assert(str == "123");
3371 
3372         str.downsize(2);
3373         assert(str == "12");
3374     }
3375 
3376     //doc.upsize:
3377     pure nothrow @safe @nogc unittest{
3378         BasicString!char str = "123";
3379 
3380         str.upsize(5, 'x');
3381         assert(str == "123xx");
3382 
3383         str.upsize(2);
3384         assert(str == "123xx");
3385     }
3386 
3387 	//doc.shrinkToFit:
3388 	pure nothrow @safe @nogc unittest{
3389 		BasicString!char str = "123";
3390 		assert(str.capacity == BasicString!char.minimalCapacity);
3391 
3392 		str.reserve(str.capacity * 2);
3393 		assert(str.capacity > BasicString!char.minimalCapacity);
3394 
3395 		str.shrinkToFit();
3396 		assert(str.capacity == BasicString!char.minimalCapacity);
3397 	}
3398 
3399 	//doc.ctor(null):
3400 	pure nothrow @safe @nogc unittest{
3401 		{
3402 			BasicString!char str = null;
3403 			assert(str.empty);
3404 		}
3405 	}
3406 
3407 	//doc.ctor(allocator):
3408 	pure nothrow @safe @nogc unittest{
3409 		{
3410 			BasicString!(char, DefaultAllocator) str = DefaultAllocator.init;
3411 			assert(str.empty);
3412 		}
3413 	}
3414 
3415 	//doc.ctor(character):
3416 	pure nothrow @safe @nogc unittest{
3417 		{
3418 			BasicString!char str = 'x';
3419 			assert(str == "x");
3420 		}
3421 
3422 		{
3423 			BasicString!char str = '読';
3424 			assert(str == "読");
3425 		}
3426 	}
3427 
3428 	//doc.ctor(character, allocator):
3429 	pure nothrow @safe @nogc unittest{
3430 		{
3431 			auto str = BasicString!(char, DefaultAllocator)('読', DefaultAllocator.init);
3432 			assert(str == "読");
3433 		}
3434 	}
3435 
3436 	//doc.ctor(slice):
3437 	pure nothrow @safe @nogc unittest{
3438 		{
3439 			BasicString!char str = "test";
3440 			assert(str == "test");
3441 		}
3442 
3443 		{
3444 			BasicString!char str = "test 読"d;
3445 			assert(str == "test 読");
3446 		}
3447 
3448 		{
3449 			wchar[3] data = [cast(wchar)'1', '2', '3'];
3450 			BasicString!char str = data[];
3451 			assert(str == "123");
3452 		}
3453 	}
3454 
3455 	//doc.ctor(slice, allocator):
3456 	pure nothrow @safe @nogc unittest{
3457 		{
3458 			auto str = BasicString!(char, DefaultAllocator)("test", DefaultAllocator.init);
3459 			assert(str == "test");
3460 		}
3461 
3462 		{
3463 			auto str = BasicString!(char, DefaultAllocator)("test 読"d, DefaultAllocator.init);
3464 			assert(str == "test 読");
3465 		}
3466 
3467 		{
3468 			wchar[3] data = [cast(wchar)'1', '2', '3'];
3469 			auto str = BasicString!(char, DefaultAllocator)(data[], DefaultAllocator.init);
3470 			assert(str == "123");
3471 		}
3472 	}
3473 
3474 	//doc.ctor(integer):
3475 	pure nothrow @safe @nogc unittest{
3476 		{
3477 			BasicString!char str = 123uL;
3478 			assert(str == "123");
3479 		}
3480 
3481 		{
3482 			BasicString!dchar str = -123;
3483 			assert(str == "-123");
3484 		}
3485 	}
3486 
3487 	//doc.ctor(integer, allocator):
3488 	pure nothrow @safe @nogc unittest{
3489 		{
3490 			auto str = BasicString!(char, DefaultAllocator)(123uL, DefaultAllocator.init);
3491 			assert(str == "123");
3492 		}
3493 
3494 		{
3495 			auto str = BasicString!(dchar, DefaultAllocator)(-123, DefaultAllocator.init);
3496 			assert(str == "-123");
3497 		}
3498 	}
3499 
3500 	//doc.ctor(rhs):
3501 	//doc.ctor(rhs, allcoator):
3502 	pure nothrow @safe @nogc unittest{
3503 		{
3504 			BasicString!char a = "123";
3505 			BasicString!char b = a;
3506 			assert(b == "123");
3507 		}
3508 
3509 		{
3510 			BasicString!dchar a = "123";
3511 			BasicString!char b = a;
3512 			assert(b == "123");
3513 		}
3514 
3515 		{
3516 			BasicString!dchar a = "123";
3517 			auto b = BasicString!char(a, DefaultAllocator.init);
3518 			assert(b == "123");
3519 		}
3520 
3521 		import core.lifetime : move;
3522 		{
3523 			BasicString!char a = "123";
3524 			BasicString!char b = move(a);
3525 			assert(b == "123");
3526 		}
3527 
3528 	}
3529 
3530 	//doc.opAssign(null):
3531 	//doc.opAssign(slice):
3532 	//doc.opAssign(character):
3533 	//doc.opAssign(integer):
3534 	//doc.opAssign(rhs):
3535 	pure nothrow @safe @nogc unittest{
3536 		BasicString!char str = "123";
3537 		assert(!str.empty);
3538 
3539 		str = null;
3540 		assert(str.empty);
3541 
3542 		str = 'X';
3543 		assert(str == "X");
3544 
3545 		str = "abc"w;
3546 		assert(str == "abc");
3547 
3548 		str = -123;
3549 		assert(str == "-123");
3550 
3551 		str = BasicString!char("42");
3552 		assert(str == "42");
3553 
3554 		str = BasicString!wchar("abc");
3555 		assert(str == "abc");
3556 
3557 	}
3558 
3559 	//doc.opBinary(rhs):
3560 	pure nothrow @safe @nogc unittest{
3561 		BasicString!char str = null;
3562 		assert(str.empty);
3563 
3564 		str = str + '1';
3565 		assert(str == "1");
3566 
3567 		str = str + "23"d;
3568 		assert(str == "123");
3569 
3570 		str = str + BasicString!dchar("456");
3571 		assert(str == "123456");
3572 
3573 	}
3574 
3575 	//doc.opBinaryRight(rhs):
3576 	pure nothrow @safe @nogc unittest{
3577 		BasicString!char str = null;
3578 		assert(str.empty);
3579 
3580 		str = '1' + str;
3581 		assert(str == "1");
3582 
3583 		str = "32"d + str;
3584 		assert(str == "321");
3585 
3586 		str = BasicString!dchar("654") + str;
3587 		assert(str == "654321");
3588 	}
3589 
3590 	//doc.opBinaryRight!"in":
3591 	pure nothrow @safe @nogc unittest{
3592 		BasicString!char str = "a123読";
3593 
3594 		assert('a' in str);
3595 		assert('b' !in str);
3596 		assert('3' in str);
3597 		assert('読' in str);
3598 	}
3599 
3600 	//doc.opEquals(rhs):
3601 	pure nothrow @safe @nogc unittest{
3602 		BasicString!char str = "123";
3603 
3604 		assert(str == "123");
3605 		assert("123" == str);
3606 
3607 		assert(str == "123"w);
3608 		assert("123"w == str);
3609 
3610 		assert(str == "123"d);
3611 		assert("123"d == str);
3612 
3613 		assert(str == BasicString!wchar("123"));
3614 		assert(BasicString!wchar("123") == str);
3615 
3616 		assert(str == 123);
3617 		assert(123 == str);
3618 
3619 		import std.range : only;
3620 		assert(str == only('1', '2', '3'));
3621 		assert(only('1', '2', '3') == str);
3622 	}
3623 
3624 	//doc.opCmp(rhs):
3625 	pure nothrow @safe @nogc unittest{
3626 
3627 	}
3628 
3629 	//doc.opIndex():
3630 	pure nothrow @system @nogc unittest{
3631         ()@system{
3632 		    BasicString!char str = "123";
3633 
3634 		    char[] slice = str[];
3635 		    assert(slice.length == str.length);
3636 		    assert(slice.ptr is str.ptr);
3637 
3638 		    str.reserve(str.capacity * 2);
3639 		    assert(slice.length == str.length);
3640 		    assert(slice.ptr !is str.ptr);  // slice contains dangling pointer.
3641         }();
3642         ()@safe{
3643             FixedString!(char, 20) str = "123";
3644 
3645             char[] slice = str[];
3646             assert(slice.length == str.length);
3647             assert(slice.ptr is str.ptr);
3648 
3649             assert(slice == "123");
3650         }();
3651 	}
3652 
3653 	//doc.opIndex(pos):
3654 	pure nothrow @system @nogc unittest{
3655 		BasicString!char str = "abcd";
3656 
3657 		assert(str[1] == 'b');
3658 	}
3659 
3660 	//doc.opSlice(begin, end):
3661 	pure nothrow @system @nogc unittest{
3662         ()@system{
3663             BasicString!char str = "123456";
3664             assert(str[1 .. $-1] == "2345");
3665         }();
3666         ()@safe{
3667             FixedString!(char, 20) str = "123456";
3668             assert(str[1 .. $-1] == "2345");
3669         }();
3670 	}
3671 
3672 	//doc.opIndexAssign(begin, end):
3673 	pure nothrow @safe @nogc unittest{
3674 		BasicString!char str = "abcd";
3675 
3676 		str[1] = 'x';
3677 
3678 		assert(str == "axcd");
3679 	}
3680 
3681 	//doc.proxySwap(rhs):
3682 	pure nothrow @safe @nogc unittest{
3683 		BasicString!char a = "1";
3684 		BasicString!char b = "2";
3685 
3686 		a.proxySwap(b);
3687 		assert(a == "2");
3688 		assert(b == "1");
3689 
3690 		import std.algorithm.mutation : swap;
3691 
3692 		swap(a, b);
3693 		assert(a == "1");
3694 		assert(b == "2");
3695 	}
3696 
3697 	//doc.append(val, count):
3698 	pure nothrow @safe @nogc unittest{
3699 		{
3700 			BasicString!char str = "123456";
3701 
3702 			str.append('x', 2);
3703 			assert(str == "123456xx");
3704 		}
3705 
3706 		{
3707 			BasicString!char str = "123456";
3708 
3709 			str.append("abc");
3710 			assert(str == "123456abc");
3711 		}
3712 
3713 		{
3714 			BasicString!char str = "123456";
3715 			BasicString!char str2 = "xyz";
3716 
3717 			str.append(str2);
3718 			assert(str == "123456xyz");
3719 		}
3720 
3721 		{
3722 			BasicString!char str = "12";
3723 
3724 			str.append(+34);
3725 			assert(str == "1234");
3726 		}
3727 	}
3728 
3729 	//doc.insert(pos, val, count):
3730 	//doc.insert(ptr, val, count):
3731 	pure nothrow @system @nogc unittest{
3732 		{
3733 			BasicString!char str = "123456";
3734 
3735 			str.insert(2, 'x', 2);
3736 			assert(str == "12xx3456");
3737 		}
3738 
3739 		{
3740 			BasicString!char str = "123456";
3741 
3742 			str.insert(2, "abc");
3743 			assert(str == "12abc3456");
3744 		}
3745 
3746 		{
3747 			BasicString!char str = "123456";
3748 			BasicString!char str2 = "abc";
3749 
3750 			str.insert(2, str2);
3751 			assert(str == "12abc3456");
3752 		}
3753 
3754 		{
3755 			BasicString!char str = "123456";
3756 
3757 			str.insert(str.ptr + 2, 'x', 2);
3758 			assert(str == "12xx3456");
3759 		}
3760 
3761 		{
3762 			BasicString!char str = "123456";
3763 
3764 			str.insert(str.ptr + 2, "abc");
3765 			assert(str == "12abc3456");
3766 		}
3767 
3768 		{
3769 			BasicString!char str = "123456";
3770 			BasicString!char str2 = "abc";
3771 
3772 			str.insert(str.ptr + 2, str2);
3773 			assert(str == "12abc3456");
3774 		}
3775 	}
3776 
3777 
3778 	//doc.erase(pos):
3779 	//doc.erase(pos, n):
3780 	//doc.erase(ptr):
3781 	//doc.erase(slice):
3782 	pure nothrow @system @nogc unittest{
3783 		{
3784 			BasicString!char str = "123456";
3785 
3786 			str.erase(2);
3787 			assert(str == "12");
3788 		}
3789 
3790 		{
3791 			BasicString!char str = "123456";
3792 
3793 			str.erase(1, 2);
3794 			assert(str == "1456");
3795 		}
3796 
3797 		{
3798 			BasicString!char str = "123456";
3799 
3800 			str.erase(str.ptr + 2);
3801 			assert(str == "12");
3802 		}
3803 
3804 		{
3805 			BasicString!char str = "123456";
3806 
3807 			str.erase(str[1 .. $-1]);
3808 			assert(str == "16");
3809 		}
3810 	}
3811 
3812 
3813 	//doc.replace(pos, len val, count):
3814 	//doc.replace(slice, val, count):
3815 	pure nothrow @system @nogc unittest{
3816 		{
3817 			BasicString!char str = "123456";
3818 
3819 			str.replace(2, 2, 'x', 5);
3820 			assert(str == "12xxxxx56");
3821 		}
3822 
3823 		{
3824 			BasicString!char str = "123456";
3825 
3826 			str.replace(2, 2, "abcdef");
3827 			assert(str == "12abcdef56");
3828 		}
3829 
3830 		{
3831 			BasicString!char str = "123456";
3832 			BasicString!char str2 = "xy";
3833 
3834 			str.replace(2, 3, str2);
3835 			assert(str == "12xy56");
3836 		}
3837 
3838 		{
3839 			BasicString!char str = "123456";
3840 
3841 			str.replace(str[2 .. 4], 'x', 5);
3842 			assert(str == "12xxxxx56");
3843 		}
3844 
3845 		{
3846 			BasicString!char str = "123456";
3847 
3848 			str.replace(str[2 .. 4], "abcdef");
3849 			assert(str == "12abcdef56");
3850 		}
3851 
3852 		{
3853 			BasicString!char str = "123456";
3854 			BasicString!char str2 = "xy";
3855 
3856 			str.replace(str[2 .. $], str2);
3857 			assert(str == "12xy56");
3858 		}
3859 	}
3860 
3861 
3862 	//doc.build(...):
3863 	pure nothrow @system @nogc unittest{
3864 		BasicString!char str = BasicString!char.build('1', cast(dchar)'2', "345"d, BasicString!wchar("678"));
3865 
3866 		assert(str == "12345678");
3867 
3868 	}
3869 
3870 
3871 }
3872 
3873 
3874 
3875 //normal ut
3876 version(unittest){
3877 	version(BTL_BASIC_STRING_TESTS)
3878 	struct TestStatelessAllocator(bool Realloc){
3879 
3880 		private struct Allocation{
3881 			void[] alloc;
3882 			long count;
3883 
3884 
3885 			this(void[] alloc, long c)pure nothrow @safe @nogc{
3886 				this.alloc = alloc;
3887 				this.count = c;
3888 			}
3889 		}
3890 
3891 		private static Allocation[] allocations;
3892 		private static void[][] bad_dealocations;
3893 
3894 
3895 		private void add(void[] b)scope nothrow @trusted{
3896 			if(b.length == 0)
3897 				return;
3898 
3899 			foreach(ref a; allocations){
3900 				if(a.alloc.ptr is b.ptr && a.alloc.length == b.length){
3901 					a.count += 1;
3902 					return;
3903 				}
3904 			}
3905 
3906 			allocations ~= Allocation(b, 1);
3907 		}
3908 
3909 		private void del(void[] b)scope nothrow @trusted{
3910 			foreach(ref a; allocations){
3911 				if(a.alloc.ptr is b.ptr && a.alloc.length == b.length){
3912 					a.count -= 1;
3913 					return;
3914 				}
3915 			}
3916 
3917 			bad_dealocations ~= b;
3918 		}
3919 
3920 
3921 		import std.experimental.allocator.common : platformAlignment;
3922 
3923 		public enum uint alignment = platformAlignment;
3924 
3925 		public void[] allocate(size_t bytes)scope @trusted nothrow{
3926 			auto data = Mallocator.instance.allocate(bytes);
3927 			if(data.length == 0)
3928 				return null;
3929 
3930 			this.add(data);
3931 
3932 			return data;
3933 		}
3934 
3935 		public bool deallocate(void[] b)scope @system nothrow{
3936 			const result = Mallocator.instance.deallocate(b);
3937 			assert(result);
3938 
3939 			this.del(b);
3940 
3941 			return result;
3942 
3943 		}
3944 
3945 		public bool reallocate(ref void[] b, size_t s)scope @system nothrow{
3946 			static if(Realloc){
3947 				void[] old = b;
3948 
3949 				const result = Mallocator.instance.reallocate(b, s);
3950 
3951 				this.del(old);
3952 				this.add(b);
3953 
3954 				return result;
3955 
3956 			}
3957 			else return false;
3958 		}
3959 
3960 
3961 		public bool empty()scope const nothrow @safe @nogc{
3962 			import std.algorithm : all;
3963 
3964 			return true
3965 				&& bad_dealocations.length == 0
3966 				&& allocations.all!((a) => a.count == 0);
3967 
3968 		}
3969 
3970 		static typeof(this) instance;
3971 	}
3972 
3973 	version(BTL_BASIC_STRING_TESTS)
3974 	class TestStateAllocator(bool Realloc){
3975 
3976 		private struct Allocation{
3977 			void[] alloc;
3978 			long count;
3979 
3980 
3981 			this(void[] alloc, long c)pure nothrow @safe @nogc{
3982 				this.alloc = alloc;
3983 				this.count = c;
3984 			}
3985 		}
3986 
3987 		private Allocation[] allocations;
3988 		private void[][] bad_dealocations;
3989 
3990 
3991 		private void add(void[] b)scope nothrow @trusted{
3992 			if(b.length == 0)
3993 				return;
3994 
3995 			foreach(ref a; allocations){
3996 				if(a.alloc.ptr is b.ptr && a.alloc.length == b.length){
3997 					a.count += 1;
3998 					return;
3999 				}
4000 			}
4001 
4002 			allocations ~= Allocation(b, 1);
4003 		}
4004 
4005 		private void del(void[] b)scope nothrow @trusted{
4006 			foreach(ref a; allocations){
4007 				if(a.alloc.ptr is b.ptr && a.alloc.length == b.length){
4008 					a.count -= 1;
4009 					return;
4010 				}
4011 			}
4012 
4013 			bad_dealocations ~= b;
4014 		}
4015 
4016 
4017 		import std.experimental.allocator.common : platformAlignment;
4018 
4019 		public enum uint alignment = platformAlignment;
4020 
4021 		public void[] allocate(size_t bytes)scope @trusted nothrow{
4022 			auto data = Mallocator.instance.allocate(bytes);
4023 			if(data.length == 0)
4024 				return null;
4025 
4026 			this.add(data);
4027 
4028 			return data;
4029 		}
4030 
4031 		public bool deallocate(void[] b)scope @system nothrow{
4032 			const result = Mallocator.instance.deallocate(b);
4033 			assert(result);
4034 
4035 			this.del(b);
4036 
4037 			return result;
4038 
4039 		}
4040 
4041 		public bool reallocate(ref void[] b, size_t s)scope @system nothrow{
4042 			static if(Realloc){
4043 				void[] old = b;
4044 
4045 				const result = Mallocator.instance.reallocate(b, s);
4046 
4047 				this.del(old);
4048 				this.add(b);
4049 
4050 				return result;
4051 
4052 			}
4053 			else return false;
4054 		}
4055 
4056 
4057 		public bool empty()scope const nothrow @safe @nogc{
4058 			import std.algorithm : all;
4059 
4060 			return true
4061 				&& bad_dealocations.length == 0
4062 				&& allocations.all!((a) => a.count == 0);
4063 
4064 		}
4065 	}
4066 
4067 
4068 
4069 
4070 	version(BTL_BASIC_STRING_TESTS){
4071 		private auto trustedSlice(S)(scope auto ref S str)@trusted{
4072 			return str[];
4073 		}
4074 		private auto trustedSlice(S)(scope auto ref S str, size_t b, size_t e)@trusted{
4075 			return str[b .. e];
4076 		}
4077 		private auto trustedSliceToEnd(S)(scope auto ref S str, size_t b)@trusted{
4078 			return str[b .. $];
4079 		}
4080 
4081 		void unittest_allocator_impl(Char, Allocator)(Allocator allocator){
4082 			alias Str = BasicString!(Char, Allocator);
4083 
4084 			static if(Str.hasStatelessAllocator)
4085 				alias allocatorWithState = AliasSeq!();
4086 			else
4087 				alias allocatorWithState = AliasSeq!(allocator);
4088 
4089 			Str str = Str("1", allocatorWithState);
4090 			auto a = str.allocator;
4091 		}
4092 
4093 		void unittest_reserve_impl(Char, Allocator)(Allocator allocator){
4094 			alias Str = BasicString!(Char, Allocator);
4095 
4096 			static if(Str.hasStatelessAllocator)
4097 				alias allocatorWithState = AliasSeq!();
4098 			else
4099 				alias allocatorWithState = AliasSeq!(allocator);
4100 
4101 			///reserve:
4102 			Str str = Str("1", allocatorWithState);
4103 			assert(str.capacity == Str.minimalCapacity);
4104 			//----------------------------
4105 			const size_t new_capacity = str.capacity * 2 + 1;
4106 			str.reserve(new_capacity);
4107 			assert(str.capacity >= new_capacity);
4108 			//----------------------------
4109 			str.clear();
4110 			assert(str.empty);
4111 		}
4112 
4113 		void unittest_resize_impl(Char, Allocator)(Allocator allocator){
4114 			alias Str = BasicString!(Char, Allocator);
4115 
4116 			static if(Str.hasStatelessAllocator)
4117 				alias allocatorWithState = AliasSeq!();
4118 			else
4119 				alias allocatorWithState = AliasSeq!(allocator);
4120 
4121 			///resize:
4122 			Str str = Str("1", allocatorWithState);
4123 			assert(str.capacity == Str.minimalCapacity);
4124 			//----------------------------
4125 			str.resize(Str.minimalCapacity);
4126 			assert(str.capacity == Str.minimalCapacity);
4127 			assert(str.length == Str.minimalCapacity);
4128 			//----------------------------
4129 			str.resize(Str.minimalCapacity - 1, '_');
4130 			assert(str.capacity == Str.minimalCapacity);
4131 			assert(str.length == Str.minimalCapacity - 1);
4132 			//----------------------------
4133 			str.resize(Str.minimalCapacity + 3, '_');
4134 			assert(str.capacity > Str.minimalCapacity);
4135 			assert(str.length == Str.minimalCapacity + 3);
4136 
4137 		}
4138 
4139 
4140 		void unittest_ctor_string_impl(Char, Allocator)(Allocator allocator){
4141 			alias Str = BasicString!(Char, Allocator);
4142 
4143 			static if(Str.hasStatelessAllocator)
4144 				alias allocatorWithState = AliasSeq!();
4145 			else
4146 				alias allocatorWithState = AliasSeq!(allocator);
4147 
4148 			static foreach(enum val; AliasSeq!(
4149 				"0123",
4150 				"0123456789_0123456789_0123456789_0123456789",
4151 			))
4152 			static foreach(enum I; AliasSeq!(1, 2, 3, 4)){{
4153 				static if(I == 1){
4154 					char[val.length] s = val;
4155 					wchar[val.length] w = val;
4156 					dchar[val.length] d = val;
4157 				}
4158 				else static if(I == 2){
4159 					immutable(char)[val.length] s = val;
4160 					immutable(wchar)[val.length] w = val;
4161 					immutable(dchar)[val.length] d = val;
4162 				}
4163 				else static if(I == 3){
4164 					enum string s = val;
4165 					enum wstring w = val;
4166 					enum dstring d = val;
4167 				}
4168 				else static if(I == 4){
4169 					auto s = BasicString!(char, Allocator)(val, allocatorWithState);
4170 					auto w = BasicString!(wchar, Allocator)(val, allocatorWithState);
4171 					auto d = BasicString!(dchar, Allocator)(val, allocatorWithState);
4172 				}
4173 				else static assert(0, "no impl");
4174 
4175 				auto str1 = Str(s, allocatorWithState);
4176 				str1 = s;
4177 				auto str2 = Str(s.trustedSlice, allocatorWithState);
4178 				str2 = s.trustedSlice;
4179 				assert(str1 == str2);
4180 
4181 				auto wstr1 = Str(w, allocatorWithState);
4182 				wstr1 = w;
4183 				auto wstr2 = Str(w.trustedSlice, allocatorWithState);
4184 				wstr2 = w.trustedSlice;
4185 				assert(wstr1 == wstr2);
4186 
4187 				auto dstr1 = Str(d, allocatorWithState);
4188 				dstr1 = d;
4189 				auto dstr2 = Str(d.trustedSlice, allocatorWithState);
4190 				dstr2 = d.trustedSlice;
4191 				assert(dstr1 == dstr2);
4192 			}}
4193 
4194 
4195 		}
4196 
4197 		void unittest_ctor_char_impl(Char, Allocator)(Allocator allocator){
4198 			alias Str = BasicString!(Char, Allocator);
4199 
4200 			static if(Str.hasStatelessAllocator)
4201 				alias allocatorWithState = AliasSeq!();
4202 			else
4203 				alias allocatorWithState = AliasSeq!(allocator);
4204 
4205 			static foreach(enum val; AliasSeq!(
4206 				cast(char)'1',
4207 				cast(wchar)'2',
4208 				cast(dchar)'3',
4209 			))
4210 			static foreach(enum I; AliasSeq!(1, 2, 3)){{
4211 				static if(I == 1){
4212 					char c = val;
4213 					wchar w = val;
4214 					dchar d = val;
4215 				}
4216 				else static if(I == 2){
4217 					immutable(char) c = val;
4218 					immutable(wchar) w = val;
4219 					immutable(dchar) d = val;
4220 				}
4221 				else static if(I == 3){
4222 					enum char c = val;
4223 					enum wchar w = val;
4224 					enum dchar d = val;
4225 				}
4226 				else static assert(0, "no impl");
4227 
4228 				auto str = Str(c, allocatorWithState);
4229 				str = c;
4230 
4231 				auto wstr = Str(w, allocatorWithState);
4232 				wstr = w;
4233 
4234 				auto dstr = Str(d, allocatorWithState);
4235 				dstr = d;
4236 			}}
4237 
4238 		}
4239 
4240 
4241 		void unittest_shrink_to_fit_impl(Char, Allocator)(Allocator allocator){
4242 			alias Str = BasicString!(Char, Allocator);
4243 
4244 			static if(Str.hasStatelessAllocator)
4245 				alias allocatorWithState = AliasSeq!();
4246 			else
4247 				alias allocatorWithState = AliasSeq!(allocator);
4248 
4249 			Str str = Str("123", allocatorWithState);
4250 			assert(str.capacity == Str.minimalCapacity);
4251 
4252 			//----------------------------
4253 			assert(str.small);
4254 			str.resize(str.capacity * 2, 'x');
4255 			assert(!str.small);
4256 
4257 
4258 			const size_t cap = str.capacity;
4259 			const size_t len = str.length;
4260 			str.shrinkToFit();
4261 			assert(str.length == len);
4262 			assert(str.capacity == cap);
4263 
4264 			str = "123";
4265 			assert(str.length == 3);
4266 			assert(str.capacity == cap);
4267 
4268 			str.shrinkToFit();
4269 			assert(str.length == 3);
4270 			assert(str.capacity == Str.minimalCapacity);
4271 
4272 			//----------------------------
4273 			str.clear();
4274 			assert(str.empty);
4275 
4276 		}
4277 
4278 
4279 		void unittest_operator_plus_string_impl(Char, Allocator)(Allocator allocator){
4280 			alias Str = BasicString!(Char, Allocator);
4281 
4282 			static if(Str.hasStatelessAllocator)
4283 				alias allocatorWithState = AliasSeq!();
4284 			else
4285 				alias allocatorWithState = AliasSeq!(allocator);
4286 
4287 			static foreach(enum I; AliasSeq!(1, 2, 3, 4)){{
4288 				static if(I == 1){
4289 					auto s = BasicString!(char, Allocator)("45", allocatorWithState);
4290 					auto w = BasicString!(wchar, Allocator)("67", allocatorWithState);
4291 					auto d = BasicString!(dchar, Allocator)("89", allocatorWithState);
4292 				}
4293 				else static if(I == 2){
4294 					immutable(char)[2] s = "45";
4295 					immutable(wchar)[2] w = "67";
4296 					immutable(dchar)[2] d = "89";
4297 				}
4298 				else static if(I == 3){
4299 					enum string s = "45";
4300 					enum wstring w = "67";
4301 					enum dstring d = "89";
4302 				}
4303 				else static if(I == 4){
4304 					char[2] sx = ['4', '5'];
4305 					wchar[2] wx = ['6', '7'];
4306 					dchar[2] dx = ['8', '9'];
4307 					char[] s = sx[];
4308 					wchar[] w = wx[];
4309 					dchar[] d = dx[];
4310 				}
4311 				else static assert(0, "no impl");
4312 
4313 
4314 				Str str = Str("123", allocatorWithState);
4315 				assert(str.capacity == Str.minimalCapacity);
4316 
4317 				////----------------------------
4318 				str = (str + s);
4319 				str = (s + str);
4320 				str += s;
4321 				assert(str == "451234545");
4322 
4323 				str = (str + w);
4324 				str = (w + str);
4325 				str += w;
4326 				assert(str == "674512345456767");
4327 
4328 				str = (str + d);
4329 				str = (d + str);
4330 				str += d;
4331 				assert(str == "896745123454567678989");
4332 
4333 				//----------------------------
4334 				str.clear();
4335 				assert(str.empty);
4336 			}}
4337 		}
4338 
4339 		void unittest_operator_plus_char_impl(Char, Allocator)(Allocator allocator){
4340 			alias Str = BasicString!(Char, Allocator);
4341 
4342 			static if(Str.hasStatelessAllocator)
4343 				alias allocatorWithState = AliasSeq!();
4344 			else
4345 				alias allocatorWithState = AliasSeq!(allocator);
4346 
4347 			static foreach(enum I; AliasSeq!(1, 2)){{
4348 				static if(I == 1){
4349 					char c = 'a';
4350 					wchar w = 'b';
4351 					dchar d = 'c';
4352 				}
4353 				else static if(I == 2){
4354 					enum char c = 'a';
4355 					enum wchar w = 'b';
4356 					enum dchar d = 'c';
4357 				}
4358 				else static assert(0, "no impl");
4359 
4360 
4361 				Str str = Str("123", allocatorWithState);
4362 				assert(str.capacity == Str.minimalCapacity);
4363 
4364 				////----------------------------
4365 				str = (str + c);
4366 				str = (c + str);
4367 				str += c;
4368 				assert(str == "a123aa");
4369 
4370 				str = (str + w);
4371 				str = (w + str);
4372 				str += w;
4373 				assert(str == "ba123aabb");
4374 
4375 				str = (str + d);
4376 				str = (d + str);
4377 				str += d;
4378 				assert(str == "cba123aabbcc");
4379 
4380 				//----------------------------
4381 				str.clear();
4382 				assert(str.empty);
4383 			}}
4384 		}
4385 
4386 
4387 		void unittest_append_impl(Char, Allocator)(Allocator allocator){
4388 			alias Str = BasicString!(Char, Allocator);
4389 
4390 			static if(Str.hasStatelessAllocator)
4391 				alias allocatorWithState = AliasSeq!();
4392 			else
4393 				alias allocatorWithState = AliasSeq!(allocator);
4394 
4395 			static foreach(enum val; AliasSeq!(
4396 				"0123",
4397 				"0123456789_0123456789_0123456789_0123456789",
4398 			))
4399 			static foreach(enum rep; AliasSeq!(
4400 				'x',
4401 				"",
4402 				"a",
4403 				"ab",
4404 				"abcdefgh_abcdefgh_abcdefgh_abcdefgh",
4405 			))
4406 			static foreach(enum size_t count; AliasSeq!(0, 1, 2, 3))
4407 			static foreach(alias T; AliasSeq!(char, wchar, dchar)){{
4408 				import std.traits : isArray;
4409 
4410 				static if(isArray!(typeof(rep)))
4411 					alias Rep = immutable(T)[];
4412 				else
4413 					alias Rep = T;
4414 
4415 
4416 				Str str = Str(val, allocatorWithState);
4417 
4418 				str.append(cast(Rep)rep, count);
4419 
4420 
4421 				Str rep_complet = Str(allocatorWithState);
4422 				for(size_t i = 0; i < count; ++i)
4423 					rep_complet += cast(Rep)rep;
4424 
4425 				import std.range;
4426 				assert(str == Str.build(allocatorWithState, val, rep_complet.trustedSlice));
4427 				//assert(str == chain(val, rep_complet[]));
4428 
4429 			}}
4430 
4431 		}
4432 
4433 		void unittest_insert_impl(Char, Allocator)(Allocator allocator){
4434 			alias Str = BasicString!(Char, Allocator);
4435 
4436 			static if(Str.hasStatelessAllocator)
4437 				alias allocatorWithState = AliasSeq!();
4438 			else
4439 				alias allocatorWithState = AliasSeq!(allocator);
4440 
4441 			static foreach(enum val; AliasSeq!(
4442 				"0123",
4443 				"0123456789_0123456789_0123456789_0123456789",
4444 			))
4445 			static foreach(enum rep_source; AliasSeq!(
4446 				'x',
4447 				"",
4448 				"a",
4449 				"ab",
4450 				"abcdefgh_abcdefgh_abcdefgh_abcdefgh",
4451 			))
4452 			static foreach(enum size_t count; AliasSeq!(0, 1, 2, 3))
4453 			static foreach(alias T; AliasSeq!(char, wchar, dchar)){{
4454 				import std.traits : isArray;
4455 
4456 				static if(isArray!(typeof(rep_source)))
4457 					enum immutable(T)[] rep = rep_source;
4458 				else
4459 					enum T rep = rep_source;
4460 
4461 
4462 				Str rep_complet = Str(allocatorWithState);
4463 				for(size_t i = 0; i < count; ++i)
4464 					rep_complet += rep;
4465 
4466 				{
4467 					Str str = Str(val, allocatorWithState);
4468 
4469 					const x = str.insert(2, rep, count);
4470 					assert(Str(rep, allocatorWithState).length * count == x);
4471 					assert(str == Str.build(allocatorWithState, val.trustedSlice(0, 2), rep_complet, val.trustedSliceToEnd(2)));
4472 				}
4473 				{
4474 					Str str = Str(val, allocatorWithState);
4475 
4476 					const x = str.insert(str.length, rep, count);
4477 					assert(Str(rep, allocatorWithState).length * count == x);
4478 					assert(str == Str.build(allocatorWithState, val, rep_complet));
4479 				}
4480 				{
4481 					Str str = Str(val, allocatorWithState);
4482 
4483 					const x = str.insert(str.length + 2000, rep, count);
4484 					assert(Str(rep, allocatorWithState).length * count == x);
4485 					assert(str == Str.build(allocatorWithState, val, rep_complet));
4486 				}
4487 				{
4488 					Str str = Str(val, allocatorWithState);
4489 
4490 					const x = str.insert(0, rep, count);
4491 					assert(Str(rep, allocatorWithState).length * count == x);
4492 					assert(str == Str.build(allocatorWithState, rep_complet, val));
4493 				}
4494 				//------------------------------------------------
4495 				{
4496 					Str str = Str(val, allocatorWithState);
4497 
4498 					const x = str.insert((()@trusted => str.ptr + 2)(), rep, count);
4499 					assert(Str(rep, allocatorWithState).length * count == x);
4500 					assert(str == Str.build(allocatorWithState, val.trustedSlice(0, 2), rep_complet, val.trustedSliceToEnd(2)));
4501 				}
4502 				{
4503 					Str str = Str(val, allocatorWithState);
4504 
4505 					const x = str.insert((()@trusted => str.ptr + str.length)(), rep, count);
4506 					assert(Str(rep, allocatorWithState).length * count == x);
4507 					assert(str == Str.build(allocatorWithState, val, rep_complet));
4508 				}
4509 				{
4510 					Str str = Str(val, allocatorWithState);
4511 
4512 					const x = str.insert((()@trusted => str.ptr + str.length + 2000)(), rep, count);
4513 					assert(Str(rep, allocatorWithState).length * count == x);
4514 					assert(str == Str.build(allocatorWithState, val, rep_complet));
4515 				}
4516 				{
4517 					Str str = Str(val, allocatorWithState);
4518 
4519 					const x = str.insert((()@trusted => str.ptr)(), rep, count);
4520 					assert(Str(rep, allocatorWithState).length * count == x);
4521 					assert(str == Str.build(allocatorWithState, rep_complet, val));
4522 				}
4523 				{
4524 					Str str = Str(val, allocatorWithState);
4525 
4526 					const x = str.insert((()@trusted => str.ptr - 1000)(), rep, count);
4527 					assert(Str(rep, allocatorWithState).length * count == x);
4528 					assert(str == Str.build(allocatorWithState, rep_complet, val));
4529 				}
4530 
4531 			}}
4532 		}
4533 
4534 		void unittest_erase_impl(Char, Allocator)(Allocator allocator){
4535 			alias Str = BasicString!(Char, Allocator);
4536 
4537 			static if(Str.hasStatelessAllocator)
4538 				alias allocatorWithState = AliasSeq!();
4539 			else
4540 				alias allocatorWithState = AliasSeq!(allocator);
4541 
4542 			static foreach(enum val; AliasSeq!(
4543 				"0123",
4544 				"0123456789_0123456789_0123456789_0123456789",
4545 			)){
4546 				{
4547 					Str str = Str(val, allocatorWithState);
4548 
4549 					str.erase(2);
4550 					//assert(str.equals_test(Str(val[0 .. 2])));
4551 					assert(str == Str(val[0 .. 2], allocatorWithState));
4552 				}
4553 				{
4554 					Str str = Str(val, allocatorWithState);
4555 
4556 					str.erase(1, 2);
4557 					assert(str == Str.build(allocatorWithState, val[0 .. 1], val[3 .. $]));
4558 				}
4559 				{
4560 					Str str = Str(val, allocatorWithState);
4561 
4562 					str.erase(1, 1000);
4563 					assert(str == Str.build(allocatorWithState, val[0 .. 1]));
4564 				}
4565 				{
4566 					Str str = Str(val, allocatorWithState);
4567 
4568 					str.erase(str.trustedSliceToEnd(2));
4569 					assert(str == Str.build(allocatorWithState, val[0 .. 2]));
4570 				}
4571 				{
4572 					Str str = Str(val, allocatorWithState);
4573 
4574 					str.erase(str.trustedSlice(1, 3));
4575 					assert(str == Str.build(allocatorWithState, val.trustedSlice(0, 1), val.trustedSliceToEnd(3)));
4576 				}
4577 				{
4578 					Str str = Str(val, allocatorWithState);
4579 
4580 					str.erase((()@trusted => str.ptr + 2)());
4581 					assert(str == Str(val.trustedSlice(0, 2), allocatorWithState));
4582 				}
4583 			}
4584 
4585 			///downsize (erase):
4586 			{
4587 				Str str = Str("123", allocatorWithState);
4588 				assert(str.length == 3);
4589 
4590 				//----------------------------
4591 				str.erase(3);
4592 				assert(str.length == 3);
4593 
4594 				str.erase(1000);
4595 				assert(str.length == 3);
4596 
4597 				str.erase(1);
4598 				assert(str.length == 1);
4599 
4600 				//----------------------------
4601 				const size_t new_length = str.capacity * 2;
4602 				str.resize(new_length);
4603 				assert(str.capacity >= new_length);
4604 				assert(str.length == new_length);
4605 
4606 				str.erase(3);
4607 				assert(str.length == 3);
4608 
4609 				str.erase(1000);
4610 				assert(str.length == 3);
4611 
4612 				str.erase(1);
4613 				assert(str.length == 1);
4614 
4615 				//----------------------------
4616 				str.clear();
4617 				assert(str.empty);
4618 			}
4619 		}
4620 
4621 		void unittest_replace_impl(Char, Allocator)(Allocator allocator){
4622 			alias Str = BasicString!(Char, Allocator);
4623 
4624 			static if(Str.hasStatelessAllocator)
4625 				alias allocatorWithState = AliasSeq!();
4626 			else
4627 				alias allocatorWithState = AliasSeq!(allocator);
4628 
4629 			static foreach(enum val; AliasSeq!(
4630 				"0123",
4631 				"0123456789_0123456789_0123456789_0123456789",
4632 			))
4633 			static foreach(enum rep_source; AliasSeq!(
4634 				'x',
4635 				"",
4636 				"a",
4637 				"ab",
4638 				"abcdefgh_abcdefgh_abcdefgh_abcdefgh",
4639 			))
4640 			static foreach(enum size_t count; AliasSeq!(0, 1, 2, 3))
4641 			static foreach(alias T; AliasSeq!(char, wchar, dchar)){{
4642 				import std.traits : isArray;
4643 
4644 				static if(isArray!(typeof(rep_source)))
4645 					enum immutable(T)[] rep = rep_source;
4646 				else
4647 					enum T rep = rep_source;
4648 
4649 
4650 				Str rep_complet = Str(allocatorWithState);
4651 				for(size_t i = 0; i < count; ++i)
4652 					rep_complet += rep;
4653 
4654 				{
4655 					Str str = Str(val, allocatorWithState);
4656 
4657 					str.replace(1, 2, rep, count);
4658 					//debug writeln(val, ": ", str[], " vs ", val[0 .. 1], " | ", rep_complet[], " | ", val[3 .. $]);
4659 					//assert(str[] == Str.build(val[0 .. 1], rep_complet[], val[3 .. $]));
4660 				}
4661 				{
4662 					Str str = Str(val, allocatorWithState);
4663 
4664 					str.replace(1, val.length - 1, rep, count);
4665 					//assert(str[] == Str.build(val[0 .. 1], rep_complet[]));
4666 				}
4667 				{
4668 					Str str = Str(val, allocatorWithState);
4669 
4670 					str.replace(1, val.length + 2000, rep, count);
4671 					//assert(str[] == Str.build(val[0 .. 1], rep_complet[]));
4672 				}
4673 				//------------------------
4674 				{
4675 					Str str = Str(val, allocatorWithState);
4676 
4677 					str.replace((()@trusted => str[1 .. $ - 1])(), rep, count);
4678 					//assert(str[] == Str.build(val[0 .. 1], rep_complet[], val[$ - 1 .. $]));
4679 				}
4680 				{
4681 					Str str = Str(val, allocatorWithState);
4682 
4683 					str.replace((()@trusted => str[1 ..  $])(), rep, count);
4684 					//assert(str[] == Str.build(val[0 .. 1], rep_complet[]));
4685 				}
4686 				{
4687 					Str str = Str(val, allocatorWithState);
4688 
4689 					str.replace((()@trusted => str.ptr[1 .. str.length + 2000])(), rep, count);
4690 					//assert(str[] == Str.build(val[0 .. 1], rep_complet[]));
4691 				}
4692 
4693 			}}
4694 		}
4695 
4696 
4697 		void unittest_output_range_impl(Char, Allocator)(Allocator allocator){
4698 			alias Str = BasicString!(Char, Allocator);
4699 
4700 			static if(Str.hasStatelessAllocator)
4701 				alias allocatorWithState = AliasSeq!();
4702 			else
4703 				alias allocatorWithState = AliasSeq!(allocator);
4704 
4705 			static foreach(alias T; AliasSeq!(char, wchar, dchar)){{
4706 				import std.range : only;
4707 				import std.algorithm.mutation : copy;
4708 
4709 				{
4710 					Str str = only(
4711 						cast(immutable(T)[])"a",
4712 						cast(immutable(T)[])"bc",
4713 						cast(immutable(T)[])"",
4714 						cast(immutable(T)[])"d"
4715 					).copy(Str(allocatorWithState));
4716 
4717 				}
4718 				{
4719 					Str str = only(
4720 						cast(T)'a',
4721 						cast(T)'b',
4722 						cast(T)'c'
4723 					).copy(Str(allocatorWithState));
4724 
4725 					assert(str == Str("abc", allocatorWithState));
4726 
4727 				}
4728 			}}
4729 		}
4730 
4731 	}
4732 
4733 
4734 	version(BTL_BASIC_STRING_TESTS)
4735 	void unittest_impl(Char, Allocator)(Allocator allocator){
4736 		unittest_allocator_impl!Char(allocator);
4737 
4738 		unittest_reserve_impl!Char(allocator);
4739 		unittest_resize_impl!Char(allocator);
4740 
4741 		unittest_ctor_string_impl!Char(allocator);
4742 		unittest_ctor_char_impl!Char(allocator);
4743 
4744 		unittest_shrink_to_fit_impl!Char(allocator);
4745 
4746 		unittest_operator_plus_string_impl!Char(allocator);
4747 		unittest_operator_plus_char_impl!Char(allocator);
4748 
4749 		unittest_append_impl!Char(allocator);
4750 		unittest_insert_impl!Char(allocator);
4751 		unittest_erase_impl!Char(allocator);
4752 		unittest_replace_impl!Char(allocator);
4753 
4754 		unittest_output_range_impl!Char(allocator);
4755 
4756 	}
4757 
4758 
4759 
4760 	version(BTL_BASIC_STRING_TESTS)
4761 	void unittest_impl(Allocator)(Allocator allocator = Allocator.init){
4762 		import std.stdio : writeln;
4763 		import std.range : only;
4764 
4765 		static foreach(alias Char; AliasSeq!(char, wchar, dchar))
4766 			unittest_impl!Char(allocator);
4767 
4768 	}
4769 
4770 	version(BTL_BASIC_STRING_TESTS)
4771 	@nogc @safe pure nothrow unittest{
4772 		unittest_impl!Mallocator();
4773 	}
4774 
4775 	version(BTL_BASIC_STRING_TESTS)
4776 	nothrow unittest{
4777 		version(D_BetterC){}
4778 		else{
4779 			static foreach(enum bool Realloc; [false, true]){
4780 				{
4781 					alias AX = TestStatelessAllocator!Realloc;
4782 
4783 					assert(AX.instance.empty);
4784 
4785 					unittest_impl!AX();
4786 
4787 					assert(AX.instance.empty);
4788 				}
4789 
4790 				{
4791 					alias AX = TestStateAllocator!Realloc;
4792 
4793 					auto allocator = new AX;
4794 
4795 
4796 					assert(allocator.empty);
4797 
4798 					unittest_impl(allocator);
4799 
4800 					assert(allocator.empty);
4801 
4802 
4803 					//unittest_impl(allocator);
4804 
4805 				}
4806 
4807 				{
4808 					alias AX = TestStateAllocator!Realloc;
4809 					auto allocator = new AX;
4810 
4811 					assert(allocator.empty);
4812 
4813 					{
4814 						alias Str = BasicString!(char, AX);
4815 
4816 						//Str b;
4817 						//auto a = Str(allocator, "0123456789_0123456789_0123456789_");
4818 
4819 					}
4820 
4821 					assert(allocator.empty);
4822 
4823 				}
4824 			}
4825 		}
4826 	}
4827 
4828 }
4829 
4830 
4831 //move ctor
4832 pure nothrow unittest{
4833 	import std.range : iota, array;
4834 	import std.algorithm : map;
4835 	import core.lifetime : move;
4836 
4837 	alias Str1 = BasicString!(char, 1);
4838 	alias Str2 = BasicString!(char, 2);
4839 	alias Str128 = BasicString!(char, 128);
4840 
4841 	//heap -> heap
4842 	{
4843 		Str1 a = iota(0, Str1.minimalCapacity * 2)
4844 			.map!(i => i%2 ? 'a' : 'b')
4845 			.array;
4846 		void* ptr = a.ptr;
4847 		Str1 b = move(a);
4848 
4849 		assert(b.ptr is ptr);
4850 	}
4851 
4852 	//heap -> heap
4853 	{
4854 		Str1 a = iota(0, Str1.minimalCapacity * 2)
4855 			.map!(i => (i%2) ? 'a' : 'b')
4856 			.array;
4857 		void* ptr = a.ptr;
4858 		Str2 b = move(a);
4859 
4860 		assert(b.ptr is ptr);
4861 	}
4862 
4863 	//inline -> heap
4864 	{
4865 		Str128 a = iota(0, Str2.minimalCapacity * 2)
4866 			.map!(i => (i%2) ? 'a' : 'b')
4867 			.array;
4868 		void* ptr = a.ptr;
4869 		Str2 b = move(a);
4870 
4871 		assert(b.ptr !is ptr);
4872 	}
4873 
4874 	//heap -> inline
4875 	{
4876 		Str2 a = iota(0, Str2.minimalCapacity * 2)
4877 			.map!(i => (i%2) ? 'a' : 'b')
4878 			.array;
4879 		void* ptr = a.ptr;
4880 		Str128 b = move(a);
4881 
4882 		assert(b.ptr !is ptr);
4883 	}
4884 }
4885 
4886 //move assign
4887 pure nothrow unittest{
4888 	import std.range : iota, array;
4889 	import std.algorithm : map;
4890 	import core.lifetime : move;
4891 
4892 	alias Str1 = BasicString!(char, 1);
4893 	alias Str2 = BasicString!(char, 2);
4894 	alias Str128 = BasicString!(char, 128);
4895 
4896 	//heap -> heap
4897 	{
4898 		Str1 a = iota(0, Str1.minimalCapacity * 2)
4899 			.map!(i => i%2 ? 'a' : 'b')
4900 			.array;
4901 		void* ptr = a.ptr;
4902 		Str1 b;
4903 		b = move(a);
4904 
4905 		assert(b.ptr is ptr);
4906 	}
4907 
4908 	//heap -> heap
4909 	{
4910 		Str1 a = iota(0, Str1.minimalCapacity * 2)
4911 			.map!(i => (i%2) ? 'a' : 'b')
4912 			.array;
4913 		void* ptr = a.ptr;
4914 		Str2 b;
4915 		b = move(a);
4916 
4917 		assert(b.ptr is ptr);
4918 	}
4919 
4920 	//inline -> heap
4921 	{
4922 		Str128 a = iota(0, Str2.minimalCapacity * 2)
4923 			.map!(i => (i%2) ? 'a' : 'b')
4924 			.array;
4925 		void* ptr = a.ptr;
4926 		Str2 b;
4927 		b = move(a);
4928 
4929 		assert(b.ptr !is ptr);
4930 	}
4931 
4932 	//heap -> inline
4933 	{
4934 		Str2 a = iota(0, Str2.minimalCapacity * 2)
4935 			.map!(i => (i%2) ? 'a' : 'b')
4936 			.array;
4937 		void* ptr = a.ptr;
4938 		Str128 b;
4939 		b = move(a);
4940 
4941 		assert(b.ptr !is ptr);
4942 	}
4943 }
4944 
4945 //LargeString:
4946 pure nothrow @safe @nogc unittest{
4947 	LargeString!char str;
4948 
4949 	assert(str.small);
4950 	assert(str.minimalCapacity == 0);
4951 
4952 	str = "";
4953 	assert(str.small);
4954 	assert(str.capacity == 0);
4955 
4956 
4957 	str = "1";
4958 	assert(!str.small);
4959 	assert(str.capacity >= 1);
4960 
4961 	str = null;
4962 	assert(!str.small);
4963 
4964 	str.release();
4965 	assert(str.small);
4966 }
4967 
4968 //NullString:
4969 pure nothrow @safe @nogc unittest{
4970 	BasicString!(char, 0, void) str;
4971 
4972 	assert(str.small);
4973 	assert(str.minimalCapacity == 0);
4974 
4975 	str = "";
4976 	assert(str.small);
4977 	assert(str.capacity == 0);
4978 
4979 
4980 	/+str = "1";
4981 	assert(!str.small);
4982 	assert(str.capacity >= 1);+/
4983 
4984 	str = null;
4985 	assert(str.small);
4986 
4987 	str.release();
4988 	assert(str.small);
4989 }
4990 
4991 //FixedString:
4992 pure nothrow @safe @nogc unittest{
4993 	FixedString!(char, 10) str;
4994 
4995 	assert(str.small);
4996 	assert(str.minimalCapacity >= 10);
4997 
4998 	str = "";
4999 	assert(str.small);
5000 
5001 	for(int i = str.minimalCapacity; i != 0; --i)
5002 		str ~= 'x';
5003 
5004 	assert(str.length == str.capacity);
5005 	assert(str.capacity == str.minimalCapacity);
5006 
5007 	///str ~= 'y';
5008 }
5009 
5010 //append range
5011 unittest{
5012 	import std.range : ElementEncodingType, isInputRange, isRandomAccessRange;
5013 
5014 	String str;
5015 
5016 	struct Range{
5017 		int i;
5018 		this(int i){this.i = i;}
5019 		char front(){return 'x';}
5020 		void popFront(){i -= 1;}
5021 		bool empty(){return i == 0;}
5022 		int length(){return i;}
5023 
5024 	}
5025 	static assert(isInputRange!Range);
5026 	str.append(Range(4));
5027 
5028 	assert(str == "xxxx");
5029 
5030 }
5031 
5032 /+
5033 //appendMore
5034 unittest{
5035 	import std.range : ElementEncodingType, isInputRange, isRandomAccessRange;
5036 
5037 	String str;
5038 
5039 	str.appendMore(1, 2, '-', "lol");
5040 
5041 	assert(str == "12-lol");
5042 
5043 }
5044 +/