/* * Copyright (c) 2004,2011-2012,2014 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // // adornment - generic attached-storage facility // // Adornments are dynamic objects (subclasses of class Adornment) that can // be "attached" ("hung off") any object derived from Adornable. Any number // of Adornments can be attached to one object using different unique keys // (of type void *). // // Adornments can be used by a single caller to remember data "with" an Adornable // object. Multiple, cooperating callers can share an Adornment as long as they // agree on the Key. // // Memory management: All Adornments must be dynamically allocated, and will be // deleted when their Adornable dies. Once attached, their memory is owned by the // Adornable (NOT the caller). Do not get fancy with an Adornment's memory; // trying to share one Adornment instance between Adornables or slots is bad. // If you need shared storage, use a RefPointer attachment. // // Your Adornment's destructor will be called when its Adornable dies, or when // its slot is replaced (whichever happens sooner). So you CAN get notification // of an object's death by attaching an Adornment with a unique key and putting // code in its destructor. // // It is fairly popular for a subclass of Adornable to rename its getAdornment and // adornment methods as operator [], but we won't make that decision for you // at this level. // #ifndef _H_ADORNMENTS #define _H_ADORNMENTS #include <security_utilities/utilities.h> #include <security_utilities/threading.h> #include <map> namespace Security { class Adornable; // // An Adornment is data "hung" (stored with) an Adornable. // class Adornment { friend class Adornable; public: typedef const void *Key; virtual ~Adornment() = 0; protected: Adornment() { } }; // // An Adornable can carry Adornments, potentially a different one for each // Key. We provide both a raw interface (dealing in Adornment subclasses), // and an attachment form that just pretends that the Adornable has extra, // dynamically allocated members filed under various keys. // class Adornable { public: Adornable() : mAdornments(NULL) { } ~Adornable(); // adornment keys (slots) typedef Adornment::Key Key; // primitive access, raw form Adornment *getAdornment(Key key) const; // NULL if not present void setAdornment(Key key, Adornment *ad); // use NULL to delete Adornment *swapAdornment(Key key, Adornment *ad); // rotate in/out // typed primitive access. Ad must be a unique subclass of Adornment template <class Ad> Ad *getAdornment(Key key) const { return safe_cast<Ad *>(getAdornment(key)); } template <class Ad> Ad *swapAdornment(Key key, Ad *ad) { return safe_cast<Ad *>(swapAdornment(key, ad)); } // inquiries for the Adornable itself bool empty() const { return !mAdornments || mAdornments->empty(); } unsigned int size() const { return mAdornments ? (unsigned int)mAdornments->size() : 0; } void clearAdornments(); public: // Adornment ref interface. Will return an (optionally constructed) Adornment &. template <class T> T &adornment(Key key); template <class T, class Arg1> T &adornment(Key key, Arg1 &arg1); template <class T, class Arg1, class Arg2> T &adornment(Key key, Arg1 &arg1, Arg2 &arg2); template <class T, class Arg1, class Arg2, class Arg3> T &adornment(Key key, Arg1 &arg1, Arg2 &arg2, Arg3 &arg3); // attached-value interface template <class T> T &attachment(Key key); template <class T, class Arg1> T &attachment(Key key, Arg1 arg1); private: Adornment *&adornmentSlot(Key key); template <class Type> struct Attachment : public Adornment { Attachment() { } template <class Arg1> Attachment(Arg1 arg) : mValue(arg) { } Type mValue; }; private: typedef std::map<Key, Adornment *> AdornmentMap; AdornmentMap *mAdornments; }; // // Out-of-line implementations // template <class T> T & Adornable::adornment(Key key) { Adornment *&slot = adornmentSlot(key); if (!slot) slot = new T; return dynamic_cast<T &>(*slot); } template <class T, class Arg1> T & Adornable::adornment(Key key, Arg1 &arg1) { Adornment *&slot = adornmentSlot(key); if (!slot) slot = new T(arg1); return dynamic_cast<T &>(*slot); } template <class T, class Arg1, class Arg2> T & Adornable::adornment(Key key, Arg1 &arg1, Arg2 &arg2) { Adornment *&slot = adornmentSlot(key); if (!slot) slot = new T(arg1, arg2); return dynamic_cast<T &>(*slot); } template <class T, class Arg1, class Arg2, class Arg3> T & Adornable::adornment(Key key, Arg1 &arg1, Arg2 &arg2, Arg3 &arg3) { Adornment *&slot = adornmentSlot(key); if (!slot) slot = new T(arg1, arg2, arg3); return dynamic_cast<T &>(*slot); } template <class T> T &Adornable::attachment(Key key) { typedef Attachment<T> Attach; Adornment *&slot = adornmentSlot(key); if (!slot) slot = new Attach; return safe_cast<Attach *>(slot)->mValue; } template <class T, class Arg1> T &Adornable::attachment(Key key, Arg1 arg1) { typedef Attachment<T> Attach; Adornment *&slot = adornmentSlot(key); if (!slot) slot = new Attach(arg1); return safe_cast<Attach *>(slot)->mValue; } } // end namespace Security #endif //_H_ADORNMENTS