/** * D header file for interaction with C++ std::vector. * * Copyright: Copyright (c) 2018 D Language Foundation * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Guillaume Chatelet * Manu Evans * Source: $(DRUNTIMESRC core/stdcpp/vector.d) */ module core.stdcpp.vector; ///////////////////////////////////////////////////////////////////////////////// std::vector declaration.//// Current caveats :// - missing noexcept// - nothrow @trusted @nogc for most functions depend on knowledge// of T's construction/destruction/assignment semantics/////////////////////////////////////////////////////////////////////////////// import core.stdcpp.allocator; enum DefaultConstruct { value } /// Constructor argument for default constructionenum Default = DefaultConstruct(); extern(C++, "std"): alias vector(T) = vector!(T, allocator!T);extern(C++, class) struct vector(T, Alloc){ import core.lifetime : forward, move, core_emplace = emplace; static assert(!is(T == bool), "vector!bool not supported!");extern(D): /// alias size_type = size_t; /// alias difference_type = ptrdiff_t; /// alias value_type = T; /// alias allocator_type = Alloc; /// alias pointer = T*; /// alias const_pointer = const(T)*; /// MSVC allocates on default initialisation in debug, which can't be modelled by D `struct` @disable this(); /// alias length = size; /// alias opDollar = length; /// size_t[2] opSlice(size_t dim : 0)(size_t start, size_t end) const pure nothrow @safe @nogc { return [start, end]; } /// ref inout(T) opIndex(size_t index) inout pure nothrow @safe @nogc { return as_array[index]; } /// inout(T)[] opIndex(size_t[2] slice) inout pure nothrow @safe @nogc { return as_array[slice[0] .. slice[1]]; } /// inout(T)[] opIndex() inout pure nothrow @safe @nogc { return as_array(); } /// ref vector opAssign(U)(auto ref vector!(U, Alloc) s) { opAssign(s.as_array); return this; } /// ref vector opAssign(T[] array) { clear(); reserve(array.length); insert(0, array); return this; } /// void opIndexAssign()(auto ref T val, size_t index) { as_array[index] = val; } /// void opIndexAssign()(auto ref T val, size_t[2] slice) { as_array[slice[0] .. slice[1]] = val; } /// void opIndexAssign(T[] val, size_t[2] slice) { as_array[slice[0] .. slice[1]] = val[]; } /// void opIndexAssign()(auto ref T val) { as_array[] = val; } /// void opIndexAssign(T[] val) { as_array[] = val[]; } /// void opIndexOpAssign(string op)(auto ref T val, size_t index) { mixin("as_array[index] " ~ op ~ "= val;"); } /// void opIndexOpAssign(string op)(auto ref T val, size_t[2] slice) { mixin("as_array[slice[0] .. slice[1]] " ~ op ~ "= val;"); } /// void opIndexOpAssign(string op)(T[] val, size_t[2] slice) { mixin("as_array[slice[0] .. slice[1]] " ~ op ~ "= val[];"); } /// void opIndexOpAssign(string op)(auto ref T val) { mixin("as_array[] " ~ op ~ "= val;"); } /// void opIndexOpAssign(string op)(T[] val) { mixin("as_array[] " ~ op ~ "= val[];"); } /// ref inout(T) front() inout pure nothrow @safe @nogc { return as_array[0]; } /// ref inout(T) back() inout pure nothrow @safe @nogc { return as_array[$-1]; } /// ref vector opOpAssign(string op : "~")(auto ref T item) { push_back(forward!item); return this; } /// ref vector opOpAssign(string op : "~")(T[] array) { insert(length, array); return this; } /// void append(T[] array) { insert(length, array); } /// Performs elementwise equality check. bool opEquals(this This, That)(auto ref That rhs) if (is(immutable That == immutable vector)) { return as_array == rhs.as_array; } /// Performs lexicographical comparison. static if (is(typeof((ref T a, ref T b) => a < b))) int opCmp(this This, That)(auto ref That rhs) if (is(immutable That == immutable vector)) { return __cmp(as_array, rhs.as_array); } /// Hash to allow `vector`s to be used as keys for built-in associative arrays. /// **The result will generally not be the same as C++ `std::hash<std::vector<T>>`.** size_t toHash() const { return .hashOf(as_array); } // Modifiers /// void push_back(U)(auto ref U element) { emplace_back(forward!element); } version (CppRuntime_Microsoft) { //---------------------------------------------------------------------------------- // Microsoft runtime //---------------------------------------------------------------------------------- /// this(DefaultConstruct) @nogc { _Alloc_proxy(); } /// this()(size_t count) { _Alloc_proxy(); _Buy(count); scope(failure) _Tidy(); _Get_data()._Mylast = _Udefault(_Get_data()._Myfirst, count); } /// this()(size_t count, auto ref T val) { _Alloc_proxy(); _Buy(count); scope(failure) _Tidy(); _Get_data()._Mylast = _Ufill(_Get_data()._Myfirst, count, val); } /// this()(T[] array) { _Alloc_proxy(); _Buy(array.length); scope(failure) _Tidy(); _Get_data()._Mylast = _Utransfer!false(array.ptr, array.ptr + array.length, _Get_data()._Myfirst); } /// this(this) { _Alloc_proxy(); pointer _First = _Get_data()._Myfirst; pointer _Last = _Get_data()._Mylast; _Buy(_Last - _First); scope(failure) _Tidy(); _Get_data()._Mylast = _Utransfer!false(_First, _Last, _Get_data()._Myfirst); } /// ~this() { _Tidy(); } /// ref inout(Alloc) get_allocator() inout pure nothrow @safe @nogc { return _Getal(); } /// size_type max_size() const pure nothrow @safe @nogc { return ((size_t.max / T.sizeof) - 1) / 2; } // HACK: clone the windows version precisely? /// size_type size() const pure nothrow @safe @nogc { return _Get_data()._Mylast - _Get_data()._Myfirst; } /// size_type capacity() const pure nothrow @safe @nogc { return _Get_data()._Myend - _Get_data()._Myfirst; } /// bool empty() const pure nothrow @safe @nogc { return _Get_data()._Myfirst == _Get_data()._Mylast; } /// inout(T)* data() inout pure nothrow @safe @nogc { return _Get_data()._Myfirst; } /// inout(T)[] as_array() inout pure nothrow @trusted @nogc { return _Get_data()._Myfirst[0 .. size()]; } /// ref inout(T) at(size_type i) inout pure nothrow @trusted @nogc { return _Get_data()._Myfirst[0 .. size()][i]; } /// ref T emplace_back(Args...)(auto ref Args args) { if (_Has_unused_capacity()) return _Emplace_back_with_unused_capacity(forward!args); return *_Emplace_reallocate(_Get_data()._Mylast, forward!args); } /// void reserve(const size_type newCapacity) { if (newCapacity > capacity()) {// if (newCapacity > max_size())// _Xlength(); _Reallocate_exactly(newCapacity); } } /// void shrink_to_fit() { if (_Has_unused_capacity()) { if (empty()) _Tidy(); else _Reallocate_exactly(size()); } } /// void pop_back() { static if (_ITERATOR_DEBUG_LEVEL == 2) { assert(!empty(), "vector empty before pop"); _Orphan_range(_Get_data()._Mylast - 1, _Get_data()._Mylast); } destroy!false(_Get_data()._Mylast[-1]); --_Get_data()._Mylast; } /// void clear() { _Base._Orphan_all(); _Destroy(_Get_data()._Myfirst, _Get_data()._Mylast); _Get_data()._Mylast = _Get_data()._Myfirst; } /// void resize()(const size_type newsize) { static assert(is(typeof({static T i;})), T.stringof ~ ".this() is annotated with @disable."); _Resize(newsize, (pointer _Dest, size_type _Count) => _Udefault(_Dest, _Count)); } /// void resize()(const size_type newsize, auto ref T val) { _Resize(newsize, (pointer _Dest, size_type _Count) => _Ufill(_Dest, _Count, forward!val)); } void emplace(Args...)(size_t offset, auto ref Args args) { pointer _Whereptr = _Get_data()._Myfirst + offset; pointer _Oldlast = _Get_data()._Mylast; if (_Has_unused_capacity()) { if (_Whereptr == _Oldlast) _Emplace_back_with_unused_capacity(forward!args); else { T _Obj = T(forward!args); static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Whereptr, _Oldlast); move(_Oldlast[-1], *_Oldlast); ++_Get_data()._Mylast; _Move_backward_unchecked(_Whereptr, _Oldlast - 1, _Oldlast); move(_Obj, *_Whereptr); } return; } _Emplace_reallocate(_Whereptr, forward!args); } /// void insert(size_t offset, T[] array) { pointer _Where = _Get_data()._Myfirst + offset; pointer _First = array.ptr; pointer _Last = _First + array.length; const size_type _Count = array.length; const size_type _Whereoff = offset; const bool _One_at_back = _Count == 1 && _Get_data()._Myfirst + _Whereoff == _Get_data()._Mylast; if (_Count == 0) { // nothing to do, avoid invalidating iterators } else if (_Count > _Unused_capacity()) { // reallocate const size_type _Oldsize = size(); // if (_Count > max_size() - _Oldsize)// _Xlength(); const size_type _Newsize = _Oldsize + _Count; const size_type _Newcapacity = _Calculate_growth(_Newsize); pointer _Newvec = _Getal().allocate(_Newcapacity); pointer _Constructed_last = _Newvec + _Whereoff + _Count; pointer _Constructed_first = _Constructed_last; try { _Utransfer!false(_First, _Last, _Newvec + _Whereoff); _Constructed_first = _Newvec + _Whereoff; if (_One_at_back) { _Utransfer!(true, true)(_Get_data()._Myfirst, _Get_data()._Mylast, _Newvec); } else { _Utransfer!true(_Get_data()._Myfirst, _Where, _Newvec); _Constructed_first = _Newvec; _Utransfer!true(_Where, _Get_data()._Mylast, _Newvec + _Whereoff + _Count); } } catch (Throwable e) { _Destroy(_Constructed_first, _Constructed_last); _Getal().deallocate(_Newvec, _Newcapacity); throw e; } _Change_array(_Newvec, _Newsize, _Newcapacity); } else { // Attempt to provide the strong guarantee for EmplaceConstructible failure. // If we encounter copy/move construction/assignment failure, provide the basic guarantee. // (For one-at-back, this provides the strong guarantee.) pointer _Oldlast = _Get_data()._Mylast; const size_type _Affected_elements = cast(size_type)(_Oldlast - _Where); if (_Count < _Affected_elements) { // some affected elements must be assigned _Get_data()._Mylast = _Utransfer!true(_Oldlast - _Count, _Oldlast, _Oldlast); _Move_backward_unchecked(_Where, _Oldlast - _Count, _Oldlast); _Destroy(_Where, _Where + _Count); try { _Utransfer!false(_First, _Last, _Where); } catch (Throwable e) { // glue the broken pieces back together try { _Utransfer!true(_Where + _Count, _Where + 2 * _Count, _Where); } catch (Throwable e) { // vaporize the detached piece static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Where, _Oldlast); _Destroy(_Where + _Count, _Get_data()._Mylast); _Get_data()._Mylast = _Where; throw e; } _Move_unchecked(_Where + 2 * _Count, _Get_data()._Mylast, _Where + _Count); _Destroy(_Oldlast, _Get_data()._Mylast); _Get_data()._Mylast = _Oldlast; throw e; } } else { // affected elements don't overlap before/after pointer _Relocated = _Where + _Count; _Get_data()._Mylast = _Utransfer!true(_Where, _Oldlast, _Relocated); _Destroy(_Where, _Oldlast); try { _Utransfer!false(_First, _Last, _Where); } catch (Throwable e) { // glue the broken pieces back together try { _Utransfer!true(_Relocated, _Get_data()._Mylast, _Where); } catch (Throwable e) { // vaporize the detached piece static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Where, _Oldlast); _Destroy(_Relocated, _Get_data()._Mylast); _Get_data()._Mylast = _Where; throw e; } _Destroy(_Relocated, _Get_data()._Mylast); _Get_data()._Mylast = _Oldlast; throw e; } } static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Where, _Oldlast); } } private: import core.stdcpp.xutility : MSVCLinkDirectives; // Make sure the object files wont link against mismatching objects mixin MSVCLinkDirectives!true; pragma(inline, true) { ref inout(_Base.Alloc) _Getal() inout pure nothrow @safe @nogc { return _Base._Mypair._Myval1; } ref inout(_Base.ValTy) _Get_data() inout pure nothrow @safe @nogc { return _Base._Mypair._Myval2; } } void _Alloc_proxy() @nogc { static if (_ITERATOR_DEBUG_LEVEL > 0) _Base._Alloc_proxy(); } void _AssignAllocator(ref const(allocator_type) al) nothrow @nogc { static if (_Base._Mypair._HasFirst) _Getal() = al; } bool _Buy(size_type _Newcapacity) @trusted @nogc { _Get_data()._Myfirst = null; _Get_data()._Mylast = null; _Get_data()._Myend = null; if (_Newcapacity == 0) return false; // TODO: how to handle this in D? kinda like a range exception...// if (_Newcapacity > max_size())// _Xlength(); _Get_data()._Myfirst = _Getal().allocate(_Newcapacity); _Get_data()._Mylast = _Get_data()._Myfirst; _Get_data()._Myend = _Get_data()._Myfirst + _Newcapacity; return true; } static void _Destroy(pointer _First, pointer _Last) { for (; _First != _Last; ++_First) destroy!false(*_First); } void _Tidy() { _Base._Orphan_all(); if (_Get_data()._Myfirst) { _Destroy(_Get_data()._Myfirst, _Get_data()._Mylast); _Getal().deallocate(_Get_data()._Myfirst, capacity()); _Get_data()._Myfirst = null; _Get_data()._Mylast = null; _Get_data()._Myend = null; } } size_type _Unused_capacity() const pure nothrow @safe @nogc { return _Get_data()._Myend - _Get_data()._Mylast; } bool _Has_unused_capacity() const pure nothrow @safe @nogc { return _Get_data()._Myend != _Get_data()._Mylast; } ref T _Emplace_back_with_unused_capacity(Args...)(auto ref Args args) { core_emplace(_Get_data()._Mylast, forward!args); static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Get_data()._Mylast, _Get_data()._Mylast); return *_Get_data()._Mylast++;Lines 1–500 of 850. Load more
/** * D header file for interaction with C++ std::vector. * * Copyright: Copyright (c) 2018 D Language Foundation * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Guillaume Chatelet * Manu Evans * Source: $(DRUNTIMESRC core/stdcpp/vector.d) */ module core.stdcpp.vector; /////////////////////////////////////////////////////////////////////////////// // std::vector declaration. // // Current caveats : // - missing noexcept // - nothrow @trusted @nogc for most functions depend on knowledge // of T's construction/destruction/assignment semantics /////////////////////////////////////////////////////////////////////////////// import core.stdcpp.allocator; enum DefaultConstruct { value } /// Constructor argument for default construction enum Default = DefaultConstruct(); extern(C++, "std"): alias vector(T) = vector!(T, allocator!T); extern(C++, class) struct vector(T, Alloc) { import core.lifetime : forward, move, core_emplace = emplace; static assert(!is(T == bool), "vector!bool not supported!"); extern(D): /// alias size_type = size_t; /// alias difference_type = ptrdiff_t; /// alias value_type = T; /// alias allocator_type = Alloc; /// alias pointer = T*; /// alias const_pointer = const(T)*; /// MSVC allocates on default initialisation in debug, which can't be modelled by D `struct` @disable this(); /// alias length = size; /// alias opDollar = length; /// size_t[2] opSlice(size_t dim : 0)(size_t start, size_t end) const pure nothrow @safe @nogc { return [start, end]; } /// ref inout(T) opIndex(size_t index) inout pure nothrow @safe @nogc { return as_array[index]; } /// inout(T)[] opIndex(size_t[2] slice) inout pure nothrow @safe @nogc { return as_array[slice[0] .. slice[1]]; } /// inout(T)[] opIndex() inout pure nothrow @safe @nogc { return as_array(); } /// ref vector opAssign(U)(auto ref vector!(U, Alloc) s) { opAssign(s.as_array); return this; } /// ref vector opAssign(T[] array) { clear(); reserve(array.length); insert(0, array); return this; } /// void opIndexAssign()(auto ref T val, size_t index) { as_array[index] = val; } /// void opIndexAssign()(auto ref T val, size_t[2] slice) { as_array[slice[0] .. slice[1]] = val; } /// void opIndexAssign(T[] val, size_t[2] slice) { as_array[slice[0] .. slice[1]] = val[]; } /// void opIndexAssign()(auto ref T val) { as_array[] = val; } /// void opIndexAssign(T[] val) { as_array[] = val[]; } /// void opIndexOpAssign(string op)(auto ref T val, size_t index) { mixin("as_array[index] " ~ op ~ "= val;"); } /// void opIndexOpAssign(string op)(auto ref T val, size_t[2] slice) { mixin("as_array[slice[0] .. slice[1]] " ~ op ~ "= val;"); } /// void opIndexOpAssign(string op)(T[] val, size_t[2] slice) { mixin("as_array[slice[0] .. slice[1]] " ~ op ~ "= val[];"); } /// void opIndexOpAssign(string op)(auto ref T val) { mixin("as_array[] " ~ op ~ "= val;"); } /// void opIndexOpAssign(string op)(T[] val) { mixin("as_array[] " ~ op ~ "= val[];"); } /// ref inout(T) front() inout pure nothrow @safe @nogc { return as_array[0]; } /// ref inout(T) back() inout pure nothrow @safe @nogc { return as_array[$-1]; } /// ref vector opOpAssign(string op : "~")(auto ref T item) { push_back(forward!item); return this; } /// ref vector opOpAssign(string op : "~")(T[] array) { insert(length, array); return this; } /// void append(T[] array) { insert(length, array); } /// Performs elementwise equality check. bool opEquals(this This, That)(auto ref That rhs) if (is(immutable That == immutable vector)) { return as_array == rhs.as_array; } /// Performs lexicographical comparison. static if (is(typeof((ref T a, ref T b) => a < b))) int opCmp(this This, That)(auto ref That rhs) if (is(immutable That == immutable vector)) { return __cmp(as_array, rhs.as_array); } /// Hash to allow `vector`s to be used as keys for built-in associative arrays. /// **The result will generally not be the same as C++ `std::hash<std::vector<T>>`.** size_t toHash() const { return .hashOf(as_array); } // Modifiers /// void push_back(U)(auto ref U element) { emplace_back(forward!element); } version (CppRuntime_Microsoft) { //---------------------------------------------------------------------------------- // Microsoft runtime //---------------------------------------------------------------------------------- /// this(DefaultConstruct) @nogc { _Alloc_proxy(); } /// this()(size_t count) { _Alloc_proxy(); _Buy(count); scope(failure) _Tidy(); _Get_data()._Mylast = _Udefault(_Get_data()._Myfirst, count); } /// this()(size_t count, auto ref T val) { _Alloc_proxy(); _Buy(count); scope(failure) _Tidy(); _Get_data()._Mylast = _Ufill(_Get_data()._Myfirst, count, val); } /// this()(T[] array) { _Alloc_proxy(); _Buy(array.length); scope(failure) _Tidy(); _Get_data()._Mylast = _Utransfer!false(array.ptr, array.ptr + array.length, _Get_data()._Myfirst); } /// this(this) { _Alloc_proxy(); pointer _First = _Get_data()._Myfirst; pointer _Last = _Get_data()._Mylast; _Buy(_Last - _First); scope(failure) _Tidy(); _Get_data()._Mylast = _Utransfer!false(_First, _Last, _Get_data()._Myfirst); } /// ~this() { _Tidy(); } /// ref inout(Alloc) get_allocator() inout pure nothrow @safe @nogc { return _Getal(); } /// size_type max_size() const pure nothrow @safe @nogc { return ((size_t.max / T.sizeof) - 1) / 2; } // HACK: clone the windows version precisely? /// size_type size() const pure nothrow @safe @nogc { return _Get_data()._Mylast - _Get_data()._Myfirst; } /// size_type capacity() const pure nothrow @safe @nogc { return _Get_data()._Myend - _Get_data()._Myfirst; } /// bool empty() const pure nothrow @safe @nogc { return _Get_data()._Myfirst == _Get_data()._Mylast; } /// inout(T)* data() inout pure nothrow @safe @nogc { return _Get_data()._Myfirst; } /// inout(T)[] as_array() inout pure nothrow @trusted @nogc { return _Get_data()._Myfirst[0 .. size()]; } /// ref inout(T) at(size_type i) inout pure nothrow @trusted @nogc { return _Get_data()._Myfirst[0 .. size()][i]; } /// ref T emplace_back(Args...)(auto ref Args args) { if (_Has_unused_capacity()) return _Emplace_back_with_unused_capacity(forward!args); return *_Emplace_reallocate(_Get_data()._Mylast, forward!args); } /// void reserve(const size_type newCapacity) { if (newCapacity > capacity()) { // if (newCapacity > max_size()) // _Xlength(); _Reallocate_exactly(newCapacity); } } /// void shrink_to_fit() { if (_Has_unused_capacity()) { if (empty()) _Tidy(); else _Reallocate_exactly(size()); } } /// void pop_back() { static if (_ITERATOR_DEBUG_LEVEL == 2) { assert(!empty(), "vector empty before pop"); _Orphan_range(_Get_data()._Mylast - 1, _Get_data()._Mylast); } destroy!false(_Get_data()._Mylast[-1]); --_Get_data()._Mylast; } /// void clear() { _Base._Orphan_all(); _Destroy(_Get_data()._Myfirst, _Get_data()._Mylast); _Get_data()._Mylast = _Get_data()._Myfirst; } /// void resize()(const size_type newsize) { static assert(is(typeof({static T i;})), T.stringof ~ ".this() is annotated with @disable."); _Resize(newsize, (pointer _Dest, size_type _Count) => _Udefault(_Dest, _Count)); } /// void resize()(const size_type newsize, auto ref T val) { _Resize(newsize, (pointer _Dest, size_type _Count) => _Ufill(_Dest, _Count, forward!val)); } void emplace(Args...)(size_t offset, auto ref Args args) { pointer _Whereptr = _Get_data()._Myfirst + offset; pointer _Oldlast = _Get_data()._Mylast; if (_Has_unused_capacity()) { if (_Whereptr == _Oldlast) _Emplace_back_with_unused_capacity(forward!args); else { T _Obj = T(forward!args); static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Whereptr, _Oldlast); move(_Oldlast[-1], *_Oldlast); ++_Get_data()._Mylast; _Move_backward_unchecked(_Whereptr, _Oldlast - 1, _Oldlast); move(_Obj, *_Whereptr); } return; } _Emplace_reallocate(_Whereptr, forward!args); } /// void insert(size_t offset, T[] array) { pointer _Where = _Get_data()._Myfirst + offset; pointer _First = array.ptr; pointer _Last = _First + array.length; const size_type _Count = array.length; const size_type _Whereoff = offset; const bool _One_at_back = _Count == 1 && _Get_data()._Myfirst + _Whereoff == _Get_data()._Mylast; if (_Count == 0) { // nothing to do, avoid invalidating iterators } else if (_Count > _Unused_capacity()) { // reallocate const size_type _Oldsize = size(); // if (_Count > max_size() - _Oldsize) // _Xlength(); const size_type _Newsize = _Oldsize + _Count; const size_type _Newcapacity = _Calculate_growth(_Newsize); pointer _Newvec = _Getal().allocate(_Newcapacity); pointer _Constructed_last = _Newvec + _Whereoff + _Count; pointer _Constructed_first = _Constructed_last; try { _Utransfer!false(_First, _Last, _Newvec + _Whereoff); _Constructed_first = _Newvec + _Whereoff; if (_One_at_back) { _Utransfer!(true, true)(_Get_data()._Myfirst, _Get_data()._Mylast, _Newvec); } else { _Utransfer!true(_Get_data()._Myfirst, _Where, _Newvec); _Constructed_first = _Newvec; _Utransfer!true(_Where, _Get_data()._Mylast, _Newvec + _Whereoff + _Count); } } catch (Throwable e) { _Destroy(_Constructed_first, _Constructed_last); _Getal().deallocate(_Newvec, _Newcapacity); throw e; } _Change_array(_Newvec, _Newsize, _Newcapacity); } else { // Attempt to provide the strong guarantee for EmplaceConstructible failure. // If we encounter copy/move construction/assignment failure, provide the basic guarantee. // (For one-at-back, this provides the strong guarantee.) pointer _Oldlast = _Get_data()._Mylast; const size_type _Affected_elements = cast(size_type)(_Oldlast - _Where); if (_Count < _Affected_elements) { // some affected elements must be assigned _Get_data()._Mylast = _Utransfer!true(_Oldlast - _Count, _Oldlast, _Oldlast); _Move_backward_unchecked(_Where, _Oldlast - _Count, _Oldlast); _Destroy(_Where, _Where + _Count); try { _Utransfer!false(_First, _Last, _Where); } catch (Throwable e) { // glue the broken pieces back together try { _Utransfer!true(_Where + _Count, _Where + 2 * _Count, _Where); } catch (Throwable e) { // vaporize the detached piece static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Where, _Oldlast); _Destroy(_Where + _Count, _Get_data()._Mylast); _Get_data()._Mylast = _Where; throw e; } _Move_unchecked(_Where + 2 * _Count, _Get_data()._Mylast, _Where + _Count); _Destroy(_Oldlast, _Get_data()._Mylast); _Get_data()._Mylast = _Oldlast; throw e; } } else { // affected elements don't overlap before/after pointer _Relocated = _Where + _Count; _Get_data()._Mylast = _Utransfer!true(_Where, _Oldlast, _Relocated); _Destroy(_Where, _Oldlast); try { _Utransfer!false(_First, _Last, _Where); } catch (Throwable e) { // glue the broken pieces back together try { _Utransfer!true(_Relocated, _Get_data()._Mylast, _Where); } catch (Throwable e) { // vaporize the detached piece static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Where, _Oldlast); _Destroy(_Relocated, _Get_data()._Mylast); _Get_data()._Mylast = _Where; throw e; } _Destroy(_Relocated, _Get_data()._Mylast); _Get_data()._Mylast = _Oldlast; throw e; } } static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Where, _Oldlast); } } private: import core.stdcpp.xutility : MSVCLinkDirectives; // Make sure the object files wont link against mismatching objects mixin MSVCLinkDirectives!true; pragma(inline, true) { ref inout(_Base.Alloc) _Getal() inout pure nothrow @safe @nogc { return _Base._Mypair._Myval1; } ref inout(_Base.ValTy) _Get_data() inout pure nothrow @safe @nogc { return _Base._Mypair._Myval2; } } void _Alloc_proxy() @nogc { static if (_ITERATOR_DEBUG_LEVEL > 0) _Base._Alloc_proxy(); } void _AssignAllocator(ref const(allocator_type) al) nothrow @nogc { static if (_Base._Mypair._HasFirst) _Getal() = al; } bool _Buy(size_type _Newcapacity) @trusted @nogc { _Get_data()._Myfirst = null; _Get_data()._Mylast = null; _Get_data()._Myend = null; if (_Newcapacity == 0) return false; // TODO: how to handle this in D? kinda like a range exception... // if (_Newcapacity > max_size()) // _Xlength(); _Get_data()._Myfirst = _Getal().allocate(_Newcapacity); _Get_data()._Mylast = _Get_data()._Myfirst; _Get_data()._Myend = _Get_data()._Myfirst + _Newcapacity; return true; } static void _Destroy(pointer _First, pointer _Last) { for (; _First != _Last; ++_First) destroy!false(*_First); } void _Tidy() { _Base._Orphan_all(); if (_Get_data()._Myfirst) { _Destroy(_Get_data()._Myfirst, _Get_data()._Mylast); _Getal().deallocate(_Get_data()._Myfirst, capacity()); _Get_data()._Myfirst = null; _Get_data()._Mylast = null; _Get_data()._Myend = null; } } size_type _Unused_capacity() const pure nothrow @safe @nogc { return _Get_data()._Myend - _Get_data()._Mylast; } bool _Has_unused_capacity() const pure nothrow @safe @nogc { return _Get_data()._Myend != _Get_data()._Mylast; } ref T _Emplace_back_with_unused_capacity(Args...)(auto ref Args args) { core_emplace(_Get_data()._Mylast, forward!args); static if (_ITERATOR_DEBUG_LEVEL == 2) _Orphan_range(_Get_data()._Mylast, _Get_data()._Mylast); return *_Get_data()._Mylast++;