Add Closer, partial RAII class

Closer is a template using which C-style resources can be managed
in a C++ context where exceptions can occur. By placing a C resource
in a Closer instance, it is certain the resource will be freed when
the closing scope is exited irrespective of whether that occurs due
to the normal control flow, due to a return statement or an exception
having been thrown.

To be used with Closer, the CloserTraits template must be specialized
for the type in question. With this change specializations are provided
for FILE*, json_t*, pcre_code* and pcre2_match_data*.
This commit is contained in:
Johan Wikman 2016-12-29 14:43:53 +02:00
parent 482fbe6400
commit 0b4c379539
4 changed files with 306 additions and 0 deletions

View File

@ -0,0 +1,16 @@
#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/bsl.
*
* Change Date: 2019-07-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 <maxscale/cdefs.h>
#include <jansson.h>

View File

@ -0,0 +1,44 @@
#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/bsl.
*
* Change Date: 2019-07-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 <maxscale/cppdefs.hh>
#include <maxscale/jansson.h>
#include <maxscale/utils.hh>
namespace maxscale
{
/**
* @class CloserTraits<json_t*> jansson.hh <maxscale/jansson.hh>
*
* Specialization of @c CloserTraits for @c json_t*.
*/
template<>
struct CloserTraits<json_t*>
{
static void close_if(json_t* pJson)
{
if (pJson)
{
json_decref(pJson);
}
}
static void reset(json_t*& pJson)
{
pJson = NULL;
}
};
}

66
include/maxscale/pcre2.hh Normal file
View File

@ -0,0 +1,66 @@
#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/bsl.
*
* Change Date: 2019-07-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 <maxscale/cppdefs.hh>
#include <maxscale/pcre2.h>
#include <maxscale/utils.hh>
namespace maxscale
{
/**
* @class CloserTraits<pcre2_code*> pcre2.hh <maxscale/pcre2.hh>
*
* Specialization of @c CloserTraits for @c pcre2_code*.
*/
template<>
struct CloserTraits<pcre2_code*>
{
static void close_if(pcre2_code* pCode)
{
if (pCode)
{
pcre2_code_free(pCode);
}
}
static void reset(pcre2_code*& pCode)
{
pCode = NULL;
}
};
/**
* @class CloserTraits<pcre2_match_data*> pcre2.hh <maxscale/pcre2.hh>
*
* Specialization of @c CloserTraits for @c pcre2_match_data*.
*/
template<>
struct CloserTraits<pcre2_match_data*>
{
static void close_if(pcre2_match_data* pData)
{
if (pData)
{
pcre2_match_data_free(pData);
}
}
static void reset(pcre2_match_data*& pData)
{
pData = NULL;
}
};
}

180
include/maxscale/utils.hh Normal file
View File

@ -0,0 +1,180 @@
#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/bsl.
*
* Change Date: 2019-07-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 <maxscale/cppdefs.hh>
#include <stdio.h>
namespace maxscale
{
/**
* @class CloserTraits utils.hh <maxscale/utils.hh>
*
* A traits class used by Closer. To be specialized for all types that are
* used with Closer.
*/
template<class T>
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 <maxscale/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*> 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 T>
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<T>::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<T>::close_if(m_resource);
CloserTraits<T>::reset(m_resource);
}
/**
* Resets the closer, that is, releases the resource and assigns a
* new resource to it.
*/
void reset(T resource)
{
CloserTraits<T>::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<T>::reset(m_resource);
return resource;
}
private:
Closer(const Closer&);
Closer& operator = (const Closer&);
private:
T m_resource;
};
}
namespace maxscale
{
/**
* @class CloserTraits<FILE*> utils.hh <maxscale/utils.hh>
*
* Specialization of @c CloserTraits for @c FILE*.
*/
template<>
struct CloserTraits<FILE*>
{
static void close_if(FILE* pFile)
{
if (pFile)
{
fclose(pFile);
}
}
static void reset(FILE*& pFile)
{
pFile = NULL;
}
};
}