Skip to content

Commit

Permalink
Merge pull request #63 from Samy-33/transient-set
Browse files Browse the repository at this point in the history
feat(transient): adds transient_set and disj! fn
  • Loading branch information
jeaye committed Mar 22, 2024
2 parents 250a33e + b1e56e5 commit 48f38c2
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 3 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ add_library(
src/cpp/jank/runtime/obj/transient_hash_map.cpp
src/cpp/jank/runtime/obj/transient_vector.cpp
src/cpp/jank/runtime/obj/persistent_set.cpp
src/cpp/jank/runtime/obj/transient_set.cpp
src/cpp/jank/runtime/obj/persistent_string.cpp
src/cpp/jank/runtime/obj/cons.cpp
src/cpp/jank/runtime/obj/range.cpp
Expand Down
6 changes: 6 additions & 0 deletions include/cpp/jank/runtime/erasure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <jank/runtime/obj/persistent_hash_map_sequence.hpp>
#include <jank/runtime/obj/transient_hash_map.hpp>
#include <jank/runtime/obj/transient_vector.hpp>
#include <jank/runtime/obj/transient_set.hpp>
#include <jank/runtime/obj/iterator.hpp>
#include <jank/runtime/obj/range.hpp>
#include <jank/runtime/obj/jit_function.hpp>
Expand Down Expand Up @@ -190,6 +191,11 @@ namespace jank::runtime
return fn(expect_object<obj::persistent_set>(erased), std::forward<Args>(args)...);
}
break;
case object_type::transient_set:
{
return fn(expect_object<obj::transient_set>(erased), std::forward<Args>(args)...);
}
break;
case object_type::cons:
{
return fn(expect_object<obj::cons>(erased), std::forward<Args>(args)...);
Expand Down
9 changes: 9 additions & 0 deletions include/cpp/jank/runtime/obj/persistent_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@

namespace jank::runtime
{
namespace obj
{
using transient_set = static_object<object_type::transient_set>;
using transient_set_ptr = native_box<transient_set>;
}

template <>
struct static_object<object_type::persistent_set> : gc
{
Expand Down Expand Up @@ -62,6 +68,9 @@ namespace jank::runtime
/* behavior::callable */
object_ptr call(object_ptr) const;

/* behavior::transientable */
obj::transient_set_ptr to_transient() const;

native_bool contains(object_ptr o) const;

object base{ object_type::persistent_set };
Expand Down
66 changes: 66 additions & 0 deletions include/cpp/jank/runtime/obj/transient_set.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#pragma once

namespace jank::runtime
{
template <>
struct static_object<object_type::transient_set> : gc
{
static constexpr bool pointer_free{ false };

using value_type = detail::native_transient_set;
using persistent_type = static_object<object_type::persistent_set>;

static_object() = default;
static_object(static_object &&) noexcept = default;
static_object(static_object const &) = default;
static_object(detail::native_persistent_set const &d);
static_object(detail::native_persistent_set &&d);
static_object(value_type &&d);

static native_box<static_object> empty()
{
static auto const ret(make_box<static_object>());
return ret;
}

/* behavior::objectable */
native_bool equal(object const &) const;
native_persistent_string to_string() const;
void to_string(fmt::memory_buffer &buff) const;
native_hash to_hash() const;

/* behavior::countable */
size_t count() const;

/* behavior::consable_in_place */
native_box<static_object> cons_in_place(object_ptr head);

/* behavior::persistentable */
native_box<persistent_type> to_persistent();

/* behavior::callable */
object_ptr call(object_ptr const) const;
object_ptr call(object_ptr const, object_ptr const fallback) const;

/* behavior::associatively_readable */
object_ptr get(object_ptr const elem) const;
object_ptr get(object_ptr const elem, object_ptr const fallback) const;
object_ptr get_entry(object_ptr const elem) const;
native_bool contains(object_ptr const elem) const;

native_box<static_object> disjoin_in_place(object_ptr const elem);

void assert_active() const;

object base{ object_type::transient_set };
value_type data;
mutable native_hash hash{};
native_bool active{ true };
};

namespace obj
{
using transient_set = static_object<object_type::transient_set>;
using transient_set_ptr = native_box<transient_set>;
}
}
1 change: 1 addition & 0 deletions include/cpp/jank/runtime/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace jank::runtime
persistent_hash_map,
persistent_hash_map_sequence,
transient_hash_map,
transient_set,
transient_vector,
persistent_set,
cons,
Expand Down
3 changes: 2 additions & 1 deletion src/cpp/jank/evaluate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ namespace jank::evaluate
}
else if constexpr(std::same_as<T, runtime::obj::keyword>
|| std::same_as<T, runtime::obj::persistent_hash_map>
|| std::same_as<T, runtime::obj::persistent_array_map>)
|| std::same_as<T, runtime::obj::persistent_array_map>
|| std::same_as<T, runtime::obj::transient_set>)
{
auto const s(expr.arg_exprs.size());
switch(s)
Expand Down
4 changes: 2 additions & 2 deletions src/cpp/jank/runtime/behavior/callable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ namespace jank::runtime
|| std::same_as<T, obj::persistent_hash_map>
|| std::same_as<T, obj::persistent_array_map>
|| std::same_as<T, obj::transient_vector>
|| std::same_as<T, obj::keyword>)
|| std::same_as<T, obj::transient_set> || std::same_as<T, obj::keyword>)
{
return typed_source->call(a1);
}
Expand Down Expand Up @@ -109,7 +109,7 @@ namespace jank::runtime
}
else if constexpr(std::same_as<T, obj::persistent_hash_map>
|| std::same_as<T, obj::persistent_array_map>
|| std::same_as<T, obj::keyword>)
|| std::same_as<T, obj::transient_set> || std::same_as<T, obj::keyword>)
{
return typed_source->call(a1, a2);
}
Expand Down
5 changes: 5 additions & 0 deletions src/cpp/jank/runtime/obj/persistent_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ namespace jank::runtime
return *found;
}

obj::transient_set_ptr obj::persistent_set::to_transient() const
{
return make_box<obj::transient_set>(data);
}

native_bool obj::persistent_set::contains(object_ptr const o) const
{
return data.find(o);
Expand Down
127 changes: 127 additions & 0 deletions src/cpp/jank/runtime/obj/transient_set.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
namespace jank::runtime
{
obj::transient_set::static_object(runtime::detail::native_persistent_set &&d)
: data{ std::move(d).transient() }
{
}

obj::transient_set::static_object(runtime::detail::native_persistent_set const &d)
: data{ d.transient() }
{
}

obj::transient_set::static_object(runtime::detail::native_transient_set &&d)
: data{ std::move(d) }
{
}

native_bool obj::transient_set::equal(object const &o) const
{
/* Transient equality, in Clojure, is based solely on identity. */
return &base == &o;
}

native_persistent_string obj::transient_set::to_string() const
{
fmt::memory_buffer buff;
to_string(buff);
return native_persistent_string{ buff.data(), buff.size() };
}

void obj::transient_set::to_string(fmt::memory_buffer &buff) const
{
auto inserter(std::back_inserter(buff));
fmt::format_to(inserter, "{}@{}", magic_enum::enum_name(base.type), fmt::ptr(&base));
}

native_hash obj::transient_set::to_hash() const
{
/* Hash is also based only on identity. Clojure uses default hashCode, which does the same. */
return static_cast<native_hash>(reinterpret_cast<uintptr_t>(this));
}

size_t obj::transient_set::count() const
{
assert_active();
return data.size();
}

obj::transient_set_ptr obj::transient_set::cons_in_place(object_ptr const elem)
{
assert_active();
data.insert(elem);
return this;
}

native_box<obj::transient_set::persistent_type> obj::transient_set::to_persistent()
{
assert_active();
active = false;
return make_box<obj::persistent_set>(data.persistent());
}

object_ptr obj::transient_set::call(object_ptr const elem) const
{
assert_active();
auto const found(data.find(elem));
if(!found)
{
return obj::nil::nil_const();
}
return *found;
}

object_ptr obj::transient_set::call(object_ptr const elem, object_ptr const fallback) const
{
assert_active();
auto const found(data.find(elem));
if(!found)
{
return fallback;
}
return *found;
}

object_ptr obj::transient_set::get(object_ptr const elem) const
{
return call(elem);
}

object_ptr obj::transient_set::get(object_ptr const elem, object_ptr const fallback) const
{
return call(elem, fallback);
}

object_ptr obj::transient_set::get_entry(object_ptr const elem) const
{
auto const found = call(elem);
auto const nil(obj::nil::nil_const());
if(found == nil)
{
return nil;
}

return make_box<obj::persistent_vector>(found, found);
}

native_bool obj::transient_set::contains(object_ptr const elem) const
{
assert_active();
return data.find(elem);
}

obj::transient_set_ptr obj::transient_set::disjoin_in_place(object_ptr const elem)
{
assert_active();
data.erase(elem);
return this;
}

void obj::transient_set::assert_active() const
{
if(!active)
{
throw std::runtime_error{ "transient used after it's been made persistent" };
}
}
}
17 changes: 17 additions & 0 deletions src/jank/clojure/core.jank
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,23 @@
{ throw ~{ (ex-info :not-transient-vector {:o coll}) }; }
")))

(defn disj!
([set] set)
([set elem]
(native/raw "if( ~{ set }->type == object_type::transient_set)
{
auto typed_set = expect_object<obj::transient_set>(~{ set });
__value = typed_set->disjoin_in_place(~{ elem });
}
else
{ throw ~{ (ex-info :not-transient-set {:o set}) }; }
"))
([set elem & elems]
(let [ret (disj! set elem)]
(if elems
(recur ret (first elems) (next elems))
ret))))

; Functions.

(defn- spread [arglist]
Expand Down

0 comments on commit 48f38c2

Please sign in to comment.