Program Listing for File scope.hpp

Return to documentation for file (SeQuant/core/utility/scope.hpp)

//
// Created by Eduard Valeyev on 2/15/23.
//

#ifndef SEQUANT_CORE_SCOPE_HPP
#define SEQUANT_CORE_SCOPE_HPP

#include <utility>

#ifdef SEQUANT_CORE_UTILITY_SCOPE_HPP_USE_STD_EXPERIMENTAL_SCOPE
#error \
    "SEQUANT_CORE_UTILITY_SCOPE_HPP_USE_STD_EXPERIMENTAL_SCOPE already defined, please create an issue at github.com/ValeevGroup/SeQuant"
#endif

// availability of std::experimental::scope_exit requires experimental/scope to
// be present ...
#if __has_include(<experimental/scope>)

// ... and , if using libstdc++ >= 13, C++20 or later
#if defined(__GLIBCXX__) && __GLIBCXX__ >= 13 && __cplusplus >= 202002L
#define SEQUANT_CORE_UTILITY_SCOPE_HPP_USE_STD_EXPERIMENTAL_SCOPE 1
#endif

#endif

#if SEQUANT_CORE_UTILITY_SCOPE_HPP_USE_STD_EXPERIMENTAL_SCOPE

#include <experimental/scope>

namespace sequant::detail {
using std::experimental::scope_exit;
}

#else

namespace sequant::detail {

template <typename EF>
class scope_exit {
 public:
  template <typename Fn>
  explicit scope_exit(Fn&& fn) noexcept
      : fn_(std::forward<Fn>(fn)), released_(false) {}
  scope_exit(scope_exit&& other) noexcept = default;
  scope_exit(const scope_exit&) = delete;

  ~scope_exit() noexcept {
    if (!released_) {
      fn_();
      released_ = true;
    }
  }

  scope_exit& operator=(const scope_exit&) = delete;
  scope_exit& operator=(scope_exit&&) = delete;

  void release() noexcept { released_ = true; }

 private:
  EF fn_;
  bool released_ = false;
};

}  // namespace sequant::detail

#endif  // SEQUANT_CORE_UTILITY_SCOPE_HPP_USE_STD_EXPERIMENTAL_SCOPE
#undef SEQUANT_CORE_UTILITY_SCOPE_HPP_USE_STD_EXPERIMENTAL_SCOPE

namespace sequant::detail {
template <typename EF>
[[nodiscard]] scope_exit<EF> make_scope_exit(EF&& ef) {
  return scope_exit<EF>(std::forward<EF>(ef));
}
}  // namespace sequant::detail

#endif  // SEQUANT_CORE_SCOPE_HPP