namespace crucible {
using namespace std;
- /// Storage for objects with unique names
+ /// A thread-safe container for RAII of shared resources with unique names.
template <class Return, class... Arguments>
class NamedPtr {
public:
+ /// The name in "NamedPtr"
using Key = tuple<Arguments...>;
+ /// A shared pointer to the named object with ownership
+ /// tracking that erases the object's stored name when
+ /// the last shared pointer is destroyed.
using Ptr = shared_ptr<Return>;
+ /// A function that translates a name into a shared pointer to an object.
using Func = function<Ptr(Arguments...)>;
private:
struct Value;
mutex m_mutex;
};
using MapPtr = shared_ptr<MapRep>;
+ /// Container for Return pointers. Destructor removes entry from map.
struct Value {
Ptr m_ret_ptr;
MapPtr m_map_rep;
void func(Func f);
Ptr operator()(Arguments... args);
+
Ptr insert(const Ptr &r, Arguments... args);
};
+ /// Construct NamedPtr map and define a function to turn a name into a pointer.
template <class Return, class... Arguments>
NamedPtr<Return, Arguments...>::NamedPtr(Func f) :
m_fn(f)
{
}
+ /// Construct a Value wrapper: the value to store, the argument key to store the value under,
+ /// and a pointer to the map. Everything needed to remove the key from the map when the
+ /// last NamedPtr is deleted. NamedPtr then releases its own pointer to the value, which
+ /// may or may not trigger deletion there.
template <class Return, class... Arguments>
NamedPtr<Return, Arguments...>::Value::Value(Ptr&& ret_ptr, const Key &key, const MapPtr &map_rep) :
m_ret_ptr(ret_ptr),
{
}
+ /// Destroy a Value wrapper: remove a dead Key from the map, then let the member destructors
+ /// do the rest. The Key might be in the map and not dead, so leave it alone in that case.
template <class Return, class... Arguments>
NamedPtr<Return, Arguments...>::Value::~Value()
{
}
}
+ /// Find a Return by key and fetch a strong Return pointer.
+ /// Ignore Keys that have expired weak pointers.
template <class Return, class... Arguments>
typename NamedPtr<Return, Arguments...>::Ptr
NamedPtr<Return, Arguments...>::lookup_item(const Key &k)
return Ptr();
}
+ /// Insert the Return value of calling Func(Arguments...).
+ /// If the value already exists in the map, return the existing value.
+ /// If another thread is already running Func(Arguments...) then this thread
+ /// will block until the other thread finishes inserting the Return in the
+ /// map, and both threads will return the same Return value.
template <class Return, class... Arguments>
typename NamedPtr<Return, Arguments...>::Ptr
NamedPtr<Return, Arguments...>::insert_item(Func fn, Arguments... args)
// Release map lock, then key lock
}
+ /// (Re)define a function to turn a name into a pointer.
template <class Return, class... Arguments>
void
NamedPtr<Return, Arguments...>::func(Func func)
m_fn = func;
}
+ /// Convert a name into a pointer using the configured function.
template<class Return, class... Arguments>
typename NamedPtr<Return, Arguments...>::Ptr
NamedPtr<Return, Arguments...>::operator()(Arguments... args)
return insert_item(m_fn, args...);
}
+ /// Insert a pointer that has already been created under the
+ /// given name. Useful for inserting a pointer to a derived
+ /// class when the name doesn't contain all of the information
+ /// required for the object, or when the Return is already known by
+ /// some cheaper method than calling the function.
template<class Return, class... Arguments>
typename NamedPtr<Return, Arguments...>::Ptr
NamedPtr<Return, Arguments...>::insert(const Ptr &r, Arguments... args)
}
-#endif // NAMEDPTR_H
+#endif // CRUCIBLE_NAMEDPTR_H