#ifndef YASLI_MEMORY_H_ #define YASLI_MEMORY_H_ #include "yasli_traits.h" #include "yasli_protocols.h"//! #include #include #include //NOT A SAFE WAY TO INCLUDE IT namespace yasli { // 20.4.1, the default allocator: template class allocator; template <> class allocator; // 20.4.1.2, allocator globals template bool operator==(const allocator&, const allocator&) throw() { return true; } template bool operator!=(const allocator&, const allocator&) throw() { return false; } // 20.4.2, raw storage iterator: // @@@ not defined, use the std one @@@ //template class raw_storage_iterator; // 20.4.3, temporary buffers: // @@@ not defined, use the std one @@@ //template //pair get_temporary_buffer(ptrdiff_t n); // @@@ not defined, use the std one @@@ // template // void return_temporary_buffer(T* p); // 20.4.4, specialized algorithms: template ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result); template void uninitialized_fill_n(ForwardIterator first, Size n, const T& x); // 20.4.5, pointers: // @@@ not defined, use the std one @@@ // template class auto_ptr; } namespace yasli { template class allocator; // specialize for void: template <> class allocator { public: typedef void* pointer; typedef const void* const_pointer; // reference-to-void members are impossible. typedef void value_type; template struct rebind { typedef allocator other; }; }; template class allocator { public: typedef size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef allocator other; }; allocator() throw() {} allocator(const allocator&) throw() {} template allocator(const allocator&) throw() {} ~allocator() throw() {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) { return &x; } pointer allocate(size_type n, allocator::const_pointer = 0) { return static_cast(::operator new(n * sizeof(T))); } void deallocate(pointer p, size_type) { ::operator delete(p); } size_type max_size() const throw() { return size_type(-1); } void construct(pointer p, const T& val) { new((void *) p) T(val); } void destroy(pointer p) { ((T*) p)->~T(); } }; } // namespace yasli namespace yasli_nstd { template class mallocator { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef mallocator other; }; mallocator() throw() {} mallocator(const mallocator&) throw() {} template mallocator(const mallocator&) throw() {} ~mallocator() throw() {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) { return &x; } pointer allocate(size_type n, yasli::allocator::const_pointer = 0) { return static_cast(malloc(n * sizeof(T))); } void deallocate(pointer p, size_type) { free(p); } size_type max_size() const throw() { return size_type(-1); } void construct(pointer p, const T& val) { new((void *) p) T(val); } void destroy(pointer p) { ((T*) p)->~T(); } }; //--------------destroy-------- namespace _impl { struct non_destroyer { template static void destroy(A& a, T* p, typename A::size_type n) {} template static void destroy_range(ForwardIterator b, ForwardIterator e) {} }; struct destroyer { template static void destroy(A& a, T* p, typename A::size_type n) { const typename A::pointer p1 = p + n; for (; p < p1; ++p) a.destroy(p); } template static void destroy_range(ForwardIterator b, ForwardIterator e) { typedef typename std::iterator_traits::value_type value_type; for (; b != e; ++b) (*b).~value_type(); } }; } template void destroy(A& a, T* p, typename A::size_type n) { yasli_nstd::type_selector::value != 0, _impl::destroyer, _impl::non_destroyer >::result::destroy(a, p, n); } template void destroy_range(ForwardIterator b, ForwardIterator e) { yasli_nstd::type_selector< yasli_nstd::is_class ::value_type>::value != 0, _impl::destroyer, _impl::non_destroyer >::result::destroy_range(b, e); } //--------------- template It2 uninitialized_move(It1 b, It1 e, It2 d) { return mojo::uninitialized_move(b, e, d); } template struct generic_allocator_traits { static typename A::pointer reallocate( A& a, typename A::pointer b, typename A::pointer e, typename A::size_type newSize) { typename A::pointer p1 = a.allocate(newSize, b); const typename A::size_type oldSize = e - b; if (oldSize <= newSize) // expand { yasli_protocols::move_traits::destructive_move( b, b + oldSize, p1); } else // shrink { yasli_protocols::move_traits::destructive_move( b, b + newSize, p1); yasli_nstd::destroy(a, b + newSize, oldSize - newSize); } a.deallocate(b, oldSize); return p1; } static bool reallocate_inplace( A& a, typename A::pointer b, typename A::size_type newSize) { return false; } private: generic_allocator_traits(); }; template struct allocator_traits : public generic_allocator_traits { }; template struct allocator_traits< yasli::allocator > : public generic_allocator_traits< yasli::allocator > { #if YASLI_NEW_IS_MALLOC != 0 static bool reallocate_inplace( A& a, typename A::pointer b, typename A::size_type newSize) { allocator_traits< yasli_nstd::mallocator > ::reallocate_inplace(a, b, newSize); } static typename yasli::allocator::pointer reallocate( yasli::allocator& a, typename yasli::allocator::pointer b, typename yasli::allocator::pointer e, typename yasli::allocator::size_type newSize) { allocator_traits< yasli_nstd::mallocator > ::reallocate(a, b, e, newSize); } #endif//yasli_new_is_malloc }; template struct allocator_traits< yasli_nstd::mallocator > : public generic_allocator_traits< yasli_nstd::mallocator > { #if YASLI_HAS_EXPAND && YASLI_HAS_EFFICIENT_MSIZE static bool reallocate_inplace( yasli_nstd::mallocator& a, typename yasli_nstd::mallocator::pointer b, typename yasli_nstd::mallocator::size_type newSize) { if (b == 0) return malloc(newSize); if (newSize == 0) {free(b); return false;} return b == yasli_platform::expand(b, newSize) && yasli_platform::msize(b) >= newSize; } #endif static typename yasli_nstd::mallocator::pointer reallocate( yasli_nstd::mallocator& a, typename yasli_nstd::mallocator::pointer b, typename yasli_nstd::mallocator::pointer e, typename yasli_nstd::mallocator::size_type newSize) { if (yasli_nstd::is_memmoveable::value) { return static_cast(realloc(b, newSize)); } if(reallocate_inplace(a, b, newSize)) return b; return generic_allocator_traits< yasli_nstd::mallocator >:: reallocate(a, b, e, newSize); } }; } namespace yasli { //Here is where type_selector is really much more ugly than //enable_if. //----------------UNINIT COPY-------- namespace _impl { //safe template struct uninitialized_safe_copier { static FwdItr execute(InputItr first, InputItr last, FwdItr result) { // struct ScopeGuard { FwdItr begin; FwdItr* current; ~ScopeGuard() { if (!current) return; FwdItr end = *current; typedef typename std::iterator_traits::value_type T; for (; begin != end; ++begin) (&*begin)->~T(); } } guard = { result, &result }; for (; first != last; ++first, ++result) new(&*result) typename std::iterator_traits::value_type(*first); // commit return result; } }; template struct uninitialized_memcopier { static T* execute(const T* first, const T* last, T* result) { yasli_nstd::is_memcopyable::value; const size_t s = last - first; memmove(result, first, s * sizeof(T)); return result + s; } }; }// _impl // @@@ TODO: specialize for yasli_nstd::fill_iterator template FwdItr uninitialized_copy(InputItr first, InputItr last, FwdItr result) { std::cout<<"neither\n"; return _impl::uninitialized_safe_copier::execute(first, last, result); } template T* uninitialized_copy(const T* first, const T* last, T* result) { std::cout<<"const\n"; return yasli_nstd::type_selector::value != 0, _impl::uninitialized_memcopier, _impl::uninitialized_safe_copier >::result::execute(first, last, result); } template T* uninitialized_copy(T* first, T* last, T* result) { std::cout<<"non-const\n"; return uninitialized_copy(static_cast(first), static_cast(last), result); } //-------------------------UNINIT FILL------ template void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x) { struct ScopeGuard { ForwardIterator first; ForwardIterator* pCrt; ~ScopeGuard() { if (pCrt) yasli_nstd::destroy_range(first, *pCrt); } } guard = { first, &first }; for (; first != last; ++first) new(&*first) T(x); // Commit guard.pCrt = 0; } template void uninitialized_fill(T* first, T* last, const U& x) { struct ScopeGuard { T* first; T** pCrt; ~ScopeGuard() { if (pCrt) yasli_nstd::destroy_range(first, *pCrt); } } guard = { first, &first }; assert(first <= last); switch ((last - first) & 7u) { case 0: while (first != last) { new(first) T(x); ++first; case 7: new(first) T(x); ++first; case 6: new(first) T(x); ++first; case 5: new(first) T(x); ++first; case 4: new(first) T(x); ++first; case 3: new(first) T(x); ++first; case 2: new(first) T(x); ++first; case 1: new(first) T(x); ++first; assert(first <= last); } } // Commit guard.pCrt = 0; } }// yasli #endif // YASLI_MEMORY_H_