1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_INTL_SUPPORT
6#error Internationalization is expected to be enabled.
7#endif  // V8_INTL_SUPPORT
8
9#include "src/objects/js-segment-iterator.h"
10
11#include <map>
12#include <memory>
13#include <string>
14
15#include "src/execution/isolate.h"
16#include "src/heap/factory.h"
17#include "src/objects/intl-objects.h"
18#include "src/objects/js-segment-iterator-inl.h"
19#include "src/objects/js-segments.h"
20#include "src/objects/managed-inl.h"
21#include "src/objects/objects-inl.h"
22#include "unicode/brkiter.h"
23
24namespace v8 {
25namespace internal {
26
27Handle<String> JSSegmentIterator::GranularityAsString(Isolate* isolate) const {
28  return JSSegmenter::GetGranularityString(isolate, granularity());
29}
30
31// ecma402 #sec-createsegmentiterator
32MaybeHandle<JSSegmentIterator> JSSegmentIterator::Create(
33    Isolate* isolate, icu::BreakIterator* break_iterator,
34    JSSegmenter::Granularity granularity) {
35  // Clone a copy for both the ownership and not sharing with containing and
36  // other calls to the iterator because icu::BreakIterator keep the iteration
37  // position internally and cannot be shared across multiple calls to
38  // JSSegmentIterator::Create and JSSegments::Containing.
39  break_iterator = break_iterator->clone();
40  DCHECK_NOT_NULL(break_iterator);
41  Handle<Map> map = Handle<Map>(
42      isolate->native_context()->intl_segment_iterator_map(), isolate);
43
44  // 5. Set iterator.[[IteratedStringNextSegmentCodeUnitIndex]] to 0.
45  break_iterator->first();
46  Handle<Managed<icu::BreakIterator>> managed_break_iterator =
47      Managed<icu::BreakIterator>::FromRawPtr(isolate, 0, break_iterator);
48
49  icu::UnicodeString* string = new icu::UnicodeString();
50  break_iterator->getText().getText(*string);
51  Handle<Managed<icu::UnicodeString>> unicode_string =
52      Managed<icu::UnicodeString>::FromRawPtr(isolate, 0, string);
53
54  break_iterator->setText(*string);
55
56  // Now all properties are ready, so we can allocate the result object.
57  Handle<JSObject> result = isolate->factory()->NewJSObjectFromMap(map);
58  DisallowGarbageCollection no_gc;
59  Handle<JSSegmentIterator> segment_iterator =
60      Handle<JSSegmentIterator>::cast(result);
61
62  segment_iterator->set_flags(0);
63  segment_iterator->set_granularity(granularity);
64  segment_iterator->set_icu_break_iterator(*managed_break_iterator);
65  segment_iterator->set_unicode_string(*unicode_string);
66
67  return segment_iterator;
68}
69
70// ecma402 #sec-%segmentiteratorprototype%.next
71MaybeHandle<JSReceiver> JSSegmentIterator::Next(
72    Isolate* isolate, Handle<JSSegmentIterator> segment_iterator) {
73  Factory* factory = isolate->factory();
74  icu::BreakIterator* icu_break_iterator =
75      segment_iterator->icu_break_iterator().raw();
76  // 5. Let startIndex be iterator.[[IteratedStringNextSegmentCodeUnitIndex]].
77  int32_t start_index = icu_break_iterator->current();
78  // 6. Let endIndex be ! FindBoundary(segmenter, string, startIndex, after).
79  int32_t end_index = icu_break_iterator->next();
80
81  // 7. If endIndex is not finite, then
82  if (end_index == icu::BreakIterator::DONE) {
83    // a. Return ! CreateIterResultObject(undefined, true).
84    return factory->NewJSIteratorResult(isolate->factory()->undefined_value(),
85                                        true);
86  }
87
88  // 8. Set iterator.[[IteratedStringNextSegmentCodeUnitIndex]] to endIndex.
89
90  // 9. Let segmentData be ! CreateSegmentDataObject(segmenter, string,
91  // startIndex, endIndex).
92
93  icu::UnicodeString string;
94  icu_break_iterator->getText().getText(string);
95
96  Handle<Object> segment_data;
97  ASSIGN_RETURN_ON_EXCEPTION(
98      isolate, segment_data,
99      JSSegments::CreateSegmentDataObject(
100          isolate, segment_iterator->granularity(), icu_break_iterator, string,
101          start_index, end_index),
102      JSReceiver);
103
104  // 10. Return ! CreateIterResultObject(segmentData, false).
105  return factory->NewJSIteratorResult(segment_data, false);
106}
107
108}  // namespace internal
109}  // namespace v8
110