Skip to content

Commit

Permalink
Add and test race_unity.
Browse files Browse the repository at this point in the history
  • Loading branch information
evoskuil committed May 22, 2024
1 parent d1fd1d6 commit fbc67ff
Show file tree
Hide file tree
Showing 10 changed files with 408 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ test_libbitcoin_network_test_SOURCES = \
test/async/enable_shared_from_base.cpp \
test/async/race_quality.cpp \
test/async/race_speed.cpp \
test/async/race_unity.cpp \
test/async/race_volume.cpp \
test/async/subscriber.cpp \
test/async/thread.cpp \
Expand Down Expand Up @@ -235,6 +236,7 @@ include_bitcoin_network_async_HEADERS = \
include/bitcoin/network/async/handlers.hpp \
include/bitcoin/network/async/race_quality.hpp \
include/bitcoin/network/async/race_speed.hpp \
include/bitcoin/network/async/race_unity.hpp \
include/bitcoin/network/async/race_volume.hpp \
include/bitcoin/network/async/subscriber.hpp \
include/bitcoin/network/async/thread.hpp \
Expand All @@ -256,6 +258,7 @@ include_bitcoin_network_impl_async_HEADERS = \
include/bitcoin/network/impl/async/enable_shared_from_base.ipp \
include/bitcoin/network/impl/async/race_quality.ipp \
include/bitcoin/network/impl/async/race_speed.ipp \
include/bitcoin/network/impl/async/race_unity.ipp \
include/bitcoin/network/impl/async/race_volume.ipp \
include/bitcoin/network/impl/async/subscriber.ipp \
include/bitcoin/network/impl/async/unsubscriber.ipp
Expand Down
1 change: 1 addition & 0 deletions builds/cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ if (with-tests)
"../../test/async/enable_shared_from_base.cpp"
"../../test/async/race_quality.cpp"
"../../test/async/race_speed.cpp"
"../../test/async/race_unity.cpp"
"../../test/async/race_volume.cpp"
"../../test/async/subscriber.cpp"
"../../test/async/thread.cpp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<ClCompile Include="..\..\..\..\test\async\enable_shared_from_base.cpp" />
<ClCompile Include="..\..\..\..\test\async\race_quality.cpp" />
<ClCompile Include="..\..\..\..\test\async\race_speed.cpp" />
<ClCompile Include="..\..\..\..\test\async\race_unity.cpp" />
<ClCompile Include="..\..\..\..\test\async\race_volume.cpp" />
<ClCompile Include="..\..\..\..\test\async\subscriber.cpp" />
<ClCompile Include="..\..\..\..\test\async\thread.cpp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
<ClCompile Include="..\..\..\..\test\async\race_speed.cpp">
<Filter>src\async</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\async\race_unity.cpp">
<Filter>src\async</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\test\async\race_volume.cpp">
<Filter>src\async</Filter>
</ClCompile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\handlers.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_quality.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_speed.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_unity.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_volume.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\subscriber.hpp" />
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\thread.hpp" />
Expand Down Expand Up @@ -266,6 +267,7 @@
<None Include="..\..\..\..\include\bitcoin\network\impl\async\enable_shared_from_base.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_quality.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_speed.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_unity.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_volume.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\subscriber.ipp" />
<None Include="..\..\..\..\include\bitcoin\network\impl\async\unsubscriber.ipp" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,9 @@
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_speed.hpp">
<Filter>include\bitcoin\network\async</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_unity.hpp">
<Filter>include\bitcoin\network\async</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\include\bitcoin\network\async\race_volume.hpp">
<Filter>include\bitcoin\network\async</Filter>
</ClInclude>
Expand Down Expand Up @@ -634,6 +637,9 @@
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_speed.ipp">
<Filter>include\bitcoin\network\impl\async</Filter>
</None>
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_unity.ipp">
<Filter>include\bitcoin\network\impl\async</Filter>
</None>
<None Include="..\..\..\..\include\bitcoin\network\impl\async\race_volume.ipp">
<Filter>include\bitcoin\network\impl\async</Filter>
</None>
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/network.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <bitcoin/network/async/handlers.hpp>
#include <bitcoin/network/async/race_quality.hpp>
#include <bitcoin/network/async/race_speed.hpp>
#include <bitcoin/network/async/race_unity.hpp>
#include <bitcoin/network/async/race_volume.hpp>
#include <bitcoin/network/async/subscriber.hpp>
#include <bitcoin/network/async/thread.hpp>
Expand Down
87 changes: 87 additions & 0 deletions include/bitcoin/network/async/race_unity.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS)
*
* This file is part of libbitcoin.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBBITCOIN_NETWORK_ASYNC_RACE_UNITY_HPP
#define LIBBITCOIN_NETWORK_ASYNC_RACE_UNITY_HPP

#include <memory>
#include <tuple>
#include <utility>
#include <bitcoin/system.hpp>
#include <bitcoin/network/define.hpp>

namespace libbitcoin {
namespace network {

/// Not thread safe.
/// Used in node validation chaser to invoke upon complete, with first error.
/// race_unity invokes complete(args) provided at start(complete), with args
/// from first failed call to finish(args), with failure determined by first
/// argument in 'args', at the last expected invocation of finish(...), based
/// on the constructor 'size' parameter.
template <typename... Args>
class race_unity final
{
public:
typedef std::shared_ptr<race_unity> ptr;
typedef std::function<void(Args...)> handler;

DELETE_COPY_MOVE(race_unity);

race_unity(size_t size) NOEXCEPT;
~race_unity() NOEXCEPT;

/// True if the race_unity is running.
inline bool running() const NOEXCEPT;

/// False implies invalid usage.
bool start(handler&& complete) NOEXCEPT;

/// True implies winning finisher (last invocation, none failed).
/// First arg is an 'error code', cast to bool (failed if true).
/// There may be no winner, in which case last finish is invoked.
bool finish(const Args&... args) NOEXCEPT;

private:
template <size_t... Pack>
using unpack = std::index_sequence<Pack...>;
using packed = std::tuple<std::decay_t<Args>...>;
using sequence = std::index_sequence_for<Args...>;

template<size_t... Index>
void invoker(const handler& complete, const packed& args,
unpack<Index...>) NOEXCEPT;
bool invoke() NOEXCEPT;
bool set_failure(bool failure) NOEXCEPT;

// This is thread safe.
const size_t size_;

// These are not thread safe.
packed args_{};
bool failure_{};
size_t runners_{};
std::shared_ptr<handler> complete_{};
};

} // namespace network
} // namespace libbitcoin

#include <bitcoin/network/impl/async/race_unity.ipp>

#endif
142 changes: 142 additions & 0 deletions include/bitcoin/network/impl/async/race_unity.ipp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/**
* Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS)
*
* This file is part of libbitcoin.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBBITCOIN_NETWORK_ASYNC_RACE_UNITY_IPP
#define LIBBITCOIN_NETWORK_ASYNC_RACE_UNITY_IPP

#include <memory>
#include <tuple>
#include <utility>
#include <bitcoin/system.hpp>
#include <bitcoin/network/define.hpp>

namespace libbitcoin {
namespace network {

template <typename... Args>
race_unity<Args...>::
race_unity(size_t size) NOEXCEPT
: size_(size)
{
}

template <typename... Args>
race_unity<Args...>::
~race_unity() NOEXCEPT
{
BC_ASSERT_MSG(!running() && !complete_, "deleting running race_unity");
}

template <typename... Args>
inline bool race_unity<Args...>::
running() const NOEXCEPT
{
return to_bool(runners_);
}

template <typename... Args>
bool race_unity<Args...>::
start(handler&& complete) NOEXCEPT
{
// false implies logic error.
if (running())
return false;

BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
complete_ = std::make_shared<handler>(std::forward<handler>(complete));
BC_POP_WARNING()

failure_ = false;
runners_ = size_;
return true;
}

template <typename... Args>
bool race_unity<Args...>::
finish(const Args&... args) NOEXCEPT
{
// false implies logic error.
if (!running())
return false;

// First argument (by convention) determines failure.
// Capture parameter pack as tuple of copied arguments.
auto values = std::tuple<Args...>(args...);
const auto& ec = std::get<0>(values);
const auto failer = set_failure(!!ec);

// Save args for failer (first failure) or last success.
const auto last = (runners_ == one);
if (failer || (last && !failure_))
args_ = std::move(values);

// false invoke implies logic error.
return invoke() && last && !failure_;
}

// private
// ----------------------------------------------------------------------------

template <typename... Args>
bool race_unity<Args...>::
set_failure(bool failure) NOEXCEPT
{
// Return is failer (first to fail) and set failure.
failure &= !failure_;
failure_ |= failure;
return failure;
}

template <typename... Args>
bool race_unity<Args...>::
invoke() NOEXCEPT
{
// false implies logic error.
if (!running())
return false;

--runners_;
if (running())
return true;

// false implies logic error.
if (!complete_)
return false;

// Invoke completion handler.
invoker(*complete_, args_, sequence{});

// Clear all resources.
complete_.reset();
args_ = {};
return true;
}

template <typename... Args>
template<size_t... Index>
void race_unity<Args...>::
invoker(const handler& complete, const packed& args, unpack<Index...>) NOEXCEPT
{
// Expand tuple into parameter pack.
complete(std::get<Index>(args)...);
}

} // namespace network
} // namespace libbitcoin

#endif
Loading

0 comments on commit fbc67ff

Please sign in to comment.