mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 22:44:49 +00:00
ICU-23004 specific iterator_category etc
This commit is contained in:
parent
d73daaf77f
commit
86bc5584cc
2 changed files with 78 additions and 10 deletions
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <iterator>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#ifdef UTYPES_H
|
||||
#include "unicode/utf16.h"
|
||||
#include "unicode/utf8.h"
|
||||
|
@ -128,8 +129,6 @@ public:
|
|||
|
||||
uint8_t length() const { return len; }
|
||||
|
||||
// TODO: Do we even need the template logic here?
|
||||
// Or is it disabled anyway if the code does not compile with a non-pointer?
|
||||
template<typename Iter = UnitIter>
|
||||
std::enable_if_t<
|
||||
std::is_pointer_v<Iter>,
|
||||
|
@ -536,8 +535,17 @@ class UTFIterator {
|
|||
};
|
||||
|
||||
public:
|
||||
// TODO: Should these Iterators define value_type etc.?
|
||||
// What about iterator_category depending on the UnitIter??
|
||||
using value_type = CodeUnits<UnitIter, CP32>;
|
||||
// TODO: review the reference and pointer types. Should pointer be Proxy?
|
||||
using reference = value_type &;
|
||||
using pointer = value_type *;
|
||||
using difference_type = typename std::iterator_traits<UnitIter>::difference_type;
|
||||
using iterator_category = std::conditional_t<
|
||||
std::is_base_of_v<
|
||||
std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<UnitIter>::iterator_category>,
|
||||
std::bidirectional_iterator_tag,
|
||||
std::forward_iterator_tag>;
|
||||
|
||||
// TODO: Maybe std::move() the UnitIters?
|
||||
// TODO: We might try to support limit==nullptr, similar to U16_ macros supporting length<0.
|
||||
|
@ -610,7 +618,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
inline UTFIterator &operator--() { // pre-decrement
|
||||
template<typename Iter = UnitIter>
|
||||
inline
|
||||
std::enable_if_t<
|
||||
std::is_base_of_v<
|
||||
std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<Iter>::iterator_category>,
|
||||
UTFIterator &>
|
||||
operator--() { // pre-decrement
|
||||
if (state_ > 0) {
|
||||
// operator*() called readAndInc() so p_ is ahead of the logical position.
|
||||
Impl::moveToReadAndIncStart(p_, state_);
|
||||
|
@ -620,7 +635,14 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
inline UTFIterator operator--(int) { // post-decrement
|
||||
template<typename Iter = UnitIter>
|
||||
inline
|
||||
std::enable_if_t<
|
||||
std::is_base_of_v<
|
||||
std::bidirectional_iterator_tag,
|
||||
typename std::iterator_traits<Iter>::iterator_category>,
|
||||
UTFIterator>
|
||||
operator--(int) { // post-decrement
|
||||
UTFIterator result(*this);
|
||||
operator--();
|
||||
return result;
|
||||
|
@ -671,8 +693,11 @@ class UTFIterator<
|
|||
};
|
||||
|
||||
public:
|
||||
// TODO: Should these Iterators define value_type etc.?
|
||||
// What about iterator_category depending on the UnitIter??
|
||||
using value_type = CodeUnits<UnitIter, CP32>;
|
||||
using reference = value_type &;
|
||||
using pointer = value_type *;
|
||||
using difference_type = typename std::iterator_traits<UnitIter>::difference_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
// TODO: Does it make sense for the limits to allow having a different type?
|
||||
// We only need to be able to compare p_ vs. limit_ for == and !=.
|
||||
|
@ -779,6 +804,12 @@ class UTFReverseIterator {
|
|||
};
|
||||
|
||||
public:
|
||||
using value_type = CodeUnits<UnitIter, CP32>;
|
||||
using reference = value_type &;
|
||||
using pointer = value_type *;
|
||||
using difference_type = typename std::iterator_traits<UnitIter>::difference_type;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
inline UTFReverseIterator(UnitIter start, UnitIter p) : p_(p), start_(start) {}
|
||||
// Constructs an iterator start or limit sentinel.
|
||||
inline UTFReverseIterator(UnitIter p) : p_(p), start_(p) {}
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
typedef Unit value_type;
|
||||
typedef Unit &reference;
|
||||
typedef Unit *pointer;
|
||||
typedef size_t difference_type;
|
||||
typedef ssize_t difference_type;
|
||||
// This is a LegacyIterator but there is no specific category for that,
|
||||
// so we claim it to be a LegacyInputIterator. It *is* single-pass.
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
|
@ -83,7 +83,7 @@ public:
|
|||
typedef Unit value_type;
|
||||
typedef Unit &reference;
|
||||
typedef Unit *pointer;
|
||||
typedef size_t difference_type;
|
||||
typedef ssize_t difference_type;
|
||||
// https://en.cppreference.com/w/cpp/named_req/ForwardIterator#Multi-pass_guarantee
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
|
@ -142,6 +142,13 @@ void U16IteratorTest::runIndexedTest(int32_t index, UBool exec, const char *&nam
|
|||
void U16IteratorTest::testGood() {
|
||||
std::u16string_view good(u"abçカ🚴"sv);
|
||||
UTFStringCodePoints<char16_t, UChar32, U_BEHAVIOR_NEGATIVE> range(good);
|
||||
// TODO: Try to un-hardcode the iterator types in these checks via declspec.
|
||||
assertTrue(
|
||||
"bidirectional_iterator_tag",
|
||||
std::is_same_v<
|
||||
typename std::iterator_traits<
|
||||
UTFIterator<char16_t *, UChar32, U_BEHAVIOR_NEGATIVE>>::iterator_category,
|
||||
std::bidirectional_iterator_tag>);
|
||||
auto iter = range.begin();
|
||||
assertEquals("iter[0] * codePoint", u'a', (*iter).codePoint());
|
||||
assertEquals("iter[0] -> codePoint", u'a', iter->codePoint());
|
||||
|
@ -245,6 +252,12 @@ void U16IteratorTest::testSinglePassIter() {
|
|||
UTFIterator<SinglePassIter<char16_t>, UChar32, U_BEHAVIOR_NEGATIVE> rangeBegin(
|
||||
goodBegin, goodLimit);
|
||||
UTFIterator<SinglePassIter<char16_t>, UChar32, U_BEHAVIOR_NEGATIVE> rangeLimit(goodLimit);
|
||||
assertTrue(
|
||||
"input_iterator_tag",
|
||||
std::is_same_v<
|
||||
typename std::iterator_traits<
|
||||
UTFIterator<SinglePassIter<char16_t>, UChar32, U_BEHAVIOR_NEGATIVE>>::iterator_category,
|
||||
std::input_iterator_tag>);
|
||||
auto iter = rangeBegin;
|
||||
assertEquals("iter[0] * codePoint", u'a', (*iter).codePoint());
|
||||
assertEquals("iter[0] -> codePoint", u'a', iter->codePoint());
|
||||
|
@ -275,6 +288,12 @@ void U16IteratorTest::testFwdIter() {
|
|||
UTFIterator<FwdIter<char16_t>, UChar32, U_BEHAVIOR_NEGATIVE> rangeBegin(goodBegin, goodLimit);
|
||||
UTFIterator<FwdIter<char16_t>, UChar32, U_BEHAVIOR_NEGATIVE> rangeLimit(goodLimit);
|
||||
// TODO: UTFStringCodePoints<FwdIter, UChar32, U_BEHAVIOR_NEGATIVE> range(good);
|
||||
assertTrue(
|
||||
"forward_iterator_tag",
|
||||
std::is_same_v<
|
||||
typename std::iterator_traits<
|
||||
UTFIterator<FwdIter<char16_t>, UChar32, U_BEHAVIOR_NEGATIVE>>::iterator_category,
|
||||
std::forward_iterator_tag>);
|
||||
auto iter = rangeBegin;
|
||||
assertEquals("iter[0] * codePoint", u'a', (*iter).codePoint());
|
||||
assertEquals("iter[0] -> codePoint", u'a', iter->codePoint());
|
||||
|
@ -336,6 +355,12 @@ void U8IteratorTest::runIndexedTest(int32_t index, UBool exec, const char *&name
|
|||
void U8IteratorTest::testGood() {
|
||||
std::string_view good(reinterpret_cast<const char*>(u8"abçカ🚴"));
|
||||
UTFStringCodePoints<char, UChar32, U_BEHAVIOR_NEGATIVE> range(good);
|
||||
assertTrue(
|
||||
"bidirectional_iterator_tag",
|
||||
std::is_same_v<
|
||||
typename std::iterator_traits<
|
||||
UTFIterator<char *, UChar32, U_BEHAVIOR_NEGATIVE>>::iterator_category,
|
||||
std::bidirectional_iterator_tag>);
|
||||
auto iter = range.begin();
|
||||
assertEquals("iter[0] * codePoint", u'a', (*iter).codePoint());
|
||||
assertEquals("iter[0] -> codePoint", u'a', iter->codePoint());
|
||||
|
@ -368,6 +393,12 @@ void U8IteratorTest::testSinglePassIter() {
|
|||
UTFIterator<SinglePassIter<char>, UChar32, U_BEHAVIOR_NEGATIVE> rangeBegin(
|
||||
goodBegin, goodLimit);
|
||||
UTFIterator<SinglePassIter<char>, UChar32, U_BEHAVIOR_NEGATIVE> rangeLimit(goodLimit);
|
||||
assertTrue(
|
||||
"input_iterator_tag",
|
||||
std::is_same_v<
|
||||
typename std::iterator_traits<
|
||||
UTFIterator<SinglePassIter<char>, UChar32, U_BEHAVIOR_NEGATIVE>>::iterator_category,
|
||||
std::input_iterator_tag>);
|
||||
auto iter = rangeBegin;
|
||||
assertEquals("iter[0] * codePoint", u'a', (*iter).codePoint());
|
||||
assertEquals("iter[0] -> codePoint", u'a', iter->codePoint());
|
||||
|
@ -398,6 +429,12 @@ void U8IteratorTest::testFwdIter() {
|
|||
UTFIterator<FwdIter<char>, UChar32, U_BEHAVIOR_NEGATIVE> rangeBegin(goodBegin, goodLimit);
|
||||
UTFIterator<FwdIter<char>, UChar32, U_BEHAVIOR_NEGATIVE> rangeLimit(goodLimit);
|
||||
// TODO: UTFStringCodePoints<FwdIter, UChar32, U_BEHAVIOR_NEGATIVE> range(good);
|
||||
assertTrue(
|
||||
"forward_iterator_tag",
|
||||
std::is_same_v<
|
||||
typename std::iterator_traits<
|
||||
UTFIterator<FwdIter<char>, UChar32, U_BEHAVIOR_NEGATIVE>>::iterator_category,
|
||||
std::forward_iterator_tag>);
|
||||
auto iter = rangeBegin;
|
||||
assertEquals("iter[0] * codePoint", u'a', (*iter).codePoint());
|
||||
assertEquals("iter[0] -> codePoint", u'a', iter->codePoint());
|
||||
|
|
Loading…
Add table
Reference in a new issue