зеркало из https://github.com/mozilla/pjs.git
227 строки
10 KiB
C++
227 строки
10 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#ifndef CHECKEDUNION_H
|
|
#define CHECKEDUNION_H
|
|
|
|
//
|
|
// Use the CheckedUnion2 macro to create a checked union of two structures T1 and T2
|
|
// with the following features:
|
|
//
|
|
// 1. In DEBUG versions the union remembers which of the structures in it, if any,
|
|
// is currently valid.
|
|
// 2. The structures T1 and T2 can have constructors.
|
|
// 3. Methods are provided to explicitly construct a T1 or T2 inside the union.
|
|
//
|
|
//
|
|
// To use a CheckedUnion2, do the following:
|
|
//
|
|
// Declare the structures T1 and T2 and the checked union as follows:
|
|
//
|
|
// struct Foo { ... };
|
|
// struct Bar { ... };
|
|
// CheckedUnion2(Foo, Bar) cu;
|
|
//
|
|
// To construct a Foo inside the checked union, call the following, replacing the ...
|
|
// with arguments to Foo's constructor. Constructing a Bar is analogous.
|
|
//
|
|
// new(cu.initFoo()) Foo(...);
|
|
//
|
|
// To get a reference to the Foo inside the checked union, call the following. In DEBUG
|
|
// versions it will raise an assert if the checked union does not currently contain a Foo.
|
|
// Getting a reference to a Bar is analogous.
|
|
//
|
|
// cu.getFoo()
|
|
//
|
|
// To erase the union's knowledge of the structure it contains, call the following. This
|
|
// is a no-op in non-DEBUG versions.
|
|
//
|
|
// cu.clear();
|
|
//
|
|
// Caution: T1 and T2 should not have destructors; the checked union does not call them.
|
|
// T1 and T2 should not have elements that require more than pointer alignment.
|
|
//
|
|
|
|
#define UncheckedUnion2(T1, T2) \
|
|
union UncheckedUnion_##T1##_##T2 \
|
|
{ \
|
|
private: \
|
|
void *aligner; /* Unused field to ensure that the union is properly aligned */ \
|
|
char f##T1[sizeof(T1)]; /* Fields of T1 */ \
|
|
char f##T2[sizeof(T2)]; /* Fields of T2 */ \
|
|
\
|
|
public: \
|
|
void *init##T1() {return f##T1;} \
|
|
void *init##T2() {return f##T2;} \
|
|
void clear() {} \
|
|
\
|
|
const T1 &get##T1() const {return *static_cast<const T1 *>(static_cast<const void *>(f##T1));} \
|
|
T1 &get##T1() {return *static_cast<T1 *>(static_cast<void *>(f##T1));} \
|
|
const T2 &get##T2() const {return *static_cast<const T2 *>(static_cast<const void *>(f##T2));} \
|
|
T2 &get##T2() {return *static_cast<T2 *>(static_cast<void *>(f##T2));} \
|
|
}
|
|
|
|
#define CheckedUnion2DEBUG(T1, T2) \
|
|
class CheckedUnion_##T1##_##T2 \
|
|
{ \
|
|
T1 *p##T1; /* Pointer to T1 (to simplify looking at T1 in a debugger) or nil if none */ \
|
|
T2 *p##T2; /* Pointer to T2 (to simplify looking at T2 in a debugger) or nil if none */ \
|
|
UncheckedUnion2(T1, T2) u; \
|
|
\
|
|
public: \
|
|
CheckedUnion_##T1##_##T2() {p##T1 = 0; p##T2 = 0;} \
|
|
void *init##T1() {p##T1 = &u.get##T1(); p##T2 = 0; return u.init##T1();} \
|
|
void *init##T2() {p##T1 = 0; p##T2 = &u.get##T2(); return u.init##T2();} \
|
|
void clear() {p##T1 = 0; p##T2 = 0;} \
|
|
\
|
|
const T1 &get##T1() const {assert(p##T1); return u.get##T1();} \
|
|
T1 &get##T1() {assert(p##T1); return u.get##T1();} \
|
|
const T2 &get##T2() const {assert(p##T2); return u.get##T2();} \
|
|
T2 &get##T2() {assert(p##T2); return u.get##T2();} \
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
#define CheckedUnion2(T1, T2) CheckedUnion2DEBUG(T1, T2)
|
|
#else
|
|
#define CheckedUnion2(T1, T2) UncheckedUnion2(T1, T2)
|
|
#endif
|
|
|
|
|
|
//
|
|
// CheckedUnion3 is analogous to CheckedUnion2, but with three alternatives.
|
|
//
|
|
|
|
#define UncheckedUnion3(T1, T2, T3) \
|
|
union UncheckedUnion_##T1##_##T2##_##T3 \
|
|
{ \
|
|
private: \
|
|
void *aligner; /* Unused field to ensure that the union is properly aligned */ \
|
|
char f##T1[sizeof(T1)]; /* Fields of T1 */ \
|
|
char f##T2[sizeof(T2)]; /* Fields of T2 */ \
|
|
char f##T3[sizeof(T3)]; /* Fields of T3 */ \
|
|
\
|
|
public: \
|
|
void *init##T1() {return f##T1;} \
|
|
void *init##T2() {return f##T2;} \
|
|
void *init##T3() {return f##T3;} \
|
|
void clear() {} \
|
|
\
|
|
const T1 &get##T1() const {return *static_cast<const T1 *>(static_cast<const void *>(f##T1));} \
|
|
T1 &get##T1() {return *static_cast<T1 *>(static_cast<void *>(f##T1));} \
|
|
const T2 &get##T2() const {return *static_cast<const T2 *>(static_cast<const void *>(f##T2));} \
|
|
T2 &get##T2() {return *static_cast<T2 *>(static_cast<void *>(f##T2));} \
|
|
const T3 &get##T3() const {return *static_cast<const T3 *>(static_cast<const void *>(f##T3));} \
|
|
T3 &get##T3() {return *static_cast<T3 *>(static_cast<void *>(f##T3));} \
|
|
}
|
|
|
|
#define CheckedUnion3DEBUG(T1, T2, T3) \
|
|
class CheckedUnion_##T1##_##T2##_##T3 \
|
|
{ \
|
|
T1 *p##T1; /* Pointer to T1 (to simplify looking at T1 in a debugger) or nil if none */ \
|
|
T2 *p##T2; /* Pointer to T2 (to simplify looking at T2 in a debugger) or nil if none */ \
|
|
T3 *p##T3; /* Pointer to T3 (to simplify looking at T3 in a debugger) or nil if none */ \
|
|
UncheckedUnion3(T1, T2, T3) u; \
|
|
\
|
|
public: \
|
|
CheckedUnion_##T1##_##T2##_##T3() {p##T1 = 0; p##T2 = 0; p##T3 = 0;} \
|
|
void *init##T1() {p##T1 = &u.get##T1(); p##T2 = 0; p##T3 = 0; return u.init##T1();} \
|
|
void *init##T2() {p##T1 = 0; p##T2 = &u.get##T2(); p##T3 = 0; return u.init##T2();} \
|
|
void *init##T3() {p##T1 = 0; p##T2 = 0; p##T3 = &u.get##T3(); return u.init##T3();} \
|
|
void clear() {p##T1 = 0; p##T2 = 0; p##T3 = 0;} \
|
|
\
|
|
const T1 &get##T1() const {assert(p##T1); return u.get##T1();} \
|
|
T1 &get##T1() {assert(p##T1); return u.get##T1();} \
|
|
const T2 &get##T2() const {assert(p##T2); return u.get##T2();} \
|
|
T2 &get##T2() {assert(p##T2); return u.get##T2();} \
|
|
const T3 &get##T3() const {assert(p##T3); return u.get##T3();} \
|
|
T3 &get##T3() {assert(p##T3); return u.get##T3();} \
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
#define CheckedUnion3(T1, T2, T3) CheckedUnion3DEBUG(T1, T2, T3)
|
|
#else
|
|
#define CheckedUnion3(T1, T2, T3) UncheckedUnion3(T1, T2, T3)
|
|
#endif
|
|
|
|
|
|
//
|
|
// CheckedUnion4 is analogous to CheckedUnion2, but with four alternatives.
|
|
//
|
|
|
|
#define UncheckedUnion4(T1, T2, T3, T4) \
|
|
union UncheckedUnion_##T1##_##T2##_##T3##_##T4 \
|
|
{ \
|
|
private: \
|
|
void *aligner; /* Unused field to ensure that the union is properly aligned */ \
|
|
char f##T1[sizeof(T1)]; /* Fields of T1 */ \
|
|
char f##T2[sizeof(T2)]; /* Fields of T2 */ \
|
|
char f##T3[sizeof(T3)]; /* Fields of T3 */ \
|
|
char f##T4[sizeof(T4)]; /* Fields of T4 */ \
|
|
\
|
|
public: \
|
|
void *init##T1() {return f##T1;} \
|
|
void *init##T2() {return f##T2;} \
|
|
void *init##T3() {return f##T3;} \
|
|
void *init##T4() {return f##T4;} \
|
|
void clear() {} \
|
|
\
|
|
const T1 &get##T1() const {return *static_cast<const T1 *>(static_cast<const void *>(f##T1));} \
|
|
T1 &get##T1() {return *static_cast<T1 *>(static_cast<void *>(f##T1));} \
|
|
const T2 &get##T2() const {return *static_cast<const T2 *>(static_cast<const void *>(f##T2));} \
|
|
T2 &get##T2() {return *static_cast<T2 *>(static_cast<void *>(f##T2));} \
|
|
const T3 &get##T3() const {return *static_cast<const T3 *>(static_cast<const void *>(f##T3));} \
|
|
T3 &get##T3() {return *static_cast<T3 *>(static_cast<void *>(f##T3));} \
|
|
const T4 &get##T4() const {return *static_cast<const T4 *>(static_cast<const void *>(f##T4));} \
|
|
T4 &get##T4() {return *static_cast<T4 *>(static_cast<void *>(f##T4));} \
|
|
}
|
|
|
|
#define CheckedUnion4DEBUG(T1, T2, T3, T4) \
|
|
class CheckedUnion_##T1##_##T2##_##T3##_##T4 \
|
|
{ \
|
|
T1 *p##T1; /* Pointer to T1 (to simplify looking at T1 in a debugger) or nil if none */ \
|
|
T2 *p##T2; /* Pointer to T2 (to simplify looking at T2 in a debugger) or nil if none */ \
|
|
T3 *p##T3; /* Pointer to T3 (to simplify looking at T3 in a debugger) or nil if none */ \
|
|
T4 *p##T4; /* Pointer to T4 (to simplify looking at T4 in a debugger) or nil if none */ \
|
|
UncheckedUnion4(T1, T2, T3, T4) u; \
|
|
\
|
|
public: \
|
|
CheckedUnion_##T1##_##T2##_##T3##_##T4() {p##T1 = 0; p##T2 = 0; p##T3 = 0; p##T4 = 0;} \
|
|
void *init##T1() {p##T1 = &u.get##T1(); p##T2 = 0; p##T3 = 0; p##T4 = 0; return u.init##T1();} \
|
|
void *init##T2() {p##T1 = 0; p##T2 = &u.get##T2(); p##T3 = 0; p##T4 = 0; return u.init##T2();} \
|
|
void *init##T3() {p##T1 = 0; p##T2 = 0; p##T3 = &u.get##T3(); p##T4 = 0; return u.init##T3();} \
|
|
void *init##T4() {p##T1 = 0; p##T2 = 0; p##T3 = 0; p##T4 = &u.get##T4(); return u.init##T4();} \
|
|
void clear() {p##T1 = 0; p##T2 = 0; p##T3 = 0; p##T4 = 0;} \
|
|
\
|
|
const T1 &get##T1() const {assert(p##T1); return u.get##T1();} \
|
|
T1 &get##T1() {assert(p##T1); return u.get##T1();} \
|
|
const T2 &get##T2() const {assert(p##T2); return u.get##T2();} \
|
|
T2 &get##T2() {assert(p##T2); return u.get##T2();} \
|
|
const T3 &get##T3() const {assert(p##T3); return u.get##T3();} \
|
|
T3 &get##T3() {assert(p##T3); return u.get##T3();} \
|
|
const T4 &get##T4() const {assert(p##T4); return u.get##T4();} \
|
|
T4 &get##T4() {assert(p##T4); return u.get##T4();} \
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
#define CheckedUnion4(T1, T2, T3, T4) CheckedUnion4DEBUG(T1, T2, T3, T4)
|
|
#else
|
|
#define CheckedUnion4(T1, T2, T3, T4) UncheckedUnion4(T1, T2, T3, T4)
|
|
#endif
|
|
|
|
#endif
|