#pragma once #include namespace OpenVic { // Based on https://github.com/think-cell/think-cell-library/blob/b9c84dd7fc926fad80829ed49705fa51afe36e87/tc/base/ref.h // Boost Software License - Version 1.0 - August 17th, 2003 // Permission is hereby granted, free of charge, to any person or organization // obtaining a copy of the software and accompanying documentation covered by // this license (the "Software") to use, reproduce, display, distribute, // execute, and transmit the Software, and to prepare derivative works of the // Software, and to permit third-parties to whom the Software is furnished to // do so, all subject to the following: // The copyright notices in the Software and this entire statement, including // the above license grant, this restriction and the following disclaimer, // must be included in all copies of the Software, in whole or in part, and // all derivative works of the Software, unless such copies or derivative // works are solely in the form of machine-executable object code generated by // a source language processor. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. union AnyRef { // Any pointer to function can be converted to a pointer to a different function type. Calling the // function through a pointer to a different function type is undefined, but converting such pointer // back to pointer to the original function type yields the pointer to the original function. // https://en.cppreference.com/w/cpp/language/reinterpret_cast template [[nodiscard]] static constexpr T* as_mutable_ptr(T const* pt) noexcept { return const_cast(pt); } template explicit AnyRef(RefT& ref) noexcept : m_pvRef(std::addressof(ref)) {} template requires std::is_function::value explicit AnyRef(RefT& ref) noexcept : m_fpvRef(reinterpret_cast(std::addressof(ref))) {} template // may be const and/or volatile RefT& get_ref() const& noexcept { static_assert(!std::is_reference::value); if constexpr (std::is_function::value) { return *reinterpret_cast(m_fpvRef); } else { return *static_cast(as_mutable_ptr(m_pvRef)); } } void const* m_pvRef; void (*m_fpvRef)(); }; }