Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===---- SimplePackedSerialization.h - simple serialization ----*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// The behavior of the utilities in this header must be synchronized with the
10
// behavior of the utilities in
11
// compiler-rt/lib/orc/simple_packed_serialization.h.
12
//
13
// The Simple Packed Serialization (SPS) utilities are used to generate
14
// argument and return buffers for wrapper functions using the following
15
// serialization scheme:
16
//
17
// Primitives (signed types should be two's complement):
18
//   bool, char, int8_t, uint8_t -- 8-bit (0=false, 1=true)
19
//   int16_t, uint16_t           -- 16-bit little endian
20
//   int32_t, uint32_t           -- 32-bit little endian
21
//   int64_t, int64_t            -- 64-bit little endian
22
//
23
// Sequence<T>:
24
//   Serialized as the sequence length (as a uint64_t) followed by the
25
//   serialization of each of the elements without padding.
26
//
27
// Tuple<T1, ..., TN>:
28
//   Serialized as each of the element types from T1 to TN without padding.
29
//
30
//===----------------------------------------------------------------------===//
31
 
32
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H
33
#define LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H
34
 
35
#include "llvm/ADT/STLExtras.h"
36
#include "llvm/ADT/SmallVector.h"
37
#include "llvm/ADT/StringMap.h"
38
#include "llvm/ADT/StringRef.h"
39
#include "llvm/Support/Error.h"
40
#include "llvm/Support/SwapByteOrder.h"
41
 
42
#include <limits>
43
#include <optional>
44
#include <string>
45
#include <tuple>
46
#include <type_traits>
47
#include <utility>
48
#include <vector>
49
 
50
namespace llvm {
51
namespace orc {
52
namespace shared {
53
 
54
/// Output char buffer with overflow check.
55
class SPSOutputBuffer {
56
public:
57
  SPSOutputBuffer(char *Buffer, size_t Remaining)
58
      : Buffer(Buffer), Remaining(Remaining) {}
59
  bool write(const char *Data, size_t Size) {
60
    assert(Data && "Data must not be null");
61
    if (Size > Remaining)
62
      return false;
63
    memcpy(Buffer, Data, Size);
64
    Buffer += Size;
65
    Remaining -= Size;
66
    return true;
67
  }
68
 
69
private:
70
  char *Buffer = nullptr;
71
  size_t Remaining = 0;
72
};
73
 
74
/// Input char buffer with underflow check.
75
class SPSInputBuffer {
76
public:
77
  SPSInputBuffer() = default;
78
  SPSInputBuffer(const char *Buffer, size_t Remaining)
79
      : Buffer(Buffer), Remaining(Remaining) {}
80
  bool read(char *Data, size_t Size) {
81
    if (Size > Remaining)
82
      return false;
83
    memcpy(Data, Buffer, Size);
84
    Buffer += Size;
85
    Remaining -= Size;
86
    return true;
87
  }
88
 
89
  const char *data() const { return Buffer; }
90
  bool skip(size_t Size) {
91
    if (Size > Remaining)
92
      return false;
93
    Buffer += Size;
94
    Remaining -= Size;
95
    return true;
96
  }
97
 
98
private:
99
  const char *Buffer = nullptr;
100
  size_t Remaining = 0;
101
};
102
 
103
/// Specialize to describe how to serialize/deserialize to/from the given
104
/// concrete type.
105
template <typename SPSTagT, typename ConcreteT, typename _ = void>
106
class SPSSerializationTraits;
107
 
108
/// A utility class for serializing to a blob from a variadic list.
109
template <typename... ArgTs> class SPSArgList;
110
 
111
// Empty list specialization for SPSArgList.
112
template <> class SPSArgList<> {
113
public:
114
  static size_t size() { return 0; }
115
 
116
  static bool serialize(SPSOutputBuffer &OB) { return true; }
117
  static bool deserialize(SPSInputBuffer &IB) { return true; }
118
 
119
  static bool serializeToSmallVector(SmallVectorImpl<char> &V) { return true; }
120
 
121
  static bool deserializeFromSmallVector(const SmallVectorImpl<char> &V) {
122
    return true;
123
  }
124
};
125
 
126
// Non-empty list specialization for SPSArgList.
127
template <typename SPSTagT, typename... SPSTagTs>
128
class SPSArgList<SPSTagT, SPSTagTs...> {
129
public:
130
  // FIXME: This typedef is here to enable SPS arg serialization from
131
  // JITLink. It can be removed once JITLink can access SPS directly.
132
  using OutputBuffer = SPSOutputBuffer;
133
 
134
  template <typename ArgT, typename... ArgTs>
135
  static size_t size(const ArgT &Arg, const ArgTs &...Args) {
136
    return SPSSerializationTraits<SPSTagT, ArgT>::size(Arg) +
137
           SPSArgList<SPSTagTs...>::size(Args...);
138
  }
139
 
140
  template <typename ArgT, typename... ArgTs>
141
  static bool serialize(SPSOutputBuffer &OB, const ArgT &Arg,
142
                        const ArgTs &...Args) {
143
    return SPSSerializationTraits<SPSTagT, ArgT>::serialize(OB, Arg) &&
144
           SPSArgList<SPSTagTs...>::serialize(OB, Args...);
145
  }
146
 
147
  template <typename ArgT, typename... ArgTs>
148
  static bool deserialize(SPSInputBuffer &IB, ArgT &Arg, ArgTs &...Args) {
149
    return SPSSerializationTraits<SPSTagT, ArgT>::deserialize(IB, Arg) &&
150
           SPSArgList<SPSTagTs...>::deserialize(IB, Args...);
151
  }
152
};
153
 
154
/// SPS serialization for integral types, bool, and char.
155
template <typename SPSTagT>
156
class SPSSerializationTraits<
157
    SPSTagT, SPSTagT,
158
    std::enable_if_t<std::is_same<SPSTagT, bool>::value ||
159
                     std::is_same<SPSTagT, char>::value ||
160
                     std::is_same<SPSTagT, int8_t>::value ||
161
                     std::is_same<SPSTagT, int16_t>::value ||
162
                     std::is_same<SPSTagT, int32_t>::value ||
163
                     std::is_same<SPSTagT, int64_t>::value ||
164
                     std::is_same<SPSTagT, uint8_t>::value ||
165
                     std::is_same<SPSTagT, uint16_t>::value ||
166
                     std::is_same<SPSTagT, uint32_t>::value ||
167
                     std::is_same<SPSTagT, uint64_t>::value>> {
168
public:
169
  static size_t size(const SPSTagT &Value) { return sizeof(SPSTagT); }
170
 
171
  static bool serialize(SPSOutputBuffer &OB, const SPSTagT &Value) {
172
    SPSTagT Tmp = Value;
173
    if (sys::IsBigEndianHost)
174
      sys::swapByteOrder(Tmp);
175
    return OB.write(reinterpret_cast<const char *>(&Tmp), sizeof(Tmp));
176
  }
177
 
178
  static bool deserialize(SPSInputBuffer &IB, SPSTagT &Value) {
179
    SPSTagT Tmp;
180
    if (!IB.read(reinterpret_cast<char *>(&Tmp), sizeof(Tmp)))
181
      return false;
182
    if (sys::IsBigEndianHost)
183
      sys::swapByteOrder(Tmp);
184
    Value = Tmp;
185
    return true;
186
  }
187
};
188
 
189
// Any empty placeholder suitable as a substitute for void when deserializing
190
class SPSEmpty {};
191
 
192
/// SPS tag type for tuples.
193
///
194
/// A blob tuple should be serialized by serializing each of the elements in
195
/// sequence.
196
template <typename... SPSTagTs> class SPSTuple {
197
public:
198
  /// Convenience typedef of the corresponding arg list.
199
  typedef SPSArgList<SPSTagTs...> AsArgList;
200
};
201
 
202
/// SPS tag type for optionals.
203
///
204
/// SPSOptionals should be serialized as a bool with true indicating that an
205
/// SPSTagT value is present, and false indicating that there is no value.
206
/// If the boolean is true then the serialized SPSTagT will follow immediately
207
/// after it.
208
template <typename SPSTagT> class SPSOptional {};
209
 
210
/// SPS tag type for sequences.
211
///
212
/// SPSSequences should be serialized as a uint64_t sequence length,
213
/// followed by the serialization of each of the elements.
214
template <typename SPSElementTagT> class SPSSequence;
215
 
216
/// SPS tag type for strings, which are equivalent to sequences of chars.
217
using SPSString = SPSSequence<char>;
218
 
219
/// SPS tag type for maps.
220
///
221
/// SPS maps are just sequences of (Key, Value) tuples.
222
template <typename SPSTagT1, typename SPSTagT2>
223
using SPSMap = SPSSequence<SPSTuple<SPSTagT1, SPSTagT2>>;
224
 
225
/// Serialization for SPSEmpty type.
226
template <> class SPSSerializationTraits<SPSEmpty, SPSEmpty> {
227
public:
228
  static size_t size(const SPSEmpty &EP) { return 0; }
229
  static bool serialize(SPSOutputBuffer &OB, const SPSEmpty &BE) {
230
    return true;
231
  }
232
  static bool deserialize(SPSInputBuffer &IB, SPSEmpty &BE) { return true; }
233
};
234
 
235
/// Specialize this to implement 'trivial' sequence serialization for
236
/// a concrete sequence type.
237
///
238
/// Trivial sequence serialization uses the sequence's 'size' member to get the
239
/// length of the sequence, and uses a range-based for loop to iterate over the
240
/// elements.
241
///
242
/// Specializing this template class means that you do not need to provide a
243
/// specialization of SPSSerializationTraits for your type.
244
template <typename SPSElementTagT, typename ConcreteSequenceT>
245
class TrivialSPSSequenceSerialization {
246
public:
247
  static constexpr bool available = false;
248
};
249
 
250
/// Specialize this to implement 'trivial' sequence deserialization for
251
/// a concrete sequence type.
252
///
253
/// Trivial deserialization calls a static 'reserve(SequenceT&)' method on your
254
/// specialization (you must implement this) to reserve space, and then calls
255
/// a static 'append(SequenceT&, ElementT&) method to append each of the
256
/// deserialized elements.
257
///
258
/// Specializing this template class means that you do not need to provide a
259
/// specialization of SPSSerializationTraits for your type.
260
template <typename SPSElementTagT, typename ConcreteSequenceT>
261
class TrivialSPSSequenceDeserialization {
262
public:
263
  static constexpr bool available = false;
264
};
265
 
266
/// Trivial std::string -> SPSSequence<char> serialization.
267
template <> class TrivialSPSSequenceSerialization<char, std::string> {
268
public:
269
  static constexpr bool available = true;
270
};
271
 
272
/// Trivial SPSSequence<char> -> std::string deserialization.
273
template <> class TrivialSPSSequenceDeserialization<char, std::string> {
274
public:
275
  static constexpr bool available = true;
276
 
277
  using element_type = char;
278
 
279
  static void reserve(std::string &S, uint64_t Size) { S.reserve(Size); }
280
  static bool append(std::string &S, char C) {
281
    S.push_back(C);
282
    return true;
283
  }
284
};
285
 
286
/// Trivial std::vector<T> -> SPSSequence<SPSElementTagT> serialization.
287
template <typename SPSElementTagT, typename T>
288
class TrivialSPSSequenceSerialization<SPSElementTagT, std::vector<T>> {
289
public:
290
  static constexpr bool available = true;
291
};
292
 
293
/// Trivial SPSSequence<SPSElementTagT> -> std::vector<T> deserialization.
294
template <typename SPSElementTagT, typename T>
295
class TrivialSPSSequenceDeserialization<SPSElementTagT, std::vector<T>> {
296
public:
297
  static constexpr bool available = true;
298
 
299
  using element_type = typename std::vector<T>::value_type;
300
 
301
  static void reserve(std::vector<T> &V, uint64_t Size) { V.reserve(Size); }
302
  static bool append(std::vector<T> &V, T E) {
303
    V.push_back(std::move(E));
304
    return true;
305
  }
306
};
307
 
308
/// Trivial SmallVectorImpl<T> -> SPSSequence<char> serialization.
309
template <typename SPSElementTagT, typename T>
310
class TrivialSPSSequenceSerialization<SPSElementTagT, SmallVectorImpl<T>> {
311
public:
312
  static constexpr bool available = true;
313
};
314
 
315
/// Trivial SPSSequence<SPSElementTagT> -> SmallVectorImpl<T> deserialization.
316
template <typename SPSElementTagT, typename T>
317
class TrivialSPSSequenceDeserialization<SPSElementTagT, SmallVectorImpl<T>> {
318
public:
319
  static constexpr bool available = true;
320
 
321
  using element_type = typename SmallVectorImpl<T>::value_type;
322
 
323
  static void reserve(SmallVectorImpl<T> &V, uint64_t Size) { V.reserve(Size); }
324
  static bool append(SmallVectorImpl<T> &V, T E) {
325
    V.push_back(std::move(E));
326
    return true;
327
  }
328
};
329
 
330
/// Trivial SmallVectorImpl<T> -> SPSSequence<char> serialization.
331
template <typename SPSElementTagT, typename T, unsigned N>
332
class TrivialSPSSequenceSerialization<SPSElementTagT, SmallVector<T, N>>
333
    : public TrivialSPSSequenceSerialization<SPSElementTagT,
334
                                             SmallVectorImpl<T>> {};
335
 
336
/// Trivial SPSSequence<SPSElementTagT> -> SmallVectorImpl<T> deserialization.
337
template <typename SPSElementTagT, typename T, unsigned N>
338
class TrivialSPSSequenceDeserialization<SPSElementTagT, SmallVector<T, N>>
339
    : public TrivialSPSSequenceDeserialization<SPSElementTagT,
340
                                               SmallVectorImpl<T>> {};
341
 
342
/// Trivial ArrayRef<T> -> SPSSequence<SPSElementTagT> serialization.
343
template <typename SPSElementTagT, typename T>
344
class TrivialSPSSequenceSerialization<SPSElementTagT, ArrayRef<T>> {
345
public:
346
  static constexpr bool available = true;
347
};
348
 
349
/// Specialized SPSSequence<char> -> ArrayRef<char> serialization.
350
///
351
/// On deserialize, points directly into the input buffer.
352
template <> class SPSSerializationTraits<SPSSequence<char>, ArrayRef<char>> {
353
public:
354
  static size_t size(const ArrayRef<char> &A) {
355
    return SPSArgList<uint64_t>::size(static_cast<uint64_t>(A.size())) +
356
           A.size();
357
  }
358
 
359
  static bool serialize(SPSOutputBuffer &OB, const ArrayRef<char> &A) {
360
    if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(A.size())))
361
      return false;
362
    if (A.empty()) // Empty ArrayRef may have null data, so bail out early.
363
      return true;
364
    return OB.write(A.data(), A.size());
365
  }
366
 
367
  static bool deserialize(SPSInputBuffer &IB, ArrayRef<char> &A) {
368
    uint64_t Size;
369
    if (!SPSArgList<uint64_t>::deserialize(IB, Size))
370
      return false;
371
    if (Size > std::numeric_limits<size_t>::max())
372
      return false;
373
    A = {Size ? IB.data() : nullptr, static_cast<size_t>(Size)};
374
    return IB.skip(Size);
375
  }
376
};
377
 
378
/// 'Trivial' sequence serialization: Sequence is serialized as a uint64_t size
379
/// followed by a for-earch loop over the elements of the sequence to serialize
380
/// each of them.
381
template <typename SPSElementTagT, typename SequenceT>
382
class SPSSerializationTraits<SPSSequence<SPSElementTagT>, SequenceT,
383
                             std::enable_if_t<TrivialSPSSequenceSerialization<
384
                                 SPSElementTagT, SequenceT>::available>> {
385
public:
386
  static size_t size(const SequenceT &S) {
387
    size_t Size = SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size()));
388
    for (const auto &E : S)
389
      Size += SPSArgList<SPSElementTagT>::size(E);
390
    return Size;
391
  }
392
 
393
  static bool serialize(SPSOutputBuffer &OB, const SequenceT &S) {
394
    if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
395
      return false;
396
    for (const auto &E : S)
397
      if (!SPSArgList<SPSElementTagT>::serialize(OB, E))
398
        return false;
399
    return true;
400
  }
401
 
402
  static bool deserialize(SPSInputBuffer &IB, SequenceT &S) {
403
    using TBSD = TrivialSPSSequenceDeserialization<SPSElementTagT, SequenceT>;
404
    uint64_t Size;
405
    if (!SPSArgList<uint64_t>::deserialize(IB, Size))
406
      return false;
407
    TBSD::reserve(S, Size);
408
    for (size_t I = 0; I != Size; ++I) {
409
      typename TBSD::element_type E;
410
      if (!SPSArgList<SPSElementTagT>::deserialize(IB, E))
411
        return false;
412
      if (!TBSD::append(S, std::move(E)))
413
        return false;
414
    }
415
    return true;
416
  }
417
};
418
 
419
/// SPSTuple serialization for std::tuple.
420
template <typename... SPSTagTs, typename... Ts>
421
class SPSSerializationTraits<SPSTuple<SPSTagTs...>, std::tuple<Ts...>> {
422
private:
423
  using TupleArgList = typename SPSTuple<SPSTagTs...>::AsArgList;
424
  using ArgIndices = std::make_index_sequence<sizeof...(Ts)>;
425
 
426
  template <std::size_t... I>
427
  static size_t size(const std::tuple<Ts...> &T, std::index_sequence<I...>) {
428
    return TupleArgList::size(std::get<I>(T)...);
429
  }
430
 
431
  template <std::size_t... I>
432
  static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T,
433
                        std::index_sequence<I...>) {
434
    return TupleArgList::serialize(OB, std::get<I>(T)...);
435
  }
436
 
437
  template <std::size_t... I>
438
  static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T,
439
                          std::index_sequence<I...>) {
440
    return TupleArgList::deserialize(IB, std::get<I>(T)...);
441
  }
442
 
443
public:
444
  static size_t size(const std::tuple<Ts...> &T) {
445
    return size(T, ArgIndices{});
446
  }
447
 
448
  static bool serialize(SPSOutputBuffer &OB, const std::tuple<Ts...> &T) {
449
    return serialize(OB, T, ArgIndices{});
450
  }
451
 
452
  static bool deserialize(SPSInputBuffer &IB, std::tuple<Ts...> &T) {
453
    return deserialize(IB, T, ArgIndices{});
454
  }
455
};
456
 
457
/// SPSTuple serialization for std::pair.
458
template <typename SPSTagT1, typename SPSTagT2, typename T1, typename T2>
459
class SPSSerializationTraits<SPSTuple<SPSTagT1, SPSTagT2>, std::pair<T1, T2>> {
460
public:
461
  static size_t size(const std::pair<T1, T2> &P) {
462
    return SPSArgList<SPSTagT1>::size(P.first) +
463
           SPSArgList<SPSTagT2>::size(P.second);
464
  }
465
 
466
  static bool serialize(SPSOutputBuffer &OB, const std::pair<T1, T2> &P) {
467
    return SPSArgList<SPSTagT1>::serialize(OB, P.first) &&
468
           SPSArgList<SPSTagT2>::serialize(OB, P.second);
469
  }
470
 
471
  static bool deserialize(SPSInputBuffer &IB, std::pair<T1, T2> &P) {
472
    return SPSArgList<SPSTagT1>::deserialize(IB, P.first) &&
473
           SPSArgList<SPSTagT2>::deserialize(IB, P.second);
474
  }
475
};
476
 
477
/// SPSOptional serialization for std::optional.
478
template <typename SPSTagT, typename T>
479
class SPSSerializationTraits<SPSOptional<SPSTagT>, std::optional<T>> {
480
public:
481
  static size_t size(const std::optional<T> &Value) {
482
    size_t Size = SPSArgList<bool>::size(!!Value);
483
    if (Value)
484
      Size += SPSArgList<SPSTagT>::size(*Value);
485
    return Size;
486
  }
487
 
488
  static bool serialize(SPSOutputBuffer &OB, const std::optional<T> &Value) {
489
    if (!SPSArgList<bool>::serialize(OB, !!Value))
490
      return false;
491
    if (Value)
492
      return SPSArgList<SPSTagT>::serialize(OB, *Value);
493
    return true;
494
  }
495
 
496
  static bool deserialize(SPSInputBuffer &IB, std::optional<T> &Value) {
497
    bool HasValue;
498
    if (!SPSArgList<bool>::deserialize(IB, HasValue))
499
      return false;
500
    if (HasValue) {
501
      Value = T();
502
      return SPSArgList<SPSTagT>::deserialize(IB, *Value);
503
    } else
504
      Value = std::optional<T>();
505
    return true;
506
  }
507
};
508
 
509
/// Serialization for StringRefs.
510
///
511
/// Serialization is as for regular strings. Deserialization points directly
512
/// into the blob.
513
template <> class SPSSerializationTraits<SPSString, StringRef> {
514
public:
515
  static size_t size(const StringRef &S) {
516
    return SPSArgList<uint64_t>::size(static_cast<uint64_t>(S.size())) +
517
           S.size();
518
  }
519
 
520
  static bool serialize(SPSOutputBuffer &OB, StringRef S) {
521
    if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(S.size())))
522
      return false;
523
    if (S.empty()) // Empty StringRef may have null data, so bail out early.
524
      return true;
525
    return OB.write(S.data(), S.size());
526
  }
527
 
528
  static bool deserialize(SPSInputBuffer &IB, StringRef &S) {
529
    const char *Data = nullptr;
530
    uint64_t Size;
531
    if (!SPSArgList<uint64_t>::deserialize(IB, Size))
532
      return false;
533
    Data = IB.data();
534
    if (!IB.skip(Size))
535
      return false;
536
    S = StringRef(Size ? Data : nullptr, Size);
537
    return true;
538
  }
539
};
540
 
541
/// Serialization for StringMap<ValueT>s.
542
template <typename SPSValueT, typename ValueT>
543
class SPSSerializationTraits<SPSSequence<SPSTuple<SPSString, SPSValueT>>,
544
                             StringMap<ValueT>> {
545
public:
546
  static size_t size(const StringMap<ValueT> &M) {
547
    size_t Sz = SPSArgList<uint64_t>::size(static_cast<uint64_t>(M.size()));
548
    for (auto &E : M)
549
      Sz += SPSArgList<SPSString, SPSValueT>::size(E.first(), E.second);
550
    return Sz;
551
  }
552
 
553
  static bool serialize(SPSOutputBuffer &OB, const StringMap<ValueT> &M) {
554
    if (!SPSArgList<uint64_t>::serialize(OB, static_cast<uint64_t>(M.size())))
555
      return false;
556
 
557
    for (auto &E : M)
558
      if (!SPSArgList<SPSString, SPSValueT>::serialize(OB, E.first(), E.second))
559
        return false;
560
 
561
    return true;
562
  }
563
 
564
  static bool deserialize(SPSInputBuffer &IB, StringMap<ValueT> &M) {
565
    uint64_t Size;
566
    assert(M.empty() && "M already contains elements");
567
 
568
    if (!SPSArgList<uint64_t>::deserialize(IB, Size))
569
      return false;
570
 
571
    while (Size--) {
572
      StringRef S;
573
      ValueT V;
574
      if (!SPSArgList<SPSString, SPSValueT>::deserialize(IB, S, V))
575
        return false;
576
      if (!M.insert(std::make_pair(S, V)).second)
577
        return false;
578
    }
579
 
580
    return true;
581
  }
582
};
583
 
584
/// SPS tag type for errors.
585
class SPSError;
586
 
587
/// SPS tag type for expecteds, which are either a T or a string representing
588
/// an error.
589
template <typename SPSTagT> class SPSExpected;
590
 
591
namespace detail {
592
 
593
/// Helper type for serializing Errors.
594
///
595
/// llvm::Errors are move-only, and not inspectable except by consuming them.
596
/// This makes them unsuitable for direct serialization via
597
/// SPSSerializationTraits, which needs to inspect values twice (once to
598
/// determine the amount of space to reserve, and then again to serialize).
599
///
600
/// The SPSSerializableError type is a helper that can be
601
/// constructed from an llvm::Error, but inspected more than once.
602
struct SPSSerializableError {
603
  bool HasError = false;
604
  std::string ErrMsg;
605
};
606
 
607
/// Helper type for serializing Expected<T>s.
608
///
609
/// See SPSSerializableError for more details.
610
///
611
// FIXME: Use std::variant for storage once we have c++17.
612
template <typename T> struct SPSSerializableExpected {
613
  bool HasValue = false;
614
  T Value{};
615
  std::string ErrMsg;
616
};
617
 
618
inline SPSSerializableError toSPSSerializable(Error Err) {
619
  if (Err)
620
    return {true, toString(std::move(Err))};
621
  return {false, {}};
622
}
623
 
624
inline Error fromSPSSerializable(SPSSerializableError BSE) {
625
  if (BSE.HasError)
626
    return make_error<StringError>(BSE.ErrMsg, inconvertibleErrorCode());
627
  return Error::success();
628
}
629
 
630
template <typename T>
631
SPSSerializableExpected<T> toSPSSerializable(Expected<T> E) {
632
  if (E)
633
    return {true, std::move(*E), {}};
634
  else
635
    return {false, T(), toString(E.takeError())};
636
}
637
 
638
template <typename T>
639
Expected<T> fromSPSSerializable(SPSSerializableExpected<T> BSE) {
640
  if (BSE.HasValue)
641
    return std::move(BSE.Value);
642
  else
643
    return make_error<StringError>(BSE.ErrMsg, inconvertibleErrorCode());
644
}
645
 
646
} // end namespace detail
647
 
648
/// Serialize to a SPSError from a detail::SPSSerializableError.
649
template <>
650
class SPSSerializationTraits<SPSError, detail::SPSSerializableError> {
651
public:
652
  static size_t size(const detail::SPSSerializableError &BSE) {
653
    size_t Size = SPSArgList<bool>::size(BSE.HasError);
654
    if (BSE.HasError)
655
      Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
656
    return Size;
657
  }
658
 
659
  static bool serialize(SPSOutputBuffer &OB,
660
                        const detail::SPSSerializableError &BSE) {
661
    if (!SPSArgList<bool>::serialize(OB, BSE.HasError))
662
      return false;
663
    if (BSE.HasError)
664
      if (!SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg))
665
        return false;
666
    return true;
667
  }
668
 
669
  static bool deserialize(SPSInputBuffer &IB,
670
                          detail::SPSSerializableError &BSE) {
671
    if (!SPSArgList<bool>::deserialize(IB, BSE.HasError))
672
      return false;
673
 
674
    if (!BSE.HasError)
675
      return true;
676
 
677
    return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
678
  }
679
};
680
 
681
/// Serialize to a SPSExpected<SPSTagT> from a
682
/// detail::SPSSerializableExpected<T>.
683
template <typename SPSTagT, typename T>
684
class SPSSerializationTraits<SPSExpected<SPSTagT>,
685
                             detail::SPSSerializableExpected<T>> {
686
public:
687
  static size_t size(const detail::SPSSerializableExpected<T> &BSE) {
688
    size_t Size = SPSArgList<bool>::size(BSE.HasValue);
689
    if (BSE.HasValue)
690
      Size += SPSArgList<SPSTagT>::size(BSE.Value);
691
    else
692
      Size += SPSArgList<SPSString>::size(BSE.ErrMsg);
693
    return Size;
694
  }
695
 
696
  static bool serialize(SPSOutputBuffer &OB,
697
                        const detail::SPSSerializableExpected<T> &BSE) {
698
    if (!SPSArgList<bool>::serialize(OB, BSE.HasValue))
699
      return false;
700
 
701
    if (BSE.HasValue)
702
      return SPSArgList<SPSTagT>::serialize(OB, BSE.Value);
703
 
704
    return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
705
  }
706
 
707
  static bool deserialize(SPSInputBuffer &IB,
708
                          detail::SPSSerializableExpected<T> &BSE) {
709
    if (!SPSArgList<bool>::deserialize(IB, BSE.HasValue))
710
      return false;
711
 
712
    if (BSE.HasValue)
713
      return SPSArgList<SPSTagT>::deserialize(IB, BSE.Value);
714
 
715
    return SPSArgList<SPSString>::deserialize(IB, BSE.ErrMsg);
716
  }
717
};
718
 
719
/// Serialize to a SPSExpected<SPSTagT> from a detail::SPSSerializableError.
720
template <typename SPSTagT>
721
class SPSSerializationTraits<SPSExpected<SPSTagT>,
722
                             detail::SPSSerializableError> {
723
public:
724
  static size_t size(const detail::SPSSerializableError &BSE) {
725
    assert(BSE.HasError && "Cannot serialize expected from a success value");
726
    return SPSArgList<bool>::size(false) +
727
           SPSArgList<SPSString>::size(BSE.ErrMsg);
728
  }
729
 
730
  static bool serialize(SPSOutputBuffer &OB,
731
                        const detail::SPSSerializableError &BSE) {
732
    assert(BSE.HasError && "Cannot serialize expected from a success value");
733
    if (!SPSArgList<bool>::serialize(OB, false))
734
      return false;
735
    return SPSArgList<SPSString>::serialize(OB, BSE.ErrMsg);
736
  }
737
};
738
 
739
/// Serialize to a SPSExpected<SPSTagT> from a T.
740
template <typename SPSTagT, typename T>
741
class SPSSerializationTraits<SPSExpected<SPSTagT>, T> {
742
public:
743
  static size_t size(const T &Value) {
744
    return SPSArgList<bool>::size(true) + SPSArgList<SPSTagT>::size(Value);
745
  }
746
 
747
  static bool serialize(SPSOutputBuffer &OB, const T &Value) {
748
    if (!SPSArgList<bool>::serialize(OB, true))
749
      return false;
750
    return SPSArgList<SPSTagT>::serialize(Value);
751
  }
752
};
753
 
754
} // end namespace shared
755
} // end namespace orc
756
} // end namespace llvm
757
 
758
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEPACKEDSERIALIZATION_H