1/* 2 * Copyright (c) 2004,2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// adornment - generic attached-storage facility 27// 28// Adornments are dynamic objects (subclasses of class Adornment) that can 29// be "attached" ("hung off") any object derived from Adornable. Any number 30// of Adornments can be attached to one object using different unique keys 31// (of type void *). 32// 33// Adornments can be used by a single caller to remember data "with" an Adornable 34// object. Multiple, cooperating callers can share an Adornment as long as they 35// agree on the Key. 36// 37// Memory management: All Adornments must be dynamically allocated, and will be 38// deleted when their Adornable dies. Once attached, their memory is owned by the 39// Adornable (NOT the caller). Do not get fancy with an Adornment's memory; 40// trying to share one Adornment instance between Adornables or slots is bad. 41// If you need shared storage, use a RefPointer attachment. 42// 43// Your Adornment's destructor will be called when its Adornable dies, or when 44// its slot is replaced (whichever happens sooner). So you CAN get notification 45// of an object's death by attaching an Adornment with a unique key and putting 46// code in its destructor. 47// 48// It is fairly popular for a subclass of Adornable to rename its getAdornment and 49// adornment methods as operator [], but we won't make that decision for you 50// at this level. 51// 52#ifndef _H_ADORNMENTS 53#define _H_ADORNMENTS 54 55#include <security_utilities/utilities.h> 56#include <security_utilities/threading.h> 57#include <map> 58 59 60namespace Security { 61 62class Adornable; 63 64 65// 66// An Adornment is data "hung" (stored with) an Adornable. 67// 68class Adornment { 69 friend class Adornable; 70public: 71 typedef const void *Key; 72 73 virtual ~Adornment() = 0; 74 75protected: 76 Adornment() { } 77}; 78 79 80// 81// An Adornable can carry Adornments, potentially a different one for each 82// Key. We provide both a raw interface (dealing in Adornment subclasses), 83// and an attachment form that just pretends that the Adornable has extra, 84// dynamically allocated members filed under various keys. 85// 86class Adornable { 87public: 88 Adornable() : mAdornments(NULL) { } 89 ~Adornable(); 90 91 // adornment keys (slots) 92 typedef Adornment::Key Key; 93 94 // primitive access, raw form 95 Adornment *getAdornment(Key key) const; // NULL if not present 96 void setAdornment(Key key, Adornment *ad); // use NULL to delete 97 Adornment *swapAdornment(Key key, Adornment *ad); // rotate in/out 98 99 // typed primitive access. Ad must be a unique subclass of Adornment 100 template <class Ad> 101 Ad *getAdornment(Key key) const 102 { return safe_cast<Ad *>(getAdornment(key)); } 103 104 template <class Ad> 105 Ad *swapAdornment(Key key, Ad *ad) 106 { return safe_cast<Ad *>(swapAdornment(key, ad)); } 107 108 // inquiries for the Adornable itself 109 bool empty() const { return !mAdornments || mAdornments->empty(); } 110 unsigned int size() const { return mAdornments ? (unsigned int)mAdornments->size() : 0; } 111 void clearAdornments(); 112 113public: 114 // Adornment ref interface. Will return an (optionally constructed) Adornment &. 115 template <class T> T &adornment(Key key); 116 template <class T, class Arg1> T &adornment(Key key, Arg1 &arg1); 117 template <class T, class Arg1, class Arg2> T &adornment(Key key, Arg1 &arg1, Arg2 &arg2); 118 template <class T, class Arg1, class Arg2, class Arg3> T &adornment(Key key, Arg1 &arg1, Arg2 &arg2, Arg3 &arg3); 119 120 // attached-value interface 121 template <class T> T &attachment(Key key); 122 template <class T, class Arg1> T &attachment(Key key, Arg1 arg1); 123 124private: 125 Adornment *&adornmentSlot(Key key); 126 127 template <class Type> 128 struct Attachment : public Adornment { 129 Attachment() { } 130 template <class Arg1> Attachment(Arg1 arg) : mValue(arg) { } 131 Type mValue; 132 }; 133 134private: 135 typedef std::map<Key, Adornment *> AdornmentMap; 136 AdornmentMap *mAdornments; 137}; 138 139 140// 141// Out-of-line implementations 142// 143template <class T> T & 144Adornable::adornment(Key key) 145{ 146 Adornment *&slot = adornmentSlot(key); 147 if (!slot) 148 slot = new T; 149 return dynamic_cast<T &>(*slot); 150} 151 152template <class T, class Arg1> T & 153Adornable::adornment(Key key, Arg1 &arg1) 154{ 155 Adornment *&slot = adornmentSlot(key); 156 if (!slot) 157 slot = new T(arg1); 158 return dynamic_cast<T &>(*slot); 159} 160 161template <class T, class Arg1, class Arg2> T & 162Adornable::adornment(Key key, Arg1 &arg1, Arg2 &arg2) 163{ 164 Adornment *&slot = adornmentSlot(key); 165 if (!slot) 166 slot = new T(arg1, arg2); 167 return dynamic_cast<T &>(*slot); 168} 169 170template <class T, class Arg1, class Arg2, class Arg3> T & 171Adornable::adornment(Key key, Arg1 &arg1, Arg2 &arg2, Arg3 &arg3) 172{ 173 Adornment *&slot = adornmentSlot(key); 174 if (!slot) 175 slot = new T(arg1, arg2, arg3); 176 return dynamic_cast<T &>(*slot); 177} 178 179template <class T> 180T &Adornable::attachment(Key key) 181{ 182 typedef Attachment<T> Attach; 183 Adornment *&slot = adornmentSlot(key); 184 if (!slot) 185 slot = new Attach; 186 return safe_cast<Attach *>(slot)->mValue; 187} 188 189template <class T, class Arg1> 190T &Adornable::attachment(Key key, Arg1 arg1) 191{ 192 typedef Attachment<T> Attach; 193 Adornment *&slot = adornmentSlot(key); 194 if (!slot) 195 slot = new Attach(arg1); 196 return safe_cast<Attach *>(slot)->mValue; 197} 198 199 200} // end namespace Security 201 202#endif //_H_ADORNMENTS 203