Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <cassert>
- #include <string>
- #include <algorithm>
- #define wxToupper toupper
- using wxString = std::string;
- /**
- * class CONST_WX_STRING_VIEW
- * represents a const_iterator range inside a wxString, helper class for parsing needs.
- */
- class CONST_WX_STRING_VIEW
- {
- public:
- using iterator = wxString::const_iterator;
- using value_type = iterator::value_type;
- CONST_WX_STRING_VIEW(iterator aBegin, iterator aEnd)
- : m_begin(std::move(aBegin)), m_end(std::move(aEnd))
- {}
- CONST_WX_STRING_VIEW(const wxString& aString)
- : m_begin(aString.begin()), m_end(aString.end())
- {
- }
- CONST_WX_STRING_VIEW(const wxString& aString, size_t aCount)
- : m_begin(aString.begin())
- {
- auto it = aString.begin();
- std::advance(it, std::min(aCount, aString.size()));
- m_end = it;
- }
- CONST_WX_STRING_VIEW(const CONST_WX_STRING_VIEW& aString, size_t aCount)
- : m_begin(aString.begin())
- {
- auto it = aString.begin();
- std::advance(it, std::min(aCount, aString.size()));
- m_end = it;
- }
- CONST_WX_STRING_VIEW(const CONST_WX_STRING_VIEW&) = default;
- CONST_WX_STRING_VIEW(CONST_WX_STRING_VIEW&&) = default;
- CONST_WX_STRING_VIEW& operator=(CONST_WX_STRING_VIEW&&) = default;
- CONST_WX_STRING_VIEW& operator=(const CONST_WX_STRING_VIEW&) = default;
- CONST_WX_STRING_VIEW& operator++()
- {
- ++m_begin;
- return *this;
- }
- CONST_WX_STRING_VIEW operator++(int)
- {
- auto temp = *this;
- ++m_begin;
- return temp;
- }
- size_t size() const {
- return std::distance(m_begin, m_end);
- }
- value_type operator*() const
- {
- return *m_begin;
- }
- explicit operator bool() const
- {
- return m_begin != m_end;
- }
- const iterator& begin() const {
- return m_begin;
- }
- const iterator& end() const {
- return m_end;
- }
- wxString str() const {
- return wxString(m_begin, m_end);
- }
- private:
- iterator m_begin, m_end;
- };
- //
- // Flags for StrNumCmp
- //
- enum class STR_NUM_CMP_FLAGS : unsigned int {
- Default = 0,
- ExtendedNumbers = 1, // 3V3 => 3.3
- IgnoreCase = 2
- };
- // Helper for flag concatenation
- constexpr STR_NUM_CMP_FLAGS operator| (STR_NUM_CMP_FLAGS lhs, STR_NUM_CMP_FLAGS rhs)
- {
- return (STR_NUM_CMP_FLAGS)(static_cast<unsigned int>(lhs) | static_cast<unsigned int>(rhs));
- }
- // Helper for flag testing
- constexpr bool operator& (STR_NUM_CMP_FLAGS lhs, STR_NUM_CMP_FLAGS rhs)
- {
- return (static_cast<unsigned int>(lhs) & static_cast<unsigned int>(rhs)) != 0;
- }
- //
- // Helper functions
- //
- namespace {
- bool use_extended_numbers(STR_NUM_CMP_FLAGS flags) {
- return flags & STR_NUM_CMP_FLAGS::ExtendedNumbers;
- }
- bool use_ignore_case(STR_NUM_CMP_FLAGS flags)
- {
- return flags & STR_NUM_CMP_FLAGS::IgnoreCase;
- }
- bool parse_number(CONST_WX_STRING_VIEW& aString, double& aDouble, STR_NUM_CMP_FLAGS aFlags)
- {
- auto local = aString;
- size_t digits = 0;
- double factor = 1;
- size_t decimals = 0;
- double number = 0;
- bool parsed_decimal_point = false;
- while(local) {
- if(isdigit(*local))
- {
- if(parsed_decimal_point) {
- ++decimals;
- number += double(*local - '0') * pow(10., -static_cast<int>(decimals));
- }
- else {
- number = number * 10 + double(*local - '0');
- }
- ++digits;
- }
- else if(use_extended_numbers(aFlags) && digits == 0 && (*local == '+') || (*local == '-'))
- {
- if(*local == '-') {
- factor = -1;
- }
- }
- else if(use_extended_numbers(aFlags) && !parsed_decimal_point)
- {
- switch((*local)/*.GetValue()*/ ) {
- case 'V':
- case 'v':
- case '.':
- parsed_decimal_point = true;
- }
- if(!parsed_decimal_point) break;
- }
- else
- {
- break;
- }
- ++local;
- }
- if(digits > 0)
- {
- aString = local;
- aDouble = factor * number;
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- int StrNumCmp(CONST_WX_STRING_VIEW aString1, CONST_WX_STRING_VIEW aString2,
- STR_NUM_CMP_FLAGS flags = STR_NUM_CMP_FLAGS::Default);
- int StrNumCmp(CONST_WX_STRING_VIEW aString1, CONST_WX_STRING_VIEW aString2, size_t aCount,
- STR_NUM_CMP_FLAGS flags = STR_NUM_CMP_FLAGS::Default);
- int StrNumCmp(CONST_WX_STRING_VIEW aString1, CONST_WX_STRING_VIEW aString2, STR_NUM_CMP_FLAGS flags)
- {
- while(aString1 && aString2) {
- double num1;
- double num2;
- bool is_num1 = parse_number(aString1, num1, flags);
- bool is_num2 = parse_number(aString2, num2, flags);
- if(is_num1 && is_num2)
- {
- if(num1 < num2) return -1;
- if(num2 < num1) return 1;
- }
- else
- {
- auto a = *aString1;
- auto b = *aString2;
- if(use_ignore_case(flags))
- {
- a = wxToupper(a);
- b = wxToupper(b);
- }
- if(a < b) return -1;
- if(b < a) return 1;
- ++aString1;
- ++aString2;
- }
- }
- if(aString1 && !aString2) return 1;
- if(aString2 && !aString1) return -1;
- return 0;
- }
- int StrNumCmp(CONST_WX_STRING_VIEW aString1, CONST_WX_STRING_VIEW aString2, size_t aCount, STR_NUM_CMP_FLAGS aFlags)
- {
- return StrNumCmp({ aString1, aCount }, { aString2, aCount }, aFlags);
- }
- int main()
- {
- assert( StrNumCmp( { "" }, { "" } ) == 0 );
- assert( StrNumCmp( { "A" }, { "" } ) == 1 );
- assert( StrNumCmp( { "" }, { "B" } ) == -1 );
- assert( StrNumCmp( { "1" }, { "2" } ) == -1 );
- assert( StrNumCmp( { "10" }, { "2" } ) == 1 );
- assert( StrNumCmp( { "a" }, { "b" } ) == -1 );
- assert( StrNumCmp( { "a" }, { "A" } ) == 1 );
- assert( StrNumCmp( { "aAa" }, { "AaA" }, STR_NUM_CMP_FLAGS::IgnoreCase) == 0);
- assert( StrNumCmp( { "A34B32C43D2" }, { "A34B32C230D" }) == -1 );
- // constrained mode
- assert(StrNumCmp({ "P100" }, { "P2" }, 2) == -1);
- // Gyros-Mode
- assert( StrNumCmp({ "3V3" }, { "3.3" }, STR_NUM_CMP_FLAGS::ExtendedNumbers) == 0 );
- assert( StrNumCmp({ "+3V3" }, { "3.3" }, STR_NUM_CMP_FLAGS::ExtendedNumbers) == 0 );
- assert( StrNumCmp({ "+3V3A" }, { "3.3B" }, STR_NUM_CMP_FLAGS::ExtendedNumbers) == -1 );
- assert( StrNumCmp({ "-3V3" }, { "3.3" }, STR_NUM_CMP_FLAGS::ExtendedNumbers) == -1 );
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement