Last active
January 1, 2019 01:50
-
-
Save Sam-Belliveau/c115fef85c1a60ccfd7dec453bd4bc80 to your computer and use it in GitHub Desktop.
it is like unique_ptr or scoped_ptr, but you can copy it. When you copy it, the new ptr is marked as shared, and will not be deallocated. If it is moved or stolen, it will be marked with what the other ptr is marked with. It works for arrays and single objects. Pointers that are marked shared will not deallocate. Pointers marked Moved will not d…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| Copyright 2018, Sam R. Belliveau | |
| Permission is hereby granted, free of charge, to any person obtaining a copy | |
| of this software and associated documentation files (the "Software"), to deal | |
| in the Software without restriction, including without limitation the rights | |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| copies of the Software, and to permit persons to whom the Software is | |
| furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be | |
| included in all copies or substantial portions of the Software. | |
| 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| SOFTWARE. | |
| */ | |
| #ifndef SAMS_OWNED_POINTER_LIBRARY_HPP | |
| #define SAMS_OWNED_POINTER_LIBRARY_HPP 1 | |
| namespace SmartPtrHelpers | |
| { | |
| /* Get Special Type Info */ | |
| template<class inT> | |
| struct GetTypeInfoHelper | |
| { using type = inT; enum { array = false, fixed = false }; }; | |
| template<class inT> | |
| struct GetTypeInfoHelper<inT[]> | |
| { using type = inT; enum { array = true, fixed = false }; }; | |
| template<class inT, unsigned long long N> | |
| struct GetTypeInfoHelper<inT[N]> | |
| { using type = inT; enum { array = true, fixed = true, size = N }; }; | |
| /* Used to remove <memory> dependency */ | |
| /* Deleter with array checking */ | |
| template<class T> | |
| struct default_deleter | |
| { | |
| void operator()(typename GetTypeInfoHelper<T>::type* ptr) | |
| { | |
| if(GetTypeInfoHelper<T>::array) { delete[] ptr; } | |
| else { delete ptr; } | |
| } | |
| }; | |
| } | |
| template<class T, class Deleter = SmartPtrHelpers::default_deleter<T>> | |
| class owned_ptr | |
| { | |
| public: /* Static Classes / Types / Exceptions */ | |
| /* Size Type */ | |
| using size_type = unsigned long long; | |
| /* Class Information*/ | |
| template<class inT> | |
| using GetTypeInfo = SmartPtrHelpers::GetTypeInfoHelper<inT>; | |
| using TypeInfo = GetTypeInfo<T>; | |
| /* SFINAE */ | |
| template<bool B> struct enable_if{}; | |
| template<> struct enable_if<true>{ using type = void; }; | |
| template<bool B> using enable_if_t = typename enable_if<B>::type; | |
| /* Is T an array, (Different Situations) */ | |
| static constexpr bool IsArray = TypeInfo::array; | |
| static constexpr bool IsFixed = TypeInfo::fixed; | |
| /* Element / Pointer Types */ | |
| using element_type = typename TypeInfo::type; | |
| using pointer = typename TypeInfo::type*; | |
| using deleter_type = Deleter; | |
| public: /* Status: Values Indicate Ranking With Owned As Most Important */ | |
| enum Status { Owned = 3, Shared = 2, Moved = 1, Null = 0 }; | |
| private: /* Member Variables */ | |
| pointer ptr; // Data | |
| Status state; // Ownership Status | |
| public: /* Constructors and Assignment Methods */ | |
| owned_ptr() : ptr{nullptr}, state{Status::Null} {} | |
| /* New Pointer */ | |
| owned_ptr(pointer in_ptr) : ptr{in_ptr}, state{Status::Owned} { NullCheck(); } | |
| owned_ptr& operator=(pointer in_ptr) | |
| { | |
| deallocate(); ptr = in_ptr; | |
| state = Status::Owned; | |
| NullCheck(); | |
| return *this; | |
| } | |
| /* Share Pointer */ | |
| owned_ptr(const owned_ptr& other) : ptr{other.ptr}, state{other.ShareState()} {} | |
| owned_ptr& operator=(const owned_ptr& other) | |
| { | |
| deallocate(); ptr = other.ptr; | |
| state = other.ShareState(); | |
| return *this; | |
| } | |
| /* Move Pointer */ | |
| owned_ptr(owned_ptr&& other) : ptr{other.ptr}, state{other.state} | |
| { other.state = Status::Moved; } | |
| owned_ptr& operator=(owned_ptr&& other) | |
| { | |
| deallocate(); ptr = other.ptr; | |
| state = other.state; | |
| other.state = Status::Moved; | |
| return *this; | |
| } | |
| owned_ptr& steal(owned_ptr& other) | |
| { | |
| deallocate(); ptr = other.ptr; | |
| state = other.state; | |
| other.state = Status::Moved; | |
| return *this; | |
| } | |
| public: // Deallocater | |
| void deallocate() { if(state == Status::Owned) { deleter_type()(ptr); } } | |
| ~owned_ptr() { deallocate(); } | |
| public: // Modifiers | |
| pointer release() noexcept | |
| { | |
| if(state == Status::Owned) { state = Status::Moved; return ptr; } | |
| return nullptr; | |
| } | |
| void reset() { deallocate(); ptr = nullptr; state = Status::Null; } | |
| void swap(owned_ptr& other) | |
| { | |
| pointer tPtr = ptr; Status tState = state; | |
| ptr = other.ptr; state = other.state; | |
| other.ptr = tPtr; other.state = tState; | |
| } | |
| public: // Single Object Getters | |
| /* Have to make template tT, or error */ | |
| /* Will trigger on the entire object */ | |
| template<class tT = T, class = enable_if_t<!GetTypeInfo<tT>::array>> | |
| element_type& operator*() const { return *ptr; } | |
| template<class tT = T, class = enable_if_t<!GetTypeInfo<tT>::array>> | |
| pointer operator->() const { return ptr; } | |
| public: // Array Type Object Getters | |
| template<class tT = T, class = enable_if_t<GetTypeInfo<tT>::array>> | |
| element_type& operator[](const size_type i) { return ptr[i]; } | |
| template<class tT = T, class = enable_if_t<GetTypeInfo<tT>::array>> | |
| const element_type& operator[](const size_type i) { return ptr[i]; } | |
| public: // Observers | |
| pointer get() const noexcept { return ptr; } | |
| deleter_type& get_deleter() noexcept { return deleter_type(); } | |
| const deleter_type& get_deleter() const noexcept { return deleter_type(); } | |
| bool isOwned() const noexcept { return state == Status::Owned; } | |
| bool isShared() const noexcept { return state == Status::Shared; } | |
| bool isMoved() const noexcept { return state == Status::Moved; } | |
| bool isSafe() const noexcept { return state >= Status::Shared; } | |
| bool isNull() const noexcept { return state == Status::Null; } | |
| explicit operator bool() const noexcept { return isSafe(); } | |
| bool isArray() const noexcept { return IsArray; } | |
| bool isFixed() const noexcept { return IsFixed; } | |
| public: // If Fixed, Make It A Range | |
| template<bool TF = IsFixed, class = enable_if_t<TF>> | |
| size_type size() const noexcept { return TypeInfo::size; } | |
| template<bool TF = IsFixed, class = enable_if_t<TF>> | |
| bool empty() const noexcept { return size() > 0; } | |
| template<bool TF = IsArray, class = enable_if_t<TF>> | |
| pointer begin() noexcept { return ptr; } | |
| template<bool TF = IsArray, class = enable_if_t<TF>> | |
| const pointer begin() const noexcept { return ptr; } | |
| template<bool TF = IsArray, class = enable_if_t<TF>> | |
| const pointer cbegin() const noexcept { return ptr; } | |
| template<bool TF = IsFixed, class = enable_if_t<TF>> | |
| pointer end() noexcept { return ptr + size(); } | |
| template<bool TF = IsFixed, class = enable_if_t<TF>> | |
| const pointer end() const noexcept { return ptr + size(); } | |
| template<bool TF = IsFixed, class = enable_if_t<TF>> | |
| const pointer cend() const noexcept { return ptr + size(); } | |
| template<bool TF = IsArray, class = enable_if_t<TF>> | |
| element_type& front() { return ptr[0]; } | |
| template<bool TF = IsArray, class = enable_if_t<TF>> | |
| const element_type& front() const { return ptr[0]; } | |
| template<bool TF = IsFixed, class = enable_if_t<TF>> | |
| element_type& back() { return ptr[size()-1]; } | |
| template<bool TF = IsFixed, class = enable_if_t<TF>> | |
| const element_type& back() const { return ptr[size()-1]; } | |
| template<bool TF = IsArray, class = enable_if_t<TF>> | |
| pointer data() { return ptr; } | |
| template<bool TF = IsArray, class = enable_if_t<TF>> | |
| const pointer data() const { return ptr; } | |
| private: // Private Methods | |
| void NullCheck() noexcept { if(ptr == nullptr) state = Status::Null; } | |
| /* Returns State Another owned_ptr Should Use */ | |
| Status ShareState() const noexcept { return state < Shared ? state : Shared; } | |
| }; | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment