]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_utilities/lib/adornments.h
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / adornments.h
diff --git a/OSX/libsecurity_utilities/lib/adornments.h b/OSX/libsecurity_utilities/lib/adornments.h
new file mode 100644 (file)
index 0000000..bd5dccf
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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