Skip to content

Commit

Permalink
version 0.12.0
Browse files Browse the repository at this point in the history
  • Loading branch information
YarikTH committed May 9, 2023
1 parent ee99622 commit d35e96b
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 62 deletions.
55 changes: 55 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,61 @@
All notable changes to this project will be documented in this file. This
project adheres to [Semantic Versioning](http://semver.org/).

## [0.12.0](https://github.com/YarikTH/ureact/releases/tag/0.12.0) (2023-05-09)

[Full Changelog](https://github.com/YarikTH/ureact/compare/0.11.0...0.12.0)

Rework "has_changed" extension point and replace doctest with Cache2

- BREAKING! rework approach to "calming" made via has_changed customization
point
Overloaded free function version of `ureact::detail::has_changed()` is
replaced with Customization Point Object
Existence of operator== is no longer condition for "calming", instead free
function `has_changed` is used.
`has_changed` is provided only for arithmetic types, enum types and library
classes `ureact::signal` and `ureact::events`.

Examples of `has_changed` function:
1. free function in the same namespace
```C++
namespace foo
{
struct Foo
{
int value;
};
constexpr bool has_changed( const Foo lhs, const Foo rhs ) noexcept
{
return !( lhs.value == rhs.value );
}
}
```

2. hidden friend version for the shy ones
```C++
namespace bar
{
class Bar
{
int value;
friend constexpr bool has_changed( const Bar lhs, const Bar rhs ) noexcept
{
return !( lhs.value == rhs.value );
}
};
}
```
- Remove Codacy badge. Codacy proved to be useless for this repository
- Replace doctest with Cache2. They are mostly the same in terms of interface,
but activity and support of Cache2 is better
- Move the only benchmark from standalone benchmark folder into ureact_test
target.
Cache2 has microbenchmark feature, but I don't understand it's output and
don't trust it.
## [0.11.0](https://github.com/YarikTH/ureact/releases/tag/0.11.0) (2023-05-01)
[Full Changelog](https://github.com/YarikTH/ureact/compare/0.10.1...0.11.0)
Expand Down
2 changes: 1 addition & 1 deletion include/ureact/version.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#define UREACT_VERSION_MAJOR 0
#define UREACT_VERSION_MINOR 12
#define UREACT_VERSION_PATCH 0
#define UREACT_VERSION_STR "0.12.0 wip"
#define UREACT_VERSION_STR "0.12.0"

#define UREACT_VERSION \
( UREACT_VERSION_MAJOR * 10000 + UREACT_VERSION_MINOR * 100 + UREACT_VERSION_PATCH )
Expand Down
132 changes: 71 additions & 61 deletions single_include/ureact/ureact_amalgamated.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
// http://www.boost.org/LICENSE_1_0.txt)
//
// ----------------------------------------------------------------
// Ureact v0.12.0 wip
// Generated: 2023-05-01 19:48:00.253156
// Ureact v0.12.0
// Generated: 2023-05-09 17:49:17.123193
// ----------------------------------------------------------------
// ureact - C++ header-only FRP library
// The library is heavily influenced by cpp.react - https://github.com/snakster/cpp.react
Expand All @@ -34,7 +34,7 @@
#define UREACT_VERSION_MAJOR 0
#define UREACT_VERSION_MINOR 12
#define UREACT_VERSION_PATCH 0
#define UREACT_VERSION_STR "0.12.0 wip"
#define UREACT_VERSION_STR "0.12.0"

#define UREACT_VERSION \
( UREACT_VERSION_MAJOR * 10000 + UREACT_VERSION_MINOR * 100 + UREACT_VERSION_PATCH )
Expand Down Expand Up @@ -2552,6 +2552,16 @@ class events : protected detail::events_internals<E>

template <typename Ret, typename Node, typename... Args>
friend Ret detail::create_wrapped_node( Args&&... args );

private:
/*!
* @brief has_changed overload for @ref events
*/
UREACT_WARN_UNUSED_RESULT friend constexpr bool has_changed(
const events& lhs, const events& rhs ) noexcept
{
return !lhs.equal_to( rhs );
}
};

/*!
Expand Down Expand Up @@ -3238,82 +3248,72 @@ UREACT_END_NAMESPACE

UREACT_BEGIN_NAMESPACE

template <typename S>
class signal;
#if defined( __clang__ ) && defined( __clang_minor__ )
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wfloat-equal"
#endif

template <typename E>
class events;
/*!
* @brief has_changed overload for arithmetic types and enums
*
* @note Can't use ADL, so should be placed before has_changed_comparable
* @note float-equal warning is suppressed, because it is perfectly fine to compare them in this context
*/
template <class T, class = std::enable_if_t<std::is_arithmetic_v<T> || std::is_enum_v<T>>>
UREACT_WARN_UNUSED_RESULT constexpr bool has_changed( const T lhs, const T rhs ) noexcept
{
return !( lhs == rhs );
}

namespace detail
#if defined( __clang__ ) && defined( __clang_minor__ )
# pragma clang diagnostic pop
#endif

// msvc finds ureact::detail::has_changed niebloid if it is not in the different namespace
// as a result infinite recursion occurs.
// to prevent this additional detail namespace is provided.
namespace has_changed_detail
{

/// c++17 analog of equality_comparable concept from c++20
/// https://en.cppreference.com/w/cpp/concepts/equality_comparable
template <typename T, typename = void>
struct equality_comparable : std::false_type
struct has_changed_comparable : std::false_type
{};

// TODO: check if result of == is exactly bool
template <typename T>
struct equality_comparable<T, std::void_t<decltype( std::declval<T>() == std::declval<T>() )>>
: std::true_type
struct has_changed_comparable<T,
std::void_t<decltype( has_changed( std::declval<T>(), std::declval<T>() ) )>> : std::true_type
{};

template <typename T>
inline constexpr bool equality_comparable_v = equality_comparable<T>::value;
inline constexpr bool has_changed_comparable_v = has_changed_comparable<T>::value;

} // namespace detail

#if defined( __clang__ ) && defined( __clang_minor__ )
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wfloat-equal"
#endif

/*!
* @brief std::not_equal_to analog intended to prevent reaction of signals to setting the same value as before aka "calming"
*
* Additionally:
* * it equally compares signal<S> and events<E> even if their operator== is overloaded
* * it equally compares reference wrappers because they can be used as S for signal<S> and their operator== does unexpected compare
* * it returns true if types are not equally comparable otherwise
*/
template <typename T>
UREACT_WARN_UNUSED_RESULT constexpr bool has_changed( const T& lhs, const T& rhs )
struct HasChangedCPO
{
if constexpr( detail::equality_comparable_v<T> )
{
return !( lhs == rhs );
}
else
template <class T>
constexpr bool operator()( const T& lhs, const T& rhs ) const noexcept
{
return true;
if constexpr( has_changed_comparable_v<T> )
return has_changed( lhs, rhs );
else
return true; // Assume always changed
}
}
};

// TODO: check if lhs.equal_to( rhs ) can be called instead of checking for specific types
template <typename S>
UREACT_WARN_UNUSED_RESULT constexpr bool has_changed( const signal<S>& lhs, const signal<S>& rhs )
{
return !lhs.equal_to( rhs );
}
} // namespace has_changed_detail

template <typename E>
UREACT_WARN_UNUSED_RESULT constexpr bool has_changed( const events<E>& lhs, const events<E>& rhs )
namespace detail
{
return !lhs.equal_to( rhs );
}

template <typename T>
UREACT_WARN_UNUSED_RESULT constexpr bool has_changed( //
const std::reference_wrapper<T>& lhs, //
const std::reference_wrapper<T>& rhs )
{
return has_changed( lhs.get(), rhs.get() );
}
/*!
* @brief std::not_equal_to analog intended to prevent reaction of signals to setting the same value as before aka "calming"
*
* @note To make a user-defined type "calmable", provide correct has_changed function
* for the type in the same namespace the type is defined.
* Expected signature is "bool has_changed( const T& lhs, const T& rhs )"
*/
inline constexpr has_changed_detail::HasChangedCPO has_changed{};

#if defined( __clang__ ) && defined( __clang_minor__ )
# pragma clang diagnostic pop
#endif
} // namespace detail

UREACT_END_NAMESPACE

Expand Down Expand Up @@ -3627,6 +3627,16 @@ class signal : protected detail::signal_internals<S>

template <typename Ret, typename Node, typename... Args>
friend Ret detail::create_wrapped_node( Args&&... args );

private:
/*!
* @brief has_changed overload for @ref signal
*/
UREACT_WARN_UNUSED_RESULT friend constexpr bool has_changed(
const signal& lhs, const signal& rhs ) noexcept
{
return !lhs.equal_to( rhs );
}
};

/*!
Expand Down Expand Up @@ -4644,7 +4654,7 @@ class signal_flatten_node final : public signal_node<InnerS>
UREACT_WARN_UNUSED_RESULT update_result update() override
{
const auto& new_inner = get_internals( m_outer->value_ref() ).get_node_ptr();
if( has_changed( new_inner, m_inner ) )
if( new_inner != m_inner )
{
// Topology has been changed
auto old_inner = m_inner;
Expand Down Expand Up @@ -4687,7 +4697,7 @@ class event_flatten_node final : public event_stream_node<InnerE>
UREACT_WARN_UNUSED_RESULT update_result update() override
{
const auto& new_inner = get_internals( m_outer->value_ref() ).get_node_ptr();
if( has_changed( new_inner, m_inner ) )
if( new_inner != m_inner )
{
// Topology has been changed
auto old_inner = m_inner;
Expand Down

0 comments on commit d35e96b

Please sign in to comment.