1 // Copyright (C) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "icing/index/term-id-codec.h"
16 
17 #include <cstdint>
18 #include <limits>
19 #include <memory>
20 
21 #include "icing/text_classifier/lib3/utils/base/statusor.h"
22 #include "icing/absl_ports/canonical_errors.h"
23 #include "icing/legacy/core/icing-string-util.h"
24 #include "icing/util/status-macros.h"
25 
26 namespace icing {
27 namespace lib {
28 
Create(uint32_t max_main_tvi,uint32_t max_lite_tvi)29 libtextclassifier3::StatusOr<std::unique_ptr<TermIdCodec>> TermIdCodec::Create(
30     uint32_t max_main_tvi, uint32_t max_lite_tvi) {
31   uint64_t sum =
32       static_cast<uint64_t>(max_main_tvi) + static_cast<uint64_t>(max_lite_tvi);
33   if (sum > std::numeric_limits<uint32_t>::max()) {
34     return absl_ports::InvalidArgumentError(IcingStringUtil::StringPrintf(
35         "Sum of max_main_tvi, %d, and max_lite_tvi, %d must be less than the "
36         "uint32_t max, %d.",
37         max_main_tvi, max_lite_tvi, std::numeric_limits<uint32_t>::max()));
38   }
39 
40   // TODO(cassiewang): When we convert these values to signed ints, we should
41   // check to make sure they're >= 0.
42 
43   return std::unique_ptr<TermIdCodec>(
44       new TermIdCodec(max_main_tvi, max_lite_tvi));
45 }
46 
EncodeTvi(uint32_t tvi,TviType tvi_type) const47 libtextclassifier3::StatusOr<uint32_t> TermIdCodec::EncodeTvi(
48     uint32_t tvi, TviType tvi_type) const {
49   switch (tvi_type) {
50     case TviType::MAIN:
51       if (tvi >= max_main_tvi_) {
52         return absl_ports::InvalidArgumentError(IcingStringUtil::StringPrintf(
53             "Main tvi %d is greater "
54             "than or equal to the max_main_tvi %d",
55             tvi, max_main_tvi_));
56       }
57       return tvi;
58     case TviType::LITE: {
59       if (tvi >= max_lite_tvi_) {
60         return absl_ports::InvalidArgumentError(IcingStringUtil::StringPrintf(
61             "Lite tvi %d is greater "
62             "than or equal to the max_lite_tvi %d",
63             tvi, max_lite_tvi_));
64       }
65       return max_main_tvi_ + tvi;
66     }
67   }
68 }
69 
DecodeTviType(uint32_t term_id) const70 libtextclassifier3::StatusOr<TviType> TermIdCodec::DecodeTviType(
71     uint32_t term_id) const {
72   if (term_id < max_main_tvi_) {
73     return TviType::MAIN;
74   } else if (term_id < max_term_id()) {
75     return TviType::LITE;
76   }
77   return absl_ports::InvalidArgumentError(IcingStringUtil::StringPrintf(
78       "Given TermId %d is greater than or equal to the max TermId %d", term_id,
79       max_term_id()));
80 }
81 
82 libtextclassifier3::StatusOr<TermIdCodec::DecodedTermInfo>
DecodeTermInfo(uint32_t term_id) const83 TermIdCodec::DecodeTermInfo(uint32_t term_id) const {
84   DecodedTermInfo result;
85   ICING_ASSIGN_OR_RETURN(result.tvi_type, DecodeTviType(term_id));
86   switch (result.tvi_type) {
87     case TviType::MAIN:
88       result.tvi = term_id;
89       break;
90     case TviType::LITE:
91       result.tvi = term_id - max_main_tvi_;
92       break;
93   }
94   return result;
95 }
96 
97 }  // namespace lib
98 }  // namespace icing
99