]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2004 Apple Computer, 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 | ||
60 | namespace Security { | |
61 | ||
62 | class Adornable; | |
63 | ||
64 | ||
65 | // | |
66 | // An Adornment is data "hung" (stored with) an Adornable. | |
67 | // | |
68 | class Adornment { | |
69 | friend class Adornable; | |
70 | public: | |
71 | typedef const void *Key; | |
72 | ||
73 | virtual ~Adornment() = 0; | |
74 | ||
75 | protected: | |
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 | // | |
86 | class Adornable { | |
87 | public: | |
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(); } | |
427c49bc | 110 | unsigned int size() const { return mAdornments ? (unsigned int)mAdornments->size() : 0; } |
b1ab9ed8 A |
111 | void clearAdornments(); |
112 | ||
113 | public: | |
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 | ||
124 | private: | |
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 | ||
134 | private: | |
135 | typedef std::map<Key, Adornment *> AdornmentMap; | |
136 | AdornmentMap *mAdornments; | |
137 | }; | |
138 | ||
139 | ||
140 | // | |
141 | // Out-of-line implementations | |
142 | // | |
143 | template <class T> T & | |
144 | Adornable::adornment(Key key) | |
145 | { | |
146 | Adornment *&slot = adornmentSlot(key); | |
147 | if (!slot) | |
148 | slot = new T; | |
149 | return dynamic_cast<T &>(*slot); | |
150 | } | |
151 | ||
152 | template <class T, class Arg1> T & | |
153 | Adornable::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 | ||
161 | template <class T, class Arg1, class Arg2> T & | |
162 | Adornable::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 | ||
170 | template <class T, class Arg1, class Arg2, class Arg3> T & | |
171 | Adornable::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 | ||
179 | template <class T> | |
180 | T &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 | ||
189 | template <class T, class Arg1> | |
190 | T &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 |