// Copyright (c) 2020 INRA Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef ORG_VLEPROJECT_IRRITATOR_2020 #define ORG_VLEPROJECT_IRRITATOR_2020 #include #include #ifdef __has_include #if __has_include() #include #define irt_have_numbers 1 #else #define irt_have_numbers 0 #endif #endif #include #include #include #include #include /***************************************************************************** * * Helper macros * ****************************************************************************/ #ifndef irt_assert #include #define irt_assert(_expr) assert(_expr) #endif namespace irt { static inline bool is_fatal_breakpoint = true; } #ifndef NDEBUG #if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) && \ __GNUC__ >= 2 #define irt_breakpoint() \ do { \ if (::irt::is_fatal_breakpoint) \ __asm__ __volatile__("int $03"); \ } while (0) #elif (defined(_MSC_VER) || defined(__DMC__)) && defined(_M_IX86) #define irt_breakpoint() \ do { \ if (::irt::is_fatal_breakpoint) \ __asm int 3h \ } while (0) #elif defined(_MSC_VER) #define irt_breakpoint() \ do { \ if (::irt::is_fatal_breakpoint) \ __debugbreak(); \ } while (0) #elif defined(__alpha__) && !defined(__osf__) && defined(__GNUC__) && \ __GNUC__ >= 2 #define irt_breakpoint() \ do { \ if (::irt::is_fatal_breakpoint) \ __asm__ __volatile__("bpt"); \ } while (0) #elif defined(__APPLE__) #define irt_breakpoint() \ do { \ if (::irt::is_fatal_breakpoint) \ __builtin_trap(); \ } while (0) #else /* !__i386__ && !__alpha__ */ #define irt_breakpoint() \ do { \ if (::irt::is_fatal_breakpoint) \ raise(SIGTRAP); \ } while (0) #endif /* __i386__ */ #else #define irt_breakpoint() \ do { \ } while (0) #endif #define irt_bad_return(status__) \ do { \ irt_breakpoint(); \ return status__; \ } while (0) #define irt_return_if_bad(expr__) \ do { \ auto status__ = (expr__); \ if (status__ != status::success) { \ irt_breakpoint(); \ return status__; \ } \ } while (0) #define irt_return_if_fail(expr__, status__) \ do { \ if (!(expr__)) { \ irt_breakpoint(); \ return status__; \ } \ } while (0) #if defined(__GNUC__) #define irt_unreachable() __builtin_unreachable(); #elif defined(_MSC_VER) #define irt_unreachable() __assume(0) #else #define irt_unreachable() #endif namespace irt { using i8 = int8_t; using i16 = int16_t; using i32 = int32_t; using i64 = int64_t; using u8 = uint8_t; using u16 = uint16_t; using u32 = uint32_t; using u64 = uint64_t; using sz = size_t; template constexpr typename std::make_unsigned::type to_unsigned(Integer value) { irt_assert(value >= 0); return static_cast::type>(value); } /***************************************************************************** * * Return status of many function * ****************************************************************************/ enum class status { success, unknown_dynamics, block_allocator_bad_capacity, block_allocator_not_enough_memory, head_allocator_bad_capacity, head_allocator_not_enough_memory, simulation_not_enough_model, simulation_not_enough_memory_message_list_allocator, simulation_not_enough_memory_input_port_list_allocator, simulation_not_enough_memory_output_port_list_allocator, data_array_init_capacity_error, data_array_not_enough_memory, data_array_archive_init_capacity_error, data_array_archive_not_enough_memory, array_init_capacity_zero, array_init_capacity_too_big, array_init_not_enough_memory, vector_init_capacity_zero, vector_init_capacity_too_big, vector_init_not_enough_memory, dynamics_unknown_id, dynamics_unknown_port_id, dynamics_not_enough_memory, model_connect_output_port_unknown, model_connect_input_port_unknown, model_connect_already_exist, model_connect_bad_dynamics, model_integrator_dq_error, model_integrator_X_error, model_integrator_internal_error, model_integrator_output_error, model_integrator_running_without_x_dot, model_integrator_ta_with_bad_x_dot, model_quantifier_bad_quantum_parameter, model_quantifier_bad_archive_length_parameter, model_quantifier_shifting_value_neg, model_quantifier_shifting_value_less_1, model_time_func_bad_init_message, model_flow_bad_samplerate, model_flow_bad_data, gui_not_enough_memory, io_not_enough_memory, io_file_format_error, io_file_format_model_error, io_file_format_model_number_error, io_file_format_model_unknown, io_file_format_dynamics_unknown, io_file_format_dynamics_limit_reach, io_file_format_dynamics_init_error }; constexpr i8 status_last() noexcept { return static_cast(status::io_file_format_dynamics_init_error); } constexpr sz status_size() noexcept { return static_cast(status_last() + static_cast(1)); } constexpr bool is_success(status s) noexcept { return s == status::success; } constexpr bool is_bad(status s) noexcept { return s != status::success; } template constexpr bool is_status_equal(status s, Args... args) noexcept { return ((s == args) || ... || false); } inline status check_return(status s) noexcept { if (s != status::success) irt_breakpoint(); return s; } template constexpr bool match(const T& s, Args... args) noexcept { return ((s == args) || ... || false); } template constexpr bool are_all_same() noexcept { return (std::is_same_v && ...); } template typename std::enable_if::is_integer, bool>::type almost_equal(T x, T y, int ulp) { return std::fabs(x - y) <= std::numeric_limits::epsilon() * std::fabs(x + y) * ulp || std::fabs(x - y) < std::numeric_limits::min(); } /***************************************************************************** * * Definition of a lightweight std::function * ****************************************************************************/ template class function_ref; template class function_ref { public: constexpr function_ref() noexcept = delete; /// Creates a `function_ref` which refers to the same callable as `rhs`. constexpr function_ref(const function_ref& rhs) noexcept = default; /// Constructs a `function_ref` referring to `f`. /// /// \synopsis template constexpr function_ref(F &&f) noexcept template< typename F, std::enable_if_t, function_ref>::value && std::is_invocable_r::value>* = nullptr> constexpr function_ref(F&& f) noexcept : obj(const_cast(reinterpret_cast(std::addressof(f)))) { cb = [](void* obj, Args... args) -> R { return std::invoke( *reinterpret_cast::type>(obj), std::forward(args)...); }; } /// Makes `*this` refer to the same callable as `rhs`. constexpr function_ref& operator=( const function_ref& rhs) noexcept = default; /// Makes `*this` refer to `f`. /// /// \synopsis template constexpr function_ref &operator=(F &&f) /// noexcept; template< typename F, std::enable_if_t::value>* = nullptr> constexpr function_ref& operator=(F&& f) noexcept { obj = reinterpret_cast(std::addressof(f)); cb = [](void* obj, Args... args) { return std::invoke( *reinterpret_cast::type>(obj), std::forward(args)...); }; return *this; } constexpr void swap(function_ref& rhs) noexcept { std::swap(obj, rhs.obj); std::swap(cb, rhs.cb); } R operator()(Args... args) const { return cb(obj, std::forward(args)...); } private: void* obj = nullptr; R (*cb)(void*, Args...) = nullptr; }; /// Swaps the referred callables of `lhs` and `rhs`. template constexpr void swap(function_ref& lhs, function_ref& rhs) noexcept { lhs.swap(rhs); } template function_ref(R (*)(Args...)) -> function_ref; template function_ref(R (*)(Args...) noexcept) -> function_ref; /***************************************************************************** * * Definition of Time * * TODO: * - enable template definition of float or [float|double,bool absolute] * representation of time? * ****************************************************************************/ using time = double; template struct time_domain {}; template<> struct time_domain