diff --git a/Mk2_3phase_RFdatalog_temp/movingAvg.h b/Mk2_3phase_RFdatalog_temp/movingAvg.h index 7ce38544..2a36b34c 100644 --- a/Mk2_3phase_RFdatalog_temp/movingAvg.h +++ b/Mk2_3phase_RFdatalog_temp/movingAvg.h @@ -16,68 +16,131 @@ #include "type_traits.hpp" -template< typename T, uint8_t N = 10 > +/** + * @brief Template class for implementing a sliding average + * + * @tparam T Type of values to be stored + * @tparam DURATION_IN_MINUTES Size of main array + * @tparam VALUES_PER_MINUTE Size of sub array + * + * @note + * Since the Arduino RAM is tiny, we need to store a few values as possible. + * Suppose, you want a sliding window of 10 minutes and receive a value every 5 seconds. + * With one single array, 10 x 12 values would be necessary to store. + * Using 2 arrays, one to store incoming values over 1 minute and one to store values every minutes, + * we need only 12 + 10 values. + * How it works : + * - the average is calculated over 1 minute with incoming values + * - this sub-average is added to the main array + * - the average is calculated on the main array + * + * Drawback of this method: the average is updated only every minutes ! + */ +template< typename T, uint8_t DURATION_IN_MINUTES = 10, uint8_t VALUES_PER_MINUTE = 10 > class movingAvg { public: + /** + * @brief Reset everything + * + */ void clear() { _idx = 0; + _sub_idx = 0; if constexpr (is_floating_point< T >::value) - _sum = 0.0; + { + _sum = 0.0F; + _sub_sum = 0.0F; + } else + { _sum = 0; + _sub_sum = 0; + } - uint8_t i{ N }; - do - { + uint8_t i{ DURATION_IN_MINUTES }; + do { --i; if constexpr (is_floating_point< T >::value) - _ar[i] = 0.0; + { + _ar[i] = 0.0F; + _sub_ar[i] = 0.0F; + } else + { _ar[i] = 0; + _sub_ar[i] = 0; + } } while (i); } + /** + * @brief Add a value + * + * @param _value Value to be added + */ void addValue(const T& _value) { - _sum -= _ar[_idx]; - _ar[_idx] = _value; - _sum += _value; - ++_idx; + _sub_sum -= _sub_ar[_sub_idx]; + _sub_ar[_sub_idx] = _value; + _sub_sum += _value; + ++_sub_idx; - if (_idx == N) + if (_sub_idx == VALUES_PER_MINUTE) { - _idx = 0; // faster than % + _sub_idx = 0; // faster than % + _addValue(_getAverage()); } } void fillValue(const T& _value) { _idx = 0; - _sum = N * _value; + _sum = DURATION_IN_MINUTES * _value; - uint8_t i{ N }; + uint8_t i{ DURATION_IN_MINUTES }; do { _ar[--i] = _value; } while (i); } + /** + * @brief Get the sliding average + * + * @return auto The sliding average + * + * @note This value is updated every minute, except for the special case of a duration of + * ONE minute. In this case, it is updated for each new input value. + */ auto getAverage() const { - return _sum / N; + if constexpr (DURATION_IN_MINUTES == 1) + return _getAverage(); + else if constexpr (DURATION_IN_MINUTES == 2) + return _sum >> 1; + else if constexpr (DURATION_IN_MINUTES == 4) + return _sum >> 2; + else if constexpr (DURATION_IN_MINUTES == 8) + return _sum >> 3; + else if constexpr (DURATION_IN_MINUTES == 16) + return _sum >> 4; + else if constexpr (DURATION_IN_MINUTES == 32) + return _sum >> 5; + else + return _sum * invN; } auto getElement(uint8_t idx) const { - if (idx >= N) + if (idx >= DURATION_IN_MINUTES) { if constexpr (is_floating_point< T >::value) - return 0.0; + return 0.0F; else - return 0; + return (T)0; } return _ar[idx]; @@ -85,16 +148,58 @@ class movingAvg constexpr uint8_t getSize() const { - return N; + return DURATION_IN_MINUTES; + } + +private: + void _clear_sub() + { + _sub_idx = 0; + + if constexpr (is_floating_point< T >::value) + _sub_sum = 0.0F; + else + _sub_sum = 0; + + uint8_t i{ VALUES_PER_MINUTE }; + do { + --i; + if constexpr (is_floating_point< T >::value) + _sub_ar[i] = 0.0F; + else + _sub_ar[i] = 0; + } while (i); + } + + void _addValue(const T& _value) + { + _sum -= _ar[_idx]; + _ar[_idx] = _value; + _sum += _value; + ++_idx; + + if (_idx == DURATION_IN_MINUTES) + { + _idx = 0; // faster than % + } + } + + auto _getAverage() const + { + return _sub_sum * invD; } private: uint8_t _idx{ 0 }; + uint8_t _sub_idx{ 0 }; typename conditional< is_floating_point< T >::value, T, int32_t >::type _sum{ 0 }; + typename conditional< is_floating_point< T >::value, T, int32_t >::type _sub_sum{ 0 }; - T _ar[N]{}; + T _sub_ar[VALUES_PER_MINUTE]{}; + T _ar[DURATION_IN_MINUTES]{}; - static constexpr float invN{ 1 / N }; + static constexpr float invD{ 1.0 / VALUES_PER_MINUTE }; + static constexpr float invN{ 1.0 / DURATION_IN_MINUTES }; }; #endif diff --git a/Mk2_3phase_RFdatalog_temp/utils_relay.h b/Mk2_3phase_RFdatalog_temp/utils_relay.h index ac231b00..40721595 100644 --- a/Mk2_3phase_RFdatalog_temp/utils_relay.h +++ b/Mk2_3phase_RFdatalog_temp/utils_relay.h @@ -233,7 +233,7 @@ template< uint8_t T = 1 > class relayOutput mutable uint16_t duration{ 0 }; /**< Duration of the current state */ mutable bool relayIsON{ false }; /**< True if the relay is ON */ - static inline movingAvg< int16_t, T * 60 / DATALOG_PERIOD_IN_SECONDS > sliding_Average; + static inline movingAvg< int16_t, T, 60 / DATALOG_PERIOD_IN_SECONDS > sliding_Average; }; #endif // _UTILS_RELAY_H \ No newline at end of file diff --git a/Mk2_3phase_RFdatalog_temp/validation.h b/Mk2_3phase_RFdatalog_temp/validation.h index 1245be3f..1c8a8717 100644 --- a/Mk2_3phase_RFdatalog_temp/validation.h +++ b/Mk2_3phase_RFdatalog_temp/validation.h @@ -42,7 +42,10 @@ static_assert(!(DUAL_TARIFF & (ul_OFF_PEAK_DURATION > 12)), "******** Off-peak d static_assert(!EMONESP_CONTROL || (DIVERSION_PIN_PRESENT && DIVERSION_PIN_PRESENT && (PRIORITY_ROTATION == RotationModes::PIN) && OVERRIDE_PIN_PRESENT), "******** Wrong configuration. Please check your config.h ! ********"); -constexpr uint16_t check_pins() +static_assert(!RELAY_DIVERSION | (60 / DATALOG_PERIOD_IN_SECONDS * DATALOG_PERIOD_IN_SECONDS == 60), "******** Wrong configuration. DATALOG_PERIOD_IN_SECONDS must be a divider of 60 ! ********"); + +constexpr uint16_t +check_pins() { uint16_t used_pins{ 0 }; diff --git a/dev/MathPerfTests/MathPerfTests.ino b/dev/MathPerfTests/MathPerfTests.ino new file mode 100644 index 00000000..b478ac3d --- /dev/null +++ b/dev/MathPerfTests/MathPerfTests.ino @@ -0,0 +1,111 @@ + +#include + +#include "movingAvg.h" + +const int nb_of_interation_per_pass = 30000; +const int nb_of_pass = 100; + +unsigned long initial_time = 0; +unsigned long final_time = 0; + +float duration_dummy_loop = 0; +float duration = 0; +float duration_sum = 0; + + +// All variables used for calculations are declared globally and volatile to minimize +// any possible compiler optimisation when performing the same operation multiple times. + +volatile int dummy = 0; + +volatile float float_1 = 0; +volatile float float_2 = 0; +volatile float float_3 = 0; + +volatile long long_1 = 0; +volatile long long_2 = 0; +volatile long long_3 = 0; + +volatile int int_1 = 0; +volatile int int_2 = 0; +volatile int int_3 = 0; + +volatile byte byte_1 = 0; +volatile byte byte_2 = 0; +volatile byte byte_3 = 0; + +volatile boolean bool_1 = 0; +volatile boolean bool_2 = 0; +volatile boolean bool_3 = 0; + +movingAvg< int32_t, 1, 12 > sliding_Average; + +void setup() { + + Serial.begin(115200); +} + +void loop() { + + for (int j = 0; j < nb_of_pass; j++) { + + // STEP 1: We first calculate the time taken to run a dummy FOR loop to measure the overhead cause by the execution of the loop. + initial_time = micros(); + for (int i = 0; i < nb_of_interation_per_pass; i++) { + dummy++; // A dummy instruction is introduced here. If not, the compiler is smart enough to just skip the loop entirely... + } + final_time = micros(); + duration_dummy_loop = float(final_time - initial_time) / nb_of_interation_per_pass; // The average duration of a dummy loop is calculated + dummy = 0; + + // STEP 2 (optional): Pick some relevant random numbers to test the command under random conditions. Make sure to pick numbers appropriate for your command (e.g. no negative number for the command "sqrt()") + randomSeed(micros() * analogRead(0)); + long_1 = random(-36000, 36000); + + // STEP 3: Calculation of the time taken to run the dummy FOR loop and the command to test. + initial_time = micros(); + for (int i = 0; i < nb_of_interation_per_pass; i++) { + dummy++; // The dummy instruction is also performed here so that we can remove the effect of the dummy FOR loop accurately. + // **************** PUT YOUR COMMAND TO TEST HERE ******************** + sliding_Average.addValue(i); + + long_3 = sliding_Average.getAverage(); + // **************** PUT YOUR COMMAND TO TEST HERE ******************** + } + final_time = micros(); + + // STEP 4: Calculation of the time taken to run only the target command. + duration = float(final_time - initial_time) / nb_of_interation_per_pass - duration_dummy_loop; + duration_sum += duration; + dummy = 0; + + Serial.print(sliding_Average.getAverage()); + Serial.print(" - "); + Serial.print(j); + Serial.print(". "); + print_result(duration); + } + + Serial.println(); + Serial.println("********* FINAL AVERAGED VALUE *********** "); + print_result(duration_sum / nb_of_pass); + Serial.println("****************************************** "); + Serial.println(); + for (uint8_t idx = 0; idx < sliding_Average.getSize(); ++idx) { + Serial.println(sliding_Average.getElement(idx)); + } + Serial.println(); + duration_sum = 0; + delay(2000); +} + +void print_result(float value_to_print) { + Serial.print("Time to execute command: "); + Serial.print("\t"); + Serial.print(value_to_print, 3); + Serial.print(" us"); + Serial.print("\t"); + Serial.print(round(value_to_print * 16)); + Serial.println(" cycles"); +} \ No newline at end of file diff --git a/dev/MathPerfTests/movingAvg.h b/dev/MathPerfTests/movingAvg.h new file mode 100644 index 00000000..c232fd7f --- /dev/null +++ b/dev/MathPerfTests/movingAvg.h @@ -0,0 +1,205 @@ +/** + * @file movingAvg.h + * @author Frédéric Metrich (frederic.metrich@live.fr) + * @brief Code for sliding-window average + * @version 0.1 + * @date 2023-06-14 + * + * @copyright Copyright (c) 2023 + * + */ + +#ifndef MOVINGAVG_H +#define MOVINGAVG_H + +#include + +#include "type_traits.hpp" + +/** + * @brief Template class for implementing a sliding average + * + * @tparam T Type of values to be stored + * @tparam DURATION_IN_MINUTES Size of main array + * @tparam VALUES_PER_MINUTE Size of sub array + * + * @note + * Since the Arduino RAM is tiny, we need to store a few values as possible. + * Suppose, you want a sliding window of 10 minutes and receive a value every 5 seconds. + * With one single array, 10 x 12 values would be necessary to store. + * Using 2 arrays, one to store incoming values over 1 minute and one to store values every minutes, + * we need only 12 + 10 values. + * How it works : + * - the average is calculated over 1 minute with incoming values + * - this sub-average is added to the main array + * - the average is calculated on the main array + * + * Drawback of this method: the average is updated only every minutes ! + */ +template< typename T, uint8_t DURATION_IN_MINUTES = 10, uint8_t VALUES_PER_MINUTE = 10 > +class movingAvg +{ +public: + /** + * @brief Reset everything + * + */ + void clear() + { + _idx = 0; + _sub_idx = 0; + + if constexpr (is_floating_point< T >::value) + { + _sum = 0.0F; + _sub_sum = 0.0F; + } + else + { + _sum = 0; + _sub_sum = 0; + } + + uint8_t i{ DURATION_IN_MINUTES }; + do { + --i; + if constexpr (is_floating_point< T >::value) + { + _ar[i] = 0.0F; + _sub_ar[i] = 0.0F; + } + else + { + _ar[i] = 0; + _sub_ar[i] = 0; + } + } while (i); + } + + /** + * @brief Add a value + * + * @param _value Value to be added + */ + void addValue(const T& _value) + { + _sub_sum -= _sub_ar[_sub_idx]; + _sub_ar[_sub_idx] = _value; + _sub_sum += _value; + ++_sub_idx; + + if (_sub_idx == VALUES_PER_MINUTE) + { + _sub_idx = 0; // faster than % + _addValue(_getAverage()); + } + } + + void fillValue(const T& _value) + { + _idx = 0; + _sum = DURATION_IN_MINUTES * _value; + + uint8_t i{ DURATION_IN_MINUTES }; + do + { + _ar[--i] = _value; + } while (i); + } + + /** + * @brief Get the sliding average + * + * @return auto The sliding average + * + * @note This value is updated every minute, except for the special case of a duration of + * ONE minute. In this case, it is updated for each new input value. + */ + auto getAverage() const + { + if constexpr (DURATION_IN_MINUTES == 1) + return _getAverage(); + else if constexpr (DURATION_IN_MINUTES == 2) + return _sum >> 1; + else if constexpr (DURATION_IN_MINUTES == 4) + return _sum >> 2; + else if constexpr (DURATION_IN_MINUTES == 8) + return _sum >> 3; + else if constexpr (DURATION_IN_MINUTES == 16) + return _sum >> 4; + else if constexpr (DURATION_IN_MINUTES == 32) + return _sum >> 5; + else + return _sum * invN; + } + + auto getElement(uint8_t idx) const + { + if (idx >= DURATION_IN_MINUTES) + { + if constexpr (is_floating_point< T >::value) + return 0.0F; + else + return (T)0; + } + + return _ar[idx]; + } + + constexpr uint8_t getSize() const + { + return DURATION_IN_MINUTES; + } + +private: + void _clear_sub() + { + _sub_idx = 0; + + if constexpr (is_floating_point< T >::value) + _sub_sum = 0.0F; + else + _sub_sum = 0; + + uint8_t i{ VALUES_PER_MINUTE }; + do { + --i; + if constexpr (is_floating_point< T >::value) + _sub_ar[i] = 0.0F; + else + _sub_ar[i] = 0; + } while (i); + } + + void _addValue(const T& _value) + { + _sum -= _ar[_idx]; + _ar[_idx] = _value; + _sum += _value; + ++_idx; + + if (_idx == DURATION_IN_MINUTES) + { + _idx = 0; // faster than % + } + } + + auto _getAverage() const + { + return _sub_sum * invD; + } + +private: + uint8_t _idx{ 0 }; + uint8_t _sub_idx{ 0 }; + typename conditional< is_floating_point< T >::value, T, int32_t >::type _sum{ 0 }; + typename conditional< is_floating_point< T >::value, T, int32_t >::type _sub_sum{ 0 }; + + T _sub_ar[VALUES_PER_MINUTE]{}; + T _ar[DURATION_IN_MINUTES]{}; + + static constexpr float invD{ 1.0 / VALUES_PER_MINUTE }; + static constexpr float invN{ 1.0 / DURATION_IN_MINUTES }; +}; + +#endif diff --git a/dev/MathPerfTests/movingAvg.h.bak b/dev/MathPerfTests/movingAvg.h.bak new file mode 100644 index 00000000..ad8a5342 --- /dev/null +++ b/dev/MathPerfTests/movingAvg.h.bak @@ -0,0 +1,170 @@ +/** + * @file movingAvg.h + * @author Frédéric Metrich (frederic.metrich@live.fr) + * @brief Code for sliding-window average + * @version 0.1 + * @date 2023-06-14 + * + * @copyright Copyright (c) 2023 + * + */ + +#ifndef MOVINGAVG_H +#define MOVINGAVG_H + +#include + +#include "type_traits.hpp" + +/** + * @brief Template class for implementing a sliding average + * + * @tparam T Type of values to be stored + * @tparam DURATION_IN_MINUTES Size of main array + * @tparam VALUES_PER_MINUTE Size of sub array + * + * @note + * Since the Arduino RAM is tiny, we need to store a few values as possible. + * Suppose, you want a sliding window of 10 minutes and receive a value every 5 seconds. + * With one single array, 10 x 12 values would be necessary to store. + * Using 2 arrays, one to store incoming values over 1 minute and one to store values every minutes, + * we need only 12 + 10 values. + * How it works : + * - the average is calculated over 1 minute with incoming values + * - this sub-average is added to the main array + * - the average is calculated on the main array + * + * Drawback of this method: the average is updated only every minutes ! + */ +template< typename T, uint8_t DURATION_IN_MINUTES = 10, uint8_t VALUES_PER_MINUTE = 10 > +class movingAvg { +public: + void clear() { + _idx = 0; + _sub_idx = 0; + + if constexpr (is_floating_point< T >::value) { + _sum = 0.0F; + _sub_sum = 0.0F; + } else { + _sum = 0; + _sub_sum = 0; + } + + uint8_t i{ DURATION_IN_MINUTES }; + do { + --i; + if constexpr (is_floating_point< T >::value) { + _ar[i] = 0.0F; + _sub_ar[i] = 0.0F; + } else { + _ar[i] = 0; + _sub_ar[i] = 0; + } + } while (i); + } + + void addValue(const T& _value) { + _sub_sum -= _sub_ar[_sub_idx]; + _sub_ar[_sub_idx] = _value; + _sub_sum += _value; + ++_sub_idx; + + if (_sub_idx == VALUES_PER_MINUTE) { + _sub_idx = 0; // faster than % + + if constexpr (DURATION_IN_MINUTES != 1) + _addValue(_getAverage()); + } + } + + void fillValue(const T& _value) { + _idx = 0; + _sum = DURATION_IN_MINUTES * _value; + + uint8_t i{ DURATION_IN_MINUTES }; + do { + _ar[--i] = _value; + } while (i); + } + + auto getAverage() const { + if constexpr (DURATION_IN_MINUTES == 1) + return _getAverage(); + else if constexpr (DURATION_IN_MINUTES == 2) + return _sum >> 1; + else if constexpr (DURATION_IN_MINUTES == 4) + return _sum >> 2; + else if constexpr (DURATION_IN_MINUTES == 8) + return _sum >> 3; + else if constexpr (DURATION_IN_MINUTES == 16) + return _sum >> 4; + else if constexpr (DURATION_IN_MINUTES == 32) + return _sum >> 5; + else + return _sum * invN; + } + + auto getElement(uint8_t idx) const { + if (idx >= DURATION_IN_MINUTES) { + if constexpr (is_floating_point< T >::value) + return 0.0F; + else + return (T)0; + } + + return _ar[idx]; + } + + constexpr uint8_t getSize() const { + return DURATION_IN_MINUTES; + } + +private: + void _clear_sub() { + _sub_idx = 0; + + if constexpr (is_floating_point< T >::value) + _sub_sum = 0.0F; + else + _sub_sum = 0; + + uint8_t i{ VALUES_PER_MINUTE }; + do { + --i; + if constexpr (is_floating_point< T >::value) + _sub_ar[i] = 0.0F; + else + _sub_ar[i] = 0; + } while (i); + } + + void _addValue(const T& _value) { + _sum -= _ar[_idx]; + _ar[_idx] = _value; + _sum += _value; + ++_idx; + + if (_idx == DURATION_IN_MINUTES) { + _idx = 0; // faster than % + } + } + + auto _getAverage() const { + return _sub_sum * invD; + } + +private: + uint8_t _idx{ 0 }; + uint8_t _sub_idx{ 0 }; + typename conditional< is_floating_point< T >::value, T, int32_t >::type _sum{ 0 }; + typename conditional< is_floating_point< T >::value, T, int32_t >::type _sub_sum{ 0 }; + + T _sub_ar[VALUES_PER_MINUTE]{}; + T _ar[DURATION_IN_MINUTES]{}; + + static constexpr float invD{ 1.0 / VALUES_PER_MINUTE }; + static constexpr float invN{ 1.0 / DURATION_IN_MINUTES }; +}; + +#endif diff --git a/dev/MathPerfTests/type_traits.hpp b/dev/MathPerfTests/type_traits.hpp new file mode 100644 index 00000000..ccacb696 --- /dev/null +++ b/dev/MathPerfTests/type_traits.hpp @@ -0,0 +1,36 @@ +/** + * @file type_traits.hpp + * @author Frédéric Metrich (frederic.metrich@live.fr) + * @brief Some useful but missing stl functions templates + * @version 0.1 + * @date 2023-06-14 + * + * @copyright Copyright (c) 2023 + * + */ + +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "type_traits/conditional.hpp" +#include "type_traits/enable_if.hpp" +#include "type_traits/integral_constant.hpp" +#include "type_traits/is_array.hpp" +#include "type_traits/is_base_of.hpp" +#include "type_traits/is_class.hpp" +#include "type_traits/is_const.hpp" +#include "type_traits/is_convertible.hpp" +#include "type_traits/is_enum.hpp" +#include "type_traits/is_floating_point.hpp" +#include "type_traits/is_integral.hpp" +#include "type_traits/is_pointer.hpp" +#include "type_traits/is_same.hpp" +#include "type_traits/is_signed.hpp" +#include "type_traits/is_unsigned.hpp" +#include "type_traits/make_unsigned.hpp" +#include "type_traits/make_void.hpp" +#include "type_traits/remove_const.hpp" +#include "type_traits/remove_reference.hpp" diff --git a/dev/MathPerfTests/type_traits/conditional.hpp b/dev/MathPerfTests/type_traits/conditional.hpp new file mode 100644 index 00000000..f74c048f --- /dev/null +++ b/dev/MathPerfTests/type_traits/conditional.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +template< bool Condition, class TrueType, class FalseType > +struct conditional +{ + typedef TrueType type; +}; + +template< class TrueType, class FalseType > +struct conditional< false, TrueType, FalseType > +{ + typedef FalseType type; +}; diff --git a/dev/MathPerfTests/type_traits/declval.hpp b/dev/MathPerfTests/type_traits/declval.hpp new file mode 100644 index 00000000..7fe4a586 --- /dev/null +++ b/dev/MathPerfTests/type_traits/declval.hpp @@ -0,0 +1,8 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +template< typename T > +T&& declval(); \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/enable_if.hpp b/dev/MathPerfTests/type_traits/enable_if.hpp new file mode 100644 index 00000000..7427afb4 --- /dev/null +++ b/dev/MathPerfTests/type_traits/enable_if.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +// A meta-function that return the type T if Condition is true. +template< bool Condition, typename T = void > +struct enable_if +{ +}; + +template< typename T > +struct enable_if< true, T > +{ + typedef T type; +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/integral_constant.hpp b/dev/MathPerfTests/type_traits/integral_constant.hpp new file mode 100644 index 00000000..632d3d97 --- /dev/null +++ b/dev/MathPerfTests/type_traits/integral_constant.hpp @@ -0,0 +1,14 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +template< typename T, T v > +struct integral_constant +{ + static const T value = v; +}; + +typedef integral_constant< bool, true > true_type; +typedef integral_constant< bool, false > false_type; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_array.hpp b/dev/MathPerfTests/type_traits/is_array.hpp new file mode 100644 index 00000000..443e4cc3 --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_array.hpp @@ -0,0 +1,22 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once +#include + +// size_t +template< typename T > +struct is_array : false_type +{ +}; + +template< typename T > +struct is_array< T[] > : true_type +{ +}; + +template< typename T, size_t N > +struct is_array< T[N] > : true_type +{ +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_base_of.hpp b/dev/MathPerfTests/type_traits/is_base_of.hpp new file mode 100644 index 00000000..e037dc3f --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_base_of.hpp @@ -0,0 +1,22 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once +#include "remove_reference.hpp" + +// A meta-function that returns true if Derived inherits from TBase is an +// integral type. +template< typename TBase, typename TDerived > +class is_base_of +{ +protected: // <- to avoid GCC's "all member functions in class are private" + static int probe(const TBase*); + static char probe(...); + +public: + static const bool value = + sizeof(probe(reinterpret_cast< typename remove_reference< TDerived >::type* >( + 0))) + == sizeof(int); +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_class.hpp b/dev/MathPerfTests/type_traits/is_class.hpp new file mode 100644 index 00000000..49923711 --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_class.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "declval.hpp" + +template< typename T > +struct is_class +{ +protected: // <- to avoid GCC's "all member functions in class are private" + template< typename U > + static int probe(void (U::*)(void)); + template< typename > + static char probe(...); + +public: + static const bool value = sizeof(probe< T >(0)) == sizeof(int); +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_const.hpp b/dev/MathPerfTests/type_traits/is_const.hpp new file mode 100644 index 00000000..9eed3f05 --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_const.hpp @@ -0,0 +1,18 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +// A meta-function that return the type T without the const modifier +template< typename T > +struct is_const : false_type +{ +}; + +template< typename T > +struct is_const< const T > : true_type +{ +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_convertible.hpp b/dev/MathPerfTests/type_traits/is_convertible.hpp new file mode 100644 index 00000000..d50754b0 --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_convertible.hpp @@ -0,0 +1,41 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "declval.hpp" + +#ifdef _MSC_VER +#pragma warning(push) +// conversion from 'T' to 'To', possible loss of data +#pragma warning(disable : 4244) +#endif + +// clang-format off +#ifdef __ICCARM__ +// Suppress IAR Compiler Warning[Pa093]: implicit conversion from floating point to integer +#pragma diag_suppress=Pa093 +#endif +// clang-format on +template< typename From, typename To > +struct is_convertible +{ +protected: // <- to avoid GCC's "all member functions in class are private" + static int probe(To); + static char probe(...); + + static From& _from; + +public: + static const bool value = sizeof(probe(_from)) == sizeof(int); +}; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// clang-format off +#ifdef __ICCARM__ +#pragma diag_default=Pa093 +#endif +// clang-format on diff --git a/dev/MathPerfTests/type_traits/is_enum.hpp b/dev/MathPerfTests/type_traits/is_enum.hpp new file mode 100644 index 00000000..c3f6373c --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_enum.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "is_class.hpp" +#include "is_convertible.hpp" +#include "is_floating_point.hpp" +#include "is_integral.hpp" +#include "is_same.hpp" + +template< typename T > +struct is_enum +{ + static const bool value = is_convertible< T, int >::value && !is_class< T >::value && !is_integral< T >::value && !is_floating_point< T >::value; +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_floating_point.hpp b/dev/MathPerfTests/type_traits/is_floating_point.hpp new file mode 100644 index 00000000..b1138aac --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_floating_point.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "integral_constant.hpp" +#include "is_same.hpp" +#include "remove_cv.hpp" + +template< class T > +struct is_floating_point + : integral_constant< + bool, // + is_same< float, typename remove_cv< T >::type >::value || is_same< double, typename remove_cv< T >::type >::value > +{ +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_integral.hpp b/dev/MathPerfTests/type_traits/is_integral.hpp new file mode 100644 index 00000000..2a3f11e6 --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_integral.hpp @@ -0,0 +1,26 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "integral_constant.hpp" +#include "is_same.hpp" +#include "remove_cv.hpp" + +// clang-format off +template +struct is_integral : integral_constant::type, signed char>::value || + is_same::type, unsigned char>::value || + is_same::type, signed short>::value || + is_same::type, unsigned short>::value || + is_same::type, signed int>::value || + is_same::type, unsigned int>::value || + is_same::type, signed long>::value || + is_same::type, unsigned long>::value || + is_same::type, signed long long>::value || + is_same::type, unsigned long long>::value || + is_same::type, char>::value || + is_same::type, bool>::value> {}; +// clang-format on \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_pointer.hpp b/dev/MathPerfTests/type_traits/is_pointer.hpp new file mode 100644 index 00000000..be7c4ca9 --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_pointer.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +template< typename T > +struct is_pointer : false_type +{ +}; + +template< typename T > +struct is_pointer< T* > : true_type +{ +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_same.hpp b/dev/MathPerfTests/type_traits/is_same.hpp new file mode 100644 index 00000000..638e24ea --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_same.hpp @@ -0,0 +1,18 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +// A meta-function that returns true if types T and U are the same. +template< typename T, typename U > +struct is_same : false_type +{ +}; + +template< typename T > +struct is_same< T, T > : true_type +{ +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_signed.hpp b/dev/MathPerfTests/type_traits/is_signed.hpp new file mode 100644 index 00000000..4f5d9058 --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_signed.hpp @@ -0,0 +1,22 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "integral_constant.hpp" +#include "is_same.hpp" +#include "remove_cv.hpp" + +// clang-format off +template +struct is_signed : integral_constant::type, char>::value || + is_same::type, signed char>::value || + is_same::type, signed short>::value || + is_same::type, signed int>::value || + is_same::type, signed long>::value || + is_same::type, signed long long>::value || + is_same::type, float>::value || + is_same::type, double>::value> {}; +// clang-format on \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/is_unsigned.hpp b/dev/MathPerfTests/type_traits/is_unsigned.hpp new file mode 100644 index 00000000..78610be4 --- /dev/null +++ b/dev/MathPerfTests/type_traits/is_unsigned.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "integral_constant.hpp" +#include "is_same.hpp" +#include "remove_cv.hpp" + +// clang-format off +template +struct is_unsigned : integral_constant::type, unsigned char>::value || + is_same::type, unsigned short>::value || + is_same::type, unsigned int>::value || + is_same::type, unsigned long>::value || + is_same::type, unsigned long long>::value || + is_same::type, bool>::value> {}; +// clang-format on \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/make_unsigned.hpp b/dev/MathPerfTests/type_traits/make_unsigned.hpp new file mode 100644 index 00000000..ff7bd7e9 --- /dev/null +++ b/dev/MathPerfTests/type_traits/make_unsigned.hpp @@ -0,0 +1,60 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "type_identity.hpp" + +template< typename T > +struct make_unsigned; + +template<> +struct make_unsigned< char > : type_identity< unsigned char > +{ +}; + +template<> +struct make_unsigned< signed char > : type_identity< unsigned char > +{ +}; +template<> +struct make_unsigned< unsigned char > : type_identity< unsigned char > +{ +}; + +template<> +struct make_unsigned< signed short > : type_identity< unsigned short > +{ +}; +template<> +struct make_unsigned< unsigned short > : type_identity< unsigned short > +{ +}; + +template<> +struct make_unsigned< signed int > : type_identity< unsigned int > +{ +}; +template<> +struct make_unsigned< unsigned int > : type_identity< unsigned int > +{ +}; + +template<> +struct make_unsigned< signed long > : type_identity< unsigned long > +{ +}; +template<> +struct make_unsigned< unsigned long > : type_identity< unsigned long > +{ +}; + +template<> +struct make_unsigned< signed long long > : type_identity< unsigned long long > +{ +}; +template<> +struct make_unsigned< unsigned long long > : type_identity< unsigned long long > +{ +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/make_void.hpp b/dev/MathPerfTests/type_traits/make_void.hpp new file mode 100644 index 00000000..01323f66 --- /dev/null +++ b/dev/MathPerfTests/type_traits/make_void.hpp @@ -0,0 +1,11 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +template< class = void > +struct make_void +{ + typedef void type; +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/remove_const.hpp b/dev/MathPerfTests/type_traits/remove_const.hpp new file mode 100644 index 00000000..de50bfc8 --- /dev/null +++ b/dev/MathPerfTests/type_traits/remove_const.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +// A meta-function that return the type T without the const modifier +template< typename T > +struct remove_const +{ + typedef T type; +}; +template< typename T > +struct remove_const< const T > +{ + typedef T type; +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/remove_cv.hpp b/dev/MathPerfTests/type_traits/remove_cv.hpp new file mode 100644 index 00000000..1bc9b8cb --- /dev/null +++ b/dev/MathPerfTests/type_traits/remove_cv.hpp @@ -0,0 +1,26 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +template< typename T > +struct remove_cv +{ + typedef T type; +}; +template< typename T > +struct remove_cv< const T > +{ + typedef T type; +}; +template< typename T > +struct remove_cv< volatile T > +{ + typedef T type; +}; +template< typename T > +struct remove_cv< const volatile T > +{ + typedef T type; +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/remove_reference.hpp b/dev/MathPerfTests/type_traits/remove_reference.hpp new file mode 100644 index 00000000..7ca07386 --- /dev/null +++ b/dev/MathPerfTests/type_traits/remove_reference.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +// A meta-function that return the type T without the reference modifier. +template< typename T > +struct remove_reference +{ + typedef T type; +}; +template< typename T > +struct remove_reference< T& > +{ + typedef T type; +}; \ No newline at end of file diff --git a/dev/MathPerfTests/type_traits/type_identity.hpp b/dev/MathPerfTests/type_traits/type_identity.hpp new file mode 100644 index 00000000..9f8689f7 --- /dev/null +++ b/dev/MathPerfTests/type_traits/type_identity.hpp @@ -0,0 +1,13 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include "integral_constant.hpp" + +template< typename T > +struct type_identity +{ + typedef T type; +}; \ No newline at end of file