Last active
December 30, 2018 11:19
-
-
Save graphitemaster/2308283 to your computer and use it in GitHub Desktop.
This file contains 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
/* | |
* GCC and GCC-like compilers set this flag when -std=c++0x is set | |
* we can use these to make this code use some C++11 features. | |
*/ | |
#ifdef __GXX_EXPERIMENTAL_CXX0X__ | |
#define SASSERT(X,Y) static_assert(X,Y) | |
#define NULLPTR nullptr | |
#else | |
/* | |
* Primitive static assert implementation: | |
* | |
* Expression fails, char is typedef'ed with | |
* a negitive value, which is illegal and will | |
* trigger a compiler error. | |
*/ | |
#define SASSERT(X,Y) \ | |
typedef char static_assert_ ## __LINE__ [(X)?1:-1] | |
/* | |
* We'll implement out own nullptr | |
*/ | |
const class | |
{ | |
public: | |
/* | |
* Convertible to any type of non-null member | |
* pointers. | |
*/ | |
template<typename T> | |
inline operator T*() const { return 0; } | |
/* | |
* Also convertible to any type of null member | |
* pointers. | |
*/ | |
template<typename T1, typename T2> | |
inline operator T1 T2::*() const { return 0;} | |
private: | |
/* | |
* This will make it impossible to take the | |
* address of nullptr | |
*/ | |
void operator&() const; | |
} NULLPTR = {}; | |
#endif | |
struct holding_failure {}; | |
struct holding_empty {}; | |
struct holding_policy | |
{ | |
typedef void base_type; | |
typedef base_type* value_type; | |
typedef size_t size_type; | |
virtual value_type get (value_type*) = 0; | |
virtual void destroy(value_type*) = 0; | |
virtual void copy (void const*, value_type*) = 0; | |
virtual void clone (value_type const*, value_type*) = 0; | |
virtual void move (value_type const*, value_type*) = 0; | |
virtual size_type size () = 0; | |
}; | |
template<typename T> | |
struct holding_policy_base : holding_policy { | |
virtual size_t size() { return sizeof(T); } | |
}; | |
/* | |
* Minimal holding policy does not require any sort | |
* of managment of class constructors or destructors | |
* The reason is `holding_policy_min` is only required | |
* for POD ( plain old data types ). Alternitive types | |
* specifically user-defined types, or standard library | |
* types use the latter policy, dubbed, holding_policy_max. | |
*/ | |
template<typename T> | |
struct holding_policy_min : holding_policy_base<T> | |
{ | |
virtual void destroy( | |
holding_policy::value_type* x | |
){/* POD types have no dtor */} | |
virtual void copy ( | |
holding_policy::base_type const* src, | |
holding_policy::value_type* dst | |
){ | |
// placement new | |
new(dst) T(*reinterpret_cast<T const*>(src)); | |
} | |
virtual void clone( | |
holding_policy::value_type const* src, | |
holding_policy::value_type* dst | |
){ *dst = *src; } | |
virtual void move( | |
holding_policy::value_type const* src, | |
holding_policy::value_type* dst | |
){ *dst = *src; } | |
virtual holding_policy::base_type* get(holding_policy::value_type* src){ | |
return reinterpret_cast<holding_policy::value_type>(src); | |
} | |
}; | |
/* | |
* This is the policy structure for larger types, | |
* or rather, non POD types, such as user defined | |
* types, or standard library containers. This | |
* handles proper construction, and destruction, | |
* allowing safe use of holding. | |
*/ | |
template<typename T> | |
struct holding_policy_max : holding_policy_base<T> | |
{ | |
virtual void destroy( | |
holding_policy::value_type* x | |
){ | |
if (*x) | |
{ | |
/* | |
* Proper class destruction | |
*/ | |
delete (*reinterpret_cast<T**>(x)); | |
*x = NULLPTR; | |
} | |
} | |
virtual void copy ( | |
holding_policy::base_type const* src, | |
holding_policy::value_type* dst | |
){ | |
*dst = new T(*reinterpret_cast<T const*>(src)); | |
} | |
virtual void clone( | |
holding_policy::value_type const* src, | |
holding_policy::value_type* dst | |
){ | |
*dst = new T(**reinterpret_cast<T* const*>(src)); | |
} | |
virtual void move( | |
holding_policy::value_type const* src, | |
holding_policy::value_type* dst | |
) { | |
/* | |
* Proper class destruction, and reconstruction | |
* for movement of data. | |
*/ | |
(*reinterpret_cast<T**>(dst))->~T(); | |
**reinterpret_cast<T**>(dst) = **reinterpret_cast<T* const*>(src); | |
} | |
virtual holding_policy::base_type* get(holding_policy::value_type* src){ | |
return *src; | |
} | |
}; | |
/* | |
* Class fowarding of holding_type, since policy selection | |
* requires this beforehand as a template specialization. | |
*/ | |
struct holding_type; | |
/* | |
* Policy selectors, this will allow policy selection via type def, | |
* 100% compile-time translation. | |
*/ | |
template<typename T> | |
struct holding_policy_select { typedef holding_policy_max<T> type; }; | |
template<typename T> | |
struct holding_policy_select<T*> { typedef holding_policy_min<T*> type; }; | |
template<> | |
struct holding_policy_select<holding_type> { | |
typedef void type; | |
}; | |
/* | |
* Template specializations of POD types, for min holding policys | |
* these must be modified if C++ decides to add any more language | |
* specific types. | |
*/ | |
template<> struct holding_policy_select<signed char> {typedef holding_policy_min<signed char> type;}; | |
template<> struct holding_policy_select<unsigned char> {typedef holding_policy_min<unsigned char> type;}; | |
template<> struct holding_policy_select<signed short> {typedef holding_policy_min<signed short> type;}; | |
template<> struct holding_policy_select<unsigned short>{typedef holding_policy_min<unsigned short> type;}; | |
template<> struct holding_policy_select<signed int> {typedef holding_policy_min<signed int> type;}; | |
template<> struct holding_policy_select<unsigned int> {typedef holding_policy_min<unsigned int> type;}; | |
template<> struct holding_policy_select<signed long> {typedef holding_policy_min<signed long> type;}; | |
template<> struct holding_policy_select<unsigned long> {typedef holding_policy_min<unsigned long> type;}; | |
template<> struct holding_policy_select<float> {typedef holding_policy_min<float> type;}; | |
template<> struct holding_policy_select<bool> {typedef holding_policy_min<bool> type;}; | |
/* | |
* This function will return the correct `empty` type for any type | |
* using the policy system above. | |
*/ | |
template<typename T> | |
holding_policy* holding_policy_get() | |
{ | |
/* | |
* Store as static for compile time optimizations. | |
*/ | |
static typename holding_policy_select<T>::type p; | |
return &p; | |
} | |
/* | |
* We need a way to validate that the user specifies | |
* const char * opposed to char * for getting a string | |
* literal, otherwise the cast will throw a runtime | |
* error, and it's better to catch that during compilation | |
* opposed to runtime. Thats what this is for. | |
*/ | |
template<typename T> struct holding_is_charptr {enum{value=0};}; | |
template<> struct holding_is_charptr<char*> {enum{value=1};}; | |
/* | |
* The following class below implements the variant type required | |
* to create the holding class dubbed `holding_type` | |
*/ | |
struct holding_type | |
{ | |
public: | |
/* | |
* Initializing constructor | |
*/ | |
template<typename T> | |
holding_type(const T& rhs) : | |
m_policy(holding_policy_get<holding_empty>()), | |
m_object(NULLPTR) { | |
assign(rhs); | |
} | |
/* | |
* Empty constructor to prevent the compiler | |
* from creating a trivial constructor. | |
*/ | |
holding_type() : | |
m_policy(holding_policy_get<holding_empty>()), | |
m_object(NULLPTR) | |
{} | |
/* | |
* Special constructing for string literals only. | |
* This should be considered UB, but the standard | |
* says it's safe. | |
*/ | |
holding_type(const char *c) : | |
m_policy(holding_policy_get<holding_empty>()), | |
m_object(NULLPTR) { | |
assign(c); | |
} | |
/* | |
* Default copy constructor, exactly the same as | |
* any other constructor, the assign() method | |
* does all the work. Constructor initializer lists | |
* are exactly the same straight through. | |
*/ | |
holding_type(const holding_type& c) : | |
m_policy(holding_policy_get<holding_empty>()), | |
m_object(NULLPTR) { | |
assign(c); | |
} | |
/* | |
* Simple deconstruction, all handled by the policy | |
* system for POD and user defined types. Safe for | |
* any object. | |
*/ | |
~holding_type() { | |
m_policy->destroy(&m_object); | |
} | |
/* | |
* This function handles all the work for assignment, | |
* which is used in all the constructors, even the | |
* copy constructor. | |
*/ | |
template<typename T> | |
holding_type& assign(const T& x) | |
{ | |
/* | |
* *this needs to be reset for assignment of | |
* new data, otherwise errors could occur. | |
*/ | |
reset(); | |
/* | |
* Get the correct policy, and build from value | |
* of `x` which is of type `T` | |
*/ | |
m_policy = holding_policy_get<T>(); | |
m_policy->copy(&x, &m_object); | |
return *this; | |
} | |
/* | |
* Assignment from another holding_type, overloaded | |
* function. | |
*/ | |
holding_type& assign(const holding_type& x) | |
{ | |
/* | |
* *this needs to be reset for assignment of | |
* new data, otherwise errors could occur. | |
*/ | |
reset(); | |
/* | |
* Think of this as a copy constructor, since | |
* the data for *this will be taken from x. | |
* The only different between this assignment | |
* and the former is this one does not copy from | |
* value, but rather clones from the previous | |
* holding_type, which is better. | |
*/ | |
m_policy = x.m_policy; | |
m_policy->clone(&x.m_object, &m_object); | |
return *this; | |
} | |
/* | |
* Assignment operator, allowing assignment | |
* of *this like a normal type, the actual work | |
* is done by the aformentioned assign functions. | |
*/ | |
template<typename T> | |
holding_type& operator=(const T& x) { return assign(x);} | |
/* | |
* Assignment operator for literal strings, since things like | |
* const char[x] are not considered const char* by the compiler | |
* as a operator translation step, but rather are implitically | |
* convertable to const char * as a translation step. | |
*/ | |
holding_type& operator=(const char* x) { return assign(x); } | |
/* | |
* Reset method, statically deletes the given object | |
* within the correct policy, while resetting the policy | |
* of a new holding_empty policy | |
*/ | |
void reset() | |
{ | |
m_policy->destroy(&m_object); | |
m_policy = holding_policy_get<holding_empty>(); | |
} | |
/* | |
* Returns true if object contains no | |
* actual physical value. | |
*/ | |
bool empty() const { | |
return m_policy == holding_policy_get<holding_empty>(); | |
} | |
/* | |
* Returns true if type types are of the same, | |
* and thus can be compatible. | |
*/ | |
bool compat(holding_type& x) const { | |
return m_policy == x.m_policy; | |
} | |
/* | |
* Utility swap function | |
*/ | |
holding_type& swap(holding_type& x) | |
{ | |
/* | |
* Use internal swap functions | |
* replace with std::swap() if | |
* required. | |
*/ | |
internal_swap(m_policy, x.m_policy); | |
internal_swap(m_object, x.m_object); | |
return *this; | |
} | |
/* | |
* This function is what gives back the correct | |
* type of the data, via cast. This is all possible | |
* and totally safe thanks to the policy system. | |
*/ | |
template<typename T> | |
T& cast() | |
{ | |
SASSERT( | |
holding_is_charptr<T>::value != 1, | |
"error, using holding_type::cast() with non-const `char*`, use `const char*` instead" | |
); | |
if (m_policy != holding_policy_get<T>()) | |
throw holding_failure(); | |
T* r = reinterpret_cast<T*>(m_policy->get(&m_object)); | |
return *r; | |
} | |
private: | |
/* | |
* We implement our own internal swaping | |
* system for people who choose not to | |
* use the standard library. Other wise | |
* if you do so choose, replace the calls | |
* in the utility swap function above | |
* with calls to std::swap(). | |
*/ | |
template<typename T> | |
void internal_swap(T& src, T& dst) | |
{ | |
T cmp(src); | |
src = dst; | |
dst = src; | |
} | |
/* | |
* The actual data is stored here | |
* everything as a void *, and a policy | |
* to manage, assign, and create from | |
* this object safely. | |
*/ | |
holding_policy* m_policy; | |
void * m_object; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment