#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif
#include "src/objects/js-segment-iterator.h"
#include <map>
#include <memory>
#include <string>
#include <utility>
#include "src/execution/isolate.h"
#include "src/heap/factory.h"
#include "src/objects/intl-objects.h"
#include "src/objects/js-segment-iterator-inl.h"
#include "src/objects/js-segments.h"
#include "src/objects/managed-inl.h"
#include "src/objects/objects-inl.h"
#include "unicode/brkiter.h"
namespace v8 {
namespace internal {
Handle<String> JSSegmentIterator::GranularityAsString(Isolate* isolate) const {
return JSSegmenter::GetGranularityString(isolate, granularity());
}
MaybeDirectHandle<JSSegmentIterator> JSSegmentIterator::Create(
Isolate* isolate, DirectHandle<String> input_string,
const icu::BreakIterator& incoming_break_iterator,
JSSegmenter::Granularity granularity) {
std::unique_ptr<icu::BreakIterator> cloned_iterator{
incoming_break_iterator.clone()};
auto iterator_with_text = std::make_shared<IcuBreakIteratorWithText>(
isolate, std::move(cloned_iterator), input_string);
DirectHandle<Managed<IcuBreakIteratorWithText>> managed =
Managed<IcuBreakIteratorWithText>::From(isolate, 0, iterator_with_text);
iterator_with_text->iterator()->first();
DirectHandle<Map> map(isolate->native_context()->intl_segment_iterator_map(),
isolate);
DirectHandle<JSObject> result = isolate->factory()->NewJSObjectFromMap(map);
DisallowGarbageCollection no_gc;
DirectHandle<JSSegmentIterator> segment_iterator =
Cast<JSSegmentIterator>(result);
segment_iterator->set_flags(0);
segment_iterator->set_granularity(granularity);
segment_iterator->set_icu_iterator_with_text(*managed);
segment_iterator->set_raw_string(*input_string);
return segment_iterator;
}
MaybeDirectHandle<JSReceiver> JSSegmentIterator::Next(
Isolate* isolate, DirectHandle<JSSegmentIterator> segment_iterator) {
STACK_CHECK(isolate, MaybeDirectHandle<JSReceiver>());
Factory* factory = isolate->factory();
IcuBreakIteratorWithText* const iterator_with_text =
segment_iterator->icu_iterator_with_text()->raw();
icu::BreakIterator* const icu_break_iterator = iterator_with_text->iterator();
int32_t start_index = icu_break_iterator->current();
int32_t end_index = icu_break_iterator->next();
if (end_index == icu::BreakIterator::DONE) {
return factory->NewJSIteratorResult(isolate->factory()->undefined_value(),
true);
}
DirectHandle<JSSegmentDataObject> segment_data;
if (segment_iterator->granularity() == JSSegmenter::Granularity::GRAPHEME &&
start_index == end_index - 1) {
DirectHandle<String> segment;
uint16_t code = segment_iterator->raw_string()->Get(start_index);
if (code > unibrow::Latin1::kMaxChar) {
segment = factory->LookupSingleCharacterStringFromCode(code);
}
DirectHandle<Number> index;
if (!Smi::IsValid(start_index)) index = factory->NewHeapNumber(start_index);
DirectHandle<Map> map(
isolate->native_context()->intl_segment_data_object_map(), isolate);
segment_data = Cast<JSSegmentDataObject>(factory->NewJSObjectFromMap(map));
Tagged<JSSegmentDataObject> raw = *segment_data;
DisallowHeapAllocation no_gc;
raw->set_segment(code <= unibrow::Latin1::kMaxChar
? ReadOnlyRoots(isolate).single_character_string(code)
: *segment,
SKIP_WRITE_BARRIER);
raw->set_index(
Smi::IsValid(start_index) ? Smi::FromInt(start_index) : *index,
SKIP_WRITE_BARRIER);
raw->set_input(segment_iterator->raw_string(), SKIP_WRITE_BARRIER);
} else {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, segment_data,
JSSegments::CreateSegmentDataObject(
isolate, segment_iterator->granularity(), icu_break_iterator,
direct_handle(segment_iterator->raw_string(), isolate),
*iterator_with_text->text(), start_index, end_index));
}
return factory->NewJSIteratorResult(segment_data, false);
}
}
}