Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/format.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ on:

jobs:
pre-commit:
name: pre-commit
runs-on: ubuntu-latest
name: pre-commit (${{ matrix.ubuntu-version }})
runs-on: ubuntu-${{ matrix.ubuntu-version }}
strategy:
fail-fast: false
matrix:
ubuntu-version: [24.04, 26.04]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
Expand Down
5 changes: 4 additions & 1 deletion include/rsl/algorithm.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_ALGORITHM_HPP_
#define RSL_ALGORITHM_HPP_

#include <algorithm>

Expand Down Expand Up @@ -40,3 +41,5 @@ template <typename Collection>
}

} // namespace rsl

#endif // RSL_ALGORITHM_HPP_
42 changes: 36 additions & 6 deletions include/rsl/monad.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#pragma once
#ifndef RSL_MONAD_HPP_
#define RSL_MONAD_HPP_

#include <tl/expected.hpp>

#if defined(__cpp_concepts) && (__cpp_concepts >= 201907L)
#include <concepts>
#endif
#include <optional>

namespace rsl {
Expand All @@ -20,8 +24,8 @@ namespace rsl {
* @return Return type of fn
*/
template <typename T, typename Fn>
[[nodiscard]] constexpr auto mbind(std::optional<T> const& opt,
Fn fn) -> std::invoke_result_t<Fn, T> {
[[nodiscard]] constexpr auto mbind(std::optional<T> const& opt, Fn fn)
-> std::invoke_result_t<Fn, T> {
static_assert(std::is_convertible_v<std::nullopt_t, std::invoke_result_t<Fn, T>>,
"Fn must return a std::optional");
if (opt) return fn(opt.value());
Expand All @@ -41,8 +45,8 @@ template <typename T, typename Fn>
* @return Return type of the function
*/
template <typename T, typename E, typename Fn>
[[nodiscard]] constexpr auto mbind(tl::expected<T, E> const& exp,
Fn fn) -> std::invoke_result_t<Fn, T> {
[[nodiscard]] constexpr auto mbind(tl::expected<T, E> const& exp, Fn fn)
-> std::invoke_result_t<Fn, T> {
if (exp) return fn(exp.value());
return tl::unexpected(exp.error());
}
Expand Down Expand Up @@ -152,6 +156,13 @@ constexpr inline bool is_optional_impl<std::optional<T>> = true;
template <typename T>
constexpr inline bool is_optional = is_optional_impl<std::remove_cv_t<std::remove_reference_t<T>>>;

template <typename>
constexpr inline bool is_expected_impl = false;
template <typename T, typename E>
constexpr inline bool is_expected_impl<tl::expected<T, E>> = true;
template <typename T>
constexpr inline bool is_expected = is_expected_impl<std::remove_cv_t<std::remove_reference_t<T>>>;

} // namespace rsl

/**
Expand All @@ -165,12 +176,20 @@ constexpr inline bool is_optional = is_optional_impl<std::remove_cv_t<std::remov
*
* @return Return type of f
*/
#if defined(__cpp_concepts) && (__cpp_concepts >= 201907L)
template <typename T, typename Fn>
requires(rsl::is_optional<T>)
[[nodiscard]] constexpr auto operator|(T&& opt, Fn&& fn) {
return rsl::mbind(std::forward<T>(opt), std::forward<Fn>(fn));
}
#else
template <typename T, typename Fn, typename = std::enable_if_t<rsl::is_optional<T>>,
typename = std::enable_if_t<std::is_invocable_v<
Fn, typename std::remove_cv_t<std::remove_reference_t<T>>::value_type>>>
[[nodiscard]] constexpr auto operator|(T&& opt, Fn&& fn) {
return rsl::mbind(std::forward<T>(opt), std::forward<Fn>(fn));
}
#endif

/**
* @brief Overload of the | operator as bind
Expand Down Expand Up @@ -200,8 +219,19 @@ template <typename T, typename E, typename Fn>
*
* @return Return the result of invoking the function on val
*/
template <typename T, typename Fn, typename = std::enable_if_t<!rsl::is_optional<T>>>
#if defined(__cpp_concepts) && (__cpp_concepts >= 201907L)
template <typename T, typename Fn>
requires(!rsl::is_optional<T> && !rsl::is_expected<T> && std::invocable<Fn, T>)
[[nodiscard]] constexpr auto operator|(T&& val, Fn&& fn) {
return std::invoke(std::forward<Fn>(fn), std::forward<T>(val));
}
#else
template <typename T, typename Fn,
typename = std::enable_if_t<!rsl::is_optional<T> && !rsl::is_expected<T>>>
[[nodiscard]] constexpr auto operator|(T&& val, Fn&& fn) ->
typename std::enable_if_t<std::is_invocable_v<Fn, T>, std::invoke_result_t<Fn, T>> {
return std::invoke(std::forward<Fn>(fn), std::forward<T>(val));
}
#endif

#endif // RSL_MONAD_HPP_
5 changes: 4 additions & 1 deletion include/rsl/no_discard.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_NO_DISCARD_HPP_
#define RSL_NO_DISCARD_HPP_

#include <utility>

Expand Down Expand Up @@ -26,3 +27,5 @@ class NoDiscard {
};

} // namespace rsl

#endif // RSL_NO_DISCARD_HPP_
5 changes: 4 additions & 1 deletion include/rsl/overload.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_OVERLOAD_HPP_
#define RSL_OVERLOAD_HPP_

namespace rsl {

Expand All @@ -18,3 +19,5 @@ template <class... Ts>
Overload(Ts...) -> Overload<Ts...>;

} // namespace rsl

#endif // RSL_OVERLOAD_HPP_
29 changes: 16 additions & 13 deletions include/rsl/parameter_validators.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_PARAMETER_VALIDATORS_HPP_
#define RSL_PARAMETER_VALIDATORS_HPP_

#include <rsl/algorithm.hpp>
#include <rsl/export.hpp>
Expand Down Expand Up @@ -36,8 +37,8 @@ template <typename T>

template <typename T, typename Fn>
[[nodiscard]] auto size_compare(rclcpp::Parameter const& parameter, size_t const size,
std::string const& predicate_description,
Fn const& predicate) -> tl::expected<void, std::string> {
std::string const& predicate_description, Fn const& predicate)
-> tl::expected<void, std::string> {
static constexpr auto format_string = "Length of parameter '{}' is '{}' but must be {} '{}'";
switch (parameter.get_type()) {
case rclcpp::ParameterType::PARAMETER_STRING:
Expand All @@ -55,8 +56,8 @@ template <typename T, typename Fn>

template <typename T, typename Fn>
[[nodiscard]] auto compare(rclcpp::Parameter const& parameter, T const& value,
std::string const& predicate_description,
Fn const& predicate) -> tl::expected<void, std::string> {
std::string const& predicate_description, Fn const& predicate)
-> tl::expected<void, std::string> {
if (auto const param_value = parameter.get_value<T>(); !predicate(param_value, value))
return tl::unexpected(fmt::format("Parameter '{}' with the value '{}' must be {} '{}'",
parameter.get_name(), stringify(param_value),
Expand Down Expand Up @@ -182,8 +183,8 @@ template <typename T>
* @return Help string if the parameter is invalid, otherwise void
*/
template <typename T>
[[nodiscard]] auto lower_element_bounds(rclcpp::Parameter const& parameter,
T const& lower) -> tl::expected<void, std::string> {
[[nodiscard]] auto lower_element_bounds(rclcpp::Parameter const& parameter, T const& lower)
-> tl::expected<void, std::string> {
auto const& param_value = parameter.get_value<std::vector<T>>();
for (auto val : param_value)
if (val < lower)
Expand All @@ -200,8 +201,8 @@ template <typename T>
* @return Help string if the parameter is invalid, otherwise void
*/
template <typename T>
[[nodiscard]] auto upper_element_bounds(rclcpp::Parameter const& parameter,
T const& upper) -> tl::expected<void, std::string> {
[[nodiscard]] auto upper_element_bounds(rclcpp::Parameter const& parameter, T const& upper)
-> tl::expected<void, std::string> {
auto const& param_value = parameter.get_value<std::vector<T>>();
for (auto val : param_value)
if (val > upper)
Expand All @@ -218,8 +219,8 @@ template <typename T>
* @return Help string if the parameter is invalid, otherwise void
*/
template <typename T>
[[nodiscard]] auto bounds(rclcpp::Parameter const& parameter, T const& lower,
T const& upper) -> tl::expected<void, std::string> {
[[nodiscard]] auto bounds(rclcpp::Parameter const& parameter, T const& lower, T const& upper)
-> tl::expected<void, std::string> {
auto const& param_value = parameter.get_value<T>();
if (param_value < lower || param_value > upper)
return tl::unexpected(
Expand Down Expand Up @@ -304,8 +305,8 @@ template <typename T>
* @return Help string if the parameter is invalid, otherwise void
*/
template <typename T>
[[nodiscard]] auto one_of(rclcpp::Parameter const& parameter,
std::vector<T> const& collection) -> tl::expected<void, std::string> {
[[nodiscard]] auto one_of(rclcpp::Parameter const& parameter, std::vector<T> const& collection)
-> tl::expected<void, std::string> {
auto const& param_value = parameter.get_value<T>();
if (contains(collection, param_value)) return {};
return tl::unexpected(fmt::format(
Expand All @@ -320,3 +321,5 @@ template <typename T>
-> rcl_interfaces::msg::SetParametersResult;

} // namespace rsl

#endif // RSL_PARAMETER_VALIDATORS_HPP_
13 changes: 8 additions & 5 deletions include/rsl/queue.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_QUEUE_HPP_
#define RSL_QUEUE_HPP_

#include <chrono>
#include <condition_variable>
Expand Down Expand Up @@ -26,7 +27,7 @@ class Queue {
* @return Queue size
*/
[[nodiscard]] auto size() const noexcept {
auto const lock = std::lock_guard(mutex_);
auto const lock = std::scoped_lock(mutex_);
return queue_.size();
}

Expand All @@ -35,7 +36,7 @@ class Queue {
* @return True if the queue is empty, otherwise false
*/
[[nodiscard]] auto empty() const noexcept {
auto const lock = std::lock_guard(mutex_);
auto const lock = std::scoped_lock(mutex_);
return queue_.empty();
}

Expand All @@ -44,7 +45,7 @@ class Queue {
* @param value Data to push into the queue
*/
void push(T value) noexcept {
auto const lock = std::lock_guard(mutex_);
auto const lock = std::scoped_lock(mutex_);
queue_.push(std::move(value));
cv_.notify_one();
}
Expand All @@ -53,7 +54,7 @@ class Queue {
* @brief Clear the queue
*/
void clear() noexcept {
auto const lock = std::lock_guard(mutex_);
auto const lock = std::scoped_lock(mutex_);

// Swap queue with an empty queue of the same type to ensure queue_ is left in a
// default-constructed state
Expand All @@ -77,3 +78,5 @@ class Queue {
}
};
} // namespace rsl

#endif // RSL_QUEUE_HPP_
5 changes: 4 additions & 1 deletion include/rsl/random.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_RANDOM_HPP_
#define RSL_RANDOM_HPP_

#include <rsl/export.hpp>

Expand Down Expand Up @@ -68,3 +69,5 @@ template <typename IntType>
[[nodiscard]] RSL_EXPORT auto random_unit_quaternion() -> Eigen::Quaterniond;

} // namespace rsl

#endif // RSL_RANDOM_HPP_
5 changes: 4 additions & 1 deletion include/rsl/static_string.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_STATIC_STRING_HPP_
#define RSL_STATIC_STRING_HPP_

#include <array>
#include <cassert>
Expand Down Expand Up @@ -58,3 +59,5 @@ template <size_t capacity>
}

} // namespace rsl

#endif // RSL_STATIC_STRING_HPP_
5 changes: 4 additions & 1 deletion include/rsl/static_vector.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_STATIC_VECTOR_HPP_
#define RSL_STATIC_VECTOR_HPP_

#include <tcb_span/span.hpp>

Expand Down Expand Up @@ -82,3 +83,5 @@ template <typename T, size_t capacity>
}

} // namespace rsl

#endif // RSL_STATIC_VECTOR_HPP_
5 changes: 4 additions & 1 deletion include/rsl/strong_type.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_STRONG_TYPE_HPP_
#define RSL_STRONG_TYPE_HPP_

#include <utility>

Expand Down Expand Up @@ -39,3 +40,5 @@ class StrongType {
};

} // namespace rsl

#endif // RSL_STRONG_TYPE_HPP_
5 changes: 4 additions & 1 deletion include/rsl/try.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#ifndef RSL_TRY_HPP_
#define RSL_TRY_HPP_

#include <tl/expected.hpp>

Expand Down Expand Up @@ -33,3 +34,5 @@
if (!_expected.has_value()) return tl::unexpected(_expected.error()); \
_expected.value(); \
})

#endif // RSL_TRY_HPP_
19 changes: 15 additions & 4 deletions src/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,24 @@
#include <algorithm>
#include <array>
#include <functional>
#if __has_include(<numbers>)
#include <numbers>
#endif
#include <optional>
#include <stdexcept>

namespace rsl {

namespace {

#if defined(__cpp_lib_math_constants) && (__cpp_lib_math_constants >= 201907L)
constexpr auto k_pi = std::numbers::pi_v<double>;
#else
constexpr auto k_pi = 3.141592653589793238462643383279502884;
#endif

} // namespace

auto rng(std::seed_seq seed_sequence) -> std::mt19937& {
thread_local auto generator = std::optional<std::mt19937>();

Expand All @@ -30,14 +43,12 @@ auto rng(std::seed_seq seed_sequence) -> std::mt19937& {
}

auto random_unit_quaternion() -> Eigen::Quaterniond {
static constexpr auto pi = 3.1415926535897932385;

// From "Uniform Random Rotations", Ken Shoemake, Graphics Gems III, pg. 124-132
auto const x0 = uniform_real(0., 1.);
auto const r1 = std::sqrt(1 - x0);
auto const r2 = std::sqrt(x0);
auto const t1 = uniform_real(0., 2 * pi);
auto const t2 = uniform_real(0., 2 * pi);
auto const t1 = uniform_real(0., 2 * k_pi);
auto const t2 = uniform_real(0., 2 * k_pi);
auto const x = r1 * std::sin(t1);
auto const y = r1 * std::cos(t1);
auto const z = r2 * std::sin(t2);
Expand Down
Loading
Loading