Action Engine
Loading...
Searching...
No Matches
array.h
1// Copyright 2025 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#ifndef ACTIONENGINE_MSGPACK_ARRAY_H
16#define ACTIONENGINE_MSGPACK_ARRAY_H
17
18#include "actionengine/msgpack/core_helpers.h"
19
20namespace act::msgpack {
21
22template <typename T>
23absl::StatusOr<uint32_t> EgltMsgpackGetExtent(const LookupPointer& data,
24 std::vector<T>* absl_nullable) {
25 const auto [pos, end, _] = data;
26
27 uint32_t extent = 0;
28 uint32_t length = -1;
29 auto elements_pos = const_cast<Byte*>(pos);
30
31 if (*pos >= 0x90 && *pos <= 0x9F) {
32 length = *pos - 0x90; // FixArray case
33 elements_pos += 1; // Move past the FixArray header
34 extent += 1; // 1 byte for the FixArray header
35 }
36
37 if (*pos == FormatSignature::kArray16) {
38 if (end - pos < 3) {
39 return GetInsufficientDataError(data, "std::vector<T>");
40 }
41 length = FromBigEndianBytes<uint16_t>(pos + 1);
42 elements_pos += 3; // Move past the Array16 header
43 extent += 3; // 1 byte for the signature + 2 bytes for length
44 }
45
46 if (*pos == FormatSignature::kArray32) {
47 if (end - pos < 5) {
48 return GetInsufficientDataError(data, "std::vector<T>");
49 }
50 length = FromBigEndianBytes<uint32_t>(pos + 1);
51 elements_pos += 5; // Move past the Array32 header
52 extent += 5; // 1 byte for the signature + 4 bytes for length
53 }
54
55 if (length == -1) {
56 return GetInvalidFormatSignatureError(pos, "std::vector<T>", data.begin);
57 }
58
59 if (elements_pos >= end) {
60 return GetInsufficientDataError(data, "std::vector<T> elements");
61 }
62
63 for (uint32_t i = 0; i < length; ++i) {
64 if (elements_pos >= end) {
65 return GetInsufficientDataError(data, "std::vector<T> elements");
66 }
67 auto element_extent = GetExtent<T>(elements_pos, end);
68 if (!element_extent.ok()) {
69 return element_extent.status();
70 }
71 extent += *element_extent;
72 elements_pos += *element_extent;
73 }
74
75 return extent;
76}
77
78template <typename T>
79absl::Status EgltMsgpackSerialize(const std::vector<T>& value,
80 const InsertInfo& insert) {
81 SerializedBytesVector result, encoded_size;
82
83 if (value.size() <= 15) {
84 encoded_size = {
85 static_cast<Byte>(FormatSignature::kFixArray + value.size())};
86 } else if (value.size() <= 65535) {
87 encoded_size = ToBigEndianBytes<uint16_t>(value.size(), 1);
88 encoded_size[0] = FormatSignature::kArray16;
89 } else {
90 encoded_size = ToBigEndianBytes<uint32_t>(value.size(), 1);
91 encoded_size[0] = FormatSignature::kArray32;
92 }
93
94 // value.size() * sizeof(T) is a rough estimate of the size needed for
95 // serializing the elements, which may not be exact for all types.
96 result.reserve(encoded_size.size() + value.size() * sizeof(T));
97 result.insert(result.end(), encoded_size.begin(), encoded_size.end());
98
99 for (const auto& element : value) {
100 auto serialized_element = Serialize(element);
101 if (!serialized_element.ok()) {
102 return serialized_element.status();
103 }
104 result.insert(result.end(), serialized_element->begin(),
105 serialized_element->end());
106 }
107
108 insert.bytes->insert(insert.at, result.begin(), result.end());
109 return absl::OkStatus();
110}
111
112template <typename T>
113absl::StatusOr<uint32_t> EgltMsgpackDeserialize(
114 const LookupPointer& data, std::vector<T>* absl_nonnull output) {
115 const auto [pos, end, _] = data;
116
117 uint32_t length = -1;
118 auto elements_pos = const_cast<Byte*>(pos);
119
120 if (*pos >= 0x90 && *pos <= 0x9F) {
121 length = *pos - 0x90; // FixArray case
122 elements_pos += 1; // Move past the FixArray header
123 }
124
125 if (*pos == FormatSignature::kArray16) {
126 if (end - pos < 3) {
127 return GetInsufficientDataError(data, "std::vector<T>");
128 }
129 length = FromBigEndianBytes<uint16_t>(pos + 1);
130 elements_pos += 3; // Move past the Array16 header
131 }
132
133 if (*pos == FormatSignature::kArray32) {
134 if (end - pos < 5) {
135 return GetInsufficientDataError(data, "std::vector<T>");
136 }
137 length = FromBigEndianBytes<uint32_t>(pos + 1);
138 elements_pos += 5; // Move past the Array32 header
139 }
140
141 if (length == -1) {
142 return GetInvalidFormatSignatureError(pos, "std::vector<T>", data.begin);
143 }
144
145 if (elements_pos >= end) {
146 return GetInsufficientDataError(data, "std::vector<T> elements");
147 }
148
149 output->reserve(output->size() + length);
150 for (uint32_t i = 0; i < length; ++i) {
151 if (elements_pos >= end) {
152 return GetInsufficientDataError(data, "std::vector<T> elements");
153 }
154 auto expected_element_extent =
155 EgltMsgpackGetExtent(LookupPointer(elements_pos, end),
156 static_cast<std::vector<T>*>(nullptr));
157 if (!expected_element_extent.ok()) {
158 return expected_element_extent.status();
159 }
160 auto element = Deserialize<T>(LookupPointer(elements_pos, end));
161 if (!element.ok()) {
162 return element.status();
163 }
164 output->push_back(std::move(element->value));
165 DCHECK(*expected_element_extent == element->extent)
166 << "Expected extent: " << *expected_element_extent
167 << ", actual extent: " << element->extent;
168 elements_pos += element->extent;
169 }
170
171 return elements_pos - pos; // Return the total extent of the array.
172}
173
174} // namespace act::msgpack
175
176#endif // ACTIONENGINE_MSGPACK_ARRAY_H