diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/lazy_sequence.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/lazy_sequence.hpp index 919651d9b..17281f59c 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/lazy_sequence.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/lazy_sequence.hpp @@ -1,5 +1,9 @@ #pragma once +#include + +#include + #include #include @@ -19,7 +23,8 @@ namespace jank::runtime::obj lazy_sequence() = default; lazy_sequence(lazy_sequence &&) noexcept = default; - lazy_sequence(lazy_sequence const &) = default; + lazy_sequence(lazy_sequence const &); + lazy_sequence &operator=(lazy_sequence const &); lazy_sequence(object_ref fn); lazy_sequence(object_ref fn, object_ref sequence); @@ -46,6 +51,16 @@ namespace jank::runtime::obj lazy_sequence_ref with_meta(object_ref m) const; private: + struct state + { + object_ref fn{}; + object_ref sv{}; + object_ref s{}; + }; + + folly::Synchronized::LockedPtr lock_state() const; + void force_locked(folly::Synchronized::LockedPtr &lock) const; + object_ref resolve_fn() const; object_ref resolve_seq() const; @@ -56,11 +71,8 @@ namespace jank::runtime::obj object_ref unwrap(object_ref ls) const; public: - /* TODO: Synchronize. */ object base{ obj_type }; - mutable object_ref fn{}; - mutable object_ref sv{}; - mutable object_ref s{}; + mutable folly::Synchronized state_; jtl::option meta; }; } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/lazy_sequence.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/lazy_sequence.cpp index 328597091..c900a4b17 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/lazy_sequence.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/lazy_sequence.cpp @@ -11,54 +11,99 @@ namespace jank::runtime::obj { + lazy_sequence::lazy_sequence(lazy_sequence const &other) + { + base = other.base; + meta = other.meta; + auto other_lock(other.lock_state()); + auto lock(lock_state()); + *lock = *other_lock; + } + + lazy_sequence &lazy_sequence::operator=(lazy_sequence const &other) + { + if(this == &other) + { + return *this; + } + + base = other.base; + meta = other.meta; + auto other_lock(other.lock_state()); + auto lock(lock_state()); + *lock = *other_lock; + return *this; + } + lazy_sequence::lazy_sequence(object_ref const fn) - : fn{ fn } { jank_debug_assert(fn.is_some()); + auto lock(lock_state()); + lock->fn = fn; } lazy_sequence::lazy_sequence(object_ref const fn, object_ref const sequence) - : fn{ fn } - , s{ sequence } { + auto lock(lock_state()); + lock->fn = fn; + lock->s = sequence; + } + + folly::Synchronized::LockedPtr + lazy_sequence::lock_state() const + { + return const_cast &>(state_).lock(); + } + + void lazy_sequence::force_locked( + folly::Synchronized::LockedPtr &lock) const + { + if(lock->fn.is_nil()) + { + return; + } + + lock->sv = dynamic_call(lock->fn); + lock->fn = jank_nil; } object_ref lazy_sequence::seq() const { realize(); - return s; + auto lock(lock_state()); + return lock->s; } lazy_sequence_ref lazy_sequence::fresh_seq() const { - realize(); - if(s.is_nil()) + auto const sequence(seq()); + if(sequence.is_nil()) { return {}; } - auto const r(runtime::fresh_seq(s)); + auto const r(runtime::fresh_seq(sequence)); jank_debug_assert(r != jank_nil); return make_box(jank_nil, r); } object_ref lazy_sequence::first() const { - realize(); - if(s.is_nil()) + auto const sequence(seq()); + if(sequence.is_nil()) { - return s; + return sequence; } - return runtime::first(s); + return runtime::first(sequence); } object_ref lazy_sequence::next() const { - realize(); - if(s.is_nil()) + auto const sequence(seq()); + if(sequence.is_nil()) { return {}; } - auto const n(runtime::next(s)); + auto const n(runtime::next(sequence)); return n; } @@ -99,46 +144,43 @@ namespace jank::runtime::obj void lazy_sequence::realize() const { - /* TODO: Lock. */ - force(); - if(sv.is_some()) + auto lock(lock_state()); + force_locked(lock); + if(lock->sv.is_nil()) { - auto ls{ sv }; - sv = jank_nil; - if(ls.is_some() && ls->type == object_type::lazy_sequence) - { - ls = unwrap(ls); - } - s = runtime::seq(ls); + return; } + + auto ls(lock->sv); + lock->sv = jank_nil; + if(ls.is_some() && ls->type == object_type::lazy_sequence) + { + ls = unwrap(ls); + } + lock->s = runtime::seq(ls); } void lazy_sequence::force() const { - if(fn.is_some()) - { - sv = dynamic_call(fn); - fn = jank_nil; - } + auto lock(lock_state()); + force_locked(lock); } void lazy_sequence::lock_and_force() const { - /* TODO: Lock */ - force(); + auto lock(lock_state()); + force_locked(lock); } object_ref lazy_sequence::sval() const { - if(fn.is_some()) - { - lock_and_force(); - } - if(sv.is_some()) + auto lock(lock_state()); + force_locked(lock); + if(lock->sv.is_some()) { - return sv; + return lock->sv; } - return s; + return lock->s; } object_ref lazy_sequence::unwrap(object_ref ls) const