blob: 0d7bc8d992193f4b8c2328aff9666574cf15960a [file] [log] [blame]
//===-- CleanUp.h -----------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_CleanUp_h_
#define liblldb_CleanUp_h_
#include "lldb/lldb-public.h"
#include <functional>
namespace lldb_utility {
//----------------------------------------------------------------------
// Templated class that guarantees that a cleanup callback function will
// be called. The cleanup function will be called once under the
// following conditions:
// - when the object goes out of scope
// - when the user explicitly calls clean.
// - the current value will be cleaned up when a new value is set using
// set(T value) as long as the current value hasn't already been cleaned.
//
// This class is designed to be used with simple types for type T (like
// file descriptors, opaque handles, pointers, etc). If more complex
// type T objects are desired, we need to probably specialize this class
// to take "const T&" for all input T parameters. Yet if a type T is
// complex already it might be better to build the cleanup functionality
// into T.
//
// The cleanup function must take one argument that is of type T.
// The calback function return type is R. The return value is currently
// needed for "CallbackType". If there is an easy way to get around the
// need for the return value we can change this class.
//
// The two template parameters are:
// T - The variable type of value that will be stored and used as the
// sole argument for the cleanup callback.
// R - The return type for the cleanup function.
//
// EXAMPLES
// // Use with file handles that get opened where you want to close
// // them. Below we use "int open(const char *path, int oflag, ...)"
// // which returns an integer file descriptor. -1 is the invalid file
// // descriptor so to make an object that will call "int close(int fd)"
// // automatically we can use:
//
// CleanUp <int, int> fd(open("/tmp/a.txt", O_RDONLY, 0), -1, close);
//
// // malloc/free example
// CleanUp <void *, void> malloced_bytes(malloc(32), NULL, free);
//----------------------------------------------------------------------
template <typename T, typename R = void> class CleanUp {
public:
typedef T value_type;
typedef std::function<R(value_type)> CallbackType;
//----------------------------------------------------------------------
// Constructor that sets the current value only. No values are
// considered to be invalid and the cleanup function will be called
// regardless of the value of m_current_value.
//----------------------------------------------------------------------
CleanUp(value_type value, CallbackType callback)
: m_current_value(value), m_invalid_value(), m_callback(callback),
m_callback_called(false), m_invalid_value_is_valid(false) {}
//----------------------------------------------------------------------
// Constructor that sets the current value and also the invalid value.
// The cleanup function will be called on "m_value" as long as it isn't
// equal to "m_invalid_value".
//----------------------------------------------------------------------
CleanUp(value_type value, value_type invalid, CallbackType callback)
: m_current_value(value), m_invalid_value(invalid), m_callback(callback),
m_callback_called(false), m_invalid_value_is_valid(true) {}
//----------------------------------------------------------------------
// Automatically cleanup when this object goes out of scope.
//----------------------------------------------------------------------
~CleanUp() { clean(); }
//----------------------------------------------------------------------
// Access the value stored in this class
//----------------------------------------------------------------------
value_type get() { return m_current_value; }
//----------------------------------------------------------------------
// Access the value stored in this class
//----------------------------------------------------------------------
const value_type get() const { return m_current_value; }
//----------------------------------------------------------------------
// Reset the owned value to "value". If a current value is valid and
// the cleanup callback hasn't been called, the previous value will
// be cleaned up (see void CleanUp::clean()).
//----------------------------------------------------------------------
void set(const value_type value) {
// Cleanup the current value if needed
clean();
// Now set the new value and mark our callback as not called
m_callback_called = false;
m_current_value = value;
}
//----------------------------------------------------------------------
// Checks is "m_current_value" is valid. The value is considered valid
// no invalid value was supplied during construction of this object or
// if an invalid value was supplied and "m_current_value" is not equal
// to "m_invalid_value".
//
// Returns true if "m_current_value" is valid, false otherwise.
//----------------------------------------------------------------------
bool is_valid() const {
if (m_invalid_value_is_valid)
return m_current_value != m_invalid_value;
return true;
}
//----------------------------------------------------------------------
// This function will call the cleanup callback provided in the
// constructor one time if the value is considered valid (See is_valid()).
// This function sets m_callback_called to true so we don't call the
// cleanup callback multiple times on the same value.
//----------------------------------------------------------------------
void clean() {
if (m_callback && !m_callback_called) {
m_callback_called = true;
if (is_valid())
m_callback(m_current_value);
}
}
//----------------------------------------------------------------------
// Cancels the cleanup that would have been called on "m_current_value"
// if it was valid. This function can be used to release the value
// contained in this object so ownership can be transferred to the caller.
//----------------------------------------------------------------------
value_type release() {
m_callback_called = true;
return m_current_value;
}
private:
value_type m_current_value;
const value_type m_invalid_value;
CallbackType m_callback;
bool m_callback_called;
bool m_invalid_value_is_valid;
// Outlaw default constructor, copy constructor and the assignment operator
DISALLOW_COPY_AND_ASSIGN(CleanUp);
};
template <typename T, typename R, typename A0> class CleanUp2 {
public:
typedef T value_type;
typedef std::function<R(value_type, A0)> CallbackType;
//----------------------------------------------------------------------
// Constructor that sets the current value only. No values are
// considered to be invalid and the cleanup function will be called
// regardless of the value of m_current_value.
//----------------------------------------------------------------------
CleanUp2(value_type value, CallbackType callback, A0 arg)
: m_current_value(value), m_invalid_value(), m_callback(callback),
m_callback_called(false), m_invalid_value_is_valid(false),
m_argument(arg) {}
//----------------------------------------------------------------------
// Constructor that sets the current value and also the invalid value.
// The cleanup function will be called on "m_value" as long as it isn't
// equal to "m_invalid_value".
//----------------------------------------------------------------------
CleanUp2(value_type value, value_type invalid, CallbackType callback, A0 arg)
: m_current_value(value), m_invalid_value(invalid), m_callback(callback),
m_callback_called(false), m_invalid_value_is_valid(true),
m_argument(arg) {}
//----------------------------------------------------------------------
// Automatically cleanup when this object goes out of scope.
//----------------------------------------------------------------------
~CleanUp2() { clean(); }
//----------------------------------------------------------------------
// Access the value stored in this class
//----------------------------------------------------------------------
value_type get() { return m_current_value; }
//----------------------------------------------------------------------
// Access the value stored in this class
//----------------------------------------------------------------------
const value_type get() const { return m_current_value; }
//----------------------------------------------------------------------
// Reset the owned value to "value". If a current value is valid and
// the cleanup callback hasn't been called, the previous value will
// be cleaned up (see void CleanUp::clean()).
//----------------------------------------------------------------------
void set(const value_type value) {
// Cleanup the current value if needed
clean();
// Now set the new value and mark our callback as not called
m_callback_called = false;
m_current_value = value;
}
//----------------------------------------------------------------------
// Checks is "m_current_value" is valid. The value is considered valid
// no invalid value was supplied during construction of this object or
// if an invalid value was supplied and "m_current_value" is not equal
// to "m_invalid_value".
//
// Returns true if "m_current_value" is valid, false otherwise.
//----------------------------------------------------------------------
bool is_valid() const {
if (m_invalid_value_is_valid)
return m_current_value != m_invalid_value;
return true;
}
//----------------------------------------------------------------------
// This function will call the cleanup callback provided in the
// constructor one time if the value is considered valid (See is_valid()).
// This function sets m_callback_called to true so we don't call the
// cleanup callback multiple times on the same value.
//----------------------------------------------------------------------
void clean() {
if (m_callback && !m_callback_called) {
m_callback_called = true;
if (is_valid())
m_callback(m_current_value, m_argument);
}
}
//----------------------------------------------------------------------
// Cancels the cleanup that would have been called on "m_current_value"
// if it was valid. This function can be used to release the value
// contained in this object so ownership can be transferred to the caller.
//----------------------------------------------------------------------
value_type release() {
m_callback_called = true;
return m_current_value;
}
private:
value_type m_current_value;
const value_type m_invalid_value;
CallbackType m_callback;
bool m_callback_called;
bool m_invalid_value_is_valid;
A0 m_argument;
// Outlaw default constructor, copy constructor and the assignment operator
DISALLOW_COPY_AND_ASSIGN(CleanUp2);
};
} // namespace lldb_utility
#endif // #ifndef liblldb_CleanUp_h_