• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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