You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

73 lines
2.2 KiB

/**
* Copyright (c) 2018 Niklas Rosenstein
* MIT licensed.
*
* @description This header provides an interface for creating context
* managers in C++ similar to what you have in Python.
*/
#pragma once
#include <functional>
#include <vector>
namespace niklasrosenstein {
/* Base class for context managers. A context manager can only be moved and
* not copied. It will call a function when it is destroyed (be careful
* about closure scope being destroyed when returned from a function). */
class ctx_manager {
friend class exit_stack;
std::function<void()> _func;
public:
ctx_manager() : _func() {}
ctx_manager(ctx_manager const& other) = delete;
ctx_manager(ctx_manager&& other) : _func(std::move(other._func)) { other._func = {}; }
ctx_manager(std::function<void()>&& f) : _func(std::move(f)) {}
ctx_manager(std::function<void()> const& f) : _func(f) {}
~ctx_manager() { if (_func) _func(); }
ctx_manager& operator = (ctx_manager const& other) = delete;
ctx_manager& operator = (ctx_manager&& other) {
_func = std::move(other._func);
other._func = {};
return *this;
}
operator bool () const { return (bool) _func; }
};
/* Represents a stack of functions that will be called when the
* exit_stack is destroyed. */
struct exit_stack {
std::vector<std::function<void()>> callbacks;
inline exit_stack() {}
inline exit_stack(std::function<void()>&& func) { callbacks.push_back(std::forward<std::function<void()>>(func)); }
inline exit_stack(ctx_manager&& func) { this->operator << (std::forward<ctx_manager>(func)); }
inline ~exit_stack() {
for (auto it = callbacks.rbegin(); it != callbacks.rend(); ++it) {
(*it)();
}
}
inline exit_stack& operator << (std::function<void()>&& func) {
callbacks.push_back(std::forward<std::function<void()>>(func));
return *this;
}
inline exit_stack& operator << (ctx_manager&& ctx) {
if (ctx._func) {
callbacks.push_back(std::move(ctx._func));
ctx._func = {};
}
return *this;
}
inline void clear() {
callbacks.clear();
}
};
} // namespace niklasrosenstein