]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/adornments.h
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / adornments.h
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
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(); }
110 unsigned int size() const { return mAdornments ? (unsigned int)mAdornments->size() : 0; }
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