Skip to content

Commit

Permalink
Merge pull request #197 from arximboldi/jp/emscripten-at-or
Browse files Browse the repository at this point in the history
Fix at_or when no exception support
  • Loading branch information
arximboldi authored Nov 22, 2023
2 parents 32310f8 + 539ca37 commit 53dfad0
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 41 deletions.
2 changes: 1 addition & 1 deletion default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ stdenv.mkDerivation rec {
cmake
gcc7
sass
pkgconfig
pkgs.pkg-config or pkgs.pkgconfig
];
cmakeFlags = [
"-Dlager_BUILD_TESTS=OFF"
Expand Down
63 changes: 49 additions & 14 deletions lager/lenses/at.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,51 @@ template <typename T, typename OptValue>
using insert_opt_t = std::decay_t<decltype(std::declval<T>().insert(
std::declval<OptValue>().value()))>;

template <typename T, typename K>
using has_count_t = decltype(std::declval<T>().count(std::declval<K>()));

// When building without exception support, returns whether the container has
// the key, using some heuristics to distinguish vector-likes or map-like
// containers. Otherwise it just returns true and we use the normal
// exception-based mechanism.
template <typename Whole, typename Key>
bool maybe_has_key(const Whole& whole, const Key& k) noexcept
{
#ifdef LAGER_NO_EXCEPTIONS
if constexpr (zug::meta::is_detected<has_count_t, Whole, Key>::value) {
return whole.count(k) > 0;
} else if constexpr (std::is_convertible<Key, typename Whole::size_type>::
value) {
const auto k_ = static_cast<typename Whole::size_type>(k);
return k_ >= typename Whole::size_type{} && k_ < whole.size();
} else {
static_assert(
zug::meta::is_detected<has_count_t, Whole, Key>::value ||
std::is_convertible<Key, typename Whole::size_type>::value,
"at lense not supported with LAGER_NO_EXCEPTIONS");
return true;
}
#else
return true;
#endif
}

template <typename Whole,
typename Part,
typename Key,
std::enable_if_t<
!zug::meta::is_detected<set_opt_t, Whole, Key, Part>::value &&
!zug::meta::is_detected<insert_opt_t, Whole, Part>::value,
!zug::meta::is_detected<insert_opt_t, Whole, Part>::value,
int> = 0>
std::decay_t<Whole> at_setter_impl(Whole&& whole, Part&& part, Key&& key)
{
auto r = std::forward<Whole>(whole);
if (part.has_value()) {
LAGER_TRY {
if (maybe_has_key(r, key) && part.has_value()) {
LAGER_TRY
{
r.at(std::forward<Key>(key)) = std::forward<Part>(part).value();
} LAGER_CATCH(std::out_of_range const&) {}
}
LAGER_CATCH(std::out_of_range const&) {}
}
return r;
}
Expand All @@ -50,12 +81,14 @@ template <
int> = 0>
std::decay_t<Whole> at_setter_impl(Whole&& whole, Part&& part, Key&& key)
{
if (part.has_value()) {
LAGER_TRY {
if (maybe_has_key(whole, key) && part.has_value()) {
LAGER_TRY
{
(void) whole.at(std::forward<Key>(key));
return std::forward<Whole>(whole).set(
std::forward<Key>(key), std::forward<Part>(part).value());
} LAGER_CATCH(std::out_of_range const&) {}
}
LAGER_CATCH(std::out_of_range const&) {}
}
return std::forward<Whole>(whole);
}
Expand All @@ -69,9 +102,12 @@ template <
std::decay_t<Whole> at_setter_impl(Whole&& whole, Part&& part, Key&& key)
{
if (part.has_value()) {
LAGER_TRY {
return std::forward<Whole>(whole).insert(std::forward<Part>(part).value());
} LAGER_CATCH(std::out_of_range const&) {}
LAGER_TRY
{
return std::forward<Whole>(whole).insert(
std::forward<Part>(part).value());
}
LAGER_CATCH(std::out_of_range const&) {}
}
return std::forward<Whole>(whole);
}
Expand All @@ -91,11 +127,10 @@ auto at(Key key)
return [f = LAGER_FWD(f), &key](auto&& whole) {
using Part = std::optional<std::decay_t<decltype(whole.at(key))>>;
return f([&]() -> Part {
LAGER_TRY {
return LAGER_FWD(whole).at(key);
} LAGER_CATCH(std::out_of_range const&) {
if (!detail::maybe_has_key(whole, key))
return std::nullopt;
}
LAGER_TRY { return LAGER_FWD(whole).at(key); }
LAGER_CATCH(std::out_of_range const&) { return std::nullopt; }
}())([&](Part part) {
return detail::at_setter_impl(
LAGER_FWD(whole), std::move(part), key);
Expand Down
36 changes: 20 additions & 16 deletions lager/lenses/at_or.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#pragma once

#include <lager/lenses/at.hpp>

#include <lager/config.hpp>
#include <lager/util.hpp>

#include <zug/compose.hpp>
#include <zug/meta/detected.hpp>

#include <optional>
#include <stdexcept>
#include <utility>

Expand All @@ -16,8 +17,8 @@ namespace detail {

// detect if T satifsies the immer API for setting values
template <typename T, typename Key, typename V>
using set_t = std::decay_t<decltype(
std::declval<T>().set(std::declval<Key>(), std::declval<V>()))>;
using set_t = std::decay_t<decltype(std::declval<T>().set(std::declval<Key>(),
std::declval<V>()))>;

template <
typename Whole,
Expand All @@ -27,10 +28,11 @@ template <
int> = 0>
std::decay_t<Whole> at_or_setter_impl(Whole&& whole, Part&& part, Key&& key)
{
if (!maybe_has_key(whole, key))
return std::forward<Whole>(whole);
auto r = std::forward<Whole>(whole);
LAGER_TRY {
r.at(std::forward<Key>(key)) = std::forward<Part>(part);
} LAGER_CATCH(std::out_of_range const&) {}
LAGER_TRY { r.at(std::forward<Key>(key)) = std::forward<Part>(part); }
LAGER_CATCH(std::out_of_range const&) {}
return r;
}

Expand All @@ -42,11 +44,15 @@ template <
int> = 0>
std::decay_t<Whole> at_or_setter_impl(Whole&& whole, Part&& part, Key&& key)
{
LAGER_TRY {
if (!maybe_has_key(whole, key))
return std::forward<Whole>(whole);
LAGER_TRY
{
(void) whole.at(std::forward<Key>(key));
return std::forward<Whole>(whole).set(std::forward<Key>(key),
std::forward<Part>(part));
} LAGER_CATCH(std::out_of_range const&) {}
}
LAGER_CATCH(std::out_of_range const&) {}
return std::forward<Whole>(whole);
}

Expand All @@ -62,11 +68,10 @@ auto at_or(Key key)
return [f = LAGER_FWD(f), &key](auto&& whole) {
using Part = std::decay_t<decltype(whole.at(key))>;
return f([&]() -> Part {
LAGER_TRY {
return LAGER_FWD(whole).at(key);
} LAGER_CATCH(std::out_of_range const&) {
if (!detail::maybe_has_key(whole, key))
return Part{};
}
LAGER_TRY { return LAGER_FWD(whole).at(key); }
LAGER_CATCH(std::out_of_range const&) { return Part{}; }
}())([&](auto&& part) {
return detail::at_or_setter_impl(
LAGER_FWD(whole), LAGER_FWD(part), key);
Expand All @@ -85,11 +90,10 @@ auto at_or(Key key, Default&& def)
return [f = LAGER_FWD(f), &key, &def](auto&& whole) {
using Part = std::decay_t<decltype(whole.at(key))>;
return f([&]() -> Part {
LAGER_TRY {
return LAGER_FWD(whole).at(key);
} LAGER_CATCH(std::out_of_range const&) {
if (!detail::maybe_has_key(whole, key))
return def;
}
LAGER_TRY { return LAGER_FWD(whole).at(key); }
LAGER_CATCH(std::out_of_range const&) { return def; }
}())([&](auto&& part) {
return detail::at_or_setter_impl(
LAGER_FWD(whole), LAGER_FWD(part), key);
Expand Down
14 changes: 9 additions & 5 deletions lager/reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ struct reader_mixin

auto node_() const
{
if(auto node = detail::access::node(*static_cast<const DerivT*>(this))) {
if (auto node =
detail::access::node(*static_cast<const DerivT*>(this))) {
return node;
}
throw std::runtime_error("Accessing uninitialized reader");
LAGER_THROW(std::runtime_error("Accessing uninitialized reader"));
}
};

Expand All @@ -101,20 +102,23 @@ class reader_base
int> = 0>
reader_base(reader_base<T> x)
: base_t{std::move(x)}
{}
{
}

template <typename T,
std::enable_if_t<std::is_same_v<zug::meta::value_t<NodeT>,
zug::meta::value_t<T>>,
int> = 0>
reader_base(cursor_base<T> x)
: base_t{std::move(x)}
{}
{
}

template <typename NodeT2>
reader_base(std::shared_ptr<NodeT2> n)
: base_t{std::move(n)}
{}
{
}
};

/*!
Expand Down
14 changes: 9 additions & 5 deletions lager/writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ struct writer_mixin

auto node_() const
{
if(auto node = detail::access::node(*static_cast<const DerivT*>(this))) {
if (auto node =
detail::access::node(*static_cast<const DerivT*>(this))) {
return node;
}
throw std::runtime_error("Accessing uninitialized writer");
LAGER_THROW(std::runtime_error("Accessing uninitialized writer"));
}
};

Expand All @@ -100,16 +101,19 @@ class writer_base
template <typename T>
writer_base(writer_base<T> x)
: node_(std::move(x.node_))
{}
{
}

template <typename T>
writer_base(cursor_base<T> x)
: node_(detail::access::node(std::move(x)))
{}
{
}

writer_base(node_ptr_t sig)
: node_(std::move(sig))
{}
{
}
};

/*!
Expand Down

0 comments on commit 53dfad0

Please sign in to comment.