mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-15 08:26:04 +08:00
Various bugfixes
This commit is contained in:
parent
4f411c66a9
commit
f30df9a68a
@ -1467,9 +1467,7 @@ namespace etl
|
||||
//*********************************************************************
|
||||
size_type find(const_pointer s, size_type pos, size_type n) const
|
||||
{
|
||||
size_t sz = etl::strlen(s);
|
||||
|
||||
return find_impl(s, s + n, sz, pos);
|
||||
return find_impl(s, s + n, n, pos);
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
|
||||
@ -1742,7 +1742,7 @@ namespace etl
|
||||
{
|
||||
count = 1U;
|
||||
|
||||
if ((value & 0xFFFFFFFFF0000000ULL) == 0U)
|
||||
if ((value & 0xFFFFFFFF00000000ULL) == 0U)
|
||||
{
|
||||
value <<= 32U;
|
||||
count += 32U;
|
||||
@ -1795,7 +1795,7 @@ namespace etl
|
||||
{
|
||||
typedef typename etl::make_unsigned<T>::type unsigned_t;
|
||||
|
||||
return static_cast<T>(count_trailing_ones(static_cast<unsigned_t>(value)));
|
||||
return static_cast<T>(count_leading_zeros(static_cast<unsigned_t>(value)));
|
||||
}
|
||||
|
||||
#if ETL_USING_8BIT_TYPES
|
||||
@ -1927,8 +1927,8 @@ namespace etl
|
||||
|
||||
if ((value & 0xFFFF0000UL) == 0xFFFF0000UL)
|
||||
{
|
||||
value <<= 8U;
|
||||
count += 8U;
|
||||
value <<= 16U;
|
||||
count += 16U;
|
||||
}
|
||||
|
||||
if ((value & 0xFF000000UL) == 0xFF000000UL)
|
||||
@ -1988,14 +1988,14 @@ namespace etl
|
||||
|
||||
if ((value & 0xFFFFFFFF00000000ULL) == 0xFFFFFFFF00000000ULL)
|
||||
{
|
||||
value <<= 8U;
|
||||
count += 8U;
|
||||
value <<= 32U;
|
||||
count += 32U;
|
||||
}
|
||||
|
||||
if ((value & 0xFFFF000000000000ULL) == 0xFFFF000000000000ULL)
|
||||
{
|
||||
value <<= 8U;
|
||||
count += 8U;
|
||||
value <<= 16U;
|
||||
count += 16U;
|
||||
}
|
||||
|
||||
if ((value & 0xFF00000000000000ULL) == 0xFF00000000000000ULL)
|
||||
|
||||
@ -1206,7 +1206,7 @@ namespace etl
|
||||
{
|
||||
this->clear();
|
||||
|
||||
for (typename etl::icircular_buffer<T>::const_iterator itr = other.begin(); itr != other.end(); ++itr)
|
||||
for (typename etl::icircular_buffer<T>::iterator itr = other.begin(); itr != other.end(); ++itr)
|
||||
{
|
||||
this->push(etl::move(*itr));
|
||||
}
|
||||
|
||||
@ -606,10 +606,10 @@ namespace etl
|
||||
}
|
||||
|
||||
//***************************************************
|
||||
reference operator[](size_t i)
|
||||
const_reference operator[](size_t i) const
|
||||
{
|
||||
iterator result(*this);
|
||||
result += i;
|
||||
const_iterator result(*this);
|
||||
result += static_cast<difference_type>(i);
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
@ -206,7 +206,7 @@ namespace etl
|
||||
//*******************************************
|
||||
/// Get the error.
|
||||
//*******************************************
|
||||
ETL_CONSTEXPR14 TError&& error() const&& ETL_NOEXCEPT
|
||||
ETL_CONSTEXPR14 const TError&& error() const&& ETL_NOEXCEPT
|
||||
{
|
||||
return etl::move(error_value);
|
||||
}
|
||||
@ -1309,7 +1309,7 @@ namespace etl
|
||||
template < typename F, typename U = typename etl::remove_cvref< typename etl::invoke_result<F, void, const TError&&>::type>::type>
|
||||
auto transform_error(F&& f) const&& -> expected<void, U>
|
||||
{
|
||||
return transform_error_impl<F, const this_type&&, U, const TError&&>(etl::forward<F>(f), *this);
|
||||
return transform_error_impl<F, const this_type&&, U, const TError&&>(etl::forward<F>(f), etl::move(*this));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -116,15 +116,15 @@ namespace etl
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Unsorted exception for the list.
|
||||
///\ingroup list
|
||||
/// Unsorted exception for the forward_list.
|
||||
///\ingroup forward_list
|
||||
//***************************************************************************
|
||||
class forward_list_no_pool : public forward_list_exception
|
||||
{
|
||||
public:
|
||||
|
||||
forward_list_no_pool(string_type file_name_, numeric_type line_number_)
|
||||
: forward_list_exception(ETL_ERROR_TEXT("list:no pool", ETL_FORWARD_LIST_FILE_ID"D"), file_name_, line_number_)
|
||||
: forward_list_exception(ETL_ERROR_TEXT("forward_list:no pool", ETL_FORWARD_LIST_FILE_ID"D"), file_name_, line_number_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@ -479,7 +479,7 @@ namespace etl
|
||||
//*********************************
|
||||
const_iterator end() const
|
||||
{
|
||||
return accumulator.begin();
|
||||
return accumulator.end();
|
||||
}
|
||||
|
||||
//*********************************
|
||||
@ -487,7 +487,7 @@ namespace etl
|
||||
//*********************************
|
||||
const_iterator cend() const
|
||||
{
|
||||
return accumulator.cbegin();
|
||||
return accumulator.cend();
|
||||
}
|
||||
|
||||
//*********************************
|
||||
|
||||
@ -890,7 +890,10 @@ namespace etl
|
||||
template <typename TLink>
|
||||
typename etl::enable_if< etl::is_same<TLink, etl::bidirectional_link<TLink::ID> >::value, void>::type link_clear_range(TLink* start)
|
||||
{
|
||||
etl::link_clear_range(*start);
|
||||
if (start != ETL_NULLPTR)
|
||||
{
|
||||
etl::link_clear_range(*start);
|
||||
}
|
||||
}
|
||||
|
||||
#if ETL_USING_CPP17
|
||||
|
||||
@ -589,9 +589,9 @@ namespace etl
|
||||
return npos;
|
||||
}
|
||||
|
||||
position = etl::min(position, size());
|
||||
position = etl::min(position, size() - view.size());
|
||||
|
||||
const_iterator iposition = etl::find_end(begin(), begin() + position, view.begin(), view.end());
|
||||
const_iterator iposition = etl::find_end(begin(), begin() + position + view.size(), view.begin(), view.end());
|
||||
|
||||
if (iposition == end())
|
||||
{
|
||||
|
||||
@ -499,19 +499,19 @@ namespace etl
|
||||
};
|
||||
#if ETL_HAS_NATIVE_CHAR8_T
|
||||
template <>
|
||||
struct is_signed<char8_t> : true_type
|
||||
struct is_signed<char8_t> : false_type
|
||||
{
|
||||
};
|
||||
#endif
|
||||
#if ETL_HAS_NATIVE_CHAR16_T
|
||||
template <>
|
||||
struct is_signed<char16_t> : true_type
|
||||
struct is_signed<char16_t> : false_type
|
||||
{
|
||||
};
|
||||
#endif
|
||||
#if ETL_HAS_NATIVE_CHAR32_T
|
||||
template <>
|
||||
struct is_signed<char32_t> : true_type
|
||||
struct is_signed<char32_t> : false_type
|
||||
{
|
||||
};
|
||||
#endif
|
||||
@ -569,6 +569,24 @@ namespace etl
|
||||
struct is_unsigned<unsigned long long> : true_type
|
||||
{
|
||||
};
|
||||
#if ETL_HAS_NATIVE_CHAR8_T
|
||||
template <>
|
||||
struct is_unsigned<char8_t> : true_type
|
||||
{
|
||||
};
|
||||
#endif
|
||||
#if ETL_HAS_NATIVE_CHAR16_T
|
||||
template <>
|
||||
struct is_unsigned<char16_t> : true_type
|
||||
{
|
||||
};
|
||||
#endif
|
||||
#if ETL_HAS_NATIVE_CHAR32_T
|
||||
template <>
|
||||
struct is_unsigned<char32_t> : true_type
|
||||
{
|
||||
};
|
||||
#endif
|
||||
template <typename T>
|
||||
struct is_unsigned<const T> : is_unsigned<T>
|
||||
{
|
||||
|
||||
@ -377,7 +377,7 @@ namespace etl
|
||||
inline bool operator==(const pair<T1, T2>& a, const pair<T1, T2>& b)
|
||||
{
|
||||
#include "private/diagnostic_float_equal_push.h"
|
||||
return (a.first == b.first) && !(a.second < b.second) && !(a.second > b.second);
|
||||
return (a.first == b.first) && (a.second == b.second);
|
||||
#include "private/diagnostic_pop.h"
|
||||
}
|
||||
|
||||
|
||||
@ -3040,6 +3040,108 @@ namespace
|
||||
|
||||
CHECK_ARRAY_EQUAL(expected.data(), output.data(), expected.size());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_count_leading_zeros_signed_32)
|
||||
{
|
||||
// int32_t(-1) = 0xFFFFFFFF → 0 leading zeros
|
||||
CHECK_EQUAL(0, int(etl::count_leading_zeros(int32_t(-1))));
|
||||
|
||||
// int32_t(1) = 0x00000001 → 31 leading zeros
|
||||
CHECK_EQUAL(31, int(etl::count_leading_zeros(int32_t(1))));
|
||||
|
||||
// int32_t(0) = 0x00000000 → 32 leading zeros
|
||||
CHECK_EQUAL(32, int(etl::count_leading_zeros(int32_t(0))));
|
||||
|
||||
// int32_t(256) = 0x00000100 → 23 leading zeros
|
||||
CHECK_EQUAL(23, int(etl::count_leading_zeros(int32_t(256))));
|
||||
|
||||
// Verify against unsigned version
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
int32_t value = int32_t(1) << i;
|
||||
CHECK_EQUAL(int(etl::count_leading_zeros(uint32_t(value))), int(etl::count_leading_zeros(value)));
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_count_leading_zeros_signed_64)
|
||||
{
|
||||
CHECK_EQUAL(0, int(etl::count_leading_zeros(int64_t(-1))));
|
||||
CHECK_EQUAL(63, int(etl::count_leading_zeros(int64_t(1))));
|
||||
CHECK_EQUAL(64, int(etl::count_leading_zeros(int64_t(0))));
|
||||
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
int64_t value = int64_t(1) << i;
|
||||
CHECK_EQUAL(int(etl::count_leading_zeros(uint64_t(value))), int(etl::count_leading_zeros(value)));
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_count_leading_zeros_64_specific_values)
|
||||
{
|
||||
// Value that specifically triggers the upper-32-bit mask path
|
||||
// Bit 35 set: 0x0000000800000000 → 28 leading zeros
|
||||
CHECK_EQUAL(28, int(etl::count_leading_zeros(uint64_t(0x0000000800000000ULL))));
|
||||
// Bit 31 set: 0x0000000080000000 → 32 leading zeros
|
||||
CHECK_EQUAL(32, int(etl::count_leading_zeros(uint64_t(0x0000000080000000ULL))));
|
||||
// All zeros in upper 32: 0x00000000FFFFFFFF → 32 leading zeros
|
||||
CHECK_EQUAL(32, int(etl::count_leading_zeros(uint64_t(0x00000000FFFFFFFFULL))));
|
||||
// Upper half has bit: 0x0000000100000000 → 31 leading zeros
|
||||
CHECK_EQUAL(31, int(etl::count_leading_zeros(uint64_t(0x0000000100000000ULL))));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_count_leading_ones_32_specific_values)
|
||||
{
|
||||
// 0xFFFF0000 → upper 16 bits set → exactly 16 leading ones
|
||||
CHECK_EQUAL(16, int(etl::count_leading_ones(uint32_t(0xFFFF0000UL))));
|
||||
// 0xFFFF8000 → 17 leading ones
|
||||
CHECK_EQUAL(17, int(etl::count_leading_ones(uint32_t(0xFFFF8000UL))));
|
||||
// 0xFFFFF000 → 20 leading ones
|
||||
CHECK_EQUAL(20, int(etl::count_leading_ones(uint32_t(0xFFFFF000UL))));
|
||||
// 0xFFFFFF00 → 24 leading ones
|
||||
CHECK_EQUAL(24, int(etl::count_leading_ones(uint32_t(0xFFFFFF00UL))));
|
||||
// 0xFFFFFFFE → 31 leading ones
|
||||
CHECK_EQUAL(31, int(etl::count_leading_ones(uint32_t(0xFFFFFFFEUL))));
|
||||
// 0xFFFFFFFF → 32 leading ones
|
||||
CHECK_EQUAL(32, int(etl::count_leading_ones(uint32_t(0xFFFFFFFFUL))));
|
||||
// 0x80000000 → 1 leading one
|
||||
CHECK_EQUAL(1, int(etl::count_leading_ones(uint32_t(0x80000000UL))));
|
||||
|
||||
// Verify against reference for boundary values
|
||||
for (uint32_t i = 0; i < 33; ++i)
|
||||
{
|
||||
// Create value with exactly 'i' leading ones
|
||||
uint32_t value = (i == 0) ? 0U : (i == 32) ? 0xFFFFFFFFUL : ~((1UL << (32U - i)) - 1UL);
|
||||
CHECK_EQUAL(int(test_leading_ones(value)), int(etl::count_leading_ones(value)));
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_count_leading_ones_64_specific_values)
|
||||
{
|
||||
// 0xFFFFFFFF00000000 → 32 leading ones
|
||||
CHECK_EQUAL(32, int(etl::count_leading_ones(uint64_t(0xFFFFFFFF00000000ULL))));
|
||||
// 0xFFFFFFFFFFFF0000 → 48 leading ones
|
||||
CHECK_EQUAL(48, int(etl::count_leading_ones(uint64_t(0xFFFFFFFFFFFF0000ULL))));
|
||||
// 0xFFFF000000000000 → 16 leading ones
|
||||
CHECK_EQUAL(16, int(etl::count_leading_ones(uint64_t(0xFFFF000000000000ULL))));
|
||||
// 0xFFFFFFFFFFFFFF00 → 56 leading ones
|
||||
CHECK_EQUAL(56, int(etl::count_leading_ones(uint64_t(0xFFFFFFFFFFFFFF00ULL))));
|
||||
// 0xFFFFFFFFFFFFFFFE → 63 leading ones
|
||||
CHECK_EQUAL(63, int(etl::count_leading_ones(uint64_t(0xFFFFFFFFFFFFFFFEULL))));
|
||||
// 0xFFFFFFFFFFFFFFFF → 64 leading ones
|
||||
CHECK_EQUAL(64, int(etl::count_leading_ones(uint64_t(0xFFFFFFFFFFFFFFFFULL))));
|
||||
|
||||
// Verify against reference for boundary values
|
||||
for (uint64_t i = 0; i < 65; ++i)
|
||||
{
|
||||
uint64_t value = (i == 0) ? 0ULL : (i == 64) ? 0xFFFFFFFFFFFFFFFFULL : ~((1ULL << (64ULL - i)) - 1ULL);
|
||||
CHECK_EQUAL(int(test_leading_ones(value)), int(etl::count_leading_ones(value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -1072,5 +1072,30 @@ namespace
|
||||
|
||||
CHECK(!is_equal);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_move_assignment_actually_moves)
|
||||
{
|
||||
DataM data;
|
||||
data.push(ItemM("A"));
|
||||
data.push(ItemM("B"));
|
||||
data.push(ItemM("C"));
|
||||
|
||||
DataM data2;
|
||||
data2 = std::move(data);
|
||||
|
||||
CHECK_EQUAL(3U, data2.size());
|
||||
|
||||
// If the move was correct, data2 should hold the moved-to values
|
||||
CHECK_EQUAL("A", data2[0].value);
|
||||
CHECK_EQUAL("B", data2[1].value);
|
||||
CHECK_EQUAL("C", data2[2].value);
|
||||
|
||||
// Original should be moved-from (empty strings with move-only type)
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
CHECK(data[i].value.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -2272,6 +2272,29 @@ namespace
|
||||
|
||||
CHECK(std::equal(blank_data.begin(), blank_data.end(), data.begin()));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_const_iterator_subscript)
|
||||
{
|
||||
DataNDC data(initial_data.begin(), initial_data.end());
|
||||
|
||||
const DataNDC& cdata = data;
|
||||
|
||||
// Access via const_iterator operator[]
|
||||
DataNDC::const_iterator cit = cdata.begin();
|
||||
|
||||
// Verify operator[] returns values matching sequential access
|
||||
for (size_t i = 0; i < cdata.size(); ++i)
|
||||
{
|
||||
CHECK(cit[i] == cdata[i]);
|
||||
}
|
||||
|
||||
// Verify const_iterator operator[] returns const_reference
|
||||
// (This is a compile-time check - if the fix is reverted,
|
||||
// the type would be non-const reference which is incorrect for const_iterator)
|
||||
const NDC& ref = cit[0];
|
||||
CHECK(ref == cdata[0]);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -1616,5 +1616,26 @@ namespace
|
||||
Error result = exp.error_or(Error("default"));
|
||||
CHECK_EQUAL("real_error", result.e);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_unexpected_error_const_rvalue_ref)
|
||||
{
|
||||
const etl::unexpected<Error> ue(Error("test_error"));
|
||||
|
||||
// Move from const rvalue — should get const Error&&
|
||||
const Error&& ref = std::move(ue).error();
|
||||
CHECK_EQUAL("test_error", ref.e);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_transform_error_void_const_rvalue)
|
||||
{
|
||||
const etl::expected<void, Error> exp(etl::unexpected<Error>(Error("original")));
|
||||
|
||||
auto result = std::move(exp).transform_error([](const Error& e) { return Error(e.e + "_transformed"); });
|
||||
|
||||
CHECK_FALSE(result.has_value());
|
||||
CHECK_EQUAL("original_transformed", result.error().e);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -1444,6 +1444,28 @@ namespace
|
||||
CHECK_EQUAL(ItemNDC("F"), *itr++);
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_forward_list_exception_types)
|
||||
{
|
||||
// Verify exception class hierarchy is correct
|
||||
CHECK(true == (std::is_base_of<etl::exception, etl::forward_list_exception>::value));
|
||||
CHECK(true == (std::is_base_of<etl::forward_list_exception, etl::forward_list_full>::value));
|
||||
CHECK(true == (std::is_base_of<etl::forward_list_exception, etl::forward_list_empty>::value));
|
||||
CHECK(true == (std::is_base_of<etl::forward_list_exception, etl::forward_list_iterator>::value));
|
||||
|
||||
#if defined(ETL_VERBOSE_ERRORS)
|
||||
// When verbose errors are enabled, check the error text contains "forward_list"
|
||||
etl::forward_list_full ex_full(__FILE__, __LINE__);
|
||||
etl::forward_list_empty ex_empty(__FILE__, __LINE__);
|
||||
|
||||
std::string full_msg(ex_full.what());
|
||||
std::string empty_msg(ex_empty.what());
|
||||
|
||||
CHECK(full_msg.find("forward_list") != std::string::npos);
|
||||
CHECK(empty_msg.find("forward_list") != std::string::npos);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
} // namespace
|
||||
|
||||
@ -332,5 +332,59 @@ namespace
|
||||
isEqual = std::equal(output2.begin(), output2.end(), histogram.begin());
|
||||
CHECK(isEqual);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_sparse_histogram_iteration)
|
||||
{
|
||||
StringHistogram histogram;
|
||||
|
||||
// Empty histogram: begin == end
|
||||
CHECK(histogram.begin() == histogram.end());
|
||||
CHECK(histogram.cbegin() == histogram.cend());
|
||||
|
||||
// Add items
|
||||
histogram.add(std::string("apple"));
|
||||
histogram.add(std::string("banana"));
|
||||
histogram.add(std::string("apple"));
|
||||
|
||||
// Non-empty: begin != end
|
||||
CHECK(histogram.begin() != histogram.end());
|
||||
CHECK(histogram.cbegin() != histogram.cend());
|
||||
|
||||
// Count elements by iterating
|
||||
size_t count = 0;
|
||||
for (auto it = histogram.begin(); it != histogram.end(); ++it)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
CHECK_EQUAL(2U, count); // "apple" and "banana"
|
||||
|
||||
// Same with cbegin/cend
|
||||
count = 0;
|
||||
for (auto it = histogram.cbegin(); it != histogram.cend(); ++it)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
CHECK_EQUAL(2U, count);
|
||||
|
||||
// Verify we can find the expected values
|
||||
bool found_apple = false;
|
||||
bool found_banana = false;
|
||||
for (auto it = histogram.begin(); it != histogram.end(); ++it)
|
||||
{
|
||||
if (it->first == "apple")
|
||||
{
|
||||
CHECK_EQUAL(2, it->second);
|
||||
found_apple = true;
|
||||
}
|
||||
if (it->first == "banana")
|
||||
{
|
||||
CHECK_EQUAL(1, it->second);
|
||||
found_banana = true;
|
||||
}
|
||||
}
|
||||
CHECK(found_apple);
|
||||
CHECK(found_banana);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -1845,5 +1845,15 @@ namespace
|
||||
CHECK(c.etl_left == nullptr);
|
||||
CHECK(c.etl_right == nullptr);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_link_clear_range_bidirectional_nullptr)
|
||||
{
|
||||
// Passing nullptr should be a no-op, not a crash
|
||||
BData* null_ptr = nullptr;
|
||||
etl::link_clear_range<BLink0>(null_ptr);
|
||||
// If we get here without crashing, the test passes
|
||||
CHECK(true);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -5475,5 +5475,32 @@ namespace
|
||||
CHECK(text1 == sstream_view);
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_find_char_pointer_n_shorter_than_strlen)
|
||||
{
|
||||
const value_t haystack_str[] = STR("Hello World");
|
||||
|
||||
TextSTD compare(haystack_str);
|
||||
TextL text(haystack_str);
|
||||
|
||||
// Haystack is "Hello World" (size 11).
|
||||
// search_str is "Worldly" (strlen 7).
|
||||
// We search for first 5 chars ("World") starting at pos=6.
|
||||
// Old code: (6 + 7 = 13) > 11 → premature npos (BUG)
|
||||
// Fixed: (6 + 5 = 11) <= 11 → proceeds to search → finds at 6
|
||||
const value_t search_str[] = STR("Worldly");
|
||||
|
||||
size_t pos_std = compare.find(search_str, 6, 5);
|
||||
size_t pos_etl = text.find(search_str, 6, 5);
|
||||
CHECK_EQUAL(6U, pos_std);
|
||||
CHECK_EQUAL(pos_std, pos_etl);
|
||||
|
||||
// pos=5 also triggers: (5 + 7 = 12) > 11 with old code
|
||||
pos_std = compare.find(search_str, 5, 5);
|
||||
pos_etl = text.find(search_str, 5, 5);
|
||||
CHECK_EQUAL(6U, pos_std);
|
||||
CHECK_EQUAL(pos_std, pos_etl);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -877,7 +877,7 @@ namespace
|
||||
CHECK(2U == view.rfind(s2, 5));
|
||||
CHECK(View::npos == view.rfind(s4));
|
||||
|
||||
CHECK(1U == view.rfind(s3, 5, 2));
|
||||
CHECK(5U == view.rfind(s3, 5, 2));
|
||||
CHECK(View::npos == view.rfind(s4, 0, 11));
|
||||
}
|
||||
|
||||
@ -1183,5 +1183,40 @@ namespace
|
||||
CHECK_TRUE(u32view == u32sstream_view);
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_rfind_boundary_positions)
|
||||
{
|
||||
etl::string_view sv("abcabc");
|
||||
|
||||
// rfind "abc" with position=3: should find the second "abc" at position 3
|
||||
size_t pos = sv.rfind(etl::string_view("abc"), 3);
|
||||
CHECK_EQUAL(3U, pos);
|
||||
|
||||
// rfind "abc" with position=2: should find only the first "abc" at position 0
|
||||
pos = sv.rfind(etl::string_view("abc"), 2);
|
||||
CHECK_EQUAL(0U, pos);
|
||||
|
||||
// rfind "abc" with position=0: should find at position 0
|
||||
pos = sv.rfind(etl::string_view("abc"), 0);
|
||||
CHECK_EQUAL(0U, pos);
|
||||
|
||||
// rfind with npos (search entire string)
|
||||
pos = sv.rfind(etl::string_view("abc"));
|
||||
CHECK_EQUAL(3U, pos);
|
||||
|
||||
// rfind something not found
|
||||
pos = sv.rfind(etl::string_view("xyz"));
|
||||
CHECK_EQUAL(etl::string_view::npos, pos);
|
||||
|
||||
// Compare with std::string to verify exact behavior
|
||||
std::string std_sv("abcabc");
|
||||
for (size_t p = 0; p <= std_sv.size(); ++p)
|
||||
{
|
||||
size_t std_pos = std_sv.rfind("abc", p);
|
||||
size_t etl_pos = sv.rfind(etl::string_view("abc"), p);
|
||||
CHECK_EQUAL(std_pos, etl_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -2247,6 +2247,25 @@ namespace
|
||||
CHECK_FALSE((etl::is_object_v<int&>));
|
||||
CHECK_FALSE((etl::is_object_v<int&&>));
|
||||
CHECK_FALSE((etl::is_object_v<decltype(f)>));
|
||||
#endif
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_is_signed_unsigned_char_types)
|
||||
{
|
||||
#if ETL_HAS_NATIVE_CHAR8_T
|
||||
CHECK_FALSE(etl::is_signed<char8_t>::value);
|
||||
CHECK_TRUE(etl::is_unsigned<char8_t>::value);
|
||||
#endif
|
||||
|
||||
#if ETL_HAS_NATIVE_CHAR16_T
|
||||
CHECK_FALSE(etl::is_signed<char16_t>::value);
|
||||
CHECK_TRUE(etl::is_unsigned<char16_t>::value);
|
||||
#endif
|
||||
|
||||
#if ETL_HAS_NATIVE_CHAR32_T
|
||||
CHECK_FALSE(etl::is_signed<char32_t>::value);
|
||||
CHECK_TRUE(etl::is_unsigned<char32_t>::value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1047,5 +1047,51 @@ namespace
|
||||
CHECK_EQUAL(expect1c, result1g);
|
||||
#endif
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_pair_equality_uses_equality_operator)
|
||||
{
|
||||
// Basic equality
|
||||
etl::pair<int, int> p1(1, 2);
|
||||
etl::pair<int, int> p2(1, 2);
|
||||
etl::pair<int, int> p3(1, 3);
|
||||
etl::pair<int, int> p4(2, 2);
|
||||
|
||||
CHECK_TRUE(p1 == p2);
|
||||
CHECK_FALSE(p1 == p3); // different second
|
||||
CHECK_FALSE(p1 == p4); // different first
|
||||
|
||||
// Custom type where operator== and operator< can disagree
|
||||
// The old code used !(a<b) && !(a>b), which is NOT equivalent to a==b
|
||||
// for types that don't define a total order consistent with equality.
|
||||
struct WeirdType
|
||||
{
|
||||
int value;
|
||||
bool equal_flag;
|
||||
|
||||
bool operator==(const WeirdType& other) const
|
||||
{
|
||||
return equal_flag && other.equal_flag;
|
||||
}
|
||||
bool operator<(const WeirdType& other) const
|
||||
{
|
||||
return value < other.value;
|
||||
}
|
||||
bool operator>(const WeirdType& other) const
|
||||
{
|
||||
return value > other.value;
|
||||
}
|
||||
};
|
||||
|
||||
WeirdType w1{1, false};
|
||||
WeirdType w2{1, false}; // same value, but equal_flag is false
|
||||
|
||||
// With proper ==: w1 == w2 should be false (both equal_flags are false)
|
||||
// With old !(w1<w2)&&!(w1>w2): would be true (same value)
|
||||
etl::pair<int, WeirdType> pw1(0, w1);
|
||||
etl::pair<int, WeirdType> pw2(0, w2);
|
||||
|
||||
CHECK_FALSE(pw1 == pw2); // This would FAIL with the old < > based comparison
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user