/* mbed Microcontroller Library * Copyright (c) 2019 ARM Limited * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MSTD_MEMORY_ #define MSTD_MEMORY_ /* * * - includes toolchain's * - For ARM C 5, C++11/14 features: * - std::align * - std::addressof * - std::uninitialized_copy_n * - std::unique_ptr, std::make_unique, std::default_delete * - For all toolchains, C++17 backports: * - mstd::uninitialized_default_construct, mstd::uninitialized_value_construct * - mstd::uninitialized_move, mstd::uninitialized_move_n * - mstd::destroy_at, mstd::destroy, mstd::destroy_n */ #include #include #include // std::pair #include // std::iterator_traits #ifdef __CC_ARM #include // size_t, ptrdiff_t #include <_move.h> // exchange namespace std { // [ptr.align] inline void *align(size_t alignment, size_t size, void *&ptr, size_t &space) noexcept { /* Behavior is undefined if alignment is not a power of 2 */ uintptr_t addr = reinterpret_cast(ptr); uintptr_t new_addr = (addr + (alignment - 1)) & ~(alignment - 1); uintptr_t pad = new_addr - addr; if (pad + size <= space) { space -= pad; ptr = reinterpret_cast(new_addr); return ptr; } else { return nullptr; } } // [specialized.addressof] template T *addressof(T &arg) noexcept { return reinterpret_cast(const_cast(&reinterpret_cast(arg))); } // [uninitialized.copy] - ARMCC has pre-C++11 uninitialized_copy template ForwardIterator uninitialized_copy_n(InputIterator first, Size n, ForwardIterator result) { for ( ; n > 0; ++result, (void) ++first, --n) { ::new (static_cast(addressof(*result))) typename std::iterator_traits::value_type(*first); } return result; } // [uninitialized.fill] - ARMCC has pre-C++11 uninitialized_fill and uninitialized_fill_n // [unique.ptr] namespace impl { /* Base version - use T * */ template struct unique_ptr_type_helper { typedef T *type; }; /* if "remove_reference_t::pointer" is a type, specialise to use it */ template struct unique_ptr_type_helper::pointer>> { typedef typename remove_reference_t::pointer type; }; template using unique_ptr_type_helper_t = typename unique_ptr_type_helper::type; // Want to eliminate storage for the deleter - could just use it as a base // class, for empty base optimisation, if we knew it was a class. But it could be // a pointer or reference. Here's a version that uses deleter as base, template class deleter_store : private D { public: constexpr deleter_store() noexcept = default; template constexpr deleter_store(_D &&d) noexcept : D(std::forward<_D>(d)) { } D &get_deleter() noexcept { return static_cast(*this); } const D &get_deleter() const noexcept { return static_cast(*this); } }; //Here's a version that stores (for pointer/reference) template class deleter_store::value>> { D d; public: constexpr deleter_store() noexcept : d() { } template constexpr deleter_store(_D &&d) noexcept : d(std::forward<_D>(d)) { } D &get_deleter() noexcept { return d; } const D &get_deleter() const noexcept { return d; } }; } // [unique.ptr.dltr.dflt] template struct default_delete { constexpr default_delete() noexcept = default; template ::value>> default_delete(const default_delete &d) noexcept { } void operator()(T *ptr) const { // Program is ill-formed if T is incomplete - generate diagnostic by breaking compilation // (Behaviour of raw delete of incomplete class is undefined if complete class is non-trivial, else permitted) static_assert(sizeof(T) == sizeof(T), "Cannot delete incomplete type"); delete ptr; } }; // [unique.ptr.dltr.dflt1] template struct default_delete { constexpr default_delete() noexcept = default; template ::value>> default_delete(const default_delete &d) noexcept { } template ::value>> void operator()(U *ptr) const { delete[] ptr; } }; // [unique.ptr.single] template< class T, class D = default_delete > class unique_ptr : public impl::deleter_store { template static constexpr bool is_compatible_unique_ptr() { return is_convertible::pointer, pointer>::value && !is_array::value; } public: typedef impl::unique_ptr_type_helper_t pointer; typedef T element_type; typedef D deleter_type; // [unique.ptr.single.ctor] template ::value && is_default_constructible<_D>::value>> constexpr unique_ptr() noexcept : impl::deleter_store(), ptr_() { } template ::value && is_default_constructible<_D>::value>> constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } template ::value && is_default_constructible<_D>::value>> explicit unique_ptr(pointer ptr) noexcept : impl::deleter_store(), ptr_(ptr) { } template ::value>> unique_ptr(pointer ptr, const D &d) noexcept : impl::deleter_store(d), ptr_(ptr) { } template ::value>> unique_ptr(pointer ptr, enable_if_t::value, _D &&> d) noexcept : impl::deleter_store(move(d)), ptr_(ptr) { } template > unique_ptr(pointer ptr, enable_if_t::value, _A &&> d) = delete; unique_ptr(const unique_ptr &) = delete; unique_ptr(unique_ptr &&u) noexcept : impl::deleter_store(forward(u.get_deleter())), ptr_(u.ptr_) { u.ptr_ = nullptr; } template () && (is_reference::value ? is_same::value : is_convertible::value)>> unique_ptr(unique_ptr&& u) noexcept : impl::deleter_store(std::forward(u.get_deleter())), ptr_(u.release()) { } // [unique.ptr.single.dtor] ~unique_ptr() { if (ptr_) { this->get_deleter()(ptr_); } } // [unique.ptr.single.modifiers] pointer release() noexcept { return std::exchange(ptr_, nullptr); } void reset(pointer ptr = pointer()) noexcept { pointer old = std::exchange(ptr_, ptr); if (old) { this->get_deleter()(old); } } void swap(unique_ptr &other) noexcept { using std::swap; swap(this->get_deleter(), other.get_deleter()); swap(ptr_, other.ptr_); } // [unique.ptr.single.asgn] unique_ptr &operator=(const unique_ptr &r) = delete; unique_ptr &operator=(unique_ptr &&r) noexcept { reset(r.release()); this->get_deleter() = std::forward(r.get_deleter()); return *this; } unique_ptr &operator=(nullptr_t) noexcept { reset(); return *this; } template enable_if_t() && is_assignable::value, unique_ptr> &operator=(unique_ptr &&u) noexcept { reset(u.release()); this->get_deleter() = std::forward(u.get_deleter()); return *this; } // [unique.ptr.single.observers] pointer get() const noexcept { return ptr_; } pointer operator->() const noexcept { return ptr_; } add_lvalue_reference_t operator*() const noexcept { return *ptr_; } explicit operator bool() const noexcept { return ptr_; } private: pointer ptr_; }; // [unique.ptr.runtime] template class unique_ptr : public impl::deleter_store { template static constexpr bool is_compatible_pointer() { return is_same::value || is_same::value || (is_same::value && is_pointer::value && is_convertible (*)[], element_type (*)[]>::value); } template > static constexpr bool is_compatible_unique_ptr() { return is_array::value && is_same::value && is_same::value && is_convertible::value; } public: typedef impl::unique_ptr_type_helper_t pointer; typedef T element_type; typedef D deleter_type; // [unique.ptr.runtime.ctor] / [unique.ptr.single.ctor] template ::value && is_default_constructible<_D>::value>> constexpr unique_ptr() noexcept : impl::deleter_store(), ptr_() { } template ::value && is_default_constructible<_D>::value>> constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { } template ::value && is_default_constructible<_D>::value>, class U, typename = enable_if_t()>> explicit unique_ptr(U ptr) noexcept : impl::deleter_store(), ptr_(ptr) { } template ::value>, class U, typename = enable_if_t()>> unique_ptr(U ptr, const D &d) noexcept : impl::deleter_store(d), ptr_(ptr) { } template ::value>, class U, typename = enable_if_t()>> unique_ptr(U ptr, enable_if_t::value, _D &&> d) noexcept : impl::deleter_store(std::move(d)), ptr_(ptr) { } template , class U, typename = enable_if_t()>> unique_ptr(U ptr, enable_if_t::value, _A &&> d) = delete; unique_ptr(const unique_ptr &) = delete; unique_ptr(unique_ptr &&u) noexcept : impl::deleter_store(std::forward(u.get_deleter())), ptr_(u.ptr_) { u.ptr_ = nullptr; } template () && (is_reference::value ? is_same::value : is_convertible::value)>> unique_ptr(unique_ptr&& u) noexcept : impl::deleter_store(std::forward(u.get_deleter())), ptr_(u.release()) { } // [unique.ptr.single.dtor] ~unique_ptr() { if (ptr_) { this->get_deleter()(ptr_); } } // [unique.ptr.runtime.modifiers] / [unique.ptr.single.modifiers] pointer release() noexcept { return std::exchange(ptr_, nullptr); } void reset(pointer ptr = pointer()) noexcept { pointer old = std::exchange(ptr_, ptr); if (old) { this->get_deleter()(old); } } template void reset(U) = delete; void swap(unique_ptr &other) noexcept { using std::swap; swap(this->get_deleter(), other.get_deleter()); swap(ptr_, other.ptr_); } // [unique.ptr.runtime.asgn] / [unique.ptr.single.asgn] unique_ptr &operator=(const unique_ptr &r) = delete; unique_ptr &operator=(unique_ptr &&r) noexcept { reset(r.release()); this->get_deleter() = std::forward(r.get_deleter()); return *this; } unique_ptr &operator=(nullptr_t) noexcept { reset(); return *this; } template enable_if_t() && is_assignable::value, unique_ptr> &operator=(unique_ptr &&u) noexcept { reset(u.release()); this->get_deleter() = std::forward(u.get_deleter()); return *this; } // [unique.ptr.runtime.observers] / [unique.ptr.single.observers] pointer get() const noexcept { return ptr_; } T &operator[](size_t index) const { return ptr_[index]; } explicit operator bool() const noexcept { return ptr_; } private: pointer ptr_; }; // [unique.ptr.create] template enable_if_t::value, unique_ptr> make_unique(Args &&... args) { return unique_ptr(new T(std::forward(args)...)); } template enable_if_t::value && extent::value == 0, unique_ptr> make_unique(size_t size) { return unique_ptr(new remove_extent_t[size]()); } template enable_if_t::value != 0, void> make_unique(Args &&... args) = delete; // [unique.ptr.special] template< class T, class D> void swap(unique_ptr &lhs, unique_ptr &rhs) noexcept { lhs.swap(rhs); } template bool operator==(const unique_ptr &x, const unique_ptr &y) { return x.get() == y.get(); } template bool operator!=(const unique_ptr &x, const unique_ptr &y) { return x.get() != y.get(); } template bool operator<(const unique_ptr &x, const unique_ptr &y) { using CT = common_type_t::pointer, typename unique_ptr::pointer>; return less()(x.get(), y.get()); } template bool operator<=(const unique_ptr &x, const unique_ptr &y) { return !(y < x); } template bool operator>(const unique_ptr &x, const unique_ptr &y) { return y < x; } template bool operator>=(const unique_ptr &x, const unique_ptr &y) { return !(x < y); } template bool operator==(const unique_ptr &x, nullptr_t) noexcept { return !x; } template bool operator==(nullptr_t, const unique_ptr &x) noexcept { return !x; } template bool operator!=(const unique_ptr &x, nullptr_t) noexcept { return bool(x); } template bool operator!=(nullptr_t, const unique_ptr &x) noexcept { return bool(x); } template bool operator<(const unique_ptr &x, nullptr_t) noexcept { return less::pointer>()(x.get(), nullptr); } template bool operator<(nullptr_t, const unique_ptr &x) noexcept { return less::pointer>()(nullptr, x.get()); } template bool operator>(const unique_ptr &x, nullptr_t) noexcept { return nullptr < x; } template bool operator>(nullptr_t, const unique_ptr &x) noexcept { return x < nullptr; } template bool operator<=(const unique_ptr &x, nullptr_t) noexcept { return !(nullptr < x); } template bool operator<=(nullptr_t, const unique_ptr &x) noexcept { return !(x < nullptr); } template bool operator>=(const unique_ptr &x, nullptr_t) noexcept { return !(x < nullptr); } template bool operator>=(nullptr_t, const unique_ptr &x) noexcept { return !(nullptr < x); } } // namespace std #endif // __CC_ARM namespace mstd { using std::align; using std::allocator; using std::addressof; // [uninitialized.construct.default] (C++17) template void uninitialized_default_construct(ForwardIterator first, ForwardIterator last) { for (; first != last; ++first) { ::new (static_cast(addressof(*first))) typename std::iterator_traits::value_type; } } template ForwardIterator uninitialized_default_construct_n(ForwardIterator first, Size n) { for (; n; ++first, --n) { ::new (static_cast(addressof(*first))) typename std::iterator_traits::value_type; } return first; } // [uninitialized.construct.value] (C++17) template void uninitialized_value_construct(ForwardIterator first, ForwardIterator last) { for (; first != last; ++first) { ::new (static_cast(addressof(*first))) typename std::iterator_traits::value_type(); } } template ForwardIterator uninitialized_value_construct_n(ForwardIterator first, Size n) { for (; n; ++first, --n) { ::new (static_cast(addressof(*first))) typename std::iterator_traits::value_type(); } return first; } // [uninitialized.move] (C++17) template ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result) { for (; first != last; ++result, (void) ++first) { ::new (static_cast(addressof(*result))) typename std::iterator_traits::value_type(move(*first)); } return result; } template std::pair uninitialized_move_n(InputIterator first, Size n, ForwardIterator result) { for ( ; n > 0; ++result, (void) ++first, --n) { ::new (static_cast(addressof(*result))) typename std::iterator_traits::value_type(std::move(*first)); } return { first, result }; } using std::uninitialized_copy; using std::uninitialized_copy_n; using std::uninitialized_fill; using std::uninitialized_fill_n; // [specialized.destroy] (C++17) template void destroy_at(T *location) { location->~T(); } template void destroy(ForwardIterator first, ForwardIterator last) { for (; first != last; ++first) { destroy_at(addressof(*first)); } } template ForwardIterator destroy_n(ForwardIterator first, Size n) { for (; n > 0; (void)++first, --n) { destroy_at(addressof(*first)); } return first; } using std::default_delete; using std::unique_ptr; using std::make_unique; } #endif // MSTD_MEMORY_