tvm
serializer.h
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
33 #ifndef TVM_SUPPORT_SERIALIZER_H_
34 #define TVM_SUPPORT_SERIALIZER_H_
35 
36 #include <dlpack/dlpack.h>
37 #include <tvm/ffi/container/array.h>
38 #include <tvm/ffi/container/map.h>
39 #include <tvm/ffi/endian.h>
40 #include <tvm/ffi/string.h>
41 #include <tvm/support/io.h>
42 
43 #include <cstdint>
44 #include <cstring>
45 #include <string>
46 #include <type_traits>
47 #include <unordered_map>
48 #include <utility>
49 #include <vector>
50 
51 namespace tvm {
52 namespace support {
53 
54 // ---- Arithmetic types ----
55 template <typename T>
56 struct Serializer<T, std::enable_if_t<std::is_arithmetic_v<T>>> {
57  static constexpr bool enabled = true;
58 
59  static void Write(Stream* strm, const T& data) {
60  if constexpr (TVM_FFI_IO_NO_ENDIAN_SWAP) {
61  strm->Write(&data, sizeof(T));
62  } else {
63  T copy = data;
64  ffi::ByteSwap(&copy, sizeof(T), 1);
65  strm->Write(&copy, sizeof(T));
66  }
67  }
68 
69  static bool Read(Stream* strm, T* data) {
70  bool ok = strm->Read(data, sizeof(T)) == sizeof(T);
71  if constexpr (!TVM_FFI_IO_NO_ENDIAN_SWAP) {
72  ffi::ByteSwap(data, sizeof(T), 1);
73  }
74  return ok;
75  }
76 };
77 
78 // ---- Enum types (delegate to underlying arithmetic type) ----
79 template <typename T>
80 struct Serializer<T, std::enable_if_t<std::is_enum_v<T>>> {
81  static constexpr bool enabled = true;
82  using U = std::underlying_type_t<T>;
83 
84  static void Write(Stream* strm, const T& data) {
85  Serializer<U>::Write(strm, static_cast<U>(data));
86  }
87 
88  static bool Read(Stream* strm, T* data) {
89  U val;
90  if (!Serializer<U>::Read(strm, &val)) return false;
91  *data = static_cast<T>(val);
92  return true;
93  }
94 };
95 
96 // ---- std::string ----
97 template <>
98 struct Serializer<std::string> {
99  static constexpr bool enabled = true;
100 
101  static void Write(Stream* strm, const std::string& data) {
102  uint64_t sz = static_cast<uint64_t>(data.size());
103  Serializer<uint64_t>::Write(strm, sz);
104  if (sz != 0) {
105  strm->Write(data.data(), data.size());
106  }
107  }
108 
109  static bool Read(Stream* strm, std::string* data) {
110  uint64_t sz;
111  if (!Serializer<uint64_t>::Read(strm, &sz)) return false;
112  data->resize(static_cast<size_t>(sz));
113  if (sz != 0) {
114  size_t nbytes = static_cast<size_t>(sz);
115  return strm->Read(&(*data)[0], nbytes) == nbytes;
116  }
117  return true;
118  }
119 };
120 
121 // ---- std::vector<T> ----
122 template <typename T>
123 struct Serializer<std::vector<T>> {
124  static constexpr bool enabled = true;
125 
126  static void Write(Stream* strm, const std::vector<T>& vec) {
127  uint64_t sz = static_cast<uint64_t>(vec.size());
128  Serializer<uint64_t>::Write(strm, sz);
129  if constexpr (std::is_arithmetic_v<T> && TVM_FFI_IO_NO_ENDIAN_SWAP) {
130  if (sz != 0) {
131  strm->Write(vec.data(), sizeof(T) * vec.size());
132  }
133  } else {
134  for (const auto& v : vec) {
135  Serializer<T>::Write(strm, v);
136  }
137  }
138  }
139 
140  static bool Read(Stream* strm, std::vector<T>* vec) {
141  uint64_t sz;
142  if (!Serializer<uint64_t>::Read(strm, &sz)) return false;
143  vec->resize(static_cast<size_t>(sz));
144  if constexpr (std::is_arithmetic_v<T> && TVM_FFI_IO_NO_ENDIAN_SWAP) {
145  if (sz != 0) {
146  size_t nbytes = sizeof(T) * static_cast<size_t>(sz);
147  return strm->Read(vec->data(), nbytes) == nbytes;
148  }
149  return true;
150  } else {
151  for (size_t i = 0; i < static_cast<size_t>(sz); ++i) {
152  if (!Serializer<T>::Read(strm, &(*vec)[i])) return false;
153  }
154  return true;
155  }
156  }
157 };
158 
159 // ---- std::pair<A, B> ----
160 template <typename A, typename B>
161 struct Serializer<std::pair<A, B>> {
162  static constexpr bool enabled = true;
163 
164  static void Write(Stream* strm, const std::pair<A, B>& data) {
165  Serializer<A>::Write(strm, data.first);
166  Serializer<B>::Write(strm, data.second);
167  }
168 
169  static bool Read(Stream* strm, std::pair<A, B>* data) {
170  return Serializer<A>::Read(strm, &data->first) && Serializer<B>::Read(strm, &data->second);
171  }
172 };
173 
174 // ---- std::unordered_map<K, V> ----
175 template <typename K, typename V>
176 struct Serializer<std::unordered_map<K, V>> {
177  static constexpr bool enabled = true;
178 
179  static void Write(Stream* strm, const std::unordered_map<K, V>& data) {
180  std::vector<std::pair<K, V>> vec(data.begin(), data.end());
181  Serializer<std::vector<std::pair<K, V>>>::Write(strm, vec);
182  }
183 
184  static bool Read(Stream* strm, std::unordered_map<K, V>* data) {
185  std::vector<std::pair<K, V>> vec;
186  if (!Serializer<std::vector<std::pair<K, V>>>::Read(strm, &vec)) return false;
187  data->clear();
188  data->insert(vec.begin(), vec.end());
189  return true;
190  }
191 };
192 
193 // ---- ffi::String ----
194 template <>
195 struct Serializer<ffi::String> {
196  static constexpr bool enabled = true;
197 
198  static void Write(Stream* strm, const ffi::String& data) {
199  uint64_t sz = static_cast<uint64_t>(data.size());
200  Serializer<uint64_t>::Write(strm, sz);
201  if (sz != 0) {
202  strm->Write(data.data(), data.size());
203  }
204  }
205 
206  static bool Read(Stream* strm, ffi::String* data) {
207  std::string s;
208  if (!Serializer<std::string>::Read(strm, &s)) return false;
209  *data = ffi::String(std::move(s));
210  return true;
211  }
212 };
213 
214 // ---- ffi::Bytes (binary payload, same wire format as std::string) ----
215 template <>
216 struct Serializer<ffi::Bytes> {
217  static constexpr bool enabled = true;
218 
219  static void Write(Stream* strm, const ffi::Bytes& data) {
220  uint64_t sz = static_cast<uint64_t>(data.size());
221  Serializer<uint64_t>::Write(strm, sz);
222  if (sz != 0) {
223  strm->Write(data.data(), data.size());
224  }
225  }
226 
227  static bool Read(Stream* strm, ffi::Bytes* data) {
228  std::string s;
229  if (!Serializer<std::string>::Read(strm, &s)) return false;
230  *data = ffi::Bytes(std::move(s));
231  return true;
232  }
233 };
234 
235 // ---- ffi::Array<T> (binary-compatible with std::vector<T>) ----
236 template <typename T>
237 struct Serializer<ffi::Array<T>> {
238  static constexpr bool enabled = true;
239 
240  static void Write(Stream* strm, const ffi::Array<T>& arr) {
241  uint64_t sz = static_cast<uint64_t>(arr.size());
242  Serializer<uint64_t>::Write(strm, sz);
243  for (size_t i = 0; i < arr.size(); ++i) {
244  Serializer<T>::Write(strm, arr[i]);
245  }
246  }
247 
248  static bool Read(Stream* strm, ffi::Array<T>* arr) {
249  uint64_t sz;
250  if (!Serializer<uint64_t>::Read(strm, &sz)) return false;
251  *arr = ffi::Array<T>();
252  for (uint64_t i = 0; i < sz; ++i) {
253  T val;
254  if (!Serializer<T>::Read(strm, &val)) return false;
255  arr->push_back(std::move(val));
256  }
257  return true;
258  }
259 };
260 
261 // ---- ffi::Map<K, V> (binary format: uint64_t count, then key/value pairs) ----
262 template <typename K, typename V>
263 struct Serializer<ffi::Map<K, V>> {
264  static constexpr bool enabled = true;
265 
266  static void Write(Stream* strm, const ffi::Map<K, V>& data) {
267  uint64_t sz = static_cast<uint64_t>(data.size());
268  Serializer<uint64_t>::Write(strm, sz);
269  for (const auto& kv : data) {
270  Serializer<K>::Write(strm, kv.first);
271  Serializer<V>::Write(strm, kv.second);
272  }
273  }
274 
275  static bool Read(Stream* strm, ffi::Map<K, V>* data) {
276  uint64_t sz;
277  if (!Serializer<uint64_t>::Read(strm, &sz)) return false;
278  *data = ffi::Map<K, V>();
279  for (uint64_t i = 0; i < sz; ++i) {
280  K key;
281  V val;
282  if (!Serializer<K>::Read(strm, &key)) return false;
283  if (!Serializer<V>::Read(strm, &val)) return false;
284  data->Set(std::move(key), std::move(val));
285  }
286  return true;
287  }
288 };
289 
290 // ---- DLDataType ----
291 template <>
292 struct Serializer<DLDataType> {
293  static constexpr bool enabled = true;
294 
295  static void Write(Stream* strm, const DLDataType& dtype) {
296  Serializer<uint8_t>::Write(strm, dtype.code);
297  Serializer<uint8_t>::Write(strm, dtype.bits);
298  Serializer<uint16_t>::Write(strm, dtype.lanes);
299  }
300 
301  static bool Read(Stream* strm, DLDataType* dtype) {
302  if (!Serializer<uint8_t>::Read(strm, &dtype->code)) return false;
303  if (!Serializer<uint8_t>::Read(strm, &dtype->bits)) return false;
304  if (!Serializer<uint16_t>::Read(strm, &dtype->lanes)) return false;
305  return true;
306  }
307 };
308 
309 // ---- DLDevice ----
310 template <>
311 struct Serializer<DLDevice> {
312  static constexpr bool enabled = true;
313 
314  static void Write(Stream* strm, const DLDevice& dev) {
315  int32_t device_type = static_cast<int32_t>(dev.device_type);
317  Serializer<int32_t>::Write(strm, dev.device_id);
318  }
319 
320  static bool Read(Stream* strm, DLDevice* dev) {
321  int32_t device_type = 0;
322  if (!Serializer<int32_t>::Read(strm, &device_type)) return false;
323  dev->device_type = static_cast<DLDeviceType>(device_type);
324  if (!Serializer<int32_t>::Read(strm, &dev->device_id)) return false;
325  return true;
326  }
327 };
328 
329 } // namespace support
330 } // namespace tvm
331 
332 #endif // TVM_SUPPORT_SERIALIZER_H_
Abstract binary stream for serialization.
Definition: io.h:57
virtual size_t Write(const void *ptr, size_t size)=0
Write raw bytes to the stream.
Binary stream I/O interface.
constexpr const char * device_type
The device type.
Definition: stmt.h:1011
const Op & copy()
See pesudo code below:
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition: analyzer.h:37
static bool Read(Stream *strm, DLDataType *dtype)
Definition: serializer.h:301
static void Write(Stream *strm, const DLDataType &dtype)
Definition: serializer.h:295
static void Write(Stream *strm, const DLDevice &dev)
Definition: serializer.h:314
static bool Read(Stream *strm, DLDevice *dev)
Definition: serializer.h:320
static void Write(Stream *strm, const ffi::Array< T > &arr)
Definition: serializer.h:240
static bool Read(Stream *strm, ffi::Array< T > *arr)
Definition: serializer.h:248
static void Write(Stream *strm, const ffi::Bytes &data)
Definition: serializer.h:219
static bool Read(Stream *strm, ffi::Bytes *data)
Definition: serializer.h:227
static bool Read(Stream *strm, ffi::Map< K, V > *data)
Definition: serializer.h:275
static void Write(Stream *strm, const ffi::Map< K, V > &data)
Definition: serializer.h:266
static bool Read(Stream *strm, ffi::String *data)
Definition: serializer.h:206
static void Write(Stream *strm, const ffi::String &data)
Definition: serializer.h:198
Primary Serializer template. Specialize for each serializable type.
Definition: io.h:42
static constexpr bool enabled
Definition: io.h:43