#pragma once /* * Copyright (c) 2016 MariaDB Corporation Ab * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file and at www.mariadb.com/bsl11. * * Change Date: 2020-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2 or later of the General * Public License. */ #include #include #include namespace maxscale { /** * @class CloserTraits utils.hh * * A traits class used by Closer. To be specialized for all types that are * used with Closer. */ template struct CloserTraits { /** * Closes/frees/destroys a resource. * * @param t Close the resource *if* it has not been closed already. */ static void close_if(T t); /** * Resets a reference to a resource. After the call, the value of t should * be such that @c close_if can recognize that the reference already has * been closed. * * @param t Reference to a resource. */ static void reset(T& t); }; /** * @class Closer utils.hh * * The template class Closer is a class that is intended to be used * for ensuring that a C style resource is released at the end of a * scoped block, irrespective of how that block is exited (by reaching * the end of it, or by a return or exception in the middle of it). * * Closer performs the actual resource releasing using CloserTraits * that need to be specialized for every type of resource to be managed. * * Example: * @code * void f() * { * FILE* pFile = fopen(...); * * if (pFile) * { * Closer file(pFile); * * // Use pFile, call functions that potentually may throw * } * } * @endcode * * Without @c Closer all code would have to be placed within try/catch * blocks, which quickly becomes unwieldy as the number of managed * resources grows. */ template class Closer { public: /** * Creates the closer and stores the provided resourece. Note that * the constructor assumes that the resource exists already. * * @param resource The resource whose closing is to be ensured. */ Closer(T resource) : m_resource(resource) { } /** * Destroys the closer and releases the resource. */ ~Closer() { CloserTraits::close_if(m_resource); } /** * Returns the original resource. Note that the ownership of the * resource remains with the closer. * * @return The resource that was provided in the constructor. */ T get() const { return m_resource; } /** * Resets the closer, that is, releases the resource. */ void reset() { CloserTraits::close_if(m_resource); CloserTraits::reset(m_resource); } /** * Resets the closer, that is, releases the resource and assigns a * new resource to it. */ void reset(T resource) { CloserTraits::close_if(m_resource); m_resource = resource; } /** * Returns the original resource together with its ownership. That is, * after this call the responsibility for releasing the resource belongs * to the caller. * * @return The resource that was provided in the constructor. */ T release() { T resource = m_resource; CloserTraits::reset(m_resource); return resource; } private: Closer(const Closer&); Closer& operator = (const Closer&); private: T m_resource; }; } namespace maxscale { /** * @class CloserTraits utils.hh * * Specialization of @c CloserTraits for @c FILE*. */ template<> struct CloserTraits { static void close_if(FILE* pFile) { if (pFile) { fclose(pFile); } } static void reset(FILE*& pFile) { pFile = NULL; } }; /* Helper type for Registry. Must be specialized for each EntryType. The types * listed below are just examples and will not compile. */ template struct RegistryTraits { typedef int id_type; typedef EntryType* entry_type; static id_type get_id(entry_type entry) { static_assert(sizeof(EntryType) != sizeof(EntryType), "get_id() and the" " surrounding struct must be specialized for every EntryType!"); return 0; } static entry_type null_entry() { return NULL; } }; /** * Class Registy wraps a map, allowing only a few operations on it. The intended * use is simple registries, such as the session registry in Worker. The owner * can expose a reference to this class without exposing all the methods the * underlying container implements. When instantiating with a new EntryType, the * traits-class RegistryTraits should be specialized for the new type as well. */ template class Registry { Registry(const Registry&); Registry& operator = (const Registry&); public: typedef typename RegistryTraits::id_type id_type; typedef typename RegistryTraits::entry_type entry_type; Registry() { } /** * Find an entry in the registry. * * @param id Entry key * @return The found entry, or NULL if not found */ entry_type lookup(id_type id) const { entry_type rval = RegistryTraits::null_entry(); typename ContainerType::const_iterator iter = m_registry.find(id); if (iter != m_registry.end()) { rval = iter->second; } return rval; } /** * Add an entry to the registry. * * @param entry The entry to add * @return True if successful, false if id was already in */ bool add(entry_type entry) { id_type id = RegistryTraits::get_id(entry); typename ContainerType::value_type new_value(id, entry); return m_registry.insert(new_value).second; } /** * Remove an entry from the registry. * * @param id Entry id * @return True if an entry was removed, false if not found */ bool remove(id_type id) { entry_type rval = lookup(id); if (rval) { m_registry.erase(id); } return rval; } private: typedef typename std::tr1::unordered_map ContainerType; ContainerType m_registry; }; }