Skip to content

Commit

Permalink
Moved initial_draft.cpp into a unit test and got it building/running
Browse files Browse the repository at this point in the history
added dependency to stlab libraries.
  • Loading branch information
sean-parent committed Feb 21, 2024
1 parent 6edff83 commit d0017a0
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 300 deletions.
4 changes: 4 additions & 0 deletions Dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ function(chains_setup_dependencies)
# For each dependency, see if it's
# already been provided to us by a parent project

if(NOT TARGET stlab::libraries)
cpmaddpackage("gh:stlab/[email protected]")
endif()

if(NOT TARGET fmtlib::fmtlib)
cpmaddpackage("gh:fmtlib/fmt#9.1.0")
endif()
Expand Down
20 changes: 5 additions & 15 deletions include/chains/tuple.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include <tuple>
#include <utility>
#include <tuple> // std::apply, std::forward_as_tuple, std::tuple
#include <type_traits> // std::is_same_v
#include <utility> // std::forward, std::move
#include <variant> // std::monostate

#ifndef CHAIN_TUPLE_HPP
#define CHAIN_TUPLE_HPP

namespace chain::inline v0 {

Expand Down Expand Up @@ -35,19 +38,6 @@ auto operator|(tuple_pipeable<T>&& p, F& f) {
return tuple_pipeable{void_to_monostate(f)(std::move(p._value))};
}

/* REVISIT (sparent) : how to forward a value through `just`? */

template <class T>
struct just_ref {
T& _value;
just_ref(T& a) : _value{a} {}
};

template <class T, class F>
auto operator|(just_ref<T>&& p, F&& f) {
return tuple_pipeable{std::apply(std::forward<F>(f), std::move(p._value))};
}

} // namespace detail

//--------------------------------------------------------------------------------------------------
Expand Down
85 changes: 43 additions & 42 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ add_test(NAME cli.has_help COMMAND intro --help)
add_test(NAME cli.version_matches COMMAND intro --version)
set_tests_properties(cli.version_matches PROPERTIES PASS_REGULAR_EXPRESSION "${PROJECT_VERSION}")

add_executable(tests tests.cpp tuple_tests.cpp)
add_executable(tests tuple_tests.cpp initial_draft.cpp)
target_link_libraries(
tests
PRIVATE chains::chains_warnings
chains::chains_options
chains::sample_library
stlab::stlab
Catch2::Catch2WithMain)

if(WIN32 AND BUILD_SHARED_LIBS)
Expand All @@ -61,47 +62,47 @@ catch_discover_tests(
.xml)

# Add a file containing a set of constexpr tests
add_executable(constexpr_tests constexpr_tests.cpp)
target_link_libraries(
constexpr_tests
PRIVATE chains::chains_warnings
chains::chains_options
chains::sample_library
Catch2::Catch2WithMain)

catch_discover_tests(
constexpr_tests
TEST_PREFIX
"constexpr."
REPORTER
XML
OUTPUT_DIR
.
OUTPUT_PREFIX
"constexpr."
OUTPUT_SUFFIX
.xml)
# add_executable(constexpr_tests constexpr_tests.cpp)
# target_link_libraries(
# constexpr_tests
# PRIVATE chains::chains_warnings
# chains::chains_options
# chains::sample_library
# Catch2::Catch2WithMain)

# catch_discover_tests(
# constexpr_tests
# TEST_PREFIX
# "constexpr."
# REPORTER
# XML
# OUTPUT_DIR
# .
# OUTPUT_PREFIX
# "constexpr."
# OUTPUT_SUFFIX
# .xml)

# Disable the constexpr portion of the test, and build again this allows us to have an executable that we can debug when
# things go wrong with the constexpr testing
add_executable(relaxed_constexpr_tests constexpr_tests.cpp)
target_link_libraries(
relaxed_constexpr_tests
PRIVATE chains::chains_warnings
chains::chains_options
chains::sample_library
Catch2::Catch2WithMain)
target_compile_definitions(relaxed_constexpr_tests PRIVATE -DCATCH_CONFIG_RUNTIME_STATIC_REQUIRE)

catch_discover_tests(
relaxed_constexpr_tests
TEST_PREFIX
"relaxed_constexpr."
REPORTER
XML
OUTPUT_DIR
.
OUTPUT_PREFIX
"relaxed_constexpr."
OUTPUT_SUFFIX
.xml)
# add_executable(relaxed_constexpr_tests constexpr_tests.cpp)
# target_link_libraries(
# relaxed_constexpr_tests
# PRIVATE chains::chains_warnings
# chains::chains_options
# chains::sample_library
# Catch2::Catch2WithMain)
# target_compile_definitions(relaxed_constexpr_tests PRIVATE -DCATCH_CONFIG_RUNTIME_STATIC_REQUIRE)

# catch_discover_tests(
# relaxed_constexpr_tests
# TEST_PREFIX
# "relaxed_constexpr."
# REPORTER
# XML
# OUTPUT_DIR
# .
# OUTPUT_PREFIX
# "relaxed_constexpr."
# OUTPUT_SUFFIX
# .xml)
12 changes: 0 additions & 12 deletions test/constexpr_tests.cpp

This file was deleted.

221 changes: 4 additions & 217 deletions initial_draft.cpp → test/initial_draft.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@

#include <catch2/catch_test_macros.hpp>

#include <tuple>
#include <utility>

Expand Down Expand Up @@ -352,7 +355,7 @@ inline auto then(F&& future) {
using namespace std;
using namespace stlab;

int main() {
TEST_CASE("Initial draft", "[initial_draft]") {
auto a0 = on(default_executor) | [] {
cout << "Hello from thread: " << std::this_thread::get_id() << "\n";
return 42;
Expand Down Expand Up @@ -397,219 +400,3 @@ int main() {

pre_exit();
}

#if 0

#include <thread>
#include <tuple>

#include <stlab/concurrency/await.hpp>
#include <stlab/concurrency/default_executor.hpp>
#include <stlab/concurrency/future.hpp>

namespace stlab {namespace detail {

template <class T>
struct pipeable {
T _value;
pipeable(T&& a) : _value{std::move(a)} { }
};

template <class T, class F>
auto operator|(pipeable<T>&& p, F&& f) {
return pipeable{f(std::move(p._value))};
}

template <class T>
struct just {
T& _value;
just(T& a) : _value{a} { }
};

template <class T, class F>
auto operator|(just<T>&& p, F&& f) {
return pipeable{std::apply(std::forward<F>(f), p._value)};
}

}

/*
Operations on a chain:
chain(f) // a chain can be created from a function
chain(f, applyr) // optionally, an applyr can be provided
chain | f -> chain
compose(chain, chain) -> chain
// return applyr(op, args...) where op is a function that represents the composed functions in the chain.
operator()(args...) -> value
*/

template <class I, class... Fs>
class chain
{
I _applyr;
std::tuple<Fs...> _functions;

public:
// REVISIT: Should `forward_as_tuple(args...)` be `forward_as_tuple(std::forward<decltype(args)>(args)...)`?
static auto default_applyr = [](chain& c, auto&&... args) {
return std::apply([_args = std::forward_as_tuple(args...)](auto&&... functions) mutable {
return (detail::just{_args} | ... | functions);
}, c._functions)._value;
};

chain(I&& applyr, Fs&&... functions) : _applyr{std::forward<I>(applyr)}, _functions{std::make_tuple(std::forward<Fs>(functions)...)} {}
explicit chain(Fs&&... functions) : chain{default_applyr, std::forward<Fs>(functions)...} {}

template <class J>
chain(I&& applyr, chain<J, Fs...>&& c): _applyr{std::forward<I>(applyr)}, _functions{std::move(c._functions)} {}

template <class... Args>
auto operator()(Args&&... args) {
_applyr(*this, std::forward<Args>(args)...);
}

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

chain(chain&&) noexcept = default;
chain& operator=(chain&&) noexcept = default;
};

template <class E, class I, class... Fs>
auto resume_on(chain<I, Fs...>&& c, E&& executor) {
return chain{[_executor = std::forward<E>(executor), c = std::move(c)](auto& ch, auto&&... args) mutable {
return stlab::async(std::move(_executor), [_chain = chain{default_applyr, std::move(ch)}]() mutable {
return _chain();
});
}, std::identity{}};
}

#if 0

namespace detail {

template <class T>
struct pipeable {
T _value;
pipeable(T&& a) : _value{std::move(a)} { }
};

template <class T, class F>
auto operator|(pipeable<T>&& p, F&& f) {
return pipeable{f(std::move(p._value))};
}

template <class T>
struct just {
T& _value;

just(T& a) : _value{a} { }
};

template <class T, class F>
auto operator|(just<T>&& p, F&& f) {
return pipeable{std::apply(std::forward<F>(f), p._value)};
}

}


template <class... Fs>
struct chain {
static constexpr bool chainable{true};
std::tuple<Fs...> _functions;

template <class F>
using next_type = chain<Fs..., F>;

template <class C>
chain(C&&, std::tuple<Fs...>&& t) : _functions{std::move(t)} { }

chain(std::tuple<Fs...>&& t) : _functions{std::move(t)} { }

// chain(Fs&&... args) : _functions{std::forward<Fs>(args)...} { }

template <class... Args>
auto operator()(Args&&... args) {
return std::apply([_args = std::forward_as_tuple(args...)](auto&&... functions) mutable {
return (detail::just{_args} | ... | functions);
}, _functions)._value;
}
};

// REVISIT : This is binding the executer and arguments to a chainable. I need to factor out
// the bind/wrap operation as a build block for composing algorithms.

template <class E, class O, class... Fs>
struct spawner : chain<Fs...> {
E _executor;
O _op;

template<typename F>
using next_type = spawner<E, O, Fs..., F>;

template <class S>
spawner(S&& s, std::tuple<Fs...>&& t) : _executor{std::move(s._executor)}, _op{std::move(s._op)},
chain<Fs...>{std::move(t)} { }

spawner(E&& e, O&& op) : _executor{std::forward<E>(e)}, _op{std::forward<O>(op)}, chain<>{std::tuple{}} { }

auto operator()() {
return stlab::async(std::move(_executor), [_chain = chain{std::move(this->_functions)}, _op = std::move(_op)]() mutable {
return _chain(_op());
});
}
};


template <class C, class F>
auto operator|(C&& c, F&& f) requires C::chainable {
auto functions{std::tuple_cat(std::move(c._functions), std::make_tuple(std::forward<F>(f)))};
using next_type = C::template next_type<std::decay_t<F>>;
return next_type{std::move(c), std::move(functions)};
}

/*
return a chainable (void)->future<T> that will schedule the task and any chained operations on
the executer when apply. The `T` is the result type of the last chained operation.
*/

template <typename E, typename F>
auto schedule_on(E executor, F&& f) {
return spawner<std::decay_t<E>, std::decay_t<F>>{std::move(executor), std::forward<F>(f)};
}

#endif

}

#include <iostream>

using namespace std;
using namespace stlab;

int main() {
#if 0
stlab::chain c{[](int x) -> float { return x; }, [](float a){ return a + 0.5; }};
auto c2{std::move(c) | [](float a){ return std::to_string(a + 2.0); }};
std::cout << c2(42) << "\n";
#endif

auto a0 = schedule_on(default_executor, []{
cout << "Hello from thread: " << std::this_thread::get_id() << "\n";
return 42;
});

auto a1 = std::move(a0) | [](int x){
cout << "received: " << x << "\n";
return "forwarding: " + std::to_string(x + 1);
};

cout << "Main thread: " << std::this_thread::get_id() << "\n";
cout << "Ready to go async!\n";

std::cout << await(a1()) << "\n";

pre_exit();
}
#endif
Loading

0 comments on commit d0017a0

Please sign in to comment.