/dotmars/base/variant.d
D | 231 lines | 178 code | 37 blank | 16 comment | 30 complexity | efc8dafcd270be6ac3383df75c5af931 MD5 | raw file
- /** Module: variant.d: A stack-based variant implemention
-
- Written in the D programming language 1.0
-
- Authors: Wei Li <oldrev@gmail.com>
- Copyright: Copyright (C) 2007 Wei Li.
- License: BSD
- */
-
- module dotmars.base.variant;
-
- import dotmars.base.tuple;
- import dotmars.base.stdexcept;
-
- private template MaxSizeImp(T, V...)
- {
- static if(V.length > 0)
- private const int tailResult = MaxSizeImp!(V).result;
- else
- private const int tailResult = T.sizeof;
-
- public const int result = T.sizeof > tailResult ? T.sizeof : tailResult;
- };
-
- private template MaxSize(TList...)
- {
- const int MaxSize = MaxSizeImp!(TList).result;
- }
-
-
- /**
- A Variant implemention inspired by boost.variant
- */
- struct Variant(TList...)
- {
- //ensure void was not in the TList
- static assert( IndexOf!(void, TList) < 0, "Error: Invalid type in the TList");
-
- public alias TList TypeList;
- public alias Variant!(TypeList) SelfType;
- private alias ubyte[MaxSize!(TypeList)] Holder;
-
- private Holder m_held;
- private int m_which = -1;
-
- template indexof(T)
- {
- const int indexof = IndexOf!(T, TypeList);
- }
-
- public static SelfType opCall(ValueType)(ValueType val)
- {
- SelfType var;
- var.opAssign!(ValueType)(val);
- return var;
- }
-
- public int which()
- {
- return m_which;
- }
-
- public ValueType opAssign(ValueType)(ValueType rhs)
- {
- const auto i = IndexOf!(ValueType, TypeList);
- static assert(i >= 0);
- ValueType* heldPtr = cast(ValueType*)m_held.ptr;
- *heldPtr = rhs;
- m_which = i;
-
- return rhs;
- }
-
- public bool opEquals(ValueType)(ValueType rhs)
- {
- assert(!empty);
-
- static if(is(ValueType == SelfType))
- {
- foreach(T; TypeList)
- {
- const int i = IndexOf!(T, TypeList);
- if(i == which)
- {
- return (rhs.which == which) && (get!(T) == rhs.get!(T));
- }
- }
- }
- else
- {
- const int i = IndexOf!(ValueType, TypeList);
- static assert(i >= 0);
-
- return get!(ValueType)() == rhs;
- }
- }
-
-
- public int opCmp(ValueType)(ValueType rhs) //used for hash or something else
- out(result)
- {
- assert(result == 0 || result == 1 || result == -1);
- }
- body
- {
- if(rhs == *this)return 0;
-
- static if(is(ValueType == SelfType))
- {
- foreach(T; TypeList)
- {
- const int i = IndexOf!(T, TypeList);
- if((i == which) && (rhs.which == which))
- {
- return get!(T) < rhs.get!(T) ? -1 : 1;
- }
- }
- }
- else
- {
- const int i = IndexOf!(ValueType, TypeList);
- static assert(i >= 0);
-
- return get!(ValueType)() < rhs ? -1 : 1;
- }
- }
-
- public TypeInfo type()
- {
- if(which < 0)return typeid(void);
- foreach(T; TypeList)
- {
- const int i = IndexOf!(T, TypeList);
- if(i == which)
- {
- return typeid(TypeList[i]);
- }
- }
- }
-
- public ValueType get(ValueType)()
- {
- if(indexof!(ValueType) != which)
- throw new BadCastException("Invalid type");
-
- return *(cast(ValueType*)m_held.ptr);
- }
-
- //An nice name stolen from std.variant
- public ValueType* peek(ValueType)()
- {
- //hey, I say again, we need the ref!
- if(indexof!(ValueType) != which)
- return null;
-
- return cast(ValueType*)m_held.ptr;
- }
-
- public bool empty()
- {
- return m_which < 0;
- }
-
- public void swap(inout SelfType var)
- {
- Holder h;
- h[] = m_held[];
- int w = which;
- m_held[] = var.m_held[];
- m_which = var.which;
- var.m_held[] = h[];
- var.m_which = w;
- }
-
-
- public hash_t toHash()
- {
- return type.getHash(m_held.ptr);
- }
-
- //TODO: Make it sense.
- public string toString()
- {
- return "variant";
- }
-
- //overloading for arithmetic operators, copied from Tango :)
-
- typeof(T+T) opAdd(T)( T rhs ) { return get!(T) + rhs; }
- typeof(T+T) opAdd_r(T)( T lhs ) { return lhs + get!(T); }
- typeof(T-T) opSub(T)( T rhs ) { return get!(T) - rhs; }
- typeof(T-T) opSub_r(T)( T lhs ) { return lhs - get!(T); }
- typeof(T*T) opMul(T)( T rhs ) { return get!(T) * rhs; }
- typeof(T*T) opMul_r(T)( T lhs ) { return lhs * get!(T); }
- typeof(T/T) opDiv(T)( T rhs ) { return get!(T) / rhs; }
- typeof(T/T) opDiv_r(T)( T lhs ) { return lhs / get!(T); }
- typeof(T%T) opMod(T)( T rhs ) { return get!(T) % rhs; }
- typeof(T%T) opMod_r(T)( T lhs ) { return lhs % get!(T); }
- typeof(T&T) opAnd(T)( T rhs ) { return get!(T) & rhs; }
- typeof(T&T) opAnd_r(T)( T lhs ) { return lhs & get!(T); }
- typeof(T|T) opOr(T)( T rhs ) { return get!(T) | rhs; }
- typeof(T|T) opOr_r(T)( T lhs ) { return lhs | get!(T); }
- typeof(T^T) opXor(T)( T rhs ) { return get!(T) ^ rhs; }
- typeof(T^T) opXor_r(T)( T lhs ) { return lhs ^ get!(T); }
- typeof(T<<T) opShl(T)( T rhs ) { return get!(T) << rhs; }
- typeof(T<<T) opShl_r(T)( T lhs ) { return lhs << get!(T); }
- typeof(T>>T) opShr(T)( T rhs ) { return get!(T) >> rhs; }
- typeof(T>>T) opShr_r(T)( T lhs ) { return lhs >> get!(T); }
- typeof(T>>>T) opUShr(T)( T rhs ) { return get!(T) >>> rhs; }
- typeof(T>>>T) opUShr_r(T)( T lhs ) { return lhs >>> get!(T); }
- typeof(T~T) opCat(T)( T rhs ) { return get!(T) ~ rhs; }
- typeof(T~T) opCat_r(T)( T lhs ) { return lhs ~ get!(T); }
-
- T opAddAssign(T)( T rhs ) { return (*this = get!(T) + rhs); }
- T opSubAssign(T)( T rhs ) { return (*this = get!(T) - rhs); }
- T opMulAssign(T)( T rhs ) { return (*this = get!(T) * rhs); }
- T opDivAssign(T)( T rhs ) { return (*this = get!(T) / rhs); }
- T opModAssign(T)( T rhs ) { return (*this = get!(T) % rhs); }
- T opAndAssign(T)( T rhs ) { return (*this = get!(T) & rhs); }
- T opOrAssign(T)( T rhs ) { return (*this = get!(T) | rhs); }
- T opXorAssign(T)( T rhs ) { return (*this = get!(T) ^ rhs); }
- T opShlAssign(T)( T rhs ) { return (*this = get!(T) << rhs); }
- T opShrAssign(T)( T rhs ) { return (*this = get!(T) >> rhs); }
- T opUShrAssign(T)( T rhs ) { return (*this = get!(T) >>> rhs); }
- T opCatAssign(T)( T rhs ) { return (*this = get!(T) ~ rhs); }
-
- T opIndex(T, K)(K key) { return get!(T)[key]; }
- T opIndexAssign(T, K)(T rhs, K key) { return get!(T)[key] = rhs; }
-
- }
-