Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ add accumulate, enhance invoke and rename it to function #10

Merged
merged 3 commits into from
Dec 9, 2022
Merged
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
14 changes: 7 additions & 7 deletions include/safe.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#pragma once

#include <safe/dsl.hpp>

#include <safe/var.hpp>

#include <safe/invoke.hpp>

#include <safe/array.hpp>
#include <safe/dsl.hpp>
#include <safe/constant.hpp>
#include <safe/value.hpp>
#include <safe/int.hpp>
#include <safe/int.hpp>

#include <safe/function.hpp>
#include <safe/algorithm.hpp>

#include <safe/array.hpp>
4 changes: 4 additions & 0 deletions include/safe/algorithm.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once


#include <safe/algorithm/accumulate.hpp>
116 changes: 116 additions & 0 deletions include/safe/algorithm/accumulate.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#pragma once


#include <safe/var.hpp>
#include <safe/constant.hpp>
#include <safe/dsl/simplify.hpp>

#include <safe/detail/concepts.hpp>

#include <type_traits>
#include <utility>


namespace safe {
namespace detail {
template<auto count>
inline consteval auto fold(auto e, auto op){
if constexpr (count > 100) {
bdeane-intel marked this conversation as resolved.
Show resolved Hide resolved
return safe::dsl::detail::simp(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(fold<count - 10>(e, op),
e), e), e), e), e), e), e), e), e), e),
e), e), e), e), e), e), e), e), e), e),
e), e), e), e), e), e), e), e), e), e),
e), e), e), e), e), e), e), e), e), e),
e), e), e), e), e), e), e), e), e), e),
e), e), e), e), e), e), e), e), e), e),
e), e), e), e), e), e), e), e), e), e),
e), e), e), e), e), e), e), e), e), e),
e), e), e), e), e), e), e), e), e), e),
e), e), e), e), e), e), e), e), e), e)
);

} else if constexpr (count > 10) {
bdeane-intel marked this conversation as resolved.
Show resolved Hide resolved
return safe::dsl::detail::simp(
op(op(op(op(op(op(op(op(op(op(fold<count - 10>(e, op), e), e), e), e), e), e), e), e), e), e)
);

} else if constexpr (count > 1) {
return safe::dsl::detail::simp(op(fold<count - 1>(e, op), e));

} else {
return e;
}
}

inline constexpr auto plus_op = [](auto a, auto b){return a + b;};
}


template<size_t max_iter>
[[nodiscard]] inline constexpr auto accumulate(
detail::iter_like auto first,
auto last,
auto op
) {
constexpr auto req = decltype((*first).requirement){};
constexpr auto sum_req = detail::fold<max_iter>(req, op);

using ret_num_t = decltype((*first).unsafe_value());

auto iter_count = size_t{};
auto sum = ret_num_t{};
while ((first != last) && (iter_count < max_iter)) {
sum = op(sum, (*first).unsafe_value());
first++;
iter_count++;
}

return safe::var<ret_num_t, sum_req>{sum};
}

template<size_t max_iter>
[[nodiscard]] inline constexpr auto accumulate(
detail::iter_like auto first,
auto last
) {
return accumulate<max_iter>(first, last, detail::plus_op);
}

template<size_t max_iter>
[[nodiscard]] inline constexpr auto accumulate(
detail::range_like auto & range,
auto op
) {
return accumulate<max_iter>(range.begin(), range.end(), op);
}

template<size_t max_iter>
[[nodiscard]] inline constexpr auto accumulate(
detail::range_like auto & range
) {
return accumulate<max_iter>(range.begin(), range.end(), detail::plus_op);
}

template<size_t max_iter>
[[nodiscard]] inline constexpr auto accumulate(
detail::range_like auto const & range,
auto op
) {
return accumulate<max_iter>(range.begin(), range.end(), op);
}

template<size_t max_iter>
[[nodiscard]] inline constexpr auto accumulate(auto const & range) {
return accumulate<max_iter>(range.begin(), range.end(), detail::plus_op);
}
}
20 changes: 20 additions & 0 deletions include/safe/detail/concepts.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <concepts>

namespace safe::detail {
template<class I>
concept iter_like =
requires(I i) {
i++;
*i;
i != i;
};

template<class R>
concept range_like =
requires(R r) {
{r.begin()} -> iter_like;
r.end();
};
}
5 changes: 3 additions & 2 deletions include/safe/detail/integral_type.hpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
#pragma once


#include <safe/dsl/ival.hpp>
#include <safe/detail/fwd.hpp>

#include <type_traits>
#include <limits>


namespace safe::detail {
template<typename T>
using integral_type =
var<T, ival<
var<T, safe::dsl::ival<
std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max()>
>;
Expand Down
10 changes: 9 additions & 1 deletion include/safe/detail/invoke.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,16 @@ namespace safe::detail {
}


template<typename T, typename ReturnT, typename... ArgTs>
mp_list<ArgTs...> helper(ReturnT (T::*)(ArgTs...));

template<typename T, typename ReturnT, typename... ArgTs>
mp_list<ArgTs...> helper(ReturnT (T::*)(ArgTs...) const);

template<typename F>
struct function_args;
struct function_args {
bdeane-intel marked this conversation as resolved.
Show resolved Hide resolved
using type = decltype(helper(&F::operator()));
};

template<typename ReturnT, typename... ArgTs>
struct function_args<ReturnT(ArgTs...)> {
Expand Down
1 change: 1 addition & 0 deletions include/safe/dsl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <safe/dsl/bitwise_and.hpp>
#include <safe/dsl/bitwise_xor.hpp>
#include <safe/dsl/bitwise_invert.hpp>
#include <safe/dsl/bit_width.hpp>

#include <safe/dsl/min.hpp>
#include <safe/dsl/max.hpp>
Expand Down
31 changes: 31 additions & 0 deletions include/safe/dsl/bit_width.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <safe/dsl/ival.hpp>
#include <safe/dsl/mask.hpp>
#include <safe/dsl/primitive.hpp>
#include <safe/dsl/fwd.hpp>

#include <algorithm>
#include <bit>

namespace safe::dsl {
template<typename T>
struct bit_width_t {};

template<detail::Primitive T>
struct bit_width_t<T> {
using val = detail::to_mask_t<T>;

using type = ival_t<
std::bit_width(val::const_bits),
std::bit_width(val::var_bits | val::const_bits)
>;
};

template<typename T>
[[nodiscard]] constexpr auto bit_width(T)
-> bit_width_t<T>
{
return {};
}
}
4 changes: 2 additions & 2 deletions include/safe/dsl/detail/checked.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ namespace safe::dsl::detail {
if (overflow | underflow | lhs.is_overflow() | rhs.is_overflow()) {
return checked<ret_t>{zero, true};
} else {
return checked<ret_t>{lhs.value() + rhs.value(), false};
return checked<ret_t>(lhs.value() + rhs.value(), false);
bdeane-intel marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -155,7 +155,7 @@ namespace safe::dsl::detail {
if (overflow | underflow | lhs.is_overflow() | rhs.is_overflow()) {
return checked<ret_t>{zero, true};
} else {
return checked<ret_t>{lhs.value() - rhs.value(), false};
return checked<ret_t>(lhs.value() - rhs.value(), false);
}
}

Expand Down
1 change: 1 addition & 0 deletions include/safe/dsl/detail/triint.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once


#include <limits>
#include <type_traits>
#include <cstdint>

Expand Down
95 changes: 95 additions & 0 deletions include/safe/function.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#pragma once


#include <safe/var.hpp>
#include <safe/detail/invoke.hpp>

#include <boost/mp11.hpp>

#include <utility>
#include <type_traits>


namespace safe {
/**
* @brief Create a safe, optionally piece-wise, function.
*
* If the arguments satisfy the first function's requirements, it is called
* and its return value is returned. If not, the second function is tried,
* and so on. If none of the arguments work for any of the functions' arguments,
* the last function is called with no arguments and its return value is
* returned.
*
* If RetT is void, then no default function should be specified and the
* function object's return value will be bool.
*
* @tparam RetT
* The return type of the function object.
*
* @param func
* The first function to attempt to apply to the arguments.
*
* @param remaining_funcs
* The remaining functions to attempt to apply to the arguments.
*
* @return A function object.
*/
template<typename RetT>
[[nodiscard]] inline constexpr auto function(
auto func,
auto... remaining_funcs
) {
using namespace boost::mp11;

using func_arg_types =
detail::function_args_t<decltype(func)>;

if constexpr (std::is_same_v<void, RetT>) {
return [=](auto && ... args) -> bool {
static_assert(
mp_size<func_arg_types>::value == sizeof...(args),
"The number of arguments passed in must match the args in func.");

bool const args_satisfy_reqs =
detail::check(func_arg_types{}, std::forward<decltype(args)>(args)...);

if (args_satisfy_reqs) {
func(std::forward<decltype(args)>(args)...);
return true;

} else if constexpr (sizeof...(remaining_funcs) > 0) { // check the remaining functions' requirements
return function<RetT>(remaining_funcs...)(std::forward<decltype(args)>(args)...);
bdeane-intel marked this conversation as resolved.
Show resolved Hide resolved

} else { // no match, return failure
return false;
}
};

} else {
return [=](auto && ... args) -> RetT {
if constexpr (sizeof...(remaining_funcs) == 0) {
static_assert(
mp_size<func_arg_types>::value == 0,
"Last function in `safe::function` returns the default value and must not take any arguments.");

return func();

} else {
static_assert(
mp_size<func_arg_types>::value == sizeof...(args),
"The number of arguments passed in must match the args in func.");

bool const args_satisfy_reqs =
detail::check(func_arg_types{}, std::forward<decltype(args)>(args)...);

if (args_satisfy_reqs) {
return func(std::forward<decltype(args)>(args)...);

} else { // check the remaining functions' requirements
return function<RetT>(remaining_funcs...)(std::forward<decltype(args)>(args)...);
}
}
};
}
}
}
3 changes: 2 additions & 1 deletion include/safe/int.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ namespace safe {
typename T,
char... Chars>
[[nodiscard]] constexpr auto to_constant() {
constexpr T value = [](){
// FIXME: handle or fail at compile-time for invalid strings
constexpr T value = [](){
constexpr std::array<char, sizeof...(Chars)> chars{Chars...};
T sum = 0;

Expand Down
Loading