From 2e976bf3d19b24bebf817ac9fc3d5d66de847d89 Mon Sep 17 00:00:00 2001 From: yamacir-kit Date: Thu, 24 Oct 2024 00:03:13 +0900 Subject: [PATCH] Cleanup struct `homogeneous_vector` Signed-off-by: yamacir-kit --- README.md | 6 +- VERSION | 2 +- include/meevax/kernel/homogeneous_vector.hpp | 83 ++++------------ .../kernel/input_homogeneous_vector_port.hpp | 5 +- include/meevax/kernel/list.hpp | 7 ++ .../kernel/output_homogeneous_vector_port.hpp | 2 +- include/meevax/memory/collector.hpp | 28 +++++- src/kernel/binary_input_file_port.cpp | 4 +- src/kernel/binary_output_file_port.cpp | 2 +- src/kernel/boot.cpp | 94 ++++++++++++------- src/kernel/textual_input_port.cpp | 20 ++-- 11 files changed, 130 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index 1bc798b53..29a6d9fed 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Procedures for each standard are provided by the following R7RS-style libraries: cmake -B build -DCMAKE_BUILD_TYPE=Release cd build make package -sudo apt install build/meevax_0.5.244_amd64.deb +sudo apt install build/meevax_0.5.245_amd64.deb ``` or @@ -122,9 +122,9 @@ sudo rm -rf /usr/local/share/meevax | Target Name | Description |-------------|------------- -| `all` | Build shared-library `libmeevax.0.5.244.so` and executable `meevax` +| `all` | Build shared-library `libmeevax.0.5.245.so` and executable `meevax` | `test` | Test executable `meevax` -| `package` | Generate debian package `meevax_0.5.244_amd64.deb` +| `package` | Generate debian package `meevax_0.5.245_amd64.deb` | `install` | Copy files into `/usr/local` directly ## Usage diff --git a/VERSION b/VERSION index 0db6715bd..47ea9633b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.244 +0.5.245 diff --git a/include/meevax/kernel/homogeneous_vector.hpp b/include/meevax/kernel/homogeneous_vector.hpp index 5b0822600..871ce28e5 100644 --- a/include/meevax/kernel/homogeneous_vector.hpp +++ b/include/meevax/kernel/homogeneous_vector.hpp @@ -28,17 +28,20 @@ namespace meevax inline namespace kernel { template - struct homogeneous_vector + struct homogeneous_vector : private std::valarray { - std::valarray valarray; + using std::valarray::operator []; + using std::valarray::size; + using std::valarray::valarray; + using std::valarray::value_type; - homogeneous_vector() = default; + auto valarray() -> decltype(auto) { return static_cast &>(*this); } + auto valarray() const -> decltype(auto) { return static_cast const&>(*this); } - // list->@vector - explicit homogeneous_vector(object xs) - : valarray(length(xs)) + explicit homogeneous_vector(from_list_tag, let xs) + : std::valarray(length(xs)) { - std::generate(std::begin(valarray), std::end(valarray), [&]() mutable + std::generate(std::begin(*this), std::end(*this), [&]() mutable { let const x = car(xs); xs = cdr(xs); @@ -46,61 +49,21 @@ inline namespace kernel }); } - // make-@vector - explicit homogeneous_vector(std::size_t size, object const& x) - : valarray(input_cast(x), size) - {} - - // @vector-copy - explicit homogeneous_vector(homogeneous_vector const& v, std::size_t begin, std::size_t end) - : valarray(v.valarray[std::slice(begin, begin < end ? end - begin : 0, 1)]) - {} - - // @vector-copy - explicit homogeneous_vector(homogeneous_vector const& v, std::size_t begin = 0) - : homogeneous_vector { v, begin, v.valarray.size() } - {} - - // @vector-append - explicit homogeneous_vector(homogeneous_vector const& a, homogeneous_vector const& b) - : valarray(a.valarray.size() + b.valarray.size()) + static auto tag() -> auto const& { - slice(0, a.valarray.size()) = a.valarray; - slice(b.valarray.size(), valarray.size()) = b.valarray; - } - - // string->u8vector - explicit homogeneous_vector(T const* data, std::size_t size) - : valarray(data, size) - {} - - // get-output-u8vector - explicit homogeneous_vector(std::vector const& v) - : valarray(v.data(), v.size()) - {} - - template - explicit homogeneous_vector(Iterator begin, Iterator end) - : valarray(std::distance(begin, end)) - { - std::copy(begin, end, std::begin(valarray)); - } - - static auto tag() -> decltype(auto) - { - auto static const tag = lexical_cast(std::is_integral_v ? std::is_signed_v ? 's' : 'u' : 'f', sizeof(T) * CHAR_BIT); + auto static const tag = (std::is_integral_v ? std::is_signed_v ? "s" : "u" : "f") + std::to_string(sizeof(T) * CHAR_BIT); return tag; } template static auto input_cast(object const& x) -> T { - using Us = std::tuple; + using types = std::tuple; - if constexpr (I < std::tuple_size_v) + if constexpr (I < std::tuple_size_v) { - using U = std::tuple_element_t; - return x.is() ? static_cast(x.as()) : input_cast(x); + using type = std::tuple_element_t; + return x.is() ? static_cast(x.as()) : input_cast(x); } else { @@ -112,16 +75,6 @@ inline namespace kernel { return make, T, exact_integer>>(x); } - - auto slice(std::size_t begin, std::size_t end, std::size_t stride = 1) -> decltype(auto) - { - return valarray[std::slice(begin, end - begin, stride)]; - } - - auto slice(std::size_t begin = 0) -> decltype(auto) - { - return slice(begin, valarray.size()); - } }; template @@ -133,7 +86,7 @@ inline namespace kernel auto whitespace = ""; - for (auto const& value : datum.valarray) + for (auto value : datum.valarray()) { output << std::exchange(whitespace, " ") << cyan(homogeneous_vector::output_cast(value)); } @@ -149,7 +102,7 @@ inline namespace kernel return std::all_of(std::begin(xs), std::end(xs), [](auto x) { return x; }); }; - return check(a.valarray == b.valarray); + return check(a.valarray() == b.valarray()); } using s8vector = homogeneous_vector; diff --git a/include/meevax/kernel/input_homogeneous_vector_port.hpp b/include/meevax/kernel/input_homogeneous_vector_port.hpp index d278932f9..994540a20 100644 --- a/include/meevax/kernel/input_homogeneous_vector_port.hpp +++ b/include/meevax/kernel/input_homogeneous_vector_port.hpp @@ -33,7 +33,7 @@ inline namespace kernel std::deque deque; explicit input_homogeneous_vector_port(homogeneous_vector const& v) - : deque(std::begin(v.valarray), std::end(v.valarray)) + : deque(std::begin(v.valarray()), std::end(v.valarray())) {} auto close() -> void override @@ -61,7 +61,8 @@ inline namespace kernel } else { - let const v = make>(deque.begin(), std::next(deque.begin(), size)); + let const v = make>(direct_initialization, size); + std::copy(deque.begin(), std::next(deque.begin(), size), std::begin(v.as>().valarray())); deque.erase(deque.begin(), std::next(deque.begin(), size)); return v; } diff --git a/include/meevax/kernel/list.hpp b/include/meevax/kernel/list.hpp index 27cbb781a..cb8e768ed 100644 --- a/include/meevax/kernel/list.hpp +++ b/include/meevax/kernel/list.hpp @@ -24,6 +24,13 @@ namespace meevax { inline namespace kernel { + struct from_list_tag + { + explicit from_list_tag() = default; + }; + + inline constexpr from_list_tag from_list {}; + inline auto list = [](auto&&... xs) constexpr { return (std::forward(xs) | ... | nullptr); diff --git a/include/meevax/kernel/output_homogeneous_vector_port.hpp b/include/meevax/kernel/output_homogeneous_vector_port.hpp index 5479c6d74..7f7ddf656 100644 --- a/include/meevax/kernel/output_homogeneous_vector_port.hpp +++ b/include/meevax/kernel/output_homogeneous_vector_port.hpp @@ -49,7 +49,7 @@ inline namespace kernel auto put(u8vector const& v) -> void override { - std::copy(std::begin(v.valarray), std::end(v.valarray), std::back_inserter(vector)); + std::copy(std::begin(v.valarray()), std::end(v.valarray()), std::back_inserter(vector)); } }; diff --git a/include/meevax/memory/collector.hpp b/include/meevax/memory/collector.hpp index 68db795c9..a36817242 100644 --- a/include/meevax/memory/collector.hpp +++ b/include/meevax/memory/collector.hpp @@ -37,6 +37,20 @@ inline namespace memory { using view = std::pair; // TODO Adapt to C++20's std::range concept + struct direct_initialization_tag + { + explicit direct_initialization_tag() = default; + }; + + inline constexpr direct_initialization_tag direct_initialization {}; + + struct list_initialization_tag + { + explicit list_initialization_tag() = default; + }; + + inline constexpr list_initialization_tag list_initialization {}; + /* This mark-and-sweep garbage collector is based on the implementation of gc_ptr written by William E. Kempf and posted to CodeProject. @@ -91,11 +105,19 @@ inline namespace memory static inline auto allocator = allocator_type(); + template + explicit constexpr binder(direct_initialization_tag, Us&&... xs) + : std::conditional_t and std::is_constructible_v, Top, Bound>(std::forward(xs)...) + {} + + template + explicit constexpr binder(list_initialization_tag, Us&&... xs) + : std::conditional_t and std::is_constructible_v, Top, Bound> { std::forward(xs)... } + {} + template explicit constexpr binder(Us&&... xs) - : std::conditional_t and std::is_constructible_v, Top, Bound> { - std::forward(xs)... - } + : binder { list_initialization, std::forward(xs)... } {} ~binder() override = default; diff --git a/src/kernel/binary_input_file_port.cpp b/src/kernel/binary_input_file_port.cpp index 32f8e544e..6e71d1855 100644 --- a/src/kernel/binary_input_file_port.cpp +++ b/src/kernel/binary_input_file_port.cpp @@ -48,12 +48,12 @@ inline namespace kernel { if (auto buffer = std::vector(size); ifstream.read(reinterpret_cast(buffer.data()), size)) { - return make(buffer); + return make(direct_initialization, buffer.data(), buffer.size()); } else { buffer.resize(ifstream.gcount()); - return make(buffer); + return make(direct_initialization, buffer.data(), buffer.size()); } } diff --git a/src/kernel/binary_output_file_port.cpp b/src/kernel/binary_output_file_port.cpp index 2e7ff9455..96e4531bb 100644 --- a/src/kernel/binary_output_file_port.cpp +++ b/src/kernel/binary_output_file_port.cpp @@ -43,7 +43,7 @@ inline namespace kernel auto binary_output_file_port::put(u8vector const& v) -> void { - for (auto u8 : v.valarray) + for (auto u8 : v.valarray()) { ofstream.write(reinterpret_cast(&u8), 1); } diff --git a/src/kernel/boot.cpp b/src/kernel/boot.cpp index b9c9147a1..26d6418a8 100644 --- a/src/kernel/boot.cpp +++ b/src/kernel/boot.cpp @@ -1284,7 +1284,8 @@ inline namespace kernel library.define("get-output-u8vector", [](let const& xs) { - return make(car(xs).as().vector); + return make(car(xs).as().vector.data(), + car(xs).as().vector.size()); }); library.define("eof-object?", [](let const& xs) @@ -2043,10 +2044,10 @@ inline namespace kernel define("(meevax vector homogeneous)", [](library & library) { - #define DEFINE_VECTOR(TAG) \ + #define DEFINE_VECTOR_AUX(TAG, VECTOR) \ library.define(#TAG "vector?", [](let const& xs) \ { \ - return car(xs).is(); \ + return car(xs).is(); \ }); \ \ library.define("make-" #TAG "vector", [](let const& xs) \ @@ -2054,10 +2055,10 @@ inline namespace kernel switch (length(xs)) \ { \ case 1: \ - return make(car(xs).as(), unspecified); \ + return make(direct_initialization, static_cast(0), car(xs).as()); \ \ case 2: \ - return make(car(xs).as(), cadr(xs)); \ + return make(direct_initialization, VECTOR::input_cast(cadr(xs)), car(xs).as()); \ \ default: \ throw error(make("procedure make-" #TAG "vector takes one or two arguments, but got"), xs); \ @@ -2066,22 +2067,22 @@ inline namespace kernel \ library.define(#TAG "vector", [](let const& xs) \ { \ - return make(xs); \ + return make(from_list, xs); \ }); \ \ library.define(#TAG "vector-length", [](let const& xs) \ { \ - return make(car(xs).as().valarray.size()); \ + return make(car(xs).as().size()); \ }); \ \ library.define(#TAG "vector-ref", [](let const& xs) \ { \ - return TAG##vector::output_cast(car(xs).as().valarray[cadr(xs).as()]); \ + return VECTOR::output_cast(car(xs).as()[cadr(xs).as()]); \ }); \ \ library.define(#TAG "vector-set!", [](let const& xs) \ { \ - car(xs).as().valarray[cadr(xs).as()] = TAG##vector::input_cast(caddr(xs)); \ + car(xs).as()[cadr(xs).as()] = VECTOR::input_cast(caddr(xs)); \ }); \ \ library.define(#TAG "vector-copy", [](let const& xs) \ @@ -2089,16 +2090,29 @@ inline namespace kernel switch (length(xs)) \ { \ case 1: \ - return make(car(xs).as()); \ + { \ + std::size_t begin = 0; \ + std::size_t end = car(xs).as().size(); \ + assert(begin <= end); \ + return make(car(xs).as()[std::slice(begin, end - begin, 1)]); \ + } \ \ case 2: \ - return make(car(xs).as(), \ - cadr(xs).as()); \ + { \ + std::size_t begin = cadr(xs).as(); \ + std::size_t end = car(xs).as().size(); \ + assert(begin <= end); \ + return make(car(xs).as()[std::slice(begin, end - begin, 1)]); \ + } \ \ case 3: \ - return make(car(xs).as(), \ - cadr(xs).as(), \ - caddr(xs).as()); \ + { \ + std::size_t begin = cadr(xs).as(); \ + std::size_t end = caddr(xs).as(); \ + assert(begin <= end); \ + return make(car(xs).as()[std::slice(begin, end - begin, 1)]); \ + } \ + \ default: \ throw error(make("procedure " #TAG "vector-copy takes one to three arguments, but got"), xs); \ } \ @@ -2112,9 +2126,9 @@ inline namespace kernel { \ std::size_t at = cadr(xs).as(); \ std::size_t begin = 0; \ - std::size_t end = caddr(xs).as().valarray.size(); \ + std::size_t end = caddr(xs).as().size(); \ assert(begin <= end); \ - car(xs).as().valarray[std::slice(at, end - begin, 1)] = caddr(xs).as().valarray[std::slice(begin, end - begin, 1)]; \ + car(xs).as()[std::slice(at, end - begin, 1)] = caddr(xs).as()[std::slice(begin, end - begin, 1)]; \ } \ break; \ \ @@ -2122,9 +2136,9 @@ inline namespace kernel { \ std::size_t at = cadr(xs).as(); \ std::size_t begin = cadddr(xs).as(); \ - std::size_t end = caddr(xs).as().valarray.size(); \ + std::size_t end = caddr(xs).as().size(); \ assert(begin <= end); \ - car(xs).as().valarray[std::slice(at, end - begin, 1)] = caddr(xs).as().valarray[std::slice(begin, end - begin, 1)]; \ + car(xs).as()[std::slice(at, end - begin, 1)] = caddr(xs).as()[std::slice(begin, end - begin, 1)]; \ } \ break; \ \ @@ -2134,7 +2148,7 @@ inline namespace kernel std::size_t begin = cadddr(xs).as(); \ std::size_t end = caddddr(xs).as(); \ assert(begin <= end); \ - car(xs).as().valarray[std::slice(at, end - begin, 1)] = caddr(xs).as().valarray[std::slice(begin, end - begin, 1)]; \ + car(xs).as()[std::slice(at, end - begin, 1)] = caddr(xs).as()[std::slice(begin, end - begin, 1)]; \ } \ break; \ \ @@ -2145,8 +2159,12 @@ inline namespace kernel \ library.define(#TAG "vector-append", [](let const& xs) \ { \ - return make(car(xs).as(), \ - cadr(xs).as()); \ + auto const& a = car(xs).as(); \ + auto const& b = cadr(xs).as(); \ + let const c = make(direct_initialization, a.size() + b.size()); \ + c.as()[std::slice(0, a.size(), 1)] = a.valarray(); \ + c.as()[std::slice(a.size(), b.size(), 1)] = b.valarray(); \ + return c; \ }); \ \ library.define(#TAG "vector->list", [](let const& xs) \ @@ -2155,7 +2173,7 @@ inline namespace kernel { \ auto xcons = [](auto&& x, auto&& y) \ { \ - return cons(TAG##vector::output_cast(y), x); \ + return cons(VECTOR::output_cast(y), x); \ }; \ \ return reverse(std::accumulate(std::next(std::begin(v), a), \ @@ -2165,17 +2183,17 @@ inline namespace kernel switch (length(xs)) \ { \ case 1: \ - return list(car(xs).as().valarray, \ + return list(car(xs).as().valarray(), \ 0, \ - car(xs).as().valarray.size()); \ + car(xs).as().size()); \ \ case 2: \ - return list(car(xs).as().valarray, \ + return list(car(xs).as().valarray(), \ cadr(xs).as(), \ - car(xs).as().valarray.size()); \ + car(xs).as().size()); \ \ case 3: \ - return list(car(xs).as().valarray, \ + return list(car(xs).as().valarray(), \ cadr(xs).as(), \ caddr(xs).as()); \ \ @@ -2186,14 +2204,17 @@ inline namespace kernel \ library.define("list->" #TAG "vector", [](let const& xs) \ { \ - return make(car(xs)); \ + return make(from_list, car(xs)); \ }) + #define DEFINE_VECTOR(TAG) DEFINE_VECTOR_AUX(TAG, TAG##vector) + DEFINE_VECTOR(s8); DEFINE_VECTOR(s16); DEFINE_VECTOR(s32); DEFINE_VECTOR(s64); DEFINE_VECTOR(u8); DEFINE_VECTOR(u16); DEFINE_VECTOR(u32); DEFINE_VECTOR(u64); DEFINE_VECTOR(f32); DEFINE_VECTOR(f64); #undef DEFINE_VECTOR + #undef DEFINE_VECTOR_AUX library.define("u8vector->string", [](let const& xs) { @@ -2207,20 +2228,23 @@ inline namespace kernel switch (length(xs)) { case 1: - std::for_each(std::begin(car(xs).as().valarray), - std::end(car(xs).as().valarray), + std::for_each(std::begin(car(xs).as().valarray()), + std::end(car(xs).as().valarray()), print); break; case 2: - std::for_each(std::next(std::begin(car(xs).as().valarray), cadr(xs).as()), - std::end(car(xs).as().valarray), + std::for_each(std::next(std::begin(car(xs).as().valarray()), + cadr(xs).as()), + std::end(car(xs).as().valarray()), print); break; case 3: - std::for_each(std::next(std::begin(car(xs).as().valarray), cadr(xs).as()), - std::next(std::begin(car(xs).as().valarray), caddr(xs).as()), + std::for_each(std::next(std::begin(car(xs).as().valarray()), + cadr(xs).as()), + std::next(std::begin(car(xs).as().valarray()), + caddr(xs).as()), print); break; diff --git a/src/kernel/textual_input_port.cpp b/src/kernel/textual_input_port.cpp index 53a61a9bf..7b1fe7fad 100644 --- a/src/kernel/textual_input_port.cpp +++ b/src/kernel/textual_input_port.cpp @@ -392,10 +392,10 @@ inline namespace kernel switch (std::stoi(take_character_while(is_digit, character('0')))) { case 32: - return make(read()); + return make(from_list, read()); case 64: - return make(read()); + return make(from_list, read()); default: take_token(c2); @@ -419,16 +419,16 @@ inline namespace kernel switch (auto n = take_character_while(is_digit); std::stoi(n)) { case 8: - return make(read()); + return make(from_list, read()); case 16: - return make(read()); + return make(from_list, read()); case 32: - return make(read()); + return make(from_list, read()); case 64: - return make(read()); + return make(from_list, read()); default: throw read_error(make("An unknown literal expression was encountered"), @@ -443,16 +443,16 @@ inline namespace kernel switch (auto const n = take_character_while(is_digit); std::stoi(n)) { case 8: - return make(read()); + return make(from_list, read()); case 16: - return make(read()); + return make(from_list, read()); case 32: - return make(read()); + return make(from_list, read()); case 64: - return make(read()); + return make(from_list, read()); default: throw read_error(make("An unknown literal expression was encountered"),