1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef LIBTEXTCLASSIFIER_ANNOTATOR_TYPES_H_
18 #define LIBTEXTCLASSIFIER_ANNOTATOR_TYPES_H_
19
20 #include <time.h>
21
22 #include <algorithm>
23 #include <cmath>
24 #include <functional>
25 #include <map>
26 #include <set>
27 #include <string>
28 #include <unordered_set>
29 #include <utility>
30 #include <vector>
31
32 #include "annotator/entity-data_generated.h"
33 #include "utils/base/integral_types.h"
34 #include "utils/base/logging.h"
35 #include "utils/flatbuffers.h"
36 #include "utils/optional.h"
37 #include "utils/variant.h"
38
39 namespace libtextclassifier3 {
40
41 constexpr int kInvalidIndex = -1;
42 constexpr int kSunday = 1;
43 constexpr int kMonday = 2;
44 constexpr int kTuesday = 3;
45 constexpr int kWednesday = 4;
46 constexpr int kThursday = 5;
47 constexpr int kFriday = 6;
48 constexpr int kSaturday = 7;
49
50 // Index for a 0-based array of tokens.
51 using TokenIndex = int;
52
53 // Index for a 0-based array of codepoints.
54 using CodepointIndex = int;
55
56 // Marks a span in a sequence of codepoints. The first element is the index of
57 // the first codepoint of the span, and the second element is the index of the
58 // codepoint one past the end of the span.
59 // TODO(b/71982294): Make it a struct.
60 using CodepointSpan = std::pair<CodepointIndex, CodepointIndex>;
61
SpansOverlap(const CodepointSpan & a,const CodepointSpan & b)62 inline bool SpansOverlap(const CodepointSpan& a, const CodepointSpan& b) {
63 return a.first < b.second && b.first < a.second;
64 }
65
ValidNonEmptySpan(const CodepointSpan & span)66 inline bool ValidNonEmptySpan(const CodepointSpan& span) {
67 return span.first < span.second && span.first >= 0 && span.second >= 0;
68 }
69
70 template <typename T>
DoesCandidateConflict(const int considered_candidate,const std::vector<T> & candidates,const std::set<int,std::function<bool (int,int)>> & chosen_indices_set)71 bool DoesCandidateConflict(
72 const int considered_candidate, const std::vector<T>& candidates,
73 const std::set<int, std::function<bool(int, int)>>& chosen_indices_set) {
74 if (chosen_indices_set.empty()) {
75 return false;
76 }
77
78 auto conflicting_it = chosen_indices_set.lower_bound(considered_candidate);
79 // Check conflict on the right.
80 if (conflicting_it != chosen_indices_set.end() &&
81 SpansOverlap(candidates[considered_candidate].span,
82 candidates[*conflicting_it].span)) {
83 return true;
84 }
85
86 // Check conflict on the left.
87 // If we can't go more left, there can't be a conflict:
88 if (conflicting_it == chosen_indices_set.begin()) {
89 return false;
90 }
91 // Otherwise move one span left and insert if it doesn't overlap with the
92 // candidate.
93 --conflicting_it;
94 if (!SpansOverlap(candidates[considered_candidate].span,
95 candidates[*conflicting_it].span)) {
96 return false;
97 }
98
99 return true;
100 }
101
102 // Marks a span in a sequence of tokens. The first element is the index of the
103 // first token in the span, and the second element is the index of the token one
104 // past the end of the span.
105 // TODO(b/71982294): Make it a struct.
106 using TokenSpan = std::pair<TokenIndex, TokenIndex>;
107
108 // Returns the size of the token span. Assumes that the span is valid.
TokenSpanSize(const TokenSpan & token_span)109 inline int TokenSpanSize(const TokenSpan& token_span) {
110 return token_span.second - token_span.first;
111 }
112
113 // Returns a token span consisting of one token.
SingleTokenSpan(int token_index)114 inline TokenSpan SingleTokenSpan(int token_index) {
115 return {token_index, token_index + 1};
116 }
117
118 // Returns an intersection of two token spans. Assumes that both spans are valid
119 // and overlapping.
IntersectTokenSpans(const TokenSpan & token_span1,const TokenSpan & token_span2)120 inline TokenSpan IntersectTokenSpans(const TokenSpan& token_span1,
121 const TokenSpan& token_span2) {
122 return {std::max(token_span1.first, token_span2.first),
123 std::min(token_span1.second, token_span2.second)};
124 }
125
126 // Returns and expanded token span by adding a certain number of tokens on its
127 // left and on its right.
ExpandTokenSpan(const TokenSpan & token_span,int num_tokens_left,int num_tokens_right)128 inline TokenSpan ExpandTokenSpan(const TokenSpan& token_span,
129 int num_tokens_left, int num_tokens_right) {
130 return {token_span.first - num_tokens_left,
131 token_span.second + num_tokens_right};
132 }
133
134 // Token holds a token, its position in the original string and whether it was
135 // part of the input span.
136 struct Token {
137 std::string value;
138 CodepointIndex start;
139 CodepointIndex end;
140
141 // Whether the token is a padding token.
142 bool is_padding;
143
144 // Whether the token contains only white characters.
145 bool is_whitespace;
146
147 // Default constructor constructs the padding-token.
TokenToken148 Token()
149 : Token(/*arg_value=*/"", /*arg_start=*/kInvalidIndex,
150 /*arg_end=*/kInvalidIndex, /*is_padding=*/true,
151 /*is_whitespace=*/false) {}
152
TokenToken153 Token(const std::string& arg_value, CodepointIndex arg_start,
154 CodepointIndex arg_end)
155 : Token(/*arg_value=*/arg_value, /*arg_start=*/arg_start,
156 /*arg_end=*/arg_end, /*is_padding=*/false,
157 /*is_whitespace=*/false) {}
158
TokenToken159 Token(const std::string& arg_value, CodepointIndex arg_start,
160 CodepointIndex arg_end, bool is_padding, bool is_whitespace)
161 : value(arg_value),
162 start(arg_start),
163 end(arg_end),
164 is_padding(is_padding),
165 is_whitespace(is_whitespace) {}
166
167 bool operator==(const Token& other) const {
168 return value == other.value && start == other.start && end == other.end &&
169 is_padding == other.is_padding;
170 }
171
IsContainedInSpanToken172 bool IsContainedInSpan(CodepointSpan span) const {
173 return start >= span.first && end <= span.second;
174 }
175 };
176
177 // Pretty-printing function for Token.
178 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
179 const Token& token);
180
181 enum DatetimeGranularity {
182 GRANULARITY_UNKNOWN = -1, // GRANULARITY_UNKNOWN is used as a proxy for this
183 // structure being uninitialized.
184 GRANULARITY_YEAR = 0,
185 GRANULARITY_MONTH = 1,
186 GRANULARITY_WEEK = 2,
187 GRANULARITY_DAY = 3,
188 GRANULARITY_HOUR = 4,
189 GRANULARITY_MINUTE = 5,
190 GRANULARITY_SECOND = 6
191 };
192
193 // This struct represents a unit of date and time expression.
194 // Examples include:
195 // - In {March 21, 2019} datetime components are month: {March},
196 // day of month: {21} and year: {2019}.
197 // - {8:00 am} contains hour: {8}, minutes: {0} and am/pm: {am}
198 struct DatetimeComponent {
199 enum class ComponentType {
200 UNSPECIFIED = 0,
201 // Year of the date seen in the text match.
202 YEAR = 1,
203 // Month of the year starting with January = 1.
204 MONTH = 2,
205 // Week (7 days).
206 WEEK = 3,
207 // Day of week, start of the week is Sunday & its value is 1.
208 DAY_OF_WEEK = 4,
209 // Day of the month starting with 1.
210 DAY_OF_MONTH = 5,
211 // Hour of the day with a range of 0-23,
212 // values less than 12 need the AMPM field below or heuristics
213 // to definitively determine the time.
214 HOUR = 6,
215 // Minute of the hour with a range of 0-59.
216 MINUTE = 7,
217 // Seconds of the minute with a range of 0-59.
218 SECOND = 8,
219 // Meridiem field where 0 == AM, 1 == PM.
220 MERIDIEM = 9,
221 // Number of hours offset from UTC this date time is in.
222 ZONE_OFFSET = 10,
223 // Number of hours offest for DST.
224 DST_OFFSET = 11,
225 };
226
227 // TODO(hassan): Remove RelativeQualifier as in the presence of relative
228 // count RelativeQualifier is redundant.
229 // Enum to represent the relative DateTimeComponent e.g. "next Monday",
230 // "the following day", "tomorrow".
231 enum class RelativeQualifier {
232 UNSPECIFIED = 0,
233 NEXT = 1,
234 THIS = 2,
235 LAST = 3,
236 NOW = 4,
237 TOMORROW = 5,
238 YESTERDAY = 6,
239 PAST = 7,
240 FUTURE = 8
241 };
242
243 bool operator==(const DatetimeComponent& other) const {
244 return component_type == other.component_type &&
245 relative_qualifier == other.relative_qualifier &&
246 relative_count == other.relative_count && value == other.value;
247 }
248
249 bool ShouldRoundToGranularity() const;
250
251 ComponentType component_type = ComponentType::UNSPECIFIED;
252 RelativeQualifier relative_qualifier = RelativeQualifier::UNSPECIFIED;
253
254 // Represents the absolute value of DateTime components.
255 int value = 0;
256 // The number of units of change present in the relative DateTimeComponent.
257 int relative_count = 0;
258
259 DatetimeComponent() = default;
260
DatetimeComponentDatetimeComponent261 explicit DatetimeComponent(ComponentType arg_component_type,
262 RelativeQualifier arg_relative_qualifier,
263 int arg_value, int arg_relative_count)
264 : component_type(arg_component_type),
265 relative_qualifier(arg_relative_qualifier),
266 value(arg_value),
267 relative_count(arg_relative_count) {}
268 };
269
270 // Utility method to calculate Returns the finest granularity of
271 // DatetimeComponents.
272 DatetimeGranularity GetFinestGranularity(
273 const std::vector<DatetimeComponent>& datetime_component);
274
275 // Return the 'DatetimeComponent' from collection filter by component type.
276 Optional<DatetimeComponent> GetDatetimeComponent(
277 const std::vector<DatetimeComponent>& datetime_components,
278 const DatetimeComponent::ComponentType& component_type);
279
280 struct DatetimeParseResult {
281 // The absolute time in milliseconds since the epoch in UTC.
282 int64 time_ms_utc;
283
284 // The precision of the estimate then in to calculating the milliseconds
285 DatetimeGranularity granularity;
286
287 // List of parsed DateTimeComponent.
288 std::vector<DatetimeComponent> datetime_components;
289
DatetimeParseResultDatetimeParseResult290 DatetimeParseResult() : time_ms_utc(0), granularity(GRANULARITY_UNKNOWN) {}
291
DatetimeParseResultDatetimeParseResult292 DatetimeParseResult(int64 arg_time_ms_utc,
293 DatetimeGranularity arg_granularity,
294 std::vector<DatetimeComponent> arg_datetime__components)
295 : time_ms_utc(arg_time_ms_utc),
296 granularity(arg_granularity),
297 datetime_components(arg_datetime__components) {}
298
IsSetDatetimeParseResult299 bool IsSet() const { return granularity != GRANULARITY_UNKNOWN; }
300
301 bool operator==(const DatetimeParseResult& other) const {
302 return granularity == other.granularity &&
303 time_ms_utc == other.time_ms_utc &&
304 datetime_components == other.datetime_components;
305 }
306 };
307
308 const float kFloatCompareEpsilon = 1e-5;
309
310 struct DatetimeParseResultSpan {
311 CodepointSpan span;
312 std::vector<DatetimeParseResult> data;
313 float target_classification_score;
314 float priority_score;
315
DatetimeParseResultSpanDatetimeParseResultSpan316 DatetimeParseResultSpan()
317 : target_classification_score(-1.0), priority_score(-1.0) {}
318
DatetimeParseResultSpanDatetimeParseResultSpan319 DatetimeParseResultSpan(const CodepointSpan& span,
320 const std::vector<DatetimeParseResult>& data,
321 const float target_classification_score,
322 const float priority_score) {
323 this->span = span;
324 this->data = data;
325 this->target_classification_score = target_classification_score;
326 this->priority_score = priority_score;
327 }
328
329 bool operator==(const DatetimeParseResultSpan& other) const {
330 return span == other.span && data == other.data &&
331 std::abs(target_classification_score -
332 other.target_classification_score) < kFloatCompareEpsilon &&
333 std::abs(priority_score - other.priority_score) <
334 kFloatCompareEpsilon;
335 }
336 };
337
338 // Pretty-printing function for DatetimeParseResultSpan.
339 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
340 const DatetimeParseResultSpan& value);
341
342 // This struct contains information intended to uniquely identify a device
343 // contact. Instances are created by the Knowledge Engine, and dereferenced by
344 // the Contact Engine.
345 struct ContactPointer {
346 std::string focus_contact_id;
347 std::string device_id;
348 std::string device_contact_id;
349 std::string contact_name;
350 std::string contact_name_hash;
351
352 bool operator==(const ContactPointer& other) const {
353 return focus_contact_id == other.focus_contact_id &&
354 device_id == other.device_id &&
355 device_contact_id == other.device_contact_id &&
356 contact_name == other.contact_name &&
357 contact_name_hash == other.contact_name_hash;
358 }
359 };
360
361 struct ClassificationResult {
362 std::string collection;
363 float score;
364 DatetimeParseResult datetime_parse_result;
365 std::string serialized_knowledge_result;
366 ContactPointer contact_pointer;
367 std::string contact_name, contact_given_name, contact_family_name,
368 contact_nickname, contact_email_address, contact_phone_number, contact_id;
369 std::string app_name, app_package_name;
370 int64 numeric_value;
371 double numeric_double_value;
372
373 // Length of the parsed duration in milliseconds.
374 int64 duration_ms;
375
376 // Internal score used for conflict resolution.
377 float priority_score;
378
379
380 // Entity data information.
381 std::string serialized_entity_data;
entity_dataClassificationResult382 const EntityData* entity_data() const {
383 return LoadAndVerifyFlatbuffer<EntityData>(serialized_entity_data.data(),
384 serialized_entity_data.size());
385 }
386
ClassificationResultClassificationResult387 explicit ClassificationResult()
388 : score(-1.0f),
389 numeric_value(0),
390 numeric_double_value(0.),
391 duration_ms(0),
392 priority_score(-1.0) {}
393
ClassificationResultClassificationResult394 ClassificationResult(const std::string& arg_collection, float arg_score)
395 : collection(arg_collection),
396 score(arg_score),
397 numeric_value(0),
398 numeric_double_value(0.),
399 duration_ms(0),
400 priority_score(arg_score) {}
401
ClassificationResultClassificationResult402 ClassificationResult(const std::string& arg_collection, float arg_score,
403 float arg_priority_score)
404 : collection(arg_collection),
405 score(arg_score),
406 numeric_value(0),
407 numeric_double_value(0.),
408 duration_ms(0),
409 priority_score(arg_priority_score) {}
410
411 bool operator!=(const ClassificationResult& other) const {
412 return !(*this == other);
413 }
414
415 bool operator==(const ClassificationResult& other) const;
416 };
417
418 // Aliases for long enum values.
419 const AnnotationUsecase ANNOTATION_USECASE_SMART =
420 AnnotationUsecase_ANNOTATION_USECASE_SMART;
421 const AnnotationUsecase ANNOTATION_USECASE_RAW =
422 AnnotationUsecase_ANNOTATION_USECASE_RAW;
423
424 struct LocationContext {
425 // User location latitude in degrees.
426 double user_location_lat = 180.;
427
428 // User location longitude in degrees.
429 double user_location_lng = 360.;
430
431 // The estimated horizontal accuracy of the user location in meters.
432 // Analogous to android.location.Location accuracy.
433 float user_location_accuracy_meters = 0.f;
434
435 bool operator==(const LocationContext& other) const {
436 return std::fabs(this->user_location_lat - other.user_location_lat) <
437 1e-8 &&
438 std::fabs(this->user_location_lng - other.user_location_lng) <
439 1e-8 &&
440 std::fabs(this->user_location_accuracy_meters -
441 other.user_location_accuracy_meters) < 1e-8;
442 }
443 };
444
445 struct BaseOptions {
446 // Comma-separated list of locale specification for the input text (BCP 47
447 // tags).
448 std::string locales;
449
450 // Comma-separated list of BCP 47 language tags.
451 std::string detected_text_language_tags;
452
453 // Tailors the output annotations according to the specified use-case.
454 AnnotationUsecase annotation_usecase = ANNOTATION_USECASE_SMART;
455
456 // The location context passed along with each annotation.
457 Optional<LocationContext> location_context;
458
459 bool operator==(const BaseOptions& other) const {
460 bool location_context_equality = this->location_context.has_value() ==
461 other.location_context.has_value();
462 if (this->location_context.has_value() &&
463 other.location_context.has_value()) {
464 location_context_equality =
465 this->location_context.value() == other.location_context.value();
466 }
467 return this->locales == other.locales &&
468 this->annotation_usecase == other.annotation_usecase &&
469 this->detected_text_language_tags ==
470 other.detected_text_language_tags &&
471 location_context_equality;
472 }
473 };
474
475 struct DatetimeOptions {
476 // For parsing relative datetimes, the reference now time against which the
477 // relative datetimes get resolved.
478 // UTC milliseconds since epoch.
479 int64 reference_time_ms_utc = 0;
480
481 // Timezone in which the input text was written (format as accepted by ICU).
482 std::string reference_timezone;
483
484 bool operator==(const DatetimeOptions& other) const {
485 return this->reference_time_ms_utc == other.reference_time_ms_utc &&
486 this->reference_timezone == other.reference_timezone;
487 }
488 };
489
490 struct SelectionOptions : public BaseOptions {};
491
492 struct ClassificationOptions : public BaseOptions, public DatetimeOptions {
493 // Comma-separated list of language tags which the user can read and
494 // understand (BCP 47).
495 std::string user_familiar_language_tags;
496
497 bool operator==(const ClassificationOptions& other) const {
498 return this->user_familiar_language_tags ==
499 other.user_familiar_language_tags &&
500 BaseOptions::operator==(other) && DatetimeOptions::operator==(other);
501 }
502 };
503
504 struct Permissions {
505 // If true the user location can be used to provide better annotations.
506 bool has_location_permission = true;
507 // If true, annotators can use personal data to provide personalized
508 // annotations.
509 bool has_personalization_permission = true;
510
511 bool operator==(const Permissions& other) const {
512 return this->has_location_permission == other.has_location_permission &&
513 this->has_personalization_permission ==
514 other.has_personalization_permission;
515 }
516 };
517
518 struct AnnotationOptions : public BaseOptions, public DatetimeOptions {
519 // List of entity types that should be used for annotation.
520 std::unordered_set<std::string> entity_types;
521
522 // If true, serialized_entity_data in the results is populated."
523 bool is_serialized_entity_data_enabled = false;
524
525 // Defines the permissions for the annotators.
526 Permissions permissions;
527
528 bool operator==(const AnnotationOptions& other) const {
529 return this->is_serialized_entity_data_enabled ==
530 other.is_serialized_entity_data_enabled &&
531 this->permissions == other.permissions &&
532 this->entity_types == other.entity_types &&
533 BaseOptions::operator==(other) && DatetimeOptions::operator==(other);
534 }
535 };
536
537 // Returns true when ClassificationResults are euqal up to scores.
538 bool ClassificationResultsEqualIgnoringScoresAndSerializedEntityData(
539 const ClassificationResult& a, const ClassificationResult& b);
540
541 // Pretty-printing function for ClassificationResult.
542 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
543 const ClassificationResult& result);
544
545 // Pretty-printing function for std::vector<ClassificationResult>.
546 logging::LoggingStringStream& operator<<(
547 logging::LoggingStringStream& stream,
548 const std::vector<ClassificationResult>& results);
549
550 // Represents a result of Annotate call.
551 struct AnnotatedSpan {
552 enum class Source { OTHER, KNOWLEDGE, DURATION, DATETIME, PERSON_NAME };
553
554 // Unicode codepoint indices in the input string.
555 CodepointSpan span = {kInvalidIndex, kInvalidIndex};
556
557 // Classification result for the span.
558 std::vector<ClassificationResult> classification;
559
560 // The source of the annotation, used in conflict resolution.
561 Source source = Source::OTHER;
562
563 AnnotatedSpan() = default;
564
AnnotatedSpanAnnotatedSpan565 AnnotatedSpan(CodepointSpan arg_span,
566 std::vector<ClassificationResult> arg_classification)
567 : span(arg_span), classification(std::move(arg_classification)) {}
568
AnnotatedSpanAnnotatedSpan569 AnnotatedSpan(CodepointSpan arg_span,
570 std::vector<ClassificationResult> arg_classification,
571 Source arg_source)
572 : span(arg_span),
573 classification(std::move(arg_classification)),
574 source(arg_source) {}
575 };
576
577 struct InputFragment {
578 std::string text;
579
580 // If present will override the AnnotationOptions reference time and timezone
581 // when annotating this specific string fragment.
582 Optional<DatetimeOptions> datetime_options;
583 };
584
585 // Pretty-printing function for AnnotatedSpan.
586 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
587 const AnnotatedSpan& span);
588
589 // StringPiece analogue for std::vector<T>.
590 template <class T>
591 class VectorSpan {
592 public:
VectorSpan()593 VectorSpan() : begin_(), end_() {}
VectorSpan(const std::vector<T> & v)594 VectorSpan(const std::vector<T>& v) // NOLINT(runtime/explicit)
595 : begin_(v.begin()), end_(v.end()) {}
VectorSpan(typename std::vector<T>::const_iterator begin,typename std::vector<T>::const_iterator end)596 VectorSpan(typename std::vector<T>::const_iterator begin,
597 typename std::vector<T>::const_iterator end)
598 : begin_(begin), end_(end) {}
599
600 const T& operator[](typename std::vector<T>::size_type i) const {
601 return *(begin_ + i);
602 }
603
size()604 int size() const { return end_ - begin_; }
begin()605 typename std::vector<T>::const_iterator begin() const { return begin_; }
end()606 typename std::vector<T>::const_iterator end() const { return end_; }
data()607 const float* data() const { return &(*begin_); }
608
609 private:
610 typename std::vector<T>::const_iterator begin_;
611 typename std::vector<T>::const_iterator end_;
612 };
613
614 // Class to provide representation of date and time expressions
615 class DatetimeParsedData {
616 public:
617 // Function to set the absolute value of DateTimeComponent for the given
618 // FieldType, if the field is not present it will create the field and set
619 // the value.
620 void SetAbsoluteValue(const DatetimeComponent::ComponentType& field_type,
621 int value);
622
623 // Function to set the relative value of DateTimeComponent, if the field is
624 // not present the function will create the field and set the relative value.
625 void SetRelativeValue(
626 const DatetimeComponent::ComponentType& field_type,
627 const DatetimeComponent::RelativeQualifier& relative_value);
628
629 // Add collection of 'DatetimeComponent' to 'DatetimeParsedData'.
630 void AddDatetimeComponents(
631 const std::vector<DatetimeComponent>& datetime_components);
632
633 // Function to set the relative count of DateTimeComponent, if the field is
634 // not present the function will create the field and set the count.
635 void SetRelativeCount(const DatetimeComponent::ComponentType& field_type,
636 int relative_count);
637
638 // Function to populate the absolute value of the FieldType and return true.
639 // In case of no FieldType function will return false.
640 bool GetFieldValue(const DatetimeComponent::ComponentType& field_type,
641 int* field_value) const;
642
643 // Function to populate the relative value of the FieldType and return true.
644 // In case of no relative value function will return false.
645 bool GetRelativeValue(
646 const DatetimeComponent::ComponentType& field_type,
647 DatetimeComponent::RelativeQualifier* relative_value) const;
648
649 // Returns relative DateTimeComponent from the parsed DateTime span.
650 void GetRelativeDatetimeComponents(
651 std::vector<DatetimeComponent>* date_time_components) const;
652
653 // Returns DateTimeComponent from the parsed DateTime span.
654 void GetDatetimeComponents(
655 std::vector<DatetimeComponent>* date_time_components) const;
656
657 // Represent the granularity of the Parsed DateTime span. The function will
658 // return “GRANULARITY_UNKNOWN” if no datetime field is set.
659 DatetimeGranularity GetFinestGranularity() const;
660
661 // Utility function to check if DateTimeParsedData has FieldType initialized.
662 bool HasFieldType(const DatetimeComponent::ComponentType& field_type) const;
663
664 // Function to check if DateTimeParsedData has relative DateTimeComponent for
665 // given FieldType.
666 bool HasRelativeValue(
667 const DatetimeComponent::ComponentType& field_type) const;
668
669 // Function to check if DateTimeParsedData has absolute value
670 // DateTimeComponent for given FieldType.
671 bool HasAbsoluteValue(
672 const DatetimeComponent::ComponentType& field_type) const;
673
674 // Function to check if DateTimeParsedData has any DateTimeComponent.
675 bool IsEmpty() const;
676
677 private:
678 DatetimeComponent& GetOrCreateDatetimeComponent(
679
680 const DatetimeComponent::ComponentType& component_type);
681
682 std::map<DatetimeComponent::ComponentType, DatetimeComponent>
683 date_time_components_;
684 };
685
686 // Pretty-printing function for DateTimeParsedData.
687 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
688 const DatetimeParsedData& data);
689
690 } // namespace libtextclassifier3
691
692 #endif // LIBTEXTCLASSIFIER_ANNOTATOR_TYPES_H_
693