/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2011-2019 Danny Robson */ #pragma once #include #include #include #include namespace cruft::ptr { /// A utiliity function that deletes the provided pointer. /// /// Useful as a means of moving `delete` calls inside a translation unit /// and hence removing the need to include implementation headers for a /// type that needs deletion. template void destroy (ValueT*); /// A smart pointer that defers deletion to `destroy`. /// /// This is solely useful as a way of avoid undefined type errors when /// using std::unique_ptr and forward declarations. template class thin { public: explicit thin (ValueT *_value) { m_value = _value; } ~thin () { destroy (m_value); } thin (thin const&) = delete; thin& operator= (thin const&) = delete; thin (thin &&rhs) noexcept : m_value (rhs.m_value) { rhs.m_value = nullptr; } thin& operator= (thin &&rhs) noexcept { std::swap (m_value, rhs.m_value); } ValueT & operator* (void) &{ return *m_value; } ValueT const& operator* (void) const &{ return *m_value; } ValueT * operator->(void) &{ return m_value; } ValueT const* operator->(void) const &{ return m_value; } private: ValueT *m_value; }; template thin make_thin (ArgsT &&...args) { return thin (new ValueT (std::forward (args)...)); } } namespace cruft::align { /////////////////////////////////////////////////////////////////////////// /// round the pointer upwards to satisfy the provided alignment constexpr inline uintptr_t up (uintptr_t ptr, size_t alignment) { // we perform this as two steps to avoid unnecessarily incrementing when // remainder is zero. if (auto mod = ptr % alignment; mod) ptr += alignment - mod; return ptr; } /////////////////////////////////////////////////////////////////////////// /// round the pointer upwards to satisfy the provided alignment template constexpr T* up (T *ptr, size_t alignment) { // we perform this as two steps to avoid unnecessarily incrementing when // remainder is zero. return reinterpret_cast( up (reinterpret_cast (ptr), alignment) ); } //------------------------------------------------------------------------- template constexpr T* up (T *ptr, std::align_val_t _alignment) { auto alignment = std::underlying_type_t (_alignment); return up (ptr, alignment); } ///------------------------------------------------------------------------ /// round the pointer upwards to the nearest valid alignment for T template constexpr auto up (T *t) { return up (t, alignof (T)); } ///------------------------------------------------------------------------ /// round the pointer upwards to the nearest valid alignment for T template constexpr auto up (uintptr_t ptr) { return up (ptr, alignof (T)); } /////////////////////////////////////////////////////////////////////////// constexpr inline uintptr_t down (uintptr_t ptr, size_t alignment) { return ptr - ptr % alignment; } //------------------------------------------------------------------------- template constexpr T* down (T *ptr, size_t alignment) { return reinterpret_cast ( down (reinterpret_cast (ptr), alignment) ); } }