// -*-c++-*- /* $Id: union.h,v 1.7 1999/09/16 00:49:50 dm Exp $ */ /* * * Copyright (C) 1998 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #ifndef _ARPC_TAGUNION_INCLUDED_ #define _ARPC_TAGUNION_INCLUDED_ 1 #include "opnew.h" #include "array.h" #include #ifndef TUNION_DEBUG # if defined (CHECK_BOUNDS) || defined (DMALLOC) # define TUNION_DEBUG 1 # endif /* CHECK_BOUNDS || DMALLOC */ #endif /* !TUNION_DEBUG */ #if 0 /* For a contant n, C++ defines sizeof (T[n]) to be n * sizeof (T). * Assuming 8 is the maximum alignment requirement, this means any * object T's maximum alignment requirment is sizeof (T) % 8. * AlignmentHack (T) can be used to declare a primitive type with the * same alignment requirements. */ template struct __alignment_hack; template<> struct __alignment_hack<0> { typedef double type; }; template<> struct __alignment_hack<1> { typedef char type; }; template<> struct __alignment_hack<2> { typedef u_int16_t type; }; template<> struct __alignment_hack<3> { typedef char type; }; template<> struct __alignment_hack<4> { typedef u_int32_t type; }; template<> struct __alignment_hack<5> { typedef char type; }; template<> struct __alignment_hack<6> { typedef u_int16_t type; }; template<> struct __alignment_hack<7> { typedef char type; }; #define AlignmentHack(T) typename ::__alignment_hack<(sizeof(T)%8)>::type #else #define AlignmentHack(T) u_int64_t #endif class union_entry_base { protected: struct vtbl { const std::type_info *type; void (*destructor) (union_entry_base *); void (*assignop) (union_entry_base *, const union_entry_base *); size_t size; }; const vtbl *vptr; public: void init () { vptr = NULL; } void init (const union_entry_base &b) { init (); assign (b); } void destroy () { if (vptr) vptr->destructor (this); init (); } void assign (const union_entry_base &b) { if (b.vptr) b.vptr->assignop (this, &b); else destroy (); } const std::type_info *type () const { return vptr ? vptr->type : NULL; } }; template class union_entry : public union_entry_base { union { AlignmentHack(T) _hack; char m[sizeof (T)]; }; static const vtbl *getvptr () { static const vtbl vt = { &typeid (T), &destructor, &assignop, sizeof (T) }; return &vt; } static void destructor (union_entry_base *tb) { union_entry *te = static_cast (tb); te->_addr ()->~T (); } static void assignop (union_entry_base *dstb, const union_entry_base *srcb) { union_entry *dst = static_cast (dstb); const union_entry *src = static_cast (srcb); dst->select (); (void) (*dst->_addr () = *src->_addr ()); // XXX - cast required by egcs } T *_addr () { return reinterpret_cast (m); } const T *_addr () const { return reinterpret_cast (m); } void verify () const { #if TUNION_DEBUG if (!vptr || *vptr->type != typeid (T)) panic ("union_entry<%s>::verify: accessed when %s selected\n", typeid (T).name (), vptr ? vptr->type->name () : "NULL"); #endif /* TUNION_DEBUG */ } public: T *addr () { verify (); return _addr (); } const T *addr () const { verify (); return _addr (); } T *operator-> () { return addr (); } const T *operator-> () const { return addr (); } T &operator *() { return *addr (); } const T &operator *() const { return *addr (); } operator T *() { return addr (); } operator const T *() const { return addr (); } void select () { if (!vptr || *vptr->type != typeid (T)) { destroy (); vptr = getvptr (); new (static_cast (m)) T; } } void Xstompcast () { #if TUNION_DEBUG if (!vptr || vptr->size != sizeof (T)) panic ("union_entry<%s>::Xstompcast: cast changes object size\n", typeid (T).name ()); #endif /* TUNION_DEBUG */ vptr = getvptr (); } }; template<> class union_entry : public union_entry_base { static const vtbl *getvptr () { static const vtbl vt = { &typeid (void), &destructor, &assignop, 0 }; return &vt; } static void destructor (union_entry_base *tb) {} static void assignop (union_entry_base *dstb, const union_entry_base *srcb) { union_entry *dst = static_cast (dstb); dst->select (); } public: void select () { if (!vptr || *vptr->type != typeid (void)) { destroy (); vptr = getvptr (); } } /* It's okay to cast anything to void. */ void Xstompcast () { select (); } }; template class union_entry : public union_entry { // typedef toarray (T[n]) array_t; toarray (T) &operator[] (ptrdiff_t i) { return (**this)[i]; } const toarray (T) &operator[] (ptrdiff_t i) const { return (**this)[i]; } }; #endif /* !_ARPC_TAGUNION_INCLUDED_ */