File: array_traits.h

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (159 lines) | stat: -rw-r--r-- 5,928 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_H_
#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_H_

#include <concepts>

#include "base/numerics/safe_conversions.h"
#include "mojo/public/cpp/bindings/lib/default_construct_tag_internal.h"
#include "mojo/public/cpp/bindings/lib/template_util.h"

namespace mojo {

// This must be specialized for any type |T| to be serialized/deserialized as
// a mojom array.
//
// Usually you would like to do a partial specialization for a container (e.g.
// vector) template. Imagine you want to specialize it for Container<>, you need
// to implement:
//
//   template <typename T>
//   struct ArrayTraits<Container<T>> {
//     using Element = T;
//     // These two statements are optional. Use them if you'd like to serialize
//     // a container that supports iterators but does not support O(1) random
//     // access and so GetAt(...) would be expensive.
//     // using Iterator = Container<T>::iterator;
//     // using ConstIterator = Container<T>::const_iterator;
//
//     // These two methods are optional. Please see comments in struct_traits.h
//     // Note that unlike with StructTraits, IsNull() is called *twice* during
//     // serialization for ArrayTraits.
//     static bool IsNull(const Container<T>& input);
//     static void SetToNull(Container<T>* output);
//
//     static size_t GetSize(const Container<T>& input);
//
//     // These two methods are optional. They are used to access the
//     // underlying storage of the array to speed up copy of POD types.
//     static T* GetData(Container<T>& input);
//     static const T* GetData(const Container<T>& input);
//
//     // The following six methods are optional if the GetAt(...) methods are
//     // implemented. These methods specify how to read the elements of
//     // Container in some sequential order specified by the iterator.
//     //
//     // Acquires an iterator positioned at the first element in the container.
//     static ConstIterator GetBegin(const Container<T>& input);
//     static Iterator GetBegin(Container<T>& input);
//
//     // Advances |iterator| to the next position within the container.
//     static void AdvanceIterator(ConstIterator& iterator);
//     static void AdvanceIterator(Iterator& iterator);
//
//     // Returns a reference to the value at the current position of
//     // |iterator|. Optionally, the ConstIterator version of GetValue can
//     // return by value instead of by reference if it makes sense for the
//     // type.
//     static const T& GetValue(ConstIterator& iterator);
//     static T& GetValue(Iterator& iterator);
//
//     // These two methods are optional if the iterator methods are
//     // implemented.
//     static T& GetAt(Container<T>& input, size_t index);
//     static const T& GetAt(const Container<T>& input, size_t index);
//
//     // Returning false results in deserialization failure and causes the
//     // message pipe receiving it to be disconnected.
//     // Note that mojo does not require that Resize preserve the original
//     // elements in `input` it merely has to set the size of `input` to
//     // `size`.
//     static bool Resize(Container<T>& input, size_t size);
//   };
//
template <typename T>
struct ArrayTraits {
  static_assert(internal::AlwaysFalse<T>::value,
                "Cannot find the mojo::ArrayTraits specialization. Did you "
                "forget to include the corresponding header file?");
};

// Generic specialization for vector-like containers.
template <typename Container>
  requires requires(Container& c, size_t i) {
    typename Container::value_type;
    { c.size() } -> std::same_as<typename Container::size_type>;
    { c.clear() } -> std::same_as<void>;
    { c[i] } -> std::same_as<typename Container::reference>;
  }
struct ArrayTraits<Container> {
  using Element = Container::value_type;

  // vector-like containers have no built-in null.
  static bool IsNull(const Container& c) { return false; }
  static void SetToNull(Container* c) {
    // TODO(dcheng): Should this ever be called? It seems questionable...
    c->clear();
  }

  static auto GetSize(const Container& c) { return c.size(); }

  // Conditional since some vector implementations have specializations which do
  // not provide direct access to an underlying array, e.g. `std::vector<bool>`.
  static auto* GetData(Container& c)
    requires requires {
      { c.data() } -> std::same_as<typename Container::pointer>;
    }
  {
    return c.data();
  }
  static const auto* GetData(const Container& c)
    requires requires {
      { c.data() } -> std::same_as<typename Container::const_pointer>;
    }
  {
    return c.data();
  }

  // The static_casts here are safe, since out-of-range issues would be caught
  // by `Resize()`.
  static decltype(auto) GetAt(Container& c, size_t index) {
    return c[static_cast<typename Container::size_type>(index)];
  }
  static decltype(auto) GetAt(const Container& c, size_t index) {
    return c[static_cast<typename Container::size_type>(index)];
  }

  static bool Resize(Container& c, size_t size) {
    if (c.size() == size) {
      return true;
    }

    if (!base::IsValueInRangeForNumericType<typename Container::size_type>(
            size)) {
      return false;
    }

    if constexpr (std::constructible_from<Element,
                                          ::mojo::DefaultConstruct::Tag>) {
      Container temp;
      temp.reserve(size);
      for (size_t i = 0; i < size; ++i) {
        temp.emplace_back(internal::DefaultConstructTag());
      }
      c.swap(temp);
    } else {
      Container temp(static_cast<typename Container::size_type>(size));
      c.swap(temp);
    }

    return true;
  }
};

}  // namespace mojo

#endif  // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_H_