diff --git a/local/pkgs/biu/include/biu/common.hpp b/local/pkgs/biu/include/biu/common.hpp index a882dbf4..64462c58 100644 --- a/local/pkgs/biu/include/biu/common.hpp +++ b/local/pkgs/biu/include/biu/common.hpp @@ -22,6 +22,8 @@ namespace biu using int128_t = __int128_t; using uint128_t = __uint128_t; + struct Empty {}; + struct CaseInsensitiveStringLessComparator { template constexpr bool operator()(const String& s1, const String& s2) const; @@ -64,11 +66,31 @@ namespace biu template using FallbackIfNoTypeDeclared = typename detail_::FallbackIfNoTypeDeclaredHelper::Type; - namespace detail_ { struct ExecResult { int exit_code; std::string stdout, stderr; }; } - detail_::ExecResult exec + namespace detail_ + { + template struct ExecResult + { + int exit_code; + std::conditional_t stdout; + std::conditional_t stderr; + }; + template + detail_::ExecResult exec + ( + std::filesystem::path program, std::vector args, std::optional stdin, + std::map extra_env + ); + } + template requires (!DirectStdin) + detail_::ExecResult exec ( - std::filesystem::path program, std::vector args, std::optional stdin, - std::map extra_env + std::filesystem::path program, std::vector args, std::optional stdin = {}, + std::map extra_env = {} + ); + template requires DirectStdin + detail_::ExecResult exec + ( + std::filesystem::path program, std::vector args, std::map extra_env = {} ); } } diff --git a/local/pkgs/biu/include/biu/common.tpp b/local/pkgs/biu/include/biu/common.tpp index c664d151..d9df6c8d 100644 --- a/local/pkgs/biu/include/biu/common.tpp +++ b/local/pkgs/biu/include/biu/common.tpp @@ -1,6 +1,7 @@ # pragma once # include # include +# include namespace biu::common { @@ -21,4 +22,56 @@ namespace biu::common [](char c1, char c2){return std::tolower(c1) < std::tolower(c2);} ); } -} \ No newline at end of file + template detail_::ExecResult exec + ( + std::filesystem::path program, std::vector args, std::optional stdin, + std::map extra_env + ) + { + namespace bp = boost::process; + bp::ipstream stdout_stream, stderr_stream; + bp::opstream input_stream; + auto&& stdout = + [&]{ if constexpr (directStdout) return bp::std_out > ::stdout; else return bp::std_out > stdout_stream; }(); + auto&& stderr = + [&]{ if constexpr (directStderr) return bp::std_err > ::stderr; else return bp::std_err > stderr_stream; }(); + auto&& input = [&] + { + if constexpr (directStdin) return bp::std_in < ::stdin; + else if (stdin) return bp::std_in < input_stream; else return bp::std_in < bp::null; + }(); + std::unique_ptr process; + bp::environment env = boost::this_process::environment(); + for (const auto& [key, value] : extra_env) env[key] = value; + process = std::make_unique(program.string(), bp::args(args), stdout, stderr, input, env); + if (stdin) { input << *stdin; input.pipe().close(); } + process->wait(); + return + { + process->exit_code(), + [&] + { + if constexpr (directStdout) return std::string{std::istreambuf_iterator{stdout.rdbuf()}, {}}; + else return Empty{}; + }(), + [&] + { + if constexpr (directStderr) return std::string{std::istreambuf_iterator{stderr.rdbuf()}, {}}; + else return Empty{}; + }() + }; + } + template requires (!DirectStdin) + detail_::ExecResult exec + ( + std::filesystem::path program, std::vector args, std::optional stdin, + std::map extra_env + ) + { return exec(program, args, stdin, extra_env); } + template requires DirectStdin + detail_::ExecResult exec + ( + std::filesystem::path program, std::vector args, std::map extra_env + ) + { return exec(program, args, {}, extra_env); } +} diff --git a/local/pkgs/biu/src/common.cpp b/local/pkgs/biu/src/common.cpp index d9904c19..b0de6c8f 100644 --- a/local/pkgs/biu/src/common.cpp +++ b/local/pkgs/biu/src/common.cpp @@ -1,45 +1,9 @@ # include # include # include -# include namespace biu { std::regex literals::operator""_re(const char* str, std::size_t len) { return std::regex{str, len}; } - namespace common - { - void block_forever() { std::promise().get_future().wait(); std::unreachable(); } - detail_::ExecResult exec - ( - std::filesystem::path program, std::vector args, std::optional stdin, - std::map extra_env - ) - { - namespace bp = boost::process; - bp::ipstream stdout, stderr; - bp::opstream input; - std::unique_ptr process; - bp::environment env = boost::this_process::environment(); - for (const auto& [key, value] : extra_env) env[key] = value; - if (stdin) - { - process = std::make_unique - (program.string(), bp::args(args), bp::std_out > stdout, bp::std_err > stderr, - bp::std_in < input, env); - input << *stdin; - input.pipe().close(); - } - else process = std::make_unique - (program.string(), bp::args(args), bp::std_out > stdout, bp::std_err > stderr, - bp::std_in < bp::null, env); - process->wait(); - return - { - process->exit_code(), - std::string{std::istreambuf_iterator{stdout.rdbuf()}, {}}, - std::string{std::istreambuf_iterator{stderr.rdbuf()}, {}} - }; - } - } - + namespace common { void block_forever() { std::promise().get_future().wait(); std::unreachable(); } } }