#ifndef STATEPATTERNPTR_H_INCLUDED #define STATEPATTERNPTR_H_INCLUDED // static const char StatePatternPtr_h_RcsId[] = "$Id: StatePatternPtr.h,v 1.5 2003/01/16 04:54:25 neutron Exp $"; // // StatePatternPtr.h: // A template implementation of the State Design Pattern. // // Design: // This class contains a union that contains either a pointer to // type A, or a pointer to type B. It distinguishes between them // by setting the LSB on type B. // // C O N F I D E N T I A L // // Copyright 2002 Hewlett-Packard // // No part of this file may be reproduced, stored in a retrieval system, // or transmitted in any form or by any means--electronic, mechanical, // photocopying, recording, or otherwise--without prior written permission // of Hewlett Packard. // template class StatePatternPtr { protected: StatePatternPtr(); StatePatternPtr(const StatePatternPtr &); StatePatternPtr &operator=(const StatePatternPtr &); ~StatePatternPtr(); bool IsA() const; // Do we point to an A? bool IsB() const; // Do we point to a B? A *GetA() const; // Return A *, assuming we have one. B *GetB() const; // Return B *, assuming we have one. void SetA(A *); // Point to this A from now on. void SetB(B *); // Point to this B from now on. private: // If the LSB is clear, it's an A, otherwise, it's a B. // Storing and retrieving an A is faster, so choose A & B wisely. // Note that we are *always* pointing to something--never NULL. union { A *a; B *b; }; // Wow! An anonymous union! }; // Default constructor template inline StatePatternPtr::StatePatternPtr() : a(new A) { } // Copy constructor // Initialize a so we don't to delete the uninitialized a. template StatePatternPtr::StatePatternPtr(const StatePatternPtr &from) : a(0) { if (from.IsA()) SetA(new A(*from.GetA())); else SetB(new B(*from.GetB())); } // Assignment operator template StatePatternPtr &StatePatternPtr::operator=( const StatePatternPtr &from) { if (this == &from) // Self-assignment? return *this; // We are out of here! if (from.IsA()) SetA(new A(*from.GetA())); else SetB(new B(*from.GetB())); return *this; } #include // Destructor template StatePatternPtr::~StatePatternPtr() { assert(a); /// Must never be NULL. if (IsA()) delete GetA(); else delete GetB(); } // Do we point to an A? template inline bool StatePatternPtr::IsA() const { return !IsB(); } // Do we point to a B? template inline bool StatePatternPtr::IsB() const { return long(a) & 01; } // Return an A *, assuming that we point to one. template inline A *StatePatternPtr::GetA() const { assert(IsA()); return a; } // Return a B *, assuming that we point to one. template inline B *StatePatternPtr::GetB() const { assert(IsB()); return reinterpret_cast(long(b) & ~01); } // Point to this A from now on. template void StatePatternPtr::SetA(A *new_a) { assert(new_a); // Mustn't be NULL assert(!(long(new_a) & 01)); // Can't have low bit set if (IsA()) delete GetA(); else delete GetB(); a = new_a; } // Point to this B from now on. template void StatePatternPtr::SetB(B *new_b) { assert(new_b); // Mustn't be NULL assert(!(long(new_b) & 01)); // Can't have low bit set if (IsA()) delete GetA(); else delete GetB(); b = reinterpret_cast(long(new_b) | 01); } #endif /* STATEPATTERNPTR_H_INCLUDED */