From b5c4338df4ac4f4b281860e3fdfc9c1ec36314ec Mon Sep 17 00:00:00 2001 From: Saket Date: Sat, 16 Mar 2024 13:37:20 +0530 Subject: [PATCH 1/5] adds conj!, assoc! and dissoc! for transients --- include/cpp/jank/prelude.hpp | 1 + .../behavior/associatively_writable.hpp | 2 +- .../jank/runtime/obj/transient_hash_map.hpp | 3 +- .../jank/runtime/obj/transient_hash_map.cpp | 7 ++ src/jank/clojure/core.jank | 81 +++++++++++++++++++ 5 files changed, 92 insertions(+), 2 deletions(-) diff --git a/include/cpp/jank/prelude.hpp b/include/cpp/jank/prelude.hpp index 40a6a22ea..cf24402e2 100644 --- a/include/cpp/jank/prelude.hpp +++ b/include/cpp/jank/prelude.hpp @@ -28,3 +28,4 @@ #include #include #include +#include diff --git a/include/cpp/jank/runtime/behavior/associatively_writable.hpp b/include/cpp/jank/runtime/behavior/associatively_writable.hpp index 8bf45646a..b0099eaa6 100644 --- a/include/cpp/jank/runtime/behavior/associatively_writable.hpp +++ b/include/cpp/jank/runtime/behavior/associatively_writable.hpp @@ -14,7 +14,7 @@ namespace jank::runtime::behavior template concept associatively_writable_in_place = requires(T * const t) { { - t->assoc_in_place(object_ptr{}, object_ptr{}) + t->assoc_in_place(object_ptr{}, object_ptr{}), t->dissoc_in_place(object_ptr{}) } -> std::convertible_to; }; } diff --git a/include/cpp/jank/runtime/obj/transient_hash_map.hpp b/include/cpp/jank/runtime/obj/transient_hash_map.hpp index b0d6f12b0..c992f5a84 100644 --- a/include/cpp/jank/runtime/obj/transient_hash_map.hpp +++ b/include/cpp/jank/runtime/obj/transient_hash_map.hpp @@ -41,7 +41,8 @@ namespace jank::runtime native_bool contains(object_ptr key) const; /* behavior::associatively_writable_in_place */ - native_box assoc_in_place(object_ptr key, object_ptr val); + native_box assoc_in_place(object_ptr const key, object_ptr const val); + native_box dissoc_in_place(object_ptr const key); /* behavior::consable_in_place */ native_box cons_in_place(object_ptr head); diff --git a/src/cpp/jank/runtime/obj/transient_hash_map.cpp b/src/cpp/jank/runtime/obj/transient_hash_map.cpp index 97af6be5c..d0bf7aa69 100644 --- a/src/cpp/jank/runtime/obj/transient_hash_map.cpp +++ b/src/cpp/jank/runtime/obj/transient_hash_map.cpp @@ -97,6 +97,13 @@ namespace jank::runtime return this; } + obj::transient_hash_map_ptr obj::transient_hash_map::dissoc_in_place(object_ptr const key) + { + assert_active(); + data.erase(key); + return this; + } + obj::transient_hash_map_ptr obj::transient_hash_map::cons_in_place(object_ptr const head) { assert_active(); diff --git a/src/jank/clojure/core.jank b/src/jank/clojure/core.jank index 7c3a53c33..a746022c2 100644 --- a/src/jank/clojure/core.jank +++ b/src/jank/clojure/core.jank @@ -431,6 +431,87 @@ #{ o }# );")) +(def conj!) +(def conj! + (fn* conj! + ([] + (transient [])) + ([coll] + coll) + ([coll x] + (native/raw "__value = visit_object + ( + [&](auto const typed_t, auto const head) -> object_ptr + { + using T = typename decltype(typed_t)::value_type; + + if constexpr(behavior::persistentable) + { + return typed_t->cons_in_place(head); + } + else + { throw #{ (ex-info :not-persistentable {:o coll}) }#; } + }, + #{ coll }#, + #{ x }# + ); + ")))) + +(def assoc!) +(def assoc! + (fn* assoc! + ([coll k v] + (native/raw "__value = visit_object + ( + [&](auto const typed_t, auto const key, auto const val) -> object_ptr + { + using T = typename decltype(typed_t)::value_type; + + if constexpr(behavior::associatively_writable_in_place) + { + return typed_t->assoc_in_place(key, val); + } + else + { throw #{ (ex-info :not-associatively_writable_in_place {:o coll}) }#; } + }, + #{ coll }#, + #{ k }#, + #{ v }# + ); + ")) + ([coll k v & kvs] + (let* [ret (assoc! coll k v)] + (if kvs + (recur ret (first kvs) (second kvs) (nnext kvs)) + ret))))) + +(def dissoc!) +(def dissoc! + (fn* dissoc! + ([coll k] + (native/raw "__value = visit_object + ( + [&](auto const typed_t, auto const key) -> object_ptr + { + using T = typename decltype(typed_t)::value_type; + + if constexpr(behavior::associatively_writable_in_place) + { + return typed_t->dissoc_in_place(key); + } + else + { throw #{ (ex-info :not-associatively_writable_in_place {:o coll}) }#; } + }, + #{ coll }#, + #{ k }# + ); + ")) + ([coll k & ks] + (let* [ret (dissoc! coll k)] + (if ks + (recur ret (first ks) (next ks)) + ret))))) + ; Functions. (defn- spread [arglist] From 93133df018c4b6dee7634ed2cb3685b148c24992 Mon Sep 17 00:00:00 2001 From: Saket Date: Sun, 17 Mar 2024 01:17:39 +0530 Subject: [PATCH 2/5] feat(transient-vector): adds pop! to core.jank --- .../cpp/jank/runtime/obj/transient_vector.hpp | 2 ++ src/cpp/jank/runtime/obj/transient_vector.cpp | 13 ++++++++++++ src/jank/clojure/core.jank | 21 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/include/cpp/jank/runtime/obj/transient_vector.hpp b/include/cpp/jank/runtime/obj/transient_vector.hpp index 12031ad80..6fced4c2d 100644 --- a/include/cpp/jank/runtime/obj/transient_vector.hpp +++ b/include/cpp/jank/runtime/obj/transient_vector.hpp @@ -23,6 +23,8 @@ namespace jank::runtime return ret; } + native_box pop(); + /* behavior::objectable */ native_bool equal(object const &) const; native_persistent_string to_string() const; diff --git a/src/cpp/jank/runtime/obj/transient_vector.cpp b/src/cpp/jank/runtime/obj/transient_vector.cpp index 370ac4e65..87e852717 100644 --- a/src/cpp/jank/runtime/obj/transient_vector.cpp +++ b/src/cpp/jank/runtime/obj/transient_vector.cpp @@ -40,6 +40,19 @@ namespace jank::runtime return static_cast(reinterpret_cast(this)); } + obj::transient_vector_ptr obj::transient_vector::pop() + { + assert_active(); + if(data.empty()) + { + throw std::runtime_error{ "Can't pop empty vector" }; + } + + data.take(data.size() - 1); + + return this; + } + size_t obj::transient_vector::count() const { assert_active(); diff --git a/src/jank/clojure/core.jank b/src/jank/clojure/core.jank index a746022c2..14a54a80b 100644 --- a/src/jank/clojure/core.jank +++ b/src/jank/clojure/core.jank @@ -512,6 +512,27 @@ (recur ret (first ks) (next ks)) ret))))) +(def pop!) +(def pop! + (fn* pop! + ([coll] + (native/raw "__value = visit_object + ( + [&](auto const typed_t) -> object_ptr + { + using T = typename decltype(typed_t)::value_type; + + if constexpr(std::same_as) + { + return typed_t->pop(); + } + else + { throw #{ (ex-info :not-transient-vector {:o coll}) }#; } + }, + #{ coll }# + ); + ")))) + ; Functions. (defn- spread [arglist] From a3af729d79db1c62dd1851ac275428020d8202ae Mon Sep 17 00:00:00 2001 From: Saket Date: Mon, 18 Mar 2024 10:20:57 +0530 Subject: [PATCH 3/5] rename pop to pop_in_place and formatting fix --- .../cpp/jank/runtime/obj/transient_vector.hpp | 2 +- src/cpp/jank/runtime/obj/transient_vector.cpp | 7 +- src/jank/clojure/core.jank | 178 ++++++++---------- 3 files changed, 84 insertions(+), 103 deletions(-) diff --git a/include/cpp/jank/runtime/obj/transient_vector.hpp b/include/cpp/jank/runtime/obj/transient_vector.hpp index 6fced4c2d..efe9e70c5 100644 --- a/include/cpp/jank/runtime/obj/transient_vector.hpp +++ b/include/cpp/jank/runtime/obj/transient_vector.hpp @@ -23,7 +23,7 @@ namespace jank::runtime return ret; } - native_box pop(); + native_box pop_in_place(); /* behavior::objectable */ native_bool equal(object const &) const; diff --git a/src/cpp/jank/runtime/obj/transient_vector.cpp b/src/cpp/jank/runtime/obj/transient_vector.cpp index 87e852717..0d312acbf 100644 --- a/src/cpp/jank/runtime/obj/transient_vector.cpp +++ b/src/cpp/jank/runtime/obj/transient_vector.cpp @@ -40,16 +40,13 @@ namespace jank::runtime return static_cast(reinterpret_cast(this)); } - obj::transient_vector_ptr obj::transient_vector::pop() + obj::transient_vector_ptr obj::transient_vector::pop_in_place() { assert_active(); if(data.empty()) - { - throw std::runtime_error{ "Can't pop empty vector" }; - } + { throw std::runtime_error{ "Can't pop empty vector" }; } data.take(data.size() - 1); - return this; } diff --git a/src/jank/clojure/core.jank b/src/jank/clojure/core.jank index 14a54a80b..1b400eff1 100644 --- a/src/jank/clojure/core.jank +++ b/src/jank/clojure/core.jank @@ -431,107 +431,91 @@ #{ o }# );")) -(def conj!) -(def conj! - (fn* conj! - ([] - (transient [])) - ([coll] - coll) - ([coll x] - (native/raw "__value = visit_object - ( - [&](auto const typed_t, auto const head) -> object_ptr - { - using T = typename decltype(typed_t)::value_type; +(defn conj! + ([] + (transient [])) + ([coll] + coll) + ([coll x] + (native/raw "__value = visit_object + ( + [=](auto const typed_t, auto const head) -> object_ptr + { + using T = typename decltype(typed_t)::value_type; - if constexpr(behavior::persistentable) - { - return typed_t->cons_in_place(head); - } - else - { throw #{ (ex-info :not-persistentable {:o coll}) }#; } - }, - #{ coll }#, - #{ x }# - ); - ")))) - -(def assoc!) -(def assoc! - (fn* assoc! - ([coll k v] - (native/raw "__value = visit_object - ( - [&](auto const typed_t, auto const key, auto const val) -> object_ptr - { - using T = typename decltype(typed_t)::value_type; + if constexpr(behavior::persistentable) + { return typed_t->cons_in_place(head); } + else + { throw #{ (ex-info :not-persistentable {:o coll}) }#; } + }, + #{ coll }#, + #{ x }# + ); + "))) - if constexpr(behavior::associatively_writable_in_place) - { - return typed_t->assoc_in_place(key, val); - } - else - { throw #{ (ex-info :not-associatively_writable_in_place {:o coll}) }#; } - }, - #{ coll }#, - #{ k }#, - #{ v }# - ); - ")) - ([coll k v & kvs] - (let* [ret (assoc! coll k v)] - (if kvs - (recur ret (first kvs) (second kvs) (nnext kvs)) - ret))))) - -(def dissoc!) -(def dissoc! - (fn* dissoc! - ([coll k] - (native/raw "__value = visit_object - ( - [&](auto const typed_t, auto const key) -> object_ptr - { - using T = typename decltype(typed_t)::value_type; +(defn assoc! + ([coll k v] + (native/raw "__value = visit_object + ( + [=](auto const typed_t, auto const key, auto const val) -> object_ptr + { + using T = typename decltype(typed_t)::value_type; - if constexpr(behavior::associatively_writable_in_place) - { - return typed_t->dissoc_in_place(key); - } - else - { throw #{ (ex-info :not-associatively_writable_in_place {:o coll}) }#; } - }, - #{ coll }#, - #{ k }# - ); - ")) - ([coll k & ks] - (let* [ret (dissoc! coll k)] - (if ks - (recur ret (first ks) (next ks)) - ret))))) - -(def pop!) -(def pop! - (fn* pop! - ([coll] - (native/raw "__value = visit_object - ( - [&](auto const typed_t) -> object_ptr - { - using T = typename decltype(typed_t)::value_type; + if constexpr(behavior::associatively_writable_in_place) + { return typed_t->assoc_in_place(key, val); } + else + { throw #{ (ex-info :not-associatively_writable_in_place {:o coll}) }#; } + }, + #{ coll }#, + #{ k }#, + #{ v }# + ); + ")) + ([coll k v & kvs] + (let [ret (assoc! coll k v)] + (if kvs + (recur ret (first kvs) (second kvs) (nnext kvs)) + ret)))) + +(defn dissoc! + ([coll k] + (native/raw "__value = visit_object + ( + [=](auto const typed_t, auto const key) -> object_ptr + { + using T = typename decltype(typed_t)::value_type; - if constexpr(std::same_as) - { - return typed_t->pop(); - } - else - { throw #{ (ex-info :not-transient-vector {:o coll}) }#; } - }, - #{ coll }# - ); - ")))) + if constexpr(behavior::associatively_writable_in_place) + { return typed_t->dissoc_in_place(key); } + else + { throw #{ (ex-info :not-associatively_writable_in_place {:o coll}) }#; } + }, + #{ coll }#, + #{ k }# + ); + ")) + ([coll k & ks] + (let [ret (dissoc! coll k)] + (if ks + (recur ret (first ks) (next ks)) + ret)))) + +(defn pop! + ([coll] + (native/raw "__value = visit_object + ( + [=](auto const typed_t) -> object_ptr + { + using T = typename decltype(typed_t)::value_type; + + if constexpr(std::same_as) + { return typed_t->pop_in_place(); } + else + { throw #{ (ex-info :not-transient-vector {:o coll}) }#; } + }, + #{ coll }# + ); + "))) ; Functions. From 8ab39cecb9808a4dfcf94e1869239fe52410f855 Mon Sep 17 00:00:00 2001 From: Saket Date: Fri, 22 Mar 2024 22:07:31 +0530 Subject: [PATCH 4/5] addresses comments for refactoring and fixes --- include/cpp/jank/prelude.hpp | 1 + .../behavior/associatively_writable.hpp | 6 +- .../cpp/jank/runtime/obj/transient_vector.hpp | 4 +- src/cpp/jank/runtime/obj/transient_vector.cpp | 22 +++--- src/jank/clojure/core.jank | 68 +++++++++---------- 5 files changed, 51 insertions(+), 50 deletions(-) diff --git a/include/cpp/jank/prelude.hpp b/include/cpp/jank/prelude.hpp index cf24402e2..826880123 100644 --- a/include/cpp/jank/prelude.hpp +++ b/include/cpp/jank/prelude.hpp @@ -28,4 +28,5 @@ #include #include #include +#include #include diff --git a/include/cpp/jank/runtime/behavior/associatively_writable.hpp b/include/cpp/jank/runtime/behavior/associatively_writable.hpp index b0099eaa6..4dd9a1b12 100644 --- a/include/cpp/jank/runtime/behavior/associatively_writable.hpp +++ b/include/cpp/jank/runtime/behavior/associatively_writable.hpp @@ -14,7 +14,11 @@ namespace jank::runtime::behavior template concept associatively_writable_in_place = requires(T * const t) { { - t->assoc_in_place(object_ptr{}, object_ptr{}), t->dissoc_in_place(object_ptr{}) + t->assoc_in_place(object_ptr{}, object_ptr{}) + } -> std::convertible_to; + + { + t->dissoc_in_place(object_ptr{}) } -> std::convertible_to; }; } diff --git a/include/cpp/jank/runtime/obj/transient_vector.hpp b/include/cpp/jank/runtime/obj/transient_vector.hpp index efe9e70c5..11632bdb1 100644 --- a/include/cpp/jank/runtime/obj/transient_vector.hpp +++ b/include/cpp/jank/runtime/obj/transient_vector.hpp @@ -23,8 +23,6 @@ namespace jank::runtime return ret; } - native_box pop_in_place(); - /* behavior::objectable */ native_bool equal(object const &) const; native_persistent_string to_string() const; @@ -49,6 +47,8 @@ namespace jank::runtime object_ptr get_entry(object_ptr const idx) const; native_bool contains(object_ptr const elem) const; + native_box pop_in_place(); + void assert_active() const; object base{ object_type::transient_vector }; diff --git a/src/cpp/jank/runtime/obj/transient_vector.cpp b/src/cpp/jank/runtime/obj/transient_vector.cpp index 0d312acbf..86cb302e1 100644 --- a/src/cpp/jank/runtime/obj/transient_vector.cpp +++ b/src/cpp/jank/runtime/obj/transient_vector.cpp @@ -40,16 +40,6 @@ namespace jank::runtime return static_cast(reinterpret_cast(this)); } - obj::transient_vector_ptr obj::transient_vector::pop_in_place() - { - assert_active(); - if(data.empty()) - { throw std::runtime_error{ "Can't pop empty vector" }; } - - data.take(data.size() - 1); - return this; - } - size_t obj::transient_vector::count() const { assert_active(); @@ -164,6 +154,18 @@ namespace jank::runtime } } + obj::transient_vector_ptr obj::transient_vector::pop_in_place() + { + assert_active(); + if(data.empty()) + { + throw std::runtime_error{ "Can't pop empty vector" }; + } + + data.take(data.size() - 1); + return this; + } + void obj::transient_vector::assert_active() const { if(!active) diff --git a/src/jank/clojure/core.jank b/src/jank/clojure/core.jank index 1e9035dd7..c89a7101a 100644 --- a/src/jank/clojure/core.jank +++ b/src/jank/clojure/core.jank @@ -408,9 +408,9 @@ if constexpr(behavior::transientable) { return typed_o->to_transient(); } else - { throw #{ (ex-info :not-transientable {:o o}) }#; } + { throw ~{ (ex-info :not-transientable {:o o}) }; } }, - #{ o }# + ~{ o } );")) ; Returns a new, persistent version of the transient collection, in @@ -426,9 +426,9 @@ if constexpr(behavior::persistentable) { return typed_o->to_persistent(); } else - { throw #{ (ex-info :not-persistentable {:o o}) }#; } + { throw ~{ (ex-info :not-persistentable {:o o}) }; } }, - #{ o }# + ~{ o } );")) (defn conj! @@ -439,17 +439,17 @@ ([coll x] (native/raw "__value = visit_object ( - [=](auto const typed_t, auto const head) -> object_ptr + [=](auto const typed_coll, auto const head) -> object_ptr { - using T = typename decltype(typed_t)::value_type; + using T = typename decltype(typed_coll)::value_type; - if constexpr(behavior::persistentable) - { return typed_t->cons_in_place(head); } + if constexpr(behavior::consable_in_place) + { return typed_coll->cons_in_place(head); } else - { throw #{ (ex-info :not-persistentable {:o coll}) }#; } + { throw ~{ (ex-info :not-persistentable {:o coll}) }; } }, - #{ coll }#, - #{ x }# + ~{ coll }, + ~{ x } ); "))) @@ -457,18 +457,18 @@ ([coll k v] (native/raw "__value = visit_object ( - [=](auto const typed_t, auto const key, auto const val) -> object_ptr + [=](auto const typed_coll, auto const key, auto const val) -> object_ptr { - using T = typename decltype(typed_t)::value_type; + using T = typename decltype(typed_coll)::value_type; if constexpr(behavior::associatively_writable_in_place) - { return typed_t->assoc_in_place(key, val); } + { return typed_coll->assoc_in_place(key, val); } else - { throw #{ (ex-info :not-associatively_writable_in_place {:o coll}) }#; } + { throw ~{ (ex-info :not-associatively_writable_in_place {:o coll}) }; } }, - #{ coll }#, - #{ k }#, - #{ v }# + ~{ coll }, + ~{ k }, + ~{ v } ); ")) ([coll k v & kvs] @@ -481,17 +481,17 @@ ([coll k] (native/raw "__value = visit_object ( - [=](auto const typed_t, auto const key) -> object_ptr + [=](auto const typed_coll, auto const key) -> object_ptr { - using T = typename decltype(typed_t)::value_type; + using T = typename decltype(typed_coll)::value_type; if constexpr(behavior::associatively_writable_in_place) - { return typed_t->dissoc_in_place(key); } + { return typed_coll->dissoc_in_place(key); } else - { throw #{ (ex-info :not-associatively_writable_in_place {:o coll}) }#; } + { throw ~{ (ex-info :not-associatively_writable_in_place {:o coll}) }; } }, - #{ coll }#, - #{ k }# + ~{ coll }, + ~{ k } ); ")) ([coll k & ks] @@ -502,19 +502,13 @@ (defn pop! ([coll] - (native/raw "__value = visit_object - ( - [=](auto const typed_t) -> object_ptr - { - using T = typename decltype(typed_t)::value_type; - - if constexpr(std::same_as) - { return typed_t->pop_in_place(); } - else - { throw #{ (ex-info :not-transient-vector {:o coll}) }#; } - }, - #{ coll }# - ); + (native/raw "if( ~{ coll }->type == object_type::transient_vector ) + { + auto transient_coll = expect_object(~{ coll }); + __value = transient_coll->pop_in_place(); + } + else + { throw ~{ (ex-info :not-transient-vector {:o coll}) }; } "))) ; Functions. From b25c90189d5561d8d76c0b36e1a57a527c39d09e Mon Sep 17 00:00:00 2001 From: Saket Date: Sat, 23 Mar 2024 00:47:25 +0530 Subject: [PATCH 5/5] copypasta typo fix --- src/jank/clojure/core.jank | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jank/clojure/core.jank b/src/jank/clojure/core.jank index d3f67b34e..db5ffe323 100644 --- a/src/jank/clojure/core.jank +++ b/src/jank/clojure/core.jank @@ -438,7 +438,7 @@ if constexpr(behavior::consable_in_place) { return typed_coll->cons_in_place(head); } else - { throw ~{ (ex-info :not-persistentable {:o coll}) }; } + { throw ~{ (ex-info :not-consable-in-place {:o coll}) }; } }, ~{ coll }, ~{ x }