From 2dca29b5ebb509bc601b0aa4db5ff69352cfb614 Mon Sep 17 00:00:00 2001 From: PhilipDeegan Date: Tue, 20 Feb 2024 14:33:43 +0000 Subject: [PATCH] add zip utility (#44) --- inc/mkn/kul/cli.hpp | 2 +- inc/mkn/kul/zip.hpp | 97 ++++++++++++++++++++++++++++ mkn.yaml | 1 + test/test.cpp | 38 +---------- test/test/{cli.ipp => cli.cpp} | 4 ++ test/test/{except.ipp => except.cpp} | 4 ++ test/test/{io.ipp => io.cpp} | 8 ++- test/test/{math.ipp => math.cpp} | 4 ++ test/test/{os.ipp => os.cpp} | 5 ++ test/test/{proc.ipp => proc.cpp} | 4 ++ test/test/{span.ipp => span.cpp} | 5 ++ test/test/{string.ipp => string.cpp} | 19 ++++++ test/test/test_common.hpp | 28 ++++++++ test/test/zip.cpp | 27 ++++++++ 14 files changed, 206 insertions(+), 40 deletions(-) create mode 100644 inc/mkn/kul/zip.hpp rename test/test/{cli.ipp => cli.cpp} (85%) rename test/test/{except.ipp => except.cpp} (76%) rename test/test/{io.ipp => io.cpp} (95%) rename test/test/{math.ipp => math.cpp} (93%) rename test/test/{os.ipp => os.cpp} (92%) rename test/test/{proc.ipp => proc.cpp} (92%) rename test/test/{span.ipp => span.cpp} (93%) rename test/test/{string.ipp => string.cpp} (98%) create mode 100644 test/test/test_common.hpp create mode 100644 test/test/zip.cpp diff --git a/inc/mkn/kul/cli.hpp b/inc/mkn/kul/cli.hpp index 7ca3333..00fc406 100644 --- a/inc/mkn/kul/cli.hpp +++ b/inc/mkn/kul/cli.hpp @@ -197,7 +197,7 @@ class Args { std::stringstream ss; for (std::size_t i = j + 1; i < argc; ++i) ss << argv[i] << " "; rest_ = ss.str(); - if(rest_.size()) rest_.pop_back(); + if (rest_.size()) rest_.pop_back(); break; // assumes end } if (c.compare("---") == 0) KEXCEPT(Exception, "Illegal argument ---"); diff --git a/inc/mkn/kul/zip.hpp b/inc/mkn/kul/zip.hpp new file mode 100644 index 0000000..aea9cfa --- /dev/null +++ b/inc/mkn/kul/zip.hpp @@ -0,0 +1,97 @@ +/** +Copyright (c) 2023, 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_IO_HPP_ +#define _MKN_KUL_IO_HPP_ + +#include +#include + +namespace mkn::kul { + +template +struct Element { + using C = std::tuple_element_t; + using T = typename C::value_type; // const containers do not have const value_types + using value_type = std::conditional_t, T const&, T&>; +}; + +template +constexpr auto tuple_element_value_type_refs_(Tuple, std::index_sequence const&&) + -> std::tuple::value_type...>; + +template +auto constexpr tuple_element_value_type_refs() + -> decltype(tuple_element_value_type_refs_(std::tuple{}, + std::make_index_sequence{})); + +template +constexpr auto get_tuple_element_value_type_refs_(Tuple& tup, std::size_t index, + std::index_sequence const&&) { + return std::forward_as_tuple(std::get(tup)[index]...); +} +template +auto constexpr get_tuple_element_value_type_refs(Tuple& tuple, std::size_t index) { + return get_tuple_element_value_type_refs_(tuple, index, + std::make_index_sequence>{}); +} + +template +struct Zipit { + auto operator*() { return get_tuple_element_value_type_refs(args, idx); } + bool operator==(Zipit const& that) const { return idx == that.idx; } + bool operator!=(Zipit const& that) const { return !(*(this) == that); } + auto& operator++() { + ++idx; + return *this; + } + + std::size_t idx = 0; + std::tuple& args; +}; + +template +struct Zipper { + using Iter = Zipit; + + auto begin() { return Iter{0, tup}; } + auto end() { return Iter{std::get<0>(tup).size(), tup}; } + + std::tuple tup; +}; + +template +auto zip(Args&... args) { + return Zipper{std::forward_as_tuple(args...)}; +} + +} // namespace mkn::kul + +#endif /* _MKN_KUL_IO_HPP_ */ diff --git a/mkn.yaml b/mkn.yaml index abe48f5..18904ed 100644 --- a/mkn.yaml +++ b/mkn.yaml @@ -32,6 +32,7 @@ profile: parent: lib inc: . main: test/test.cpp + src: test/test mode: none dep: google.test if_arg: diff --git a/test/test.cpp b/test/test.cpp index a69b390..adbf6f9 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -29,45 +29,9 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "gmock/gmock.h" #include "gtest/gtest.h" -#include "mkn/kul/assert.hpp" -#include "mkn/kul/cli.hpp" -#include "mkn/kul/io.hpp" -#include "mkn/kul/log.hpp" -#include "mkn/kul/math.hpp" -#include "mkn/kul/os.hpp" -#include "mkn/kul/proc.hpp" -#include "mkn/kul/threads.hpp" -#include "mkn/kul/span.hpp" -#include "mkn/kul/tuple.hpp" - -#ifdef _WIN32 -#define bzero ZeroMemory -#endif - -auto tryCatch = [](std::vector> funcs, bool katch) { - for (const auto& func : funcs) try { - func(); - ASSERT_TRUE(!katch); - } catch (const mkn::kul::Exception& e) { - if (!katch) KOUT(NON) << e.debug(); - ASSERT_TRUE(katch); - } -}; - -#include "test/cli.ipp" -#include "test/except.ipp" -#include "test/io.ipp" -#include "test/math.ipp" -#include "test/os.ipp" -#include "test/proc.ipp" -#include "test/string.ipp" -#include "test/span.ipp" - int main(int argc, char* argv[]) { - KOUT(NON) << __FILE__; - ::testing::InitGoogleMock(&argc, argv); + ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/test/test/cli.ipp b/test/test/cli.cpp similarity index 85% rename from test/test/cli.ipp rename to test/test/cli.cpp index 55f013f..ed2b293 100644 --- a/test/test/cli.ipp +++ b/test/test/cli.cpp @@ -1,5 +1,9 @@ +#include "test_common.hpp" + +#include "mkn/kul/cli.hpp" + TEST(CLI_Test, ParseCommandLineArguments) { std::vector v; mkn::kul::cli::asArgs("/path/to \"words in quotes\" words\\ not\\ in\\ quotes end", v); diff --git a/test/test/except.ipp b/test/test/except.cpp similarity index 76% rename from test/test/except.ipp rename to test/test/except.cpp index 2355551..26c37ed 100644 --- a/test/test/except.ipp +++ b/test/test/except.cpp @@ -1,5 +1,9 @@ +#include "test_common.hpp" + +#include "mkn/kul/except.hpp" + TEST(Exception, String) { std::string full = "FAILURE"; try { diff --git a/test/test/io.ipp b/test/test/io.cpp similarity index 95% rename from test/test/io.ipp rename to test/test/io.cpp index 3d1f17f..84f12de 100644 --- a/test/test/io.ipp +++ b/test/test/io.cpp @@ -1,5 +1,9 @@ +#include "test_common.hpp" + +#include "mkn/kul/io.hpp" + TEST(IO_Test, ReadFileLine) { mkn::kul::io::Reader r("LICENSE.md"); char const* c = r.readLine(); @@ -10,7 +14,7 @@ TEST(IO_Test, ReadFileLine) { } TEST(IO_Test, ReadFile) { char c[20] = {0}; - bzero(c, 20); + bzero(c); mkn::kul::File file("LICENSE.md"); if (!file) KEXCEPT(mkn::kul::Exception, "ReadFile: FileNotFound: ") << file.full(); mkn::kul::io::Reader r("LICENSE.md"); @@ -37,7 +41,7 @@ TEST(IO_Test, ReadBinaryFileLine) { } TEST(IO_Test, ReadBinaryFile) { char c[20] = {0}; - bzero(c, 20); + bzero(c); mkn::kul::io::BinaryReader r("LICENSE.md"); r.read(c, 20); std::string s1 = c; diff --git a/test/test/math.ipp b/test/test/math.cpp similarity index 93% rename from test/test/math.ipp rename to test/test/math.cpp index a779a2c..f3752b1 100644 --- a/test/test/math.ipp +++ b/test/test/math.cpp @@ -1,5 +1,9 @@ +#include "test_common.hpp" + +#include "mkn/kul/math.hpp" + template void do_math() { T beta = 2; diff --git a/test/test/os.ipp b/test/test/os.cpp similarity index 92% rename from test/test/os.ipp rename to test/test/os.cpp index 5cfeba0..6c8a184 100644 --- a/test/test/os.ipp +++ b/test/test/os.cpp @@ -1,5 +1,10 @@ +#include "test_common.hpp" + +#include "mkn/kul/os.hpp" +#include "mkn/kul/proc.hpp" + TEST(OperatingSystemTests, HasRAMUsageSupport) { ASSERT_TRUE(mkn::kul::this_proc::physicalMemory()); ASSERT_TRUE(mkn::kul::this_proc::virtualMemory()); diff --git a/test/test/proc.ipp b/test/test/proc.cpp similarity index 92% rename from test/test/proc.ipp rename to test/test/proc.cpp index 468301c..d7267a3 100644 --- a/test/test/proc.ipp +++ b/test/test/proc.cpp @@ -1,5 +1,9 @@ +#include "test_common.hpp" + +#include "mkn/kul/proc.hpp" + TEST(Process_Test, LaunchProcess) { mkn::kul::Process p("bash"); p << "-c" diff --git a/test/test/span.ipp b/test/test/span.cpp similarity index 93% rename from test/test/span.ipp rename to test/test/span.cpp index 20e9134..6ca37e7 100644 --- a/test/test/span.ipp +++ b/test/test/span.cpp @@ -1,4 +1,9 @@ + +#include "test_common.hpp" + +#include "mkn/kul/span.hpp" + TEST(Span, init) { { std::vector v{1, 2, 3}; diff --git a/test/test/string.ipp b/test/test/string.cpp similarity index 98% rename from test/test/string.ipp rename to test/test/string.cpp index bfbc204..fe94b2e 100644 --- a/test/test/string.ipp +++ b/test/test/string.cpp @@ -1,5 +1,9 @@ +#include "test_common.hpp" + +#include "mkn/kul/string.hpp" + TEST(StringOperations, SplitByChar) { std::vector v; mkn::kul::String::SPLIT("split - by - char - dash", '-', v); @@ -37,18 +41,21 @@ TEST(StringOperations, String_2_UInt16_t_invalid_tooLarge) { }}, true); } + TEST(StringOperations, String_2_UInt16_t_invalid_tooNegative) { tryCatch( {// tooNegative []() { mkn::kul::String::UINT16("-1"); }}, true); } + TEST(StringOperations, String_2_UInt16_t_invalid_hasLetters) { tryCatch({// contains letters * 3 []() { mkn::kul::String::UINT16("a2c"); }, []() { mkn::kul::String::UINT16("1bc"); }, []() { mkn::kul::String::UINT16("ab3"); }}, true); } + TEST(StringOperations, String_2_UInt16_t_valid) { tryCatch( {// valid @@ -64,6 +71,7 @@ TEST(StringOperations, String_2_Int16_t_invalid_tooLarge) { }}, true); } + TEST(StringOperations, String_2_Int16_t_invalid_tooNegative) { tryCatch( {// tooNegative @@ -72,12 +80,14 @@ TEST(StringOperations, String_2_Int16_t_invalid_tooNegative) { }}, true); } + TEST(StringOperations, String_2_Int16_t_invalid_hasLetters) { tryCatch({// contains letters * 3 []() { mkn::kul::String::INT16("a2c"); }, []() { mkn::kul::String::INT16("1bc"); }, []() { mkn::kul::String::INT16("ab3"); }}, true); } + TEST(StringOperations, String_2_Int16_t_valid) { tryCatch({// valid []() { mkn::kul::String::INT16("100"); }, []() { mkn::kul::String::INT16("-100"); }}, @@ -94,18 +104,21 @@ TEST(StringOperations, String_2_UInt32_t_invalid_tooLarge) { }}, true); } + TEST(StringOperations, String_2_UInt32_t_invalid_tooNegative) { tryCatch( {// tooNegative []() { mkn::kul::String::UINT32(std::to_string(-1)); }}, true); } + TEST(StringOperations, String_2_UInt32_t_invalid_hasLetters) { tryCatch({// contains letters * 3 []() { mkn::kul::String::UINT32("a2c"); }, []() { mkn::kul::String::UINT32("1bc"); }, []() { mkn::kul::String::UINT32("ab3"); }}, true); } + TEST(StringOperations, String_2_UInt32_t_valid) { tryCatch( {// valid @@ -123,6 +136,7 @@ TEST(StringOperations, String_2_Int32_t_invalid_tooLarge) { }}, true); } + TEST(StringOperations, String_2_Int32_t_invalid_tooNegative) { tryCatch( {// tooNegative @@ -133,6 +147,7 @@ TEST(StringOperations, String_2_Int32_t_invalid_tooNegative) { }}, true); } + TEST(StringOperations, String_2_Int32_t_invalid_hasLetters) { tryCatch({// contains letters * 3 []() { mkn::kul::String::INT32("a2c"); }, []() { mkn::kul::String::INT32("1bc"); }, @@ -154,6 +169,7 @@ TEST(StringOperations, String_2_UInt64_t_invalid_tooLarge) { }}, true); } + TEST(StringOperations, String_2_UInt64_t_invalid_tooNegative) { tryCatch( {// tooNegative @@ -163,12 +179,14 @@ TEST(StringOperations, String_2_UInt64_t_invalid_tooNegative) { }}, true); } + TEST(StringOperations, String_2_UInt64_t_invalid_hasLetters) { tryCatch({// contains letters * 3 []() { mkn::kul::String::UINT64("a2c"); }, []() { mkn::kul::String::UINT64("1bc"); }, []() { mkn::kul::String::UINT64("ab3"); }}, true); } + TEST(StringOperations, String_2_UInt64_t_valid) { tryCatch( {// valid @@ -189,6 +207,7 @@ TEST(StringOperations, String_2_Int64_t_invalid) { []() { mkn::kul::String::INT64("ab3"); }}, true); } + TEST(StringOperations, String_2_Int64_t_valid) { tryCatch( {// valid diff --git a/test/test/test_common.hpp b/test/test/test_common.hpp new file mode 100644 index 0000000..c504f19 --- /dev/null +++ b/test/test/test_common.hpp @@ -0,0 +1,28 @@ + +#ifndef _MKN_KUL_TESTS_CMN_HPP_ +#define _MKN_KUL_TESTS_CMN_HPP_ + +#include "gtest/gtest.h" + +#include + +#include "mkn/kul/log.hpp" +#include "mkn/kul/except.hpp" + + +template +void bzero(T(&ar)[N]) { + std::fill_n(&ar[0], N, 0); +} + +void inline tryCatch(std::vector> funcs, bool katch) { + for (auto const& func : funcs) try { + func(); + ASSERT_TRUE(!katch); + } catch (mkn::kul::Exception const& e) { + if (!katch) KOUT(NON) << e.debug(); + ASSERT_TRUE(katch); + } +}; + +#endif /*_MKN_KUL_TESTS_CMN_HPP_*/ diff --git a/test/test/zip.cpp b/test/test/zip.cpp new file mode 100644 index 0000000..0b17610 --- /dev/null +++ b/test/test/zip.cpp @@ -0,0 +1,27 @@ + + +#include "test_common.hpp" + +#include "mkn/kul/zip.hpp" + +#include +#include + +TEST(ZipOperations, works) { + std::vector const d0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // 45 + std::vector const d1{10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; // 145 + std::array const d2{0, 100, 200, 300, 400, 500, 600, 700, 800, 900}; // 4500 = 4690 + + EXPECT_EQ(d0.size(), d1.size()); + EXPECT_EQ(d1.size(), d2.size()); + + double result = 0; + for (auto const& [a, b, c] : mkn::kul::zip(d0, d1, d2)) result += a + b + c; + + double expected = 0; + for (auto const& v : d0) expected += v; + for (auto const& v : d1) expected += v; + for (auto const& v : d2) expected += v; + + EXPECT_EQ(result, expected); +}