1 /**
2 	Common code shared with other `btl.autoptr` modules .
3 
4 	License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
5 	Authors:   Adam Búš
6 */
7 module btl.autoptr.common;
8 
9 import std.meta : AliasSeq;
10 
11 import btl.traits.common;
12 import btl.traits.assume;
13 import btl.lifetime;
14 
15 import btl.internal.traits;
16 import btl.internal.allocator;
17 import btl.internal.gc;
18 
19 
20 
21 /**
22 	Type used as parameter for function pointer returned from `DestructorType`.
23 */
24 public alias Evoid = btl.lifetime.Evoid;
25 
26 
27 /**
28 	Type used in forward constructors.
29 */
30 alias Forward = btl.traits.common.Forward;
31 
32 
33 
34 /**/
35 package struct SmartPtr{}
36 
37 
38 
39 /**
40 	Default `ControlBlock` for `SharedPtr` and `RcPtr`.
41 */
42 public alias SharedControlBlock = ControlBlock!(int, int);
43 public deprecated alias SharedControlType = SharedControlBlock;
44 
45 
46 
47 /**
48 	Default `ControlBlock` for `UniquePtr`.
49 */
50 public alias UniqueControlBlock = ControlBlock!void;
51 public deprecated alias UniqueControlType = UniqueControlBlock;
52 
53 
54 
55 /**
56 	Default allcoator for `SharedPtr.make`, `RcPtr.make`, `UniquePtr.make` and `IntrusivePtr.make`.
57 */
58 public alias DefaultAllocator = Mallocator;
59 
60 
61 
62 
63 /**
64 	Check if type `Type` is of type destructor type (is(void function(Evoid* )pure nothrow @safe @nogc : Type))
65 */
66 alias isDestructorType = btl.lifetime.isDtorType;
67 
68 
69 ///
70 unittest{
71 	static assert(isDestructorType!(void function(Evoid* )pure));
72 	static assert(isDestructorType!(DestructorType!long));
73 	static assert(!isDestructorType!(long));
74 }
75 
76 
77 
78 /**
79 	Destructor type of destructors of types `Types` ( void function(Evoid*)@destructor_attributes ).
80 */
81 public template DestructorType(Types...){
82 	import std.traits : Unqual, isDynamicArray, BaseClassesTuple;
83 	import std.range : ElementEncodingType;
84 	import std.meta : AliasSeq;
85 
86 	static void fn_body(Evoid*)pure nothrow @safe @nogc{}
87 
88 	static void impl()(Evoid*){
89 
90 		static foreach(alias Type; Types){
91 			static if(is(Type == class)){
92 				{
93 					ClassDtorType!Type fn = &fn_body;
94 					fn(null);
95 				}
96 			}
97 			else static if(isDynamicArray!Type){
98 				{
99 					ElementEncodingType!(Unqual!Type) tmp;
100 				}
101 			}
102 			else static if(is(void function(Evoid*)pure nothrow @safe @nogc : Unqual!Type)){
103 				{
104 					Unqual!Type fn = &fn_body;
105 					fn(null);
106 				}
107 			}
108 			else{
109 				{
110 					DtorType!Type fn = &fn_body;
111 					fn(null);
112 				}
113 			}
114 		}
115 	}
116 
117 	alias DestructorType = typeof(&impl!());
118 }
119 
120 
121 ///
122 unittest{
123 	static assert(is(DestructorType!long == void function(Evoid*)pure nothrow @safe @nogc));
124 
125 
126 	static struct Struct{
127 		~this()nothrow @system{
128 		}
129 	}
130 	static assert(is(DestructorType!Struct == void function(Evoid*)nothrow @system));
131 
132 
133 	version(D_BetterC)
134 		static extern(C)class Class{
135 			~this()pure @trusted{
136 
137 			}
138 		}
139 	else
140 		static class Class{
141 			~this()pure @trusted{
142 
143 			}
144 		}
145 
146 	static assert(is(DestructorType!Class == void function(Evoid*)pure @safe));
147 
148 	//multiple types:
149 	static assert(is(DestructorType!(Class, Struct, long) == void function(Evoid*)@system));
150 
151 	static assert(is(
152 		DestructorType!(Class, DestructorType!long, DestructorType!Struct) == DestructorType!(Class, Struct, long)
153 	));
154 }
155 
156 
157 
158 /**
159 	Similiar to `DestructorType` but returns destructor attributes of type `Deleter` and attributes necessary to call variable of type `Deleter` with parameter of type `T`.
160 */
161 public template DestructorDeleterType(T, Deleter){
162 	import std.traits : isCallable;
163 
164 	static assert(isCallable!Deleter);
165 
166 	static assert(__traits(compiles, (ElementReferenceTypeImpl!T elm){
167 		cast(void)Deleter.init(elm);
168 	}));
169 
170 	alias Get(T) = T;
171 
172 	static void impl()(Evoid*){
173 		ElementReferenceTypeImpl!T elm;
174 
175 		Deleter deleter;
176 
177 		cast(void)deleter(elm);
178 	}
179 
180 	alias DestructorDeleterType = typeof(&impl!());
181 
182 }
183 
184 
185 
186 /**
187 	Similiar to `DestructorType` but returns destructor attributes of type `Allocator` and attributes of methods `void[] allocate(size_t)` and `void deallocate(void[])`.
188 
189 	If method `allocate` is `@safe`/`@trusted` then method `deallocate` is assumed to be `@trusted` even if doesn't have `@safe`/`@trusted` attribute.
190 */
191 public template DestructorAllocatorType(Allocator){
192 	import std.traits : Unqual, isPointer, PointerTarget, isAggregateType, hasMember;
193 	import std.range : ElementEncodingType;
194 	import std.meta : AliasSeq;
195 
196 	static if(isPointer!Allocator)
197 		alias AllocatorType = PointerTarget!Allocator;
198 	else
199 		alias AllocatorType = Allocator;
200 
201 	static assert(isAggregateType!AllocatorType);
202 
203 	static assert(hasMember!(AllocatorType, "deallocate"));
204 	static assert(hasMember!(AllocatorType, "allocate"));
205 
206 	static if(isStatelessAllocator!Allocator){
207 		static assert(__traits(compiles, (){
208 			const size_t size;
209 			void[] data = statelessAllcoator!Allocator.allocate(size);
210 		}()));
211 
212 		static assert(__traits(compiles, (){
213 			void[] data;
214 			statelessAllcoator!Allocator.deallocate(data);
215 		}()));
216 	}
217 	else{
218 		static assert(__traits(compiles, (){
219 			const size_t size;
220 			Allocator.init.allocate(size);
221 		}()));
222 
223 		static assert(__traits(compiles, (){
224 			void[] data;
225 			Allocator.init.deallocate(data);
226 		}()));
227 	}
228 
229 
230 	alias Get(T) = T;
231 
232 	static void impl()(Evoid*){
233 		static if(!isStatelessAllocator!Allocator){
234 			{
235 				Allocator allocator;
236 			}
237 		}
238 		void[] data;
239 		const size_t size;
240 
241 		static if(isStatelessAllocator!Allocator){
242 			enum bool safe_alloc = __traits(compiles, ()@safe{
243 				const size_t size;
244 				statelessAllcoator!Allocator.allocate(size);
245 			}());
246 
247 			data = statelessAllcoator!Allocator.allocate(size);
248 
249 			static if(safe_alloc)
250 				function(void[] data)@trusted{
251 					statelessAllcoator!Allocator.deallocate(data);
252 				}(data);
253 			else
254 				statelessAllcoator!Allocator.deallocate(data);
255 		}
256 		else{
257 			enum bool safe_alloc = __traits(compiles, ()@safe{
258 				const size_t size;
259 				Allocator.init.allocate(size);
260 			}());
261 
262 			data = Allocator.init.allocate(size);
263 
264 			static if(safe_alloc)
265 				function(void[] data)@trusted{
266 					Allocator.init.deallocate(data);
267 				}(data);
268 			else
269 				Allocator.init.deallocate(data);
270 		}
271 
272 	}
273 
274 	alias DestructorAllocatorType = typeof(&impl!());
275 }
276 
277 
278 
279 /**
280 	This template deduce `ControlType` shared qualifier in `SharedPtr`, `RcPtr` and `UniquePtr`.
281 
282 	If `Type` is shared then `ControlType` is shared too (atomic counting).
283 */
284 public template ControlBlockDeduction(Type, ControlType){
285 	import std.traits : Select;
286 
287 	alias impl = Select!(
288 		is(Type == shared), /+|| is(Type == immutable)+/
289 		shared(ControlType),
290 		ControlType
291 	);
292 
293 	alias ControlBlockDeduction = impl;
294 }
295 deprecated alias ControlTypeDeduction = ControlBlockDeduction;
296 
297 
298 
299 ///
300 unittest{
301 	alias CB = ControlBlock!(int, int);
302 
303 	static assert(is(ControlBlockDeduction!(long, CB) == CB));
304 	static assert(is(ControlBlockDeduction!(void, CB) == CB));
305 	static assert(is(ControlBlockDeduction!(shared double, CB) == shared CB));
306 	static assert(is(ControlBlockDeduction!(const int, CB) == CB));
307 	static assert(is(ControlBlockDeduction!(shared const int, CB) == shared CB));
308 
309 	static assert(is(ControlBlockDeduction!(immutable int, CB) == CB));
310 
311 	static assert(is(ControlBlockDeduction!(shared int[], CB) == shared CB));
312 	static assert(is(ControlBlockDeduction!(shared(int)[], CB) == CB));
313 }
314 
315 
316 /**
317 	Check if type `T` is of type `ControlBlock!(...)`.
318 */
319 public template isControlBlock(T...)
320 if(T.length == 1){
321 	import std.traits : Unqual, isMutable;
322 
323 	enum bool isControlBlock = is(
324 		Unqual!(T[0]) == ControlBlock!Args, Args...
325 	);
326 }
327 
328 ///
329 unittest{
330 	static assert(!isControlBlock!long);
331 	static assert(!isControlBlock!(void*));
332 	static assert(isControlBlock!(ControlBlock!long));  
333 	static assert(isControlBlock!(ControlBlock!(int, int)));
334 }
335 
336 
337 /**
338 	Control block for `SharedPtr`, `RcPtr`, `UniquePtr` and `IntrusivePtr`.
339 
340 	Contains ref counting and dynamic dispatching for destruction and dealocation of managed object.
341 
342 	Template parameters:
343 
344 		`_Shared` signed integer for ref counting of `SharedPtr` or void if ref counting is not necessary (`UniquePtr` doesn't need ref counting).
345 
346 		`_Weak` signed integer for weak ref counting of `SharedPtr` or void if weak pointer is not necessary.
347 
348 */
349 public template ControlBlock(_Shared, _Weak = void){
350 	import std.traits : Unqual, isUnsigned, isIntegral, isMutable;
351 	import core.atomic;
352 
353 	static assert((isIntegral!_Shared && !isUnsigned!_Shared) || is(_Shared == void));
354 	static assert(is(Unqual!_Shared == _Shared));
355 
356 	static assert((isIntegral!_Weak && !isUnsigned!_Weak) || is(_Weak == void));
357 	static assert(is(Unqual!_Weak == _Weak));
358 
359 	struct ControlBlock{
360 		/**
361 			Signed integer for ref counting of `SharedPtr` or void if ref counting is not necessary (`UniquePtr`). 
362 		*/
363 		public alias Shared = _Shared;
364 
365 		/**
366 			Signed integer for weak ref counting of `SharedPtr` or void if weak counting is not necessary (`UniquePtr` or `SharedPtr` without weak ptr).
367 		*/
368 		public alias Weak = _Weak;
369 
370 		/**
371 			`true` if `ControlBlock` has ref counting (`Shared != void`).
372 		*/
373 		public enum bool hasSharedCounter = !is(_Shared == void);
374 
375 		/**
376 			`true` if `ControlBlock` has weak ref counting (`Weak != void`).
377 		*/
378 		public enum bool hasWeakCounter = !is(_Weak == void);
379 
380 		/**
381 			Copy constructor is @disabled.
382 		*/
383 		public @disable this(scope ref const typeof(this) )scope pure nothrow @safe @nogc;
384 
385 		/**
386 			Assign is @disabled.
387 		*/
388 		public @disable void opAssign(scope ref const typeof(this) )scope pure nothrow @safe @nogc;
389 
390 
391 		//necessary for intrusive ptr
392 		package void initialize(this This)(immutable Vtable* vptr)scope pure nothrow @trusted @nogc{
393 			(cast(Unqual!This*)&this).vptr = vptr;
394 		}
395 
396 		static assert(hasSharedCounter >= hasWeakCounter);
397 
398 		package static struct Vtable{
399 
400 			static if(hasSharedCounter)
401 			void function(ControlBlock*)pure nothrow @safe @nogc on_zero_shared;
402 
403 			static if(hasWeakCounter)
404 			void function(ControlBlock*)pure nothrow @safe @nogc on_zero_weak;
405 
406 			void function(ControlBlock*, bool)pure nothrow @safe @nogc manual_destroy;
407 
408 			bool initialized()const pure nothrow @safe @nogc{
409 				return manual_destroy !is null;
410 			} 
411 
412 			bool valid()const pure nothrow @safe @nogc{
413 				bool result = true;
414 				static if(hasSharedCounter){
415 					if(on_zero_shared is null)
416 						return false;
417 				}
418 				static if(hasWeakCounter){
419 					if(on_zero_weak is null)
420 						return false;
421 				}
422 
423 				return manual_destroy !is null;
424 			}
425 		}
426 
427 		private immutable(Vtable)* vptr;
428 
429 		static if(hasSharedCounter)
430 			private Shared shared_count = 0;
431 
432 		static if(hasWeakCounter)
433 			private Weak weak_count = 0;
434 
435 		package this(this This)(immutable Vtable* vptr)pure nothrow @safe @nogc{
436 			assert(vptr !is null);
437 			this.vptr = vptr;
438 		}
439 
440 		package final auto count(bool weak, this This)()scope const pure nothrow @safe @nogc{
441 			static if(weak){
442 				static if(hasWeakCounter){
443 					static if(is(This == shared))
444 						return atomicLoad(this.weak_count);
445 					else
446 						return this.weak_count;
447 				}
448 				else
449 					return int.init;
450 			}
451 			else{
452 				static if(hasSharedCounter){
453 					static if(is(This == shared))
454 						return atomicLoad(this.shared_count);
455 					else
456 						return this.shared_count;
457 				}
458 				else
459 					return int.max;
460 			}
461 
462 		}
463 
464 
465 		package final void add(bool weak, this This)()scope @trusted pure nothrow @nogc
466 		if(isMutable!This){
467 			enum bool atomic = is(This == shared);
468 
469 			static if(weak){
470 				static if(hasWeakCounter){
471 					rc_increment!atomic(this.weak_count);
472 				}
473 			}
474 			else{
475 				static if(hasSharedCounter){
476 					rc_increment!atomic(this.shared_count);
477 				}
478 			}
479 		}
480 
481 		public final void release(bool weak, this This)()@trusted pure nothrow @nogc{
482 			enum bool atomic = is(This == shared);
483 			auto self = cast(Unconst!This*)&this;
484 
485 			static if(is(This == immutable)){
486 				static if(hasSharedCounter)
487 					assert(this.count!(false) == 0);
488 				static if(hasWeakCounter)
489 					assert(this.count!(true) == 0);
490 			}
491 
492 			static if(!hasSharedCounter){
493 				static assert(is(This == immutable));
494 				self.manual_destroy(true);  ///TODO
495 			}
496 			else static if(weak){
497 				static if(hasWeakCounter){
498 					static if(atomic){
499 						if(atomicLoad!(MemoryOrder.acq)(self.weak_count) == 0)
500 							self.on_zero_weak();
501 
502 						else if(rc_decrement!atomic(self.weak_count) == -1)
503 							self.on_zero_weak();
504 					}
505 					else{
506 						if(this.weak_count == 0)
507 							self.on_zero_weak();
508 						else if(rc_decrement!atomic(self.weak_count) == -1)
509 							self.on_zero_weak();
510 					}
511 				}
512 			}
513 			else{
514 				static assert(hasSharedCounter);
515 
516 				if(rc_decrement!atomic(self.shared_count) == -1){
517 					//auto tmp = &this;
518 					//auto self = &this;
519 					self.on_zero_shared();
520 
521 					self.release!true;
522 				}
523 			}
524 		}
525 
526 		static if(hasSharedCounter){
527 			package final bool add_shared_if_exists()@trusted pure nothrow @nogc{
528 
529 				if(this.shared_count == -1){
530 					return false;
531 				}
532 				this.shared_count += 1;
533 				return true;
534 			}
535 
536 			package final bool add_shared_if_exists()shared @trusted pure nothrow @nogc{
537 				auto owners = atomicLoad(this.shared_count);
538 
539 				while(owners != -1){
540 					import core.atomic;
541 					if(casWeak(&this.shared_count,
542 						&owners,
543 						cast(Shared)(owners + 1)
544 					)){
545 						return true;
546 					}
547 				}
548 
549 				return false;
550 			}
551 		}
552 
553 		static if(hasSharedCounter)
554 		package void on_zero_shared(this This)()pure nothrow @nogc @trusted{
555 			this.vptr.on_zero_shared(cast(ControlBlock*)&this);
556 		}
557 
558 		static if(hasWeakCounter)
559 		package void on_zero_weak(this This)()pure nothrow @nogc @trusted{
560 			this.vptr.on_zero_weak(cast(ControlBlock*)&this);
561 		}
562 
563 		package void manual_destroy(this This)(bool dealocate)pure nothrow @nogc @trusted{
564 			this.vptr.manual_destroy(cast(ControlBlock*)&this, dealocate);
565 		}
566 	}
567 }
568 
569 
570 ///
571 unittest{
572 	static assert(is(ControlBlock!(int, long).Shared == int));
573 	static assert(is(ControlBlock!(int, long).Weak == long));
574 	static assert(is(ControlBlock!int.Shared == int));
575 	static assert(is(ControlBlock!int.Weak == void));
576 
577 	static assert(ControlBlock!(int, int).hasSharedCounter);
578 	static assert(ControlBlock!(int, int).hasWeakCounter);
579 
580 	static assert(is(ControlBlock!int == ControlBlock!(int, void)));  
581 	static assert(ControlBlock!int.hasSharedCounter);   
582 	static assert(ControlBlock!int.hasWeakCounter == false);
583 
584 	static assert(ControlBlock!void.hasSharedCounter == false);
585 	static assert(ControlBlock!void.hasWeakCounter == false);
586 }
587 
588 
589 
590 /**
591 	Return number of `ControlBlock`s in type `Type`.
592 
593 	`IntrusivePtr` need exact `1` control block.
594 */
595 public template isIntrusive(Type){
596 	static if(is(Type == struct)){
597 		enum size_t impl = isIntrusiveStruct!(Type)();
598 	}
599 	else static if(is(Type == class)){
600 		enum size_t impl = isIntrusiveClass!(Type, false)();
601 	}
602 	else{
603 		enum size_t impl = 0;
604 	}
605 
606 	enum size_t isIntrusive = impl;
607 }
608 
609 ///
610 unittest{
611 	static assert(isIntrusive!long == 0);
612 
613 	static assert(isIntrusive!(ControlBlock!int) == 0);
614 
615 	static class Foo{
616 		long x;
617 		ControlBlock!int control;
618 	}
619 
620 	static assert(isIntrusive!Foo == 1);
621 
622 	static struct Struct{
623 		long x;
624 		ControlBlock!int control;
625 		Foo foo;
626 	}
627 	static assert(isIntrusive!Struct == 1);
628 
629 
630 	static class Bar : Foo{
631 		const ControlBlock!int control2;
632 		Struct s;
633 
634 	}
635 	static assert(isIntrusive!Bar == 2);
636 
637 
638 	static class Zee{
639 		long l;
640 		double x;
641 		Struct str;
642 	}
643 	static assert(isIntrusive!Zee == 0);
644 
645 }
646 
647 private size_t isIntrusiveClass(Type, bool ignoreBase)()pure nothrow @trusted @nogc
648 if(is(Type == class)){
649 	import std.traits : BaseClassesTuple;
650 
651 	Type ty = null;
652 
653 	size_t result = 0;
654 
655 	static foreach(alias T; typeof(ty.tupleof)){
656 		static if(is(T == struct) && isControlBlock!T)
657 			result += 1;
658 	}
659 
660 	static if(!ignoreBase)
661 	static foreach(alias T; BaseClassesTuple!Type){
662 		result += isIntrusiveClass!(T, true);
663 	}
664 
665 	return result;
666 
667 }
668 
669 private size_t isIntrusiveStruct(Type)()pure nothrow @trusted @nogc
670 if(is(Type == struct)){
671 	Type* ty = null;
672 
673 	size_t result = 0;
674 
675 	static foreach(alias T; typeof((*ty).tupleof)){
676 		static if(is(T == struct) && isControlBlock!T)
677 			result += 1;
678 	}
679 
680 	return result;
681 }
682 
683 
684 
685 /**
686 	Alias to `ControlBlock` including qualifiers contained by `Type`.
687 
688 	If `mutable` is `true`, then result type alias is mutable (can be shared).
689 */
690 public template IntrusiveControlBlock(Type, bool mutable = false){
691 
692 	static if(is(Type == class))
693 		alias PtrControlBlock = typeof(intrusivControlBlock(Type.init));
694 	else static if(is(Type == struct))
695 		alias PtrControlBlock = typeof(intrusivControlBlock(*cast(Type*)null));
696 	else 
697 		alias PtrControlBlock = void*;
698 
699 
700 	import std.traits : CopyTypeQualifiers, PointerTarget, Unconst;
701 
702 	static if(mutable && is(PtrControlBlock == shared))
703 		alias impl = shared(Unconst!(PointerTarget!PtrControlBlock));
704 	else
705 		alias impl = PointerTarget!PtrControlBlock;
706 
707 	alias IntrusiveControlBlock = impl;
708 
709 }
710 
711 ///
712 unittest{
713 
714 	static class Foo{
715 		ControlBlock!int c;
716 	}
717 
718 	static assert(is(
719 		IntrusiveControlBlock!(Foo) == ControlBlock!int
720 	));
721 	static assert(is(
722 		IntrusiveControlBlock!(const Foo) == const ControlBlock!int
723 	));
724 	static assert(is(
725 		IntrusiveControlBlock!(shared Foo) == shared ControlBlock!int
726 	));
727 	static assert(is(
728 		IntrusiveControlBlock!(const shared Foo) == const shared ControlBlock!int
729 	));
730 	static assert(is(
731 		IntrusiveControlBlock!(immutable Foo) == immutable ControlBlock!int
732 	));
733 
734 
735 
736 	static class Bar{
737 		shared ControlBlock!int c;
738 	}
739 
740 	static assert(is(
741 		IntrusiveControlBlock!(Bar) == shared ControlBlock!int
742 	));
743 	static assert(is(
744 		IntrusiveControlBlock!(const Bar) == const shared ControlBlock!int
745 	));
746 	static assert(is(
747 		IntrusiveControlBlock!(shared Bar) == shared ControlBlock!int
748 	));
749 	static assert(is(
750 		IntrusiveControlBlock!(const shared Bar) == const shared ControlBlock!int
751 	));
752 	static assert(is(
753 		IntrusiveControlBlock!(immutable Bar) == immutable ControlBlock!int
754 	));
755 
756 
757 
758 	static assert(is(
759 		IntrusiveControlBlock!(long) == void
760 	));
761 
762 }
763 
764 
765 
766 
767 /**
768 	Check if `T` is smart pointer of type `btl.autoptr.shared_ptr.SharedPtr`, `btl.autoptr.rc_ptr.RcPtr` or `btl.autoptr.intrusive_ptr.IntrusivePtr`.
769 */
770 template isSmartPtr(T){
771 	/+import btl.autoptr.shared_ptr : isSharedPtr;
772 	import btl.autoptr.rc_ptr : isRcPtr;
773 	import btl.autoptr.intrusive_ptr : isIntrusivePtr;
774 
775 	enum bool isSmartPtr = false
776 		|| isSharedPtr!T
777 		|| isRcPtr!T
778 		|| isIntrusivePtr!T;+/
779 	enum bool isSmartPtr = is(T.SmartPtr : .SmartPtr);
780 }
781 
782 
783 
784 import std.meta : allSatisfy, staticMap, AliasSeq;
785 import std.traits : isMutable;
786 import core.lifetime : forward, move;
787 
788 /**
789 	Sefly dereference all `args` of types `btl.autoptr.shared_ptr.SharedPtr`, `btl.autoptr.rc_ptr.RcPtr` and `btl.autoptr.intrusive_ptr.IntrusivePtr` and forward them to callable alias `fn`.
790 
791 	Ref args are copyied and non ref args are moved.
792 
793 */
794 public template apply(alias fn){
795 	auto impl(Args...)(scope Args args){
796 		pragma(inline, true); @property auto elm(alias arg)()@trusted{
797 			return arg.element();
798 		}
799 
800 		return fn(staticMap!(elm, args));
801 	}
802 
803 	auto apply(Args...)(scope auto ref Args args)
804 	if(    allSatisfy!(isSmartPtr, Args)
805 		&& allSatisfy!(isMutable, staticMap!(GetControlType, Args))
806 	){
807 		pragma(inline, true); @property auto ref param(alias arg)()@trusted{
808 			static assert(!is(typeof(arg) == shared));
809 
810 			static if(arg.isWeak)
811 				return arg.lock();
812 			else
813 				return forward!arg;
814 		}
815 		return impl(staticMap!(param, args));
816 	}
817 }
818 
819 
820 
821 public auto mutablePtr(P)(scope auto ref P ptr)@system //@system
822 if(true
823     && isSmartPtr!P //(isIntrusivePtr!P || isSharedPtr!P || isRcPtr!P)
824     && !is(P == immutable) && !is(P == inout) && !is(P.ControlType == immutable)
825 ){
826     import std.traits : CopyTypeQualifiers, Unconst, isMutable, TemplateOf;
827 
828     static assert(isMutable!(P.ControlType));
829 
830     alias Ptr = TemplateOf!P;
831 
832     alias Self = Ptr!(
833         CopyTypeQualifiers!(P, P.ElementType),
834         P.DestructorType,
835         P.ControlType,
836         P.isWeak
837     );
838 
839     static if(__traits(isRef, ptr))
840         return *cast(Self*)&ptr;
841     else
842         return move(*cast(Self*)&ptr);
843 }
844 
845 
846 ///
847 @safe pure nothrow @nogc unittest{
848 	import btl.autoptr.shared_ptr;
849 	import btl.autoptr.rc_ptr;
850 	import btl.autoptr.intrusive_ptr;
851 
852 	import core.lifetime : move;
853 
854 	static class Foo{
855 		ControlBlock!(int, int) c;
856 		int i;
857 
858 		this(int i)pure nothrow @safe @nogc{
859 			this.i = i;
860 		}
861 
862 		~this()pure nothrow @safe @nogc{
863 			i = -1;
864 		}
865 	}
866 
867 	()@safe{
868 		auto a = SharedPtr!long.make(42);
869 		auto b = RcPtr!float.make(3.14);
870 		auto c = IntrusivePtr!Foo.make(123);
871 
872 		assert(a.useCount == 1);
873 		assert(b.useCount == 1);
874 		assert(c.useCount == 1);
875 
876 		int i = apply!((scope long* x, scope float* y, scope Foo z){
877 			assert(a.useCount == 2);
878 			assert(b.useCount == 2);
879 
880 			a = null;
881 			b = null;
882 			c = null;
883 
884 			assert(z.i != -1);
885 			//x, y, z are still valid until end of the scope.
886 
887 			return z.i;
888 		})(a, b, move(c));
889 
890 		assert(i == 123);
891 	}();
892 
893 }
894 
895 
896 
897 package template weakLock(From, To){
898 	enum weakLock = (From.isWeak && !To.isWeak);
899 }
900 
901 package template GetControlType(Ptr){
902 	import std.traits : CopyTypeQualifiers;
903 
904 	alias GetControlType = CopyTypeQualifiers!(Ptr, Ptr.ControlType);
905 }
906 
907 package template GetElementType(Ptr){
908 	import std.traits : CopyTypeQualifiers;
909 
910 	alias GetElementType = CopyTypeQualifiers!(Ptr, Ptr.ElementType);
911 }
912 
913 package template GetElementReferenceType(Ptr){
914 	import std.traits : CopyTypeQualifiers;
915 
916 	alias GetElementReferenceType = ElementReferenceTypeImpl!(GetElementType!Ptr);
917 }
918 
919 
920 package template UnqualSmartPtr(Ptr){
921 	import std.traits : TemplateOf;
922 
923 	alias SmartPtr = TemplateOf!Ptr;
924 
925 	alias UnqualSmartPtr = SmartPtr!(
926 		GetElementType!Ptr,
927 		Ptr.DestructorType,
928 		GetControlType!Ptr,
929 		Ptr.isWeak
930 	);
931 }
932 
933 package template ElementReferenceTypeImpl(T){
934     import std.traits : Select, isDynamicArray;
935     import std.range : ElementEncodingType;
936 
937 
938     static if(false
939         || is(T == class) || is(T == interface)
940         || is(T == function) || is(T == delegate)
941         || is(T : U*, U)
942     ){
943         alias ElementReferenceTypeImpl = T;
944     }
945     else static if(isDynamicArray!T){
946         alias ElementReferenceTypeImpl = ElementEncodingType!T[];
947     }
948     else{
949         alias ElementReferenceTypeImpl = T*;
950     }
951 }
952 
953 package template ElementPointerTypeImpl(T){
954     import std.traits : Select, isDynamicArray;
955     import std.range : ElementEncodingType;
956 
957 
958     static if(false
959         || is(T == class) || is(T == interface)
960         //|| is(T == function) || is(T == delegate)
961         //|| is(T : U*, U)
962     ){
963         alias ElementPointerTypeImpl = T;
964     }
965     else static if(isDynamicArray!T){
966         alias ElementPointerTypeImpl = ElementEncodingType!T*;
967     }
968     else{
969         alias ElementPointerTypeImpl = T*;
970     }
971 }
972 
973 
974 package static auto lockSmartPtr(alias fn, Ptr, Args...)
975 (scope auto ref shared Ptr ptr, scope auto ref Args args){
976 	import std.traits : CopyConstness, CopyTypeQualifiers, Unqual;
977 	import core.lifetime : forward;
978 	import btl.internal.mutex : getMutex;
979 
980 	shared mutex = getMutex(ptr);
981 
982 	mutex.lock();
983 	scope(exit)mutex.unlock();
984 
985 	alias Result = UnqualSmartPtr!(shared Ptr);
986 
987 
988 	return fn(
989 		*(()@trusted => cast(Result*)&ptr )(),
990 		forward!args
991 	);
992 }
993 
994 
995 import std.traits : BaseClassesTuple, Unqual, Unconst, CopyTypeQualifiers;
996 import std.meta : AliasSeq;
997 
998 /*
999 	Return pointer to qualified control block.
1000 	Pointer is mutable and can be shared if control block is shared.
1001 	For example if control block is immutable, then return type can be immtuable(ControlBlock)* or shared(immutable(ControlBlock)*).
1002 	If result pointer is shared then atomic ref counting is necessary.
1003 */
1004 package auto intrusivControlBlock(Type)(return auto ref Type elm)pure nothrow @trusted @nogc{
1005 
1006 	static if(is(Type == struct)){
1007 		static if(isControlBlock!Type){
1008 			static if(is(Type == shared))
1009 				return cast(CopyTypeQualifiers!(shared(void), Type*))&elm;
1010 			else
1011 				return &elm;
1012 		}
1013 		else{
1014 			static assert(isIntrusive!(Unqual!Type) == 1);
1015 
1016 			foreach(ref x; (*cast(Unqual!(typeof(elm))*)&elm).tupleof){
1017 				static if(isControlBlock!(typeof(x))){
1018 					auto control = intrusivControlBlock(*cast(CopyTypeQualifiers!(Type, typeof(x))*)&x);
1019 
1020 					static if(is(Type == shared) || is(typeof(x) == shared))
1021 						return cast(CopyTypeQualifiers!(shared(void), typeof(control)))control;
1022 					else
1023 						return control;
1024 				}
1025 			}
1026 		}
1027 	}
1028 	else static if(is(Type == class)){
1029 		static assert(isIntrusive!(Unqual!Type) == 1);
1030 
1031 		static if(isIntrusiveClass!(Type, true)){
1032 			foreach(ref x; (cast(Unqual!(typeof(elm)))elm).tupleof){
1033 				static if(isControlBlock!(typeof(x))){
1034 					auto control = intrusivControlBlock(*cast(CopyTypeQualifiers!(Type, typeof(x))*)&x);
1035 
1036 					static if(is(Type == shared) || is(typeof(x) == shared))
1037 						return cast(CopyTypeQualifiers!(shared(void), typeof(control)))control;
1038 					else
1039 						return control;
1040 				}
1041 			}
1042 
1043 		}
1044 		else static foreach(alias T; BaseClassesTuple!Type){
1045 			static if(isIntrusiveClass!(T, true)){
1046 
1047 				foreach(ref x; (cast(Unqual!T)elm).tupleof){
1048 					static if(isControlBlock!(typeof(x))){
1049 						auto control = intrusivControlBlock(*cast(CopyTypeQualifiers!(Type, typeof(x))*)&x);
1050 
1051 						static if(is(Type == shared) || is(typeof(x) == shared))
1052 							return cast(CopyTypeQualifiers!(shared(void), typeof(control)))control;
1053 						else
1054 							return control;
1055 					}
1056 				}
1057 
1058 			}
1059 		}
1060 	}
1061 	else{
1062 		return cast(void*)null;
1063 	}
1064 
1065 }
1066 
1067 //control block
1068 unittest{
1069 	import std.traits : lvalueOf;
1070 	static struct Foo{
1071 		ControlBlock!int c;
1072 	}
1073 
1074 	static assert(is(
1075 		typeof(intrusivControlBlock(lvalueOf!Foo)) == ControlBlock!int*
1076 	));
1077 	static assert(is(
1078 		typeof(intrusivControlBlock(lvalueOf!(shared Foo))) == shared ControlBlock!int*
1079 	));
1080 	static assert(is(
1081 		typeof(intrusivControlBlock(lvalueOf!(const Foo))) == const(ControlBlock!int)*
1082 	));
1083 	static assert(is(
1084 		typeof(intrusivControlBlock(lvalueOf!(shared const Foo))) == shared const(ControlBlock!int)*
1085 	));
1086 	static assert(is(
1087 		typeof(intrusivControlBlock(lvalueOf!(immutable Foo))) == immutable(ControlBlock!int)*
1088 	));
1089 	static assert(is(
1090 		typeof(intrusivControlBlock(lvalueOf!(long))) == void*
1091 	));
1092 }
1093 
1094 //shared control block
1095 unittest{
1096 	import std.traits : lvalueOf;
1097 	static struct Foo{
1098 		shared ControlBlock!int c;
1099 	}
1100 
1101 	static assert(is(
1102 		typeof(intrusivControlBlock(lvalueOf!Foo)) == shared ControlBlock!int*
1103 	));
1104 	static assert(is(
1105 		typeof(intrusivControlBlock(lvalueOf!(shared Foo))) == shared ControlBlock!int*
1106 	));
1107 	static assert(is(
1108 		typeof(intrusivControlBlock(lvalueOf!(const Foo))) == shared const(ControlBlock!int)*
1109 	));
1110 	static assert(is(
1111 		typeof(intrusivControlBlock(lvalueOf!(shared const Foo))) == shared const(ControlBlock!int)*
1112 	));
1113 	static assert(is(
1114 		typeof(intrusivControlBlock(lvalueOf!(immutable Foo))) == shared immutable(ControlBlock!int)*
1115 	));
1116 }
1117 
1118 
1119 //std dynamic cast.
1120 package auto dynCastElement(To, From)(return From from)pure nothrow @trusted @nogc
1121 if(isClassOrInterface!From && isClassOrInterface!To){
1122 	import std.traits : CopyTypeQualifiers, Unqual;
1123 
1124 	alias Result = CopyTypeQualifiers!(From, To);
1125 
1126 	return (from is null)
1127 		? Result.init
1128 		: cast(Result)cast(Unqual!To)cast(Unqual!From)from;
1129 }
1130 
1131 
1132 //Return offset of intrusive control block in Type.
1133 package size_t intrusivControlBlockOffset(Type)()pure nothrow @safe @nogc{
1134 	static assert(isIntrusive!(Unqual!Type) == 1);
1135 
1136 	static if(is(Type == struct)){
1137 		static foreach(alias var; Type.tupleof){
1138 			static if(isControlBlock!(typeof(var)))
1139 				return var.offsetof;
1140 		}
1141 	}
1142 	else static if(is(Type == class)){
1143 		static if(isIntrusiveClass!(Type, true)){
1144 			static foreach(alias var; Type.tupleof){
1145 				static if(isControlBlock!(typeof(var)))
1146 					return var.offsetof;
1147 
1148 			}
1149 		}
1150 		else static foreach(alias T; BaseClassesTuple!Type){
1151 			static if(isIntrusiveClass!(T, true)){
1152 				static foreach(alias var; T.tupleof){
1153 					static if(isControlBlock!(typeof(var)))
1154 						return var.offsetof;
1155 				}
1156 			}
1157 		}
1158 	}
1159 	else static assert(0, "no impl");
1160 }
1161 
1162 unittest{
1163 	static assert(isIntrusive!long == 0);
1164 	static assert(isIntrusive!(ControlBlock!int) == 0);
1165 
1166 	static class Foo{
1167 		long x;
1168 		ControlBlock!int control;
1169 	}
1170 
1171 
1172 	{
1173 		Foo foo;
1174 		auto control = intrusivControlBlock(foo);
1175 	}
1176 
1177 
1178 	static assert(isIntrusive!Foo == 1);
1179 	static assert(Foo.control.offsetof == intrusivControlBlockOffset!Foo());
1180 
1181 	static struct Struct{
1182 		long x;
1183 		ControlBlock!int control;
1184 		Foo foo;
1185 	}
1186 
1187 	static assert(isIntrusive!Struct == 1);
1188 	static assert(Struct.control.offsetof == intrusivControlBlockOffset!Struct());
1189 
1190 
1191 	static class Bar : Foo{
1192 		ControlBlock!int control2;
1193 		Struct s;
1194 
1195 	}
1196 
1197 	static assert(isIntrusive!Bar == 2);
1198 }
1199 
1200 
1201 /*
1202 	same as core.lifetime.emplace but limited for intrusive class and struct.
1203 	initialize vptr for intrusive control block before calling ctor of class/struct. 
1204 */
1205 package void emplaceIntrusive(T, Vptr, Args...)(auto ref T chunk, immutable Vptr* vptr, auto ref Args args)
1206 if(isIntrusive!T){
1207 	static assert(is(T == struct) || is(T == class));
1208 	assert(vptr !is null);
1209 
1210 	()@trusted{
1211 		static if(is(T == struct)){
1212 			import core.internal.lifetime : emplaceInitializer;
1213 
1214 			emplaceInitializer(*cast(Unqual!T*)&chunk);
1215 		}
1216 		else static if(is(T == class)){
1217 			// Initialize the object in its pre-ctor state
1218 			enum classSize = __traits(classInstanceSize, T);
1219 			(cast(void*) chunk)[0 .. classSize] = typeid(T).initializer[];  //(() @trusted => (cast(void*) chunk)[0 .. classSize] = typeid(T).initializer[])();
1220 		}
1221 		else static assert(0, "no impl");
1222 
1223 	}();
1224 
1225 	auto control = intrusivControlBlock(chunk);
1226 	control.initialize(vptr);
1227 
1228 	import core.lifetime : forward, emplace;
1229 
1230 
1231 	static if (args.length == 0 && !is(T == class)){
1232 		static assert(is(typeof({static T i;})),
1233 			"Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~
1234 			".this() is annotated with @disable."
1235 		);
1236 
1237 		//emplaceInitializer(chunk);
1238 	}
1239 
1240 	// Call the ctor if any
1241 	else static if (is(typeof(chunk.__ctor(forward!args)))){
1242 		// T defines a genuine constructor accepting args
1243 		// Go the classic route: write .init first, then call ctor
1244 		chunk.__ctor(forward!args);
1245 	}
1246 	else{
1247 		static assert(args.length == 0 && !is(typeof(&T.__ctor)),
1248 			"Don't know how to initialize an object of type "
1249 			~ T.stringof ~ " with arguments " ~ typeof(args).stringof);
1250 	}
1251 
1252 }
1253 
1254 package template MakeEmplace(_Type, _DestructorType, _ControlType, _AllocatorType, bool supportGC){
1255 	import core.lifetime : emplace;
1256 	import std.traits: hasIndirections, isAbstractClass, isMutable, isDynamicArray,
1257 		Select, CopyTypeQualifiers,
1258 		Unqual, Unconst, PointerTarget;
1259 
1260 	///static assert(isIntrusive!_Type == 0);
1261 
1262 	static assert(!isAbstractClass!_Type,
1263 		"cannot create object of abstract class" ~ Unqual!_Type.stringof
1264 	);
1265 	static assert(!is(_Type == interface),
1266 		"cannot create object of interface type " ~ Unqual!_Type.stringof
1267 	);
1268 
1269 	static if(!isDynamicArray!_Type)
1270 	static assert(is(DestructorType!_Type : _DestructorType));
1271 
1272 	static assert(is(DestructorAllocatorType!_AllocatorType : _DestructorType),
1273 		"allocator attributes `" ~ DestructorAllocatorType!_AllocatorType.stringof ~ "`" ~
1274 		"doesn't support destructor attributes `" ~ _DestructorType.stringof
1275 	);
1276 
1277 	enum bool hasStatelessAllocator = isStatelessAllocator!_AllocatorType;
1278 
1279 	enum bool hasWeakCounter = _ControlType.hasWeakCounter;
1280 
1281 	enum bool hasSharedCounter = _ControlType.hasSharedCounter;
1282 
1283 	enum bool allocatorGCRange = supportGC
1284 		&& !hasStatelessAllocator
1285 		&& hasIndirections!_AllocatorType;
1286 
1287 	enum bool dataGCRange = supportGC
1288 		&& (false
1289 			|| classHasIndirections!_Type
1290 			|| hasIndirections!_Type
1291 			|| (is(_Type == class) && is(Unqual!_Type : Object))
1292 		);
1293 
1294 	alias Vtable = _ControlType.Vtable;
1295 
1296 
1297 	struct MakeEmplace{
1298 		private static immutable Vtable vtable;
1299 
1300 		private _ControlType control;
1301 		private void[instanceSize!_Type] data;
1302 
1303 		static if(!hasStatelessAllocator)
1304 			private _AllocatorType allocator;
1305 
1306 		static assert(control.offsetof + typeof(control).sizeof == data.offsetof);
1307 
1308 		version(D_BetterC)
1309 			private static void shared_static_this()pure nothrow @safe @nogc{
1310 				assumePure(()@trusted{
1311 					Vtable* vptr = cast(Vtable*)&vtable;
1312 
1313 					static if(hasSharedCounter)
1314 						vptr.on_zero_shared = &virtual_on_zero_shared;
1315 
1316 					static if(hasWeakCounter)
1317 						vptr.on_zero_weak = &virtual_on_zero_weak;
1318 
1319 					vptr.manual_destroy = &virtual_manual_destroy;
1320 				})();
1321 
1322 			}
1323 		else
1324 			shared static this()nothrow @safe @nogc{
1325 				static if(hasWeakCounter){
1326 					vtable = Vtable(
1327 						&virtual_on_zero_shared,
1328 						&virtual_on_zero_weak,
1329 						&virtual_manual_destroy
1330 					);
1331 				}
1332 				else static if(hasSharedCounter){
1333 					vtable = Vtable(
1334 						&virtual_on_zero_shared,
1335 						&virtual_manual_destroy
1336 					);
1337 				}
1338 				else vtable = Vtable(
1339 					&virtual_manual_destroy
1340 				);
1341 			}
1342 
1343 		@disable public this(this)pure nothrow @safe @nogc;
1344 
1345 		public @property _ControlType* base()return pure nothrow @trusted @nogc{
1346 			//static assert(this.control.offsetof == 0);
1347 			/+return function _ControlType*(ref _ControlType ct)@trusted{
1348 				return &ct;
1349 			}(this.control);+/
1350 			return &this.control;
1351 		}
1352 
1353 		public @property Select!(isClassOrInterface!_Type, _Type, _Type*) get()pure nothrow @trusted @nogc{
1354 			return cast(typeof(return))this.data.ptr;
1355 		}
1356 
1357 
1358 
1359 
1360 		public static MakeEmplace* make(Args...)(_AllocatorType a, auto ref Args args){
1361 			import std.traits: hasIndirections;
1362 			import core.lifetime : forward, emplace;
1363 
1364 			static assert(!isAbstractClass!_Type,
1365 				"cannot create object of abstract class" ~ Unqual!_Type.stringof
1366 			);
1367 			static assert(!is(_Type == interface),
1368 				"cannot create object of interface type " ~ Unqual!_Type.stringof
1369 			);
1370 
1371 
1372 			static if(hasStatelessAllocator)
1373 				void[] raw = statelessAllcoator!_AllocatorType.allocate(typeof(this).sizeof);
1374 			else
1375 				void[] raw = a.allocate(typeof(this).sizeof);
1376 
1377 			if(raw.length == 0)
1378 				return null;
1379 
1380 			smart_ptr_allocate(raw[]);
1381 
1382 			MakeEmplace* result = (()@trusted => cast(MakeEmplace*)raw.ptr)();
1383 
1384 			static if(dataGCRange){
1385 				static assert(supportGC);
1386 				static if(!hasStatelessAllocator)
1387 				static assert(typeof(this).data.offsetof < typeof(this).allocator.offsetof);
1388 
1389 				static if(allocatorGCRange)
1390 					enum size_t gc_range_size = typeof(this).allocator.offsetof
1391 						- typeof(this).data.offsetof
1392 						+ typeof(this.allocator).sizeof;
1393 				else
1394 					enum size_t gc_range_size = data.length;
1395 
1396 				gcAddRange(
1397 					(()@trusted => cast(void*)result.data.ptr)(),
1398 					gc_range_size
1399 				);
1400 			}
1401 			else static if(allocatorGCRange){
1402 				static assert(supportGC);
1403 				static assert(!dataGCRange);
1404 
1405 				gcAddRange(
1406 					cast(void*)&result.allocator,
1407 					_AllocatorType.sizeof
1408 				);
1409 			}
1410 
1411 			//debug new MakeEmplace(forward!(a, args));
1412 			return emplace(result, forward!(a, args));
1413 		}
1414 
1415 		public this(this This, Args...)(_AllocatorType a, auto ref Args args)
1416 		if(isMutable!This){
1417 			version(D_BetterC){
1418 				if(!vtable.initialized())
1419 					shared_static_this();
1420 			}
1421 			else
1422 				assert(vtable.initialized());
1423 
1424 			import core.lifetime : forward, emplace;
1425 
1426 			static if(!hasStatelessAllocator){
1427 				static if(isMoveConstructableElement!_AllocatorType)
1428 					this.allocator = forward!a;
1429 				else
1430 					this.allocator = a;
1431 			}
1432 
1433 			import std.traits : isStaticArray;
1434 			import std.range : ElementEncodingType;
1435 
1436 			assert(vtable.valid, "vtables are not initialized");
1437 			this.control = _ControlType(&vtable);   //this.control.initialize(&vtable);
1438 
1439 			static if(is(Unqual!_Type == void)){
1440 				//nothing
1441 			}
1442 			else static if(isStaticArray!_Type){
1443 				static if(args.length == 1 && is(Args[0] : _Type)){
1444 					//cast(void)emplace!(_Type)(this.data, forward!args);
1445 					cast(void)emplace(
1446 						((ref data)@trusted => cast(_Type*)data.ptr)(this.data),
1447 						forward!args
1448 					);
1449 				}
1450 				else{
1451 					_Type* data = cast(_Type*)this.data.ptr;
1452 
1453 					foreach(ref ElementEncodingType!_Type d; (*data)[]){
1454 
1455 						static if(isClassOrInterface!(ElementEncodingType!_Type)){
1456 							static if(args.length == 0)
1457 								d = null;
1458 							else static if(args.length == 1)
1459 								d = args[0];
1460 							else static assert(0, "no impl");
1461 
1462 						}
1463 						else{
1464 							cast(void)emplace(&d, args);
1465 						}
1466 					}
1467 				}
1468 			}
1469 			else{
1470 				static if(isClassOrInterface!_Type)
1471 					auto data = ((ref data)@trusted => cast(_Type)data.ptr)(this.data);
1472 				else
1473 					auto data = ((ref data)@trusted => cast(_Type*)data.ptr)(this.data);
1474 
1475 				cast(void)emplace(
1476 					data,
1477 					forward!args
1478 				);
1479 			}
1480 
1481 
1482 
1483 			smart_ptr_construct();
1484 		}
1485 
1486 
1487 
1488 		static if(hasSharedCounter){
1489 			public static void virtual_on_zero_shared(Unqual!_ControlType* control)pure nothrow @nogc @trusted{
1490 				auto self = get_offset_this(control);
1491 				self.destruct();
1492 
1493 				static if(!hasWeakCounter)
1494 					self.deallocate();
1495 			}
1496 		}
1497 
1498 		static if(hasWeakCounter){
1499 			public static void virtual_on_zero_weak(Unqual!_ControlType* control)pure nothrow @nogc @trusted{
1500 				auto self = get_offset_this(control);
1501 				self.deallocate();
1502 			}
1503 		}
1504 
1505 		public static void virtual_manual_destroy(Unqual!_ControlType* control, bool dealocate)pure nothrow @nogc @trusted{
1506 			auto self = get_offset_this(control);
1507 			self.destruct();
1508 			if(dealocate)
1509 				self.deallocate();
1510 
1511 		}
1512 
1513 		private static inout(MakeEmplace)* get_offset_this(inout(Unqual!_ControlType)* control)pure nothrow @system @nogc{
1514 			assert(control !is null);
1515 
1516 			 return cast(typeof(return))((cast(void*)control) - MakeEmplace.control.offsetof);
1517 		}
1518 
1519 
1520 		private void destruct()pure nothrow @system @nogc{
1521 
1522 			static if(is(_Type == struct) || is(_Type == class)){
1523 				void* data_ptr = this.data.ptr;
1524 
1525 				//btl.internal.lifetime.destruct!(_Type, DestructorType!void)(data_ptr);
1526 				static if(is(_Type == struct)){
1527 					_Type* data = ((ref data)@trusted => cast(_Type*)data.ptr)(this.data);
1528 					destructImpl!(false, DtorType!void)(*data);
1529 				}
1530 				else static if(is(_Type == class)){
1531 					_Type data = ((ref data)@trusted => cast(_Type)data.ptr)(this.data);
1532 					destructClassImpl!(false, DtorType!void)(data);
1533 				}
1534 				else static assert(0, "no impl");
1535 
1536 				static if(!allocatorGCRange && dataGCRange){
1537 					gcRemoveRange(data_ptr);
1538 				}
1539 
1540 			}
1541 			else static if(is(_Type == interface)){
1542 				assert(0, "no impl");
1543 			}
1544 			else{
1545 				// nothing
1546 			}
1547 
1548 			smart_ptr_destruct();
1549 		}
1550 
1551 		private void deallocate()pure nothrow @system @nogc{
1552 			void* self = cast(void*)&this;
1553 			destructImpl!(false, DtorType!void)(this);//btl.internal.lifetime.destruct!(typeof(this), DestructorType!void)(self);
1554 
1555 			void[] raw = self[0 .. typeof(this).sizeof];
1556 
1557 
1558 			static if(hasStatelessAllocator)
1559 				assumePureNoGcNothrow(function(void[] raw)@trusted => statelessAllcoator!_AllocatorType.deallocate(raw))(raw);
1560 			else
1561 				assumePureNoGcNothrow(function(void[] raw, ref typeof(this.allocator) allo)@trusted => allo.deallocate(raw))(raw, this.allocator);
1562 
1563 
1564 			static if(allocatorGCRange){
1565 				static if(dataGCRange)
1566 					gcRemoveRange(this.data.ptr);
1567 				else
1568 					gcRemoveRange(&this.allocator);
1569 			}
1570 
1571 			smart_ptr_deallocate(raw[]);
1572 		}
1573 
1574 	}
1575 }
1576 
1577 package template MakeDynamicArray(_Type, _DestructorType, _ControlType, _AllocatorType, bool supportGC){
1578 	import std.traits: hasIndirections, isAbstractClass, isDynamicArray, Unqual;
1579 	import std.range : ElementEncodingType;
1580 
1581 	static assert(isDynamicArray!_Type);
1582 
1583 	static assert(is(DestructorType!_Type : _DestructorType));
1584 
1585 	static assert(is(DestructorAllocatorType!_AllocatorType : _DestructorType),
1586 		"allocator attributes `" ~ DestructorAllocatorType!_AllocatorType.stringof ~ "`" ~
1587 		"doesn't support destructor attributes `" ~ _DestructorType.stringof
1588 	);
1589 
1590 	enum bool hasStatelessAllocator = isStatelessAllocator!_AllocatorType;
1591 
1592 	enum bool hasWeakCounter = _ControlType.hasWeakCounter;
1593 
1594 	enum bool hasSharedCounter = _ControlType.hasSharedCounter;
1595 
1596 	//enum bool referenceElementType = isClassOrInterface!_Type;
1597 
1598 	enum bool allocatorGCRange = supportGC
1599 		&& !hasStatelessAllocator
1600 		&& hasIndirections!_AllocatorType;
1601 
1602 	enum bool dataGCRange = supportGC
1603 		&& hasIndirections!(ElementEncodingType!_Type);
1604 
1605 	alias Vtable = _ControlType.Vtable;
1606 
1607 	struct MakeDynamicArray{
1608 		static if(!hasStatelessAllocator)
1609 			private _AllocatorType allocator;
1610 
1611 		private size_t length;
1612 		private _ControlType control;
1613 		private ElementEncodingType!_Type[0] data_impl;
1614 
1615 		static assert(control.offsetof + typeof(control).sizeof == data_impl.offsetof);
1616 
1617 		@property inout(ElementEncodingType!_Type)[] data()return inout pure nothrow @trusted @nogc{
1618 			return data_impl.ptr[0 .. this.length];
1619 		}
1620 
1621 		private static immutable Vtable vtable;
1622 
1623 		version(D_BetterC)
1624 			private static void shared_static_this()pure nothrow @safe @nogc{
1625 				assumePure(()@trusted{
1626 					Vtable* vptr = cast(Vtable*)&vtable;
1627 
1628 					static if(hasSharedCounter)
1629 						vptr.on_zero_shared = &virtual_on_zero_shared;
1630 
1631 					static if(hasWeakCounter)
1632 						vptr.on_zero_weak = &virtual_on_zero_weak;
1633 
1634 					vptr.manual_destroy = &virtual_manual_destroy;
1635 				})();
1636 
1637 			}
1638 		else
1639 			shared static this()nothrow @safe @nogc{
1640 				static if(hasWeakCounter){
1641 					vtable = Vtable(
1642 						&virtual_on_zero_shared,
1643 						&virtual_on_zero_weak,
1644 						&virtual_manual_destroy
1645 					);
1646 				}
1647 				else static if(hasSharedCounter){
1648 					vtable = Vtable(
1649 						&virtual_on_zero_shared,
1650 						&virtual_manual_destroy
1651 					);
1652 				}
1653 				else vtable = Vtable(
1654 					&virtual_manual_destroy
1655 				);
1656 			}
1657 
1658 		@disable public this(this)pure nothrow @safe @nogc;
1659 
1660 		public @property _ControlType* base()return pure nothrow @trusted @nogc{
1661 			return &this.control;
1662 		}
1663 
1664 		public @property auto get()return pure nothrow @trusted @nogc{
1665 			return this.data;
1666 		}
1667 
1668 
1669 
1670 
1671 		public static MakeDynamicArray* make(Args...)(_AllocatorType a, const size_t n, auto ref Args args){
1672 			import std.traits: hasIndirections;
1673 			import core.lifetime : forward, emplace;
1674 
1675 			const size_t arraySize = (ElementEncodingType!_Type.sizeof * n);
1676 
1677 			static if(hasStatelessAllocator)
1678 				void[] raw = statelessAllcoator!_AllocatorType.allocate(typeof(this).sizeof + arraySize);
1679 			else
1680 				void[] raw = a.allocate(typeof(this).sizeof + arraySize);
1681 
1682 			if(raw.length == 0)
1683 				return null;
1684 
1685 			smart_ptr_allocate(raw[]);
1686 
1687 			MakeDynamicArray* result = (()@trusted => cast(MakeDynamicArray*)raw.ptr)();
1688 
1689 
1690 			static if(allocatorGCRange){
1691 				static assert(supportGC);
1692 				static assert(typeof(this).length.offsetof >= typeof(this).allocator.offsetof);
1693 
1694 				static if(dataGCRange)
1695 					const size_t gc_range_size = typeof(this).sizeof
1696 						- typeof(this).allocator.offsetof
1697 						+ arraySize;
1698 				else
1699 					enum size_t gc_range_size = _AllocatorType.sizeof;
1700 
1701 				gcAddRange(
1702 					cast(void*)&result.allocator,
1703 					gc_range_size
1704 				);
1705 			}
1706 			else static if(dataGCRange){
1707 				static assert(supportGC);
1708 				static assert(!allocatorGCRange);
1709 
1710 				gcAddRange(
1711 					(()@trusted => result.data.ptr)(),
1712 					arraySize   //result.data.length * _Type.sizeof
1713 				);
1714 			}
1715 
1716 			return emplace!MakeDynamicArray(result, forward!(a, n, args));
1717 		}
1718 
1719 
1720 		public this(Args...)(_AllocatorType a, const size_t n, auto ref Args args){
1721 			version(D_BetterC){
1722 				if(!vtable.initialized())
1723 					shared_static_this();
1724 			}
1725 			else 
1726 				assert(vtable.initialized());
1727 
1728 			this.control = _ControlType(&vtable);
1729 			assert(vtable.valid, "vtables are not initialized");
1730 
1731 			static if(!hasStatelessAllocator){
1732 				static if(isMoveConstructableElement!_AllocatorType)
1733 					this.allocator = forward!a;
1734 				else
1735 					this.allocator = a;
1736 			}
1737 
1738 			this.length = n;
1739 
1740 			import core.lifetime : emplace;
1741 
1742 			foreach(ref d; this.data[])
1743 				emplace((()@trusted => &d)(), args);
1744 
1745 			smart_ptr_construct();
1746 		}
1747 
1748 
1749 		static if(hasSharedCounter)
1750 		private static void virtual_on_zero_shared(Unqual!_ControlType* control)pure nothrow @nogc @trusted{
1751 			auto self = get_offset_this(control);
1752 			self.destruct();
1753 
1754 			static if(!hasWeakCounter)
1755 				self.deallocate();
1756 		}
1757 
1758 		static if(hasWeakCounter)
1759 		private static void virtual_on_zero_weak(Unqual!_ControlType* control)pure nothrow @nogc @trusted{
1760 			auto self = get_offset_this(control);
1761 			self.deallocate();
1762 		}
1763 
1764 		private static void virtual_manual_destroy(Unqual!_ControlType* control, bool deallocate)pure nothrow @trusted @nogc{
1765 			auto self = get_offset_this(control);
1766 			self.destruct();
1767 
1768 			if(deallocate)
1769 				self.deallocate();
1770 		}
1771 
1772 		private static inout(MakeDynamicArray)* get_offset_this(inout(Unqual!_ControlType)* control)pure nothrow @system @nogc{
1773 			assert(control !is null);
1774 			return cast(typeof(return))((cast(void*)control) - MakeDynamicArray.control.offsetof);
1775 		}
1776 
1777 		private void destruct()pure nothrow @system @nogc{
1778 			destructRangeImpl!(false, DtorType!void)(this.data);
1779 
1780 			static if(!allocatorGCRange && dataGCRange){
1781 				gcRemoveRange(this.data.ptr);
1782 			}
1783 
1784 			smart_ptr_destruct();
1785 		}
1786 
1787 		private void deallocate()pure nothrow @system @nogc{
1788 
1789 			const size_t data_length = ElementEncodingType!_Type.sizeof * this.data.length;
1790 			void* self = cast(void*)&this;
1791 			destructImpl!(false, DtorType!void)(this);    //btl.internal.lifetime.destruct!(typeof(this), DestructorType!void)(self);
1792 
1793 
1794 			void[] raw = self[0 .. typeof(this).sizeof + data_length];
1795 
1796 
1797 
1798 			static if(hasStatelessAllocator)
1799 				assumePureNoGcNothrow(function(void[] raw)@trusted => statelessAllcoator!_AllocatorType.deallocate(raw))(raw);
1800 			else
1801 				assumePureNoGcNothrow(function(void[] raw, ref typeof(this.allocator) allo)@trusted => allo.deallocate(raw))(raw, this.allocator);
1802 
1803 
1804 			static if(allocatorGCRange){
1805 				gcRemoveRange(&this.allocator);
1806 			}
1807 
1808 			smart_ptr_deallocate(raw[]);
1809 		}
1810 
1811 	}
1812 }
1813 
1814 package template MakeIntrusive(_Type/+, _DestructorType+/, _AllocatorType, bool supportGC)
1815 if(isIntrusive!_Type == 1){
1816 	import core.lifetime : emplace;
1817 	import std.traits: hasIndirections, isAbstractClass, isMutable,
1818 		Select, CopyTypeQualifiers,
1819 		Unqual, Unconst, PointerTarget, BaseClassesTuple;
1820 
1821 	static assert(is(_Type == struct) || is(_Type == class));
1822 
1823 	static assert(!isAbstractClass!_Type,
1824 		"cannot create object of abstract class" ~ Unqual!_Type.stringof
1825 	);
1826 
1827 	static assert(!is(_Type == interface),
1828 		"cannot create object of interface type " ~ Unqual!_Type.stringof
1829 	);
1830 
1831 	static assert(is(DestructorAllocatorType!_AllocatorType : .DestructorType!_Type),
1832 		"allocator attributes `" ~ DestructorAllocatorType!_AllocatorType.stringof ~ "`" ~
1833 		"doesn't support destructor attributes `" ~ .DestructorType!_Type.stringof
1834 	);
1835 
1836 	static if(is(_Type == class))
1837 	static foreach(alias Base; BaseClassesTuple!_Type){
1838 		static if(!is(Base == Object))
1839 		static assert(is(.DestructorType!_Type : .DestructorType!Base));
1840 	}
1841 
1842 	alias ControlType = IntrusiveControlBlock!_Type;
1843 
1844 	enum bool hasStatelessAllocator = isStatelessAllocator!_AllocatorType;
1845 
1846 	enum bool hasWeakCounter = ControlType.hasWeakCounter;
1847 
1848 	enum bool hasSharedCounter = ControlType.hasSharedCounter;
1849 
1850 	enum bool allocatorGCRange = supportGC
1851 		&& !hasStatelessAllocator
1852 		&& hasIndirections!_AllocatorType;
1853 
1854 	enum bool dataGCRange = supportGC
1855 		&& (false
1856 			|| classHasIndirections!_Type
1857 			|| hasIndirections!_Type
1858 			|| (is(_Type == class) && is(Unqual!_Type : Object))
1859 		);
1860 
1861 	alias Vtable = ControlType.Vtable;
1862 
1863 
1864 	struct MakeIntrusive{
1865 		private static immutable Vtable vtable;
1866 
1867 
1868 		private @property ref auto control()return pure nothrow @trusted @nogc{
1869 			static if(isClassOrInterface!_Type)
1870 				auto control = intrusivControlBlock(cast(_Type)this.data.ptr);
1871 			else 
1872 				auto control = intrusivControlBlock(*cast(_Type*)this.data.ptr);
1873 
1874 			alias ControlPtr = typeof(control);
1875 
1876 			static if(is(typeof(control) == shared))
1877 				alias MutableControl = shared(Unconst!(PointerTarget!ControlPtr)*);
1878 			else
1879 				alias MutableControl = Unconst!(PointerTarget!ControlPtr)*;
1880 
1881 			//static assert(!is(typeof(*control) == immutable), "intrusive control block cannot be immutable");
1882 			return *cast(MutableControl)control;
1883 		}
1884 
1885 		private void[instanceSize!_Type] data;
1886 
1887 		static if(!hasStatelessAllocator)
1888 			private _AllocatorType allocator;
1889 
1890 		version(D_BetterC)
1891 			private static void shared_static_this()pure nothrow @safe @nogc{
1892 				assumePure(()@trusted{
1893 					Vtable* vptr = cast(Vtable*)&vtable;
1894 
1895 					static if(hasSharedCounter)
1896 						vptr.on_zero_shared = &virtual_on_zero_shared;
1897 
1898 					static if(hasWeakCounter)
1899 						vptr.on_zero_weak = &virtual_on_zero_weak;
1900 
1901 					vptr.manual_destroy = &virtual_manual_destroy;
1902 				})();
1903 
1904 			}
1905 		else
1906 			shared static this()nothrow @safe @nogc{
1907 				static if(hasWeakCounter){
1908 					vtable = Vtable(
1909 						&virtual_on_zero_shared,
1910 						&virtual_on_zero_weak,
1911 						&virtual_manual_destroy
1912 					);
1913 				}
1914 				else static if(hasSharedCounter){
1915 					vtable = Vtable(
1916 						&virtual_on_zero_shared,
1917 						&virtual_manual_destroy
1918 					);
1919 				}
1920 				else vtable = Vtable(
1921 					&virtual_manual_destroy
1922 				);
1923 			}
1924 
1925 		public @property Select!(isClassOrInterface!_Type, _Type, _Type*) get()return pure nothrow @trusted @nogc{
1926 			return cast(typeof(return))this.data.ptr;
1927 		}
1928 
1929 
1930 
1931 
1932 		public static MakeIntrusive* make(Args...)(_AllocatorType a, auto ref Args args){
1933 			import std.traits: hasIndirections;
1934 			import core.lifetime : forward, emplace;
1935 
1936 			static if(hasStatelessAllocator)
1937 				void[] raw = statelessAllcoator!_AllocatorType.allocate(typeof(this).sizeof);
1938 			else
1939 				void[] raw = a.allocate(typeof(this).sizeof);
1940 
1941 			if(raw.length == 0)
1942 				return null;
1943 
1944 			smart_ptr_allocate(raw[]);
1945 
1946 			MakeIntrusive* result = (()@trusted => cast(MakeIntrusive*)raw.ptr)();
1947 
1948 			static if(dataGCRange){
1949 				static assert(supportGC);
1950 
1951 				static if(!hasStatelessAllocator)
1952 				static assert(typeof(this).data.offsetof < typeof(this).allocator.offsetof);
1953 
1954 				static if(allocatorGCRange)
1955 					enum size_t gc_range_size = typeof(this).allocator.offsetof
1956 						- typeof(this).data.offsetof
1957 						+ typeof(this.allocator).sizeof;
1958 				else
1959 					enum size_t gc_range_size = data.length;
1960 
1961 				gcAddRange(
1962 					(()@trusted => cast(void*)result.data.ptr)(),
1963 					gc_range_size
1964 				);
1965 			}
1966 			else static if(allocatorGCRange){
1967 				static assert(supportGC);
1968 				static assert(!dataGCRange);
1969 
1970 				gcAddRange(
1971 					cast(void*)&result.allocator,
1972 					_AllocatorType.sizeof
1973 				);
1974 			}
1975 
1976 			return emplace(result, forward!(a, args));
1977 		}
1978 
1979 
1980 		public this(this This, Args...)(_AllocatorType a, auto ref Args args)
1981 		if(isMutable!This){
1982 			version(D_BetterC){
1983 				if(!vtable.initialized())
1984 					shared_static_this();
1985 			}
1986 			else
1987 				assert(vtable.initialized());
1988 
1989 			import core.lifetime : forward, emplace;
1990 
1991 			static if(!hasStatelessAllocator){
1992 				static if(isMoveConstructableElement!_AllocatorType)
1993 					this.allocator = forward!a;
1994 				else
1995 					this.allocator = a;
1996 			}
1997 
1998 			import std.traits : isStaticArray;
1999 			import std.range : ElementEncodingType;
2000 
2001 			assert(vtable.valid, "vtables are not initialized");
2002 
2003 			static if(is(_Type == class)){
2004 				_Type data = ((ref data)@trusted => cast(_Type)data.ptr)(this.data);
2005 				emplaceIntrusive(data, &vtable, forward!args);
2006 				//emplace(data, forward!args);
2007 				//intrusivControlBlock(data).initialize(&vtable);
2008 			}
2009 			else static if(is(_Type == struct)){ 
2010 				_Type* data = ((ref data)@trusted => cast(_Type*)data.ptr)(this.data);
2011 				emplaceIntrusive(*data, &vtable, forward!args);
2012 				//emplace(data, forward!args);
2013 				//intrusivControlBlock(*data).initialize(&vtable);
2014 			}
2015 			else static assert(0, "no impl");
2016 
2017 
2018 
2019 			smart_ptr_construct();
2020 		}
2021 
2022 
2023 
2024 		static if(hasSharedCounter){
2025 			public static void virtual_on_zero_shared(Unqual!ControlType* control)pure nothrow @nogc @trusted{
2026 				auto self = get_offset_this(control);
2027 				self.destruct();
2028 
2029 				static if(!hasWeakCounter)
2030 					self.deallocate();
2031 			}
2032 		}
2033 
2034 		static if(hasWeakCounter){
2035 			public static void virtual_on_zero_weak(Unqual!ControlType* control)pure nothrow @nogc @trusted{
2036 				auto self = get_offset_this(control);
2037 				self.deallocate();
2038 			}
2039 		}
2040 
2041 		public static void virtual_manual_destroy(Unqual!ControlType* control, bool dealocate)pure nothrow @nogc @trusted{
2042 			auto self = get_offset_this(control);
2043 			self.destruct();
2044 			if(dealocate)
2045 				self.deallocate();
2046 
2047 		}
2048 
2049 		private static inout(MakeIntrusive)* get_offset_this(inout(Unqual!ControlType)* control)pure nothrow @system @nogc{
2050 			assert(control !is null);
2051 
2052 			enum size_t offset = data.offsetof + intrusivControlBlockOffset!_Type;
2053 			return cast(typeof(return))((cast(void*)control) - offset);
2054 		}
2055 
2056 
2057 		private void destruct()pure nothrow @system @nogc{
2058 
2059 			static if(is(_Type == struct) || is(_Type == class)){
2060 				void* data_ptr = this.data.ptr;
2061 				//btl.internal.lifetime.destruct!(_Type, DestructorType!void)(data_ptr);
2062 
2063 				static if(is(_Type == struct)){
2064 					_Type* data = ((ref data)@trusted => cast(_Type*)data.ptr)(this.data);
2065 					destructImpl!(false, DtorType!void)(*data);
2066 				}
2067 				else static if(is(_Type == class)){
2068 					_Type data = ((ref data)@trusted => cast(_Type)data.ptr)(this.data);
2069 					destructClassImpl!(false, DtorType!void)(data);
2070 				}
2071 				else static assert(0, "no impl");
2072 
2073 				static if(!allocatorGCRange && dataGCRange){
2074 					gcRemoveRange(data_ptr);
2075 				}
2076 
2077 			}
2078 			else static if(is(_Type == interface)){
2079 				assert(0, "no impl");
2080 			}
2081 			else{
2082 				// nothing
2083 			}
2084 
2085 			smart_ptr_destruct();
2086 		}
2087 
2088 		private void deallocate()pure nothrow @system @nogc{
2089 			void* self = cast(void*)&this;
2090 			destructImpl!(false, DtorType!void)(this);//btl.internal.lifetime.destruct!(typeof(this), DestructorType!void)(self);
2091 
2092 			void[] raw = self[0 .. typeof(this).sizeof];
2093 
2094 
2095 			static if(hasStatelessAllocator)
2096 				assumePureNoGcNothrow(function(void[] raw)@trusted => statelessAllcoator!_AllocatorType.deallocate(raw))(raw);
2097 			else
2098 				assumePureNoGcNothrow(function(void[] raw, ref typeof(this.allocator) allo)@trusted => allo.deallocate(raw))(raw, this.allocator);
2099 
2100 
2101 			static if(allocatorGCRange){
2102 				static if(dataGCRange)
2103 					gcRemoveRange(this.data.ptr);
2104 				else
2105 					gcRemoveRange(&this.allocator);
2106 			}
2107 
2108 			smart_ptr_deallocate(raw[]);
2109 		}
2110 
2111 	}
2112 }
2113 
2114 package template MakeDeleter(_Type, _DestructorType, _ControlType, DeleterType, _AllocatorType, bool supportGC){
2115 	import std.traits: hasIndirections, isAbstractClass, isDynamicArray, Unqual;
2116 
2117 	static if(!isDynamicArray!_Type)
2118 	static assert(is(DestructorType!_Type : _DestructorType));
2119 
2120 	static assert(is(DestructorAllocatorType!_AllocatorType : _DestructorType),
2121 		"allocator attributes `" ~ DestructorAllocatorType!_AllocatorType.stringof ~ "`" ~
2122 		"doesn't support destructor attributes `" ~ _DestructorType.stringof
2123 	);
2124 
2125 	static assert(is(.DestructorDeleterType!(_Type, DeleterType) : _DestructorType),
2126 		"deleter attributes '" ~ DestructorDeleterType!(_Type, DeleterType).stringof ~
2127 		"' doesn't support destructor attributes " ~ _DestructorType.stringof
2128 	);
2129 
2130 	enum bool hasStatelessAllocator = isStatelessAllocator!_AllocatorType;
2131 
2132 	enum bool hasWeakCounter = _ControlType.hasWeakCounter;
2133 
2134 	enum bool hasSharedCounter = _ControlType.hasSharedCounter;
2135 
2136 	enum bool allocatorGCRange = supportGC
2137 		&& !hasStatelessAllocator
2138 		&& hasIndirections!_AllocatorType;
2139 
2140 	enum bool deleterGCRange = supportGC
2141 		&& hasIndirections!DeleterType;
2142 
2143 	enum bool dataGCRange = supportGC;
2144 
2145 	alias Vtable = _ControlType.Vtable;
2146 
2147 	alias ElementReferenceType = ElementReferenceTypeImpl!_Type;
2148 
2149 	struct MakeDeleter{
2150 		static assert(control.offsetof == 0);
2151 
2152 		private _ControlType control;
2153 
2154 		static if(!hasStatelessAllocator)
2155 			private _AllocatorType allocator;
2156 
2157 		private DeleterType deleter;
2158 		package ElementReferenceType data;
2159 
2160 		private static immutable Vtable vtable;
2161 
2162 		version(D_BetterC)
2163 			private static void shared_static_this()pure nothrow @safe @nogc{
2164 				assumePure(()@trusted{
2165 					Vtable* vptr = cast(Vtable*)&vtable;
2166 
2167 					static if(hasSharedCounter)
2168 						vptr.on_zero_shared = &virtual_on_zero_shared;
2169 
2170 					static if(hasWeakCounter)
2171 						vptr.on_zero_weak = &virtual_on_zero_weak;
2172 
2173 					vptr.manual_destroy = &virtual_manual_destroy;
2174 				})();
2175 
2176 			}
2177 		else
2178 			shared static this()nothrow @safe @nogc{
2179 				static if(hasWeakCounter){
2180 					vtable = Vtable(
2181 						&virtual_on_zero_shared,
2182 						&virtual_on_zero_weak,
2183 						&virtual_manual_destroy
2184 					);
2185 				}
2186 				else static if(hasSharedCounter){
2187 					vtable = Vtable(
2188 						&virtual_on_zero_shared,
2189 						&virtual_manual_destroy
2190 					);
2191 				}
2192 				else vtable = Vtable(
2193 					&virtual_manual_destroy
2194 				);
2195 			}
2196 
2197 
2198 		@disable public this(this)pure nothrow @safe @nogc;
2199 
2200 		public _ControlType* base()pure nothrow @safe @nogc{
2201 			return &this.control;
2202 		}
2203 
2204 		public alias get = data;
2205 
2206 
2207 		public static MakeDeleter* make(Args...)
2208 		(_AllocatorType a, DeleterType deleter, ElementReferenceType data){
2209 			import std.traits: hasIndirections;
2210 			import core.lifetime : forward, emplace;
2211 
2212 			static assert(!isAbstractClass!_Type,
2213 				"cannot create object of abstract class" ~ Unqual!_Type.stringof
2214 			);
2215 			static assert(!is(_Type == interface),
2216 				"cannot create object of interface type " ~ Unqual!_Type.stringof
2217 			);
2218 
2219 
2220 			static if(hasStatelessAllocator)
2221 				void[] raw = statelessAllcoator!_AllocatorType.allocate(typeof(this).sizeof);
2222 			else
2223 				void[] raw = a.allocate(typeof(this).sizeof);
2224 
2225 			if(raw.length == 0)
2226 				return null;
2227 
2228 
2229 			smart_ptr_allocate(raw[]);
2230 
2231 			MakeDeleter* result = (()@trusted => cast(MakeDeleter*)raw.ptr)();
2232 
2233 			static if(allocatorGCRange){
2234 				static assert(supportGC);
2235 				static assert(typeof(this).data.offsetof >= typeof(this).deleter.offsetof);
2236 				static assert(typeof(this).deleter.offsetof >= typeof(this).allocator.offsetof);
2237 
2238 				static if(dataGCRange)
2239 					enum size_t gc_range_size = typeof(this).data.offsetof
2240 						- typeof(this).allocator.offsetof
2241 						+ typeof(this.data).sizeof;
2242 				else static if(deleterGCRange)
2243 					enum size_t gc_range_size = typeof(this).deleter.offsetof
2244 						- typeof(this).allocator.offsetof
2245 						+ typeof(this.deleter).sizeof;
2246 				else
2247 					enum size_t gc_range_size = _AllocatorType.sizeof;
2248 
2249 				gcAddRange(
2250 					cast(void*)&result.allocator,
2251 					gc_range_size
2252 				);
2253 			}
2254 			else static if(deleterGCRange){
2255 				static assert(supportGC);
2256 				static assert(!allocatorGCRange);
2257 				static assert(typeof(this).data.offsetof >= typeof(this).deleter.offsetof);
2258 
2259 				static if(dataGCRange)
2260 					enum size_t gc_range_size = typeof(this).data.offsetof
2261 						- typeof(this).deleter.offsetof
2262 						+ typeof(this.data).sizeof;
2263 				else
2264 					enum size_t gc_range_size = _DeleterType.sizeof;
2265 
2266 				gcAddRange(
2267 					cast(void*)&result.deleter,
2268 					gc_range_size
2269 				);
2270 			}
2271 			else static if(dataGCRange){
2272 				static assert(supportGC);
2273 				static assert(!allocatorGCRange);
2274 				static assert(!deleterGCRange);
2275 
2276 				gcAddRange(
2277 					&result.data,
2278 					ElementReferenceType.sizeof
2279 				);
2280 			}
2281 
2282 			return emplace(result, forward!(a, deleter, data));
2283 		}
2284 
2285 
2286 		public this(Args...)(_AllocatorType a, DeleterType deleter, ElementReferenceType data){
2287 			import core.lifetime : forward, emplace;
2288 
2289 			smart_ptr_construct();
2290 
2291 			version(D_BetterC){
2292 				if(!vtable.initialized())
2293 					shared_static_this();
2294 			}
2295 			else 
2296 				assert(vtable.initialized());
2297 
2298 			this.control = _ControlType(&vtable);
2299 			assert(vtable.valid, "vtables are not initialized");
2300 
2301 			static if(!hasStatelessAllocator){
2302 				static if(isMoveConstructableElement!_AllocatorType)
2303 					this.allocator = forward!a;
2304 				else
2305 					this.allocator = a;
2306 			}
2307 
2308 			this.deleter = forward!deleter;
2309 			this.data = data;
2310 		}
2311 
2312 
2313 		static if(hasSharedCounter){
2314 			public static void virtual_on_zero_shared(Unqual!_ControlType* control)pure nothrow @nogc @trusted{
2315 				auto self = get_offset_this(control);
2316 				self.destruct();
2317 
2318 				static if(!hasWeakCounter)
2319 					self.deallocate();
2320 			}
2321 		}
2322 
2323 		static if(hasWeakCounter){
2324 			public static void virtual_on_zero_weak(Unqual!_ControlType* control)pure nothrow @nogc @trusted{
2325 				auto self = get_offset_this(control);
2326 				self.deallocate();
2327 			}
2328 		}
2329 
2330 		public static void virtual_manual_destroy(Unqual!_ControlType* control, bool dealocate)pure nothrow @nogc @trusted{
2331 			auto self = get_offset_this(control);
2332 			self.destruct();
2333 			if(dealocate)
2334 				self.deallocate();
2335 
2336 		}
2337 
2338 		private static inout(MakeDeleter)* get_offset_this(inout(Unqual!_ControlType)* control)pure nothrow @system @nogc{
2339 			assert(control !is null);
2340 			return cast(typeof(return))((cast(void*)control) - MakeDeleter.control.offsetof);
2341 		}
2342 
2343 		private void destruct()pure nothrow @system @nogc{
2344 			assumePureNoGcNothrow((ref DeleterType deleter, ElementReferenceType data){
2345 				deleter(data);
2346 			})(this.deleter, this.data);
2347 
2348 			static if(!allocatorGCRange && !deleterGCRange && dataGCRange){
2349 				static assert(supportGC);
2350 
2351 				gcRemoveRange(&this.data);
2352 			}
2353 
2354 			smart_ptr_destruct();
2355 		}
2356 
2357 		private void deallocate()pure nothrow @system @nogc{
2358 			void* self = cast(void*)&this;
2359 			destructImpl!(false, DtorType!void)(this);    //btl.internal.lifetime.destruct!(typeof(this), DestructorType!void)(self);
2360 
2361 			void[] raw = self[0 .. typeof(this).sizeof];
2362 
2363 
2364 			static if(hasStatelessAllocator)
2365 				assumePureNoGcNothrow(function(void[] raw) => statelessAllcoator!_AllocatorType.deallocate(raw))(raw);
2366 			else
2367 				assumePureNoGcNothrow(function(void[] raw, ref typeof(this.allocator) allo) => allo.deallocate(raw))(raw, this.allocator);
2368 
2369 
2370 
2371 			static if(allocatorGCRange){
2372 				static assert(supportGC);
2373 
2374 				gcRemoveRange(&this.allocator);
2375 			}
2376 			else static if(deleterGCRange){
2377 				static assert(supportGC);
2378 				static assert(!allocatorGCRange);
2379 
2380 				gcRemoveRange(&this.deleter);
2381 			}
2382 
2383 			smart_ptr_deallocate(raw[]);
2384 		}
2385 	}
2386 }
2387 
2388 
2389 
2390 
2391 version(BTL_AUTOPTR_COUNT_ALLOCATIONS)
2392 	public __gshared int _conter_allocations = 0;
2393 
2394 version(BTL_AUTOPTR_COUNT_CONSTRUCTIONS)
2395 	public __gshared int _conter_constructs = 0;
2396 
2397 version(BTL_AUTOPTR_COUNT_ALLOCATIONS)
2398 	enum bool BTL_AUTOPTR_COUNT = true;
2399 else version(BTL_AUTOPTR_COUNT_CONSTRUCTIONS)
2400 	enum bool BTL_AUTOPTR_COUNT = true;
2401 else
2402 	enum bool BTL_AUTOPTR_COUNT = false;
2403 
2404 
2405 static if(BTL_AUTOPTR_COUNT){
2406 
2407 	private void shared_static_dtor_impl(){
2408 		version(BTL_AUTOPTR_COUNT_ALLOCATIONS)
2409 		if(_conter_allocations != 0){
2410 			version(D_BetterC){
2411 				assert(0, "_conter_allocations != 0");
2412 			}
2413 			else{
2414 				import std.conv;
2415 				assert(0, "_conter_allocations: " ~ _conter_allocations.to!string);
2416 			}
2417 		}
2418 
2419 		version(BTL_AUTOPTR_COUNT_CONSTRUCTIONS)
2420 		if(_conter_constructs != 0){
2421 			version(D_BetterC){
2422 				assert(0, "_conter_constructs != 0");
2423 			}
2424 			else{
2425 				import std.conv;
2426 				assert(0, "_conter_constructs: " ~ _conter_constructs.to!string);
2427 			}
2428 		}
2429 	}
2430 
2431 	version(D_BetterC){
2432 		pragma(crt_destructor)
2433 		extern(C) void shared_static_this(){
2434 			shared_static_dtor_impl();
2435 		}
2436 	}
2437 	else
2438 		shared static ~this(){
2439 			shared_static_dtor_impl();
2440 
2441 		}
2442 
2443 
2444 
2445 }
2446 
2447 
2448 package void smart_ptr_allocate(scope const void[] data)pure nothrow @safe @nogc{
2449 	version(BTL_AUTOPTR_COUNT_ALLOCATIONS){
2450 		import core.atomic;
2451 
2452 		assumePure(function void()@trusted{
2453 			atomicFetchAdd!(MemoryOrder.raw)(_conter_allocations, 1);
2454 		})();
2455 	}
2456 }
2457 package void smart_ptr_construct()pure nothrow @safe @nogc{
2458 	version(BTL_AUTOPTR_COUNT_CONSTRUCTIONS){
2459 		import core.atomic;
2460 
2461 		assumePure(function void()@trusted{
2462 			atomicFetchAdd!(MemoryOrder.raw)(_conter_constructs, 1);
2463 		})();
2464 	}
2465 }
2466 package void smart_ptr_deallocate(scope const void[] data)pure nothrow @safe @nogc{
2467 	version(BTL_AUTOPTR_COUNT_ALLOCATIONS){
2468 		import core.atomic;
2469 
2470 		assumePure(function void()@trusted{
2471 			atomicFetchSub!(MemoryOrder.raw)(_conter_allocations, 1);
2472 		})();
2473 	}
2474 }
2475 package void smart_ptr_destruct()pure nothrow @safe @nogc{
2476 	version(BTL_AUTOPTR_COUNT_CONSTRUCTIONS){
2477 		import core.atomic;
2478 
2479 		assumePure(function void()@trusted{
2480 			atomicFetchSub!(MemoryOrder.raw)(_conter_constructs, 1);
2481 		})();
2482 	}
2483 }
2484 
2485 
2486 //increment counter and return new value, if counter is shared then atomic increment is used.
2487 private static T rc_increment(bool atomic, T)(ref T counter){
2488 	static if(atomic || is(T == shared)){
2489 		import core.atomic;
2490 
2491 		debug{
2492 			import std.traits : Unqual;
2493 
2494 			auto tmp1 = cast(Unqual!T)counter;
2495 			auto result1 = (tmp1 += 1);
2496 
2497 			auto tmp2 = cast(Unqual!T)counter;
2498 			auto result2 = atomicFetchAdd!(MemoryOrder.raw)(tmp2, 1) + 1;
2499 
2500 			assert(result1 == result2);
2501 		}
2502 
2503 		return atomicFetchAdd!(MemoryOrder.raw)(counter, 1) + 1;
2504 	}
2505 	else{
2506 		auto result = counter += 1;
2507 
2508 		result += 0;
2509 		return result;
2510 	}
2511 }
2512 
2513 unittest{
2514 	import core.atomic;
2515 
2516 	const int counter = 0;
2517 	int tmp1 = counter;
2518 	int result1 = (tmp1 += 1);
2519 	assert(result1 == 1);
2520 
2521 	int tmp2 = counter;
2522 	int result2 = atomicFetchAdd!(MemoryOrder.raw)(tmp2, 1) + 1;
2523 	assert(result2 == 1);
2524 
2525 	assert(result1 == result2);
2526 }
2527 
2528 //decrement counter and return new value, if counter is shared then atomic increment is used.
2529 private static T rc_decrement(bool atomic, T)(ref T counter){
2530 	static if(atomic || is(T == shared)){
2531 		import core.atomic;
2532 
2533 		debug{
2534 			import std.traits : Unqual;
2535 
2536 			auto tmp1 = cast(Unqual!T)counter;
2537 			auto result1 = (tmp1 -= 1);
2538 
2539 			auto tmp2 = cast(Unqual!T)counter;
2540 			auto result2 = atomicFetchSub!(MemoryOrder.acq_rel)(tmp2, 1) - 1;
2541 
2542 			assert(result1 == result2);
2543 
2544 		}
2545 
2546 		//return atomicFetchAdd!(MemoryOrder.acq_rel)(counter, -1);
2547 		return atomicFetchSub!(MemoryOrder.acq_rel)(counter, 1) - 1;
2548 	}
2549 	else{
2550 		return counter -= 1;
2551 	}
2552 }
2553 
2554 unittest{
2555 	import core.atomic;
2556 
2557 	const int counter = 0;
2558 	int tmp1 = counter;
2559 	int result1 = (tmp1 -= 1);
2560 	assert(result1 == -1);
2561 
2562 	int tmp2 = counter;
2563 	int result2 = atomicFetchSub!(MemoryOrder.acq_rel)(tmp2, 1) - 1;
2564 	assert(result2 == -1);
2565 
2566 	assert(result1 == result2);
2567 }
2568 
2569 package template isMoveCtor(T, alias arg){
2570 	enum bool isMoveCtor = is(T == struct)
2571 		&& !isRef!arg
2572 		&& is(immutable T == immutable typeof(arg));
2573 }