1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
// -*-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 <typeinfo>
#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<size_t n> 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 T> 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<union_entry *> (tb);
te->_addr ()->~T ();
}
static void assignop (union_entry_base *dstb,
const union_entry_base *srcb) {
union_entry *dst = static_cast<union_entry *> (dstb);
const union_entry *src = static_cast<const union_entry *> (srcb);
dst->select ();
(void) (*dst->_addr () = *src->_addr ()); // XXX - cast required by egcs
}
T *_addr () { return reinterpret_cast<T *> (m); }
const T *_addr () const { return reinterpret_cast<const T *> (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<void *> (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<void> : 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<union_entry *> (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 T, size_t n> class union_entry<T[n]>
: public union_entry<toarray (T[n])> {
// 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_ */
|