mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Optimisation of strings
This commit is contained in:
parent
e8a5673f7a
commit
cb6d924dad
@ -45,6 +45,7 @@ SOFTWARE.
|
||||
#include "memory.h"
|
||||
#include "binary.h"
|
||||
#include "flags.h"
|
||||
#include "string_utilities.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@ -247,11 +248,9 @@ namespace etl
|
||||
|
||||
//*************************************************************************
|
||||
/// 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
|
||||
bool is_truncated() const
|
||||
{
|
||||
#if ETL_HAS_STRING_TRUNCATION_CHECKS
|
||||
return flags.test<IS_TRUNCATED>();
|
||||
@ -262,15 +261,13 @@ namespace etl
|
||||
|
||||
//*************************************************************************
|
||||
/// Returns whether the string was truncated by the last operation.
|
||||
/// Deprecated. Use is_truncated()
|
||||
///\return Whether the string was truncated by the last operation.
|
||||
//*************************************************************************
|
||||
bool is_truncated() const
|
||||
ETL_DEPRECATED
|
||||
bool truncated() const
|
||||
{
|
||||
#if ETL_HAS_STRING_TRUNCATION_CHECKS
|
||||
return flags.test<IS_TRUNCATED>();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return is_truncated();
|
||||
}
|
||||
|
||||
#if ETL_HAS_STRING_TRUNCATION_CHECKS
|
||||
@ -724,7 +721,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
void assign(const_pointer text)
|
||||
{
|
||||
assign_impl(text, text + etl::strlen(text), false, false);
|
||||
assign_impl(text, false, false);
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
@ -761,7 +758,7 @@ namespace etl
|
||||
set_truncated(n > CAPACITY);
|
||||
|
||||
#if ETL_HAS_ERROR_ON_STRING_TRUNCATION
|
||||
ETL_ASSERT(flags.test<IS_TRUNCATED>() == false, ETL_ERROR(string_truncation));
|
||||
ETL_ASSERT(is_truncated == false, ETL_ERROR(string_truncation));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -1093,10 +1090,7 @@ namespace etl
|
||||
|
||||
current_size = CAPACITY;
|
||||
|
||||
while (position_ != end())
|
||||
{
|
||||
*position_++ = *first++;
|
||||
}
|
||||
position_ = copy_characters(first, etl::distance(position_, end()), position_);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1127,10 +1121,7 @@ namespace etl
|
||||
|
||||
etl::copy_backward(position_, position_ + characters_to_shift, begin() + to_position + characters_to_shift);
|
||||
|
||||
while (first != last)
|
||||
{
|
||||
*position_++ = *first++;
|
||||
}
|
||||
position_ = copy_characters(first, etl::distance(first, last), position_);
|
||||
}
|
||||
|
||||
p_buffer[current_size] = 0;
|
||||
@ -1310,7 +1301,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
iterator erase(iterator i_element)
|
||||
{
|
||||
etl::copy(i_element + 1, end(), i_element);
|
||||
etl::mem_copy(i_element + 1, end(), i_element);
|
||||
p_buffer[--current_size] = 0;
|
||||
|
||||
return i_element;
|
||||
@ -1325,7 +1316,7 @@ namespace etl
|
||||
{
|
||||
iterator i_element_(to_iterator(i_element));
|
||||
|
||||
etl::copy(i_element_ + 1, end(), i_element_);
|
||||
etl::mem_copy(i_element + 1, end(), i_element_);
|
||||
p_buffer[--current_size] = 0;
|
||||
|
||||
return i_element_;
|
||||
@ -1349,7 +1340,7 @@ namespace etl
|
||||
return first_;
|
||||
}
|
||||
|
||||
etl::copy(last_, end(), first_);
|
||||
etl::mem_copy(last_, end(), first_);
|
||||
size_type n_delete = etl::distance(first_, last_);
|
||||
|
||||
current_size -= n_delete;
|
||||
@ -1386,7 +1377,7 @@ namespace etl
|
||||
count = size() - pos;
|
||||
}
|
||||
|
||||
etl::copy_n(p_buffer + pos, count, dest);
|
||||
etl::mem_copy(p_buffer + pos, count, dest);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -2559,16 +2550,24 @@ namespace etl
|
||||
//*************************************************************************
|
||||
/// Compare helper function
|
||||
//*************************************************************************
|
||||
int compare(const_pointer first1, const_pointer last1, const_pointer first2, const_pointer last2) const
|
||||
static int compare(const_pointer first1, const_pointer last1,
|
||||
const_pointer first2, const_pointer last2)
|
||||
{
|
||||
while ((first1 != last1) && (first2 != last2))
|
||||
typedef typename etl::make_unsigned<value_type>::type type;
|
||||
|
||||
difference_type length1 = etl::distance(first1, last1);
|
||||
difference_type length2 = etl::distance(first2, last2);
|
||||
difference_type compare_length = min(length1, length2);
|
||||
|
||||
// First compare the string characters.
|
||||
while (compare_length != 0)
|
||||
{
|
||||
if (*first1 < *first2)
|
||||
if (static_cast<type>(*first1) < static_cast<type>(*first2))
|
||||
{
|
||||
// Compared character is lower.
|
||||
return -1;
|
||||
}
|
||||
else if (*first1 > *first2)
|
||||
else if (static_cast<type>(*first1) > static_cast<type>(*first2))
|
||||
{
|
||||
// Compared character is higher.
|
||||
return 1;
|
||||
@ -2576,24 +2575,24 @@ namespace etl
|
||||
|
||||
++first1;
|
||||
++first2;
|
||||
--compare_length;
|
||||
}
|
||||
|
||||
// We reached the end of one or both of the strings.
|
||||
if ((first1 == last1) && (first2 == last2))
|
||||
// Then compare the string lengths.
|
||||
if (length1 < length2)
|
||||
{
|
||||
// Same length.
|
||||
return 0;
|
||||
}
|
||||
else if (first1 == last1)
|
||||
{
|
||||
// Compared string is shorter.
|
||||
// First string is shorter.
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
|
||||
if (length1 > length2)
|
||||
{
|
||||
// Compared string is longer.
|
||||
// First string is longer.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Strings are the same length.
|
||||
return 0;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -2651,30 +2650,91 @@ namespace etl
|
||||
private:
|
||||
|
||||
//*********************************************************************
|
||||
/// Common implementation for 'assign'.
|
||||
/// Copy characters using pointers.
|
||||
/// Returns a pointer to the character after the last copied.
|
||||
//*********************************************************************
|
||||
template <typename TIterator1, typename TIterator2>
|
||||
typename etl::enable_if<etl::is_pointer<TIterator1>::value && etl::is_pointer<TIterator2>::value, TIterator2>::type
|
||||
copy_characters(TIterator1 from, size_t dist, TIterator2 to)
|
||||
{
|
||||
etl::mem_copy(from, dist, to);
|
||||
|
||||
return to + dist;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Copy characters using non-pointers.
|
||||
/// Returns an iterator to the character after the last copied.
|
||||
//*********************************************************************
|
||||
template <typename TIterator1, typename TIterator2>
|
||||
typename etl::enable_if<!etl::is_pointer<TIterator1>::value || !etl::is_pointer<TIterator2>::value, TIterator2>::type
|
||||
copy_characters(TIterator1 from, size_t dist, TIterator2 to)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
while (count != dist)
|
||||
{
|
||||
*to++ = *from++;
|
||||
++count;
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Common implementation for 'assign' for iterators.
|
||||
//*********************************************************************
|
||||
template <typename TIterator>
|
||||
void assign_impl(TIterator first, TIterator last, bool truncated, bool secure)
|
||||
{
|
||||
#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++;
|
||||
}
|
||||
difference_type dist = etl::distance(first, last);
|
||||
|
||||
#if ETL_IS_DEBUG_BUILD
|
||||
ETL_ASSERT(dist >= 0, ETL_ERROR(string_iterator));
|
||||
#endif
|
||||
|
||||
#if ETL_HAS_STRING_TRUNCATION_CHECKS
|
||||
set_truncated((size_t(dist) > CAPACITY) || truncated);
|
||||
|
||||
#if ETL_HAS_ERROR_ON_STRING_TRUNCATION
|
||||
ETL_ASSERT(is_truncated == false, ETL_ERROR(string_truncation));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ETL_HAS_STRING_CLEAR_AFTER_USE
|
||||
if (secure)
|
||||
{
|
||||
set_secure();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Limit the actual distance to the capacity.
|
||||
dist = difference_type(min(size_t(dist), CAPACITY));
|
||||
copy_characters(first, dist, p_buffer);
|
||||
current_size = dist;
|
||||
p_buffer[current_size] = 0;
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
/// Common implementation for 'assign' for single pointer.
|
||||
//*********************************************************************
|
||||
void assign_impl(const_pointer first, bool truncated, bool secure)
|
||||
{
|
||||
initialise();
|
||||
|
||||
etl::str_n_copy_result result = etl::str_n_copy(first, CAPACITY, p_buffer);
|
||||
|
||||
current_size = result.count;
|
||||
p_buffer[current_size] = 0;
|
||||
|
||||
#if ETL_HAS_STRING_TRUNCATION_CHECKS
|
||||
set_truncated((first != last) || truncated);
|
||||
|
||||
set_truncated(result.truncated || truncated);
|
||||
#if ETL_HAS_ERROR_ON_STRING_TRUNCATION
|
||||
ETL_ASSERT(flags.test<IS_TRUNCATED>() == false, ETL_ERROR(string_truncation));
|
||||
ETL_ASSERT(is_truncated == false, ETL_ERROR(string_truncation));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -2979,6 +3039,24 @@ namespace etl
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Spaceship operator.
|
||||
///\param lhs Reference to the first string.
|
||||
///\param rhs Reference to the second string.
|
||||
///\return -1 if lhs < rhs
|
||||
/// 0 if lhs == rhs
|
||||
/// 1 if lhs > rhs
|
||||
///\ingroup string
|
||||
//***************************************************************************
|
||||
#if ETL_USING_CPP20
|
||||
template <typename T>
|
||||
int operator <=>(const etl::ibasic_string<T>& lhs,
|
||||
const etl::ibasic_string<T>& rhs)
|
||||
{
|
||||
return lhs.compare(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Operator overload to write to std basic_ostream
|
||||
///\param os Reference to the output stream.
|
||||
|
||||
@ -883,6 +883,50 @@ namespace etl
|
||||
|
||||
etl::transform(itr, s.end(), itr, ::tolower);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// str_n_copy
|
||||
/// Copies from src to dst until either n characters have been copied, or a
|
||||
/// terminating null is found.
|
||||
/// Null terminates the destination if less than n characters have been copied.
|
||||
/// Returns a str_n_copy_result.
|
||||
//***************************************************************************
|
||||
struct str_n_copy_result
|
||||
{
|
||||
size_t count;
|
||||
bool truncated;
|
||||
bool terminated;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
str_n_copy_result str_n_copy(const T* src, size_t n, T* dst)
|
||||
{
|
||||
if ((src == ETL_NULLPTR) || (dst == ETL_NULLPTR))
|
||||
{
|
||||
return str_n_copy_result{ 0, false, false };
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
|
||||
while ((count != n) && (*src != 0))
|
||||
{
|
||||
*dst++ = *src++;
|
||||
++count;
|
||||
}
|
||||
|
||||
// Did we stop because of a terminating zero?
|
||||
if (count != n)
|
||||
{
|
||||
// Yes we did.
|
||||
*dst = 0;
|
||||
return str_n_copy_result{ count, false, true };
|
||||
}
|
||||
else
|
||||
{
|
||||
// No. Truncation depends on the next src character being a terminating zero or not.
|
||||
return str_n_copy_result{ count, *src != 0, false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "private/minmax_pop.h"
|
||||
|
||||
@ -44,6 +44,9 @@ SOFTWARE.
|
||||
#undef STR_PTR
|
||||
#define STR_PTR const char*
|
||||
|
||||
#undef STR_TYPE
|
||||
#define STR_TYPE char
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_string_utilities_char)
|
||||
@ -1781,5 +1784,81 @@ namespace
|
||||
|
||||
CHECK(text == expected);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_str_n_copy_destination_larger)
|
||||
{
|
||||
STR_PTR src = STR("Hello World");
|
||||
STR_TYPE dst[15];
|
||||
|
||||
etl::str_n_copy_result result = etl::str_n_copy(src, 15, dst);
|
||||
CHECK_EQUAL(etl::strlen(src), result.count);
|
||||
CHECK_FALSE(result.truncated);
|
||||
CHECK_TRUE(result.terminated);
|
||||
CHECK(dst[11] == 0);
|
||||
|
||||
bool are_equal = etl::equal(src, src + 12, dst);
|
||||
CHECK(are_equal);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_str_n_copy_destination_exact_include_space_for_terminator)
|
||||
{
|
||||
STR_PTR src = STR("Hello World");
|
||||
STR_TYPE dst[12];
|
||||
|
||||
etl::str_n_copy_result result = etl::str_n_copy(src, 12, dst);
|
||||
CHECK_EQUAL(11, result.count);
|
||||
CHECK_FALSE(result.truncated);
|
||||
CHECK_TRUE(result.terminated);
|
||||
CHECK(dst[11] == 0);
|
||||
|
||||
bool are_equal = etl::equal(src, src + 12, dst);
|
||||
CHECK(are_equal);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_str_n_copy_destination_exclude_space_for_terminator_exact_no_termination)
|
||||
{
|
||||
STR_PTR src = STR("Hello World");
|
||||
STR_TYPE dst[11];
|
||||
|
||||
etl::str_n_copy_result result = etl::str_n_copy(src, 11, dst);
|
||||
CHECK_EQUAL(11, result.count);
|
||||
CHECK_FALSE(result.truncated);
|
||||
CHECK_FALSE(result.terminated);
|
||||
CHECK(dst[10] != 0);
|
||||
|
||||
bool are_equal = etl::equal(src, src + 11, dst);
|
||||
CHECK(are_equal);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_str_n_copy_destination_smaller_no_termination)
|
||||
{
|
||||
STR_PTR src = STR("Hello World");
|
||||
STR_TYPE dst[9];
|
||||
|
||||
etl::str_n_copy_result result = etl::str_n_copy(src, 9, dst);
|
||||
CHECK_EQUAL(9, result.count);
|
||||
CHECK_TRUE(result.truncated);
|
||||
CHECK_FALSE(result.terminated);
|
||||
CHECK(dst[8] != 0);
|
||||
|
||||
bool are_equal = etl::equal(src, src + 9, dst);
|
||||
CHECK(are_equal);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_str_n_copy_zero_sized_destination)
|
||||
{
|
||||
STR_PTR src = STR("Hello World");
|
||||
STR_TYPE dst[15];
|
||||
|
||||
etl::str_n_copy_result result = etl::str_n_copy(src, 0, dst);
|
||||
CHECK_EQUAL(0, result.count);
|
||||
CHECK_TRUE(result.truncated);
|
||||
CHECK_FALSE(result.terminated);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user