Skip to content

Commit

Permalink
moved from hope, small refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
glensand committed Jan 21, 2024
1 parent 00a9dea commit bdd7002
Show file tree
Hide file tree
Showing 39 changed files with 3,636 additions and 0 deletions.
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.11)

project(hope-core-main)

enable_testing()

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_subdirectory(test)
add_subdirectory(lib)
20 changes: 20 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.11)

project(hope-core)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

file(GLOB HOPE_HEADERS
hope_core/fsm*.h
hope_core/switch_expression*.h
hope_core/tuple*.h
hope_core/type_traits*.h
)

add_library(hope-core INTERFACE ${HOPE_HEADERS})
target_include_directories(hope-core INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

set(CMAKE_INSTALL_DIRECTORY ${CMAKE_BINARY_DIR})
INSTALL(DIRECTORY hope_core/ DESTINATION ${CMAKE_INSTALL_DIRECTORY}/include/hope_core
FILES_MATCHING PATTERN "*.h")
67 changes: 67 additions & 0 deletions lib/hope_core/fsm/fsm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* Copyright (C) 2021 - 2024 Gleb Bezborodov - All Rights Reserved
* You may use, distribute and modify this code under the
* terms of the MIT license.
*
* You should have received a copy of the MIT license with
* this file. If not, please write to: bezborodoff.gleb@gmail.com, or visit : https://github.com/glensand/hope-core
*/

#pragma once

#include "hope/tuple/flat_tuple.h"
#include <variant>

namespace hope::fsm {

template <typename State>
struct transit_to final {
using target_state_t = State;
};

template <typename, typename... Ts>
class fsm;

template <typename... States, typename... Handlers>
class fsm<flat_tuple<States...>, Handlers...> final : public Handlers... {
public:
using Handlers::operator()...;

constexpr explicit fsm(Handlers&&... handlers)
: Handlers(std::forward<Handlers>(handlers))...{ }

template<typename Event>
void on_event(Event&& e) {
std::size_t state_index{ 0 };
bool transition_done{ false };
for_each(states, [&] (auto&& state){
if(!transition_done && state_index == cur_state) {
using state_t = std::decay_t<decltype(state)>;
if constexpr (std::is_invocable_v<fsm, state_t, Event&&>) {
using result_t = std::invoke_result_t<fsm, state_t, Event&&>;
auto transition_res = this->operator()(state, std::forward<Event>(e));
(void)transition_res; // remove unused variable warning (var is handled 'cause it may be used later)
if constexpr (!std::is_same_v<result_t, void>) { // move to next state
cur_state = find<typename result_t::target_state_t>(type_list<States...>{});
transition_done = true;
}
}
}
++state_index;
});
}

[[nodiscard]] std::size_t get_cur_state() const noexcept {
return cur_state;
}

private:
flat_tuple<States...> states;
std::size_t cur_state{ 0 };
};

template <typename... States, typename... Handlers>
constexpr auto make(Handlers&&... handlers) {
return fsm<flat_tuple<States...>, Handlers...>(std::forward<Handlers>(handlers)...);
}

}
102 changes: 102 additions & 0 deletions lib/hope_core/switch_expression/switch_expression.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* Copyright (C) 2021 - 2024 Gleb Bezborodov - All Rights Reserved
* You may use, distribute and modify this code under the
* terms of the MIT license.
*
* You should have received a copy of the MIT license with
* this file. If not, please write to: bezborodoff.gleb@gmail.com, or visit : https://github.com/glensand/hope-core
*/

#pragma once

#include <tuple>
#include "hope_core/type_traits/type_list.h"

namespace hope {

template<typename... Ts>
class switch_expression_member final {
static_assert(sizeof ...(Ts) > 0);
public:
explicit switch_expression_member(const Ts&... args)
: expression(args...) {

}

template<typename TKey, typename TClass, typename... TVs>
bool apply(TClass& instance, const TKey& key, TVs&&... args) {
return evaluate(instance, key, std::make_index_sequence<sizeof ...(Ts)>{}, std::forward<TVs>(args)...);
}

private:
template<typename TKey, typename TClass, std::size_t...Is, typename... TVs>
bool evaluate(TClass& instance, const TKey key, std::index_sequence<Is...>, TVs&&... args) {
return (... || try_apply<Is>(instance, key, std::forward<TVs>(args)...));
}

template<std::size_t I, typename TKey, typename TClass, typename... TVs>
bool try_apply(TClass& Instance, const TKey key, TVs&&... args) {
if constexpr (I + 1 < sizeof ...(Ts)) {
// Even is a key, odd is a function
if constexpr (I % 2 == 0) {
// todo:: check if callable
if (key == std::get<I>(expression)) {
auto* function = std::get<I + 1>(expression);
(Instance.*function)(std::forward<TVs>(Args)...);
return true;
}
}
}
return false;
}

std::tuple<Ts...> expression;
};

template<typename... Ts>
switch_expression_member(Ts...) -> switch_expression_member<Ts...>;


template<typename... Ts>
class switch_expression_lambda final {
static_assert(sizeof ...(Ts) > 0);

public:
explicit switch_expression_lambda(const Ts&... args)
: expression(args...) {

}

template<typename TKey, typename... TVs>
bool apply(const TKey& key, TVs&&... vals) {
return evaluate(key, std::make_index_sequence<sizeof ...(Ts)>{}, std::forward<TVs>(vals)...);
}

private:
template<typename TKey, std::size_t...Is, typename... TVs>
bool evaluate(const TKey& key, std::index_sequence<Is...>, TVs&&... vals) {
return (... || try_apply<Is>(key, std::forward<TVs>(vals)...));
}

template<std::size_t I, typename TKey, typename... TVs>
bool try_apply(const TKey& key, TVs&&... vals) {
if constexpr (I + 1 < sizeof ...(Ts)) {
// Even is a key, odd is a function
if constexpr (I % 2 == 0) {
// todo:: check if callable
if (key == std::get<I>(expression)) {
auto&& function = std::get<I + 1>(expression);
function(std::forward<TVs>(vals)...);
return true;
}
}
}
return false;
}

std::tuple<Ts...> expression;
};

template<typename... Ts>
switch_expression_lambda(Ts...) -> switch_expression_lambda<Ts...>;

}
71 changes: 71 additions & 0 deletions lib/hope_core/tuple/compute_field_count_recursive.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* Copyright (C) 2020 - 2024 Gleb Bezborodov - All Rights Reserved
* You may use, distribute and modify this code under the
* terms of the MIT license.
*
* You should have received a copy of the MIT license with
* this file. If not, please write to: bezborodoff.gleb@gmail.com, or visit : https://github.com/glensand/hope-core
*/

#pragma once

#include "hope_core/tuple/tuple_from_struct.h"
#include "hope_core/tuple/tuple_from_struct_unsafe.h"
#include "hope_core/tuple/tuple_policy.h"
#include "hope_core/type_traits/user_defined_types.h"
#include "hope_core/type_traits/detector.h"

/*! \defgroup <reflection> Static reflection
@{
\file
\brief the file contains several functions for recursively calculating the number of fields within the structure.
Only user-defined types are computed recursively, the classes of the standard library are considered a single whole
*/

namespace hope {

/**
* Implementation of the compile - time fields count computer. Is intended to use with c++ aggregates
* @tparam TStructure Structure structure the number of fields to be calculated
* @return Number of fields
*/
template<typename TStructure>
constexpr std::size_t compute_field_count_recursive_constexpr() {
if constexpr (is_user_defined_type_v<TStructure>) {
constexpr auto fields_count = detect_fields_count<TStructure>();
constexpr auto types = detail::extract_types<TStructure>(std::make_index_sequence<fields_count>());
std::size_t count{0};
for_each(types, [&](auto field) {
using type_t = typename decltype(field)::Type;
count += compute_field_count_recursive_constexpr<type_t>();
});
return count;
} else {
return 1u;
}
}

/**
* Implementation of the run - time fields count computer; NOTE: each subfield will be instantiated,
* be aware of usages of this function for heavy - weight objects.
* @tparam TStructure Structure structure the number of fields to be calculated
* @return Number of fields
*/
template<typename TStructure>
std::size_t compute_field_count_recursive() {
if constexpr(is_user_defined_type_v<TStructure>) {
const TStructure object{};
auto tuple = tuple_from_struct(object, field_policy::reference{});
std::size_t count{0};
for_each(tuple, [&](auto &&field) {
using type_t = std::decay_t<decltype(field)>;
count += compute_field_count_recursive<type_t>();
});
return count;
} else {
return 1u;
}
}

}

/*! @} */
90 changes: 90 additions & 0 deletions lib/hope_core/tuple/detect_fields_count.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/* Copyright (C) 2020 - 2024 Gleb Bezborodov - All Rights Reserved
* You may use, distribute and modify this code under the
* terms of the MIT license.
*
* You should have received a copy of the MIT license with
* this file. If not, please write to: bezborodoff.gleb@gmail.com, or visit : https://github.com/glensand/hope-core
*/

#pragma once

#include <utility>

/*! \defgroup <reflection> Static reflection
@{
\file
\brief This file consists of helper functions which is used to compute fields count (in general)
And the only one function which computes count of the structure's fields (non - recursive)
*/

namespace hope {
namespace detail {

/**
* The only one reason of existing of this class is initialization of object of different types.
* This is the same as ubiq from magic-get
* @tparam TStruct Type to be converted to
* @tparam I Index, is used to unambiguously define the type
*/
template <typename TStruct, std::size_t I>
struct any_convertible {
template <typename T, typename = std::enable_if_t<!std::is_base_of_v<T, TStruct>>>
constexpr operator T& () const noexcept;
};

/**
* This two functions is needed to determine whether object of corresponding type might be constructed with
* specified count of objects or not. NOTE: uses aggregate initialization, only aggregate initialisable
* classes are allowed.
* @tparam TStruct type of the structure to check
* @tparam Is Sequence of indexes to initialize
* @return true if the type is initialisable with sizeof(Is...) objects
*/
template <typename TStruct, std::size_t... Is>
constexpr auto is_constructable_n(std::index_sequence<Is...>)
->decltype(TStruct{ any_convertible<TStruct, Is>{}... }, bool()) {
return true;
}
template <typename TStruct, std::size_t... Is>
constexpr auto is_constructable_n(...) {
return false;
}

/**
* Implementation of the fields computation function.
* @tparam TStructure Desired type
* @tparam Is Indexes of the sequence
* @param sequence Helper sequence of the indexes which might be used to compute fields count
* @return Count of structure's fields
*/
template <typename TStructure, std::size_t... Is>
constexpr std::size_t detect_fields_count_impl(std::index_sequence<Is...> sequence) {
bool bs[] = { is_constructable_n<TStructure>(std::make_index_sequence<Is>())... };
// since cxx20... msvc sucks
//return std::distance(std::begin(bs), std::find(
// std::begin(bs), std::end(bs), false)
//);

for (std::size_t i{ 1 }; i < sequence.size(); ++i) {
if (!bs[i]) return i - 1;
}
return 0;
}
}

/**
* Interface of computation function, is intended to catch all the errors and show error reason.
* @tparam TStructure Desired type to compute fields.
* @return Number of fields
*/
template <typename TStructure>
constexpr std::size_t detect_fields_count() {
static_assert(!std::is_polymorphic_v<TStructure>, "---- hope ---- Polymorphic types are not allowed");
static_assert(std::is_aggregate_v<TStructure>, "---- hope ---- Only aggregate initializable types are allowed");

constexpr auto size = sizeof(TStructure);
return detail::detect_fields_count_impl<TStructure>(std::make_index_sequence<size + 2>());
}
}

/*! @} */
Loading

0 comments on commit bdd7002

Please sign in to comment.