Coverage Report

Created: 2023-03-26 06:03

/src/simdjson/src/implementation.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "simdjson/base.h"
2
#include <initializer_list>
3
4
namespace simdjson {
5
6
0
bool implementation::supported_by_runtime_system() const {
7
0
  uint32_t required_instruction_sets = this->required_instruction_sets();
8
0
  uint32_t supported_instruction_sets = internal::detect_supported_architectures();
9
0
  return ((supported_instruction_sets & required_instruction_sets) == required_instruction_sets);
10
0
}
11
12
namespace internal {
13
14
// Static array of known implementations. We're hoping these get baked into the executable
15
// without requiring a static initializer.
16
17
#if SIMDJSON_IMPLEMENTATION_ICELAKE
18
1
static const icelake::implementation* get_icelake_singleton() {
19
1
  static const icelake::implementation icelake_singleton{};
20
1
  return &icelake_singleton;
21
1
}
22
#endif
23
#if SIMDJSON_IMPLEMENTATION_HASWELL
24
1
static const haswell::implementation* get_haswell_singleton() {
25
1
  static const haswell::implementation haswell_singleton{};
26
1
  return &haswell_singleton;
27
1
}
28
#endif
29
#if SIMDJSON_IMPLEMENTATION_WESTMERE
30
1
static const westmere::implementation* get_westmere_singleton() {
31
1
  static const westmere::implementation westmere_singleton{};
32
1
  return &westmere_singleton;
33
1
}
34
#endif // SIMDJSON_IMPLEMENTATION_WESTMERE
35
#if SIMDJSON_IMPLEMENTATION_ARM64
36
static const arm64::implementation* get_arm64_singleton() {
37
  static const arm64::implementation arm64_singleton{};
38
  return &arm64_singleton;
39
}
40
#endif // SIMDJSON_IMPLEMENTATION_ARM64
41
#if SIMDJSON_IMPLEMENTATION_PPC64
42
static const ppc64::implementation* get_ppc64_singleton() {
43
  static const ppc64::implementation ppc64_singleton{};
44
  return &ppc64_singleton;
45
}
46
#endif // SIMDJSON_IMPLEMENTATION_PPC64
47
#if SIMDJSON_IMPLEMENTATION_FALLBACK
48
1
static const fallback::implementation* get_fallback_singleton() {
49
1
  static const fallback::implementation fallback_singleton{};
50
1
  return &fallback_singleton;
51
1
}
52
#endif // SIMDJSON_IMPLEMENTATION_FALLBACK
53
54
/**
55
 * @private Detects best supported implementation on first use, and sets it
56
 */
57
class detect_best_supported_implementation_on_first_use final : public implementation {
58
public:
59
0
  const std::string &name() const noexcept final { return set_best()->name(); }
60
0
  const std::string &description() const noexcept final { return set_best()->description(); }
61
0
  uint32_t required_instruction_sets() const noexcept final { return set_best()->required_instruction_sets(); }
62
  simdjson_warn_unused error_code create_dom_parser_implementation(
63
    size_t capacity,
64
    size_t max_length,
65
    std::unique_ptr<internal::dom_parser_implementation>& dst
66
1
  ) const noexcept final {
67
1
    return set_best()->create_dom_parser_implementation(capacity, max_length, dst);
68
1
  }
69
0
  simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final {
70
0
    return set_best()->minify(buf, len, dst, dst_len);
71
0
  }
72
0
  simdjson_warn_unused bool validate_utf8(const char * buf, size_t len) const noexcept final override {
73
0
    return set_best()->validate_utf8(buf, len);
74
0
  }
75
1
  simdjson_inline detect_best_supported_implementation_on_first_use() noexcept : implementation("best_supported_detector", "Detects the best supported implementation and sets it", 0) {}
76
private:
77
  const implementation *set_best() const noexcept;
78
};
79
80
1
static const std::initializer_list<const implementation *>& get_available_implementation_pointers() {
81
1
  static const std::initializer_list<const implementation *> available_implementation_pointers {
82
1
#if SIMDJSON_IMPLEMENTATION_ICELAKE
83
1
    get_icelake_singleton(),
84
1
#endif
85
1
#if SIMDJSON_IMPLEMENTATION_HASWELL
86
1
    get_haswell_singleton(),
87
1
#endif
88
1
#if SIMDJSON_IMPLEMENTATION_WESTMERE
89
1
    get_westmere_singleton(),
90
1
#endif
91
#if SIMDJSON_IMPLEMENTATION_ARM64
92
    get_arm64_singleton(),
93
#endif
94
#if SIMDJSON_IMPLEMENTATION_PPC64
95
    get_ppc64_singleton(),
96
#endif
97
1
#if SIMDJSON_IMPLEMENTATION_FALLBACK
98
1
    get_fallback_singleton(),
99
1
#endif
100
1
  }; // available_implementation_pointers
101
1
  return available_implementation_pointers;
102
1
}
103
104
// So we can return UNSUPPORTED_ARCHITECTURE from the parser when there is no support
105
class unsupported_implementation final : public implementation {
106
public:
107
  simdjson_warn_unused error_code create_dom_parser_implementation(
108
    size_t,
109
    size_t,
110
    std::unique_ptr<internal::dom_parser_implementation>&
111
0
  ) const noexcept final {
112
0
    return UNSUPPORTED_ARCHITECTURE;
113
0
  }
114
0
  simdjson_warn_unused error_code minify(const uint8_t *, size_t, uint8_t *, size_t &) const noexcept final override {
115
0
    return UNSUPPORTED_ARCHITECTURE;
116
0
  }
117
0
  simdjson_warn_unused bool validate_utf8(const char *, size_t) const noexcept final override {
118
0
    return false; // Just refuse to validate. Given that we have a fallback implementation
119
    // it seems unlikely that unsupported_implementation will ever be used. If it is used,
120
    // then it will flag all strings as invalid. The alternative is to return an error_code
121
    // from which the user has to figure out whether the string is valid UTF-8... which seems
122
    // like a lot of work just to handle the very unlikely case that we have an unsupported
123
    // implementation. And, when it does happen (that we have an unsupported implementation),
124
    // what are the chances that the programmer has a fallback? Given that *we* provide the
125
    // fallback, it implies that the programmer would need a fallback for our fallback.
126
0
  }
127
0
  unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {}
128
};
129
130
0
const unsupported_implementation* get_unsupported_singleton() {
131
0
    static const unsupported_implementation unsupported_singleton{};
132
0
    return &unsupported_singleton;
133
0
}
134
135
0
size_t available_implementation_list::size() const noexcept {
136
0
  return internal::get_available_implementation_pointers().size();
137
0
}
138
0
const implementation * const *available_implementation_list::begin() const noexcept {
139
0
  return internal::get_available_implementation_pointers().begin();
140
0
}
141
0
const implementation * const *available_implementation_list::end() const noexcept {
142
0
  return internal::get_available_implementation_pointers().end();
143
0
}
144
1
const implementation *available_implementation_list::detect_best_supported() const noexcept {
145
  // They are prelisted in priority order, so we just go down the list
146
1
  uint32_t supported_instruction_sets = internal::detect_supported_architectures();
147
2
  for (const implementation *impl : internal::get_available_implementation_pointers()) {
148
2
    uint32_t required_instruction_sets = impl->required_instruction_sets();
149
2
    if ((supported_instruction_sets & required_instruction_sets) == required_instruction_sets) { return impl; }
150
2
  }
151
0
  return get_unsupported_singleton(); // this should never happen?
152
1
}
153
154
1
const implementation *detect_best_supported_implementation_on_first_use::set_best() const noexcept {
155
1
  SIMDJSON_PUSH_DISABLE_WARNINGS
156
  SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
157
1
  char *force_implementation_name = getenv("SIMDJSON_FORCE_IMPLEMENTATION");
158
1
  SIMDJSON_POP_DISABLE_WARNINGS
159
160
1
  if (force_implementation_name) {
161
0
    auto force_implementation = get_available_implementations()[force_implementation_name];
162
0
    if (force_implementation) {
163
0
      return get_active_implementation() = force_implementation;
164
0
    } else {
165
      // Note: abort() and stderr usage within the library is forbidden.
166
0
      return get_active_implementation() = get_unsupported_singleton();
167
0
    }
168
0
  }
169
1
  return get_active_implementation() = get_available_implementations().detect_best_supported();
170
1
}
171
172
} // namespace internal
173
174
1
SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list& get_available_implementations() {
175
1
  static const internal::available_implementation_list available_implementations{};
176
1
  return available_implementations;
177
1
}
178
179
11.3k
SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation>& get_active_implementation() {
180
11.3k
    static const internal::detect_best_supported_implementation_on_first_use detect_best_supported_implementation_on_first_use_singleton;
181
11.3k
    static internal::atomic_ptr<const implementation> active_implementation{&detect_best_supported_implementation_on_first_use_singleton};
182
11.3k
    return active_implementation;
183
11.3k
}
184
185
0
simdjson_warn_unused error_code minify(const char *buf, size_t len, char *dst, size_t &dst_len) noexcept {
186
0
  return get_active_implementation()->minify(reinterpret_cast<const uint8_t *>(buf), len, reinterpret_cast<uint8_t *>(dst), dst_len);
187
0
}
188
0
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept {
189
0
  return get_active_implementation()->validate_utf8(buf, len);
190
0
}
191
0
const implementation * builtin_implementation() {
192
0
  static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
193
0
  assert(builtin_impl);
194
0
  return builtin_impl;
195
0
}
196
197
198
} // namespace simdjson