mirror of
https://github.com/CHN-beta/nixos.git
synced 2026-01-12 04:39:23 +08:00
packages.biu: 完成 Atomic
This commit is contained in:
@@ -57,3 +57,7 @@ add_executable(test-format test/format.cpp)
|
||||
target_link_libraries(test-format PRIVATE biu)
|
||||
set_property(TARGET test-format PROPERTY CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON)
|
||||
add_test(NAME test-format COMMAND test-format)
|
||||
add_executable(test-atomic test/atomic.cpp)
|
||||
target_link_libraries(test-atomic PRIVATE biu)
|
||||
set_property(TARGET test-atomic PROPERTY CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON)
|
||||
add_test(NAME test-atomic COMMAND test-atomic)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# pragma once
|
||||
// # include <biu/atomic/atomic.tpp>
|
||||
// # include <biu/called_by.hpp>
|
||||
# include <biu/atomic.tpp>
|
||||
# include <biu/called_by.hpp>
|
||||
# include <biu/common.tpp>
|
||||
# include <biu/concepts.tpp>
|
||||
# include <biu/string.tpp>
|
||||
|
||||
68
packages/biu/include/biu/atomic.hpp
Normal file
68
packages/biu/include/biu/atomic.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
# pragma once
|
||||
# include <mutex>
|
||||
# include <optional>
|
||||
# include <condition_variable>
|
||||
# include <cstddef>
|
||||
# include <experimental/memory>
|
||||
# include <biu/common.hpp>
|
||||
# include <biu/concepts.hpp>
|
||||
# include <biu/called_by.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
template <DecayedType ValueType> class Atomic
|
||||
{
|
||||
protected: mutable std::mutex Mutex_;
|
||||
protected: mutable std::condition_variable ConditionVariable_;
|
||||
protected: ValueType Value_;
|
||||
|
||||
public: template <bool Const> class Guard
|
||||
{
|
||||
protected: std::unique_lock<std::mutex> Lock_;
|
||||
protected: std::experimental::observer_ptr
|
||||
<std::conditional_t<Const, const Atomic<ValueType>, Atomic<ValueType>>> Value_;
|
||||
|
||||
public: template <bool OtherConst> Guard(Guard<OtherConst>&& other) requires (Const || !OtherConst);
|
||||
public: Guard
|
||||
(decltype(Lock_)&& lock, decltype(Value_) value, CalledBy<Atomic<ValueType>>);
|
||||
public: ~Guard();
|
||||
|
||||
public: std::conditional_t<Const, const ValueType&, ValueType&> operator*() const&;
|
||||
public: std::conditional_t<Const, const ValueType*, ValueType*> operator->() const&;
|
||||
public: std::conditional_t<Const, const ValueType&, ValueType&> value() const&;
|
||||
};
|
||||
|
||||
public: Atomic() = default;
|
||||
public: Atomic(auto&& value);
|
||||
public: Atomic& operator=(auto&& value);
|
||||
|
||||
public: ValueType get(this auto&& self);
|
||||
public: operator ValueType(this auto&& self);
|
||||
|
||||
protected: template <bool Throw = false> auto lock_(this auto&& self, auto&& condition_function, auto timeout);
|
||||
|
||||
// Apply a function to stored value.
|
||||
// Wait for some time (if provided) until condition funciton returns true (if provided)
|
||||
// before applying the function.
|
||||
// NoReturn: throw exception if timeout, ignore function result, and return *this, if true;
|
||||
// return bool or std::optional wrapped result of function, if false.
|
||||
// Useful when chaining multiple apply() calls.
|
||||
public: template <bool NoReturn = false> decltype(auto) apply
|
||||
(this auto&& self, auto&& function, auto&& condition_function, auto&& timeout);
|
||||
public: template <bool NoReturn = false> decltype(auto) apply
|
||||
(this auto&& self, auto&& function, auto&& condition_function);
|
||||
public: template <bool NoReturn = false> decltype(auto) apply(this auto&& self, auto&& function);
|
||||
|
||||
// Wait until condition funciton returns true or *this, with an optional timeout
|
||||
public: template <bool NoReturn = false> decltype(auto) wait
|
||||
(this auto&& self, auto&& condition_function, auto timeout);
|
||||
public: template <bool NoReturn = false> decltype(auto) wait
|
||||
(this auto&& self, auto&& condition_function);
|
||||
|
||||
// Attain lock from outside when constructing, and release when destructing.
|
||||
// Throw: same effect as NoReturn.
|
||||
public: template <bool Throw = false> auto lock(this auto&& self, auto&& condition_function, auto timeout);
|
||||
public: template <bool Throw = false> auto lock(this auto&& self, auto&& condition_function);
|
||||
public: template <bool Throw = false> auto lock(this auto&& self);
|
||||
};
|
||||
}
|
||||
153
packages/biu/include/biu/atomic.tpp
Normal file
153
packages/biu/include/biu/atomic.tpp
Normal file
@@ -0,0 +1,153 @@
|
||||
# pragma once
|
||||
# include <biu/atomic.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
template <DecayedType ValueType> template <bool Const> template <bool OtherConst>
|
||||
Atomic<ValueType>::Guard<Const>::Guard(Guard<OtherConst>&& other) requires (Const || !OtherConst)
|
||||
: Lock_{std::move(other.Lock_)}, Value_{std::move(other.Value_)} {}
|
||||
template <DecayedType ValueType> template <bool Const> Atomic<ValueType>::Guard<Const>::Guard
|
||||
(decltype(Lock_)&& lock, decltype(Value_) value, CalledBy<Atomic<ValueType>>)
|
||||
: Lock_{std::move(lock)}, Value_{value} {}
|
||||
template <DecayedType ValueType> template <bool Const> Atomic<ValueType>::Guard<Const>::~Guard()
|
||||
{ if constexpr (!Const) Value_->ConditionVariable_.notify_all(); }
|
||||
|
||||
template <DecayedType ValueType> template <bool Const> std::conditional_t<Const, const ValueType&, ValueType&>
|
||||
Atomic<ValueType>::Guard<Const>::operator*() const&
|
||||
{ return Value_->Value_; }
|
||||
template <DecayedType ValueType> template <bool Const> std::conditional_t<Const, const ValueType*, ValueType*>
|
||||
Atomic<ValueType>::Guard<Const>::operator->() const&
|
||||
{ return &Value_->Value_; }
|
||||
template <DecayedType ValueType> template <bool Const> std::conditional_t<Const, const ValueType&, ValueType&>
|
||||
Atomic<ValueType>::Guard<Const>::value() const&
|
||||
{ return Value_->Value_; }
|
||||
|
||||
template <DecayedType ValueType> Atomic<ValueType>::Atomic(auto&& value)
|
||||
: Value_{std::forward<decltype(value)>(value)} {}
|
||||
template <DecayedType ValueType> Atomic<ValueType>& Atomic<ValueType>::operator=(auto&& value)
|
||||
{
|
||||
std::scoped_lock lock(Mutex_);
|
||||
Value_ = std::forward<decltype(value)>(value);
|
||||
ConditionVariable_.notify_all();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <DecayedType ValueType> ValueType Atomic<ValueType>::get(this auto&& self)
|
||||
{ std::scoped_lock lock(self.Mutex_); return self.Value_; }
|
||||
template <DecayedType ValueType> Atomic<ValueType>::operator ValueType(this auto&& self)
|
||||
{ return self.get(); }
|
||||
|
||||
template <DecayedType ValueType> template <bool Throw> auto Atomic<ValueType>::lock_
|
||||
(this auto&& self, auto&& condition_function, auto timeout)
|
||||
{
|
||||
if constexpr (Nullptr<decltype(condition_function)>)
|
||||
return Guard<std::is_const_v<decltype(self)>>
|
||||
(std::unique_lock{self.Mutex_}, std::experimental::make_observer(&self), {});
|
||||
else if constexpr (Nullptr<decltype(timeout)>)
|
||||
{
|
||||
std::unique_lock lock(self.Mutex_);
|
||||
self.ConditionVariable_.wait(lock, [&]
|
||||
{ return std::forward<decltype(condition_function)>(condition_function)(std::as_const(self.Value_)); });
|
||||
return Guard<std::is_const_v<decltype(self)>>(std::move(lock), std::experimental::make_observer(&self), {});
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_lock lock(self.Mutex_);
|
||||
if (!self.ConditionVariable_.wait_for(lock, timeout, [&]
|
||||
{ return std::forward<decltype(condition_function)>(condition_function)(std::as_const(self.Value_)); }))
|
||||
{
|
||||
if constexpr (Throw) throw std::runtime_error("Timeout");
|
||||
else return std::optional<Guard<std::is_const_v<decltype(self)>>>();
|
||||
}
|
||||
else
|
||||
return std::optional<Guard<std::is_const_v<decltype(self)>>>
|
||||
(std::move(lock), std::experimental::make_observer(&self), {});
|
||||
}
|
||||
}
|
||||
|
||||
template <DecayedType ValueType> template <bool NoReturn> decltype(auto) Atomic<ValueType>::apply
|
||||
(this auto&& self, auto&& function, auto&& condition_function, auto&& timeout)
|
||||
{
|
||||
using function_return_type = std::invoke_result_t<decltype(function), MoveQualifiers<decltype(self), ValueType>>;
|
||||
auto&& lock = std::forward<decltype(self)>(self).template lock_<NoReturn>
|
||||
(std::forward<decltype(condition_function)>(condition_function), timeout);
|
||||
// 如果得到的是 optional
|
||||
if constexpr (SpecializationOf<std::remove_cvref_t<decltype(lock)>, std::optional>)
|
||||
// 如果超时了,返回 false 或者对应的 nullopt
|
||||
if (!lock)
|
||||
if constexpr (std::is_void_v<function_return_type>) return false;
|
||||
else return std::optional<function_return_type>();
|
||||
// 否则,执行函数并返回
|
||||
else
|
||||
if constexpr (std::is_void_v<function_return_type>)
|
||||
{
|
||||
std::forward<decltype(function)>(function)
|
||||
(std::forward<MoveQualifiers<decltype(self), ValueType>>(self.Value_));
|
||||
// 如果函数本身返回 void 并且不可能超时,返回 *this,否则返回 true
|
||||
if constexpr (Nullptr<decltype(condition_function)> || Nullptr<decltype(timeout)>)
|
||||
return std::forward<decltype(self)>(self);
|
||||
else return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto&& result = std::forward<decltype(function)>(function)
|
||||
(std::forward<MoveQualifiers<decltype(self), ValueType>>(self.Value_));
|
||||
return std::make_optional(std::forward<decltype(result)>(result));
|
||||
}
|
||||
// 否则,执行函数并返回 *this
|
||||
else
|
||||
{
|
||||
std::forward<decltype(function)>(function)
|
||||
(std::forward<MoveQualifiers<decltype(self), ValueType>>(self.Value_));
|
||||
return std::forward<decltype(self)>(self);
|
||||
}
|
||||
}
|
||||
template <DecayedType ValueType> template <bool NoReturn> decltype(auto) Atomic<ValueType>::apply
|
||||
(this auto&& self, auto&& function, auto&& condition_function)
|
||||
{
|
||||
return std::forward<decltype(self)>(self).template apply<NoReturn>
|
||||
(
|
||||
std::forward<decltype(function)>(function),
|
||||
std::forward<decltype(condition_function)>(condition_function),
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
template <DecayedType ValueType> template <bool NoReturn> decltype(auto) Atomic<ValueType>::apply
|
||||
(this auto&& self, auto&& function)
|
||||
{
|
||||
return std::forward<decltype(self)>(self).template apply<NoReturn>
|
||||
(std::forward<decltype(function)>(function), nullptr, nullptr);
|
||||
}
|
||||
|
||||
template <DecayedType ValueType> template <bool NoReturn> decltype(auto) Atomic<ValueType>::wait
|
||||
(this auto&& self, auto&& condition_function, auto timeout)
|
||||
{
|
||||
auto result = std::forward<decltype(self)>(self).template lock_<NoReturn>
|
||||
(std::forward<decltype(condition_function)>(condition_function), timeout);
|
||||
if constexpr (SpecializationOf<decltype(result), std::optional>) return result.has_value();
|
||||
else return std::forward<decltype(result)>(result);
|
||||
}
|
||||
template <DecayedType ValueType> template <bool NoReturn> decltype(auto) Atomic<ValueType>::wait
|
||||
(this auto&& self, auto&& condition_function)
|
||||
{
|
||||
return std::forward<decltype(self)>(self).template wait<NoReturn>
|
||||
(std::forward<decltype(condition_function)>(condition_function), nullptr);
|
||||
}
|
||||
|
||||
template <DecayedType ValueType> template <bool Throw> auto Atomic<ValueType>::lock
|
||||
(this auto&& self, auto&& condition_function, auto timeout)
|
||||
{
|
||||
// self 不能是右值引用
|
||||
static_assert(!std::is_rvalue_reference_v<decltype(self)>, "rvalue atomic cannot be locked");
|
||||
return std::forward<decltype(self)>(self).template lock_<Throw>
|
||||
(std::forward<decltype(condition_function)>(condition_function), timeout);
|
||||
}
|
||||
template <DecayedType ValueType> template <bool Throw> auto Atomic<ValueType>::lock
|
||||
(this auto&& self, auto&& condition_function)
|
||||
{
|
||||
return std::forward<decltype(self)>(self).template lock<Throw>
|
||||
(std::forward<decltype(condition_function)>(condition_function), nullptr);
|
||||
}
|
||||
template <DecayedType ValueType> template <bool Throw> auto Atomic<ValueType>::lock(this auto&& self)
|
||||
{ return std::forward<decltype(self)>(self).template lock<Throw>(nullptr, nullptr); }
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
# pragma once
|
||||
# include <biu/logger.hpp>
|
||||
|
||||
namespace biu::detail_
|
||||
{
|
||||
template <DecayedType ValueType> class AtomicBase<ValueType, true>
|
||||
: public Logger::ObjectMonitor<Atomic<ValueType, true>>, protected AtomicBase<ValueType, false>
|
||||
{
|
||||
using DeepBase_ = AtomicBase<ValueType, false>;
|
||||
using DeepBase_::AtomicBase;
|
||||
public: class TimeoutException : public Logger::Exception<TimeoutException>
|
||||
{
|
||||
using Logger::Exception<TimeoutException>::Exception;
|
||||
};
|
||||
|
||||
protected: template
|
||||
<
|
||||
bool ReturnFunctionResult,
|
||||
typename ConditionFunction = std::nullptr_t, typename Duration = std::nullptr_t, bool Nothrow = false
|
||||
> static auto apply_
|
||||
(
|
||||
auto&& atomic, auto&& function,
|
||||
ConditionFunction&& condition_function = nullptr, Duration timeout = nullptr
|
||||
) -> DeepBase_::template ApplyReturnType_
|
||||
<decltype(function), decltype(atomic), ReturnFunctionResult, ConditionFunction, Duration, Nothrow>
|
||||
requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(atomic), ConditionFunction, Duration>;
|
||||
|
||||
protected: template <bool Nothrow = false, typename Duration = std::nullptr_t> static auto wait_
|
||||
(auto&& atomic, auto&& condition_function, Duration timeout = nullptr)
|
||||
-> DeepBase_::template WaitReturnType_<decltype(atomic), decltype(condition_function), Duration, Nothrow>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function), Duration>;
|
||||
|
||||
protected: template
|
||||
<bool Nothrow = false, typename ConditionFunction = std::nullptr_t, typename Duration = std::nullptr_t>
|
||||
static auto lock_
|
||||
(auto&& atomic, ConditionFunction&& condition_function = nullptr, Duration timeout = nullptr)
|
||||
-> DeepBase_::template LockReturnType_<decltype(atomic), Duration, Nothrow>
|
||||
requires DeepBase_::template LockConstraint_<ConditionFunction, Duration>;
|
||||
};
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
# pragma once
|
||||
# include <mutex>
|
||||
# include <optional>
|
||||
# include <condition_variable>
|
||||
# include <cstddef>
|
||||
# include <experimental/memory>
|
||||
# include <biu/common.hpp>
|
||||
# include <biu/concepts.hpp>
|
||||
# include <biu/called_by.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
template <DecayedType ValueType, bool UseLogger = true> class Atomic;
|
||||
namespace detail_
|
||||
{
|
||||
template <DecayedType ValueType, bool UseLogger> class AtomicBase;
|
||||
template <DecayedType ValueType> class AtomicBase<ValueType, false>
|
||||
{
|
||||
protected: mutable std::recursive_mutex Mutex_;
|
||||
protected: mutable std::condition_variable_any ConditionVariable_;
|
||||
protected: ValueType Value_;
|
||||
|
||||
AtomicBase() = default;
|
||||
AtomicBase(const ValueType& value);
|
||||
AtomicBase(ValueType&& value);
|
||||
|
||||
public: class TimeoutException : public std::exception
|
||||
{
|
||||
protected: std::string Message_;
|
||||
public: explicit TimeoutException(std::string message);
|
||||
public: const char* what() const noexcept override;
|
||||
};
|
||||
|
||||
// Apply a function to stored value.
|
||||
// Wait for some time (if provided) until condition funciton returns true (if provided)
|
||||
// before applying the function.
|
||||
protected: template
|
||||
<
|
||||
typename Function, typename Atomic,
|
||||
typename ConditionFunction = std::nullptr_t, typename Duration = std::nullptr_t
|
||||
>
|
||||
constexpr static bool ApplyConstraint_ =
|
||||
(
|
||||
(std::invocable<Function, MoveQualifiers<Atomic, ValueType>> && std::is_null_pointer_v<ConditionFunction>)
|
||||
|| (
|
||||
InvocableWithResult<ConditionFunction, bool, const ValueType&>
|
||||
&& (std::is_null_pointer_v<Duration> || SpecializationOf<Duration, std::chrono::duration>)
|
||||
)
|
||||
);
|
||||
protected: template
|
||||
<
|
||||
typename Function, typename Atomic, bool ReturnFunctionResult,
|
||||
typename ConditionFunction = std::nullptr_t, typename Duration = std::nullptr_t,
|
||||
bool Nothrow = false
|
||||
> using ApplyReturnType_ = std::conditional_t
|
||||
<
|
||||
Nothrow,
|
||||
std::conditional_t
|
||||
<
|
||||
ReturnFunctionResult && !std::is_void_v<std::invoke_result<Function, ValueType>>,
|
||||
std::optional<std::remove_cvref_t<FallbackIfNoTypeDeclared<std::invoke_result
|
||||
<Function, MoveQualifiers<Atomic, ValueType>, int>>>>,
|
||||
bool
|
||||
>,
|
||||
std::conditional_t
|
||||
<
|
||||
ReturnFunctionResult,
|
||||
std::invoke_result_t<Function, MoveQualifiers<Atomic, ValueType>>,
|
||||
Atomic&&
|
||||
>
|
||||
>;
|
||||
protected: template
|
||||
<
|
||||
bool ReturnFunctionResult,
|
||||
typename ConditionFunction = std::nullptr_t, typename Duration = std::nullptr_t,
|
||||
bool Nothrow = false
|
||||
> static auto apply_
|
||||
(
|
||||
auto&& atomic, auto&& function,
|
||||
ConditionFunction&& condition_function = nullptr, Duration timeout = nullptr
|
||||
) -> ApplyReturnType_
|
||||
<decltype(function), decltype(atomic), ReturnFunctionResult, ConditionFunction, Duration, Nothrow>
|
||||
requires ApplyConstraint_<decltype(function), decltype(atomic), ConditionFunction, Duration>;
|
||||
|
||||
// Wait until condition funciton returns true, with an optional timeout
|
||||
protected: template <typename ConditionFunction, typename Duration = std::nullptr_t>
|
||||
constexpr static bool WaitConstraint_
|
||||
= (InvocableWithResult<ConditionFunction, bool, const ValueType&>
|
||||
&& (std::is_null_pointer_v<Duration> || SpecializationOf<Duration, std::chrono::duration>));
|
||||
protected: template
|
||||
<typename Atomic, typename ConditionFunction, typename Duration = std::nullptr_t, bool Nothrow = false>
|
||||
using WaitReturnType_
|
||||
= std::conditional_t<Nothrow && !std::is_null_pointer_v<Duration>, bool, Atomic&&>;
|
||||
protected: template <bool Nothrow = false, typename Duration = std::nullptr_t> static auto wait_
|
||||
(auto&& atomic, auto&& condition_function, Duration timeout = nullptr)
|
||||
-> WaitReturnType_<decltype(atomic), decltype(condition_function), Duration, Nothrow>
|
||||
requires WaitConstraint_<decltype(condition_function), Duration>;
|
||||
|
||||
protected: template <typename ConditionFunction = std::nullptr_t, typename Duration = std::nullptr_t>
|
||||
constexpr static bool LockConstraint_
|
||||
= std::is_null_pointer_v<ConditionFunction> ||
|
||||
(
|
||||
InvocableWithResult<ConditionFunction, bool, const ValueType&>
|
||||
&& (std::is_null_pointer_v<Duration> || SpecializationOf<Duration, std::chrono::duration>)
|
||||
);
|
||||
protected: template <typename Atomic, typename Duration = std::nullptr_t, bool Nothrow = false>
|
||||
using LockReturnType_
|
||||
= std::conditional_t
|
||||
<
|
||||
Nothrow && !std::is_null_pointer_v<Duration>,
|
||||
std::optional<std::conditional_t
|
||||
<
|
||||
std::is_const_v<Atomic>,
|
||||
typename std::remove_reference_t<Atomic>::template Guard<true>,
|
||||
typename std::remove_reference_t<Atomic>::template Guard<false>
|
||||
>>,
|
||||
std::conditional_t
|
||||
<
|
||||
std::is_const_v<Atomic>,
|
||||
typename std::remove_reference_t<Atomic>::template Guard<true>,
|
||||
typename std::remove_reference_t<Atomic>::template Guard<false>
|
||||
>
|
||||
>;
|
||||
protected: template
|
||||
<bool Nothrow = false, typename ConditionFunction = std::nullptr_t, typename Duration = std::nullptr_t>
|
||||
static auto lock_
|
||||
(auto&& atomic, ConditionFunction&& condition_function = nullptr, Duration timeout = nullptr)
|
||||
-> LockReturnType_<decltype(atomic), Duration, Nothrow>
|
||||
requires LockConstraint_<ConditionFunction, Duration>;
|
||||
};
|
||||
}
|
||||
|
||||
// Thread safe wrapper of custom class
|
||||
template <DecayedType ValueType, bool UseLogger> class Atomic : public detail_::AtomicBase<ValueType, UseLogger>
|
||||
{
|
||||
public: Atomic() = default;
|
||||
public: Atomic(const ValueType& value);
|
||||
public: Atomic(ValueType&& value);
|
||||
public: template <bool OtherUseLogger> Atomic(const Atomic<ValueType, OtherUseLogger>& other);
|
||||
public: template <bool OtherUseLogger> Atomic(Atomic<ValueType, OtherUseLogger>&& other);
|
||||
public: Atomic<ValueType, UseLogger>& operator=(const ValueType& value);
|
||||
public: Atomic<ValueType, UseLogger>& operator=(ValueType&& value);
|
||||
public: template <bool OtherUseLogger>
|
||||
Atomic<ValueType, UseLogger>& operator=(const Atomic<ValueType, OtherUseLogger>& other);
|
||||
public: template <bool OtherUseLogger>
|
||||
Atomic<ValueType, UseLogger>& operator=(Atomic<ValueType, OtherUseLogger>&& other);
|
||||
public: ValueType get() const&;
|
||||
public: ValueType get() &&;
|
||||
public: operator ValueType() const&;
|
||||
public: operator ValueType() &&;
|
||||
|
||||
protected: using DeepBase_ = detail_::AtomicBase<ValueType, false>;
|
||||
|
||||
public: template <bool ReturnFunctionResult = false> auto apply(auto&& function) const&
|
||||
-> DeepBase_::template ApplyReturnType_<decltype(function), decltype(*this), ReturnFunctionResult>
|
||||
requires DeepBase_::template ApplyConstraint_<decltype(function), decltype(*this)>;
|
||||
public: template <bool ReturnFunctionResult = false> auto apply(auto&& function) &
|
||||
-> DeepBase_::template ApplyReturnType_<decltype(function), decltype(*this), ReturnFunctionResult>
|
||||
requires DeepBase_::template ApplyConstraint_<decltype(function), decltype(*this)>;
|
||||
public: template <bool ReturnFunctionResult = false> auto apply(auto&& function) &&
|
||||
-> DeepBase_::template ApplyReturnType_<decltype(function), decltype(*this), ReturnFunctionResult>
|
||||
requires DeepBase_::template ApplyConstraint_<decltype(function), decltype(*this)>;
|
||||
public: template <bool ReturnFunctionResult = false>
|
||||
auto apply(auto&& function, auto&& condition_function) const&
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<decltype(function), decltype(*this), ReturnFunctionResult, decltype(condition_function)>
|
||||
requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(*this), decltype(condition_function)>;
|
||||
public: template <bool ReturnFunctionResult = false> auto apply(auto&& function, auto&& condition_function) &
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<decltype(function), decltype(*this), ReturnFunctionResult, decltype(condition_function)>
|
||||
requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(*this), decltype(condition_function)>;
|
||||
public: template <bool ReturnFunctionResult = false> auto apply(auto&& function, auto&& condition_function) &&
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<decltype(function), decltype(*this), ReturnFunctionResult, decltype(condition_function)>
|
||||
requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(*this), decltype(condition_function)>;
|
||||
public: template <bool ReturnFunctionResult = false, bool Nothrow = false>
|
||||
auto apply(auto&& function, auto&& condition_function, auto timeout) const&
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<
|
||||
decltype(function), decltype(*this), ReturnFunctionResult,
|
||||
decltype(condition_function), decltype(timeout), Nothrow
|
||||
> requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(*this), decltype(condition_function), decltype(timeout)>;
|
||||
public: template <bool ReturnFunctionResult = false, bool Nothrow = false>
|
||||
auto apply(auto&& function, auto&& condition_function, auto timeout) &
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<
|
||||
decltype(function), decltype(*this), ReturnFunctionResult,
|
||||
decltype(condition_function), decltype(timeout), Nothrow
|
||||
> requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(*this), decltype(condition_function), decltype(timeout)>;
|
||||
public: template <bool ReturnFunctionResult = false, bool Nothrow = false>
|
||||
auto apply(auto&& function, auto&& condition_function, auto timeout) &&
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<
|
||||
decltype(function), decltype(*this), ReturnFunctionResult,
|
||||
decltype(condition_function), decltype(timeout), Nothrow
|
||||
> requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(*this), decltype(condition_function), decltype(timeout)>;
|
||||
|
||||
public: auto wait(auto&& condition_function) const&
|
||||
-> DeepBase_::template WaitReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function)>;
|
||||
public: auto wait(auto&& condition_function) &
|
||||
-> DeepBase_::template WaitReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function)>;
|
||||
public: auto wait(auto&& condition_function) &&
|
||||
-> DeepBase_::template WaitReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function)>;
|
||||
public: template <bool Nothrow = false> auto wait(auto&& condition_function, auto timeout) const&
|
||||
-> DeepBase_::template WaitReturnType_
|
||||
<decltype(*this), decltype(condition_function), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function), decltype(timeout)>;
|
||||
public: template <bool Nothrow = false> auto wait(auto&& condition_function, auto timeout) &
|
||||
-> DeepBase_::template WaitReturnType_
|
||||
<decltype(*this), decltype(condition_function), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function), decltype(timeout)>;
|
||||
public: template <bool Nothrow = false> auto wait(auto&& condition_function, auto timeout) &&
|
||||
-> DeepBase_::template WaitReturnType_
|
||||
<decltype(*this), decltype(condition_function), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function), decltype(timeout)>;
|
||||
|
||||
// Attain lock from outside when constructing, and release when destructing.
|
||||
// For non-const variant, When destructing, ConditionVariable_.notify_all() is called.
|
||||
public: template <bool Const> class Guard
|
||||
{
|
||||
protected: std::unique_lock<std::recursive_mutex> Lock_;
|
||||
protected: std::experimental::observer_ptr
|
||||
<std::conditional_t<Const, const Atomic<ValueType, UseLogger>, Atomic<ValueType, UseLogger>>> Value_;
|
||||
|
||||
public: template <bool OtherConst> Guard(const Guard<OtherConst>& other) requires (Const || !OtherConst);
|
||||
public: Guard
|
||||
(decltype(Lock_)&& lock, decltype(Value_) value, CalledBy<detail_::AtomicBase<ValueType, UseLogger>>);
|
||||
public: ~Guard();
|
||||
|
||||
public: std::conditional_t<Const, const ValueType&, ValueType&> operator*() const&;
|
||||
public: std::conditional_t<Const, const ValueType*, ValueType*> operator->() const&;
|
||||
public: std::conditional_t<Const, const ValueType&, ValueType&> value() const&;
|
||||
public: auto operator*() const&& = delete;
|
||||
public: auto operator->() const&& = delete;
|
||||
public: auto value() const&& = delete;
|
||||
};
|
||||
|
||||
public: auto lock() const& -> DeepBase_::template LockReturnType_<decltype(*this)>
|
||||
requires DeepBase_::template LockConstraint_<>;
|
||||
public: auto lock() & -> DeepBase_::template LockReturnType_<decltype(*this)>
|
||||
requires DeepBase_::template LockConstraint_<>;
|
||||
public: auto lock() const&& = delete;
|
||||
public: auto lock(auto&& condition_function) const&
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template LockConstraint_<decltype(condition_function)>;
|
||||
public: auto lock(auto&& condition_function) &
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template LockConstraint_<decltype(condition_function)>;
|
||||
public: auto lock(auto&& condition_function) const&& = delete;
|
||||
public: template <bool Nothrow = false> auto lock(auto&& condition_function, auto timeout) const&
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template LockConstraint_<decltype(condition_function), decltype(timeout)>;
|
||||
public: template <bool Nothrow = false> auto lock(auto&& condition_function, auto timeout) &
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template LockConstraint_<decltype(condition_function), decltype(timeout)>;
|
||||
public: template <bool Nothrow = false> auto lock(auto&& condition_function, auto timeout) const&& = delete;
|
||||
};
|
||||
}
|
||||
@@ -1,366 +0,0 @@
|
||||
# pragma once
|
||||
# include <biu/atomic/nolog.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
template <DecayedType ValueType> detail_::AtomicBase<ValueType, false>::AtomicBase(const ValueType& value)
|
||||
: Value_{value} {}
|
||||
template <DecayedType ValueType> detail_::AtomicBase<ValueType, false>::AtomicBase(ValueType&& value)
|
||||
: Value_{std::move(value)} {}
|
||||
|
||||
template <DecayedType ValueType>
|
||||
detail_::AtomicBase<ValueType, false>::TimeoutException::TimeoutException(std::string)
|
||||
: Message_{"TimeoutException"} {}
|
||||
template <DecayedType ValueType>
|
||||
const char* detail_::AtomicBase<ValueType, false>::TimeoutException::what() const noexcept
|
||||
{return Message_.c_str();}
|
||||
|
||||
template <DecayedType ValueType>
|
||||
template <bool ReturnFunctionResult, typename ConditionFunction, typename Duration, bool Nothrow>
|
||||
auto detail_::AtomicBase<ValueType, false>::apply_
|
||||
(auto&& atomic, auto&& function, ConditionFunction&& condition_function, Duration timeout)
|
||||
-> ApplyReturnType_
|
||||
<decltype(function), decltype(atomic), ReturnFunctionResult, ConditionFunction, Duration, Nothrow>
|
||||
requires ApplyConstraint_<decltype(function), decltype(atomic), ConditionFunction, Duration>
|
||||
{
|
||||
std::unique_lock lock{atomic.Mutex_};
|
||||
|
||||
// try to meet the condition
|
||||
if constexpr (!std::is_null_pointer_v<ConditionFunction>)
|
||||
{
|
||||
if constexpr (std::is_null_pointer_v<Duration>)
|
||||
atomic.ConditionVariable_.wait(lock, [&]
|
||||
{return std::forward<ConditionFunction>(condition_function)(std::as_const(atomic.Value_));});
|
||||
else if (!atomic.ConditionVariable_.wait_for(lock, timeout, [&]
|
||||
{return std::forward<ConditionFunction>(condition_function)(std::as_const(atomic.Value_));}))
|
||||
{
|
||||
if constexpr (Nothrow)
|
||||
{
|
||||
if constexpr
|
||||
(ReturnFunctionResult && !std::is_void_v<std::invoke_result_t<decltype(function), ValueType>>)
|
||||
return std::nullopt;
|
||||
else return false;
|
||||
}
|
||||
else throw TimeoutException{};
|
||||
}
|
||||
}
|
||||
|
||||
// apply the function and return
|
||||
if constexpr (ReturnFunctionResult && !std::is_void_v<std::invoke_result_t<decltype(function), ValueType>>)
|
||||
{
|
||||
auto&& result = std::forward<decltype(function)>(function)
|
||||
(static_cast<MoveQualifiers<decltype(atomic), ValueType>&&>(atomic.Value_));
|
||||
if constexpr (!std::is_const_v<decltype(atomic)>) atomic.ConditionVariable_.notify_all();
|
||||
return std::forward<decltype(result)>(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::forward<decltype(function)>(function)
|
||||
(static_cast<MoveQualifiers<decltype(atomic), ValueType>&&>(atomic.Value_));
|
||||
if constexpr (!std::is_const_v<decltype(atomic)>) atomic.ConditionVariable_.notify_all();
|
||||
if constexpr (ReturnFunctionResult && std::is_void_v<std::invoke_result_t<decltype(function), ValueType>>)
|
||||
return;
|
||||
else return std::forward<decltype(atomic)>(atomic);
|
||||
}
|
||||
}
|
||||
|
||||
template <DecayedType ValueType> template <bool Nothrow, typename Duration>
|
||||
auto detail_::AtomicBase<ValueType, false>::wait_(auto&& atomic, auto&& condition_function, Duration timeout)
|
||||
-> WaitReturnType_<decltype(atomic), decltype(condition_function), Duration, Nothrow>
|
||||
requires WaitConstraint_<decltype(condition_function), Duration>
|
||||
{
|
||||
std::unique_lock lock{atomic.Mutex_};
|
||||
|
||||
if constexpr (std::is_null_pointer_v<Duration>)
|
||||
{
|
||||
atomic.ConditionVariable_.wait(lock, [&]
|
||||
{return std::forward<decltype(condition_function)>(condition_function)(std::as_const(atomic.Value_));});
|
||||
return std::forward<decltype(atomic)>(atomic);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!atomic.ConditionVariable_.wait_for(lock, timeout, [&]
|
||||
{return std::forward<decltype(condition_function)>(condition_function)(std::as_const(atomic.Value_));}))
|
||||
{
|
||||
if constexpr (Nothrow) return false;
|
||||
else throw TimeoutException{};
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (Nothrow) return true;
|
||||
else return std::forward<decltype(atomic)>(atomic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <DecayedType ValueType> template <bool Nothrow, typename ConditionFunction, typename Duration>
|
||||
auto detail_::AtomicBase<ValueType, false>::lock_
|
||||
(auto&& atomic, ConditionFunction&& condition_function, Duration timeout)
|
||||
-> LockReturnType_<decltype(atomic), Duration, Nothrow> requires LockConstraint_<ConditionFunction, Duration>
|
||||
{
|
||||
if constexpr (std::is_null_pointer_v<ConditionFunction>)
|
||||
return {std::unique_lock{atomic.Mutex_}, std::experimental::make_observer(&atomic), {}};
|
||||
else if constexpr (std::is_null_pointer_v<Duration>)
|
||||
{
|
||||
std::unique_lock lock{atomic.Mutex_};
|
||||
atomic.ConditionVariable_.wait(lock, [&]
|
||||
{return std::forward<ConditionFunction>(condition_function)(std::as_const(atomic.Value_));});
|
||||
return {std::move(lock), std::experimental::make_observer(&atomic), {}};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_lock lock{atomic.Mutex_};
|
||||
if (!atomic.ConditionVariable_.wait_for(lock, timeout, [&]
|
||||
{return std::forward<ConditionFunction>(condition_function)(std::as_const(atomic.Value_));}))
|
||||
{
|
||||
if constexpr (Nothrow) return std::nullopt;
|
||||
else throw TimeoutException{};
|
||||
}
|
||||
else
|
||||
return {{std::move(lock), std::experimental::make_observer(&atomic), {}}};
|
||||
}
|
||||
}
|
||||
|
||||
template <DecayedType ValueType, bool UseLogger> Atomic<ValueType, UseLogger>::Atomic(const ValueType& value)
|
||||
: detail_::AtomicBase<ValueType, UseLogger>{value} {}
|
||||
template <DecayedType ValueType, bool UseLogger> Atomic<ValueType, UseLogger>::Atomic(ValueType&& value)
|
||||
: detail_::AtomicBase<ValueType, UseLogger>{std::move(value)} {}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool OtherUseLogger>
|
||||
Atomic<ValueType, UseLogger>::Atomic(const Atomic<ValueType, OtherUseLogger>& other)
|
||||
: detail_::AtomicBase<ValueType, UseLogger>{other} {}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool OtherUseLogger>
|
||||
Atomic<ValueType, UseLogger>::Atomic(Atomic<ValueType, OtherUseLogger>&& other)
|
||||
: detail_::AtomicBase<ValueType, UseLogger>{std::move(other)} {}
|
||||
template <DecayedType ValueType, bool UseLogger>
|
||||
Atomic<ValueType, UseLogger>& Atomic<ValueType, UseLogger>::operator=(const ValueType& value)
|
||||
{
|
||||
std::scoped_lock lock{DeepBase_::Mutex_};
|
||||
DeepBase_::Value_ = value;
|
||||
DeepBase_::ConditionVariable_.notify_all();
|
||||
return *this;
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger>
|
||||
Atomic<ValueType, UseLogger>& Atomic<ValueType, UseLogger>::operator=(ValueType&& value)
|
||||
{
|
||||
std::scoped_lock lock{DeepBase_::Mutex_};
|
||||
DeepBase_::Value_ = std::move(value);
|
||||
DeepBase_::ConditionVariable_.notify_all();
|
||||
return *this;
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool OtherUseLogger>
|
||||
Atomic<ValueType, UseLogger>& operator=(const Atomic<ValueType, OtherUseLogger>& other)
|
||||
{
|
||||
std::scoped_lock lock{DeepBase_::Mutex_};
|
||||
DeepBase_::Value_ = value;
|
||||
DeepBase_::ConditionVariable_.notify_all();
|
||||
return *this;
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool OtherUseLogger>
|
||||
Atomic<ValueType, UseLogger>& operator=(Atomic<ValueType, OtherUseLogger>&& other)
|
||||
{
|
||||
std::scoped_lock lock{DeepBase_::Mutex_};
|
||||
DeepBase_::Value_ = std::move(value);
|
||||
DeepBase_::ConditionVariable_.notify_all();
|
||||
return *this;
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> ValueType Atomic<ValueType, UseLogger>::get() const&
|
||||
{
|
||||
std::scoped_lock lock{DeepBase_::Mutex_};
|
||||
return DeepBase_::Value_;
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> ValueType Atomic<ValueType, UseLogger>::get() &&
|
||||
{
|
||||
std::scoped_lock lock{DeepBase_::Mutex_};
|
||||
return std::move(DeepBase_::Value_);
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> Atomic<ValueType, UseLogger>::operator ValueType() const&
|
||||
{return get();}
|
||||
template <DecayedType ValueType, bool UseLogger> Atomic<ValueType, UseLogger>::operator ValueType() &&
|
||||
{return std::move(*this).get();}
|
||||
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool ReturnFunctionResult>
|
||||
auto Atomic<ValueType, UseLogger>::apply(auto&& function) const&
|
||||
-> DeepBase_::template ApplyReturnType_<decltype(function), decltype(*this), ReturnFunctionResult>
|
||||
requires DeepBase_::template ApplyConstraint_<decltype(function), decltype(*this)>
|
||||
{return apply_<ReturnFunctionResult>(*this, std::forward<decltype(function)>(function));}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool ReturnFunctionResult>
|
||||
auto Atomic<ValueType, UseLogger>::apply(auto&& function) &
|
||||
-> DeepBase_::template ApplyReturnType_<decltype(function), decltype(*this), ReturnFunctionResult>
|
||||
requires DeepBase_::template ApplyConstraint_<decltype(function), decltype(*this)>
|
||||
{return apply_<ReturnFunctionResult>(*this, std::forward<decltype(function)>(function));}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool ReturnFunctionResult>
|
||||
auto Atomic<ValueType, UseLogger>::apply(auto&& function) &&
|
||||
-> DeepBase_::template ApplyReturnType_<decltype(function), decltype(*this), ReturnFunctionResult>
|
||||
requires DeepBase_::template ApplyConstraint_<decltype(function), decltype(*this)>
|
||||
{return apply_<ReturnFunctionResult>(std::move(*this), std::forward<decltype(function)>(function));}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool ReturnFunctionResult>
|
||||
auto Atomic<ValueType, UseLogger>::apply(auto&& function, auto&& condition_function) const&
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<decltype(function), decltype(*this), ReturnFunctionResult, decltype(condition_function)>
|
||||
requires DeepBase_::template ApplyConstraint_<decltype(function), decltype(*this), decltype(condition_function)>
|
||||
{
|
||||
return apply_<ReturnFunctionResult>
|
||||
(
|
||||
*this, std::forward<decltype(function)>(function),
|
||||
std::forward<decltype(condition_function)>(condition_function)
|
||||
);
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool ReturnFunctionResult>
|
||||
auto Atomic<ValueType, UseLogger>::apply(auto&& function, auto&& condition_function) &
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<decltype(function), decltype(*this), ReturnFunctionResult, decltype(condition_function)>
|
||||
requires DeepBase_::template ApplyConstraint_<decltype(function), decltype(*this), decltype(condition_function)>
|
||||
{
|
||||
return apply_<ReturnFunctionResult>
|
||||
(
|
||||
*this, std::forward<decltype(function)>(function),
|
||||
std::forward<decltype(condition_function)>(condition_function)
|
||||
);
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool ReturnFunctionResult>
|
||||
auto Atomic<ValueType, UseLogger>::apply(auto&& function, auto&& condition_function) &&
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<decltype(function), decltype(*this), ReturnFunctionResult, decltype(condition_function)>
|
||||
requires DeepBase_::template ApplyConstraint_<decltype(function), decltype(*this), decltype(condition_function)>
|
||||
{
|
||||
return apply_<ReturnFunctionResult>
|
||||
(
|
||||
std::move(*this), std::forward<decltype(function)>(function),
|
||||
std::forward<decltype(condition_function)>(condition_function)
|
||||
);
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool ReturnFunctionResult, bool Nothrow>
|
||||
auto Atomic<ValueType, UseLogger>::apply(auto&& function, auto&& condition_function, auto timeout) const&
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<
|
||||
decltype(function), decltype(*this), ReturnFunctionResult,
|
||||
decltype(condition_function), decltype(timeout), Nothrow
|
||||
> requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(*this), decltype(condition_function), decltype(timeout)>
|
||||
{
|
||||
return apply_<ReturnFunctionResult, Nothrow>
|
||||
(
|
||||
*this, std::forward<decltype(function)>(function),
|
||||
std::forward<decltype(condition_function)>(condition_function), timeout
|
||||
);
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool ReturnFunctionResult, bool Nothrow>
|
||||
auto Atomic<ValueType, UseLogger>::apply(auto&& function, auto&& condition_function, auto timeout) &
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<
|
||||
decltype(function), decltype(*this), ReturnFunctionResult,
|
||||
decltype(condition_function), decltype(timeout), Nothrow
|
||||
> requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(*this), decltype(condition_function), decltype(timeout)>
|
||||
{
|
||||
return apply_<ReturnFunctionResult, Nothrow>
|
||||
(
|
||||
*this, std::forward<decltype(function)>(function),
|
||||
std::forward<decltype(condition_function)>(condition_function), timeout
|
||||
);
|
||||
}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool ReturnFunctionResult, bool Nothrow>
|
||||
auto Atomic<ValueType, UseLogger>::apply(auto&& function, auto&& condition_function, auto timeout) &&
|
||||
-> DeepBase_::template ApplyReturnType_
|
||||
<
|
||||
decltype(function), decltype(*this), ReturnFunctionResult,
|
||||
decltype(condition_function), decltype(timeout), Nothrow
|
||||
> requires DeepBase_::template ApplyConstraint_
|
||||
<decltype(function), decltype(*this), decltype(condition_function), decltype(timeout)>
|
||||
{
|
||||
return apply_<ReturnFunctionResult, Nothrow>
|
||||
(
|
||||
std::move(*this), std::forward<decltype(function)>(function),
|
||||
std::forward<decltype(condition_function)>(condition_function), timeout
|
||||
);
|
||||
}
|
||||
|
||||
template <DecayedType ValueType, bool UseLogger>
|
||||
auto Atomic<ValueType, UseLogger>::wait(auto&& condition_function) const&
|
||||
-> DeepBase_::template WaitReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function)>
|
||||
{return wait_(*this, std::forward<decltype(condition_function)>(condition_function));}
|
||||
template <DecayedType ValueType, bool UseLogger>
|
||||
auto Atomic<ValueType, UseLogger>::wait(auto&& condition_function) &
|
||||
-> DeepBase_::template WaitReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function)>
|
||||
{return wait_(*this, std::forward<decltype(condition_function)>(condition_function));}
|
||||
template <DecayedType ValueType, bool UseLogger>
|
||||
auto Atomic<ValueType, UseLogger>::wait(auto&& condition_function) &&
|
||||
-> DeepBase_::template WaitReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function)>
|
||||
{return wait_(std::move(*this), std::forward<decltype(condition_function)>(condition_function));}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Nothrow>
|
||||
auto Atomic<ValueType, UseLogger>::wait(auto&& condition_function, auto timeout) const&
|
||||
-> DeepBase_::template WaitReturnType_
|
||||
<decltype(*this), decltype(condition_function), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function), decltype(timeout)>
|
||||
{return wait_<Nothrow>(*this, std::forward<decltype(condition_function)>(condition_function), timeout);}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Nothrow>
|
||||
auto Atomic<ValueType, UseLogger>::wait(auto&& condition_function, auto timeout) &
|
||||
-> DeepBase_::template WaitReturnType_
|
||||
<decltype(*this), decltype(condition_function), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function), decltype(timeout)>
|
||||
{return wait_<Nothrow>(*this, std::forward<decltype(condition_function)>(condition_function), timeout);}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Nothrow>
|
||||
auto Atomic<ValueType, UseLogger>::wait(auto&& condition_function, auto timeout) &&
|
||||
-> DeepBase_::template WaitReturnType_
|
||||
<decltype(*this), decltype(condition_function), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template WaitConstraint_<decltype(condition_function), decltype(timeout)>
|
||||
{
|
||||
return wait_<Nothrow>
|
||||
(std::move(*this), std::forward<decltype(condition_function)>(condition_function), timeout);
|
||||
}
|
||||
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Const> template <bool OtherConst>
|
||||
Atomic<ValueType, UseLogger>::Guard<Const>::Guard(const Guard<OtherConst>& other)
|
||||
requires (Const || !OtherConst)
|
||||
: Lock_{other.Lock_}, Value_{other.Value_} {}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Const>
|
||||
Atomic<ValueType, UseLogger>::Guard<Const>::Guard
|
||||
(decltype(Lock_)&& lock, decltype(Value_) value, CalledBy<detail_::AtomicBase<ValueType, UseLogger>>)
|
||||
: Lock_{std::move(lock)}, Value_{value} {}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Const>
|
||||
Atomic<ValueType, UseLogger>::Guard<Const>::~Guard()
|
||||
{Value_->ConditionVariable_.notify_all();}
|
||||
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Const>
|
||||
std::conditional_t<Const, const ValueType&, ValueType&>
|
||||
Atomic<ValueType, UseLogger>::Guard<Const>::operator*() const&
|
||||
{return Value_->Value_;}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Const>
|
||||
std::conditional_t<Const, const ValueType*, ValueType*>
|
||||
Atomic<ValueType, UseLogger>::Guard<Const>::operator->() const&
|
||||
{return &Value_->Value_;}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Const>
|
||||
std::conditional_t<Const, const ValueType&, ValueType&>
|
||||
Atomic<ValueType, UseLogger>::Guard<Const>::value() const&
|
||||
{return Value_->Value_;}
|
||||
|
||||
template <DecayedType ValueType, bool UseLogger> auto Atomic<ValueType, UseLogger>::lock() const&
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this)> requires DeepBase_::template LockConstraint_<>
|
||||
{return lock_(*this);}
|
||||
template <DecayedType ValueType, bool UseLogger> auto Atomic<ValueType, UseLogger>::lock() &
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this)> requires DeepBase_::template LockConstraint_<>
|
||||
{return lock_(*this);}
|
||||
template <DecayedType ValueType, bool UseLogger>
|
||||
auto Atomic<ValueType, UseLogger>::lock(auto&& condition_function) const&
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template LockConstraint_<decltype(condition_function)>
|
||||
{return lock_(*this, condition_function);}
|
||||
template <DecayedType ValueType, bool UseLogger>
|
||||
auto Atomic<ValueType, UseLogger>::lock(auto&& condition_function) &
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this), decltype(condition_function)>
|
||||
requires DeepBase_::template LockConstraint_<decltype(condition_function)>
|
||||
{return lock_(*this, condition_function);}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Nothrow>
|
||||
auto Atomic<ValueType, UseLogger>::lock(auto&& condition_function, auto timeout) const&
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template LockConstraint_<decltype(condition_function), decltype(timeout)>
|
||||
{return lock_<Nothrow>(*this, condition_function, timeout);}
|
||||
template <DecayedType ValueType, bool UseLogger> template <bool Nothrow>
|
||||
auto Atomic<ValueType, UseLogger>::lock(auto&& condition_function, auto timeout) &
|
||||
-> DeepBase_::template LockReturnType_<decltype(*this), decltype(timeout), Nothrow>
|
||||
requires DeepBase_::template LockConstraint_<decltype(condition_function), decltype(timeout)>
|
||||
{return lock_<Nothrow>(*this, condition_function, timeout);}
|
||||
}
|
||||
@@ -46,9 +46,11 @@ namespace biu
|
||||
= std::is_invocable_r_v<Result, Function, Args...>;
|
||||
|
||||
template <typename T> concept Arithmetic = std::is_arithmetic<T>::value || SpecializationOf<T, std::complex>;
|
||||
|
||||
template <typename T> concept Nullptr = std::is_null_pointer_v<std::remove_cvref_t<T>>;
|
||||
}
|
||||
using concepts::DecayedType, concepts::SpecializationOf, concepts::CompletedType, concepts::ImplicitlyConvertibleTo,
|
||||
concepts::ImplicitlyConvertibleFrom, concepts::ExplicitlyConvertibleTo, concepts::ExplicitlyConvertibleFrom,
|
||||
concepts::ConvertibleTo, concepts::ConvertibleFrom, concepts::ConstevalInvokable, concepts::Enumerable,
|
||||
concepts::InvocableWithResult, concepts::Arithmetic;
|
||||
concepts::InvocableWithResult, concepts::Arithmetic, concepts::Nullptr;
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
|
||||
namespace biu
|
||||
{
|
||||
namespace detail_
|
||||
namespace format::detail_
|
||||
{
|
||||
template <typename Char, Char... c> struct FormatLiteralHelper : protected BasicStaticString<Char, c...>
|
||||
{template <typename... Param> std::basic_string<Char> operator()(Param&&... param) const;};
|
||||
}
|
||||
inline namespace literals
|
||||
{ template <typename Char, Char... c> consteval detail_::FormatLiteralHelper<Char, c...> operator""_f(); }
|
||||
{ template <typename Char, Char... c> consteval format::detail_::FormatLiteralHelper<Char, c...> operator""_f(); }
|
||||
|
||||
namespace detail_
|
||||
namespace format::detail_
|
||||
{
|
||||
template <typename T> concept OptionalWrap
|
||||
= SpecializationOf<T, std::optional> || SpecializationOf<T, std::shared_ptr>
|
||||
@@ -46,8 +46,9 @@ namespace biu
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template <typename Char, biu::detail_::OptionalWrap Wrap> struct formatter<Wrap, Char>
|
||||
: biu::detail_::FormatterReuseProxy<typename biu::detail_::UnderlyingTypeOfOptionalWrap<Wrap>::Type, Char>
|
||||
template <typename Char, biu::format::detail_::OptionalWrap Wrap> struct formatter<Wrap, Char>
|
||||
: biu::format::detail_::FormatterReuseProxy
|
||||
<typename biu::format::detail_::UnderlyingTypeOfOptionalWrap<Wrap>::Type, Char>
|
||||
{
|
||||
template <typename FormatContext> auto format(const Wrap& wrap, FormatContext& ctx) const
|
||||
-> typename FormatContext::iterator;
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
namespace biu
|
||||
{
|
||||
template <typename Char, Char... c> template <typename... Param>
|
||||
std::basic_string<Char> detail_::FormatLiteralHelper<Char, c...>::operator() (Param&&... param) const
|
||||
std::basic_string<Char> format::detail_::FormatLiteralHelper<Char, c...>::operator() (Param&&... param) const
|
||||
{ return fmt::format(BasicStaticString<Char, c...>::StringView, std::forward<Param>(param)...); }
|
||||
template <typename Char, Char... c> consteval
|
||||
detail_::FormatLiteralHelper<Char, c...> literals::operator""_f()
|
||||
format::detail_::FormatLiteralHelper<Char, c...> literals::operator""_f()
|
||||
{ return {}; }
|
||||
|
||||
template <typename T, typename Char> constexpr
|
||||
auto detail_::FormatterReuseProxy<T, Char>::parse(fmt::basic_format_parse_context<Char>& ctx)
|
||||
auto format::detail_::FormatterReuseProxy<T, Char>::parse(fmt::basic_format_parse_context<Char>& ctx)
|
||||
-> typename fmt::basic_format_parse_context<Char>::iterator
|
||||
{
|
||||
if (ctx.begin() != ctx.end() && *ctx.begin() != '}')
|
||||
@@ -49,17 +49,17 @@ namespace biu
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template <typename Char, biu::detail_::OptionalWrap Wrap> template <typename FormatContext>
|
||||
template <typename Char, biu::format::detail_::OptionalWrap Wrap> template <typename FormatContext>
|
||||
auto formatter<Wrap, Char>::format(const Wrap& wrap, FormatContext& ctx) const
|
||||
-> typename FormatContext::iterator
|
||||
{
|
||||
using value_t = biu::detail_::UnderlyingTypeOfOptionalWrap<Wrap>::Type;
|
||||
using value_t = biu::format::detail_::UnderlyingTypeOfOptionalWrap<Wrap>::Type;
|
||||
auto format_value_type = [&, this](const value_t& value)
|
||||
{
|
||||
if constexpr (!fmt::is_formattable<value_t, Char>::value)
|
||||
return fmt::format_to(ctx.out(), "non-null unformattable value");
|
||||
else if constexpr (std::default_initializable<formatter<value_t>>)
|
||||
biu::detail_::FormatterReuseProxy<value_t, Char>::format(value, ctx);
|
||||
biu::format::detail_::FormatterReuseProxy<value_t, Char>::format(value, ctx);
|
||||
else fmt::format_to(ctx.out(), "{}", value);
|
||||
};
|
||||
fmt::format_to(ctx.out(), "(");
|
||||
|
||||
11
packages/biu/test/atomic.cpp
Normal file
11
packages/biu/test/atomic.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
# include <biu.hpp>
|
||||
int main()
|
||||
{
|
||||
using namespace biu::literals;
|
||||
biu::Atomic<std::string> a("hello");
|
||||
a = "world";
|
||||
a.apply([](auto& value) { value += "!"; });
|
||||
auto b = a.get();
|
||||
auto lock = a.lock(nullptr, nullptr);
|
||||
*lock = "!";
|
||||
}
|
||||
@@ -5,10 +5,5 @@ int main()
|
||||
using namespace biu::literals;
|
||||
|
||||
std::optional<int> a = 3;
|
||||
using b = biu::detail_::UnderlyingTypeOfOptionalWrap<decltype(a)>::Type;
|
||||
std::cout << "{}\n"_f(nameof::nameof_full_type<b>());
|
||||
std::cout << "{}\n"_f(biu::concepts::CompletedType<fmt::formatter<int, char>>);
|
||||
std::cout << "{}\n"_f(biu::concepts::CompletedType<fmt::formatter<std::shared_ptr<int>, char>>);
|
||||
std::cout << "{}\n"_f(fmt::is_formattable<int>::value);
|
||||
std::cout << "{}\n"_f(a);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user