Skip to content

Instantly share code, notes, and snippets.

@socantre
Last active December 22, 2016 08:39
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save socantre/b45b3e23e6f1f4715f08 to your computer and use it in GitHub Desktop.
Save socantre/b45b3e23e6f1f4715f08 to your computer and use it in GitHub Desktop.
#include <utility>
#ifndef SCOPE_EXIT_H_
#define SCOPE_EXIT_H_
// modeled slightly after Andrescu’s talk and article(s)
namespace std {
namespace experimental {
template <typename EF> struct scope_exit {
// construction
explicit scope_exit(EF &&f) noexcept(true)
: exit_function(std::move(f)), execute_on_destruction{true} {}
// move
scope_exit(scope_exit &&rhs) noexcept(true)
: exit_function(std::move(rhs.exit_function)),
execute_on_destruction{rhs.execute_on_destruction} {
rhs.release();
}
// release
~scope_exit() noexcept(noexcept(this->exit_function())) {
if (execute_on_destruction)
this->exit_function();
}
void release() noexcept(true) { this->execute_on_destruction = false; }
private:
scope_exit(scope_exit const &) = delete;
void operator=(scope_exit const &) = delete;
scope_exit &operator=(scope_exit &&) = delete;
EF exit_function;
bool execute_on_destruction; // exposition only
};
template <typename EF>
auto make_scope_exit(EF &&exit_function) noexcept(true) -> decltype(
scope_exit<std::remove_reference_t<EF>>(std::forward<EF>(exit_function))) {
return scope_exit<std::remove_reference_t<EF>>(
std::forward<EF>(exit_function));
}
}
}
#endif /* SCOPE EXIT H */
#ifndef UNIQUE_RESOURCE_H_
#define UNIQUE_RESOURCE_H_
namespace std {
namespace experimental {
template <typename R, typename D> class unique_resource {
R resource;
D deleter;
bool execute_on_destruction; // exposition only
unique_resource &operator=(unique_resource const &) = delete;
unique_resource(unique_resource const &) = delete; // no copies!
public:
// construction
explicit unique_resource(R &&resource, D &&deleter,
bool shouldrun = true) noexcept(true)
: resource(std::move(resource)), deleter(std::move(deleter)),
execute_on_destruction{shouldrun} {}
// move
unique_resource(unique_resource &&other) noexcept(true)
: resource(std::move(other.resource)), deleter(std::move(other.deleter)),
execute_on_destruction{other.execute_on_destruction} {
other.release();
}
unique_resource &
operator=(unique_resource &&other) noexcept(noexcept(this->reset())) {
this->reset();
this->deleter = std::move(other.deleter);
this->resource = std::move(other.resource);
this->execute_on_destruction = other.execute_on_destruction;
other.release();
return *this;
}
// resource release
~unique_resource() noexcept(noexcept(this->reset())) { this->reset(); }
void reset() noexcept(noexcept(this->get_deleter()(resource))) {
if (execute_on_destruction) {
this->execute_on_destruction = false;
this->get_deleter()(resource);
}
}
void reset(R &&newresource) noexcept(noexcept(this->reset())) {
this->reset();
this->resource = std::move(newresource);
this->execute_on_destruction = true;
}
R const &release() noexcept(true) {
this->execute_on_destruction = false;
return this->get();
}
// resource access
R const &get() const noexcept(true) { return this->resource; }
operator R const &() const noexcept(true) { return this->resource; }
R operator->() const noexcept(true) { return this->resource; }
std::add_lvalue_reference_t<std::remove_pointer_t<R>> operator*() const {
return *this->resource;
}
// deleter access
const D &get_deleter() const noexcept(true) { return this->deleter; }
};
// factories
template <typename R, typename D>
auto make_unique_resource(R &&r, D &&d) noexcept(true)
-> decltype(unique_resource<R, std::remove_reference_t<D>>(
std::move(r), std::forward<std::remove_reference_t<D>>(d), true)) {
return unique_resource<R, std::remove_reference_t<D>>(
std::move(r), std::forward<std::remove_reference_t<D>>(d), true);
}
template <typename R, typename D>
auto make_unique_resource_checked(R r, R invalid, D d) noexcept(true)
-> decltype(unique_resource<R, D>(std::move(r), std::move(d), true)) {
bool shouldrun = not bool(r == invalid);
return unique_resource<R, D>(std::move(r), std::move(d), shouldrun);
}
}
}
#endif /* UNIQUE RESOURCE H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment