#ifndef SRC_BASE_DEFER_H_
#define SRC_BASE_DEFER_H_

// Minimal scope-exit / DEFER utility.
//
// DEFER { ... }; runs the braced block unconditionally when the enclosing
// scope exits (normal return, break, or exception), in reverse order of
// declaration. Useful for co-locating cleanup with the resource it frees:
//
//   void *p = acquire();
//   DEFER { release(p); };
//   ... use p; early returns are safe ...
//
// This replaces the previously vendored Neargye/scope_guard header; the codebase
// only ever used its unconditional scope-exit (DEFER) form.

#include <type_traits>
#include <utility>

namespace lodos::detail {

template <typename F>
class scope_exit {
  F action_;

 public:
  explicit scope_exit(F &&action) : action_(std::move(action)) {}
  scope_exit(scope_exit &&other) noexcept : action_(std::move(other.action_)) {}

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

  ~scope_exit() { action_(); }
};

// Tag that turns `tag{} + [&] { ... }` into a scope_exit, so the DEFER macro can
// be followed directly by a braced block (the lambda body).
struct scope_exit_tag {};

template <typename F>
scope_exit<std::decay_t<F>> operator+(scope_exit_tag, F &&action) {
  return scope_exit<std::decay_t<F>>(std::forward<F>(action));
}

}  // namespace lodos::detail

#define DEFER_STR_CONCAT_IMPL(s1, s2) s1##s2
#define DEFER_STR_CONCAT(s1, s2) DEFER_STR_CONCAT_IMPL(s1, s2)

#define DEFER                                                          \
  [[maybe_unused]] const auto DEFER_STR_CONCAT(defer_object_, __COUNTER__) = \
      ::lodos::detail::scope_exit_tag{} + [&]() -> void

#endif  // SRC_BASE_DEFER_H_
