Skip to content

Instantly share code, notes, and snippets.

@Sam-Belliveau
Last active January 1, 2019 01:50
Show Gist options
  • Select an option

  • Save Sam-Belliveau/c115fef85c1a60ccfd7dec453bd4bc80 to your computer and use it in GitHub Desktop.

Select an option

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…
/*
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