diff --git a/.github/workflows/build_nix.yml b/.github/workflows/build_nix.yml index eb32f7b..900eaa1 100644 --- a/.github/workflows/build_nix.yml +++ b/.github/workflows/build_nix.yml @@ -14,6 +14,6 @@ jobs: - name: "Build/Test" # contains slash so use quotes otherwise UB run: | - wget https://github.com/PhilipDeegan/mkn/releases/download/latest/mkn_nix - chmod +x mkn_nix - KLOG=3 ./mkn_nix clean build run -dtOp test -a "-std=c++17 -fPIC" + curl -Lo mkn https://github.com/mkn/mkn/releases/download/latest/mkn_nix + chmod +x mkn + KLOG=3 ./mkn clean build run -dtOp test -a "-std=c++17 -fPIC" diff --git a/.github/workflows/build_osx.yml b/.github/workflows/build_osx.yml index fbe07cd..641d1f4 100644 --- a/.github/workflows/build_osx.yml +++ b/.github/workflows/build_osx.yml @@ -14,6 +14,6 @@ jobs: - name: "Build/Test" # contains slash so use quotes otherwise UB run: | - wget https://github.com/PhilipDeegan/mkn/releases/download/latest/mkn_osx - chmod +x mkn_osx - KLOG=3 ./mkn_osx clean build run -dtOp test -a "-std=c++17 -fPIC" + curl -Lo mkn https://github.com/mkn/mkn/releases/download/latest/mkn_osx + chmod +x mkn + KLOG=3 ./mkn clean build run -dtOp test -a "-std=c++17 -fPIC" diff --git a/.github/workflows/build_win.yml b/.github/workflows/build_win.yml index a3fb51a..cf03709 100644 --- a/.github/workflows/build_win.yml +++ b/.github/workflows/build_win.yml @@ -12,6 +12,10 @@ jobs: steps: - uses: actions/checkout@v3 + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64 + - uses: ilammy/msvc-dev-cmd@v1 with: arch: amd64 @@ -22,5 +26,5 @@ jobs: MKN_CL_PREFERRED: 1 run: | # /bin/link interferes with cl/link.exe bash -c "rm /bin/link" - bash -c "curl -Lo mkn.exe https://github.com/PhilipDeegan/mkn/releases/download/latest/mkn.exe" + bash -c "curl -Lo mkn.exe https://github.com/mkn/mkn/releases/download/latest/mkn.exe" bash -c 'KLOG=3 ./mkn clean build run -dtKOp test -a "-EHsc -std:c++17"' diff --git a/.sublime-project b/.sublime-project new file mode 100644 index 0000000..13f8b3b --- /dev/null +++ b/.sublime-project @@ -0,0 +1,17 @@ +{ + "folders": + [ + { + "path": "." + } + ], + "settings": + { + "ClangFormat": + { + "binary": "clang-format-8", + "format_on_save": true, + "style": "file" + }, + } +} diff --git a/.sublime-project.sublime-workspace b/.sublime-project.sublime-workspace new file mode 100644 index 0000000..5a07207 --- /dev/null +++ b/.sublime-project.sublime-workspace @@ -0,0 +1,3 @@ +{ + "project": ".sublime-project" +} diff --git a/inc/mkn/kul/all.hpp b/inc/mkn/kul/all.hpp index 24acd29..84788a6 100644 --- a/inc/mkn/kul/all.hpp +++ b/inc/mkn/kul/all.hpp @@ -36,46 +36,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include "mkn/kul/span.hpp" + namespace mkn { namespace kul { -#define PRINT_LINE() std::cout << __LINE__ << std::endl - -namespace func { -template -using check = void; -} - -template -struct is_span_like : std::false_type {}; - -template -struct is_span_like().data())>, - func::check().size())>> : std::true_type {}; - -template -auto constexpr is_span_like_v = is_span_like::value; - template -void for_each(Container& container, Function && function) { +void for_each(Container& container, Function&& function) { std::for_each(std::begin(container), std::end(container), function); } template -bool any_of(Container const& container, Function && function) { +bool any_of(Container const& container, Function&& function) { return std::any_of(std::begin(container), std::end(container), function); } template -bool any_of(Container && container, Function && function) { +bool any_of(Container&& container, Function&& function) { return std::any_of(std::begin(container), std::end(container), function); } template -bool all_of(Container const& container, Function && function) { +bool all_of(Container const& container, Function&& function) { return std::all_of(std::begin(container), std::end(container), function); } template -bool all_of(Container && container, Function && function) { +bool all_of(Container&& container, Function&& function) { return all_of(container, function); } @@ -90,7 +75,7 @@ bool compare_to(T const& t, OP const& op, Args const&... args) { return ((op(args, t)) && ...); } template -bool compare_to(T && t, OP && op, Args &&... args) { +bool compare_to(T&& t, OP&& op, Args&&... args) { return compare_to(t, op, args...); } @@ -100,7 +85,7 @@ bool compare_to(T const& t, OP const& op, std::tuple const& tu return std::apply([&](auto const&... args) { return compare_to(t, op, args...); }, tuple); } template -bool compare_to(T && t, OP && op, std::tuple && tuple) { +bool compare_to(T&& t, OP&& op, std::tuple&& tuple) { return compare_to(t, op, tuple); } @@ -114,7 +99,7 @@ class All { return are(t, std::equal_to{}); } template - bool operator==(T && t) { + bool operator==(T&& t) { return are(t, std::equal_to{}); } @@ -123,7 +108,7 @@ class All { return are(t, std::not_equal_to{}); } template - bool operator!=(T && t) { + bool operator!=(T&& t) { return are(t, std::not_equal_to{}); } @@ -132,7 +117,7 @@ class All { return are(t, std::greater{}); } template - bool operator>(T && t) { + bool operator>(T&& t) { return are(t, std::greater{}); } @@ -141,7 +126,7 @@ class All { return are(t, std::less{}); } template - bool operator<(T && t) { + bool operator<(T&& t) { return are(t, std::less{}); } @@ -150,7 +135,7 @@ class All { return are(t, std::greater_equal{}); } template - bool operator>=(T && t) { + bool operator>=(T&& t) { return are(t, std::greater_equal{}); } @@ -159,7 +144,7 @@ class All { return are(t, std::less_equal{}); } template - bool operator<=(T && t) { + bool operator<=(T&& t) { return are(t, std::less_equal{}); } diff --git a/inc/mkn/kul/asio/log.hpp b/inc/mkn/kul/asio/log.hpp index d9ff0ef..cb18946 100644 --- a/inc/mkn/kul/asio/log.hpp +++ b/inc/mkn/kul/asio/log.hpp @@ -41,7 +41,8 @@ namespace log { class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; } // namespace log @@ -116,10 +117,14 @@ struct ErrMessage : public Message { ~ErrMessage() { LogMan::INSTANCE().err(ss.str()); } }; -#define KASIO_LOG_INF mkn::kul::asio::LogMessage(__FILE__, __func__, __LINE__, mkn::kul::log::mode::INF) -#define KASIO_LOG_ERR mkn::kul::asio::LogMessage(__FILE__, __func__, __LINE__, mkn::kul::log::mode::ERR) -#define KASIO_LOG_DBG mkn::kul::asio::LogMessage(__FILE__, __func__, __LINE__, mkn::kul::log::mode::DBG) -#define KASIO_LOG_TRC mkn::kul::asio::LogMessage(__FILE__, __func__, __LINE__, mkn::kul::log::mode::TRC) +#define KASIO_LOG_INF \ + mkn::kul::asio::LogMessage(__FILE__, __func__, __LINE__, mkn::kul::log::mode::INF) +#define KASIO_LOG_ERR \ + mkn::kul::asio::LogMessage(__FILE__, __func__, __LINE__, mkn::kul::log::mode::ERR) +#define KASIO_LOG_DBG \ + mkn::kul::asio::LogMessage(__FILE__, __func__, __LINE__, mkn::kul::log::mode::DBG) +#define KASIO_LOG_TRC \ + mkn::kul::asio::LogMessage(__FILE__, __func__, __LINE__, mkn::kul::log::mode::TRC) #define KASIO_LOG(sev) KLOG_##sev #define KASIO_OUT_NON mkn::kul::asio::OutMessage() diff --git a/inc/mkn/kul/cli.hpp b/inc/mkn/kul/cli.hpp index 78dc8c2..3f2ccd2 100644 --- a/inc/mkn/kul/cli.hpp +++ b/inc/mkn/kul/cli.hpp @@ -55,7 +55,8 @@ inline const std::string receive(std::string const &t = "") { class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; class ArgNotFoundException : public Exception { diff --git a/inc/mkn/kul/dbg.hpp b/inc/mkn/kul/dbg.hpp index 03fe007..ef531e0 100644 --- a/inc/mkn/kul/dbg.hpp +++ b/inc/mkn/kul/dbg.hpp @@ -71,16 +71,16 @@ class StackTrace { #endif // KUL_DBG_FUNC_ENTER #ifndef KUL_DBG_FUNC_ON_ENTER -#define KUL_DBG_FUNC_ON_ENTER \ +#define KUL_DBG_FUNC_ON_ENTER \ KOUT(TRC) << mkn::kul::LogMan::INSTANCE().str(m_fi, m_fu, m_li, mkn::kul::log::mode::TRC, "", \ - "[%M]: %T - %D : %F:%L fn(%N)") \ + "[%M]: %T - %D : %F:%L fn(%N)") \ << " - ENTERED"; #endif // KUL_DBG_FUNC_ON_ENTER #ifndef KUL_DBG_FUNC_ON_EXIT -#define KUL_DBG_FUNC_ON_EXIT \ +#define KUL_DBG_FUNC_ON_EXIT \ KOUT(TRC) << mkn::kul::LogMan::INSTANCE().str(m_fi, m_fu, m_li, mkn::kul::log::mode::TRC, "", \ - "[%M]: %T - %D : %F:%L fn(%N)") \ + "[%M]: %T - %D : %F:%L fn(%N)") \ << " - Function time: " << (mkn::kul::Now::MICROS() - m_start) << " μs"; #endif // KUL_DBG_FUNC_ON_EXIT diff --git a/inc/mkn/kul/except.hpp b/inc/mkn/kul/except.hpp index 2485178..4d9fcd6 100644 --- a/inc/mkn/kul/except.hpp +++ b/inc/mkn/kul/except.hpp @@ -142,8 +142,6 @@ class Exit : public Exception { } // namespace kul } // namespace mkn - - #define KEXCEPT(e, m) throw e(__FILE__, __LINE__, m) #define KEXCEPTSTR(e) throw e(__FILE__, __LINE__, "") #define KEXCEPTION(m) throw Exception(__FILE__, __LINE__, m) diff --git a/inc/mkn/kul/for.hpp b/inc/mkn/kul/for.hpp index 5913317..ba9aa3f 100644 --- a/inc/mkn/kul/for.hpp +++ b/inc/mkn/kul/for.hpp @@ -36,10 +36,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace mkn { namespace kul { -template +template struct Apply { - template - constexpr auto operator()(){ return std::integral_constant{}; } + template + constexpr auto operator()() { + return std::integral_constant{}; + } }; template @@ -55,17 +57,61 @@ constexpr auto apply_N(Apply&& f) { template constexpr void for_N(Fn&& fn) { -/* - for_N<2>([](auto ic) { - constexpr auto i = ic(); - // ... - }); -*/ + /* + for_N<2>([](auto ic) { + constexpr auto i = ic(); + // ... + }); + */ + + std::apply([&](auto... ics) { (fn(ics), ...); }, apply_N(Apply{})); +} - std::apply([&](auto ... ics) { (fn(ics), ...);}, apply_N(Apply{})); +template +auto generate(F&& f, std::size_t from, std::size_t to) { + using value_type = std::decay_t>; + std::vector v; + std::size_t count = to - from; + if (count > 0) v.reserve(count); + for (std::size_t i = from; i < to; ++i) v.emplace_back(f(i)); + return v; } +template +auto generate(F&& f, std::size_t count) { + return generate(std::forward(f), 0, count); +} +template +auto generate(F&& f, Container& container) { + using T = typename Container::value_type; + using value_type = std::decay_t>; + std::vector v1; + if (container.size() > 0) v1.reserve(container.size()); + for (auto& v : container) v1.emplace_back(f(v)); + return v1; +} + +template +auto constexpr generate_array__(F& f, std::array& arr) { + return f(arr[Idx]); +} + +template +auto constexpr generate_array_(F& f, std::array& arr, + std::integer_sequence) { + return std::array{generate_array__(f, arr)...}; +} + +template +auto constexpr generate(F&& f, std::array& arr) { + return generate_array_(f, arr, std::make_integer_sequence{}); +} + +template +auto generate(F&& f, Container&& v) { + return generate(std::forward(f), v); +} } // namespace kul } // namespace mkn diff --git a/inc/mkn/kul/log.hpp b/inc/mkn/kul/log.hpp index 2852f66..27fb756 100644 --- a/inc/mkn/kul/log.hpp +++ b/inc/mkn/kul/log.hpp @@ -55,7 +55,8 @@ enum mode { OFF = -1, NON = 0, INF, ERR, DBG, OTH, TRC }; class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; } // namespace log @@ -183,9 +184,7 @@ class Message { std::stringstream ss; const log::mode &m; - Message(const log::mode &_m) : m(_m) { - ss.precision(22); - } + Message(const log::mode &_m) : m(_m) { ss.precision(22); } public: template @@ -276,6 +275,6 @@ class DBoMessage : public Message { #define KERR mkn::kul::ErrMessage() -#endif //!defined(_MKN_KUL_DISABLE_KLOG_DEF_) +#endif //! defined(_MKN_KUL_DISABLE_KLOG_DEF_) #endif /* _MKN_KUL_LOG_HPP_ */ diff --git a/inc/mkn/kul/os.hpp b/inc/mkn/kul/os.hpp index 978698f..4a2f672 100644 --- a/inc/mkn/kul/os.hpp +++ b/inc/mkn/kul/os.hpp @@ -53,7 +53,8 @@ class File; namespace fs { class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; class TimeStamps { diff --git a/inc/mkn/kul/os/nixish/ipc.hpp b/inc/mkn/kul/os/nixish/ipc.hpp index 831c7fe..d16600f 100644 --- a/inc/mkn/kul/os/nixish/ipc.hpp +++ b/inc/mkn/kul/os/nixish/ipc.hpp @@ -55,7 +55,8 @@ namespace ipc { class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; class IPCCall { diff --git a/inc/mkn/kul/os/nixish/os.bot.hpp b/inc/mkn/kul/os/nixish/os.bot.hpp index 854c817..3fbd7c6 100644 --- a/inc/mkn/kul/os/nixish/os.bot.hpp +++ b/inc/mkn/kul/os/nixish/os.bot.hpp @@ -111,7 +111,9 @@ inline std::string EOL() { return "\n"; } namespace user { inline mkn::kul::Dir home() { return Dir(env::GET("HOME")); } -inline mkn::kul::Dir home(std::string const &app) { return Dir(Dir::JOIN(env::GET("HOME"), "." + app)); } +inline mkn::kul::Dir home(std::string const &app) { + return Dir(Dir::JOIN(env::GET("HOME"), "." + app)); +} } // namespace user diff --git a/inc/mkn/kul/os/nixish/src/os/dir/files.ipp b/inc/mkn/kul/os/nixish/src/os/dir/files.ipp index e07551f..bc9a2f8 100644 --- a/inc/mkn/kul/os/nixish/src/os/dir/files.ipp +++ b/inc/mkn/kul/os/nixish/src/os/dir/files.ipp @@ -37,7 +37,7 @@ std::vector mkn::kul::Dir::files(bool recursive) const KTHROW(fs DIR *dir = opendir(path().c_str()); struct dirent *entry = readdir(dir); while (entry != NULL) { - if ( !mkn::kul::Dir(JOIN(real(), entry->d_name)).is()) fs.push_back(File(entry->d_name, *this)); + if (!mkn::kul::Dir(JOIN(real(), entry->d_name)).is()) fs.push_back(File(entry->d_name, *this)); entry = readdir(dir); } closedir(dir); diff --git a/inc/mkn/kul/os/nixish/src/proc/run.ipp b/inc/mkn/kul/os/nixish/src/proc/run.ipp index 5418a6a..cd4eb02 100644 --- a/inc/mkn/kul/os/nixish/src/proc/run.ipp +++ b/inc/mkn/kul/os/nixish/src/proc/run.ipp @@ -133,8 +133,7 @@ void mkn::kul::Process::run() KTHROW(mkn::kul::proc::Exception) { /* SETUP EnvVars */ // SET ENV, it's a forked process so it doesn't matter - // it'll die soon, like you. - for (auto const &ev : vars()) - env::SET(ev.first.c_str(), ev.second.c_str()); + for (auto const &ev : vars()) env::SET(ev.first.c_str(), ev.second.c_str()); if (!this->directory().empty()) mkn::kul::env::CWD(this->directory()); exit(this->child()); diff --git a/inc/mkn/kul/os/nixish/src/signal/handler.ipp b/inc/mkn/kul/os/nixish/src/signal/handler.ipp index 83f04b0..5cb6446 100644 --- a/inc/mkn/kul/os/nixish/src/signal/handler.ipp +++ b/inc/mkn/kul/os/nixish/src/signal/handler.ipp @@ -38,7 +38,7 @@ void kul_sig_handler(int s, siginfo_t *info, void *v) { for (auto &f : mkn::kul::SignalStatic::INSTANCE().in) f(s); if (s == SIGSEGV) for (auto &f : mkn::kul::SignalStatic::INSTANCE().se) f(s); - if (s == SIGSEGV && !mkn::kul::SignalStatic::INSTANCE().q) { + if (s == SIGSEGV && !mkn::kul::SignalStatic::INSTANCE().q) { auto tid = mkn::kul::this_thread::id(); ucontext_t *uc = (ucontext_t *)v; printf("[bt] Stacktrace:\n"); diff --git a/inc/mkn/kul/os/nixish/src/signal/stacktrace.ipp b/inc/mkn/kul/os/nixish/src/signal/stacktrace.ipp index 85c234b..45aa143 100644 --- a/inc/mkn/kul/os/nixish/src/signal/stacktrace.ipp +++ b/inc/mkn/kul/os/nixish/src/signal/stacktrace.ipp @@ -32,8 +32,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This file is included by other files and is not in itself syntactically correct. -inline std::vector stacktrace(ucontext_t */*uc*/ = nullptr, int /*start*/ = 2) { - +inline std::vector stacktrace(ucontext_t * /*uc*/ = nullptr, int /*start*/ = 2) { // std::vector stacktrace(ucontext_t *uc, int start) { // constexpr size_t max_trace = 128; std::string const invalid = "??:0"; diff --git a/inc/mkn/kul/os/nixish/sys.hpp b/inc/mkn/kul/os/nixish/sys.hpp index b64e17c..c06d7e8 100644 --- a/inc/mkn/kul/os/nixish/sys.hpp +++ b/inc/mkn/kul/os/nixish/sys.hpp @@ -45,22 +45,15 @@ namespace mkn { namespace kul { namespace sys { -template +template class SharedFunction; class SharedLibrary { - template - friend class SharedFunction; - - private: - bool _loaded = 0; - void *_handle; - const mkn::kul::File _f; - public: - SharedLibrary(mkn::kul::File const &f) KTHROW(Exception) : _f(f) { + SharedLibrary(mkn::kul::File const &f, int const flags = __MKN_KUL_SYS_DLOPEN__) KTHROW(Exception) + : _f(f) { if (!_f) KEXCEPSTREAM << "Library attempted to be loaded does not exist: " << _f.full(); - _handle = dlopen(_f.real().c_str(), __MKN_KUL_SYS_DLOPEN__); + _handle = dlopen(_f.real().c_str(), flags); if (!_handle) KEXCEPSTREAM << "Cannot load library: " << f << " - Error: " << dlerror(); _loaded = 1; } @@ -68,15 +61,19 @@ class SharedLibrary { if (_loaded) dlclose(_handle); dlerror(); } - const mkn::kul::File file() const { return _f; } -}; + auto &file() const { return _f; } -template -class SharedFunction { private: - F *_funcP; - SharedLibrary &_lib; + bool _loaded = 0; + void *_handle; + mkn::kul::File const _f; + + template + friend class SharedFunction; +}; +template +class SharedFunction { public: SharedFunction(SharedLibrary &lib, std::string const &f) KTHROW(Exception) : _lib(lib) { _funcP = (F *)dlsym(_lib._handle, f.c_str()); @@ -84,22 +81,19 @@ class SharedFunction { if (dlsym_error) KEXCEPSTREAM << "Cannot load symbol create " << dlsym_error; } ~SharedFunction() { dlerror(); } - F *pointer() { return _funcP; } -}; - -template -class SharedClass { - typedef T *construct_t(); - typedef void destruct_t(T *t); + auto pointer() { return _funcP; } private: - SharedLibrary _lib; - SharedFunction _c; - SharedFunction _d; + F *_funcP; + SharedLibrary &_lib; +}; +template +class SharedClass { public: SharedClass(mkn::kul::File const &f, std::string const &c, std::string const &d) KTHROW(Exception) : _lib(f), _c(_lib, c), _d(_lib, d) {} + virtual ~SharedClass() {} protected: @@ -112,6 +106,14 @@ class SharedClass { t = nullptr; if (t) KEXCEPSTREAM << "Dynamically loaded class was not destroyed"; } + + private: + typedef T *construct_t(); + typedef void destruct_t(T *t); + + SharedLibrary _lib; + SharedFunction _c; + SharedFunction _d; }; } // namespace sys diff --git a/inc/mkn/kul/os/threads.hpp b/inc/mkn/kul/os/threads.hpp index f7d249a..2b279b7 100644 --- a/inc/mkn/kul/os/threads.hpp +++ b/inc/mkn/kul/os/threads.hpp @@ -65,7 +65,8 @@ inline void nSleep(unsigned long const &nanos) { namespace threading { class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; class InterruptionException : public Exception { public: @@ -86,7 +87,7 @@ class AThread { virtual void join() = 0; bool started() const { return s; } bool finished() const { return f; } - auto& exception() const { return ep; } + auto &exception() const { return ep; } void rethrow() { if (ep) std::rethrow_exception(ep); } @@ -103,4 +104,3 @@ class AThread { #endif #endif // _MKN_KUL_OS_THREADS_HPP_ - diff --git a/inc/mkn/kul/os/win/ipc.hpp b/inc/mkn/kul/os/win/ipc.hpp index dc204c5..29d4731 100644 --- a/inc/mkn/kul/os/win/ipc.hpp +++ b/inc/mkn/kul/os/win/ipc.hpp @@ -51,7 +51,8 @@ namespace ipc { class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; class Server { @@ -76,7 +77,8 @@ class Server { 0, // client time-out NULL); // default security attribute if (hPipe == INVALID_HANDLE_VALUE) - KEXCEPT(mkn::kul::ipc::Exception, "CreateNamedPipe failed: " + std::to_string(GetLastError())); + KEXCEPT(mkn::kul::ipc::Exception, + "CreateNamedPipe failed: " + std::to_string(GetLastError())); } protected: @@ -111,7 +113,8 @@ class Server { } Server(const int16_t &lp = -1) KTHROW(Exception) : lp(lp), - uuid(_MKN_KUL_IPC_UUID_PREFIX_ + std::string("pid\\") + std::to_string(mkn::kul::this_proc::id())) { + uuid(_MKN_KUL_IPC_UUID_PREFIX_ + std::string("pid\\") + + std::to_string(mkn::kul::this_proc::id())) { start(); } Server(std::string const &ui, const int16_t &lp = -1) KTHROW(Exception) @@ -156,7 +159,9 @@ class Client { public: virtual ~Client() { stop(); } - Client(std::string const &ui) KTHROW(Exception) : uuid(_MKN_KUL_IPC_UUID_PREFIX_ + ui) { start(); } + Client(std::string const &ui) KTHROW(Exception) : uuid(_MKN_KUL_IPC_UUID_PREFIX_ + ui) { + start(); + } Client(const int16_t &pid) KTHROW(Exception) : uuid(_MKN_KUL_IPC_UUID_PREFIX_ + std::string("pid\\") + std::to_string(pid)) { start(); @@ -166,7 +171,8 @@ class Client { LPTSTR lpvMessage = _strdup(m.c_str()); cbToWrite = (lstrlen(lpvMessage) + 1) * sizeof(TCHAR); if (!WriteFile(hPipe, lpvMessage, cbToWrite, &cbWritten, NULL)) - KEXCEPT(mkn::kul::ipc::Exception, "WriteFile to pipe failed: " + std::to_string(GetLastError())); + KEXCEPT(mkn::kul::ipc::Exception, + "WriteFile to pipe failed: " + std::to_string(GetLastError())); } }; diff --git a/inc/mkn/kul/os/win/os.bot.hpp b/inc/mkn/kul/os/win/os.bot.hpp index 86471ab..ff31783 100644 --- a/inc/mkn/kul/os/win/os.bot.hpp +++ b/inc/mkn/kul/os/win/os.bot.hpp @@ -62,7 +62,9 @@ bool mkn::kul::Dir::mk() const { } bool mkn::kul::Dir::root() const { return is() && real().size() == 3; } -bool mkn::kul::File::is() const { return !name().empty() && (bool)std::ifstream(_d.join(_n).c_str()); } +bool mkn::kul::File::is() const { + return !name().empty() && (bool)std::ifstream(_d.join(_n).c_str()); +} bool mkn::kul::File::rm() const { if (is()) { _unlink(_d.join(_n).c_str()); diff --git a/inc/mkn/kul/os/win/src/proc/run.cpp b/inc/mkn/kul/os/win/src/proc/run.cpp index 6d0fd24..8a5f419 100644 --- a/inc/mkn/kul/os/win/src/proc/run.cpp +++ b/inc/mkn/kul/os/win/src/proc/run.cpp @@ -53,9 +53,10 @@ std::string pipeIn = "\\\\.\\Pipe\\kul_proc_in." + std::to_string(this_proc::id( ss.str() + "." + std::to_string(pipeID); LPSTR lPipeOut = _strdup(pipeOut.c_str()); -g_hChildStd_OUT_Wr = ::CreateNamedPipeA(lPipeOut, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, - __MKN_KUL_PROCESS_BUFFER__, __MKN_KUL_PROCESS_BUFFER__, 0, &sa); +g_hChildStd_OUT_Wr = + ::CreateNamedPipeA(lPipeOut, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, + __MKN_KUL_PROCESS_BUFFER__, __MKN_KUL_PROCESS_BUFFER__, 0, &sa); if (!g_hChildStd_OUT_Wr) error(__LINE__, "CreatePipe failed"); g_hChildStd_OUT_Rd = ::CreateFileA(lPipeOut, GENERIC_READ, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); @@ -64,9 +65,10 @@ if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) error(__LINE__, "SetHandleInformation failed"); LPSTR lPipeErr = _strdup(pipeErr.c_str()); -g_hChildStd_ERR_Wr = ::CreateNamedPipeA(lPipeErr, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, - __MKN_KUL_PROCESS_BUFFER__, __MKN_KUL_PROCESS_BUFFER__, 0, &sa); +g_hChildStd_ERR_Wr = + ::CreateNamedPipeA(lPipeErr, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, + __MKN_KUL_PROCESS_BUFFER__, __MKN_KUL_PROCESS_BUFFER__, 0, &sa); if (!g_hChildStd_ERR_Wr) error(__LINE__, "CreatePipe failed"); g_hChildStd_ERR_Rd = ::CreateFileA(lPipeErr, GENERIC_READ, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0); diff --git a/inc/mkn/kul/os/win/src/signal/se_handler.cpp b/inc/mkn/kul/os/win/src/signal/se_handler.cpp index 4289584..f8e3795 100644 --- a/inc/mkn/kul/os/win/src/signal/se_handler.cpp +++ b/inc/mkn/kul/os/win/src/signal/se_handler.cpp @@ -39,7 +39,7 @@ uint16_t sig = pExceptionInfo->ExceptionRecord->ExceptionCode; if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) kul_sig_function_handler(sig = 11); -if ( !mkn::kul::SignalStatic::INSTANCE().q) { +if (!mkn::kul::SignalStatic::INSTANCE().q) { HANDLE process = GetCurrentProcess(); SymInitialize(process, NULL, TRUE); diff --git a/inc/mkn/kul/proc.hpp b/inc/mkn/kul/proc.hpp index e9a0d3d..764fbdc 100644 --- a/inc/mkn/kul/proc.hpp +++ b/inc/mkn/kul/proc.hpp @@ -57,7 +57,8 @@ namespace proc { class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; class ExitException : public mkn::kul::proc::Exception { @@ -79,15 +80,14 @@ class Call { void setCWD() { if (d.size()) { cwd = mkn::kul::env::CWD(); - if ( !mkn::kul::env::CWD(d)) KEXCEPTION("FAILED TO SET DIRECTORY: " + d); + if (!mkn::kul::env::CWD(d)) KEXCEPTION("FAILED TO SET DIRECTORY: " + d); } } public: ~Call() { if (d.size()) mkn::kul::env::CWD(cwd); - for (auto const &oldEv : oldEvs) - mkn::kul::env::SET(oldEv.first.c_str(), oldEv.second.c_str()); + for (auto const &oldEv : oldEvs) mkn::kul::env::SET(oldEv.first.c_str(), oldEv.second.c_str()); } Call(std::string const &_s, std::string const &_d = "") : d(_d), s(_s) { setCWD(); } Call(std::string const &_s, const mkn::kul::hash::map::S2S &evs, std::string const &_d = "") diff --git a/inc/mkn/kul/scm.hpp b/inc/mkn/kul/scm.hpp index d6e9103..5700393 100644 --- a/inc/mkn/kul/scm.hpp +++ b/inc/mkn/kul/scm.hpp @@ -42,7 +42,8 @@ namespace scm { class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; class NotFoundException : public mkn::kul::Exception { @@ -88,7 +89,7 @@ class Git : public SCM { try { KLOG(DBG) << mkn::kul::String::LINES(pc.outs())[0]; p.start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { KEXCEPT(Exception, "SCM ERROR - Checking local branch") << p.toString(); } auto ret = mkn::kul::String::SPLIT(mkn::kul::String::LINES(pc.outs())[0], "/").back(); @@ -104,7 +105,7 @@ class Git : public SCM { << "--show-current"; try { p.start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { KEXCEPT(Exception, "SCM ERROR - Checking local branch"); } return mkn::kul::String::LINES(pc.outs())[0]; @@ -120,7 +121,7 @@ class Git : public SCM { if (!v.empty()) p.arg("-b").arg(v); try { p.arg(d).start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { dr.rm(); KEXCEPT(Exception, "SCM ERROR - Check remote dependency location / version"); } @@ -137,7 +138,7 @@ class Git : public SCM { if (!r.empty() && !v.empty()) p.arg(v); try { p.start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { KEXCEPT(Exception, "SCM ERROR - Check remote dependency location / version"); } } @@ -147,7 +148,7 @@ class Git : public SCM { mkn::kul::ProcessCapture pc(p); try { p.arg("remote").arg("-v").start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { KERR << pc.errs(); KEXCEPT(Exception, "SCM ERROR " + std::string(e.what())); } @@ -165,7 +166,7 @@ class Git : public SCM { mkn::kul::ProcessCapture pc(p); try { p.arg("rev-parse").arg(b.empty() ? "HEAD" : b).start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { KERR << pc.errs(); KEXCEPT(Exception, "SCM ERROR " + std::string(e.what())); } @@ -180,7 +181,7 @@ class Git : public SCM { mkn::kul::ProcessCapture pc(p); try { p.arg("ls-remote").arg(url).arg(b).start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { KERR << pc.errs(); KEXCEPT(Exception, "SCM ERROR " + std::string(e.what())); } @@ -196,7 +197,7 @@ class Git : public SCM { mkn::kul::ProcessCapture pc(p); try { p.arg("status").arg("-sb").start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { KERR << pc.errs(); KEXCEPT(Exception, "SCM ERROR " + std::string(e.what())); } @@ -208,7 +209,7 @@ class Git : public SCM { p << "status"; if (!full) p << "--short"; p.start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { KEXCEPT(Exception, "SCM ERROR " + std::string(e.what())); } } @@ -216,7 +217,7 @@ class Git : public SCM { mkn::kul::Process p("git", d); try { p.arg("diff").start(); - } catch (mkn::kul::proc::ExitException const& e) { + } catch (mkn::kul::proc::ExitException const &e) { KEXCEPT(Exception, "SCM ERROR " + std::string(e.what())); } } diff --git a/inc/mkn/kul/serial/cli.arg.end.hpp b/inc/mkn/kul/serial/cli.arg.end.hpp index 434df07..f61ee7f 100644 --- a/inc/mkn/kul/serial/cli.arg.end.hpp +++ b/inc/mkn/kul/serial/cli.arg.end.hpp @@ -34,7 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if defined(_MKN_WITH_IO_CEREAL_) template -void save(Archive &ar) const { +void save(Archive& ar) const { auto convert_to_std_map = [](mkn::kul::hash::map::S2S const& s) -> std::unordered_map { std::unordered_map ret; @@ -44,7 +44,7 @@ void save(Archive &ar) const { ar(convert_to_std_map(vals)); } template -void load(Archive &ar) { +void load(Archive& ar) { auto convert_to_kul_map = [](std::unordered_map const& s) -> mkn::kul::hash::map::S2S { mkn::kul::hash::map::S2S ret; diff --git a/inc/mkn/kul/sort.hpp b/inc/mkn/kul/sort.hpp new file mode 100644 index 0000000..535ed81 --- /dev/null +++ b/inc/mkn/kul/sort.hpp @@ -0,0 +1,178 @@ +/** +Copyright (c) 2020, Philip Deegan. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Philip Deegan nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _MKN_KUL_SORT_HPP_ +#define _MKN_KUL_SORT_HPP_ + +#include +#include +#include + +#include "mkn/kul/span.hpp" + +namespace mkn { +namespace kul { + +namespace detail { + +auto constexpr LT_fn = [](auto const& x, auto const& y) constexpr { return x < y; }; +using LT = decltype(LT_fn); + +auto constexpr GT_fn = [](auto const& x, auto const& y) constexpr { return x > y; }; +using GT = decltype(GT_fn); + +auto constexpr accessor_fn = [](auto& c) constexpr -> auto& { return c; }; +using Accessor = decltype(accessor_fn); + +auto constexpr swaper_fn = [](auto& x, auto& y) constexpr { std::swap(x, y); }; +using Swaper = decltype(swaper_fn); + +} // namespace detail + +template +class QuickSorter { + public: + QuickSorter(C& c_, LT const& lt_, GT const& gt_, + Accessor accessor_ = detail::accessor_fn, // + Swaper swaper_ = detail::swaper_fn) + : c{c_}, lt{lt_}, gt{gt_}, accessor{accessor_}, swaper{swaper_} {} + + void sort(S l, S r) { + auto i = l, j = r; + auto const half = v[(l + r) / 2]; + do { + while (fn0(v[i], half)) i++; + while (fn1(v[j], half)) j--; + if (i <= j) { + swaper(v_[i], v_[j]); + i++, j--; + } + } while (i <= j); + if (l < j) sort(l, j); + if (i < r) sort(i, r); + } + + void sort() { sort(0, c.size() - 1); } + + private: + C& c; + + LT const& lt; + GT const& gt; + + Accessor const& accessor; + Swaper const& swaper; + + decltype(accessor(c))& v_ = accessor(c); + decltype(accessor(c)) const& v = accessor(c); + + auto static constexpr _fn0(LT const& lt_, GT const& gt_) -> auto const& { + if constexpr (ascending) + return lt_; + else + return gt_; + } + auto static constexpr _fn1(LT const& lt_, GT const& gt_) -> auto const& { + if constexpr (ascending) + return gt_; + else + return lt_; + } + + using Fn0 = std::conditional_t; + using Fn1 = std::conditional_t; + Fn0 const& fn0 = _fn0(lt, gt); + Fn1 const& fn1 = _fn1(lt, gt); +}; + +template +void sort(Container& c, S start, S end) { + using QS = QuickSorter; + QS{c, detail::LT_fn, detail::GT_fn}.sort(start, end); +} + +template +void sort(Container& c, LT const& lt, GT const& gt) { + using QS = QuickSorter; + QS{c, lt, gt}.sort(); +} + +template +void sort(Container& c) { + using QS = QuickSorter; + sort(c, detail::LT_fn, detail::GT_fn); +} + +template +void para_sort(Container& c, LT const& lt, GT const& gt, std::uint8_t n_threads = 2) { + using V = typename Container::value_type; + auto constexpr PT = CL / sizeof(V); + if (PT < 1) n_threads = 1; // no point + + auto bytes = c.size() * sizeof(V); + auto each = c.size() / n_threads; + auto even = bytes % CL == 0; + auto cls = bytes / CL + (even ? 0 : 1); + auto off = (cls / n_threads) * PT; + + std::vector threads; + threads.reserve(n_threads - 1); + std::vector starts(n_threads, 0); + std::vector ends(n_threads, c.size() - 1); + + for (std::size_t i = 1; i < n_threads; ++i) { + starts[i] = off * i; + ends[i - 1] = starts[i] - 1; + } + + using QS = QuickSorter; + for (std::size_t i = 1; i < n_threads; ++i) + threads.emplace_back([&, i]() { QS{c, lt, gt}.sort(starts[i], ends[i]); }); + + QS{c, lt, gt}.sort(starts[0], ends[0]); + for (auto& thread : threads) + if (thread.joinable()) thread.join(); + + if (n_threads > 1) QS{c, lt, gt}.sort(); +} + +template +void para_sort(Container& c, std::uint8_t n_threads = 2) { + para_sort(c, detail::LT_fn, detail::GT_fn, n_threads); +} + +} // namespace kul +} // namespace mkn + +#endif /* _MKN_KUL_SORT_HPP_ */ diff --git a/inc/mkn/kul/span.hpp b/inc/mkn/kul/span.hpp index b034ea1..c63b4c4 100644 --- a/inc/mkn/kul/span.hpp +++ b/inc/mkn/kul/span.hpp @@ -33,12 +33,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include + #include "mkn/kul/decltype.hpp" namespace mkn { namespace kul { - template struct is_span_like : std::false_type {}; @@ -141,7 +141,6 @@ struct SpanSet { std::vector m_vec; }; - } // namespace kul } // namespace mkn diff --git a/inc/mkn/kul/sys.hpp b/inc/mkn/kul/sys.hpp index 5b32e09..5e0c3b3 100644 --- a/inc/mkn/kul/sys.hpp +++ b/inc/mkn/kul/sys.hpp @@ -39,7 +39,8 @@ namespace sys { class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; } // namespace sys diff --git a/inc/mkn/kul/threads.hpp b/inc/mkn/kul/threads.hpp index 6c78ad5..eac7e4a 100644 --- a/inc/mkn/kul/threads.hpp +++ b/inc/mkn/kul/threads.hpp @@ -243,7 +243,8 @@ class ConcurrentThreadQueue { _thread.interrupt(); return *this; } - virtual ConcurrentThreadQueue &finish(const uint64_t &nWait = 1000000) KTHROW(mkn::kul::Exception) { + virtual ConcurrentThreadQueue &finish(const uint64_t &nWait = 1000000) + KTHROW(mkn::kul::Exception) { while (_up) { this_thread::nSleep(nWait); { @@ -281,7 +282,7 @@ class ConcurrentThreadQueue { return true; } - std::exception_ptr const& exception() const { return _thread.exception(); } + std::exception_ptr const &exception() const { return _thread.exception(); } void rethrow() { if (_thread.exception()) std::rethrow_exception(_thread.exception()); diff --git a/inc/mkn/kul/tuple.hpp b/inc/mkn/kul/tuple.hpp index 09043b6..1191cad 100644 --- a/inc/mkn/kul/tuple.hpp +++ b/inc/mkn/kul/tuple.hpp @@ -31,7 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef _MKN_KUL_TUPLE_HPP_ #define _MKN_KUL_TUPLE_HPP_ -#include +#include #include #include "mkn/kul/for.hpp" diff --git a/inc/mkn/kul/yaml.hpp b/inc/mkn/kul/yaml.hpp index baaee50..31af0bc 100644 --- a/inc/mkn/kul/yaml.hpp +++ b/inc/mkn/kul/yaml.hpp @@ -55,7 +55,8 @@ class NodeValidator; class Exception : public mkn::kul::Exception { public: - Exception(char const *f, uint16_t const &l, std::string const &s) : mkn::kul::Exception(f, l, s) {} + Exception(char const *f, uint16_t const &l, std::string const &s) + : mkn::kul::Exception(f, l, s) {} }; enum NodeType { NON = 0, STRING, LIST, MAP }; diff --git a/mkn.yaml b/mkn.yaml index abe48f5..62e3c03 100644 --- a/mkn.yaml +++ b/mkn.yaml @@ -31,20 +31,20 @@ profile: - name: test parent: lib inc: . - main: test/test.cpp + main: tst/test.cpp mode: none dep: google.test if_arg: win_shared: -DGTEST_LINKED_AS_SHARED_LIBRARY=1 - - name: bench + - name: usage parent: lib - main: test/bench.cpp - dep: google.benchmark + main: tst/usage.cpp - - name: usage + - name: bench parent: lib - main: test/usage.cpp + dep: google.benchmark + test: res/bench/(\w).cpp - name: format mod: | diff --git a/test/bench.cpp b/res/bench/bench.cpp similarity index 100% rename from test/bench.cpp rename to res/bench/bench.cpp diff --git a/res/bench/sort.cpp b/res/bench/sort.cpp new file mode 100644 index 0000000..659bcf0 --- /dev/null +++ b/res/bench/sort.cpp @@ -0,0 +1,69 @@ +// #include "mkn/kul/log.hpp" + +#include +#include +#include + +#include "mkn/kul/sort.hpp" + +#if __has_include("benchmark/benchmark.h") +#include "benchmark/benchmark.h" +#else +#include "benchmark/benchmark_api.h" +#endif + +namespace mkn::kul { + +static std::vector SIZES{/*100000,*/ 5000000}; + +template +struct SortFixture : public benchmark::Fixture { + public: + void SetUp(::benchmark::State const& state) override {} + + void TearDown(::benchmark::State const& /*state*/) override {} + + void solve(::benchmark::State& state) { + std::uint32_t size = state.range(0); + + auto gen = [&]() { + std::random_device rd; + std::seed_seq seed_seq{rd(), rd(), rd(), rd(), rd(), rd(), rd()}; + return std::mt19937_64(seed_seq); + }(); + + std::vector vec(size); + + std::uniform_real_distribution dist{0, 10000}; + for (std::size_t i = 0; i < size; ++i) vec[i] = dist(gen); + + for (auto _ : state) + if constexpr (std) + std::sort(vec.begin(), vec.end()); + else + mkn::kul::sort(vec); + } +}; + +BENCHMARK_TEMPLATE_DEFINE_F(SortFixture, std_double, double, true)(benchmark::State& state) { + solve(state); +} +BENCHMARK_REGISTER_F(SortFixture, std_double) + ->Unit(benchmark::kNanosecond) + ->Threads(1) + ->ArgsProduct({SIZES}); + +BENCHMARK_TEMPLATE_DEFINE_F(SortFixture, _double, double, false)(benchmark::State& state) { + solve(state); +} +BENCHMARK_REGISTER_F(SortFixture, _double) + ->Unit(benchmark::kNanosecond) + ->Threads(1) + ->ArgsProduct({SIZES}); + +} // namespace mkn::kul + +int main(int argc, char** argv) { + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); +} \ No newline at end of file diff --git a/test/test.cpp b/tst/test.cpp similarity index 97% rename from test/test.cpp rename to tst/test.cpp index 4de3d22..dcd4de1 100644 --- a/test/test.cpp +++ b/tst/test.cpp @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "mkn/kul/proc.hpp" #include "mkn/kul/threads.hpp" #include "mkn/kul/span.hpp" +#include "mkn/kul/sort.hpp" #include "mkn/kul/tuple.hpp" #ifdef _WIN32 @@ -65,6 +66,7 @@ auto tryCatch = [](std::vector> funcs, bool katch) { #include "test/proc.ipp" #include "test/string.ipp" #include "test/span.ipp" +#include "test/sort.ipp" int main(int argc, char *argv[]) { KOUT(NON) << __FILE__; diff --git a/test/test/cli.ipp b/tst/test/cli.ipp similarity index 100% rename from test/test/cli.ipp rename to tst/test/cli.ipp diff --git a/test/test/except.ipp b/tst/test/except.ipp similarity index 100% rename from test/test/except.ipp rename to tst/test/except.ipp diff --git a/test/test/io.ipp b/tst/test/io.ipp similarity index 100% rename from test/test/io.ipp rename to tst/test/io.ipp diff --git a/test/test/math.ipp b/tst/test/math.ipp similarity index 100% rename from test/test/math.ipp rename to tst/test/math.ipp diff --git a/test/test/os.ipp b/tst/test/os.ipp similarity index 100% rename from test/test/os.ipp rename to tst/test/os.ipp diff --git a/test/test/proc.ipp b/tst/test/proc.ipp similarity index 100% rename from test/test/proc.ipp rename to tst/test/proc.ipp diff --git a/tst/test/sort.ipp b/tst/test/sort.ipp new file mode 100644 index 0000000..efa7ada --- /dev/null +++ b/tst/test/sort.ipp @@ -0,0 +1,185 @@ + + +TEST(QSort, ascending) { + std::vector v{1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, + 3, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9}; + mkn::kul::sort(v); + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} + +TEST(QSort, half) { + std::vector v{1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, + 3, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9}; + auto start = v.size() / 2; + auto end = v.size() - 1; + mkn::kul::sort(v, start, end); + auto prev = v[start]; + for (std::size_t i = start + 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} + +TEST(QSort, descending) { + auto constexpr ascending = false; + std::vector v{1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, + 3, 7, 8, 9, 2, 3, 4, 5, 6, 7, 8, 9}; + mkn::kul::sort(v); + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_GE(prev, v[i]); + prev = v[i]; + } +} + +TEST(QSort, parallel_ascending0) { // 128 values + std::vector v{1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, + 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, + 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, + 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 3, 7, 8, 9, 2, 3, 4, 5, 6, 7, + 8, 9, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 2, 3, 3, 2, + 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4}; + mkn::kul::para_sort(v); + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} + +TEST(QSort, parallel_ascending1) { // 126 values + std::vector v{1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, + 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, + 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, + 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 3, 7, 8, 9, 2, 3, + 4, 5, 6, 7, 8, 9, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, + 3, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1}; + mkn::kul::para_sort(v); + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} + +TEST(QSort, parallel_ascending2) { // 4 values + // defaults to serial if elements are smaller than a cache line + std::vector v{1, 2, 3, 1}; + mkn::kul::para_sort(v); + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} + +TEST(QSort, parallel_ascending3) { // 128 values + std::vector v{1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, + 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, + 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, + 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 3, 7, 8, 9, 2, 3, 4, 5, 6, 7, + 8, 9, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 2, 3, 3, 2, + 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4}; + mkn::kul::para_sort(v, 3); + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} + +TEST(QSort, parallel_ascending4) { // 126 values + std::vector v{1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, + 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, + 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, + 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 3, 7, 8, 9, 2, 3, + 4, 5, 6, 7, 8, 9, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, + 3, 2, 3, 3, 2, 1, 6, 1, 6, 4, 1, 2, 3, 1, 2, 3, 3, 2, 1, 6, 1}; + mkn::kul::para_sort(v, 3); + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} + +auto constexpr arr_LT_fn = [](auto const& x, auto const& y) { + for (std::int16_t i = 0; i < x.size(); ++i) + if (x[i] < y[i]) + return true; + else if (x[i] != y[i]) + return false; + return false; +}; + +auto constexpr arr_GT_fn = [](auto const& x, auto const& y) { + for (std::int16_t i = 0; i < x.size(); ++i) + if (x[i] > y[i]) + return true; + else if (x[i] != y[i]) + return false; + return false; +}; + +TEST(QSort, ascending_array) { + using C = std::vector>; + // clang-format off + C v{{{1, 2, 3}, {3, 3, 3}, {2, 1, 2}, {3, 1, 3}, + {1, 3, 1}, {0, 2, 0}, {2, 0, 2}, {0, 0, 1}, + {1, 1, 0}, {4, 0, 4}, {0, 0, 4}, {4,4,0} + }}; + // clang-format on + + mkn::kul::sort(v, arr_LT_fn, arr_GT_fn); + + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} + +TEST(QSort, ascending_array1) { + using C = std::vector>; + // clang-format off + C v{{{1, 2, 3}, {3, 3, 3}, {2, 1, 2}, {3, 1, 3}, + {1, 3, 1}, {0, 2, 0}, {2, 0, 2}, {0, 0, 1}, + {1, 1, 0}, {4, 0, 4}, {0, 0, 4}, {4,4,0} + }}; + // clang-format on + + mkn::kul::sort(v); // will break in C++20? + + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} + +TEST(QSort, para_ascending_array1) { + using C = std::vector>; + // clang-format off + C v{{{1, 2, 3}, {3, 3, 3}, {2, 1, 2}, {3, 1, 3}, + {1, 3, 1}, {0, 2, 0}, {2, 0, 2}, {0, 0, 1}, + {1, 1, 0}, {4, 0, 4}, {0, 0, 4}, {4,4,0}, + {1, 2, 3}, {3, 3, 3}, {2, 1, 2}, {3, 1, 3}, + {1, 3, 1}, {0, 2, 0}, {2, 0, 2}, {0, 0, 1}, + {1, 1, 0}, {4, 0, 4}, {0, 0, 4}, {4,4,0}, + {1, 2, 3}, {3, 3, 3}, {2, 1, 2}, {3, 1, 3}, + {1, 3, 1}, {0, 2, 0}, {2, 0, 2}, {0, 0, 1} + }}; + // clang-format on + + mkn::kul::para_sort(v); // will break in C++20? + + auto prev = v[0]; + for (std::size_t i = 1; i < v.size(); ++i) { + EXPECT_LE(prev, v[i]); + prev = v[i]; + } +} diff --git a/test/test/span.ipp b/tst/test/span.ipp similarity index 100% rename from test/test/span.ipp rename to tst/test/span.ipp diff --git a/test/test/string.ipp b/tst/test/string.ipp similarity index 96% rename from test/test/string.ipp rename to tst/test/string.ipp index 937d939..bfbc204 100644 --- a/test/test/string.ipp +++ b/tst/test/string.ipp @@ -32,7 +32,9 @@ TEST(StringOperations, SplitByEscapedChar) { TEST(StringOperations, String_2_UInt16_t_invalid_tooLarge) { tryCatch( {// toolarge - []() { mkn::kul::String::UINT16(std::to_string((std::numeric_limits::max)() + 10)); }}, + []() { + mkn::kul::String::UINT16(std::to_string((std::numeric_limits::max)() + 10)); + }}, true); } TEST(StringOperations, String_2_UInt16_t_invalid_tooNegative) { @@ -57,7 +59,9 @@ TEST(StringOperations, String_2_UInt16_t_valid) { TEST(StringOperations, String_2_Int16_t_invalid_tooLarge) { tryCatch( {// toolarge - []() { mkn::kul::String::INT16(std::to_string((std::numeric_limits::max)() + 10)); }}, + []() { + mkn::kul::String::INT16(std::to_string((std::numeric_limits::max)() + 10)); + }}, true); } TEST(StringOperations, String_2_Int16_t_invalid_tooNegative) { diff --git a/test/usage.cpp b/tst/usage.cpp similarity index 97% rename from test/usage.cpp rename to tst/usage.cpp index 6d162c9..5bc560e 100644 --- a/test/usage.cpp +++ b/tst/usage.cpp @@ -154,7 +154,7 @@ class Test { KUL_DBG_FUNC_ENTER; Catch c; mkn::kul::Signal sig; // Windows: each thread requires own handler, static - // singleton otherwise so only ever one. + // singleton otherwise so only ever one. sig.segv(std::bind(&Catch::print, std::ref(c), std::placeholders::_1)); // Vector of // functions to call @@ -219,9 +219,10 @@ class Test { } { - std::vector argV{{mkn::kul::cli::Arg('f', "flag"), - mkn::kul::cli::Arg('m', "maybe_value", mkn::kul::cli::ArgType::MAYBE), - mkn::kul::cli::Arg('o', "option", mkn::kul::cli::ArgType::STRING)}}; + std::vector argV{ + {mkn::kul::cli::Arg('f', "flag"), + mkn::kul::cli::Arg('m', "maybe_value", mkn::kul::cli::ArgType::MAYBE), + mkn::kul::cli::Arg('o', "option", mkn::kul::cli::ArgType::STRING)}}; std::vector cmdV{{"COMMAND"}}; mkn::kul::cli::Args args(cmdV, argV);