diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e16a4b..b977edd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRC_DIRS "source" "source/report" "SH2" - INCLUDE_DIRS "include" "include/report" "SH2" + INCLUDE_DIRS "." "include" "include/report" "include/callback" "SH2" REQUIRES driver esp_timer cmock) diff --git a/Kconfig.projbuild b/Kconfig.projbuild index 2f3450c..63c74e0 100644 --- a/Kconfig.projbuild +++ b/Kconfig.projbuild @@ -45,13 +45,6 @@ menu "esp32_BNO08x" help MISO GPIO pin connected to BNO08x SDA pin. - config ESP32_BNO08X_GPIO_WAKE - int "WAKE GPIO NUM (optional, -1 == unused)" - range -1 50 - default -1 - help - Wake GPIO pin, connected to BNO08x P0 pin (optional) - endmenu # GPIO Config menu "SPI Configuration" @@ -63,7 +56,6 @@ menu "esp32_BNO08x" help SPI controller peripheral inside ESP32. - config ESP32_BNO08X_SCL_SPEED_HZ int "SCL SPEED (HZ)" range 10000 3000000 @@ -78,7 +70,59 @@ menu "esp32_BNO08x" help Amount of SPI transactions that can be queued during operation. This argument is loaded directly into the spi_device_interface_config_t struct used for SPI configuration. - + + endmenu #SPI Configuration + + menu "Tasks" + + config ESP32_BNO08X_CB_TASK_SZ + int "Callback task size, (cb_task())" + range 1024 20480 + default 4096 + help + Stack size of task responsible for executing callbacks. + Note that callbacks should remain as short as possible, pass the data out of + the callback with a queue or save it to different variables for longer operations. + + config ESP32_BNO08X_DATA_PROC_TASK_SZ + int "Data processing task size, (data_proc_task())" + range 1024 20480 + default 2048 + help + Stack size of task responsible for parsing/handling sensor events sent by SH2 HAL and + updating data that is returned to user. + + + config ESP32_BNO08X_SH2_HAL_SERVICE_TASK_SZ + int "sh2 HAL service task size (sh2_HAL_service_task())" + range 1024 20480 + default 4096 + help + Stack size of task responsible for calling shtp_service() when HINT is asserted, + to dispatch any sh2 HAL lib callbacks. + + endmenu #Tasks + + menu "Callbacks" + + config ESP32_BNO08X_CB_MAX + int "Maxmium amount of callbacks that can be registered." + range 1 200 + default 10 + help + Maximum amount of callbacks that can be registered. + + config ESP32_BNO08X_CB_QUEUE_SZ + int "Callback queue size." + range 1 200 + default 16 + help + Amount of callback invocation requests that can be in the air/pending at any given time. + + endmenu #Callbacks + + menu "Timeouts" + config ESP32_BNO08X_HINT_TIMEOUT_MS int "HINT TIMEOUT (ms)" range 100 10000 @@ -101,7 +145,8 @@ menu "esp32_BNO08x" How long RST pin is held low during hard reset (min 10ns according to datasheet, but should be longer for stable operation). Not recommended to lower below 100ms. - endmenu #SPI Configuration + endmenu #Timeouts + menu "Logging" @@ -119,41 +164,4 @@ menu "esp32_BNO08x" endmenu #Logging - menu "Callbacks & Tasks" - - config ESP32_BNO08X_CB_TASK_SZ - int "Callback task size, (cb_task())" - range 1024 20480 - default 4096 - help - Stack size of task responsible for executing callbacks. - Note that callbacks should remain as short as possible, pass the data out of - the callback with a queue or save it to different variables for longer operations. - - config ESP32_BNO08X_CB_QUEUE_SZ - int "Callback queue size." - range 1 200 - default 16 - help - Amount of callbacks that can be in the air/pending to be executed at any given time. - - config ESP32_BNO08X_DATA_PROC_TASK_SZ - int "Data processing task size, (data_proc_task())" - range 1024 20480 - default 2048 - help - Stack size of task responsible for parsing/handling sensor events sent by SH2 HAL and - updating data that is returned to user. - - - config ESP32_BNO08X_SH2_HAL_SERVICE_TASK_SZ - int "Data processing task size, (data_proc_task())" - range 1024 20480 - default 4096 - help - Stack size of task responsible for calling shtp_service() when HINT is asserted, - to dispatch any sh2 HAL lib callbacks. - - endmenu #Callbacks & Tasks - endmenu \ No newline at end of file diff --git a/etl/.vscode/settings.json b/etl/.vscode/settings.json new file mode 100644 index 0000000..cc52eca --- /dev/null +++ b/etl/.vscode/settings.json @@ -0,0 +1,41 @@ +{ + "files.associations": { + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "*.tcc": "cpp", + "chrono": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "exception": "cpp", + "slist": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "ratio": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "utility": "cpp" + } +} \ No newline at end of file diff --git a/etl/absolute.h b/etl/absolute.h new file mode 100644 index 0000000..7bc5ea6 --- /dev/null +++ b/etl/absolute.h @@ -0,0 +1,96 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2018 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ABSOLUTE_INCLUDED +#define ETL_ABSOLUTE_INCLUDED + +#include "type_traits.h" +#include "integral_limits.h" + +namespace etl +{ + //*************************************************************************** + // For signed types. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR + typename etl::enable_if::value, T>::type + absolute(T value) ETL_NOEXCEPT + { + return (value < T(0)) ? -value : value; + } + + //*************************************************************************** + // For unsigned types. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR + typename etl::enable_if::value, T>::type + absolute(T value) ETL_NOEXCEPT + { + return value; + } + + //*************************************************************************** + // For signed types. + // Returns the result as the unsigned type. + //*************************************************************************** +#if ETL_USING_CPP11 + template ::type> +#else + template + #endif + ETL_NODISCARD + ETL_CONSTEXPR + typename etl::enable_if::value, TReturn>::type + absolute_unsigned(T value) ETL_NOEXCEPT + { + return (value == etl::integral_limits::min) ? (etl::integral_limits::max / 2U) + 1U + : (value < T(0)) ? TReturn(-value) : TReturn(value); + } + + //*************************************************************************** + // For unsigned types. + // Returns the result as the unsigned type. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR + typename etl::enable_if::value, T>::type + absolute_unsigned(T value) ETL_NOEXCEPT + { + return etl::absolute(value); + } +} + +#endif + diff --git a/etl/algorithm.h b/etl/algorithm.h new file mode 100644 index 0000000..3929a57 --- /dev/null +++ b/etl/algorithm.h @@ -0,0 +1,3425 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Documentation: https://www.etlcpp.com/algorithm.html + +Copyright(c) 2014 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ALGORITHM_INCLUDED +#define ETL_ALGORITHM_INCLUDED + +///\defgroup algorithm algorithm +/// Including reverse engineered algorithms from C++ 0x11, 0x14, 0x17 +/// Additional new variants of certain algorithms. +///\ingroup utilities + +#include "platform.h" +#include "type_traits.h" +#include "iterator.h" +#include "functional.h" +#include "utility.h" +#include "gcd.h" + +#include +#include + +#include "private/minmax_push.h" + +#if ETL_USING_STL + #include + #include + #include + #include + #include +#endif + +namespace etl +{ + // Declare prototypes of the ETL's sort functions + template +#if ETL_USING_STD_NAMESPACE + ETL_CONSTEXPR20 +#else + ETL_CONSTEXPR14 +#endif + void shell_sort(TIterator first, TIterator last); + + template +#if ETL_USING_STD_NAMESPACE + ETL_CONSTEXPR20 +#else + ETL_CONSTEXPR14 +#endif + void shell_sort(TIterator first, TIterator last, TCompare compare); + + template + ETL_CONSTEXPR14 void insertion_sort(TIterator first, TIterator last); + + template + ETL_CONSTEXPR14 void insertion_sort(TIterator first, TIterator last, TCompare compare); +} + +//***************************************************************************** +// Algorithms defined by the ETL +//***************************************************************************** +namespace etl +{ + namespace private_algorithm + { + template + struct swap_impl; + + // Generic swap + template <> + struct swap_impl + { + template + static void do_swap(TIterator1 a, TIterator2 b) + { + typename etl::iterator_traits::value_type tmp = *a; + *a = *b; + *b = tmp; + } + }; + + // Specialised swap + template <> + struct swap_impl + { + template + static void do_swap(TIterator1 a, TIterator2 b) + { + using ETL_OR_STD::swap; // Allow ADL + swap(*a, *b); + } + }; + } + + //*************************************************************************** + // iter_swap + //*************************************************************************** + template +#if ETL_USING_STD_NAMESPACE + ETL_CONSTEXPR20 +#else + ETL_CONSTEXPR14 +#endif + void iter_swap(TIterator1 a, TIterator2 b) + { + typedef etl::iterator_traits traits1; + typedef etl::iterator_traits traits2; + + typedef typename traits1::value_type v1; + typedef typename traits2::value_type v2; + + typedef typename traits1::reference r1; + typedef typename traits2::reference r2; + + const bool use_swap = etl::is_same::value && + etl::is_reference::value && + etl::is_reference::value; + + private_algorithm::swap_impl::do_swap(a, b); + } + + //*************************************************************************** + // swap_ranges + //*************************************************************************** + template +#if ETL_USING_STD_NAMESPACE + ETL_CONSTEXPR20 +#else + ETL_CONSTEXPR14 +#endif + TIterator2 swap_ranges(TIterator1 first1, + TIterator1 last1, + TIterator2 first2) + { + while (first1 != last1) + { + iter_swap(first1, first2); + ++first1; + ++first2; + } + + return first2; + } + + //*************************************************************************** + // generate + template + ETL_CONSTEXPR14 + void generate(TIterator db, TIterator de, TFunction funct) + { + while (db != de) + { + *db++ = funct(); + } + } + + //*************************************************************************** + // copy +#if ETL_USING_STL && ETL_USING_CPP20 + // Use the STL constexpr implementation. + template + constexpr TIterator2 copy(TIterator1 sb, TIterator1 se, TIterator2 db) + { + return std::copy(sb, se, db); + } +#else + // Non-pointer or not trivially copyable or not using builtin memcpy. + template + ETL_CONSTEXPR14 TIterator2 copy(TIterator1 sb, TIterator1 se, TIterator2 db) + { + while (sb != se) + { + *db = *sb; + ++db; + ++sb; + } + + return db; + } +#endif + + //*************************************************************************** + // reverse_copy +#if ETL_USING_STL && ETL_USING_CPP20 + template + constexpr TIterator2 reverse_copy(TIterator1 sb, TIterator1 se, TIterator2 db) + { + return std::reverse_copy(sb, se, db); + } +#else + template + ETL_CONSTEXPR14 + TIterator2 reverse_copy(TIterator1 sb, TIterator1 se, TIterator2 db) + { + while (sb != se) + { + *db = *--se; + ++db; + } + + return db; + } +#endif + + //*************************************************************************** + // copy_n +#if ETL_USING_STL && ETL_USING_CPP20 + // Use the STL implementation + template + constexpr TIterator2 copy_n(TIterator1 sb, TSize count, TIterator2 db) + { + return std::copy_n(sb, count, db); + } +#else + // Non-pointer or not trivially copyable or not using builtin memcpy. + template + ETL_CONSTEXPR14 TIterator2 copy_n(TIterator1 sb, TSize count, TIterator2 db) + { + while (count != 0) + { + *db = *sb; + ++db; + ++sb; + --count; + } + + return db; + } +#endif + + //*************************************************************************** + // copy_backward +#if ETL_USING_STL && ETL_USING_CPP20 + template + constexpr TIterator2 copy_backward(TIterator1 sb, TIterator1 se, TIterator2 de) + { + return std::copy_backward(sb, se, de); + } +#else + template + ETL_CONSTEXPR14 TIterator2 copy_backward(TIterator1 sb, TIterator1 se, TIterator2 de) + { + while (se != sb) + { + *(--de) = *(--se); + } + + return de; + } +#endif + + //*************************************************************************** + // move +#if ETL_USING_STL && ETL_USING_CPP20 + template + constexpr TIterator2 move(TIterator1 sb, TIterator1 se, TIterator2 db) + { + return std::move(sb, se, db); + } +#elif ETL_USING_CPP11 + // For C++11 + template + ETL_CONSTEXPR14 TIterator2 move(TIterator1 sb, TIterator1 se, TIterator2 db) + { + while (sb != se) + { + *db = etl::move(*sb); + ++db; + ++sb; + } + + return db; + } +#else + // For C++03 + template + ETL_CONSTEXPR14 TIterator2 move(TIterator1 sb, TIterator1 se, TIterator2 db) + { + return copy(sb, se, db); + } +#endif + + //*************************************************************************** + // move_backward +#if ETL_USING_STL && ETL_USING_CPP20 + template + ETL_CONSTEXPR20 TIterator2 move_backward(TIterator1 sb, TIterator1 se, TIterator2 de) + { + return std::move_backward(sb, se, de); + } +#elif ETL_USING_CPP11 + // For C++11 + template + ETL_CONSTEXPR14 TIterator2 move_backward(TIterator1 sb, TIterator1 se, TIterator2 de) + { + while (sb != se) + { + *(--de) = etl::move(*(--se)); + } + + return de; + } +#else + // For C++03 + template + ETL_CONSTEXPR14 TIterator2 move_backward(TIterator1 sb, TIterator1 se, TIterator2 de) + { + return etl::copy_backward(sb, se, de); + } +#endif + + //*************************************************************************** + // reverse + //*************************************************************************** + // Pointers + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, void>::type + reverse(TIterator b, TIterator e) + { + if (b != e) + { + while (b < --e) + { + etl::iter_swap(b, e); + ++b; + } + } + } + + // Non-pointers + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, void>::type + reverse(TIterator b, TIterator e) + { + while ((b != e) && (b != --e)) + { + etl::iter_swap(b++, e); + } + } + + //*************************************************************************** + // lower_bound + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator lower_bound(TIterator first, TIterator last, const TValue& value, TCompare compare) + { + typedef typename etl::iterator_traits::difference_type difference_t; + + difference_t count = etl::distance(first, last); + + while (count > 0) + { + TIterator itr = first; + difference_t step = count / 2; + + etl::advance(itr, step); + + if (compare(*itr, value)) + { + first = ++itr; + count -= step + 1; + } + else + { + count = step; + } + } + + return first; + } + + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator lower_bound(TIterator first, TIterator last, const TValue& value) + { + typedef etl::less::value_type> compare; + + return etl::lower_bound(first, last, value, compare()); + } + + //*************************************************************************** + // upper_bound + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator upper_bound(TIterator first, TIterator last, const TValue& value, TCompare compare) + { + typedef typename etl::iterator_traits::difference_type difference_t; + + difference_t count = etl::distance(first, last); + + while (count > 0) + { + TIterator itr = first; + difference_t step = count / 2; + + etl::advance(itr, step); + + if (!compare(value, *itr)) + { + first = ++itr; + count -= step + 1; + } + else + { + count = step; + } + } + + return first; + } + + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator upper_bound(TIterator first, TIterator last, const TValue& value) + { + typedef etl::less::value_type> compare; + + return etl::upper_bound(first, last, value, compare()); + } + + //*************************************************************************** + // equal_range + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + ETL_OR_STD::pair equal_range(TIterator first, TIterator last, const TValue& value, TCompare compare) + { + return ETL_OR_STD::make_pair(etl::lower_bound(first, last, value, compare), + etl::upper_bound(first, last, value, compare)); + } + + template + ETL_NODISCARD + ETL_OR_STD::pair equal_range(TIterator first, TIterator last, const TValue& value) + { + typedef etl::less::value_type> compare; + + return ETL_OR_STD::make_pair(etl::lower_bound(first, last, value, compare()), + etl::upper_bound(first, last, value, compare())); + } + + //*************************************************************************** + // binary_search + //*************************************************************************** + template + ETL_NODISCARD + bool binary_search(TIterator first, TIterator last, const T& value, Compare compare) + { + first = etl::lower_bound(first, last, value, compare); + + return (!(first == last) && !(compare(value, *first))); + } + + template + ETL_NODISCARD + bool binary_search(TIterator first, TIterator last, const T& value) + { + typedef etl::less::value_type> compare; + + return binary_search(first, last, value, compare()); + } + + //*************************************************************************** + // find_if + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator find_if(TIterator first, TIterator last, TUnaryPredicate predicate) + { + while (first != last) + { + if (predicate(*first)) + { + return first; + } + + ++first; + } + + return last; + } + + //*************************************************************************** + // find + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator find(TIterator first, TIterator last, const T& value) + { + while (first != last) + { + if (*first == value) + { + return first; + } + + ++first; + } + + return last; + } + + //*************************************************************************** + // fill +#if ETL_USING_STL && ETL_USING_CPP20 + template + constexpr void fill(TIterator first, TIterator last, const TValue& value) + { + std::fill(first, last, value); + } +#else + template + ETL_CONSTEXPR14 void fill(TIterator first, TIterator last, const TValue& value) + { + while (first != last) + { + *first = value; + ++first; + } + } +#endif + + //*************************************************************************** + // fill_n +#if ETL_USING_STL && ETL_USING_CPP20 + template + constexpr TIterator fill_n(TIterator first, TSize count, const TValue& value) + { + return std::fill_n(first, count, value); + } +#else + template + ETL_CONSTEXPR14 TIterator fill_n(TIterator first, TSize count, const TValue& value) + { + while (count != 0) + { + *first++ = value; + --count; + } + + return first; + } +#endif + + //*************************************************************************** + // count + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::iterator_traits::difference_type count(TIterator first, TIterator last, const T& value) + { + typename iterator_traits::difference_type n = 0; + + while (first != last) + { + if (*first == value) + { + ++n; + } + + ++first; + } + + return n; + } + + //*************************************************************************** + // count_if + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + typename etl::iterator_traits::difference_type + count_if(TIterator first, TIterator last, TUnaryPredicate predicate) + { + typename iterator_traits::difference_type n = 0; + + while (first != last) + { + if (predicate(*first)) + { + ++n; + } + + ++first; + } + + return n; + } + + //*************************************************************************** + // equal +#if ETL_USING_STL && ETL_USING_CPP20 + // Three parameter + template + [[nodiscard]] + constexpr + bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2) + { + return std::equal(first1, last1, first2); + } + + // Three parameter + predicate + template + [[nodiscard]] + constexpr + bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TPredicate predicate) + { + return std::equal(first1, last1, first2, predicate); + } + + // Four parameter + template + [[nodiscard]] + constexpr + bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2) + { + return std::equal(first1, last1, first2, last2); + } + + // Four parameter + Predicate + template + [[nodiscard]] + constexpr + bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2, TPredicate predicate) + { + return std::equal(first1, last1, first2, last2, predicate); + } + +#else + + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2) + { + while (first1 != last1) + { + if (*first1 != *first2) + { + return false; + } + + ++first1; + ++first2; + } + + return true; + } + + // Predicate + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TPredicate predicate) + { + while (first1 != last1) + { + if (!predicate(*first1, *first2)) + { + return false; + } + + ++first1; + ++first2; + } + + return true; + } + + // Four parameter + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2) + { + while ((first1 != last1) && (first2 != last2)) + { + if (*first1 != *first2) + { + return false; + } + + ++first1; + ++first2; + } + + return (first1 == last1) && (first2 == last2); + } + + // Four parameter, Predicate + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool equal(TIterator1 first1, TIterator1 last1, TIterator2 first2, TIterator2 last2, TPredicate predicate) + { + while ((first1 != last1) && (first2 != last2)) + { + if (!predicate(*first1 , *first2)) + { + return false; + } + + ++first1; + ++first2; + } + + return (first1 == last1) && (first2 == last2); + } +#endif + + //*************************************************************************** + // lexicographical_compare + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool lexicographical_compare(TIterator1 first1, TIterator1 last1, + TIterator2 first2, TIterator2 last2, + TCompare compare) + { + while ((first1 != last1) && (first2 != last2)) + { + if (compare(*first1, *first2)) + { + return true; + } + + if (compare(*first2, *first1)) + { + return false; + } + + ++first1; + ++first2; + } + + return (first1 == last1) && (first2 != last2); + } + + // lexicographical_compare + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool lexicographical_compare(TIterator1 first1, TIterator1 last1, + TIterator2 first2, TIterator2 last2) + { + typedef etl::less::value_type> compare; + + return etl::lexicographical_compare(first1, last1, first2, last2, compare()); + } + + //*************************************************************************** + // min + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR + const T& min(const T& a, const T& b, TCompare compare) + { + return (compare(a, b)) ? a : b; + } + + template + ETL_NODISCARD + ETL_CONSTEXPR + const T& min(const T& a, const T& b) + { + typedef etl::less compare; + + return etl::min(a, b, compare()); + } + + //*************************************************************************** + // max + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR + const T& max(const T& a, const T& b, TCompare compare) + { + return (compare(a, b)) ? b : a; + } + + template + ETL_NODISCARD + ETL_CONSTEXPR + const T& max(const T& a, const T& b) + { + typedef etl::less compare; + + return etl::max(a, b, compare()); + } + + //*************************************************************************** + // for_each + //*************************************************************************** + template + ETL_CONSTEXPR14 + TUnaryOperation for_each(TIterator first, TIterator last, TUnaryOperation unary_operation) + { + while (first != last) + { + unary_operation(*first); + ++first; + } + + return unary_operation; + } + + //*************************************************************************** + // transform + //*************************************************************************** + template + ETL_CONSTEXPR14 + TIteratorOut transform(TIteratorIn first1, TIteratorIn last1, TIteratorOut d_first, TUnaryOperation unary_operation) + { + while (first1 != last1) + { + *d_first = unary_operation(*first1); + + ++d_first; + ++first1; + } + + return d_first; + } + + template + ETL_CONSTEXPR14 + TIteratorOut transform(TIteratorIn1 first1, TIteratorIn1 last1, TIteratorIn2 first2, TIteratorOut d_first, TBinaryOperation binary_operation) + { + while (first1 != last1) + { + *d_first = binary_operation(*first1, *first2); + + ++d_first; + ++first1; + ++first2; + } + + return d_first; + } + + //*************************************************************************** + // replace + //*************************************************************************** + template + ETL_CONSTEXPR14 void replace(TIterator first, TIterator last, const T& old_value, const T& new_value) + { + while (first != last) + { + if (*first == old_value) + { + *first = new_value; + } + + ++first; + } + } + + //*************************************************************************** + // replace_if + //*************************************************************************** + template + ETL_CONSTEXPR14 void replace_if(TIterator first, TIterator last, TPredicate predicate, const T& new_value) + { + while (first != last) + { + if (predicate(*first)) + { + *first = new_value; + } + + ++first; + } + } + + //*************************************************************************** + // Heap + //*************************************************************************** + namespace private_heap + { + // Push Heap Helper + template + void push_heap(TIterator first, TDistance value_index, TDistance top_index, TValue value, TCompare compare) + { + TDistance parent = (value_index - 1) / 2; + + while ((value_index > top_index) && compare(first[parent], value)) + { + first[value_index] = etl::move(first[parent]); + value_index = parent; + parent = (value_index - 1) / 2; + } + + first[value_index] = etl::move(value); + } + + // Adjust Heap Helper + template + void adjust_heap(TIterator first, TDistance value_index, TDistance length, TValue value, TCompare compare) + { + TDistance top_index = value_index; + TDistance child2nd = (2 * value_index) + 2; + + while (child2nd < length) + { + if (compare(first[child2nd], first[child2nd - 1])) + { + --child2nd; + } + + first[value_index] = etl::move(first[child2nd]); + value_index = child2nd; + child2nd = 2 * (child2nd + 1); + } + + if (child2nd == length) + { + first[value_index] = etl::move(first[child2nd - 1]); + value_index = child2nd - 1; + } + + push_heap(first, value_index, top_index, etl::move(value), compare); + } + + // Is Heap Helper + template + bool is_heap(const TIterator first, const TDistance n, TCompare compare) + { + TDistance parent = 0; + + for (TDistance child = 1; child < n; ++child) + { + if (compare(first[parent], first[child])) + { + return false; + } + + if ((child & 1) == 0) + { + ++parent; + } + } + + return true; + } + } + + // Pop Heap + template + void pop_heap(TIterator first, TIterator last, TCompare compare) + { + typedef typename etl::iterator_traits::value_type value_t; + typedef typename etl::iterator_traits::difference_type distance_t; + + value_t value = etl::move(last[-1]); + last[-1] = etl::move(first[0]); + + private_heap::adjust_heap(first, distance_t(0), distance_t(last - first - 1), etl::move(value), compare); + } + + // Pop Heap + template + void pop_heap(TIterator first, TIterator last) + { + typedef etl::less::value_type> compare; + + etl::pop_heap(first, last, compare()); + } + + // Push Heap + template + void push_heap(TIterator first, TIterator last, TCompare compare) + { + typedef typename etl::iterator_traits::difference_type difference_t; + typedef typename etl::iterator_traits::value_type value_t; + + private_heap::push_heap(first, difference_t(last - first - 1), difference_t(0), value_t(etl::move(*(last - 1))), compare); + } + + // Push Heap + template + void push_heap(TIterator first, TIterator last) + { + typedef etl::less::value_type> compare; + + etl::push_heap(first, last, compare()); + } + + // Make Heap + template + void make_heap(TIterator first, TIterator last, TCompare compare) + { + typedef typename etl::iterator_traits::difference_type difference_t; + + if ((last - first) < 2) + { + return; + } + + difference_t length = last - first; + difference_t parent = (length - 2) / 2; + + while (true) + { + private_heap::adjust_heap(first, parent, length, etl::move(*(first + parent)), compare); + + if (parent == 0) + { + return; + } + + --parent; + } + } + + // Make Heap + template + void make_heap(TIterator first, TIterator last) + { + typedef etl::less::value_type> compare; + + etl::make_heap(first, last, compare()); + } + + // Is Heap + template + ETL_NODISCARD + bool is_heap(TIterator first, TIterator last) + { + typedef etl::less::value_type> compare; + + return private_heap::is_heap(first, last - first, compare()); + } + + // Is Heap + template + ETL_NODISCARD + bool is_heap(TIterator first, TIterator last, TCompare compare) + { + return private_heap::is_heap(first, last - first, compare); + } + + // Sort Heap + template + void sort_heap(TIterator first, TIterator last) + { + while (first != last) + { + etl::pop_heap(first, last); + --last; + } + } + + // Sort Heap + template + void sort_heap(TIterator first, TIterator last, TCompare compare) + { + while (first != last) + { + etl::pop_heap(first, last, compare); + --last; + } + } + + //*************************************************************************** + // Search + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator1 search(TIterator1 first, TIterator1 last, TIterator2 search_first, TIterator2 search_last, TCompare compare) + { + while (true) + { + TIterator1 itr = first; + TIterator2 search_itr = search_first; + + while (true) + { + if (search_itr == search_last) + { + return first; + } + + if (itr == last) + { + return last; + } + + if (!compare(*itr, *search_itr)) + { + break; + } + + ++itr; + ++search_itr; + } + + ++first; + } + } + + // Search + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator1 search(TIterator1 first, TIterator1 last, TIterator2 search_first, TIterator2 search_last) + { + typedef etl::equal_to::value_type> compare; + + return etl::search(first, last, search_first, search_last, compare()); + } + + //*************************************************************************** + // Rotate + //*************************************************************************** + namespace private_algorithm + { +#if ETL_USING_CPP11 + //********************************* + // For random access iterators + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, TIterator>::type + rotate_general(TIterator first, TIterator middle, TIterator last) + { + if (first == middle || middle == last) + { + return first; + } + + typedef typename etl::iterator_traits::value_type value_type; + + int n = last - first; + int m = middle - first; + int gcd_nm = (n == 0 || m == 0) ? n + m : etl::gcd(n, m); + + TIterator result = first + (last - middle); + + for (int i = 0; i < gcd_nm; i++) + { + value_type temp = etl::move(*(first + i)); + int j = i; + + while (true) + { + int k = j + m; + + if (k >= n) + { + k = k - n; + } + + if (k == i) + { + break; + } + + *(first + j) = etl::move(*(first + k)); + j = k; + } + + *(first + j) = etl::move(temp); + } + + return result; + } +#else + //********************************* + // For random access iterators + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, TIterator>::type + rotate_general(TIterator first, TIterator middle, TIterator last) + { + if (first == middle || middle == last) + { + return first; + } + + typedef typename etl::iterator_traits::value_type value_type; + + int n = last - first; + int m = middle - first; + int gcd_nm = (n == 0 || m == 0) ? n + m : etl::gcd(n, m); + + TIterator result = first + (last - middle); + + for (int i = 0; i < gcd_nm; i++) + { + value_type temp = *(first + i); + int j = i; + + while (true) + { + int k = j + m; + + if (k >= n) + { + k = k - n; + } + + if (k == i) + { + break; + } + + *(first + j) = *(first + k); + j = k; + } + + *(first + j) = temp; + } + + return result; + } +#endif + + //********************************* + // For bidirectional iterators + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, TIterator>::type + rotate_general(TIterator first, TIterator middle, TIterator last) + { + if (first == middle || middle == last) + { + return first; + } + + TIterator result = first; + etl::advance(result, etl::distance(middle, last)); + + reverse(first, middle); + reverse(middle, last); + reverse(first, last); + + return result; + } + + //********************************* + // For forward iterators + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, TIterator>::type + rotate_general(TIterator first, TIterator middle, TIterator last) + { + if (first == middle || middle == last) + { + return first; + } + + TIterator next = middle; + TIterator result = first; + etl::advance(result, etl::distance(middle, last)); + + while (first != next) + { + using ETL_OR_STD::swap; + swap(*first++, *next++); + + if (next == last) + { + next = middle; + } + else if (first == middle) + { + middle = next; + } + } + + return result; + } + + //********************************* + // Simplified algorithm for rotate left by one + template + ETL_CONSTEXPR14 + TIterator rotate_left_by_one(TIterator first, TIterator last) + { + typedef typename etl::iterator_traits::value_type value_type; + + // Save the first item. + value_type temp(etl::move(*first)); + + // Move the rest. + TIterator result = etl::move(etl::next(first), last, first); + + // Restore the first item in its rotated position. + *result = etl::move(temp); + + // The new position of the first item. + return result; + } + + //********************************* + // Simplified for algorithm rotate right by one + template + ETL_CONSTEXPR14 + TIterator rotate_right_by_one(TIterator first, TIterator last) + { + typedef typename etl::iterator_traits::value_type value_type; + + // Save the last item. + TIterator previous = etl::prev(last); + value_type temp(etl::move(*previous)); + + // Move the rest. + TIterator result = etl::move_backward(first, previous, last); + + // Restore the last item in its rotated position. + *first = etl::move(temp); + + // The new position of the first item. + return result; + } + } + + //********************************* + template + ETL_CONSTEXPR14 + TIterator rotate(TIterator first, TIterator middle, TIterator last) + { + if (etl::next(first) == middle) + { + return private_algorithm::rotate_left_by_one(first, last); + } + + if (etl::next(middle) == last) + { +#if ETL_USING_CPP20 + if ETL_IF_CONSTEXPR(etl::is_forward_iterator::value) + { + return private_algorithm::rotate_general(first, middle, last); + } + else + { + return private_algorithm::rotate_right_by_one(first, last); + } +#else + return private_algorithm::rotate_general(first, middle, last); +#endif + } + + return private_algorithm::rotate_general(first, middle, last); + } + + //*************************************************************************** + // find_end + //*************************************************************************** + // Predicate + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator1 find_end(TIterator1 b, TIterator1 e, + TIterator2 sb, TIterator2 se, + TPredicate predicate) + { + if (sb == se) + { + return e; + } + + TIterator1 result = e; + + while (true) + { + TIterator1 new_result = etl::search(b, e, sb, se, predicate); + + if (new_result == e) + { + break; + } + else + { + result = new_result; + b = result; + ++b; + } + } + return result; + } + + // Default + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator1 find_end(TIterator1 b, TIterator1 e, + TIterator2 sb, TIterator2 se) + { + typedef etl::equal_to::value_type> predicate; + + return find_end(b, e, sb, se, predicate()); + } + + //*************************************************************************** + /// Finds the iterator to the smallest element in the range (begin, end).
+ /// + ///\ingroup algorithm + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator min_element(TIterator begin, + TIterator end, + TCompare compare) + { + TIterator minimum = begin; + ++begin; + + while (begin != end) + { + if (compare(*begin, *minimum)) + { + minimum = begin; + } + + ++begin; + } + + return minimum; + } + + //*************************************************************************** + /// min_element + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator min_element(TIterator begin, + TIterator end) + { + typedef typename etl::iterator_traits::value_type value_t; + + return etl::min_element(begin, end, etl::less()); + } + + //*************************************************************************** + /// Finds the iterator to the largest element in the range (begin, end).
+ /// + ///\ingroup algorithm + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator max_element(TIterator begin, + TIterator end, + TCompare compare) + { + TIterator maximum = begin; + ++begin; + + while (begin != end) + { + if (!compare(*begin, *maximum)) + { + maximum = begin; + } + + ++begin; + } + + return maximum; + } + + //*************************************************************************** + /// max_element + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator max_element(TIterator begin, + TIterator end) + { + typedef typename etl::iterator_traits::value_type value_t; + + return etl::max_element(begin, end, etl::less()); + } + + //*************************************************************************** + /// Finds the greatest and the smallest element in the range (begin, end).
+ /// + ///\ingroup algorithm + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + ETL_OR_STD::pair minmax_element(TIterator begin, + TIterator end, + TCompare compare) + { + TIterator minimum = begin; + TIterator maximum = begin; + ++begin; + + while (begin != end) + { + if (compare(*begin, *minimum)) + { + minimum = begin; + } + + if (compare(*maximum, *begin)) + { + maximum = begin; + } + + ++begin; + } + + return ETL_OR_STD::pair(minimum, maximum); + } + + //*************************************************************************** + /// minmax_element + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + ETL_OR_STD::pair minmax_element(TIterator begin, + TIterator end) + { + typedef typename etl::iterator_traits::value_type value_t; + + return etl::minmax_element(begin, end, etl::less()); + } + + //*************************************************************************** + /// minmax + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + ETL_OR_STD::pair minmax(const T& a, + const T& b) + { + return (b < a) ? ETL_OR_STD::pair(b, a) : ETL_OR_STD::pair(a, b); + } + + //*************************************************************************** + /// minmax + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + ETL_OR_STD::pair minmax(const T& a, + const T& b, + TCompare compare) + { + return compare(b, a) ? ETL_OR_STD::pair(b, a) : ETL_OR_STD::pair(a, b); + } + + //*************************************************************************** + /// is_sorted_until + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator is_sorted_until(TIterator begin, + TIterator end) + { + if (begin != end) + { + TIterator next = begin; + + while (++next != end) + { + if (*next < *begin) + { + return next; + } + + ++begin; + } + } + + return end; + } + + //*************************************************************************** + /// is_sorted_until + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator is_sorted_until(TIterator begin, + TIterator end, + TCompare compare) + { + if (begin != end) + { + TIterator next = begin; + + while (++next != end) + { + if (compare(*next, *begin)) + { + return next; + } + + ++begin; + } + } + + return end; + } + + //*************************************************************************** + /// is_sorted + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool is_sorted(TIterator begin, + TIterator end) + { + return etl::is_sorted_until(begin, end) == end; + } + + //*************************************************************************** + /// is_sorted + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool is_sorted(TIterator begin, + TIterator end, + TCompare compare) + { + return etl::is_sorted_until(begin, end, compare) == end; + } + + //*************************************************************************** + /// find_if_not + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator find_if_not(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (!predicate(*begin)) + { + return begin; + } + + ++begin; + } + + return end; + } + + //*************************************************************************** + /// is_permutation + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool is_permutation(TIterator1 begin1, + TIterator1 end1, + TIterator2 begin2) + { + if (begin1 != end1) + { + TIterator2 end2 = begin2; + + etl::advance(end2, etl::distance(begin1, end1)); + + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == etl::find(begin1, i, *i)) + { + size_t n = etl::count(begin2, end2, *i); + + if (n == 0 || size_t(etl::count(i, end1, *i)) != n) + { + return false; + } + } + } + } + + return true; + } + + //*************************************************************************** + /// is_permutation + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool is_permutation(TIterator1 begin1, + TIterator1 end1, + TIterator2 begin2, + TBinaryPredicate predicate) + { + if (begin1 != end1) + { + TIterator2 end2 = begin2; + + etl::advance(end2, etl::distance(begin1, end1)); + + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == etl::find_if(begin1, i, etl::bind1st(predicate, *i))) + { + size_t n = etl::count(begin2, end2, *i); + + if (n == 0 || size_t(etl::count(i, end1, *i)) != n) + { + return false; + } + } + } + } + + return true; + } + + //*************************************************************************** + /// is_permutation + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool is_permutation(TIterator1 begin1, + TIterator1 end1, + TIterator2 begin2, + TIterator2 end2) + { + if (begin1 != end1) + { + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == etl::find(begin1, i, *i)) + { + size_t n = etl::count(begin2, end2, *i); + + if (n == 0 || size_t(etl::count(i, end1, *i)) != n) + { + return false; + } + } + } + } + + return true; + } + + //*************************************************************************** + /// is_permutation + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + bool is_permutation(TIterator1 begin1, + TIterator1 end1, + TIterator2 begin2, + TIterator2 end2, + TBinaryPredicate predicate) + { + if (begin1 != end1) + { + for (TIterator1 i = begin1; i != end1; ++i) + { + if (i == etl::find_if(begin1, i, etl::bind1st(predicate, *i))) + { + size_t n = etl::count(begin2, end2, *i); + + if (n == 0 || size_t(etl::count(i, end1, *i)) != n) + { + return false; + } + } + } + } + + return true; + } + + //*************************************************************************** + /// is_partitioned + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool is_partitioned(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (!predicate(*begin)) + { + break; + } + + ++begin; + } + + while (begin != end) + { + if (predicate(*begin)) + { + return false; + } + + ++begin; + } + + return true; + } + + //*************************************************************************** + /// partition_point + /// + ///\ingroup algorithm + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator partition_point(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (!predicate(*begin)) + { + return begin; + } + + ++begin; + } + + return begin; + } + + //*************************************************************************** + /// Copies the elements from the range (begin, end) to two different ranges + /// depending on the value returned by the predicate.
+ /// + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + ETL_OR_STD::pair partition_copy(TSource begin, + TSource end, + TDestinationTrue destination_true, + TDestinationFalse destination_false, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (predicate(*begin)) + { + *destination_true = *begin; + ++destination_true; + } + else + { + *destination_false = *begin; + ++destination_false; + } + + ++begin; + } + + return ETL_OR_STD::pair(destination_true, destination_false); + } + + //*************************************************************************** + /// copy_if + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator copy_if(TIterator begin, + TIterator end, + TOutputIterator out, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (predicate(*begin)) + { + *out = *begin; + ++out; + } + + ++begin; + } + + return out; + } + + //*************************************************************************** + /// all_of + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool all_of(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + return etl::find_if_not(begin, end, predicate) == end; + } + + //*************************************************************************** + /// any_of + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool any_of(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + return etl::find_if(begin, end, predicate) != end; + } + + //*************************************************************************** + /// none_of + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + bool none_of(TIterator begin, + TIterator end, + TUnaryPredicate predicate) + { + return etl::find_if(begin, end, predicate) == end; + } + +#if ETL_NOT_USING_STL + //*************************************************************************** + /// Sorts the elements. + /// Uses user defined comparison. + ///\ingroup algorithm + //*************************************************************************** + template + void sort(TIterator first, TIterator last, TCompare compare) + { + etl::shell_sort(first, last, compare); + } + + //*************************************************************************** + /// Sorts the elements. + ///\ingroup algorithm + //*************************************************************************** + template + void sort(TIterator first, TIterator last) + { + etl::shell_sort(first, last, etl::less::value_type>()); + } + + //*************************************************************************** + /// Sorts the elements. + /// Stable. + /// Uses user defined comparison. + ///\ingroup algorithm + //*************************************************************************** + template + void stable_sort(TIterator first, TIterator last, TCompare compare) + { + etl::insertion_sort(first, last, compare); + } + + //*************************************************************************** + /// Sorts the elements. + /// Stable. + ///\ingroup algorithm + //*************************************************************************** + template + void stable_sort(TIterator first, TIterator last) + { + etl::insertion_sort(first, last, etl::less::value_type>()); + } +#else + //*************************************************************************** + /// Sorts the elements. + /// Uses user defined comparison. + ///\ingroup algorithm + //*************************************************************************** + template + void sort(TIterator first, TIterator last, TCompare compare) + { + std::sort(first, last, compare); + } + + //*************************************************************************** + /// Sorts the elements. + ///\ingroup algorithm + //*************************************************************************** + template + void sort(TIterator first, TIterator last) + { + std::sort(first, last); + } + + //*************************************************************************** + /// Sorts the elements. + /// Stable. + /// Uses user defined comparison. + ///\ingroup algorithm + //*************************************************************************** + template + void stable_sort(TIterator first, TIterator last, TCompare compare) + { + std::stable_sort(first, last, compare); + } + + //*************************************************************************** + /// Sorts the elements. + /// Stable. + ///\ingroup algorithm + //*************************************************************************** + template + void stable_sort(TIterator first, TIterator last) + { + std::stable_sort(first, last); + } +#endif + + //*************************************************************************** + /// Accumulates values. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + T accumulate(TIterator first, TIterator last, T sum) + { + while (first != last) + { + sum = etl::move(sum) + *first; + ++first; + } + + return sum; + } + + //*************************************************************************** + /// Accumulates values. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + T accumulate(TIterator first, TIterator last, T sum, TBinaryOperation operation) + { + while (first != last) + { + sum = operation(etl::move(sum), *first); + ++first; + } + + return sum; + } + + //*************************************************************************** + /// Clamp values. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR + T clamp(const T& value, const T& low, const T& high, TCompare compare) + { + return compare(value, low) ? low : compare(high, value) ? high : value; + } + + template + ETL_CONSTEXPR + T clamp(const T& value, const T& low, const T& high) + { + return clamp(value, low, high, etl::less()); + } + + template + ETL_CONSTEXPR + T clamp(const T& value, TCompare compare) + { + return compare(value, Low) ? Low : compare(High, value) ? High : value; + } + + template + ETL_CONSTEXPR + T clamp(const T& value) + { + return clamp(value, etl::less()); + } + + //*************************************************************************** + /// Remove + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TIterator remove(TIterator first, TIterator last, const T& value) + { + first = etl::find(first, last, value); + + if (first != last) + { + TIterator itr = first; + + while (++itr != last) + { + if (!(*itr == value)) + { + *first++ = etl::move(*itr); + } + } + } + + return first; + } + + //*************************************************************************** + /// Remove If + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TIterator remove_if(TIterator first, TIterator last, TUnaryPredicate predicate) + { + first = etl::find_if(first, last, predicate); + + if (first != last) + { + TIterator itr = first; + + while (++itr != last) + { + if (!predicate(*itr)) + { + *first++ = etl::move(*itr); + } + } + } + + return first; + } +} + +//***************************************************************************** +// ETL extensions to the STL algorithms. +//***************************************************************************** +namespace etl +{ + //*************************************************************************** + /// copy_s + /// A safer form of copy where the smallest of the two ranges is used. + /// There is currently no STL equivalent. + /// Specialisation for random access iterators. + ///\param i_begin Beginning of the input range. + ///\param i_end End of the input range. + ///\param o_begin Beginning of the output range. + ///\param o_end End of the output range. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && + etl::is_random_iterator::value, TOutputIterator>::type + copy_s(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end) + { + size_t s_size = etl::distance(i_begin, i_end); + size_t d_size = etl::distance(o_begin, o_end); + size_t size = (s_size < d_size) ? s_size : d_size; + + return etl::copy(i_begin, i_begin + size, o_begin); + } + + //*************************************************************************** + /// copy + /// A safer form of copy where the smallest of the two ranges is used. + /// There is currently no STL equivalent. + /// Specialisation for non random access iterators. + ///\param i_begin Beginning of the input range. + ///\param i_end End of the input range. + ///\param o_begin Beginning of the output range. + ///\param o_end End of the output range. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + typename etl::enable_if::value || + !etl::is_random_iterator::value, TOutputIterator>::type + copy_s(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end) + { + while ((i_begin != i_end) && (o_begin != o_end)) + { + *o_begin = *i_begin; + ++o_begin; + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// copy_n + /// A safer form of copy_n where the smallest of the two ranges is used. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator copy_n_s(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin, + TOutputIterator o_end) + { + while ((n-- > 0) && (o_begin != o_end)) + { + *o_begin = *i_begin; + ++o_begin; + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// copy_n + /// A safer form of copy_n where the smallest of the two ranges is used. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator copy_n_s(TInputIterator i_begin, + TSize1 n1, + TOutputIterator o_begin, + TSize2 n2) + { + while ((n1-- > 0) && (n2-- > 0)) + { + *o_begin = *i_begin; + ++o_begin; + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// copy_if + /// A safer form of copy_if where it terminates when the first end iterator is reached. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator copy_if_s(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end, + TUnaryPredicate predicate) + { + while ((i_begin != i_end) && (o_begin != o_end)) + { + if (predicate(*i_begin)) + { + *o_begin = *i_begin; + ++o_begin; + } + + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// copy_n_if + /// Combination of copy_n and copy_if. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator copy_n_if(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin, + TUnaryPredicate predicate) + { + while (n-- > 0) + { + if (predicate(*i_begin)) + { + *o_begin = *i_begin; + ++o_begin; + } + + ++i_begin; + } + + return o_begin; + } + +#if ETL_USING_CPP11 + //*************************************************************************** + /// move_s + /// A safer form of move where the smallest of the two ranges is used. + /// There is currently no STL equivalent. + /// Specialisation for random access iterators. + ///\param i_begin Beginning of the input range. + ///\param i_end End of the input range. + ///\param o_begin Beginning of the output range. + ///\param o_end End of the output range. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + typename etl::enable_if::value && + etl::is_random_iterator::value, TOutputIterator>::type + move_s(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end) + { + size_t s_size = etl::distance(i_begin, i_end); + size_t d_size = etl::distance(o_begin, o_end); + size_t size = (s_size < d_size) ? s_size : d_size; + + return etl::move(i_begin, i_begin + size, o_begin); + } + + //*************************************************************************** + /// move_s + /// A safer form of move where the smallest of the two ranges is used. + /// There is currently no STL equivalent. + /// Specialisation for non random access iterators. + ///\param i_begin Beginning of the input range. + ///\param i_end End of the input range. + ///\param o_begin Beginning of the output range. + ///\param o_end End of the output range. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + typename etl::enable_if::value || + !etl::is_random_iterator::value, TOutputIterator>::type + move_s(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end) + { + while ((i_begin != i_end) && (o_begin != o_end)) + { + *o_begin = etl::move(*i_begin); + ++i_begin; + ++o_begin; + } + + return o_begin; + } +#else + //*************************************************************************** + /// move_s + /// C++03 + /// A safer form of move where the smallest of the two ranges is used. + /// There is currently no STL equivalent. + /// Specialisation for non random access iterators. + ///\param i_begin Beginning of the input range. + ///\param i_end End of the input range. + ///\param o_begin Beginning of the output range. + ///\param o_end End of the output range. + ///\ingroup algorithm + //*************************************************************************** + template + TOutputIterator move_s(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end) + { + // Move not supported. Defer to copy. + return etl::copy_s(i_begin, i_end, o_begin, o_end); + } +#endif + + //*************************************************************************** + /// binary_find + ///\ingroup algorithm + /// Does a binary search and returns an iterator to the value or end if not found. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator binary_find(TIterator begin, + TIterator end, + const TValue& value) + { + TIterator it = etl::lower_bound(begin, end, value); + + if ((it == end) || (*it != value)) + { + it = end; + } + + return it; + } + + //*************************************************************************** + /// binary_find + ///\ingroup algorithm + /// Does a binary search and returns an iterator to the value or end if not found. + //*************************************************************************** + template + ETL_NODISCARD + ETL_CONSTEXPR14 + TIterator binary_find(TIterator begin, + TIterator end, + const TValue& value, + TBinaryPredicate predicate, + TBinaryEquality equality) + { + TIterator it = etl::lower_bound(begin, end, value, predicate); + + if ((it == end) || !equality(*it, value)) + { + it = end; + } + + return it; + } + + //*************************************************************************** + /// Like std::for_each but applies a predicate before calling the function. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TUnaryFunction for_each_if(TIterator begin, + const TIterator end, + TUnaryFunction function, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (predicate(*begin)) + { + function(*begin); + } + + ++begin; + } + + return function; + } + + //*************************************************************************** + /// Like std::for_each but for 'n' iterations. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TIterator for_each_n(TIterator begin, + TSize n, + TUnaryFunction function) + { + while (n-- > 0) + { + function(*begin); + ++begin; + } + + return begin; + } + + //*************************************************************************** + /// Like std::for_each but applies a predicate before calling the function, for 'n' iterations + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TIterator for_each_n_if(TIterator begin, + TSize n, + TUnaryFunction function, + TUnaryPredicate predicate) + { + while (n-- > 0) + { + if (predicate(*begin)) + { + function(*begin); + } + + ++begin; + } + + return begin; + } + + //*************************************************************************** + /// A safer form of std::transform where the transform returns when the first + /// range end is reached. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator transform_s(TInputIterator i_begin, + TInputIterator i_end, + TOutputIterator o_begin, + TOutputIterator o_end, + TUnaryFunction function) + { + while ((i_begin != i_end) && (o_begin != o_end)) + { + *o_begin = function(*i_begin); + ++i_begin; + ++o_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// Transform 'n' items. + /// Random iterators. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + void transform_n(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin, + TUnaryFunction function) + { + TInputIterator i_end(i_begin); + etl::advance(i_end, n); + + etl::transform(i_begin, i_end, o_begin, function); + } + + //*************************************************************************** + /// Transform 'n' items from two ranges. + /// Random iterators. + /// There is currently no STL equivalent. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + void transform_n(TInputIterator1 i_begin1, + TInputIterator2 i_begin2, + TSize n, + TOutputIterator o_begin, + TBinaryFunction function) + { + TInputIterator1 i_end1(i_begin1); + etl::advance(i_end1, n); + + etl::transform(i_begin1, i_end1, i_begin2, o_begin, function); + } + + //*************************************************************************** + /// Like std::transform but applies a predicate before calling the function. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator transform_if(TInputIterator i_begin, + const TInputIterator i_end, + TOutputIterator o_begin, + TUnaryFunction function, + TUnaryPredicate predicate) + { + while (i_begin != i_end) + { + if (predicate(*i_begin)) + { + *o_begin = function(*i_begin); + ++o_begin; + } + + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// Like etl::transform_if but inputs from two ranges. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator transform_if(TInputIterator1 i_begin1, + const TInputIterator1 i_end1, + TInputIterator2 i_begin2, + TOutputIterator o_begin, + TBinaryFunction function, + TBinaryPredicate predicate) + { + while (i_begin1 != i_end1) + { + if (predicate(*i_begin1, *i_begin2)) + { + *o_begin = function(*i_begin1, *i_begin2); + ++o_begin; + } + + ++i_begin1; + ++i_begin2; + } + + return o_begin; + } + + //*************************************************************************** + /// Like std::transform_if, for 'n' items. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator transform_n_if(TInputIterator i_begin, + TSize n, + TOutputIterator o_begin, + TUnaryFunction function, + TUnaryPredicate predicate) + { + while (n-- > 0) + { + if (predicate(*i_begin)) + { + *o_begin = function(*i_begin); + ++o_begin; + } + + ++i_begin; + } + + return o_begin; + } + + //*************************************************************************** + /// Like etl::transform_if but inputs from two ranges for 'n' items. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + TOutputIterator transform_n_if(TInputIterator1 i_begin1, + TInputIterator2 i_begin2, + TSize n, + TOutputIterator o_begin, + TBinaryFunction function, + TBinaryPredicate predicate) + { + while (n-- > 0) + { + if (predicate(*i_begin1, *i_begin2)) + { + *o_begin++ = function(*i_begin1, *i_begin2); + } + + ++i_begin1; + ++i_begin2; + } + + return o_begin; + } + + //*************************************************************************** + /// Transforms the elements from the range (begin, end) to two different ranges + /// depending on the value returned by the predicate.
+ ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + ETL_OR_STD::pair partition_transform(TSource begin, + TSource end, + TDestinationTrue destination_true, + TDestinationFalse destination_false, + TUnaryFunctionTrue function_true, + TUnaryFunctionFalse function_false, + TUnaryPredicate predicate) + { + while (begin != end) + { + if (predicate(*begin)) + { + *destination_true = function_true(*begin); + ++destination_true; + } + else + { + *destination_false = function_false(*begin); + ++destination_false; + } + + ++begin; + } + + return ETL_OR_STD::pair(destination_true, destination_false); + } + + //*************************************************************************** + /// Transforms the elements from the ranges (begin1, end1) & (begin2) + /// to two different ranges depending on the value returned by the predicate. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + ETL_OR_STD::pair partition_transform(TSource1 begin1, + TSource1 end1, + TSource2 begin2, + TDestinationTrue destination_true, + TDestinationFalse destination_false, + TBinaryFunctionTrue function_true, + TBinaryFunctionFalse function_false, + TBinaryPredicate predicate) + { + while (begin1 != end1) + { + if (predicate(*begin1, *begin2)) + { + *destination_true = function_true(*begin1, *begin2); + ++destination_true; + } + else + { + *destination_false = function_false(*begin1, *begin2); + ++destination_false; + } + + ++begin1; + ++begin2; + } + + return ETL_OR_STD::pair(destination_true, destination_false); + } + + //*************************************************************************** + /// Sorts the elements using shell sort. + /// Uses user defined comparison. + ///\ingroup algorithm + //*************************************************************************** + template +#if ETL_USING_STD_NAMESPACE + ETL_CONSTEXPR20 +#else + ETL_CONSTEXPR14 +#endif + void shell_sort(TIterator first, TIterator last, TCompare compare) + { + if (first == last) + { + return; + } + + typedef typename etl::iterator_traits::difference_type difference_t; + + difference_t n = etl::distance(first, last); + + for (difference_t i = n / 2; i > 0; i /= 2) + { + for (difference_t j = i; j < n; ++j) + { + for (difference_t k = j - i; k >= 0; k -= i) + { + TIterator itr1 = first; + TIterator itr2 = first; + + etl::advance(itr1, k); + etl::advance(itr2, k + i); + + if (compare(*itr2, *itr1)) + { + etl::iter_swap(itr1, itr2); + } + } + } + } + } + + //*************************************************************************** + /// Sorts the elements using shell sort. + ///\ingroup algorithm + //*************************************************************************** + template +#if ETL_USING_STD_NAMESPACE + ETL_CONSTEXPR20 +#else + ETL_CONSTEXPR14 +#endif + void shell_sort(TIterator first, TIterator last) + { + etl::shell_sort(first, last, etl::less::value_type>()); + } + + //*************************************************************************** + /// Sorts the elements using insertion sort. + /// Uses user defined comparison. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + void insertion_sort(TIterator first, TIterator last, TCompare compare) + { + for (TIterator itr = first; itr != last; ++itr) + { + etl::rotate(etl::upper_bound(first, itr, *itr, compare), itr, etl::next(itr)); + } + } + + //*************************************************************************** + /// Sorts the elements using insertion sort. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + void insertion_sort(TIterator first, TIterator last) + { + etl::insertion_sort(first, last, etl::less::value_type>()); + } + + //*************************************************************************** + namespace private_algorithm + { + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, TIterator>::type + get_before_last(TIterator first_, TIterator last_) + { + TIterator last = first_; + TIterator lastplus1 = first_; + ++lastplus1; + + while (lastplus1 != last_) + { + ++last; + ++lastplus1; + } + + return last; + } + + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, TIterator>::type + get_before_last(TIterator /*first_*/, TIterator last_) + { + TIterator last = last_; + --last; + + return last; + } + + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, TIterator>::type + get_before_last(TIterator /*first_*/, TIterator last_) + { + return last_ - 1; + } + } + + //*************************************************************************** + /// Sorts the elements using selection sort. + /// Uses user defined comparison. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR20 + void selection_sort(TIterator first, TIterator last, TCompare compare) + { + TIterator min; + const TIterator ilast = private_algorithm::get_before_last(first, last); + const TIterator jlast = last; + + for (TIterator i = first; i != ilast; ++i) + { + min = i; + + TIterator j = i; + ++j; + + for (; j != jlast; ++j) + { + if (compare(*j, *min)) + { + min = j; + } + } + + using ETL_OR_STD::swap; // Allow ADL + swap(*i, *min); + } + } + + //*************************************************************************** + /// Sorts the elements using selection sort. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR20 + void selection_sort(TIterator first, TIterator last) + { + selection_sort(first, last, etl::less::value_type>()); + } + + //*************************************************************************** + /// Sorts the elements using heap sort. + /// Uses user defined comparison. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + void heap_sort(TIterator first, TIterator last, TCompare compare) + { + if (!etl::is_heap(first, last, compare)) + { + etl::make_heap(first, last, compare); + } + + etl::sort_heap(first, last, compare); + } + + //*************************************************************************** + /// Sorts the elements using heap sort. + ///\ingroup algorithm + //*************************************************************************** + template + ETL_CONSTEXPR14 + void heap_sort(TIterator first, TIterator last) + { + if (!etl::is_heap(first, last)) + { + etl::make_heap(first, last); + } + + etl::sort_heap(first, last); + } + + //*************************************************************************** + /// Returns the maximum value. + //*************************************************************************** +#if ETL_USING_CPP11 + template + ETL_NODISCARD + constexpr const T& multimax(const T& a, const T& b) + { + return a < b ? b : a; + } + + template + ETL_NODISCARD + constexpr const T& multimax(const T& t, const Tx&... tx) + { + return multimax(t, multimax(tx...)); + } +#endif + + //*************************************************************************** + /// Returns the maximum value. + /// User supplied compare function. + //*************************************************************************** +#if ETL_USING_CPP11 + template + ETL_NODISCARD + constexpr const T& multimax_compare(TCompare compare, const T& a, const T& b) + { + return compare(a, b) ? b : a; + } + + template + ETL_NODISCARD + constexpr const T& multimax_compare(TCompare compare, const T& t, const Tx&... tx) + { + return multimax_compare(compare, t, multimax_compare(compare, tx...)); + } +#endif + + //*************************************************************************** + /// Returns the maximum value. + //*************************************************************************** +#if ETL_USING_CPP11 + template + ETL_NODISCARD + constexpr const T& multimin(const T& a, const T& b) + { + return a < b ? a : b; + } + + template + ETL_NODISCARD + constexpr const T& multimin(const T& t, const Tx&... tx) + { + return multimin(t, multimin(tx...)); + } +#endif + + //*************************************************************************** + /// Returns the minimum value. + /// User supplied compare function. + //*************************************************************************** +#if ETL_USING_CPP11 + template + ETL_NODISCARD + constexpr const T& multimin_compare(TCompare compare, const T& a, const T& b) + { + return compare(a, b) ? a : b; + } + + template + ETL_NODISCARD + constexpr const T& multimin_compare(TCompare compare, const T& t, const Tx&... tx) + { + return multimin_compare(compare, t, multimin_compare(compare, tx...)); + } +#endif + + //*************************************************************************** + /// Returns the iterator to the maximum value. + //*************************************************************************** +#if ETL_USING_CPP11 + template + ETL_NODISCARD + constexpr const TIterator& multimax_iter(const TIterator& a, const TIterator& b) + { + return *a < *b ? b : a; + } + + template + ETL_NODISCARD + constexpr const TIterator& multimax_iter(const TIterator& t, const TIteratorx&... tx) + { + return multimax_iter(t, multimax_iter(tx...)); + } +#endif + + //*************************************************************************** + /// Returns the iterator to the maximum value. + /// User supplied compare function. + //*************************************************************************** +#if ETL_USING_CPP11 + template + ETL_NODISCARD + constexpr const TIterator& multimax_iter_compare(TCompare compare, const TIterator& a, const TIterator& b) + { + return compare(*a, *b) ? b : a; + } + + template + ETL_NODISCARD + constexpr const TIterator& multimax_iter_compare(TCompare compare, const TIterator& t, const TIteratorx&... tx) + { + return multimax_iter_compare(compare, t, multimax_iter_compare(compare, tx...)); + } +#endif + + //*************************************************************************** + /// Returns the iterator to the minimum value. + //*************************************************************************** +#if ETL_USING_CPP11 + template + ETL_NODISCARD + constexpr const TIterator& multimin_iter(const TIterator& a, const TIterator& b) + { + return *a < *b ? a : b; + } + + template + ETL_NODISCARD + constexpr const TIterator& multimin_iter(const TIterator& t, const Tx&... tx) + { + return multimin_iter(t, multimin_iter(tx...)); + } +#endif + + //*************************************************************************** + /// Returns the iterator to the minimum value. + /// User supplied compare function. + //*************************************************************************** +#if ETL_USING_CPP11 + template + ETL_NODISCARD + constexpr const TIterator& multimin_iter_compare(TCompare compare, const TIterator& a, const TIterator& b) + { + return compare(*a, *b) ? a : b; + } + + template + ETL_NODISCARD + constexpr const TIterator& multimin_iter_compare(TCompare compare, const TIterator& t, const Tx&... tx) + { + return multimin_iter_compare(compare, t, multimin_iter_compare(compare, tx...)); + } +#endif + + //*************************************************************************** + /// partition + /// For forward iterators only + /// Does at most etl::distance(first, last) swaps. + //*************************************************************************** + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, TIterator>::type + partition(TIterator first, TIterator last, TPredicate predicate) + { + first = etl::find_if_not(first, last, predicate); + + if (first == last) + { + return first; + } + + for (TIterator i = etl::next(first); i != last; ++i) + { + if (predicate(*i)) + { + using ETL_OR_STD::swap; + swap(*i, *first); + ++first; + } + } + + return first; + } + + //*************************************************************************** + /// partition + /// For iterators that support bidirectional iteration. + /// Does at most (etl::distance(first, last) / 2) swaps. + //*************************************************************************** + template + ETL_CONSTEXPR14 + typename etl::enable_if::value, TIterator>::type + partition(TIterator first, TIterator last, TPredicate predicate) + { + while (first != last) + { + first = etl::find_if_not(first, last, predicate); + + if (first == last) + { + break; + } + + last = etl::find_if(etl::reverse_iterator(last), + etl::reverse_iterator(first), + predicate).base(); + + if (first == last) + { + break; + } + + --last; + using ETL_OR_STD::swap; + swap(*first, *last); + ++first; + } + + return first; + } + + //********************************************************* + namespace private_algorithm + { + using ETL_OR_STD::swap; + + template +#if (ETL_USING_CPP20 && ETL_USING_STL) || (ETL_USING_CPP14 && ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST)) + constexpr +#endif + TIterator nth_partition(TIterator first, TIterator last, TCompare compare) + { + typedef typename etl::iterator_traits::value_type value_type; + + TIterator pivot = last; // Maybe find a better pivot choice? + value_type pivot_value = *pivot; + + // Swap the pivot with the last, if necessary. + if (pivot != last) + { + swap(*pivot, *last); + } + + TIterator i = first; + + for (TIterator j = first; j < last; ++j) + { + if (!compare(pivot_value, *j)) // Hack to get '*j <= pivot_value' in terms of 'pivot_value < *j' + { + swap(*i, *j); + ++i; + } + } + + swap(*i, *last); + + return i; + } + } + + //********************************************************* + /// nth_element + /// see https://en.cppreference.com/w/cpp/algorithm/nth_element + //********************************************************* +#if ETL_USING_CPP11 + template ::value_type>> +#if (ETL_USING_CPP20 && ETL_USING_STL) || (ETL_USING_CPP14 && ETL_NOT_USING_STL && !defined(ETL_IN_UNIT_TEST)) + constexpr +#endif + typename etl::enable_if::value, void>::type + nth_element(TIterator first, TIterator nth, TIterator last, TCompare compare = TCompare()) + { + if (first == last) + { + return; + } + + // 'last' must point to the actual last value. + --last; + + while (first <= last) + { + TIterator p = private_algorithm::nth_partition(first, last, compare); + + if (p == nth) + { + return; + } + else if (p > nth) + { + last = p - 1; + } + else + { + first = p + 1; + } + } + } + +#else + + //********************************************************* + template + typename etl::enable_if::value, void>::type + nth_element(TIterator first, TIterator nth, TIterator last, TCompare compare) + { + if (first == last) + { + return; + } + + // 'last' must point to the actual last value. + --last; + + while (first <= last) + { + TIterator p = private_algorithm::nth_partition(first, last, compare); + + if (p == nth) + { + return; + } + else if (p > nth) + { + last = p - 1; + } + else + { + first = p + 1; + } + } + } + + //********************************************************* + template + typename etl::enable_if::value, void>::type + nth_element(TIterator first, TIterator nth, TIterator last) + { + typedef etl::less::value_type> compare_t; + + nth_element(first, last, compare_t()); + } +#endif +} + +#include "private/minmax_pop.h" + +#endif diff --git a/etl/alignment.h b/etl/alignment.h new file mode 100644 index 0000000..c6a4de0 --- /dev/null +++ b/etl/alignment.h @@ -0,0 +1,339 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ALIGNMENT_INCLUDED +#define ETL_ALIGNMENT_INCLUDED + +#include "platform.h" +#include "type_traits.h" +#include "static_assert.h" +#include "error_handler.h" +#include "exception.h" + +#include + +///\defgroup alignment alignment +/// Creates a variable of the specified type at the specified alignment. +/// \ingroup utilities + +namespace etl +{ + //*************************************************************************** + /// Exception base for alignment + //*************************************************************************** + class alignment_exception : public etl::exception + { + public: + + alignment_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Memory misalignment exception. + //*************************************************************************** + class alignment_error : public alignment_exception + { + public: + + alignment_error(string_type file_name_, numeric_type line_number_) + : alignment_exception(ETL_ERROR_TEXT("alignment:error", ETL_ALIGNMENT_FILE_ID"A"), file_name_, line_number_) + { + } + }; + + //***************************************************************************** + /// Check that 'p' has 'required_alignment'. + //***************************************************************************** + inline bool is_aligned(void* p, size_t required_alignment) + { + uintptr_t address = reinterpret_cast(p); + return (address % required_alignment) == 0U; + } + + //***************************************************************************** + /// Check that 'p' has 'Alignment'. + //***************************************************************************** + template + bool is_aligned(void* p) + { + uintptr_t address = reinterpret_cast(p); + return (address % Alignment) == 0U; + } + + //***************************************************************************** + /// Check that 'p' has the alignment of 'T'. + //***************************************************************************** + template + bool is_aligned(void* p) + { + return is_aligned::value>(p); + } + + namespace private_alignment + { +#if ETL_USING_CPP11 + //*************************************************************************** + // Matcher. + //*************************************************************************** + template + class type_with_alignment_matcher; + + // Matching alignment. + template + class type_with_alignment_matcher + { + public: + + typedef T1 type; + }; + + // Non-matching alignment + template + class type_with_alignment_matcher + { + public: + + typedef typename type_with_alignment_matcher < Alignment <= etl::alignment_of::value , Alignment, T2, TRest... > ::type type; + }; + + // Non-matching alignment, none left. + template + class type_with_alignment_matcher + { + public: + + typedef char type; + }; + + //*************************************************************************** + // Helper. + //*************************************************************************** + template + class type_with_alignment_helper + { + public: + + typedef typename type_with_alignment_matcher::value, Alignment, T1, T...>::type type; + }; +#else + //*************************************************************************** + // Matcher. + //*************************************************************************** + template + class type_with_alignment_matcher; + + // Matching alignment. + template + class type_with_alignment_matcher + { + public: + + typedef T1 type; + }; + + // Non-matching alignment. + template + class type_with_alignment_matcher + { + public: + + typedef typename type_with_alignment_matcher::value, Alignment, T2, T3, T4, T5, T6, T7, T8, void>::type type; + }; + + // Non-matching alignment, none left. + template + class type_with_alignment_matcher + { + public: + + typedef char type; + }; + + //*************************************************************************** + // Helper. + //*************************************************************************** + template + class type_with_alignment_helper + { + public: + + typedef typename type_with_alignment_matcher::value, Alignment, T1, T2, T3, T4, T5, T6, T7, T8>::type type; + }; +#endif + } + + //*************************************************************************** + /// Gets a type that has the same as the specified alignment. + ///\ingroup alignment + //*************************************************************************** + template + class type_with_alignment + { + public: + +#if ETL_USING_CPP11 + typedef struct { alignas(Alignment) char dummy; } type; +#else + #if ETL_NOT_USING_64BIT_TYPES + typedef typename private_alignment::type_with_alignment_helper::type type; + #else + typedef typename private_alignment::type_with_alignment_helper::type type; + #endif +#endif + + ETL_STATIC_ASSERT(etl::alignment_of::value == Alignment, "Unable to create the type with the specified alignment"); + }; + +#if ETL_USING_CPP11 + template + using type_with_alignment_t = typename type_with_alignment::type; +#endif + + //*************************************************************************** + /// Aligned storage + /// Length should be determined in terms of sizeof() + ///\ingroup alignment + //*************************************************************************** + template + struct aligned_storage + { + struct type + { + //type() + // : data() + //{ + //} + + /// Convert to T reference. + template + operator T& () + { + ETL_STATIC_ASSERT((etl::is_same:: value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); + T* t = *this; + return *t; + } + + /// Convert to const T reference. + template + operator const T& () const + { + ETL_STATIC_ASSERT((etl::is_same:: value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); + const T* t = *this; + return *t; + } + + /// Convert to T pointer. + template + operator T* () + { + ETL_STATIC_ASSERT((etl::is_same:: value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); + return reinterpret_cast(data); + } + + /// Convert to const T pointer. + template + operator const T* () const + { + ETL_STATIC_ASSERT((etl::is_same:: value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); + return reinterpret_cast(data); + } + + /// Get address as T reference. + template + T& get_reference() + { + ETL_STATIC_ASSERT((etl::is_same:: value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); + T* t = *this; + return *t; + } + + /// Get address as const T reference. + template + const T& get_reference() const + { + ETL_STATIC_ASSERT((etl::is_same:: value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); + const T* t = *this; + return *t; + } + + /// Get address as T pointer. + template + T* get_address() + { + ETL_STATIC_ASSERT((etl::is_same:: value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); + return reinterpret_cast(data); + } + + /// Get address as const T pointer. + template + const T* get_address() const + { + ETL_STATIC_ASSERT((etl::is_same:: value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); + return reinterpret_cast(data); + } + +#if ETL_USING_CPP11 && !defined(ETL_COMPILER_ARM5) + alignas(Alignment) char data[Length]; +#else + union + { + char data[Length]; + typename etl::type_with_alignment::type etl_alignment_type; // A POD type that has the same alignment as Alignment. + }; +#endif + }; + }; + +#if ETL_USING_CPP11 + template + using aligned_storage_t = typename aligned_storage::type; +#endif + + //*************************************************************************** + /// Aligned storage as + ///\ingroup alignment + //*************************************************************************** + template + struct aligned_storage_as : public etl::aligned_storage::value> + { + }; + +#if ETL_USING_CPP11 + template + using aligned_storage_as_t = typename aligned_storage_as::type; +#endif +} + +#endif diff --git a/etl/array.h b/etl/array.h new file mode 100644 index 0000000..8615f5a --- /dev/null +++ b/etl/array.h @@ -0,0 +1,741 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ARRAY_INCLUDED +#define ETL_ARRAY_INCLUDED + +#include "platform.h" +#include "algorithm.h" +#include "iterator.h" +#include "functional.h" +#include "exception.h" +#include "type_traits.h" +#include "parameter_type.h" +#include "static_assert.h" +#include "error_handler.h" +#include "nth_type.h" +#include "initializer_list.h" + +#include + +///\defgroup array array +/// A replacement for std::array if you haven't got C++0x11. +///\ingroup containers + +namespace etl +{ + //*************************************************************************** + ///\ingroup array + /// The base class for array exceptions. + //*************************************************************************** + class array_exception : public exception + { + public: + + array_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup array + /// The out of range exceptions. + //*************************************************************************** + class array_out_of_range : public array_exception + { + public: + + array_out_of_range(string_type file_name_, numeric_type line_number_) + : array_exception("array:range", file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup array + /// A replacement for std::array if you haven't got C++0x11. + //*************************************************************************** + template + class array + { + private: + + typedef typename etl::parameter_type::type parameter_t; + + public: + + static ETL_CONSTANT size_t SIZE = SIZE_; + + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef T* iterator; + typedef const T* const_iterator; + typedef ETL_OR_STD::reverse_iterator reverse_iterator; + typedef ETL_OR_STD::reverse_iterator const_reverse_iterator; + + //************************************************************************* + // Element access + //************************************************************************* + + //************************************************************************* + /// Returns a reference to the value at index 'i'. + ///\param i The index of the element to access. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + reference at(size_t i) + { + ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); + + return _buffer[i]; + } + + //************************************************************************* + /// Returns a const reference to the value at index 'i'. + ///\param i The index of the element to access. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + const_reference at(size_t i) const + { + ETL_ASSERT(i < SIZE, ETL_ERROR(array_out_of_range)); + + return _buffer[i]; + } + + //************************************************************************* + /// [] operator. + /// Returns a reference to the value at index 'i'. + ///\param i The index of the element to access. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + reference operator[](size_t i) + { + return _buffer[i]; + } + + //************************************************************************* + /// [] operator. + /// Returns a const reference to the value at index 'i'. + ///\param i The index of the element to access. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_reference operator[](size_t i) const + { + return _buffer[i]; + } + + //************************************************************************* + /// Returns a reference to the first element. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + reference front() + { + return _buffer[0]; + } + + //************************************************************************* + /// Returns a const reference to the first element. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_reference front() const + { + return _buffer[0]; + } + + //************************************************************************* + /// Returns a reference to the last element. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + reference back() + { + return _buffer[SIZE - 1]; + } + + //************************************************************************* + /// Returns a const reference to the last element. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_reference back() const + { + return _buffer[SIZE - 1]; + } + + //************************************************************************* + /// Returns a pointer to the first element of the internal buffer. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + pointer data() ETL_NOEXCEPT + { + return &_buffer[0]; + } + + //************************************************************************* + /// Returns a const pointer to the first element of the internal buffer. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_pointer data() const ETL_NOEXCEPT + { + return &_buffer[0]; + } + + //************************************************************************* + // Iterators + //************************************************************************* + + //************************************************************************* + /// Returns an iterator to the beginning of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + iterator begin() ETL_NOEXCEPT + { + return &_buffer[0]; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_iterator begin() const ETL_NOEXCEPT + { + return &_buffer[0]; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_iterator cbegin() const ETL_NOEXCEPT + { + return begin(); + } + + //************************************************************************* + /// Returns an iterator to the end of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + iterator end() ETL_NOEXCEPT + { + return _buffer + SIZE; + } + + //************************************************************************* + /// Returns a const iterator to the end of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_iterator end() const ETL_NOEXCEPT + { + return _buffer + SIZE; + } + + //************************************************************************* + // Returns a const iterator to the end of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_iterator cend() const ETL_NOEXCEPT + { + return _buffer + SIZE; + } + + //************************************************************************* + // Returns an reverse iterator to the reverse beginning of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + reverse_iterator rbegin() ETL_NOEXCEPT + { + return reverse_iterator(end()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_reverse_iterator rbegin() const ETL_NOEXCEPT + { + return const_reverse_iterator(end()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_reverse_iterator crbegin() const ETL_NOEXCEPT + { + return const_reverse_iterator(end()); + } + + //************************************************************************* + /// Returns a reverse iterator to the end of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + reverse_iterator rend() ETL_NOEXCEPT + { + return reverse_iterator(begin()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_reverse_iterator rend() const ETL_NOEXCEPT + { + return const_reverse_iterator(begin()); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR const_reverse_iterator crend() const ETL_NOEXCEPT + { + return const_reverse_iterator(begin()); + } + + //************************************************************************* + // Capacity + //************************************************************************* + + //************************************************************************* + /// Returns true if the array size is zero. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR bool empty() const ETL_NOEXCEPT + { + return (SIZE == 0); + } + + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR size_t size() const ETL_NOEXCEPT + { + return SIZE; + } + + //************************************************************************* + /// Returns the maximum possible size of the array. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR size_t max_size() const ETL_NOEXCEPT + { + return SIZE; + } + + //************************************************************************* + // Operations + //************************************************************************* + + //************************************************************************* + /// Fills the array with the specified value. + ///\param value The value to fill the array with. + //************************************************************************* + ETL_CONSTEXPR14 void fill(parameter_t value) + { + etl::fill(_buffer, _buffer + SIZE, value); + } + + //************************************************************************* + /// Swaps the contents of this array and another. + ///\param other A reference to the other array. + //************************************************************************* + ETL_CONSTEXPR14 void swap(array& other) ETL_NOEXCEPT + { + using ETL_OR_STD::swap; // Allow ADL + + for (size_t i = 0UL; i < SIZE; ++i) + { + swap(_buffer[i], other._buffer[i]); + } + } + + //************************************************************************* + /// Fills the array from the range. + /// If the range is smaller than the array then the unused array elements are left unmodified. + ///\param first The iterator to the first item in the range. + ///\param last The iterator to one past the final item in the range. + ///\return An iterator to the first unassigned array element, or end(). + //************************************************************************* + template + iterator assign(TIterator first, const TIterator last) + { + return etl::copy_s(first, last, begin(), end()); + } + + //************************************************************************* + /// Fills the array from the range. + /// If the range is smaller than the array then the unused array elements are initialised with the supplied value. + ///\param first The iterator to the first item in the range. + ///\param last The iterator to one past the final item in the range. + ///\return An iterator to the first array element set to 'value', or end(). + //************************************************************************* + template + iterator assign(TIterator first, const TIterator last, parameter_t value) + { + // Copy from the range. + iterator p = etl::copy_s(first, last, begin(), end()); + + // Initialise any that are left. + etl::fill(p, end(), value); + + return p; + } + + //************************************************************************* + /// Inserts a value into the array. + ///\param position The index of the position to insert at. + ///\param value The value to insert. + //************************************************************************* + inline iterator insert_at(size_t position, parameter_t value) + { + return insert(begin() + position, value); + } + + //************************************************************************* + /// Inserts a value into the array. + ///\param position The iterator to the position to insert at. + ///\param value The value to insert. + //************************************************************************* + iterator insert(const_iterator position, parameter_t value) + { + iterator p = to_iterator(position); + + etl::move_backward(p, end() - 1, end()); + *p = value; + + return p; + } + + //************************************************************************* + /// Insert into the array from the range. + ///\param position The position to insert at. + ///\param first The iterator to the first item in the range. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template + inline iterator insert_at(size_t position, TIterator first, const TIterator last) + { + return insert(begin() + position, first, last); + } + + //************************************************************************* + /// Insert into the array from the range. + ///\param position The position to insert at. + ///\param first The iterator to the first item in the range. + ///\param last The iterator to one past the final item in the range. + //************************************************************************* + template + iterator insert(const_iterator position, TIterator first, const TIterator last) + { + iterator p = to_iterator(position); + iterator result(p); + + size_t source_size = etl::distance(first, last); + size_t destination_space = etl::distance(position, cend()); + + // Do we need to move anything? + if (source_size < destination_space) + { + size_t length = SIZE - (etl::distance(begin(), p) + source_size); + etl::move_backward(p, p + length, end()); + } + + // Copy from the range. + etl::copy_s(first, last, p, end()); + + return result; + } + + //************************************************************************* + /// Erases a value from the array. + /// After erase, the last value in the array will be unmodified. + ///\param position The index of the position to erase at. + //************************************************************************* + inline iterator erase_at(size_t position) + { + return erase(begin() + position); + } + + //************************************************************************* + /// Erases a value from the array. + /// After erase, the last value in the array will be unmodified. + ///\param position The iterator to the position to erase at. + //************************************************************************* + iterator erase(const_iterator position) + { + iterator p = to_iterator(position); + etl::move(p + 1, end(), p); + + return p; + } + + //************************************************************************* + /// Erases a range of values from the array. + /// After erase, the last values in the array will be unmodified. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + //************************************************************************* + iterator erase_range(size_t first, size_t last) + { + return erase(begin() + first, begin() + last); + } + + //************************************************************************* + /// Erases a range of values from the array. + /// After erase, the last values in the array will be unmodified. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + iterator p = to_iterator(first); + etl::move(last, cend(), p); + return p; + } + + //************************************************************************* + /// Erases a value from the array. + ///\param position The index of the position to erase at. + ///\param value The value to use to overwrite the last element in the array. + //************************************************************************* + inline iterator erase_at(size_t position, parameter_t value) + { + return erase(begin() + position, value); + } + + //************************************************************************* + /// Erases a value from the array. + ///\param position The iterator to the position to erase at. + ///\param value The value to use to overwrite the last element in the array. + //************************************************************************* + iterator erase(const_iterator position, parameter_t value) + { + iterator p = to_iterator(position); + + etl::move(p + 1, end(), p); + back() = value; + + return p; + } + + //************************************************************************* + /// Erases a range of values from the array. + ///\param first The first item to erase. + ///\param last The one past the last item to erase. + ///\param value The value to use to overwrite the last elements in the array. + //************************************************************************* + iterator erase_range(size_t first, size_t last, parameter_t value) + { + return erase(begin() + first, begin() + last, value); + } + + //************************************************************************* + /// Erases a range of values from the array. + ///\param position The iterator to the position to erase at. + ///\param value The value to use to overwrite the last elements in the array. + //************************************************************************* + iterator erase(const_iterator first, const_iterator last, parameter_t value) + { + iterator p = to_iterator(first); + + p = etl::move(last, cend(), p); + etl::fill(p, end(), value); + + return to_iterator(first); + } + + /// The array data. + T _buffer[SIZE]; + + private: + + //************************************************************************* + /// Convert from const_iterator to iterator + //************************************************************************* + iterator to_iterator(const_iterator itr) const + { + return const_cast(itr); + } + }; + + template + ETL_CONSTANT size_t array::SIZE; + + //************************************************************************* + /// Template deduction guides. + //************************************************************************* +#if ETL_USING_CPP17 + template + array(T...) -> array::type, sizeof...(T)>; +#endif + + //************************************************************************* + /// Make + //************************************************************************* +#if ETL_HAS_INITIALIZER_LIST + template + constexpr auto make_array(TValues&&... values) -> etl::array + { + return { etl::forward(values)... }; + } +#endif + + //************************************************************************* + /// Overloaded swap for etl::array + ///\param lhs The first array. + ///\param rhs The second array. + //************************************************************************* + template + void swap(etl::array &lhs, etl::array &rhs) + { + lhs.swap(rhs); + } + + //************************************************************************* + /// Equal operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return true if the arrays are equal, otherwise false + //************************************************************************* + template + bool operator ==(const etl::array& lhs, const etl::array& rhs) + { + return etl::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + } + + //************************************************************************* + /// Not equal operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return true if the arrays are not equal, otherwise false + //************************************************************************* + template + bool operator !=(const etl::array& lhs, const etl::array& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// Less than operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return true if the first array is lexicographically less than the second, otherwise false + //************************************************************************* + template + bool operator <(const etl::array& lhs, const etl::array& rhs) + { + return etl::lexicographical_compare(lhs.cbegin(), + lhs.cend(), + rhs.cbegin(), + rhs.cend()); + } + + //************************************************************************* + /// Less than or equal operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return true if the first array is lexicographically less than or equal to the second, otherwise false + //************************************************************************* + template + bool operator <=(const etl::array& lhs, const etl::array& rhs) + { + return !(lhs > rhs); + } + + //************************************************************************* + /// Greater than operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return true if the first array is lexicographically greater than the second, otherwise false + template + //************************************************************************* + bool operator >(const etl::array& lhs, const etl::array& rhs) + { + return (rhs < lhs); + } + + //************************************************************************* + /// Greater than or equal operator. + ///\param lhs The first array. + ///\param rhs The second array. + ///\return true if the first array is lexicographically greater than or equal to the second, otherwise false + //************************************************************************* + template + bool operator >=(const etl::array& lhs, const etl::array& rhs) + { + return !(lhs < rhs); + } + + //************************************************************************* + /// Gets a reference to an element in the array. + ///\tparam I The index. + ///\tparam T The type. + ///\tparam MAXN The array size. + ///\param a The array. + ///\return A reference to the element + //************************************************************************* + template + inline T& get(array& a) + { + ETL_STATIC_ASSERT(I < MAXN, "Index out of bounds"); + return a[I]; + } + + //************************************************************************* + /// Gets a const reference to an element in the array. + ///\tparam I The index. + ///\tparam T The type. + ///\tparam MAXN The array size. + ///\param a The array. + ///\return A const reference to the element + //************************************************************************* + template + inline const T& get(const array& a) + { + ETL_STATIC_ASSERT(I < MAXN, "Index out of bounds"); + return a[I]; + } +} + +#endif diff --git a/etl/array_view.h b/etl/array_view.h new file mode 100644 index 0000000..f388f28 --- /dev/null +++ b/etl/array_view.h @@ -0,0 +1,655 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ARRAY_VIEW_INCLUDED +#define ETL_ARRAY_VIEW_INCLUDED + +#include "platform.h" +#include "memory.h" +#include "array.h" +#include "iterator.h" +#include "error_handler.h" +#include "exception.h" +#include "nullptr.h" +#include "hash.h" +#include "algorithm.h" +#include "type_traits.h" + +#if ETL_USING_STL && ETL_USING_CPP11 +#include +#endif + +///\defgroup array array +/// A wrapper for arrays +///\ingroup containers + +namespace etl +{ + //*************************************************************************** + /// The base class for array_view exceptions. + //*************************************************************************** + class array_view_exception : public exception + { + public: + + array_view_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the index is out of bounds. + //*************************************************************************** + class array_view_bounds : public array_view_exception + { + public: + + array_view_bounds(string_type file_name_, numeric_type line_number_) + : array_view_exception(ETL_ERROR_TEXT("array_view:bounds", ETL_ARRAY_VIEW_FILE_ID"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the view is uninitialised. + //*************************************************************************** + class array_view_uninitialised : public array_view_exception + { + public: + + array_view_uninitialised(string_type file_name_, numeric_type line_number_) + : array_view_exception(ETL_ERROR_TEXT("array_view:uninitialised", ETL_ARRAY_VIEW_FILE_ID"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Array view. + //*************************************************************************** + template + class array_view + { + public: + + typedef T value_type; + typedef size_t size_type; + typedef const T& const_reference; + typedef const T* const_pointer; + typedef const T* const_iterator; + typedef ETL_OR_STD::reverse_iterator const_reverse_iterator; + +#if defined(ETL_ARRAY_VIEW_IS_MUTABLE) + typedef T* pointer; + typedef T& reference; + typedef T* iterator; + typedef ETL_OR_STD::reverse_iterator reverse_iterator; +#else + typedef const_pointer pointer; + typedef const_reference reference; + typedef const_pointer iterator; + typedef const_reverse_iterator reverse_iterator; +#endif + + //************************************************************************* + /// Default constructor. + //************************************************************************* + ETL_CONSTEXPR array_view() + : mbegin(ETL_NULLPTR), + mend(ETL_NULLPTR) + { + } + +#if ETL_USING_CPP11 + //************************************************************************* + /// Construct from etl::array. + //************************************************************************* + template , etl::remove_cv_t>::value, void>::type> + ETL_CONSTEXPR array_view(etl::array& a) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } + + //************************************************************************* + /// Construct from etl::array. + //************************************************************************* + template , etl::remove_cv_t>::value, void>::type> + ETL_CONSTEXPR array_view(const etl::array& a) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } +#else + //************************************************************************* + /// Construct from etl::array. + //************************************************************************* + template + ETL_CONSTEXPR array_view(etl::array& a, typename etl::enable_if::type, typename etl::remove_cv::type>::value, void>::type* = 0) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } + + //************************************************************************* + /// Construct from etl::array. + //************************************************************************* + template + ETL_CONSTEXPR array_view(const etl::array& a, typename etl::enable_if::type, typename etl::remove_cv::type>::value, void>::type* = 0) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } +#endif + +#if ETL_USING_STL && ETL_USING_CPP11 + //************************************************************************* + /// Construct from std::array. + //************************************************************************* + template , etl::remove_cv_t>::value, void>::type> + ETL_CONSTEXPR array_view(std::array& a) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } + + //************************************************************************* + /// Construct from std::array. + //************************************************************************* + template , etl::remove_cv_t>::value, void>::type> + ETL_CONSTEXPR array_view(const std::array& a) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } +#endif + +#if ETL_USING_CPP11 + //************************************************************************* + /// Construct from a container or other type that supports + /// data() and size() member functions. + //************************************************************************* + template >::value && + !etl::is_array>::value && + etl::is_same, etl::remove_cv_t::value_type>>::value, void>::type> + ETL_CONSTEXPR array_view(TContainer&& a) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } +#else + //************************************************************************* + /// Construct from a container or other type that supports + /// data() and size() member functions. + //************************************************************************* + template + ETL_CONSTEXPR array_view(TContainer& a, typename etl::enable_if::type>::value && + !etl::is_array::value && + etl::is_same::type, typename etl::remove_cv::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } + + //************************************************************************* + /// Construct from a container or other type that supports + /// data() and size() member functions. + //************************************************************************* + template + ETL_CONSTEXPR array_view(const TContainer& a, typename etl::enable_if::type>::value && + !etl::is_array::value && + etl::is_same::type, typename etl::remove_cv::type::value_type>::type>::value, void>::type* = 0) ETL_NOEXCEPT + : mbegin(a.data()) + , mend(a.data() + a.size()) + { + } +#endif + + //************************************************************************* + /// Construct from iterators + //************************************************************************* + template + ETL_CONSTEXPR array_view(const TIterator begin_, const TIterator end_) + : mbegin(etl::addressof(*begin_)), + mend(etl::addressof(*begin_) + etl::distance(begin_, end_)) + { + } + + //************************************************************************* + /// Construct from C array + //************************************************************************* + template + ETL_CONSTEXPR array_view(const TIterator begin_, const TSize size_) + : mbegin(etl::addressof(*begin_)), + mend(etl::addressof(*begin_) + size_) + { + } + + //************************************************************************* + /// Construct from C array + //************************************************************************* + template + ETL_CONSTEXPR array_view(T(&begin_)[Array_Size]) + : mbegin(begin_), + mend(begin_ + Array_Size) + { + } + + //************************************************************************* + /// Copy constructor + //************************************************************************* + ETL_CONSTEXPR array_view(const array_view& other) + : mbegin(other.mbegin), + mend(other.mend) + { + } + + //************************************************************************* + /// Returns a reference to the first element. + //************************************************************************* + reference front() + { + return *mbegin; + } + + //************************************************************************* + /// Returns a const reference to the first element. + //************************************************************************* + const_reference front() const + { + return *mbegin; + } + + //************************************************************************* + /// Returns a reference to the last element. + //************************************************************************* + reference back() + { + return *(mend - 1); + } + + //************************************************************************* + /// Returns a const reference to the last element. + //************************************************************************* + const_reference back() const + { + return *(mend - 1); + } + + //************************************************************************* + /// Returns a pointer to the first element of the internal storage. + //************************************************************************* + pointer data() + { + return mbegin; + } + + //************************************************************************* + /// Returns a const pointer to the first element of the internal storage. + //************************************************************************* + const_pointer data() const + { + return mbegin; + } + + //************************************************************************* + /// Returns an iterator to the beginning of the array. + //************************************************************************* + iterator begin() + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator begin() const + { + return mbegin; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + const_iterator cbegin() const + { + return mbegin; + } + + //************************************************************************* + /// Returns an iterator to the end of the array. + //************************************************************************* + iterator end() + { + return mend; + } + + //************************************************************************* + /// Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator end() const + { + return mend; + } + + //************************************************************************* + // Returns a const iterator to the end of the array. + //************************************************************************* + const_iterator cend() const + { + return mend; + } + + //************************************************************************* + // Returns an reverse iterator to the reverse beginning of the array. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(mend); + } + + //************************************************************************* + /// Returns a reverse iterator to the end of the array. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(mbegin); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(mbegin); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(mbegin); + } + + //************************************************************************* + /// Returns true if the array size is zero. + //************************************************************************* + ETL_CONSTEXPR bool empty() const + { + return (mbegin == mend); + } + + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + ETL_CONSTEXPR size_t size() const + { + return static_cast(mend - mbegin); + } + + //************************************************************************* + /// Returns the maximum possible size of the array. + //************************************************************************* + ETL_CONSTEXPR size_t max_size() const + { + return size(); + } + + //************************************************************************* + /// Assign from a view. + //************************************************************************* + array_view& operator=(const array_view& other) + { + mbegin = other.mbegin; + mend = other.mend; + return *this; + } + + //************************************************************************* + /// Assign from iterators + //************************************************************************* + template + void assign(const TIterator begin_, const TIterator end_) + { + mbegin = etl::addressof(*begin_); + mend = etl::addressof(*begin_) + etl::distance(begin_, end_); + } + + //************************************************************************* + /// Assign from iterator and size. + //************************************************************************* + template + void assign(const TIterator begin_, const TSize size_) + { + mbegin = etl::addressof(*begin_); + mend = etl::addressof(*begin_) + size_; + } + +#if defined(ETL_ARRAY_VIEW_IS_MUTABLE) + //************************************************************************* + /// Returns a reference to the indexed value. + //************************************************************************* + reference operator[](const size_t i) + { + return mbegin[i]; + } +#endif + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference operator[](const size_t i) const + { + return mbegin[i]; + } + +#if defined(ETL_ARRAY_VIEW_IS_MUTABLE) + //************************************************************************* + /// Returns a reference to the indexed value. + //************************************************************************* + reference at(const size_t i) + { + ETL_ASSERT((mbegin != ETL_NULLPTR && mend != ETL_NULLPTR), ETL_ERROR(array_view_uninitialised)); + ETL_ASSERT(i < size(), ETL_ERROR(array_view_bounds)); + return mbegin[i]; + } +#endif + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference at(const size_t i) const + { + ETL_ASSERT((mbegin != ETL_NULLPTR && mend != ETL_NULLPTR), ETL_ERROR(array_view_uninitialised)); + ETL_ASSERT(i < size(), ETL_ERROR(array_view_bounds)); + return mbegin[i]; + } + + //************************************************************************* + /// Swaps with another array_view. + //************************************************************************* + void swap(array_view& other) + { + using ETL_OR_STD::swap; // Allow ADL + + swap(mbegin, other.mbegin); + swap(mend, other.mend); + } + + //************************************************************************* + /// Shrinks the view by moving its start forward. + //************************************************************************* + void remove_prefix(const size_type n) + { + if (n < size()) + mbegin += n; + else + mbegin = mend; + } + + //************************************************************************* + /// Shrinks the view by moving its end backward. + //************************************************************************* + void remove_suffix(const size_type n) + { + if (n < size()) + mend -= n; + else + mend = mbegin; + } + + //************************************************************************* + /// Fills the array. + //************************************************************************* + void fill(const T& value) + { + etl::fill(begin(), end(), value); + } + + //************************************************************************* + /// Equality for array views. + //************************************************************************* + friend bool operator == (const array_view& lhs, const array_view& rhs) + { + return (lhs.size() == rhs.size()) && + etl::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //************************************************************************* + /// Inequality for array views. + //************************************************************************* + friend bool operator != (const array_view& lhs, const array_view& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// Less-than for array views. + //************************************************************************* + friend bool operator < (const array_view& lhs, const array_view& rhs) + { + return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //************************************************************************* + /// Greater-than for array views. + //************************************************************************* + friend bool operator > (const array_view& lhs, const array_view& rhs) + { + return rhs < lhs; + } + + //************************************************************************* + /// Less-than-equal for array views. + //************************************************************************* + friend bool operator <= (const array_view& lhs, const array_view& rhs) + { + return !(lhs > rhs); + } + + //************************************************************************* + /// Greater-than-equal for array views. + //************************************************************************* + friend bool operator >= (const array_view& lhs, const array_view& rhs) + { + return !(lhs < rhs); + } + + private: + + pointer mbegin; + pointer mend; + }; + + //************************************************************************* + /// Template deduction guides. + //************************************************************************* +#if ETL_USING_CPP17 + template + array_view(TArray& a) + -> array_view; + + template + array_view(const TIterator begin_, const TIterator end_) + -> array_view>; + + template + array_view(const TIterator begin_, const TSize size_) + -> array_view>; +#endif + + //************************************************************************* + /// Hash function. + //************************************************************************* +#if ETL_USING_8BIT_TYPES + template + struct hash > + { + size_t operator()(const etl::array_view& view) const + { + return etl::private_hash::generic_hash(reinterpret_cast(view.data()), + reinterpret_cast(view.data() + view.size())); + } + }; +#endif +} + +//************************************************************************* +/// Swaps the values. +//************************************************************************* +template +void swap(etl::array_view& lhs, etl::array_view& rhs) +{ + lhs.swap(rhs); +} + +#endif diff --git a/etl/array_wrapper.h b/etl/array_wrapper.h new file mode 100644 index 0000000..72655f9 --- /dev/null +++ b/etl/array_wrapper.h @@ -0,0 +1,418 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ARRAY_WRAPPER_INCLUDED +#define ETL_ARRAY_WRAPPER_INCLUDED + +#include "platform.h" +#include "iterator.h" +#include "error_handler.h" +#include "exception.h" +#include "hash.h" +#include "parameter_type.h" +#include "algorithm.h" + +///\defgroup array array +/// A wrapper for arrays +///\ingroup containers + +namespace etl +{ + //*************************************************************************** + /// The base class for array_wrapper exceptions. + //*************************************************************************** + class array_wrapper_exception : public exception + { + public: + + array_wrapper_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the index is out of bounds. + //*************************************************************************** + class array_wrapper_bounds : public array_wrapper_exception + { + public: + + array_wrapper_bounds(string_type file_name_, numeric_type line_number_) + : array_wrapper_exception(ETL_ERROR_TEXT("array_wrapper:bounds", ETL_ARRAY_WRAPPER_FILE_ID"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Array wrapper. + //*************************************************************************** + template + class array_wrapper + { + public: + + typedef T value_type; + typedef size_t size_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef T* iterator; + typedef const T* const_iterator; + typedef ETL_OR_STD::reverse_iterator reverse_iterator; + typedef ETL_OR_STD::reverse_iterator const_reverse_iterator; + + typedef typename etl::parameter_type::type parameter_t; + + // Indexes for positions in the array. + enum + { + SIZE = SIZE_, + MAX_SIZE = SIZE_, + FRONT = 0, + BACK = SIZE - 1, + BEGIN = 0, + END = SIZE, + RBEGIN = SIZE - 1, + REND = -1 + }; + + //************************************************************************* + /// Returns a reference to the first element. + //************************************************************************* + reference front() + { + return *&ARRAY_[FRONT]; + } + + //************************************************************************* + /// Returns a const reference to the first element. + //************************************************************************* + ETL_CONSTEXPR const_reference front() const + { + return *&ARRAY_[FRONT]; + } + + //************************************************************************* + /// Returns a reference to the last element. + //************************************************************************* + reference back() + { + return *&ARRAY_[BACK]; + } + + //************************************************************************* + /// Returns a const reference to the last element. + //************************************************************************* + ETL_CONSTEXPR const_reference back() const + { + return *&ARRAY_[BACK]; + } + + //************************************************************************* + /// Returns a pointer to the first element of the internal storage. + //************************************************************************* + pointer data() + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns a const pointer to the first element of the internal storage. + //************************************************************************* + ETL_CONSTEXPR const_pointer data() const + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns an iterator to the beginning of the array. + //************************************************************************* + iterator begin() + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + ETL_CONSTEXPR const_iterator begin() const + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns a const iterator to the beginning of the array. + //************************************************************************* + ETL_CONSTEXPR const_iterator cbegin() const + { + return &ARRAY_[BEGIN]; + } + + //************************************************************************* + /// Returns an iterator to the end of the array. + //************************************************************************* + iterator end() + { + return &ARRAY_[END]; + } + + //************************************************************************* + /// Returns a const iterator to the end of the array. + //************************************************************************* + ETL_CONSTEXPR const_iterator end() const + { + return &ARRAY_[END]; + } + + //************************************************************************* + // Returns a const iterator to the end of the array. + //************************************************************************* + ETL_CONSTEXPR const_iterator cend() const + { + return &ARRAY_[END]; + } + + //************************************************************************* + // Returns an reverse iterator to the reverse beginning of the array. + //************************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(&ARRAY_[END]); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + ETL_CONSTEXPR const_reverse_iterator rbegin() const + { + return const_reverse_iterator(&ARRAY_[END]); + } + + //************************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the array. + //************************************************************************* + ETL_CONSTEXPR const_reverse_iterator crbegin() const + { + return const_reverse_iterator(&ARRAY_[END]); + } + + //************************************************************************* + /// Returns a reverse iterator to the end of the array. + //************************************************************************* + reverse_iterator rend() + { + return reverse_iterator(&ARRAY_[BEGIN]); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + ETL_CONSTEXPR const_reverse_iterator rend() const + { + return const_reverse_iterator(&ARRAY_[BEGIN]); + } + + //************************************************************************* + /// Returns a const reverse iterator to the end of the array. + //************************************************************************* + ETL_CONSTEXPR const_reverse_iterator crend() const + { + return const_reverse_iterator(&ARRAY_[BEGIN]); + } + + //************************************************************************* + /// Returns the size of the array. + //************************************************************************* + ETL_CONSTEXPR size_t size() const + { + return SIZE; + } + + //************************************************************************* + /// Returns the maximum possible size of the array. + //************************************************************************* + ETL_CONSTEXPR size_t max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns a reference to the indexed value. + //************************************************************************* + reference operator[](size_t i) + { + return ARRAY_[i]; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + ETL_CONSTEXPR const_reference operator[](size_t i) const + { + return ARRAY_[i]; + } + + //************************************************************************* + /// Returns a reference to the indexed value. + //************************************************************************* + reference at(size_t i) + { + ETL_ASSERT(i < SIZE, ETL_ERROR(etl::array_wrapper_bounds)); + return ARRAY_[i]; + } + + //************************************************************************* + /// Returns a const reference to the indexed value. + //************************************************************************* + const_reference at(size_t i) const + { + ETL_ASSERT(i < SIZE, ETL_ERROR(etl::array_wrapper_bounds)); + return ARRAY_[i]; + } + + //************************************************************************* + /// Fills the array. + //************************************************************************* + void fill(parameter_t value) + { + etl::fill(begin(), end(), value); + } + + //************************************************************************* + /// Swaps the contents of arrays. + //************************************************************************* + template + typename etl::enable_if::value, void>::type + swap(etl::array_wrapper& other) + { + using ETL_OR_STD::swap; // Allow ADL + + for (size_t i = 0UL; i < SIZE; ++i) + { + swap(ARRAY_[i], other.begin()[i]); + } + } + }; + + //************************************************************************* + /// Equality for array wrappers. + //************************************************************************* + template + bool operator == (const etl::array_wrapper& lhs, + const etl::array_wrapper& rhs) + { + return (SIZEL == SIZER) && etl::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //************************************************************************* + /// Inequality for array wrapper. + //************************************************************************* + template + bool operator != (const etl::array_wrapper& lhs, + const etl::array_wrapper& rhs) + { + return !(lhs == rhs); + } + + //************************************************************************* + /// Less-than for array wrapper. + //************************************************************************* + template + bool operator < (const etl::array_wrapper& lhs, + const etl::array_wrapper& rhs) + { + return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //************************************************************************* + /// Greater-than for array wrapper. + //************************************************************************* + template + bool operator > (const etl::array_wrapper& lhs, + const etl::array_wrapper& rhs) + { + return rhs < lhs; + } + + //************************************************************************* + /// Less-than-equal for array wrapper. + //************************************************************************* + template + bool operator <= (const etl::array_wrapper& lhs, + const etl::array_wrapper& rhs) + { + return !(lhs > rhs); + } + + //************************************************************************* + /// Greater-than-equal for array wrapper. + //************************************************************************* + template + bool operator >= (const etl::array_wrapper& lhs, + const etl::array_wrapper& rhs) + { + return !(lhs < rhs); + } + + //************************************************************************* + /// Hash function. + //************************************************************************* +#if ETL_USING_8BIT_TYPES + template + struct hash > + { + size_t operator()(const etl::array_wrapper& aw) const + { + const uint8_t* pb = reinterpret_cast(aw.data()); + const uint8_t* pe = pb + (SIZE * sizeof(T)); + + return etl::private_hash::generic_hash(pb, pe); + } + }; +#endif +} + +//************************************************************************* +/// Swap. +//************************************************************************* +template +void swap(etl::array_wrapper& lhs, + etl::array_wrapper& rhs) +{ + lhs.swap(rhs); +} + +#define ETL_ARRAY_WRAPPER(arraytype, arrayobject) etl::array_wrapper + +#endif + diff --git a/etl/atomic.h b/etl/atomic.h new file mode 100644 index 0000000..9d18ee5 --- /dev/null +++ b/etl/atomic.h @@ -0,0 +1,48 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ATOMIC_INCLUDED +#define ETL_ATOMIC_INCLUDED + +#include "platform.h" + +#if ETL_HAS_ATOMIC + #if (ETL_USING_CPP11 && (ETL_USING_STL || defined(ETL_IN_UNIT_TEST))) + #include "atomic/atomic_std.h" + #elif defined(ETL_COMPILER_ARM5) + #include "atomic/atomic_arm.h" + #elif defined(ETL_COMPILER_ARM6) + #include "atomic/atomic_arm.h" + #elif defined(ETL_COMPILER_GCC) + #include "atomic/atomic_gcc_sync.h" + #elif defined(ETL_COMPILER_CLANG) + #include "atomic/atomic_clang_sync.h" + #endif +#endif + +#endif diff --git a/etl/atomic/atomic_arm.h b/etl/atomic/atomic_arm.h new file mode 100644 index 0000000..42606b0 --- /dev/null +++ b/etl/atomic/atomic_arm.h @@ -0,0 +1,34 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ATOMIC_ARM_INCLUDED +#define ETL_ATOMIC_ARM_INCLUDED + +#include "atomic_gcc_sync.h" + +#endif diff --git a/etl/atomic/atomic_clang_sync.h b/etl/atomic/atomic_clang_sync.h new file mode 100644 index 0000000..23e9360 --- /dev/null +++ b/etl/atomic/atomic_clang_sync.h @@ -0,0 +1,34 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ATOMIC_CLANG_INCLUDED +#define ETL_ATOMIC_CLANG_INCLUDED + +#include "atomic_gcc_sync.h" + +#endif diff --git a/etl/atomic/atomic_gcc_sync.h b/etl/atomic/atomic_gcc_sync.h new file mode 100644 index 0000000..9e7399a --- /dev/null +++ b/etl/atomic/atomic_gcc_sync.h @@ -0,0 +1,2236 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ATOMIC_GCC_SYNC_INCLUDED +#define ETL_ATOMIC_GCC_SYNC_INCLUDED + +#include "../platform.h" +#include "../type_traits.h" +#include "../static_assert.h" +#include "../nullptr.h" +#include "../char_traits.h" +#include "../mutex.h" + +#include +#include + +// Select the atomic builtins based on the ARM5 version of the GCC compiler. +#if defined(ETL_COMPILER_ARM5) + #define ETL_USE_SYNC_BUILTINS +#endif + +// Select the atomic builtins based on the ARM6 version of the GCC compiler. +#if defined(ETL_COMPILER_ARM6) + #if ETL_COMPILER_FULL_VERSION >= 40700 + #define ETL_USE_ATOMIC_BUILTINS + #else + #define ETL_USE_SYNC_BUILTINS + #endif +#endif + +// Select the atomic builtins based on the version of the GCC compiler. +#if defined(ETL_COMPILER_GCC) + #if ETL_COMPILER_FULL_VERSION >= 40700 + #define ETL_USE_ATOMIC_BUILTINS + #else + #define ETL_USE_SYNC_BUILTINS + #endif +#endif + +// Select the atomic builtins based on the version of the Clang compiler. +#if defined(ETL_COMPILER_CLANG) + #if ETL_COMPILER_FULL_VERSION >= 50000 + #define ETL_USE_ATOMIC_BUILTINS + #else + #define ETL_USE_SYNC_BUILTINS + #endif +#endif + +namespace etl +{ +#if defined(ETL_USE_ATOMIC_BUILTINS) + +#define ETL_BUILTIN_LOCK while (__atomic_test_and_set(&flag, etl::memory_order_seq_cst)) {} +#define ETL_BUILTIN_UNLOCK __atomic_clear(&flag, etl::memory_order_seq_cst); + + //*************************************************************************** + // Atomic type for pre C++11 GCC compilers that support the builtin '__atomic' functions. + // Only integral and pointer types are supported. + //*************************************************************************** + + enum memory_order + { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST + }; + + //*************************************************************************** + /// For all types except bool, pointers and types that are always lock free. + //*************************************************************************** + template ::value> + class atomic + { + public: + + atomic() + : value(T()) + { + } + + atomic(T v) + : value(v) + { + } + + // Assignment + T operator =(T v) + { + store(v); + + return v; + } + + T operator =(T v) volatile + { + store(v); + + return v; + } + + // Pre-increment + T operator ++() + { + return __atomic_add_fetch(&value, 1, etl::memory_order_seq_cst); + } + + T operator ++() volatile + { + return __atomic_add_fetch(&value, 1, etl::memory_order_seq_cst); + } + + // Post-increment + T operator ++(int) + { + return __atomic_fetch_add(&value, 1, etl::memory_order_seq_cst); + } + + T operator ++(int) volatile + { + return __atomic_fetch_add(&value, 1, etl::memory_order_seq_cst); + } + + // Pre-decrement + T operator --() + { + return __atomic_sub_fetch(&value, 1, etl::memory_order_seq_cst); + } + + T operator --() volatile + { + return __atomic_sub_fetch(&value, 1, etl::memory_order_seq_cst); + } + + // Post-decrement + T operator --(int) + { + return __atomic_fetch_sub(&value, 1, etl::memory_order_seq_cst); + } + + T operator --(int) volatile + { + return __atomic_fetch_sub(&value, 1, etl::memory_order_seq_cst); + } + + // Add + T operator +=(T v) + { + return __atomic_fetch_add(&value, v, etl::memory_order_seq_cst); + } + + T operator +=(T v) volatile + { + return __atomic_fetch_add(&value, v, etl::memory_order_seq_cst); + } + + // Subtract + T operator -=(T v) + { + return __atomic_fetch_sub(&value, v, etl::memory_order_seq_cst); + } + + T operator -=(T v) volatile + { + return __atomic_fetch_sub(&value, v, etl::memory_order_seq_cst); + } + + // And + T operator &=(T v) + { + return __atomic_fetch_and(&value, v, etl::memory_order_seq_cst); + } + + T operator &=(T v) volatile + { + return __atomic_fetch_and(&value, v, etl::memory_order_seq_cst); + } + + // Or + T operator |=(T v) + { + return __atomic_fetch_or(&value, v, etl::memory_order_seq_cst); + } + + T operator |=(T v) volatile + { + return __atomic_fetch_or(&value, v, etl::memory_order_seq_cst); + } + + // Exclusive or + T operator ^=(T v) + { + return __atomic_fetch_xor(&value, v, etl::memory_order_seq_cst); + } + + T operator ^=(T v) volatile + { + return __atomic_fetch_xor(&value, v, etl::memory_order_seq_cst); + } + + // Conversion operator + operator T () const + { + return __atomic_fetch_add(&value, 0, etl::memory_order_seq_cst); + } + + operator T() volatile const + { + return __atomic_fetch_add(&value, 0, etl::memory_order_seq_cst); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + __atomic_store_n(&value, v, order); + } + + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + __atomic_store_n(&value, v, order); + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const + { + return __atomic_load_n(&value, order); + } + + T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + return __atomic_load_n(&value, order); + } + + // Fetch add + T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_add(&value, v, order); + } + + T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_add(&value, v, order); + } + + // Fetch subtract + T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_sub(&value, v, order); + } + + T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_sub(&value, v, order); + } + + // Fetch or + T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_or(&value, v, order); + } + + T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_or(&value, v, order); + } + + // Fetch and + T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_and(&value, v, order); + } + + T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_and(&value, v, order); + } + + // Fetch exclusive or + T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_fetch_xor(&value, v, order); + } + + T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_fetch_xor(&value, v, order); + } + + // Exchange + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_exchange_n(&value, v, order); + } + + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_exchange_n(&value, v, order); + } + + // Compare exchange weak + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_compare_exchange_n(&value, &expected, desired, true, order, order); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_compare_exchange_n(&value, &expected, desired, true, order, order); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return __atomic_compare_exchange_n(&value, &expected, desired, true, success, failure); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return __atomic_compare_exchange_n(&value, &expected, desired, true, success, failure); + } + + // Compare exchange strong + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + return __atomic_compare_exchange_n(&value, &expected, desired, false, order, order); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return __atomic_compare_exchange_n(&value, &expected, desired, false, order, order); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return __atomic_compare_exchange_n(&value, &expected, desired, false, success, failure); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return __atomic_compare_exchange_n(&value, &expected, desired, false, success, failure); + } + + private: + + atomic& operator =(const atomic&) ETL_DELETE; + atomic& operator =(const atomic&) volatile ETL_DELETE; + + mutable T value; + }; + + //*************************************************************************** + /// Specialisation for pointers + //*************************************************************************** + template + class atomic + { + public: + + atomic() + : value(0U) + { + } + + atomic(T* v) + : value(uintptr_t(v)) + { + } + + // Assignment + T* operator =(T* v) + { + store(v); + + return v; + } + + T* operator =(T* v) volatile + { + store(v); + + return v; + } + + // Pre-increment + T* operator ++() + { + return reinterpret_cast(__atomic_add_fetch(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator ++() volatile + { + return reinterpret_cast(__atomic_add_fetch(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + // Post-increment + T* operator ++(int) + { + return reinterpret_cast(__atomic_fetch_add(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator ++(int) volatile + { + return reinterpret_cast(__atomic_fetch_add(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + // Pre-decrement + T* operator --() + { + return reinterpret_cast(__atomic_sub_fetch(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator --() volatile + { + return reinterpret_cast(__atomic_sub_fetch(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + // Post-decrement + T* operator --(int) + { + return reinterpret_cast(__atomic_fetch_sub(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator --(int) volatile + { + return reinterpret_cast(__atomic_fetch_sub(&value, sizeof(T), etl::memory_order_seq_cst)); + } + + // Add + T* operator +=(ptrdiff_t v) + { + return reinterpret_cast(__atomic_fetch_add(&value, v * sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator +=(ptrdiff_t v) volatile + { + return reinterpret_cast(__atomic_fetch_add(&value, v * sizeof(T), etl::memory_order_seq_cst)); + } + + // Subtract + T* operator -=(ptrdiff_t v) + { + return reinterpret_cast(__atomic_fetch_sub(&value, v * sizeof(T), etl::memory_order_seq_cst)); + } + + T* operator -=(ptrdiff_t v) volatile + { + return reinterpret_cast(__atomic_fetch_sub(&value, v * sizeof(T), etl::memory_order_seq_cst)); + } + + // Conversion operator + operator T* () const + { + return reinterpret_cast(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst)); + } + + operator T*() volatile const + { + return reinterpret_cast(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst)); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) + { + __atomic_store_n(&value, uintptr_t(v), order); + } + + void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + __atomic_store_n(&value, uintptr_t(v), order); + } + + // Load + T* load(etl::memory_order order = etl::memory_order_seq_cst) const + { + return reinterpret_cast(__atomic_load_n(&value, order)); + } + + T* load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + return reinterpret_cast(__atomic_load_n(&value, order)); + } + + // Fetch add + T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) + { + return reinterpret_cast(__atomic_fetch_add(&value, v, order)); + } + + T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return reinterpret_cast(__atomic_fetch_add(&value, v, order)); + } + + // Fetch subtract + T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) + { + return reinterpret_cast(__atomic_fetch_sub(&value, v, order)); + } + + T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return reinterpret_cast(__atomic_fetch_sub(&value, v, order)); + } + + // Exchange + T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) + { + return reinterpret_cast(__atomic_exchange_n(&value, uintptr_t(v), order)); + } + + T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return reinterpret_cast(__atomic_exchange_n(&value, uintptr_t(v), order)); + } + + // Compare exchange weak + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, order, order); + } + + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, order, order); + } + + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, success, failure); + } + + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, success, failure); + } + + // Compare exchange strong + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, order, order); + } + + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, order, order); + } + + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, success, failure); + } + + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile + { + uintptr_t expected_v = uintptr_t(expected); + + return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, success, failure); + } + + private: + + atomic& operator =(const atomic&) ETL_DELETE; + atomic& operator =(const atomic&) volatile ETL_DELETE; + + mutable uintptr_t value; + }; + + //*************************************************************************** + /// Specialisation for bool + //*************************************************************************** + template <> + class atomic + { + public: + + atomic() + : value(0U) + { + } + + atomic(bool v) + : value(char(v)) + { + } + + // Assignment + bool operator =(bool v) + { + store(v); + + return v; + } + + bool operator =(bool v) volatile + { + store(v); + + return v; + } + + // Conversion operator + operator bool () const + { + return static_cast(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst)); + } + + operator bool() volatile const + { + return static_cast(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst)); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(bool v, etl::memory_order order = etl::memory_order_seq_cst) + { + __atomic_store_n(&value, char(v), order); + } + + void store(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + __atomic_store_n(&value, char(v), order); + } + + // Load + bool load(etl::memory_order order = etl::memory_order_seq_cst) const + { + return static_cast(__atomic_load_n(&value, order)); + } + + bool load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + return static_cast(__atomic_load_n(&value, order)); + } + + // Exchange + bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst) + { + return static_cast(__atomic_exchange_n(&value, char(v), order)); + } + + bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return static_cast(__atomic_exchange_n(&value, char(v), order)); + } + + // Compare exchange weak + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, order, order); + } + + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, order, order); + } + + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, success, failure); + } + + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, success, failure); + } + + // Compare exchange strong + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, order, order); + } + + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, order, order); + } + + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, success, failure); + } + + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile + { + char expected_v = char(expected); + char desired_v = char(desired); + + return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, success, failure); + } + + private: + + atomic& operator =(const atomic&) ETL_DELETE; + atomic& operator =(const atomic&) volatile ETL_DELETE; + + mutable char value; + }; + + //*************************************************************************** + /// Specialisation for type that are not integral, pointer or bool. + /// Uses a mutex to control access. + //*************************************************************************** + template + class atomic + { + public: + + atomic() + : flag(0) + , value(T()) + { + } + + atomic(T v) + : flag(0) + , value(v) + { + } + + // Assignment + T operator =(T v) + { + store(v); + + return v; + } + + T operator =(T v) volatile + { + store(v); + + return v; + } + + // Conversion operator + operator T () const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + operator T() volatile const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Is lock free? + bool is_lock_free() const + { + return false; + } + + bool is_lock_free() const volatile + { + return false; + } + + // Store + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + ETL_BUILTIN_LOCK; + value = v; + ETL_BUILTIN_UNLOCK; + } + + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + ETL_BUILTIN_LOCK; + value = v; + ETL_BUILTIN_UNLOCK; + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + (void)order; + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const + { + (void)order; + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Exchange + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + ETL_BUILTIN_LOCK; + T result = value; + value = v; + ETL_BUILTIN_UNLOCK; + + return result; + } + + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + ETL_BUILTIN_LOCK; + T result = value; + value = v; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Compare exchange weak + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + bool result; + + (void)order; + ETL_BUILTIN_LOCK; + if (memcmp(&value, &expected, sizeof(T)) == 0) + { + value = desired; + result = true; + } + else + { + result = false; + } + ETL_BUILTIN_UNLOCK; + + return result; + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + bool result; + + (void)order; + ETL_BUILTIN_LOCK; + if (memcmp(&value, &expected, sizeof(T)) == 0) + { + value = desired; + result = true; + } + else + { + result = false; + } + ETL_BUILTIN_UNLOCK; + + return result; + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + (void)success; + (void)failure; + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + (void)success; + (void)failure; + return compare_exchange_weak(expected, desired); + } + + // Compare exchange strong + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + (void)success; + (void)failure; + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + (void)success; + (void)failure; + return compare_exchange_weak(expected, desired); + } + + private: + + mutable char flag; + mutable T value; + }; + +#undef ETL_BUILTIN_LOCK +#undef ETL_BUILTIN_UNLOCK + +#endif + +#if defined(ETL_USE_SYNC_BUILTINS) + +#define ETL_BUILTIN_LOCK while (__sync_lock_test_and_set(&flag, 1U)) {} +#define ETL_BUILTIN_UNLOCK __sync_lock_release(&flag); + + //*************************************************************************** + // Atomic type for pre C++11 GCC compilers that support the builtin '__sync' functions. + // Only integral and pointer types are supported. + //*************************************************************************** + + typedef enum memory_order + { + memory_order_relaxed, + memory_order_consume, + memory_order_acquire, + memory_order_release, + memory_order_acq_rel, + memory_order_seq_cst + } memory_order; + + //*************************************************************************** + /// For all types except bool and pointers + //*************************************************************************** + template ::value> + class atomic + { + public: + + ETL_STATIC_ASSERT(etl::is_integral::value, "Only integral types are supported"); + + atomic() + : value(0) + { + } + + atomic(T v) + : value(v) + { + } + + // Assignment + T operator =(T v) + { + store(v); + + return v; + } + + T operator =(T v) volatile + { + store(v); + + return v; + } + + // Pre-increment + T operator ++() + { + return __sync_add_and_fetch(&value, 1); + } + + T operator ++() volatile + { + return __sync_add_and_fetch(&value, 1); + } + + // Post-increment + T operator ++(int) + { + return __sync_fetch_and_add(&value, 1); + } + + T operator ++(int) volatile + { + return __sync_fetch_and_add(&value, 1); + } + + // Pre-decrement + T operator --() + { + return __sync_sub_and_fetch(&value, 1); + } + + T operator --() volatile + { + return __sync_sub_and_fetch(&value, 1); + } + + // Post-decrement + T operator --(int) + { + return __sync_fetch_and_sub(&value, 1); + } + + T operator --(int) volatile + { + return __sync_fetch_and_sub(&value, 1); + } + + // Add + T operator +=(T v) + { + return __sync_fetch_and_add(&value, v); + } + + T operator +=(T v) volatile + { + return __sync_fetch_and_add(&value, v); + } + + // Subtract + T operator -=(T v) + { + return __sync_fetch_and_sub(&value, v); + } + + T operator -=(T v) volatile + { + return __sync_fetch_and_sub(&value, v); + } + + // And + T operator &=(T v) + { + return __sync_fetch_and_and(&value, v); + } + + T operator &=(T v) volatile + { + return __sync_fetch_and_and(&value, v); + } + + // Or + T operator |=(T v) + { + return __sync_fetch_and_or(&value, v); + } + + T operator |=(T v) volatile + { + return __sync_fetch_and_or(&value, v); + } + + // Exclusive or + T operator ^=(T v) + { + return __sync_fetch_and_xor(&value, v); + } + + T operator ^=(T v) volatile + { + return __sync_fetch_and_xor(&value, v); + } + + // Conversion operator + operator T () const + { + return __sync_fetch_and_add(&value, 0); + } + + operator T() volatile const + { + return __sync_fetch_and_add(&value, 0); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + (void)__sync_lock_test_and_set(&value, v); + } + + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + (void)__sync_lock_test_and_set(&value, v); + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const + { + (void)order; + return __sync_fetch_and_add(&value, 0); + } + + T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + (void)order; + return __sync_fetch_and_add(&value, 0); + } + + // Fetch add + T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + return __sync_fetch_and_add(&value, v); + } + + T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + return __sync_fetch_and_add(&value, v); + } + + // Fetch subtract + T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + return __sync_fetch_and_sub(&value, v); + } + + T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + return __sync_fetch_and_sub(&value, v); + } + + // Fetch or + T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + return __sync_fetch_and_or(&value, v); + } + + T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + return __sync_fetch_and_or(&value, v); + } + + // Fetch and + T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + return __sync_fetch_and_and(&value, v); + } + + T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + return __sync_fetch_and_and(&value, v); + } + + // Fetch exclusive or + T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + return __sync_fetch_and_xor(&value, v); + } + + T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + return __sync_fetch_and_xor(&value, v); + } + + // Exchange + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + return __sync_lock_test_and_set(&value, v); + } + + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + return __sync_lock_test_and_set(&value, v); + } + + // Compare exchange weak + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + T old = __sync_val_compare_and_swap(&value, expected, desired); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + T old = __sync_val_compare_and_swap(&value, expected, desired); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + (void)success; + (void)failure; + T old = __sync_val_compare_and_swap(&value, expected, desired); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + (void)success; + (void)failure; + T old = __sync_val_compare_and_swap(&value, expected, desired); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + // Compare exchange strong + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + (void)order; + T old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + (void)order; + T old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + (void)success; + (void)failure; + T old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + (void)success; + (void)failure; + T old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T))) + { + expected = old; + return false; + } + } + + return true; + } + + private: + + atomic& operator =(const atomic&) ETL_DELETE; + atomic& operator =(const atomic&) volatile ETL_DELETE; + + mutable volatile T value; + }; + + //*************************************************************************** + /// Specialisation for pointers + //*************************************************************************** + template + class atomic + { + public: + + atomic() + : value(0U) + { + } + + atomic(T* v) + : value(uintptr_t(v)) + { + } + + // Assignment + T* operator =(T* v) + { + store(v); + + return v; + } + + T* operator =(T* v) volatile + { + store(v); + + return v; + } + + // Pre-increment + T* operator ++() + { + return reinterpret_cast(__sync_add_and_fetch(&value, sizeof(T))); + } + + T* operator ++() volatile + { + return reinterpret_cast(__sync_add_and_fetch(&value, sizeof(T))); + } + + // Post-increment + T* operator ++(int) + { + return reinterpret_cast(__sync_fetch_and_add(&value, sizeof(T))); + } + + T* operator ++(int) volatile + { + return reinterpret_cast(__sync_fetch_and_add(&value, sizeof(T))); + } + + // Pre-decrement + T* operator --() + { + return reinterpret_cast(__sync_sub_and_fetch(&value, sizeof(T))); + } + + T* operator --() volatile + { + return reinterpret_cast(__sync_sub_and_fetch(&value, sizeof(T))); + } + + // Post-decrement + T* operator --(int) + { + return reinterpret_cast(__sync_fetch_and_sub(&value, sizeof(T))); + } + + T* operator --(int) volatile + { + return reinterpret_cast(__sync_fetch_and_sub(&value, sizeof(T))); + } + + // Add + T* operator +=(ptrdiff_t v) + { + return reinterpret_cast(__sync_fetch_and_add(&value, v * sizeof(T))); + } + + T* operator +=(ptrdiff_t v) volatile + { + return reinterpret_cast(__sync_fetch_and_add(&value, v * sizeof(T))); + } + + // Subtract + T* operator -=(ptrdiff_t v) + { + return reinterpret_cast(__sync_fetch_and_sub(&value, v * sizeof(T))); + } + + T* operator -=(ptrdiff_t v) volatile + { + return reinterpret_cast(__sync_fetch_and_sub(&value, v * sizeof(T))); + } + + // Conversion operator + operator T* () const + { + return reinterpret_cast(__sync_fetch_and_add(&value, 0)); + } + + operator T* () volatile const + { + return reinterpret_cast(__sync_fetch_and_add(&value, 0)); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) + { + __sync_lock_test_and_set(&value, uintptr_t(v)); + } + + void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + __sync_lock_test_and_set(&value, uintptr_t(v)); + } + + // Load + T* load(etl::memory_order order = etl::memory_order_seq_cst) const + { + return reinterpret_cast(__sync_fetch_and_add(&value, 0)); + } + + T* load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + return reinterpret_cast(__sync_fetch_and_add(&value, 0)); + } + + // Fetch add + T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) + { + return reinterpret_cast(__sync_fetch_and_add(&value, v)); + } + + T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return reinterpret_cast(__sync_fetch_and_add(&value, v)); + } + + // Fetch subtract + T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) + { + return reinterpret_cast(__sync_fetch_and_sub(&value, v)); + } + + T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return reinterpret_cast(__sync_fetch_and_sub(&value, v)); + } + + // Exchange + T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) + { + return reinterpret_cast(__sync_lock_test_and_set(&value, uintptr_t(v))); + } + + T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return reinterpret_cast(__sync_lock_test_and_set(&value, uintptr_t(v))); + } + + // Compare exchange weak + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) + { + T* old = reinterpret_cast(__sync_val_compare_and_swap(&value, uintptr_t(expected), uintptr_t(desired))); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + T* old = reinterpret_cast(__sync_val_compare_and_swap(&value, uintptr_t(expected), uintptr_t(desired))); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) + { + T* old = reinterpret_cast(__sync_val_compare_and_swap(&value, uintptr_t(expected), uintptr_t(desired))); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile + { + T* old = reinterpret_cast(__sync_val_compare_and_swap(&value, uintptr_t(expected), uintptr_t(desired))); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + // Compare exchange strong + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) + { + T* old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T*))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + T* old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T*))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) + { + T* old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T*))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile + { + T* old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(T*))) + { + expected = old; + return false; + } + } + + return true; + } + + private: + + atomic& operator =(const atomic&) ETL_DELETE; + atomic& operator =(const atomic&) volatile ETL_DELETE; + + mutable uintptr_t value; + }; + + //*************************************************************************** + /// Specialisation for bool + //*************************************************************************** + template <> + class atomic + { + public: + + atomic() + : value(0U) + { + } + + atomic(bool v) + : value(char(v)) + { + } + + // Assignment + bool operator =(bool v) + { + store(v); + + return v; + } + + bool operator =(bool v) volatile + { + store(v); + + return v; + } + + // Conversion operator + operator bool() const + { + return static_cast(__sync_fetch_and_add(&value, 0)); + } + + operator bool() volatile const + { + return static_cast(__sync_fetch_and_add(&value, 0)); + } + + // Is lock free? + bool is_lock_free() const + { + return true; + } + + bool is_lock_free() const volatile + { + return true; + } + + // Store + void store(bool v, etl::memory_order order = etl::memory_order_seq_cst) + { + __sync_lock_test_and_set(&value, char(v)); + } + + void store(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + __sync_lock_test_and_set(&value, char(v)); + } + + // Load + bool load(etl::memory_order order = etl::memory_order_seq_cst) const + { + return static_cast(__sync_fetch_and_add(&value, 0)); + } + + bool load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + return static_cast(__sync_fetch_and_add(&value, 0)); + } + + // Exchange + bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst) + { + return static_cast(__sync_lock_test_and_set(&value, char(v))); + } + + bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return static_cast(__sync_lock_test_and_set(&value, char(v))); + } + + // Compare exchange weak + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) + { + bool old = static_cast(__sync_val_compare_and_swap(&value, char(expected), char(desired))); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + bool old = static_cast(__sync_val_compare_and_swap(&value, char(expected), char(desired))); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) + { + bool old = static_cast(__sync_val_compare_and_swap(&value, char(expected), char(desired))); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile + { + bool old = static_cast(__sync_val_compare_and_swap(&value, char(expected), char(desired))); + + if (old == expected) + { + return true; + } + else + { + expected = old; + return false; + } + } + + // Compare exchange strong + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) + { + bool old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(bool))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + bool old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(bool))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) + { + bool old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(bool))) + { + expected = old; + return false; + } + } + + return true; + } + + bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile + { + bool old = expected; + + while (!compare_exchange_weak(old, desired)) + { + if (memcmp(&old, &expected, sizeof(bool))) + { + expected = old; + return false; + } + } + + return true; + } + + private: + + atomic& operator =(const atomic&) ETL_DELETE; + atomic& operator =(const atomic&) volatile ETL_DELETE; + + mutable char value; + }; + + //*************************************************************************** + /// Specialisation for type that are not integral, pointer or bool. + /// Uses a mutex to control access. + //*************************************************************************** + template + class atomic + { + public: + + atomic() + : flag(0) + , value(T()) + { + } + + atomic(T v) + : flag(0) + , value(v) + { + } + + // Assignment + T operator =(T v) + { + store(v); + + return v; + } + + T operator =(T v) volatile + { + store(v); + + return v; + } + + // Conversion operator + operator T () const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + operator T() volatile const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Is lock free? + bool is_lock_free() const + { + return false; + } + + bool is_lock_free() const volatile + { + return false; + } + + // Store + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + ETL_BUILTIN_LOCK; + value = v; + ETL_BUILTIN_UNLOCK; + } + + void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + ETL_BUILTIN_LOCK; + value = v; + ETL_BUILTIN_UNLOCK; + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Load + T load(etl::memory_order order = etl::memory_order_seq_cst) const + { + ETL_BUILTIN_LOCK; + T result = value; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Exchange + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) + { + ETL_BUILTIN_LOCK; + T result = value; + value = v; + ETL_BUILTIN_UNLOCK; + + return result; + } + + T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + ETL_BUILTIN_LOCK; + T result = value; + value = v; + ETL_BUILTIN_UNLOCK; + + return result; + } + + // Compare exchange weak + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + bool result; + + ETL_BUILTIN_LOCK; + if (memcmp(&value, &expected, sizeof(T)) == 0) + { + value = desired; + result = true; + } + else + { + result = false; + } + ETL_BUILTIN_UNLOCK; + + return result; + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + bool result; + + ETL_BUILTIN_LOCK; + if (memcmp(&value, &expected, sizeof(T)) == 0) + { + value = desired; + result = true; + } + else + { + result = false; + } + ETL_BUILTIN_UNLOCK; + + return result; + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return compare_exchange_weak(expected, desired); + } + + // Compare exchange strong + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) + { + return compare_exchange_weak(expected, desired); + } + + bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile + { + return compare_exchange_weak(expected, desired); + } + + private: + + mutable char flag; + mutable T value; + }; + +#undef ETL_SYNC_BUILTIN_LOCK +#undef ETL_SYNC_BUILTIN_UNLOCK + +#endif + + typedef etl::atomic atomic_bool; + typedef etl::atomic atomic_char; + typedef etl::atomic atomic_schar; + typedef etl::atomic atomic_uchar; + typedef etl::atomic atomic_short; + typedef etl::atomic atomic_ushort; + typedef etl::atomic atomic_int; + typedef etl::atomic atomic_uint; + typedef etl::atomic atomic_long; + typedef etl::atomic atomic_ulong; + typedef etl::atomic atomic_llong; + typedef etl::atomic atomic_ullong; + typedef etl::atomic atomic_wchar_t; +#if ETL_HAS_NATIVE_CHAR8_T + typedef etl::atomic atomic_char8_t; +#endif +#if ETL_HAS_NATIVE_CHAR16_T + typedef etl::atomic atomic_char16_t; +#endif +#if ETL_HAS_NATIVE_CHAR32_T + typedef etl::atomic atomic_char32_t; +#endif +#if ETL_USING_8BIT_TYPES + typedef etl::atomic atomic_uint8_t; + typedef etl::atomic atomic_int8_t; +#endif + typedef etl::atomic atomic_uint16_t; + typedef etl::atomic atomic_int16_t; + typedef etl::atomic atomic_uint32_t; + typedef etl::atomic atomic_int32_t; +#if ETL_USING_64BIT_TYPES + typedef etl::atomic atomic_uint64_t; + typedef etl::atomic atomic_int64_t; +#endif + typedef etl::atomic atomic_int_least8_t; + typedef etl::atomic atomic_uint_least8_t; + typedef etl::atomic atomic_int_least16_t; + typedef etl::atomic atomic_uint_least16_t; + typedef etl::atomic atomic_int_least32_t; + typedef etl::atomic atomic_uint_least32_t; +#if ETL_USING_64BIT_TYPES + typedef etl::atomic atomic_int_least64_t; + typedef etl::atomic atomic_uint_least64_t; +#endif + typedef etl::atomic atomic_int_fast8_t; + typedef etl::atomic atomic_uint_fast8_t; + typedef etl::atomic atomic_int_fast16_t; + typedef etl::atomic atomic_uint_fast16_t; + typedef etl::atomic atomic_int_fast32_t; + typedef etl::atomic atomic_uint_fast32_t; +#if ETL_USING_64BIT_TYPES + typedef etl::atomic atomic_int_fast64_t; + typedef etl::atomic atomic_uint_fast64_t; +#endif + typedef etl::atomic atomic_intptr_t; + typedef etl::atomic atomic_uintptr_t; + typedef etl::atomic atomic_size_t; + typedef etl::atomic atomic_ptrdiff_t; + typedef etl::atomic atomic_intmax_t; + typedef etl::atomic atomic_uintmax_t; +} + +#endif diff --git a/etl/atomic/atomic_std.h b/etl/atomic/atomic_std.h new file mode 100644 index 0000000..bea19d5 --- /dev/null +++ b/etl/atomic/atomic_std.h @@ -0,0 +1,120 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2018 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_ATOMIC_STD_INCLUDED +#define ETL_ATOMIC_STD_INCLUDED + +#include "../platform.h" +#include "../nullptr.h" +#include "../char_traits.h" + +#include +#include + +namespace etl +{ + //*************************************************************************** + // ETL Atomic type for compilers that support std::atomic. + // etl::atomic is a simple wrapper around std::atomic. + //*************************************************************************** + + template + using atomic = std::atomic; + + using memory_order = std::memory_order; + + static ETL_CONSTANT etl::memory_order memory_order_relaxed = std::memory_order_relaxed; + static ETL_CONSTANT etl::memory_order memory_order_consume = std::memory_order_consume; + static ETL_CONSTANT etl::memory_order memory_order_acquire = std::memory_order_acquire; + static ETL_CONSTANT etl::memory_order memory_order_release = std::memory_order_release; + static ETL_CONSTANT etl::memory_order memory_order_acq_rel = std::memory_order_acq_rel; + static ETL_CONSTANT etl::memory_order memory_order_seq_cst = std::memory_order_seq_cst; + + using atomic_bool = std::atomic; + using atomic_char = std::atomic; + using atomic_schar = std::atomic; + using atomic_uchar = std::atomic; + using atomic_short = std::atomic; + using atomic_ushort = std::atomic; + using atomic_int = std::atomic; + using atomic_uint = std::atomic; + using atomic_long = std::atomic; + using atomic_ulong = std::atomic; + using atomic_llong = std::atomic; + using atomic_ullong = std::atomic; + using atomic_wchar_t = std::atomic; +#if ETL_HAS_NATIVE_CHAR8_T + using atomic_char8_t = std::atomic; +#endif +#if ETL_HAS_NATIVE_CHAR16_T + using atomic_char16_t = std::atomic; +#endif +#if ETL_HAS_NATIVE_CHAR32_T + using atomic_char32_t = std::atomic; +#endif +#if ETL_USING_8BIT_TYPES + using atomic_uint8_t = std::atomic; + using atomic_int8_t = std::atomic; +#endif + using atomic_uint16_t = std::atomic; + using atomic_int16_t = std::atomic; + using atomic_uint32_t = std::atomic; + using atomic_int32_t = std::atomic; +#if ETL_USING_64BIT_TYPES + using atomic_uint64_t = std::atomic; + using atomic_int64_t = std::atomic; +#endif + using atomic_int_least8_t = std::atomic; + using atomic_uint_least8_t = std::atomic; + using atomic_int_least16_t = std::atomic; + using atomic_uint_least16_t = std::atomic; + using atomic_int_least32_t = std::atomic; + using atomic_uint_least32_t = std::atomic; +#if ETL_USING_64BIT_TYPES + using atomic_int_least64_t = std::atomic; + using atomic_uint_least64_t = std::atomic; +#endif + using atomic_int_fast8_t = std::atomic; + using atomic_uint_fast8_t = std::atomic; + using atomic_int_fast16_t = std::atomic; + using atomic_uint_fast16_t = std::atomic; + using atomic_int_fast32_t = std::atomic; + using atomic_uint_fast32_t = std::atomic; +#if ETL_USING_64BIT_TYPES + using atomic_int_fast64_t = std::atomic; + using atomic_uint_fast64_t = std::atomic; +#endif + using atomic_intptr_t = std::atomic; + using atomic_uintptr_t = std::atomic; + using atomic_size_t = std::atomic; + using atomic_ptrdiff_t = std::atomic; + using atomic_intmax_t = std::atomic; + using atomic_uintmax_t = std::atomic; +} + +#endif diff --git a/etl/base64.h b/etl/base64.h new file mode 100644 index 0000000..4034248 --- /dev/null +++ b/etl/base64.h @@ -0,0 +1,218 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com +Copyright(c) 2024 John Wellbelove +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_BASE64_INCLUDED +#define ETL_BASE64_INCLUDED + +#include "platform.h" +#include "static_assert.h" +#include "exception.h" +#include "error_handler.h" +#include "type_traits.h" +#include "enum_type.h" +#include "integral_limits.h" + +#include + +/************************************************************************************************************************************************************************** +* See https://en.wikipedia.org/wiki/Base64 +* +* Encoding Encoding characters Separate encoding of lines Decoding non-encoding characters +* 62nd 63rd Pad Separators Length Checksum +* RFC 1421 : Base64 for Privacy - Enhanced Mail(deprecated) + / = mandatory CR + LF 64, or lower for the last line No No +* RFC 2045 : Base64 transfer encoding for MIME + / = mandatory CR + LF At most 76 No Discarded +* RFC 2152 : Base64 for UTF - 7 + / No No No +* RFC 3501 : Base64 encoding for IMAP mailbox names + , No No No +* RFC 4648 : base64(standard)[a] + / = optional No No +* RFC 4648 : base64url(URL - and filename - safe standard) - _ = optional No No +**************************************************************************************************************************************************************************/ + +namespace etl +{ + //*************************************************************************** + /// Exception base for base64 + //*************************************************************************** + class base64_exception : public etl::exception + { + public: + + base64_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// buffer overflow exception. + //*************************************************************************** + class base64_overflow : public base64_exception + { + public: + + base64_overflow(string_type file_name_, numeric_type line_number_) + : base64_exception(ETL_ERROR_TEXT("base64:overflow", ETL_BASE64_FILE_ID"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Illegal character exception. + //*************************************************************************** + class base64_invalid_data : public base64_exception + { + public: + + base64_invalid_data(string_type file_name_, numeric_type line_number_) + : base64_exception(ETL_ERROR_TEXT("base64:invalid data", ETL_BASE64_FILE_ID"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Invalid decode input length exception. + //*************************************************************************** + class base64_invalid_decode_input_length : public base64_exception + { + public: + + base64_invalid_decode_input_length(string_type file_name_, numeric_type line_number_) + : base64_exception(ETL_ERROR_TEXT("base64:invalid decode input length", ETL_BASE64_FILE_ID"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Common Base64 definitions + //*************************************************************************** + class base64 + { + public: + + struct Encoding + { + enum enum_type + { + //RFC_1421, // Not implemented + //RFC_2045, // Not implemented + RFC_2152, + RFC_3501, + RFC_4648, + RFC_4648_PADDING, + RFC_4648_URL, + RFC_4648_URL_PADDING, + }; + + ETL_DECLARE_ENUM_TYPE(Encoding, int) + //ETL_ENUM_TYPE(RFC_1421, "RFC_1421") // Not implemented + //ETL_ENUM_TYPE(RFC_2045, "RFC_2045") // Not implemented + ETL_ENUM_TYPE(RFC_2152, "RFC_2152") + ETL_ENUM_TYPE(RFC_3501, "RFC_3501") + ETL_ENUM_TYPE(RFC_4648, "RFC_4648") + ETL_ENUM_TYPE(RFC_4648_PADDING, "RFC_4648_PADDING") + ETL_ENUM_TYPE(RFC_4648_URL, "RFC_4648_URL") + ETL_ENUM_TYPE(RFC_4648_URL_PADDING, "RFC_4648_URL_PADDING") + ETL_END_ENUM_TYPE + }; + + struct Padding + { + enum enum_type + { + No_Padding = 0, + Use_Padding = 1 + }; + + ETL_DECLARE_ENUM_TYPE(Padding, bool) + ETL_ENUM_TYPE(No_Padding, "No_Padding") + ETL_ENUM_TYPE(Use_Padding, "Use_Padding") + ETL_END_ENUM_TYPE + }; + + struct Non_Coding_Characters + { + enum enum_type + { + Ignore = 0, + Reject = 1 + }; + + ETL_DECLARE_ENUM_TYPE(Non_Coding_Characters, bool) + ETL_ENUM_TYPE(Ignore, "Ignore") + ETL_ENUM_TYPE(Reject, "Reject") + ETL_END_ENUM_TYPE + }; + + enum + { + Invalid_Data = etl::integral_limits::max, + Min_Encode_Buffer_Size = 4, + Min_Decode_Buffer_Size = 3 + }; + + protected: + + ETL_CONSTEXPR14 + base64(const char* encoder_table_, + bool use_padding_) + : encoder_table(encoder_table_) + , use_padding(use_padding_) + { + } + + //************************************************************************* + // Character set for RFC-1421, RFC-2045, RFC-2152 and RFC-4648 + //************************************************************************* + static + ETL_CONSTEXPR14 + const char* character_set_1() + { + return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + } + + //************************************************************************* + // Character set for RFC-4648-URL + //************************************************************************* + static + ETL_CONSTEXPR14 + const char* character_set_2() + { + return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + } + + //************************************************************************* + // Character set for RFC-3501-URL + //************************************************************************* + static + ETL_CONSTEXPR14 + const char* character_set_3() + { + return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; + } + + const char* encoder_table; + const bool use_padding; + }; +} +#endif diff --git a/etl/base64_decoder.h b/etl/base64_decoder.h new file mode 100644 index 0000000..848c7e3 --- /dev/null +++ b/etl/base64_decoder.h @@ -0,0 +1,868 @@ +//************************************************************************* +///Decode from Base64 from and to pointer/length +//*************************************************************************///\file + +/****************************************************************************** +The MIT License(MIT) +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com +Copyright(c) 2024 John Wellbelove +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_BASE64_DECODER_INCLUDED +#define ETL_BASE64_DECODER_INCLUDED + +#include "platform.h" +#include "static_assert.h" +#include "error_handler.h" +#include "type_traits.h" +#include "binary.h" +#include "algorithm.h" +#include "integral_limits.h" +#include "iterator.h" +#include "enum_type.h" +#include "delegate.h" +#include "span.h" + +#include "base64.h" + +#include + +#if ETL_USING_STL + #include +#endif + +#define ETL_IS_8_BIT_INTEGRAL(Type) (etl::is_integral::type>::value && \ + (etl::integral_limits::type>::bits == 8U)) + +#define ETL_IS_ITERATOR_TYPE_8_BIT_INTEGRAL(Type) (etl::is_integral::type>::value_type>::value && \ + (etl::integral_limits::type>::value_type>::bits == 8U)) + +namespace etl +{ + //************************************************************************* + /// Base64 Decoder + //************************************************************************* + class ibase64_decoder : public base64 + { + public: + + typedef etl::span span_type; + typedef etl::delegate callback_type; + + //************************************************************************* + /// Decode to Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool decode(T value) + { + ETL_STATIC_ASSERT(ETL_IS_8_BIT_INTEGRAL(T), "Input type must be an 8 bit integral"); + + push_to_input_buffer(value); + + if (input_buffer_is_full()) + { + if (decode_block()) + { + if (callback.is_valid()) + { + if (output_buffer_is_full()) + { + callback(span()); + reset_output_buffer(); + } + } + } + + reset_input_buffer(); + } + + return !error(); + } + + //************************************************************************* + /// Decode from Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool decode(TInputIterator input_begin, TInputIterator input_end) + { + ETL_STATIC_ASSERT(ETL_IS_ITERATOR_TYPE_8_BIT_INTEGRAL(TInputIterator), "Input type must be an 8 bit integral"); + + while (input_begin != input_end) + { + if (!decode(*input_begin++)) + { + return false; + } + } + + return true; + } + + //************************************************************************* + /// Decode from Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool decode(TInputIterator input_begin, size_t input_length) + { + ETL_STATIC_ASSERT(ETL_IS_ITERATOR_TYPE_8_BIT_INTEGRAL(TInputIterator), "Input type must be an 8 bit integral"); + + while (input_length-- != 0) + { + if (!decode(*input_begin++)) + { + return false; + } + } + + return true; + } + + //************************************************************************* + /// Decode from Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool decode_final(TInputIterator input_begin, TInputIterator input_end) + { + return decode(input_begin, input_end) && flush(); + } + + //************************************************************************* + /// Decode from Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool decode_final(TInputIterator input_begin, size_t input_length) + { + return decode(input_begin, input_length) && flush(); + } + + //************************************************************************* + /// Flush any remaining data to the output. + //************************************************************************* + ETL_CONSTEXPR14 + bool flush() + { + // Encode any remaining input data. + bool success = decode_block(); + + reset_input_buffer(); + + if (success) + { + if (callback.is_valid()) + { + // Send any remaining data. + if (size() != 0) + { + callback(span()); + } + + // Indicate this was the final block. + callback(span_type()); + + reset_output_buffer(); + } + } + + padding_received = false; + + return success; + } + + //************************************************************************* + /// Reset the encoder. + //************************************************************************* + ETL_CONSTEXPR14 + void restart() + { + reset_input_buffer(); + reset_output_buffer(); + overflow_detected = false; + invalid_data_detected = false; + padding_received = false; + } + + //************************************************************************* + /// Returns the beginning of the output buffer. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + const unsigned char* begin() const + { + return p_output_buffer; + } + + //************************************************************************* + /// This only returns a useful value if a callback has not been set or called. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + const unsigned char* end() const + { + return p_output_buffer + output_buffer_length; + } + + //************************************************************************* + /// Returns the beginning of the output buffer. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + const unsigned char* cbegin() const + { + return p_output_buffer; + } + + //************************************************************************* + /// This only returns a useful value if a callback has not been set or called. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + const unsigned char* cend() const + { + return p_output_buffer + output_buffer_length; + } + + //************************************************************************* + /// Returns the size of the output buffer. + /// This only returns a useful value if a callback has not been set or called. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + size_t size() const + { + return output_buffer_length; + } + + //************************************************************************* + /// Returns the maximum size of the output buffer. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + size_t buffer_size() const + { + return output_buffer_max_size; + } + + //************************************************************************* + /// Get a span of the output data. + /// This only returns a useful span if a callback has not been set or called. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + span_type span() const + { + return span_type(begin(), end()); + } + + //************************************************************************* + /// Returns true if the output buffer has overflowed + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + bool overflow() const + { + return overflow_detected; + } + + //************************************************************************* + /// Returns true if an invalid character was detected. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + bool invalid_data() const + { + return invalid_data_detected; + } + + //************************************************************************* + /// Returns true if an error was detected. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + bool error() const + { + return overflow() || invalid_data(); + } + + protected: + + //************************************************************************* + /// Constructor + //************************************************************************* + ETL_CONSTEXPR14 + ibase64_decoder(const char* encoder_table_, + bool use_padding_, + unsigned char* p_output_buffer_, + size_t ouput_buffer_max_size_, + callback_type callback_) + : base64(encoder_table_, use_padding_) + , input_buffer() + , input_buffer_length(0) + , p_output_buffer(p_output_buffer_) + , output_buffer_length(0) + , output_buffer_max_size(ouput_buffer_max_size_) + , callback(callback_) + , overflow_detected(false) + , invalid_data_detected(false) + , padding_received(false) + { + } + + //************************************************************************* + /// Calculates the minimum buffer size required to decode from Base64 + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t decoded_size_from_valid_input_length(size_t input_length) + { + return input_length - (input_length / 4U); + } + + private: + + //************************************************************************* + // Translates a sextet into an index + //************************************************************************* + template + ETL_CONSTEXPR14 + uint32_t get_index_from_sextet(T sextet) + { + const char* encoder_table_end = encoder_table + 64; + const char* p_sextet = etl::find(encoder_table, encoder_table_end, static_cast(sextet)); + + if (p_sextet != encoder_table_end) + { + return static_cast(etl::distance(encoder_table, p_sextet)); + } + else + { + invalid_data_detected = true; + return 0; + } + } + + //************************************************************************* + /// Gets the padding character + //************************************************************************* + template + ETL_NODISCARD + static + ETL_CONSTEXPR14 + T padding() + { + return static_cast('='); + } + + //************************************************************************* + /// Decode one block of data. + //************************************************************************* + ETL_CONSTEXPR14 + bool decode_block() + { + switch (input_buffer_length) + { + // Only triggered on call to flush(). + case 2: + { + uint32_t sextets = (get_index_from_sextet(input_buffer[0]) << 6); + sextets = sextets | (get_index_from_sextet(input_buffer[1])); + push_to_output_buffer((sextets >> 4) & 0xFF); + break; + } + + // Only triggered on call to flush(). + case 3: + { + uint32_t sextets = (get_index_from_sextet(input_buffer[0]) << 12); + sextets = sextets | (get_index_from_sextet(input_buffer[1]) << 6); + sextets = sextets | (get_index_from_sextet(input_buffer[2])); + push_to_output_buffer((sextets >> 10) & 0xFF); + push_to_output_buffer((sextets >> 2) & 0xFF); + break; + } + + // Only triggered on call to decode(). + case 4: + { + // Read in four sextets + uint32_t sextets = (get_index_from_sextet(input_buffer[0]) << 18); + sextets = sextets | (get_index_from_sextet(input_buffer[1]) << 12); + sextets = sextets | (get_index_from_sextet(input_buffer[2]) << 6); + sextets = sextets | (get_index_from_sextet(input_buffer[3])); + + // Write out three octets + push_to_output_buffer((sextets >> 16) & 0xFF); + push_to_output_buffer((sextets >> 8) & 0xFF); + push_to_output_buffer((sextets >> 0) & 0xFF); + break; + } + + default: + { + break; + } + } + + ETL_ASSERT(!invalid_data_detected, ETL_ERROR(etl::base64_invalid_data)); + ETL_ASSERT(!overflow_detected, ETL_ERROR(etl::base64_overflow)); + + return (!invalid_data_detected && !overflow_detected); + } + + //************************************************************************* + // Push to the output buffer. + //************************************************************************* + ETL_CONSTEXPR14 + void push_to_output_buffer(unsigned char c) + { + if (output_buffer_length < output_buffer_max_size) + { + p_output_buffer[output_buffer_length++] = c; + } + else + { + overflow_detected = true; + } + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + bool output_buffer_is_full() const + { + return output_buffer_length == output_buffer_max_size; + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + bool output_buffer_is_empty() const + { + return output_buffer_length == 0; + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + void reset_output_buffer() + { + output_buffer_length = 0; + } + + //************************************************************************* + // Push to the input buffer. + //************************************************************************* + template + ETL_CONSTEXPR14 + void push_to_input_buffer(T value) + { + if (value == padding()) + { + padding_received = true; + } + else + { + if (padding_received) + { + ETL_ASSERT_FAIL(ETL_ERROR(etl::base64_invalid_data)); + invalid_data_detected = true; + } + else + { + input_buffer[input_buffer_length++] = static_cast(value); + } + } + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + bool input_buffer_is_full() const + { + return input_buffer_length == 4U; + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + void reset_input_buffer() + { + input_buffer_length = 0; + } + + char input_buffer[4]; + size_t input_buffer_length; + + unsigned char* p_output_buffer; + size_t output_buffer_length; + const size_t output_buffer_max_size; + + callback_type callback; + + bool overflow_detected; + bool invalid_data_detected; + bool padding_received; + }; + + //************************************************************************* + /// Base64 RFC-2152 Decoder + //************************************************************************* + template + class base64_rfc2152_decoder : public ibase64_decoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Decode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Decode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-2152 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc2152_decoder() + : ibase64_decoder(etl::base64::character_set_1(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-2152 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc2152_decoder(callback_type callback_) + : ibase64_decoder(etl::base64::character_set_1(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_decoder::decoded_size_from_valid_input_length(input_length); + } + + private: + + /// The internal output buffer. + unsigned char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-3501 Decoder + //************************************************************************* + template + class base64_rfc3501_decoder : public ibase64_decoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Decode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Decode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-3501 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc3501_decoder() + : ibase64_decoder(etl::base64::character_set_3(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-3501 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc3501_decoder(callback_type callback_) + : ibase64_decoder(etl::base64::character_set_3(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_decoder::decoded_size_from_valid_input_length(input_length); + } + + private: + + /// The internal output buffer. + unsigned char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-4648 Decoder + //************************************************************************* + template + class base64_rfc4648_decoder : public ibase64_decoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Decode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Decode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-4648 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_decoder() + : ibase64_decoder(etl::base64::character_set_1(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-4648 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_decoder(callback_type callback_) + : ibase64_decoder(etl::base64::character_set_1(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_decoder::decoded_size_from_valid_input_length(input_length); + } + + private: + + /// The internal output buffer. + unsigned char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-4648-Padding Decoder + //************************************************************************* + template + class base64_rfc4648_padding_decoder : public ibase64_decoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Decode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Decode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-4648-Padding constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_padding_decoder() + : ibase64_decoder(etl::base64::character_set_1(), + etl::base64::Padding::Use_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-4648-Padding constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_padding_decoder(callback_type callback_) + : ibase64_decoder(etl::base64::character_set_1(), + etl::base64::Padding::Use_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_decoder::decoded_size_from_valid_input_length(input_length); + } + + private: + + /// The internal output buffer. + unsigned char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-4648-URL Decoder + //************************************************************************* + template + class base64_rfc4648_url_decoder : public ibase64_decoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Decode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Decode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-4648-Padding constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_url_decoder() + : ibase64_decoder(etl::base64::character_set_2(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-4648-Padding constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_url_decoder(callback_type callback_) + : ibase64_decoder(etl::base64::character_set_2(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_decoder::decoded_size_from_valid_input_length(input_length); + } + + private: + + /// The internal output buffer. + unsigned char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-4648-URL-Padding Decoder + //************************************************************************* + template + class base64_rfc4648_url_padding_decoder : public ibase64_decoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Decode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Decode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-4648-Padding constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_url_padding_decoder() + : ibase64_decoder(etl::base64::character_set_2(), + etl::base64::Padding::Use_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-4648-Padding constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_url_padding_decoder(callback_type callback_) + : ibase64_decoder(etl::base64::character_set_2(), + etl::base64::Padding::Use_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_decoder::decoded_size_from_valid_input_length(input_length); + } + + private: + + /// The internal output buffer. + unsigned char output_buffer[Buffer_Size]; + }; +} + +#undef ETL_IS_TYPE_8_BIT_INTEGRAL +#undef ETL_IS_ITERATOR_TYPE_8_BIT_INTEGRAL + +#endif diff --git a/etl/base64_encoder.h b/etl/base64_encoder.h new file mode 100644 index 0000000..cf4735e --- /dev/null +++ b/etl/base64_encoder.h @@ -0,0 +1,843 @@ +//************************************************************************* +///Decode from Base64 from and to pointer/length +//*************************************************************************///\file + +/****************************************************************************** +The MIT License(MIT) +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com +Copyright(c) 2024 John Wellbelove +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_BASE64_ENCODER_INCLUDED +#define ETL_BASE64_ENCODER_INCLUDED + +#include "platform.h" +#include "static_assert.h" +#include "error_handler.h" +#include "type_traits.h" +#include "binary.h" +#include "algorithm.h" +#include "integral_limits.h" +#include "iterator.h" +#include "enum_type.h" +#include "delegate.h" +#include "span.h" + +#include "base64.h" + +#include + +#if ETL_USING_STL + #include +#endif + +#define ETL_IS_8_BIT_INTEGRAL(Type) (etl::is_integral::type>::value && \ + (etl::integral_limits::type>::bits == 8U)) + +#define ETL_IS_ITERATOR_TYPE_8_BIT_INTEGRAL(Type) (etl::is_integral::type>::value_type>::value && \ + (etl::integral_limits::type>::value_type>::bits == 8U)) + +namespace etl +{ + //************************************************************************* + /// Base64 Encoder + //************************************************************************* + class ibase64_encoder : public base64 + { + public: + + typedef etl::span span_type; + typedef etl::delegate callback_type; + + //************************************************************************* + /// Encode to Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool encode(T value) + { + ETL_STATIC_ASSERT(ETL_IS_8_BIT_INTEGRAL(T), "Input type must be an 8 bit integral"); + + push_to_input_buffer(value); + + if (input_buffer_is_full()) + { + encode_block(); + reset_input_buffer(); + + if (callback.is_valid()) + { + if (output_buffer_is_full()) + { + callback(span()); + reset_output_buffer(); + } + } + } + + return !error(); + } + + //************************************************************************* + /// Encode to Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool encode(TInputIterator input_begin, size_t input_length) + { + ETL_STATIC_ASSERT(ETL_IS_ITERATOR_TYPE_8_BIT_INTEGRAL(TInputIterator), "Input type must be an 8 bit integral"); + + while (input_length-- != 0) + { + if (!encode(*input_begin++)) + { + return false; + } + } + + return true; + } + + //************************************************************************* + /// Encode to Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool encode(TInputIterator input_begin, TInputIterator input_end) + { + ETL_STATIC_ASSERT(ETL_IS_ITERATOR_TYPE_8_BIT_INTEGRAL(TInputIterator), "Input type must be an 8 bit integral"); + + while (input_begin != input_end) + { + if (!encode(*input_begin++)) + { + return false; + } + } + + return true; + } + + //************************************************************************* + /// Encode to Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool encode_final(TInputIterator input_begin, size_t input_length) + { + return encode(input_begin, input_length) && flush(); + } + + //************************************************************************* + /// Encode to Base64 + //************************************************************************* + template + ETL_CONSTEXPR14 + bool encode_final(TInputIterator input_begin, TInputIterator input_end) + { + return encode(input_begin, input_end) && flush(); + } + + //************************************************************************* + /// Flush any remaining data to the output. + //************************************************************************* + ETL_CONSTEXPR14 + bool flush() + { + // Encode any remaining input data. + bool success = encode_block(); + + reset_input_buffer(); + + if (success) + { + if (callback.is_valid()) + { + // Send any remaining data. + if (size() != 0) + { + callback(span()); + } + + // Indicate this was the final block. + callback(span_type()); + + reset_output_buffer(); + } + } + + return success; + } + + //************************************************************************* + /// Reset the encoder. + //************************************************************************* + ETL_CONSTEXPR14 + void restart() + { + reset_input_buffer(); + reset_output_buffer(); + } + + //************************************************************************* + /// Returns the beginning of the output buffer. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + const char* begin() const + { + return p_output_buffer; + } + + //************************************************************************* + /// This only returns a useful value if a callback has not been set or called. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + const char* end() const + { + return p_output_buffer + output_buffer_length; + } + + //************************************************************************* + /// Returns the beginning of the output buffer. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + const char* cbegin() const + { + return p_output_buffer; + } + + //************************************************************************* + /// This only returns a useful value if a callback has not been set or called. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + const char* cend() const + { + return p_output_buffer + output_buffer_length; + } + + //************************************************************************* + /// Returns the size of the output buffer. + /// This only returns a useful value if a callback has not been set or called. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + size_t size() const + { + return output_buffer_length; + } + + //************************************************************************* + /// Returns the maximum size of the output buffer. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + size_t max_size() const + { + return output_buffer_max_size; + } + + //************************************************************************* + /// Get a span of the output data. + /// This only returns a useful span if a callback has not been set or called. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + span_type span() const + { + return span_type(begin(), end()); + } + + //************************************************************************* + /// Returns true if the output buffer has overflowed + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + bool overflow() const + { + return overflowed; + } + + //************************************************************************* + /// Returns true if an error was detected. + //************************************************************************* + ETL_NODISCARD + ETL_CONSTEXPR14 + bool error() const + { + return overflow(); + } + + protected: + + //************************************************************************* + /// Constructor + //************************************************************************* + ETL_CONSTEXPR14 + ibase64_encoder(const char* encoder_table_, + bool use_padding_, + char* p_output_buffer_, + size_t ouput_buffer_max_size_, + callback_type callback_) + : base64(encoder_table_, use_padding_) + , input_buffer() + , input_buffer_length(0) + , p_output_buffer(p_output_buffer_) + , output_buffer_length(0) + , output_buffer_max_size(ouput_buffer_max_size_) + , callback(callback_) + , overflowed(false) + { + } + + //************************************************************************* + /// Encode one block of data. + //************************************************************************* + ETL_CONSTEXPR14 + bool encode_block() + { + switch (input_buffer_length) + { + // Only triggered on call to flush(). + case 1: + { + uint32_t octets = input_buffer[0]; + octets = octets << 4; // Adjust one octet (8 bits) for two sextets worth of data (12 bits) + + // Write out two sextets + optional padding. + push_to_output_buffer(encoder_table[(octets >> 6) & 0x3F]); + push_to_output_buffer(encoder_table[(octets >> 0) & 0x3F]); + + if (use_padding) + { + push_to_output_buffer('='); + push_to_output_buffer('='); + } + break; + } + + // Only triggered on call to flush(). + case 2: + { + uint32_t octets = (input_buffer[0] << 8) | input_buffer[1]; + octets <<= 2; // Adjust two octets (16 bits) for three sextets worth of data (18 bits) + + // Write out three sextets + optional padding. + push_to_output_buffer(encoder_table[(octets >> 12) & 0x3F]); + push_to_output_buffer(encoder_table[(octets >> 6) & 0x3F]); + push_to_output_buffer(encoder_table[(octets >> 0) & 0x3F]); + + if (use_padding) + { + push_to_output_buffer('='); + } + break; + } + + // Only triggered on call to encode(). + case 3: + { + uint32_t octets = (input_buffer[0] << 16) | (input_buffer[1] << 8) | input_buffer[2]; + + // Write out four sextets + push_to_output_buffer(encoder_table[(octets >> 18) & 0x3F]); + push_to_output_buffer(encoder_table[(octets >> 12) & 0x3F]); + push_to_output_buffer(encoder_table[(octets >> 6) & 0x3F]); + push_to_output_buffer(encoder_table[(octets >> 0) & 0x3F]); + break; + } + + default: + { + break; + } + } + + ETL_ASSERT(!overflowed, ETL_ERROR(etl::base64_overflow)); + + return !overflowed; + } + + //************************************************************************* + /// Calculates the minimum buffer size required to encode to Base64 + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t encoded_size(size_t input_length, bool use_padding) + { + size_t required_output_length = 0; + + if (input_length == 0U) + { + return 0U; + } + + if (use_padding) + { + required_output_length = (input_length * 4U) / 3U; + + while ((required_output_length % 4U) != 0) + { + ++required_output_length; + } + } + else + { + required_output_length = input_length + (((input_length - 1U) / 3U) + 1U); + } + + while (required_output_length % 4) + { + ++required_output_length; + } + + return required_output_length; + } + + private: + + //************************************************************************* + // Push to the output buffer. + //************************************************************************* + ETL_CONSTEXPR14 + void push_to_output_buffer(char c) + { + if (output_buffer_length < output_buffer_max_size) + { + p_output_buffer[output_buffer_length++] = c; + } + else + { + overflowed = true; + } + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + bool output_buffer_is_full() const + { + return output_buffer_length == output_buffer_max_size; + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + bool output_buffer_is_empty() const + { + return output_buffer_length == 0; + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + void reset_output_buffer() + { + output_buffer_length = 0; + } + + //************************************************************************* + // Push to the input buffer. + //************************************************************************* + template + ETL_CONSTEXPR14 + void push_to_input_buffer(T value) + { + input_buffer[input_buffer_length++] = static_cast(value); + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + bool input_buffer_is_full() const + { + return input_buffer_length == 3U; + } + + //************************************************************************* + // + //************************************************************************* + ETL_CONSTEXPR14 + void reset_input_buffer() + { + input_buffer_length = 0; + } + + uint8_t input_buffer[3]; + size_t input_buffer_length; + + char* p_output_buffer; + size_t output_buffer_length; + const size_t output_buffer_max_size; + + callback_type callback; + + bool overflowed; + }; + + //************************************************************************* + /// Base64 RFC-2152 Encoder + //************************************************************************* + template + class base64_rfc2152_encoder : public ibase64_encoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Encode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Encode_Buffer_Size"); + ETL_STATIC_ASSERT(((Buffer_Size % etl::base64::Min_Encode_Buffer_Size) == 0), "Buffer size must be a multiple of etl::base64::Min_Encode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-2152 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc2152_encoder() + : ibase64_encoder(etl::base64::character_set_1(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-2152 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc2152_encoder(callback_type callback_) + : ibase64_encoder(etl::base64::character_set_1(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_encoder::encoded_size(input_length, etl::base64::Padding::No_Padding); + } + + private: + + /// The internal output buffer. + char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-3501 Encoder + //************************************************************************* + template + class base64_rfc3501_encoder : public ibase64_encoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Encode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Encode_Buffer_Size"); + ETL_STATIC_ASSERT(((Buffer_Size% etl::base64::Min_Encode_Buffer_Size) == 0), "Buffer size must be a multiple of etl::base64::Min_Encode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-3501 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc3501_encoder() + : ibase64_encoder(etl::base64::character_set_3(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-3501 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc3501_encoder(callback_type callback_) + : ibase64_encoder(etl::base64::character_set_3(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_encoder::encoded_size(input_length, etl::base64::Padding::No_Padding); + } + + private: + + /// The internal output buffer. + char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-4648 Encoder + //************************************************************************* + template + class base64_rfc4648_encoder : public ibase64_encoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Encode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Encode_Buffer_Size"); + ETL_STATIC_ASSERT(((Buffer_Size % etl::base64::Min_Encode_Buffer_Size) == 0), "Buffer size must be a multiple of etl::base64::Min_Encode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-4648 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_encoder() + : ibase64_encoder(etl::base64::character_set_1(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-4648 constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_encoder(callback_type callback_) + : ibase64_encoder(etl::base64::character_set_1(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_encoder::encoded_size(input_length, etl::base64::Padding::No_Padding); + } + + private: + + /// The internal output buffer. + char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-4648-Padding Encoder + //************************************************************************* + template + class base64_rfc4648_padding_encoder : public ibase64_encoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Encode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Encode_Buffer_Size"); + ETL_STATIC_ASSERT(((Buffer_Size% etl::base64::Min_Encode_Buffer_Size) == 0), "Buffer size must be a multiple of etl::base64::Min_Encode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-4648-Padding constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_padding_encoder() + : ibase64_encoder(etl::base64::character_set_1(), + etl::base64::Padding::Use_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-4648-Padding constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_padding_encoder(callback_type callback_) + : ibase64_encoder(etl::base64::character_set_1(), + etl::base64::Padding::Use_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_encoder::encoded_size(input_length, etl::base64::Padding::Use_Padding); + } + + private: + + /// The internal output buffer. + char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-4648-URL Encoder + //************************************************************************* + template + class base64_rfc4648_url_encoder : public ibase64_encoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Encode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Encode_Buffer_Size"); + ETL_STATIC_ASSERT(((Buffer_Size % etl::base64::Min_Encode_Buffer_Size) == 0), "Buffer size must be a multiple of etl::base64::Min_Encode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-4648-URL constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_url_encoder() + : ibase64_encoder(etl::base64::character_set_2(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-4648-URL constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_url_encoder(callback_type callback_) + : ibase64_encoder(etl::base64::character_set_2(), + etl::base64::Padding::No_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_encoder::encoded_size(input_length, etl::base64::Padding::No_Padding); + } + + private: + + /// The internal output buffer. + char output_buffer[Buffer_Size]; + }; + + //************************************************************************* + /// Base64 RFC-4648-URL_Padding Encoder + //************************************************************************* + template + class base64_rfc4648_url_padding_encoder : public ibase64_encoder + { + public: + + ETL_STATIC_ASSERT((Buffer_Size >= etl::base64::Min_Encode_Buffer_Size), "Buffer size must be greater than etl::base64::Min_Encode_Buffer_Size"); + ETL_STATIC_ASSERT(((Buffer_Size% etl::base64::Min_Encode_Buffer_Size) == 0), "Buffer size must be a multiple of etl::base64::Min_Encode_Buffer_Size"); + + //************************************************************************* + /// Base64 RFC-4648-URL constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_url_padding_encoder() + : ibase64_encoder(etl::base64::character_set_2(), + etl::base64::Padding::Use_Padding, + output_buffer, + Buffer_Size, + callback_type()) + , output_buffer() + { + } + + //************************************************************************* + /// Base64 RFC-4648-URL constructor. + //************************************************************************* + ETL_CONSTEXPR14 + base64_rfc4648_url_padding_encoder(callback_type callback_) + : ibase64_encoder(etl::base64::character_set_2(), + etl::base64::Padding::Use_Padding, + output_buffer, + Buffer_Size, + callback_) + , output_buffer() + { + } + + //************************************************************************* + /// Calculate the required output encode buffer size. + //************************************************************************* + ETL_NODISCARD + static + ETL_CONSTEXPR14 + size_t safe_output_buffer_size(size_t input_length) + { + return ibase64_encoder::encoded_size(input_length, etl::base64::Padding::Use_Padding); + } + + private: + + /// The internal output buffer. + char output_buffer[Buffer_Size]; + }; +} + +#undef ETL_IS_TYPE_8_BIT_INTEGRAL +#undef ETL_IS_ITERATOR_TYPE_8_BIT_INTEGRAL + +#endif diff --git a/etl/basic_format_spec.h b/etl/basic_format_spec.h new file mode 100644 index 0000000..36c2d74 --- /dev/null +++ b/etl/basic_format_spec.h @@ -0,0 +1,496 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2019 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_BASIC_FORMAT_SPEC_INCLUDED +#define ETL_BASIC_FORMAT_SPEC_INCLUDED + +///\ingroup string + +#include "platform.h" +#include "type_traits.h" +#include "static_assert.h" + +namespace etl +{ + namespace private_basic_format_spec + { + //******************************************************* + // Structures returned by stream formatting manipulators. + //******************************************************* + struct base_spec + { + ETL_CONSTEXPR base_spec(uint_least8_t base_) + : base(base_) + { + } + + const uint_least8_t base; + }; + + //********************************* + struct width_spec + { + ETL_CONSTEXPR width_spec(uint_least8_t width_) + : width(width_) + { + } + + const uint_least8_t width; + }; + + //********************************* + template + struct fill_spec + { + ETL_CONSTEXPR fill_spec(TChar fill_) + : fill(fill_) + { + } + + const TChar fill; + }; + + //********************************* + struct precision_spec + { + ETL_CONSTEXPR precision_spec(uint_least8_t precision_) + : precision(precision_) + { + } + + const uint_least8_t precision; + }; + + //********************************* + struct uppercase_spec + { + ETL_CONSTEXPR uppercase_spec(bool upper_case_) + : upper_case(upper_case_) + { + } + + const bool upper_case; + }; + + //********************************* + struct boolalpha_spec + { + ETL_CONSTEXPR boolalpha_spec(bool boolalpha_) + : boolalpha(boolalpha_) + { + } + + const bool boolalpha; + }; + + //********************************* + struct showbase_spec + { + ETL_CONSTEXPR showbase_spec(bool show_base_) + : show_base(show_base_) + { + } + + const bool show_base; + }; + + //********************************* + struct left_spec + { + }; + + //********************************* + struct right_spec + { + }; + } + + //*************************************************************************** + // Stream formatting manipulators. + //*************************************************************************** + static ETL_CONSTEXPR private_basic_format_spec::base_spec setbase(uint32_t base) + { + return private_basic_format_spec::base_spec(base); + } + + //********************************* + static ETL_CONSTEXPR private_basic_format_spec::width_spec setw(uint32_t width) + { + return private_basic_format_spec::width_spec(width); + } + + //********************************* + template + static ETL_CONSTEXPR private_basic_format_spec::fill_spec setfill(TChar fill) + { + return private_basic_format_spec::fill_spec(fill); + } + + //********************************* + static ETL_CONSTEXPR private_basic_format_spec::precision_spec setprecision(uint32_t precision) + { + return private_basic_format_spec::precision_spec(precision); + } + + //********************************* + static ETL_CONSTANT private_basic_format_spec::base_spec bin(2U); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::base_spec oct(8U); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::base_spec dec(10U); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::base_spec hex(16U); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::left_spec left = private_basic_format_spec::left_spec(); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::right_spec right = private_basic_format_spec::right_spec(); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::boolalpha_spec boolalpha(true); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::boolalpha_spec noboolalpha(false); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::uppercase_spec uppercase(true); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::uppercase_spec nouppercase(false); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::showbase_spec showbase(true); + + //********************************* + static ETL_CONSTANT private_basic_format_spec::showbase_spec noshowbase(false); + + //*************************************************************************** + /// basic_format_spec + //*************************************************************************** + template + class basic_format_spec + { + public: + + //*************************************************************************** + /// Default constructor. + //*************************************************************************** + ETL_CONSTEXPR basic_format_spec() + : base_(10U) + , width_(0U) + , precision_(0U) + , upper_case_(false) + , left_justified_(false) + , boolalpha_(false) + , show_base_(false) + , fill_(typename TString::value_type(' ')) + { + } + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + ETL_CONSTEXPR basic_format_spec(uint_least8_t base__, + uint_least8_t width__, + uint_least8_t precision__, + bool upper_case__, + bool left_justified__, + bool boolalpha__, + bool show_base__, + typename TString::value_type fill__) + : base_(base__) + , width_(width__) + , precision_(precision__) + , upper_case_(upper_case__) + , left_justified_(left_justified__) + , boolalpha_(boolalpha__) + , show_base_(show_base__) + , fill_(fill__) + { + } + + //*************************************************************************** + /// Clears the format spec back to default. + //*************************************************************************** + ETL_CONSTEXPR14 void clear() + { + base_ = 10U; + width_ = 0U; + precision_ = 0U; + upper_case_ = false; + left_justified_ = false; + boolalpha_ = false; + show_base_ = false; + fill_ = typename TString::value_type(' '); + } + + //*************************************************************************** + /// Sets the base. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& base(uint32_t b) + { + base_ = static_cast(b); + return *this; + } + + //*************************************************************************** + /// Sets the base to binary. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& binary() + { + base(2); + return *this; + } + + //*************************************************************************** + /// Sets the base to octal. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& octal() + { + base(8); + return *this; + } + + //*************************************************************************** + /// Sets the base to decimal. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& decimal() + { + base(10); + return *this; + } + + //*************************************************************************** + /// Sets the base to hex. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& hex() + { + base(16); + return *this; + } + + //*************************************************************************** + /// Gets the base. + //*************************************************************************** + ETL_CONSTEXPR uint32_t get_base() const + { + return base_; + } + + //*************************************************************************** + /// Sets the show base flag. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& show_base(bool b) + { + show_base_ = b; + return *this; + } + + //*************************************************************************** + /// Gets the show base flag. + //*************************************************************************** + ETL_CONSTEXPR bool is_show_base() const + { + return show_base_; + } + + //*************************************************************************** + /// Sets the width. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& width(uint32_t w) + { + width_ = static_cast(w); + return *this; + } + + //*************************************************************************** + /// Gets the width. + //*************************************************************************** + ETL_CONSTEXPR uint32_t get_width() const + { + return width_; + } + + //*************************************************************************** + /// Sets the precision. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& precision(uint32_t p) + { + precision_ = static_cast(p); + return *this; + } + + //*************************************************************************** + /// Gets the precision. + //*************************************************************************** + ETL_CONSTEXPR uint32_t get_precision() const + { + return precision_; + } + + //*************************************************************************** + /// Sets the upper case flag. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& upper_case(bool u) + { + upper_case_ = u; + return *this; + } + + //*************************************************************************** + /// Gets the upper case flag. + //*************************************************************************** + ETL_CONSTEXPR bool is_upper_case() const + { + return upper_case_; + } + + //*************************************************************************** + /// Sets the fill character. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& fill(typename TString::value_type c) + { + fill_ = c; + return *this; + } + + //*************************************************************************** + /// Gets the fill character. + //*************************************************************************** + ETL_CONSTEXPR typename TString::value_type get_fill() const + { + return fill_; + } + + //*************************************************************************** + /// Sets the left justify flag. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& left() + { + left_justified_ = true; + return *this; + } + + //*************************************************************************** + /// Gets the left justify flag. + //*************************************************************************** + ETL_CONSTEXPR bool is_left() const + { + return left_justified_; + } + + //*************************************************************************** + /// Sets the right justify flag. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& right() + { + left_justified_ = false; + return *this; + } + + //*************************************************************************** + /// Gets the right justify flag. + //*************************************************************************** + ETL_CONSTEXPR bool is_right() const + { + return !left_justified_; + } + + //*************************************************************************** + /// Sets the bool alpha flag. + /// \return A reference to the basic_format_spec. + //*************************************************************************** + ETL_CONSTEXPR14 basic_format_spec& boolalpha(bool b) + { + boolalpha_ = b; + return *this; + } + + //*************************************************************************** + /// Gets the boolalpha flag. + //*************************************************************************** + ETL_CONSTEXPR bool is_boolalpha() const + { + return boolalpha_; + } + + //*************************************************************************** + /// Equality operator. + //*************************************************************************** + ETL_CONSTEXPR friend bool operator ==(const basic_format_spec& lhs, const basic_format_spec& rhs) + { + return (lhs.base_ == rhs.base_) && + (lhs.width_ == rhs.width_) && + (lhs.precision_ == rhs.precision_) && + (lhs.upper_case_ == rhs.upper_case_) && + (lhs.left_justified_ == rhs.left_justified_) && + (lhs.boolalpha_ == rhs.boolalpha_) && + (lhs.show_base_ == rhs.show_base_) && + (lhs.fill_ == rhs.fill_); + } + + //*************************************************************************** + /// Inequality operator. + //*************************************************************************** + ETL_CONSTEXPR friend bool operator !=(const basic_format_spec& lhs, const basic_format_spec& rhs) + { + return !(lhs == rhs); + } + + private: + + uint_least8_t base_; + uint_least8_t width_; + uint_least8_t precision_; + bool upper_case_; + bool left_justified_; + bool boolalpha_; + bool show_base_; + typename TString::value_type fill_; + }; +} + +#endif diff --git a/etl/basic_string.h b/etl/basic_string.h new file mode 100644 index 0000000..1371e80 --- /dev/null +++ b/etl/basic_string.h @@ -0,0 +1,2652 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2016 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_BASIC_STRING_INCLUDED +#define ETL_BASIC_STRING_INCLUDED + +#include "platform.h" +#include "algorithm.h" +#include "iterator.h" +#include "functional.h" +#include "char_traits.h" +#include "alignment.h" +#include "array.h" +#include "algorithm.h" +#include "type_traits.h" +#include "error_handler.h" +#include "integral_limits.h" +#include "exception.h" +#include "memory.h" +#include "exception.h" +#include "binary.h" +#include "flags.h" + +#include +#include +#include + +#include "private/minmax_push.h" + +//***************************************************************************** +///\defgroup basic_string basic_string +/// A basic_string with the capacity defined at compile time. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + ///\ingroup string + /// Exception base for strings + //*************************************************************************** + class string_exception : public etl::exception + { + public: + + string_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup string + /// String empty exception. + //*************************************************************************** + class string_empty : public etl::string_exception + { + public: + + string_empty(string_type file_name_, numeric_type line_number_) + : string_exception(ETL_ERROR_TEXT("string:empty", ETL_BASIC_STRING_FILE_ID"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup string + /// String out of bounds exception. + //*************************************************************************** + class string_out_of_bounds : public etl::string_exception + { + public: + + string_out_of_bounds(string_type file_name_, numeric_type line_number_) + : string_exception(ETL_ERROR_TEXT("string:bounds", ETL_BASIC_STRING_FILE_ID"B"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup string + /// String iterator exception. + //*************************************************************************** + class string_iterator : public etl::string_exception + { + public: + + string_iterator(string_type file_name_, numeric_type line_number_) + : string_exception(ETL_ERROR_TEXT("string:iterator", ETL_BASIC_STRING_FILE_ID"C"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup string + /// String truncation exception. + //*************************************************************************** + class string_truncation : public etl::string_exception + { + public: + + string_truncation(string_type file_name_, numeric_type line_number_) + : string_exception(ETL_ERROR_TEXT("string:iterator", ETL_BASIC_STRING_FILE_ID"D"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup string + /// The base class for all templated string types. + //*************************************************************************** + namespace private_basic_string + { + //************************************************************************* + template + class string_base_statics + { + public: + + typedef size_t size_type; + + static ETL_CONSTANT uint_least8_t IS_TRUNCATED = etl::bit<0>::value; + static ETL_CONSTANT uint_least8_t CLEAR_AFTER_USE = etl::bit<1>::value; + + static ETL_CONSTANT size_type npos = etl::integral_limits::max; + }; + + template + ETL_CONSTANT uint_least8_t string_base_statics::IS_TRUNCATED; + + template + ETL_CONSTANT uint_least8_t string_base_statics::CLEAR_AFTER_USE; + + template + ETL_CONSTANT typename string_base_statics::size_type string_base_statics::npos; + } + + //*************************************************************************** + class string_base : public private_basic_string::string_base_statics<> + { + public: + + typedef size_t size_type; + + //************************************************************************* + /// Gets the current size of the string. + ///\return The current size of the string. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Gets the current size of the string. + ///\return The current size of the string. + //************************************************************************* + size_type length() const + { + return current_size; + } + + //************************************************************************* + /// Checks the 'empty' state of the string. + ///\return true if empty. + //************************************************************************* + bool empty() const + { + return (current_size == 0); + } + + //************************************************************************* + /// Checks the 'full' state of the string. + ///\return true if full. + //************************************************************************* + bool full() const + { + return current_size == CAPACITY; + } + + //************************************************************************* + /// Returns the capacity of the string. + ///\return The capacity of the string. + //************************************************************************* + size_type capacity() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the maximum possible size of the string. + ///\return The maximum size of the string. + //************************************************************************* + size_type max_size() const + { + return CAPACITY; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_type available() const + { + return max_size() - size(); + } + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + //************************************************************************* + /// Returns whether the string was truncated by the last operation. + /// Deprecated. Use is_truncated() + ///\return Whether the string was truncated by the last operation. + //************************************************************************* + ETL_DEPRECATED + bool truncated() const + { + return flags.test(); + } + + //************************************************************************* + /// Returns whether the string was truncated by the last operation. + ///\return Whether the string was truncated by the last operation. + //************************************************************************* + bool is_truncated() const + { + return flags.test(); + } + + //************************************************************************* + /// Clears the 'truncated' flag. + //************************************************************************* + void clear_truncated() + { + flags.set(); + } +#endif + +#if ETL_HAS_STRING_CLEAR_AFTER_USE + //************************************************************************* + /// Sets the 'secure' flag to the requested state. + //************************************************************************* + void set_secure() + { + flags.set(); + } + + //************************************************************************* + /// Gets the 'secure' state flag. + //************************************************************************* + bool is_secure() const + { + return flags.test(); + } +#endif + + protected: + + //************************************************************************* + /// Constructor. + //************************************************************************* + string_base(size_type max_size_) + : current_size(0) + , CAPACITY(max_size_) + { + } + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + //************************************************************************* + /// Sets the 'truncated' flag. + //************************************************************************* + void set_truncated(bool status) + { + flags.set(status); + } +#endif + + //************************************************************************* + /// Destructor. + //************************************************************************* + ~string_base() + { + } + + size_type current_size; ///< The current number of elements in the string. + const size_type CAPACITY; ///< The maximum number of elements in the string. + +#if ETL_HAS_STRING_TRUNCATION_CHECKS || ETL_HAS_STRING_CLEAR_AFTER_USE + etl::flags flags; +#endif + }; + + //*************************************************************************** + /// The base class for specifically sized strings. + /// Can be used as a reference type for all strings containing a specific type. + ///\ingroup string + //*************************************************************************** + template + class ibasic_string : public etl::string_base + { + public: + + typedef ibasic_string interface_type; + + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef T* iterator; + typedef const T* const_iterator; + typedef ETL_OR_STD::reverse_iterator reverse_iterator; + typedef ETL_OR_STD::reverse_iterator const_reverse_iterator; + + typedef typename etl::iterator_traits::difference_type difference_type; + + //********************************************************************* + /// Returns an iterator to the beginning of the string. + ///\return An iterator to the beginning of the string. + //********************************************************************* + iterator begin() + { + return &p_buffer[0]; + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the string. + ///\return A const iterator to the beginning of the string. + //********************************************************************* + const_iterator begin() const + { + return &p_buffer[0]; + } + + //********************************************************************* + /// Returns an iterator to the end of the string. + ///\return An iterator to the end of the string. + //********************************************************************* + iterator end() + { + return &p_buffer[current_size]; + } + + //********************************************************************* + /// Returns a const_iterator to the end of the string. + ///\return A const iterator to the end of the string. + //********************************************************************* + const_iterator end() const + { + return &p_buffer[current_size]; + } + + //********************************************************************* + /// Returns a const_iterator to the beginning of the string. + ///\return A const iterator to the beginning of the string. + //********************************************************************* + const_iterator cbegin() const + { + return &p_buffer[0]; + } + + //********************************************************************* + /// Returns a const_iterator to the end of the string. + ///\return A const iterator to the end of the string. + //********************************************************************* + const_iterator cend() const + { + return &p_buffer[current_size]; + } + + //********************************************************************* + /// Returns an reverse iterator to the reverse beginning of the string. + ///\return Iterator to the reverse beginning of the string. + //********************************************************************* + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the string. + ///\return Const iterator to the reverse beginning of the string. + //********************************************************************* + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + //********************************************************************* + /// Returns a reverse iterator to the end + 1 of the string. + ///\return Reverse iterator to the end + 1 of the string. + //********************************************************************* + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the string. + ///\return Const reverse iterator to the end + 1 of the string. + //********************************************************************* + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the reverse beginning of the string. + ///\return Const reverse iterator to the reverse beginning of the string. + //********************************************************************* + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + //********************************************************************* + /// Returns a const reverse iterator to the end + 1 of the string. + ///\return Const reverse iterator to the end + 1 of the string. + //********************************************************************* + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + //********************************************************************* + /// Resizes the string. + /// If asserts or exceptions are enabled and the new size is larger than the + ///\param new_size The new size. + //********************************************************************* + void resize(size_type new_size) + { + resize(new_size, 0); + } + + //********************************************************************* + /// Resizes the string. + ///\param new_size The new size. + ///\param value The value to fill new elements with. Default = default constructed value. + //********************************************************************* + void resize(size_type new_size, T value) + { + if (new_size > CAPACITY) + { +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif +#endif + } + + new_size = etl::min(new_size, CAPACITY); + + // Size up? + if (new_size > current_size) + { + etl::fill(p_buffer + current_size, p_buffer + new_size, value); + } + + current_size = new_size; + p_buffer[new_size] = 0; + cleanup(); + } + + //********************************************************************* + /// Resizes the string, but doesn't initialise the free space + /// except for a terminator null. + ///\param new_size The new size. + //********************************************************************* + void uninitialized_resize(size_type new_size) + { + new_size = etl::min(new_size, CAPACITY); + + current_size = new_size; + p_buffer[new_size] = 0; + } + + //********************************************************************* + /// Fills the string with the specified character. + /// Does not change the string length. + ///\param value The character used to fill the string. + //********************************************************************* + void fill(T value) + { + etl::fill(begin(), end(), value); + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference operator [](size_type i) + { + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference operator [](size_type i) const + { + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::string_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A reference to the value at index 'i' + //********************************************************************* + reference at(size_type i) + { + ETL_ASSERT(i < size(), ETL_ERROR(string_out_of_bounds)); + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a const reference to the value at index 'i' + /// If asserts or exceptions are enabled, emits an etl::string_out_of_bounds if the index is out of range. + ///\param i The index. + ///\return A const reference to the value at index 'i' + //********************************************************************* + const_reference at(size_type i) const + { + ETL_ASSERT(i < size(), ETL_ERROR(string_out_of_bounds)); + return p_buffer[i]; + } + + //********************************************************************* + /// Returns a reference to the first element. + ///\return A reference to the first element. + //********************************************************************* + reference front() + { + return p_buffer[0]; + } + + //********************************************************************* + /// Returns a const reference to the first element. + ///\return A const reference to the first element. + //********************************************************************* + const_reference front() const + { + return p_buffer[0]; + } + + //********************************************************************* + /// Returns a reference to the last element. + ///\return A reference to the last element. + //********************************************************************* + reference back() + { + return p_buffer[current_size - 1]; + } + + //********************************************************************* + /// Returns a const reference to the last element. + ///\return A const reference to the last element. + //********************************************************************* + const_reference back() const + { + return p_buffer[current_size - 1]; + } + + //********************************************************************* + /// Returns a pointer to the beginning of the string data. + ///\return A pointer to the beginning of the string data. + //********************************************************************* + pointer data() + { + return p_buffer; + } + + //********************************************************************* + /// Returns a const pointer to the beginning of the string data. + ///\return A const pointer to the beginning of the string data. + //********************************************************************* + ETL_CONSTEXPR const_pointer data() const + { + return p_buffer; + } + + //********************************************************************* + /// Returns a pointer to the beginning of the string data. + ///\return A pointer to the beginning of the string data. + //********************************************************************* + pointer data_end() + { + return p_buffer + current_size; + } + + //********************************************************************* + /// Returns a const pointer to the beginning of the string data. + ///\return A const pointer to the beginning of the string data. + //********************************************************************* + const_pointer data_end() const + { + return p_buffer + current_size; + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param other The other string. + //********************************************************************* + void assign(const etl::ibasic_string& other) + { + assign(other.begin(), other.end()); + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + if (other.is_truncated()) + { + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif + } +#endif + +#if ETL_HAS_STRING_CLEAR_AFTER_USE + if (other.is_secure()) + { + set_secure(); + } +#endif + + cleanup(); + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param other The other string. + ///\param subposition The position to start from. + ///\param sublength The length to copy. + //********************************************************************* + void assign(const etl::ibasic_string& other, size_type subposition, size_type sublength) + { + if (sublength == npos) + { + sublength = other.size() - subposition; + } + + ETL_ASSERT(subposition <= other.size(), ETL_ERROR(string_out_of_bounds)); + + assign(other.begin() + subposition, sublength); + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + if (other.is_truncated()) + { + this->set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif + } +#endif + +#if ETL_HAS_STRING_CLEAR_AFTER_USE + if (other.is_secure()) + { + set_secure(); + } +#endif + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param other The other string. + //********************************************************************* + void assign(const_pointer other) + { + initialise(); + + while ((*other != 0) && (current_size < CAPACITY)) + { + p_buffer[current_size++] = *other++; + } + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(*other != 0); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT(flags.test() == false, ETL_ERROR(string_truncation)); +#endif +#endif + + p_buffer[current_size] = 0; + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param other The other string. + ///\param length The length to copy. + //********************************************************************* + void assign(const_pointer other, size_type length_) + { + initialise(); + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(length_ > CAPACITY); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT(flags.test() == false, ETL_ERROR(string_truncation)); +#endif +#endif + + length_ = etl::min(length_, CAPACITY); + + etl::copy_n(other, length_, begin()); + + current_size = length_; + p_buffer[current_size] = 0; + } + + //********************************************************************* + /// Assigns values to the string. + /// If asserts or exceptions are enabled, emits string_iterator if the iterators are reversed. + /// Truncates if the string does not have enough free space. + ///\param first The iterator to the first element. + ///\param last The iterator to the last element + 1. + //********************************************************************* + template + void assign(TIterator first, TIterator last) + { +#if ETL_IS_DEBUG_BUILD + difference_type d = etl::distance(first, last); + ETL_ASSERT(d >= 0, ETL_ERROR(string_iterator)); +#endif + + initialise(); + + while ((first != last) && (current_size != CAPACITY)) + { + p_buffer[current_size++] = *first++; + } + + p_buffer[current_size] = 0; + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(first != last); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT(flags.test() == false, ETL_ERROR(string_truncation)); +#endif +#endif + } + + //********************************************************************* + /// Assigns values to the string. + /// Truncates if the string does not have enough free space. + ///\param n The number of elements to add. + ///\param value The value to insert for each element. + //********************************************************************* + void assign(size_type n, T value) + { + initialise(); + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(n > CAPACITY); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT(flags.test() == false, ETL_ERROR(string_truncation)); +#endif +#endif + + n = etl::min(n, CAPACITY); + + etl::fill_n(begin(), n, value); + current_size = n; + p_buffer[current_size] = 0; + } + + //************************************************************************* + /// Clears the string. + //************************************************************************* + void clear() + { + initialise(); + } + + //********************************************************************* + /// Inserts a value at the end of the string. + /// Sets 'truncated' if the string is already full. + ///\param value The value to add. + //********************************************************************* + void push_back(T value) + { + if (current_size != CAPACITY) + { + p_buffer[current_size++] = value; + p_buffer[current_size] = 0; + } + else + { +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif +#endif + } + } + + //************************************************************************* + /// Removes an element from the end of the string. + /// Does nothing if the string is empty. + //************************************************************************* + void pop_back() + { + if (current_size != 0) + { + p_buffer[--current_size] = 0; + } + } + + //********************************************************************* + /// Appends to the string. + ///\param str The string to append. + //********************************************************************* + ibasic_string& append(const ibasic_string& str) + { + insert(end(), str.begin(), str.end()); + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + if (str.is_truncated()) + { + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif + } +#endif + + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param str The string to append. + ///\param subposition The position in str. + ///\param sublength The number of characters. + //********************************************************************* + ibasic_string& append(const ibasic_string& str, size_type subposition, size_type sublength = npos) + { + ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds)); + + insert(size(), str, subposition, sublength); + + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param str The string to append. + //********************************************************************* + ibasic_string& append(const T* str) + { + insert(size(), str); + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param str The string to append. + ///\param n The number of characters. + //********************************************************************* + ibasic_string& append(const T* str, size_type n) + { + insert(size(), str, n); + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param n The number of characters. + ///\param c The character. + //********************************************************************* + ibasic_string& append(size_type n, T c) + { + insert(size(), n, c); + return *this; + } + + //********************************************************************* + /// Appends to the string. + ///\param first The first of the characters to append. + ///\param last The last + 1 character to add. + //********************************************************************* + template + ibasic_string& append(TIterator first, TIterator last) + { + insert(end(), first, last); + return *this; + } + + //********************************************************************* + /// Inserts a value to the string. + ///\param position The position to insert before. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator position, T value) + { + // Quick hack, as iterators are pointers. + iterator insert_position = to_iterator(position); + + if (current_size < CAPACITY) + { + // Not full yet. + if (position != end()) + { + // Insert in the middle. + ++current_size; + etl::copy_backward(insert_position, end() - 1, end()); + *insert_position = value; + } + else + { + // Insert at the end. + *insert_position = value; + ++current_size; + } + } + else + { + // Already full. + if (position != end()) + { + // Insert in the middle. + etl::copy_backward(insert_position, end() - 1, end()); + *insert_position = value; + } + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif +#endif + } + + p_buffer[current_size] = 0; + + return insert_position; + } + + //********************************************************************* + /// Inserts 'n' values to the string. + ///\param position The position to insert before. + ///\param n The number of elements to add. + ///\param value The value to insert. + //********************************************************************* + iterator insert(const_iterator position, size_type n, T value) + { + iterator position_ = to_iterator(position); + + if (n == 0) + { + return position_; + } + + // Quick hack, as iterators are pointers. + iterator insert_position = to_iterator(position); + const size_type start = etl::distance(cbegin(), position); + + // No effect. + if (start >= CAPACITY) + { +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif +#endif + return to_iterator(position);; + } + + // Fills the string to the end? + if ((start + n) >= CAPACITY) + { + if ((current_size + n) > CAPACITY) + { +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif +#endif + } + + current_size = CAPACITY; + etl::fill(insert_position, end(), value); + } + else + { + // Lets do some shifting. + const size_type shift_amount = n; + const size_type to_position = start + shift_amount; + const size_type remaining_characters = current_size - start; + const size_type max_shift_characters = CAPACITY - start - shift_amount; + const size_type characters_to_shift = etl::min(max_shift_characters, remaining_characters); + + // Will the string truncate? + if ((start + shift_amount + remaining_characters) > CAPACITY) + { + current_size = CAPACITY; + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif +#endif + } + else + { + current_size += shift_amount; + } + + etl::copy_backward(insert_position, insert_position + characters_to_shift, begin() + to_position + characters_to_shift); + etl::fill(insert_position, insert_position + shift_amount, value); + } + + p_buffer[current_size] = 0; + + return position_; + } + + //********************************************************************* + /// Inserts a range of values to the string. + /// If asserts or exceptions are enabled, emits string_full if the string does not have enough free space. + ///\param position The position to insert before. + ///\param first The first element to add. + ///\param last The last + 1 element to add. + //********************************************************************* + template + iterator insert(const_iterator position, TIterator first, TIterator last) + { + iterator position_ = to_iterator(position); + + if (first == last) + { + return position_; + } + + const size_type start = etl::distance(begin(), position_); + const size_type n = etl::distance(first, last); + + // No effect. + if (start >= CAPACITY) + { +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif +#endif + return position_; + } + + // Fills the string to the end? + if ((start + n) >= CAPACITY) + { + if (((current_size + n) > CAPACITY)) + { +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif +#endif + } + + current_size = CAPACITY; + + while (position_ != end()) + { + *position_++ = *first++; + } + } + else + { + // Lets do some shifting. + const size_type shift_amount = n; + const size_type to_position = start + shift_amount; + const size_type remaining_characters = current_size - start; + const size_type max_shift_characters = CAPACITY - start - shift_amount; + const size_type characters_to_shift = etl::min(max_shift_characters, remaining_characters); + + // Will the string truncate? + if ((start + shift_amount + remaining_characters) > CAPACITY) + { + current_size = CAPACITY; + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif +#endif + } + else + { + current_size += shift_amount; + } + + etl::copy_backward(position_, position_ + characters_to_shift, begin() + to_position + characters_to_shift); + + while (first != last) + { + *position_++ = *first++; + } + } + + p_buffer[current_size] = 0; + + return position_; + } + + //********************************************************************* + /// Inserts a string at the specified position. + ///\param position The position to insert before. + ///\param str The string to insert. + //********************************************************************* + etl::ibasic_string& insert(size_type position, const etl::ibasic_string& str) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + insert(begin() + position, str.cbegin(), str.cend()); + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + if (str.is_truncated()) + { + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif + } +#endif + + return *this; + } + + //********************************************************************* + /// Inserts a string at the specified position from subposition for sublength. + ///\param position The position to insert before. + ///\param str The string to insert. + ///\param subposition The subposition to start from. + ///\param sublength The number of characters to insert. + //********************************************************************* + etl::ibasic_string& insert(size_type position, const etl::ibasic_string& str, size_type subposition, size_type sublength) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds)); + + if ((sublength == npos) || (subposition + sublength > str.size())) + { + sublength = str.size() - subposition; + } + + insert(begin() + position, str.cbegin() + subposition, str.cbegin() + subposition + sublength); + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + if (str.is_truncated()) + { + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif + } +#endif + + return *this; + } + + //********************************************************************* + /// Inserts a string at the specified position from pointer. + ///\param position The position to insert before. + ///\param s The string to insert. + //********************************************************************* + etl::ibasic_string& insert(size_type position, const_pointer s) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + insert(begin() + position, s, s + etl::strlen(s)); + return *this; + } + + //********************************************************************* + /// Inserts a string at the specified position from pointer for n characters. + ///\param position The position to insert before. + ///\param s The string to insert. + ///\param n The number of characters to insert. + //********************************************************************* + etl::ibasic_string& insert(size_type position, const_pointer s, size_type n) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + insert(begin() + position, s, s + n); + return *this; + } + + //********************************************************************* + /// Insert n characters of c at position. + ///\param position The position to insert before. + ///\param n The number of characters to insert. + ///\param c The character to insert. + //********************************************************************* + etl::ibasic_string& insert(size_type position, size_type n, value_type c) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + insert(begin() + position, n, c); + return *this; + } + + //********************************************************************* + /// Erases a sequence. + ///\param position Position to start from. + ///\param length Number of characters. + ///\return A reference to this string. + //********************************************************************* + etl::ibasic_string& erase(size_type position, size_type length_ = npos) + { + // Limit the length. + length_ = etl::min(length_, size() - position); + + erase(begin() + position, begin() + position + length_); + + return *this; + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(iterator i_element) + { + etl::copy(i_element + 1, end(), i_element); + p_buffer[--current_size] = 0; + + return i_element; + } + + //********************************************************************* + /// Erases an element. + ///\param i_element Iterator to the element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(const_iterator i_element) + { + iterator i_element_(to_iterator(i_element)); + + etl::copy(i_element_ + 1, end(), i_element_); + p_buffer[--current_size] = 0; + + return i_element_; + } + + //********************************************************************* + /// Erases a range of elements. + /// The range includes all the elements between first and last, including the + /// element pointed by first, but not the one pointed by last. + ///\param first Iterator to the first element. + ///\param last Iterator to the last element. + ///\return An iterator pointing to the element that followed the erased element. + //********************************************************************* + iterator erase(const_iterator first, const_iterator last) + { + iterator first_ = to_iterator(first); + iterator last_ = to_iterator(last); + + if (first_ == last_) + { + return first_; + } + + etl::copy(last_, end(), first_); + size_type n_delete = etl::distance(first_, last_); + + current_size -= n_delete; + p_buffer[current_size] = 0; + cleanup(); + + return first_; + } + + //********************************************************************* + /// Return a pointer to a C string. + //********************************************************************* + const_pointer c_str() const + { + return p_buffer; + } + + //********************************************************************* + /// Copies a portion of a string. + ///\param dest Pointer to the destination buffer. + ///\param count The number of characters to copy. + ///\param pos The position to start copying from. + //********************************************************************* + size_type copy(pointer dest, size_type count, size_type pos = 0) const + { + if (pos < size()) + { + if (count != npos) + { + count = etl::min(count, size() - pos); + } + else + { + count = size() - pos; + } + + etl::copy_n(p_buffer + pos, count, dest); + + return count; + } + else + { + return 0U; + } + } + + //********************************************************************* + /// Find content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find(const ibasic_string& str, size_type pos = 0) const + { + if ((pos + str.size()) > size()) + { + return npos; + } + + const_iterator iposition = etl::search(begin() + pos, end(), str.begin(), str.end()); + + if (iposition == end()) + { + return npos; + } + else + { + return etl::distance(begin(), iposition); + } + } + + //********************************************************************* + /// Find content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find(const_pointer s, size_type pos = 0) const + { +#if ETL_IS_DEBUG_BUILD + if ((pos + etl::strlen(s)) > size()) + { + return npos; + } +#endif + + const_iterator iposition = etl::search(begin() + pos, end(), s, s + etl::strlen(s)); + + if (iposition == end()) + { + return npos; + } + else + { + return etl::distance(begin(), iposition); + } + } + + //********************************************************************* + /// Find content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + ///\param n The number of characters to search for. + //********************************************************************* + size_type find(const_pointer s, size_type pos, size_type n) const + { +#if ETL_IS_DEBUG_BUILD + if ((pos + etl::strlen(s) - n) > size()) + { + return npos; + } +#endif + + const_iterator iposition = etl::search(begin() + pos, end(), s, s + n); + + if (iposition == end()) + { + return npos; + } + else + { + return etl::distance(begin(), iposition); + } + } + + //********************************************************************* + /// Find character within the string + ///\param c The character to find. + ///\param position The position to start searching from. + //********************************************************************* + size_type find(T c, size_type position = 0) const + { + const_iterator i = etl::find(begin() + position, end(), c); + + if (i != end()) + { + return etl::distance(begin(), i); + } + else + { + return npos; + } + } + + //********************************************************************* + /// Find content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type rfind(const ibasic_string& str, size_type position = npos) const + { + if ((str.size()) > size()) + { + return npos; + } + + if (position >= size()) + { + position = size(); + } + + position = size() - position; + + const_reverse_iterator iposition = etl::search(rbegin() + position, rend(), str.rbegin(), str.rend()); + + if (iposition == rend()) + { + return npos; + } + else + { + return size() - str.size() - etl::distance(rbegin(), iposition); + } + } + + //********************************************************************* + /// Find content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type rfind(const_pointer s, size_type position = npos) const + { + size_type len = etl::strlen(s); + + if (len > size()) + { + return npos; + } + + if (position >= size()) + { + position = size(); + } + + position = size() - position; + + const_reverse_iterator srbegin(s + len); + const_reverse_iterator srend(s); + + const_reverse_iterator iposition = etl::search(rbegin() + position, rend(), srbegin, srend); + + if (iposition == rend()) + { + return npos; + } + else + { + return size() - len - etl::distance(rbegin(), iposition); + } + } + + //********************************************************************* + /// Find content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type rfind(const_pointer s, size_type position, size_type length_) const + { + if (length_ > size()) + { + return npos; + } + + if (position >= size()) + { + position = size(); + } + + position = size() - position; + + const_reverse_iterator srbegin(s + length_); + const_reverse_iterator srend(s); + + const_reverse_iterator iposition = etl::search(rbegin() + position, rend(), srbegin, srend); + + if (iposition == rend()) + { + return npos; + } + else + { + return size() - length_ - etl::distance(rbegin(), iposition); + } + } + + //********************************************************************* + /// Find character within the string + ///\param c The character to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type rfind(T c, size_type position = npos) const + { + if (position >= size()) + { + position = size(); + } + + position = size() - position; + + const_reverse_iterator i = etl::find(rbegin() + position, rend(), c); + + if (i != rend()) + { + return size() - etl::distance(rbegin(), i) - 1; + } + else + { + return npos; + } + } + + //********************************************************************* + /// Replace 'length' characters from 'position' with 'str'. + ///\param position The position to start from. + ///\param length The number of characters to replace. + ///\param str The string to replace it with. + //********************************************************************* + ibasic_string& replace(size_type position, size_type length_, const ibasic_string& str) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = etl::min(length_, size() - position); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, str); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' to one before 'last' with 'str'. + ///\param first The position to start from. + ///\param last The one after the position to end at. + ///\param str The string to replace it with. + //********************************************************************* + ibasic_string& replace(const_iterator first, const_iterator last, const ibasic_string& str) + { + // Quick hack, as iterators are pointers. + iterator first_ = to_iterator(first); + iterator last_ = to_iterator(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, str.begin(), str.end()); + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + if (str.is_truncated()) + { + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif + } +#endif + + return *this; + } + + //********************************************************************* + /// Replace characters from 'position' of 'length' with 'str' from 'subposition' of 'sublength'. + //********************************************************************* + ibasic_string& replace(size_type position, size_type length_, const ibasic_string& str, size_type subposition, size_type sublength) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the lengths. + length_ = etl::min(length_, size() - position); + sublength = etl::min(sublength, str.size() - subposition); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, str, subposition, sublength); + +#if ETL_HAS_STRING_TRUNCATION_CHECKS + if (str.is_truncated()) + { + set_truncated(true); + +#if ETL_HAS_ERROR_ON_STRING_TRUNCATION + ETL_ASSERT_FAIL(ETL_ERROR(string_truncation)); +#endif + } +#endif + + return *this; + } + + //********************************************************************* + /// Replace characters from 'position' of 'length' with pointed to string. + //********************************************************************* + ibasic_string& replace(size_type position, size_type length_, const_pointer s) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = etl::min(length_, size() - position); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, s, etl::strlen(s)); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' 'last' with pointed to string. + //********************************************************************* + ibasic_string& replace(const_iterator first, const_iterator last, const_pointer s) + { + // Quick hack, as iterators are pointers. + iterator first_ = to_iterator(first); + iterator last_ = to_iterator(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, s, s + etl::strlen(s)); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'position' of 'length' with 'n' characters from pointed to string. + //********************************************************************* + ibasic_string& replace(size_type position, size_type length_, const_pointer s, size_type n) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = etl::min(length_, size() - position); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, s, n); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' to 'last' with 'n' characters from pointed to string. + //********************************************************************* + ibasic_string& replace(const_iterator first, const_iterator last, const_pointer s, size_type n) + { + // Quick hack, as iterators are pointers. + iterator first_ = to_iterator(first); + iterator last_ = to_iterator(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, s, s + n); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'position' of 'length' with 'n' copies of 'c'. + //********************************************************************* + ibasic_string& replace(size_type position, size_type length_, size_type n, value_type c) + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = etl::min(length_, size() - position); + + // Erase the bit we want to replace. + erase(position, length_); + + // Insert the new stuff. + insert(position, n, c); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' of 'last' with 'n' copies of 'c'. + //********************************************************************* + ibasic_string& replace(const_iterator first, const_iterator last, size_type n, value_type c) + { + // Quick hack, as iterators are pointers. + iterator first_ = to_iterator(first); + iterator last_ = to_iterator(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, n, c); + + return *this; + } + + //********************************************************************* + /// Replace characters from 'first' of 'last' with characters from 'first_replace' to 'last_replace'. + //********************************************************************* + template + ibasic_string& replace(const_iterator first, const_iterator last, TIterator first_replace, TIterator last_replace) + { + // Quick hack, as iterators are pointers. + iterator first_ = to_iterator(first); + iterator last_ = to_iterator(last); + + // Erase the bit we want to replace. + erase(first_, last_); + + // Insert the new stuff. + insert(first_, first_replace, last_replace); + + return *this; + } + + //************************************************************************* + /// Compare with string. + //************************************************************************* + int compare(const ibasic_string& str) const + { + return compare(p_buffer, + p_buffer + size(), + str.p_buffer, + str.p_buffer + str.size()); + } + + //************************************************************************* + /// Compare position / length with string. + //************************************************************************* + int compare(size_type position, size_type length_, const ibasic_string& str) const + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the length. + length_ = etl::min(length_, size() - position); + + return compare(p_buffer + position, + p_buffer + position + length_, + str.p_buffer, + str.p_buffer + str.size()); + } + + //************************************************************************* + /// Compare position / length with string / subposition / sublength. + //************************************************************************* + int compare(size_type position, size_type length_, const ibasic_string& str, size_type subposition, size_type sublength) const + { + ETL_ASSERT(position <= size(), ETL_ERROR(string_out_of_bounds)); + ETL_ASSERT(subposition <= str.size(), ETL_ERROR(string_out_of_bounds)); + + // Limit the lengths. + length_ = etl::min(length_, size() - position); + sublength = etl::min(sublength, str.size() - subposition); + + return compare(p_buffer + position, + p_buffer + position + length_, + str.p_buffer + subposition, + str.p_buffer + subposition + sublength); + } + + //************************************************************************* + /// Compare with C string + //************************************************************************* + int compare(const value_type* s) const + { + return compare(p_buffer, + p_buffer + size(), + s, + s + etl::strlen(s)); + } + + //************************************************************************* + /// Compare position / length with C string. + //************************************************************************* + int compare(size_type position, size_type length_, const_pointer s) const + { + return compare(p_buffer + position, + p_buffer + position + length_, + s, + s + etl::strlen(s)); + } + + //************************************************************************* + /// Compare position / length with C string / n. + //************************************************************************* + int compare(size_type position, size_type length_, const_pointer s, size_type n) const + { + return compare(p_buffer + position, + p_buffer + position + length_, + s, + s + n); + } + + //********************************************************************* + /// Find first of any of content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_first_of(const ibasic_string& str, size_type position = 0) const + { + return find_first_of(str.c_str(), position, str.size()); + } + + //********************************************************************* + /// Find first of any of content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_first_of(const_pointer s, size_type position = 0) const + { + return find_first_of(s, position, etl::strlen(s)); + } + + //********************************************************************* + /// Find first of any of content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + ///\param n The number of characters to search for. + //********************************************************************* + size_type find_first_of(const_pointer s, size_type position, size_type n) const + { + if (position < size()) + { + for (size_type i = position; i < size(); ++i) + { + for (size_type j = 0; j < n; ++j) + { + if (p_buffer[i] == s[j]) + { + return i; + } + } + } + } + + return npos; + } + + //********************************************************************* + /// Find first of character within the string + ///\param c The character to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_first_of(value_type c, size_type position = 0) const + { + if (position < size()) + { + for (size_type i = position; i < size(); ++i) + { + if (p_buffer[i] == c) + { + return i; + } + } + } + + return npos; + } + + //********************************************************************* + /// Find last of any of content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_last_of(const ibasic_string& str, size_type position = npos) const + { + return find_last_of(str.c_str(), position, str.size()); + } + + //********************************************************************* + /// Find last of any of content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_last_of(const_pointer s, size_type position = npos) const + { + return find_last_of(s, position, etl::strlen(s)); + } + + //********************************************************************* + /// Find last of any of content within the string + ///\param s Pointer to the content to find + ///\param pos The position to start searching from. + ///\param n The number of characters to search for. + //********************************************************************* + size_type find_last_of(const_pointer s, size_type position, size_type n) const + { + if (empty()) + { + return npos; + } + + position = etl::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + for (size_type j = 0; j < n; ++j) + { + if (p_buffer[position] == s[j]) + { + return position; + } + } + + ++it; + --position; + } + + return npos; + } + + //********************************************************************* + /// Find last of character within the string + ///\param c The character to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_last_of(value_type c, size_type position = npos) const + { + if (empty()) + { + return npos; + } + + position = etl::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + if (p_buffer[position] == c) + { + return position; + } + + ++it; + --position; + } + + return npos; + } + + //********************************************************************* + /// Find first not of any of content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_first_not_of(const ibasic_string& str, size_type position = 0) const + { + return find_first_not_of(str.c_str(), position, str.size()); + } + + //********************************************************************* + /// Find first not of any of content within the string + ///\param s Pointer to the content to not find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_first_not_of(const_pointer s, size_type position = 0) const + { + return find_first_not_of(s, position, etl::strlen(s)); + } + + //********************************************************************* + /// Find first not of any of content within the string + ///\param s Pointer to the content to not find + ///\param pos The position to start searching from. + ///\param n The number of characters to search for. + //********************************************************************* + size_type find_first_not_of(const_pointer s, size_type position, size_type n) const + { + if (position < size()) + { + for (size_type i = position; i < size(); ++i) + { + bool found = false; + + for (size_type j = 0; j < n; ++j) + { + if (p_buffer[i] == s[j]) + { + found = true; + } + } + + if (!found) + { + return i; + } + } + } + + return npos; + } + + //********************************************************************* + /// Find first not of character within the string + ///\param c The character to not find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_first_not_of(value_type c, size_type position = 0) const + { + if (position < size()) + { + for (size_type i = position; i < size(); ++i) + { + if (*(p_buffer + i) != c) + { + return i; + } + } + } + + return npos; + } + + //********************************************************************* + /// Find last not of any of content within the string + ///\param str The content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_last_not_of(const ibasic_string& str, size_type position = npos) const + { + return find_last_not_of(str.c_str(), position, str.size()); + } + + //********************************************************************* + /// Find last not of any of content within the string + ///\param s The pointer to the content to find + ///\param pos The position to start searching from. + //********************************************************************* + size_type find_last_not_of(const_pointer s, size_type position = npos) const + { + return find_last_not_of(s, position, etl::strlen(s)); + } + + //********************************************************************* + /// Find last not of any of content within the string + ///\param s The pointer to the content to find + ///\param pos The position to start searching from. + ///\param n The number of characters to use. + //********************************************************************* + size_type find_last_not_of(const_pointer s, size_type position, size_type n) const + { + if (empty()) + { + return npos; + } + + position = etl::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + bool found = false; + + for (size_type j = 0; j < n; ++j) + { + if (p_buffer[position] == s[j]) + { + found = true; + } + } + + if (!found) + { + return position; + } + + ++it; + --position; + } + + return npos; + } + + //********************************************************************* + // + //********************************************************************* + size_type find_last_not_of(value_type c, size_type position = npos) const + { + if (empty()) + { + return npos; + } + + position = etl::min(position, size() - 1); + + const_reverse_iterator it = rbegin() + size() - position - 1; + + while (it != rend()) + { + if (p_buffer[position] != c) + { + return position; + } + + ++it; + --position; + } + + return npos; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + ibasic_string& operator = (const ibasic_string& rhs) + { + if (&rhs != this) + { + assign(rhs); + } + + return *this; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + ibasic_string& operator = (const_pointer rhs) + { + assign(rhs); + + return *this; + } + + //************************************************************************* + /// += operator. + //************************************************************************* + ibasic_string& operator += (const ibasic_string& rhs) + { + append(rhs); + + return *this; + } + + //************************************************************************* + /// += operator. + //************************************************************************* + ibasic_string& operator += (const_pointer rhs) + { + append(rhs); + + return *this; + } + + //************************************************************************* + /// += operator. + //************************************************************************* + ibasic_string& operator += (T rhs) + { + append(size_type(1), rhs); + + return *this; + } + +#if ETL_HAS_ISTRING_REPAIR + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + virtual void repair() = 0; +#endif + + //********************************************************************* + /// Clears the free space to string terminator value. + //********************************************************************* + void initialize_free_space() + { +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(false); +#endif + etl::fill(&p_buffer[current_size], &p_buffer[CAPACITY + 1U], T(0)); + } + + //********************************************************************* + /// Trim the size to the distance to the first null terminator. + /// If the last buffer position has a non-null value then the truncated + /// flag will be set. + //********************************************************************* + void trim_to_terminator() + { +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(p_buffer[CAPACITY] != T(0)); +#endif + + p_buffer[CAPACITY] = T(0); // Ensure a terminating null. + current_size = etl::strlen(p_buffer); + } + + protected: + + //********************************************************************* + /// Constructor. + //********************************************************************* + ibasic_string(T* p_buffer_, size_type MAX_SIZE_) + : string_base(MAX_SIZE_), + p_buffer(p_buffer_) + { + } + + //********************************************************************* + /// Initialise the string. + //********************************************************************* + void initialise() + { + current_size = 0U; + cleanup(); + p_buffer[0] = 0; +#if ETL_HAS_STRING_TRUNCATION_CHECKS + set_truncated(false); +#endif + } + + //************************************************************************* + /// Fix the internal pointers after a low level memory copy. + //************************************************************************* + void repair_buffer(T* p_buffer_) + { + p_buffer = p_buffer_; + } + + private: + + //************************************************************************* + /// Compare helper function + //************************************************************************* + int compare(const_pointer first1, const_pointer last1, const_pointer first2, const_pointer last2) const + { + while ((first1 != last1) && (first2 != last2)) + { + if (*first1 < *first2) + { + // Compared character is lower. + return -1; + } + else if (*first1 > *first2) + { + // Compared character is higher. + return 1; + } + + ++first1; + ++first2; + } + + // We reached the end of one or both of the strings. + if ((first1 == last1) && (first2 == last2)) + { + // Same length. + return 0; + } + else if (first1 == last1) + { + // Compared string is shorter. + return -1; + } + else + { + // Compared string is longer. + return 1; + } + } + + //************************************************************************* + /// Clear the unused trailing portion of the string. + //************************************************************************* + void cleanup() + { +#if ETL_HAS_STRING_CLEAR_AFTER_USE + if (is_secure()) + { + etl::memory_clear_range(&p_buffer[current_size], &p_buffer[CAPACITY]); + } +#endif + } + + //************************************************************************* + /// Disable copy construction. + //************************************************************************* + ibasic_string(const ibasic_string&); + + //************************************************************************* + /// Pointer to the string's buffer. + //************************************************************************* + T* p_buffer; + + //************************************************************************* + /// Destructor. + //************************************************************************* +#if defined(ETL_POLYMORPHIC_STRINGS) || defined(ETL_POLYMORPHIC_CONTAINERS) || defined(ETL_ISTRING_REPAIR_ENABLE) + public: + virtual +#else + protected: +#endif + ~ibasic_string() + { +#if ETL_HAS_STRING_CLEAR_AFTER_USE + if (is_secure()) + { + initialise(); + } +#endif + } + + protected: + + //************************************************************************* + /// Convert from const_iterator to iterator + //************************************************************************* + iterator to_iterator(const_iterator itr) const + { + return const_cast(itr); + } + }; + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the arrays are equal, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator ==(const etl::ibasic_string& lhs, const etl::ibasic_string& rhs) + { + return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the arrays are equal, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator ==(const etl::ibasic_string& lhs, const T* rhs) + { + return (lhs.size() == etl::strlen(rhs)) && etl::equal(lhs.begin(), lhs.end(), rhs); + } + + //*************************************************************************** + /// Equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the arrays are equal, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator ==(const T* lhs, const etl::ibasic_string& rhs) + { + return (rhs.size() == etl::strlen(lhs)) && etl::equal(rhs.begin(), rhs.end(), lhs); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the arrays are not equal, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator !=(const etl::ibasic_string& lhs, const etl::ibasic_string& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the arrays are not equal, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator !=(const etl::ibasic_string& lhs, const T* rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Not equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the arrays are not equal, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator !=(const T* lhs, const etl::ibasic_string& rhs) + { + return !(lhs == rhs); + } + + //*************************************************************************** + /// Less than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically less than the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator <(const etl::ibasic_string& lhs, const etl::ibasic_string& rhs) + { + return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); + } + + //*************************************************************************** + /// Less than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically less than the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator <(const etl::ibasic_string& lhs, const T* rhs) + { + return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs, rhs + etl::strlen(rhs)); + } + + //*************************************************************************** + /// Less than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically less than the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator <(const T* lhs, const etl::ibasic_string& rhs) + { + return etl::lexicographical_compare(lhs, lhs + etl::strlen(lhs), rhs.begin(), rhs.end()); + } + + + //*************************************************************************** + /// Greater than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically greater than the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator >(const etl::ibasic_string& lhs, const etl::ibasic_string& rhs) + { + return (rhs < lhs); + } + + //*************************************************************************** + /// Greater than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically greater than the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator >(const etl::ibasic_string& lhs, const T* rhs) + { + return (rhs < lhs); + } + + //*************************************************************************** + /// Greater than operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically greater than the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator >(const T* lhs, const etl::ibasic_string& rhs) + { + return (rhs < lhs); + } + + + //*************************************************************************** + /// Less than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically less than or equal to the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator <=(const etl::ibasic_string& lhs, const etl::ibasic_string& rhs) + { + return !(lhs > rhs); + } + + //*************************************************************************** + /// Less than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically less than or equal to the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator <=(const etl::ibasic_string& lhs, const T* rhs) + { + return !(lhs > rhs); + } + + //*************************************************************************** + /// Less than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically less than or equal to the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator <=(const T* lhs, const etl::ibasic_string& rhs) + { + return !(lhs > rhs); + } + + + //*************************************************************************** + /// Greater than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically greater than or equal to the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator >=(const etl::ibasic_string& lhs, const etl::ibasic_string& rhs) + { + return !(lhs < rhs); + } + + //*************************************************************************** + /// Greater than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically greater than or equal to the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator >=(const etl::ibasic_string& lhs, const T* rhs) + { + return !(lhs < rhs); + } + + //*************************************************************************** + /// Greater than or equal operator. + ///\param lhs Reference to the first string. + ///\param rhs Reference to the second string. + ///\return true if the first string is lexicographically greater than or equal to the second, otherwise false + ///\ingroup string + //*************************************************************************** + template + bool operator >=(const T* lhs, const etl::ibasic_string& rhs) + { + return !(lhs < rhs); + } +} + +#include "private/minmax_pop.h" + +#endif diff --git a/etl/basic_string_stream.h b/etl/basic_string_stream.h new file mode 100644 index 0000000..2b46605 --- /dev/null +++ b/etl/basic_string_stream.h @@ -0,0 +1,281 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_BASIC_STRING_STREAM_INCLUDED +#define ETL_BASIC_STRING_STREAM_INCLUDED + +///\ingroup string + +#include "platform.h" +#include "to_string.h" + +namespace etl +{ + template + class basic_string_stream + { + public: + + typedef TFormat format_spec_type; + typedef TIString istring_type; + typedef typename TIString::value_type value_type; + typedef typename TIString::pointer pointer; + typedef typename TIString::const_pointer const_pointer; + + //************************************************************************* + /// Construct from text. + //************************************************************************* + explicit basic_string_stream(TIString& text_) + : text(text_) + { + } + + //************************************************************************* + /// Construct from text and format fmt. + //************************************************************************* + basic_string_stream(TIString& text_, const TFormat& spec_) + : text(text_) + , format(spec_) + { + } + + //************************************************************************* + /// Set the format fmt. + //************************************************************************* + void set_format(const TFormat& spec_) + { + format = spec_; + } + + //************************************************************************* + /// Get a const reference to the format fmt. + //************************************************************************* + const TFormat& get_format() const + { + return format; + } + + //************************************************************************* + /// Get a reference to the current string. + //************************************************************************* + TIString& str() + { + return text; + } + + //************************************************************************* + /// Get a const reference to the current string. + //************************************************************************* + const TIString& str() const + { + return text; + } + + //************************************************************************* + /// Resets the stream to the supplied string. + //************************************************************************* + void str(const value_type* p) + { + text.assign(p); + } + + //************************************************************************* + /// Resets the stream to the supplied string. + //************************************************************************* + void str(const TIString& is) + { + text.assign(is); + } + + //************************************************************************* + /// Stream operators. + //************************************************************************* + + //********************************* + /// TFormat + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, const TFormat& fmt) + { + ss.format = fmt; + return ss; + } + + //********************************* + /// etl::base_spec from etl::setbase, etl::bin, etl::oct, etl::dec & etl::hex stream manipulators + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, etl::private_basic_format_spec::base_spec fmt) + { + ss.format.base(fmt.base); + return ss; + } + + //********************************* + /// etl::width_spec from etl::setw stream manipulator + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, etl::private_basic_format_spec::width_spec fmt) + { + ss.format.width(fmt.width); + return ss; + } + + //********************************* + /// etl::fill_spec from etl::setfill stream manipulator + //********************************* + template + friend basic_string_stream& operator <<(basic_string_stream& ss, etl::private_basic_format_spec::fill_spec fmt) + { + ss.format.fill(fmt.fill); + return ss; + } + + //********************************* + /// etl::precision_spec from etl::setprecision stream manipulator + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, etl::private_basic_format_spec::precision_spec fmt) + { + ss.format.precision(fmt.precision); + return ss; + } + + //********************************* + /// etl::boolalpha_spec from etl::boolalpha & etl::noboolalpha stream manipulators + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, etl::private_basic_format_spec::boolalpha_spec fmt) + { + ss.format.boolalpha(fmt.boolalpha); + return ss; + } + + //********************************* + /// etl::uppercase_spec from etl::uppercase & etl::nouppercase stream manipulators + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, etl::private_basic_format_spec::uppercase_spec fmt) + { + ss.format.upper_case(fmt.upper_case); + return ss; + } + + //********************************* + /// etl::showbase_spec from etl::showbase & etl::noshowbase stream manipulators + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, etl::private_basic_format_spec::showbase_spec fmt) + { + ss.format.show_base(fmt.show_base); + return ss; + } + + //********************************* + /// etl::left_spec from etl::left stream manipulator + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, etl::private_basic_format_spec::left_spec /*fmt*/) + { + ss.format.left(); + return ss; + } + + //********************************* + /// etl::right_spec from etl::left stream manipulator + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, etl::private_basic_format_spec::right_spec /*fmt*/) + { + ss.format.right(); + return ss; + } + + //********************************* + /// From a string view + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, TStringView view) + { + etl::to_string(view, ss.text, ss.format, true); + return ss; + } + + //********************************* + /// From a character pointer to a string + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, pointer p) + { + TStringView view(p); + ss << view; + return ss; + } + + //********************************* + /// From a const character pointer to a string + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, const_pointer p) + { + TStringView view(p); + ss << view; + return ss; + } + + //********************************* + /// From a string interface + //********************************* + friend basic_string_stream& operator <<(basic_string_stream& ss, const TIString& t) + { + etl::to_string(t, ss.text, ss.format, true); + return ss; + } + + //********************************* + /// From a string + //********************************* + template