| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- #pragma once
- #include <functional>
- #include <type_traits>
- #define JVALIDATE_CONCAT2(A, B) A##B
- #define JVALIDATE_CONCAT(A, B) JVALIDATE_CONCAT2(A, B)
- /**
- * @breif Create an anonymous scoped state object, which represents a temporary
- * change of value. Since we only need to give ScopedState a name to ensure that
- * its lifetime isn't for only a single line, this macro allows us to be more
- * appropriately terse.
- *
- * @code
- * {
- * scoped_state(property_, value...);
- * // do some things...
- * }
- * @endcode
- *
- * but this one provides exit guards in the same way that @see OnBlockExit does.
- *
- * @param prop A reference to a property that should be altered in the current
- * function-scope. Is immediately modified to {@see value}, and will be returned
- * to its original value when the current scope exits.
- *
- * @param value The new value to be set into prop.
- */
- #define scoped_state(prop, value) \
- auto JVALIDATE_CONCAT(scoped_state_, __LINE__) = detail::ScopedState(prop, value)
- namespace jvalidate::detail {
- /**
- * @brief An object that alters a given value to a provided temporary, and then
- * restores it to the original value upon being destructed. Because of this
- * characteristic, the following two pieces of code are equivalent:
- *
- * @code
- * T tmp = value...;
- * std::swap(property_, tmp);
- * // do some things...
- * std::swap(property_, tmp);
- * @endcode
- *
- * @code
- * {
- * ScopedState tmp(property_, value...);
- * // do some things...
- * }
- * @endcode
- */
- class ScopedState {
- private:
- std::function<void()> reset_;
- public:
- /**
- * @brief Initialize a scoped change-in-value to a property, properly guarded
- * against early-returns, exceptions, and forgetting to reset the property.
- *
- * @tparam T The type of the value being updated
- * @tparam S Any type that is compatible with T
- *
- * @param prop A reference to a property that should be altered in the current
- * function-scope. Is immediately modified to {@see value}, and will be returned
- * to its original value when the current scope exits.
- *
- * @param value The new value to be set into prop.
- */
- template <typename T, typename S>
- requires(std::is_constructible_v<T, S>)
- ScopedState(T & prop, S value) : reset_([reset = prop, &prop]() { prop = reset; }) {
- prop = std::move(value);
- }
- ~ScopedState() { reset_(); }
- /**
- * @brief By providing an explicit operator bool, it is possible to use
- * ScopedState in an if statement, allowing you to write something like:
- *
- * @code
- * if (scoped_state(property_, value...)) {
- * // do some things...
- * }
- * @endcode
- */
- explicit operator bool() const { return true; }
- };
- }
|