/root/doris/cloud/src/meta-service/codec.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #include "codec.h" |
19 | | |
20 | | #include <cstdint> |
21 | | |
22 | | namespace doris::cloud { |
23 | | |
24 | 1.21M | void encode_bytes(std::string_view bytes, std::string* b) { |
25 | | // possible_num_0x00 prefix_suffix |
26 | 1.21M | b->reserve(b->size() + (bytes.size() / 256 * 2) + 3); |
27 | 1.21M | b->push_back(static_cast<char>(EncodingTag::BYTES_TAG)); |
28 | 1.21M | std::size_t escape_pos = 0; |
29 | 1.21M | std::size_t start_pos = 0; |
30 | 2.28M | while (true) { |
31 | 2.28M | escape_pos = bytes.find(EncodingTag::BYTE_ESCAPE, escape_pos); |
32 | 2.28M | if (escape_pos == std::string::npos) { |
33 | 1.21M | break; |
34 | 1.21M | } |
35 | 1.07M | b->insert(b->end(), bytes.begin() + start_pos, bytes.begin() + escape_pos); |
36 | 1.07M | b->push_back(EncodingTag::BYTE_ESCAPE); |
37 | 1.07M | b->push_back(EncodingTag::ESCAPED_00); |
38 | 1.07M | ++escape_pos; |
39 | 1.07M | start_pos = escape_pos; |
40 | 1.07M | } |
41 | 1.21M | b->insert(b->end(), bytes.begin() + start_pos, bytes.end()); |
42 | 1.21M | b->push_back(EncodingTag::BYTE_ESCAPE); |
43 | 1.21M | b->push_back(EncodingTag::BYTES_ENDING); |
44 | 1.21M | } |
45 | | |
46 | | /** |
47 | | * Decodes byte sequence which is generated with `encode_bytes` |
48 | | * |
49 | | * @param in intput for decoding |
50 | | * @param out output |
51 | | * @return 0 for success |
52 | | */ |
53 | 80.4k | int decode_bytes(std::string_view* in, std::string* out) { |
54 | 80.4k | if (in->at(0) != EncodingTag::BYTES_TAG) return -1; |
55 | 80.4k | using byte = unsigned char; |
56 | 80.4k | in->remove_prefix(1); // Remove bytes marker |
57 | 1.15M | while (true) { |
58 | 1.15M | size_t pos = in->find(EncodingTag::BYTE_ESCAPE); |
59 | 1.15M | if (pos == std::string::npos) { // At least one should be found |
60 | | // No EncodingTag::BYTE_ESCAPE found, array without ending |
61 | 0 | return -2; |
62 | 0 | } |
63 | 1.15M | if ((pos + 1) >= in->size()) { |
64 | | // Malformed bytes encoding |
65 | 0 | return -3; |
66 | 0 | } |
67 | 1.15M | byte c = static_cast<byte>((*in)[pos + 1]); |
68 | 1.15M | if (c == EncodingTag::BYTES_ENDING) { |
69 | 80.4k | if (out != nullptr) { |
70 | 80.4k | out->append(in->data(), pos); |
71 | 80.4k | } |
72 | 80.4k | in->remove_prefix(pos + 2); |
73 | 80.4k | break; |
74 | 1.07M | } else if (c == EncodingTag::ESCAPED_00) { |
75 | 1.07M | if (out != nullptr) { |
76 | 1.07M | out->append(in->data(), pos + 1); |
77 | 1.07M | } |
78 | 1.07M | in->remove_prefix(pos + 2); |
79 | 1.07M | } else { |
80 | | // undefined escaping marker |
81 | 0 | return -4; |
82 | 0 | } |
83 | 1.15M | } |
84 | 80.4k | return 0; |
85 | 80.4k | } |
86 | | |
87 | | /** |
88 | | * Encodes int64 to 8-byte big endian |
89 | | * FIXME: use entire 8-bytes |
90 | | */ |
91 | 825k | void encode_int64(int64_t val, std::string* b) { |
92 | | // static_assert(std::endian::little); // Since c++20 |
93 | 825k | std::string dat(9, '\x00'); |
94 | 825k | dat[0] = val < 0 ? EncodingTag::NEGATIVE_FIXED_INT_TAG : EncodingTag::POSITIVE_FIXED_INT_TAG; |
95 | 825k | int64_t& v = *reinterpret_cast<int64_t*>(dat.data() + 1); |
96 | 825k | v = val < 0 ? -val : val; |
97 | | // clang-format off |
98 | | // assert: highest bit (sign) is never 1 |
99 | 825k | v = ((v & 0xffffffff00000000) >> 32) | ((v & 0x00000000ffffffff) << 32); |
100 | 825k | v = ((v & 0xffff0000ffff0000) >> 16) | ((v & 0x0000ffff0000ffff) << 16); |
101 | 825k | v = ((v & 0xff00ff00ff00ff00) >> 8) | ((v & 0x00ff00ff00ff00ff) << 8); |
102 | | // clang-format on |
103 | 825k | b->reserve(b->size() + dat.size()); |
104 | 825k | b->insert(b->end(), dat.begin(), dat.end()); |
105 | 825k | } |
106 | | |
107 | 65.1k | int decode_int64(std::string_view* in, int64_t* val) { |
108 | | // static_assert(std::endian::little); // Since c++20 |
109 | 65.1k | if (in->size() < 9) return -1; // Insufficient length to decode |
110 | 65.1k | if (in->at(0) != EncodingTag::NEGATIVE_FIXED_INT_TAG && |
111 | 65.1k | in->at(0) != EncodingTag::POSITIVE_FIXED_INT_TAG) { |
112 | | // Invalid tag |
113 | 0 | return -2; |
114 | 0 | } |
115 | 65.1k | bool is_negative = in->at(0) == EncodingTag::NEGATIVE_FIXED_INT_TAG; |
116 | 65.1k | uint64_t v = *reinterpret_cast<const uint64_t*>(in->data() + 1); |
117 | | // clang-format off |
118 | | // assert: highest bit (sign) is never 1 |
119 | 65.1k | v = ((v & 0xffffffff00000000) >> 32) | ((v & 0x00000000ffffffff) << 32); |
120 | 65.1k | v = ((v & 0xffff0000ffff0000) >> 16) | ((v & 0x0000ffff0000ffff) << 16); |
121 | 65.1k | v = ((v & 0xff00ff00ff00ff00) >> 8) | ((v & 0x00ff00ff00ff00ff) << 8); |
122 | | // clang-format on |
123 | | |
124 | | // We haven't used entire 64 bits of unsigned int64 yet, hence we treat |
125 | | // EncodingTag::NEGATIVE_FIXED_INT_TAG and EncodingTag::POSITIVE_FIXED_INT_TAG |
126 | | // the same here |
127 | 65.1k | *val = static_cast<int64_t>(v); |
128 | 65.1k | *val = is_negative ? -*val : *val; |
129 | | |
130 | 65.1k | in->remove_prefix(9); |
131 | | |
132 | 65.1k | return 0; |
133 | 65.1k | } |
134 | | |
135 | | } // namespace doris::cloud |