Coverage Report

Created: 2026-01-17 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/simdutf/fuzz/helpers/common.h
Line
Count
Source
1
// fuzzer helper functions
2
//
3
// by Paul Dreik 2024
4
5
#pragma once
6
7
#include <algorithm>
8
#include <charconv>
9
#include <iostream>
10
#include <span>
11
#include <string>
12
#include <tuple>
13
#include <type_traits>
14
#include <vector>
15
16
#include "simdutf.h"
17
18
#include "nameof.hpp"
19
20
/// checks that the given type is a member function pointer
21
template <typename T>
22
concept member_function_pointer = std::is_member_function_pointer_v<T>;
23
24
/// gets a list of implementations to fuzz
25
inline std::span<const simdutf::implementation* const>
26
37.2k
get_supported_implementations() {
27
37.2k
  static const auto impl = []() -> auto {
28
3
    std::vector<const simdutf::implementation*> ret;
29
12
    for (auto e : simdutf::get_available_implementations()) {
30
12
      std::cerr << "implementation " << e->name() << " is available? "
31
12
                << e->supported_by_runtime_system() << '\n';
32
12
      if (e->supported_by_runtime_system()) {
33
9
        ret.push_back(e);
34
9
      }
35
12
    }
36
3
    return ret;
37
3
  }();
38
37.2k
  return {impl.data(), impl.size()};
39
37.2k
}
40
41
/// this should go into the library instead
42
28.6k
inline bool operator!=(const simdutf::result& a, const simdutf::result& b) {
43
28.6k
  return a.count != b.count || a.error != b.error;
44
28.6k
}
45
13.8k
inline bool operator==(const simdutf::result& a, const simdutf::result& b) {
46
13.8k
  return a.count == b.count && a.error == b.error;
47
13.8k
}
48
0
auto operator<=>(const simdutf::result& a, const simdutf::result& b) {
49
0
  return std::tie(a.error, a.count) <=> std::tie(b.error, a.count);
50
0
}
51
52
0
inline std::ostream& operator<<(std::ostream& os, const simdutf::result& a) {
53
0
  os << "[count=" << a.count << ", error=" << NAMEOF_ENUM(a.error) << "]";
54
0
  return os;
55
0
}
56
57
template <typename Data>
58
constexpr bool is_hashable = std::is_arithmetic_v<Data>;
59
60
struct FNV1A_hash {
61
  static constexpr std::uint64_t prime = 0x00000100000001B3;
62
  static constexpr std::uint64_t offset = 0xcbf29ce484222325;
63
64
  static constexpr std::uint64_t
65
22.6k
  fnv1ahash_impl(std::span<const unsigned char> bytes) {
66
22.6k
    auto hash = offset;
67
68
1.99G
    for (std::uint64_t byte : bytes) {
69
1.99G
      hash ^= byte;
70
1.99G
      hash *= prime;
71
1.99G
    }
72
73
22.6k
    return hash;
74
22.6k
  }
75
25.0k
  static constexpr std::uint64_t fnv1ahash_impl(std::span<const char> bytes) {
76
25.0k
    auto hash = offset;
77
78
1.17G
    for (auto byte : bytes) {
79
1.17G
      hash ^= static_cast<unsigned char>(byte);
80
1.17G
      hash *= prime;
81
1.17G
    }
82
83
25.0k
    return hash;
84
25.0k
  }
85
86
  template <typename Basic, std::size_t N>
87
    requires(is_hashable<Basic> && !std::is_same_v<Basic, char> &&
88
             !std::is_same_v<Basic, unsigned char>)
89
22.6k
  static constexpr std::uint64_t fnv1ahash_impl(std::span<Basic, N> data) {
90
22.6k
    return fnv1ahash_impl({reinterpret_cast<const unsigned char*>(data.data()),
91
22.6k
                           data.size_bytes()});
92
22.6k
  }
_ZN10FNV1A_hash14fnv1ahash_implIKDsLm18446744073709551615EQaaaa11is_hashableIT_Entsr3stdE9is_same_vIS2_cEntsr3stdE9is_same_vIS2_hEEEmNSt3__14spanIS2_XT0_EEE
Line
Count
Source
89
14.4k
  static constexpr std::uint64_t fnv1ahash_impl(std::span<Basic, N> data) {
90
14.4k
    return fnv1ahash_impl({reinterpret_cast<const unsigned char*>(data.data()),
91
14.4k
                           data.size_bytes()});
92
14.4k
  }
Unexecuted instantiation: _ZN10FNV1A_hash14fnv1ahash_implIKmLm2EQaaaa11is_hashableIT_Entsr3stdE9is_same_vIS2_cEntsr3stdE9is_same_vIS2_hEEEmNSt3__14spanIS2_XT0_EEE
_ZN10FNV1A_hash14fnv1ahash_implIKDiLm18446744073709551615EQaaaa11is_hashableIT_Entsr3stdE9is_same_vIS2_cEntsr3stdE9is_same_vIS2_hEEEmNSt3__14spanIS2_XT0_EEE
Line
Count
Source
89
8.18k
  static constexpr std::uint64_t fnv1ahash_impl(std::span<Basic, N> data) {
90
8.18k
    return fnv1ahash_impl({reinterpret_cast<const unsigned char*>(data.data()),
91
8.18k
                           data.size_bytes()});
92
8.18k
  }
93
94
  template <typename Data>
95
    requires is_hashable<Data>
96
46.6k
  static constexpr std::uint64_t fnv1ahash_impl(const std::vector<Data>& data) {
97
46.6k
    return fnv1ahash_impl(std::span(data));
98
46.6k
  }
_ZN10FNV1A_hash14fnv1ahash_implIcQ11is_hashableIT_EEEmRKNSt3__16vectorIS1_NS2_9allocatorIS1_EEEE
Line
Count
Source
96
23.9k
  static constexpr std::uint64_t fnv1ahash_impl(const std::vector<Data>& data) {
97
23.9k
    return fnv1ahash_impl(std::span(data));
98
23.9k
  }
_ZN10FNV1A_hash14fnv1ahash_implIDsQ11is_hashableIT_EEEmRKNSt3__16vectorIS1_NS2_9allocatorIS1_EEEE
Line
Count
Source
96
14.4k
  static constexpr std::uint64_t fnv1ahash_impl(const std::vector<Data>& data) {
97
14.4k
    return fnv1ahash_impl(std::span(data));
98
14.4k
  }
_ZN10FNV1A_hash14fnv1ahash_implIDiQ11is_hashableIT_EEEmRKNSt3__16vectorIS1_NS2_9allocatorIS1_EEEE
Line
Count
Source
96
8.18k
  static constexpr std::uint64_t fnv1ahash_impl(const std::vector<Data>& data) {
97
8.18k
    return fnv1ahash_impl(std::span(data));
98
8.18k
  }
99
100
47.7k
  template <typename... Data> static std::string as_str(const Data&... data) {
101
47.7k
    static_assert(sizeof...(Data) > 0, "must hash with at least one argument");
102
47.7k
    std::uint64_t h;
103
47.7k
    if constexpr (sizeof...(Data) > 1) {
104
0
      const std::array hashes{fnv1ahash_impl(data)...};
105
0
      const auto s = std::span(hashes);
106
0
      h = fnv1ahash_impl(s);
107
47.7k
    } else {
108
47.7k
      h = fnv1ahash_impl(data...);
109
47.7k
    }
110
47.7k
    constexpr std::size_t expected_chars = 16;
111
47.7k
    std::string ret(expected_chars, '0');
112
47.7k
    auto c = std::to_chars(ret.data(), ret.data() + ret.size(), h, 16);
113
47.7k
    assert(c.ec == std::errc{});
114
47.7k
    auto nwritten = c.ptr - ret.data();
115
47.7k
    assert(nwritten <= expected_chars);
116
47.7k
    std::rotate(ret.data(), c.ptr, ret.data() + expected_chars);
117
47.7k
    return ret;
118
47.7k
  }
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > FNV1A_hash::as_str<std::__1::span<char const, 18446744073709551615ul> >(std::__1::span<char const, 18446744073709551615ul> const&)
Line
Count
Source
100
1.11k
  template <typename... Data> static std::string as_str(const Data&... data) {
101
1.11k
    static_assert(sizeof...(Data) > 0, "must hash with at least one argument");
102
1.11k
    std::uint64_t h;
103
    if constexpr (sizeof...(Data) > 1) {
104
      const std::array hashes{fnv1ahash_impl(data)...};
105
      const auto s = std::span(hashes);
106
      h = fnv1ahash_impl(s);
107
1.11k
    } else {
108
1.11k
      h = fnv1ahash_impl(data...);
109
1.11k
    }
110
1.11k
    constexpr std::size_t expected_chars = 16;
111
1.11k
    std::string ret(expected_chars, '0');
112
1.11k
    auto c = std::to_chars(ret.data(), ret.data() + ret.size(), h, 16);
113
1.11k
    assert(c.ec == std::errc{});
114
1.11k
    auto nwritten = c.ptr - ret.data();
115
1.11k
    assert(nwritten <= expected_chars);
116
1.11k
    std::rotate(ret.data(), c.ptr, ret.data() + expected_chars);
117
1.11k
    return ret;
118
1.11k
  }
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > FNV1A_hash::as_str<std::__1::vector<char, std::__1::allocator<char> > >(std::__1::vector<char, std::__1::allocator<char> > const&)
Line
Count
Source
100
23.9k
  template <typename... Data> static std::string as_str(const Data&... data) {
101
23.9k
    static_assert(sizeof...(Data) > 0, "must hash with at least one argument");
102
23.9k
    std::uint64_t h;
103
    if constexpr (sizeof...(Data) > 1) {
104
      const std::array hashes{fnv1ahash_impl(data)...};
105
      const auto s = std::span(hashes);
106
      h = fnv1ahash_impl(s);
107
23.9k
    } else {
108
23.9k
      h = fnv1ahash_impl(data...);
109
23.9k
    }
110
23.9k
    constexpr std::size_t expected_chars = 16;
111
23.9k
    std::string ret(expected_chars, '0');
112
23.9k
    auto c = std::to_chars(ret.data(), ret.data() + ret.size(), h, 16);
113
23.9k
    assert(c.ec == std::errc{});
114
23.9k
    auto nwritten = c.ptr - ret.data();
115
23.9k
    assert(nwritten <= expected_chars);
116
23.9k
    std::rotate(ret.data(), c.ptr, ret.data() + expected_chars);
117
23.9k
    return ret;
118
23.9k
  }
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > FNV1A_hash::as_str<std::__1::vector<char16_t, std::__1::allocator<char16_t> > >(std::__1::vector<char16_t, std::__1::allocator<char16_t> > const&)
Line
Count
Source
100
14.4k
  template <typename... Data> static std::string as_str(const Data&... data) {
101
14.4k
    static_assert(sizeof...(Data) > 0, "must hash with at least one argument");
102
14.4k
    std::uint64_t h;
103
    if constexpr (sizeof...(Data) > 1) {
104
      const std::array hashes{fnv1ahash_impl(data)...};
105
      const auto s = std::span(hashes);
106
      h = fnv1ahash_impl(s);
107
14.4k
    } else {
108
14.4k
      h = fnv1ahash_impl(data...);
109
14.4k
    }
110
14.4k
    constexpr std::size_t expected_chars = 16;
111
14.4k
    std::string ret(expected_chars, '0');
112
14.4k
    auto c = std::to_chars(ret.data(), ret.data() + ret.size(), h, 16);
113
14.4k
    assert(c.ec == std::errc{});
114
14.4k
    auto nwritten = c.ptr - ret.data();
115
14.4k
    assert(nwritten <= expected_chars);
116
14.4k
    std::rotate(ret.data(), c.ptr, ret.data() + expected_chars);
117
14.4k
    return ret;
118
14.4k
  }
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > FNV1A_hash::as_str<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::span<char16_t const, 18446744073709551615ul> >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::span<char16_t const, 18446744073709551615ul> const&)
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > FNV1A_hash::as_str<std::__1::vector<char32_t, std::__1::allocator<char32_t> > >(std::__1::vector<char32_t, std::__1::allocator<char32_t> > const&)
Line
Count
Source
100
8.18k
  template <typename... Data> static std::string as_str(const Data&... data) {
101
8.18k
    static_assert(sizeof...(Data) > 0, "must hash with at least one argument");
102
8.18k
    std::uint64_t h;
103
    if constexpr (sizeof...(Data) > 1) {
104
      const std::array hashes{fnv1ahash_impl(data)...};
105
      const auto s = std::span(hashes);
106
      h = fnv1ahash_impl(s);
107
8.18k
    } else {
108
8.18k
      h = fnv1ahash_impl(data...);
109
8.18k
    }
110
8.18k
    constexpr std::size_t expected_chars = 16;
111
8.18k
    std::string ret(expected_chars, '0');
112
8.18k
    auto c = std::to_chars(ret.data(), ret.data() + ret.size(), h, 16);
113
8.18k
    assert(c.ec == std::errc{});
114
8.18k
    auto nwritten = c.ptr - ret.data();
115
8.18k
    assert(nwritten <= expected_chars);
116
8.18k
    std::rotate(ret.data(), c.ptr, ret.data() + expected_chars);
117
8.18k
    return ret;
118
8.18k
  }
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > FNV1A_hash::as_str<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::span<char32_t const, 18446744073709551615ul> >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::span<char32_t const, 18446744073709551615ul> const&)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > FNV1A_hash::as_str<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::span<char const, 18446744073709551615ul> >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::span<char const, 18446744073709551615ul> const&)
119
};
120
121
static_assert(FNV1A_hash::fnv1ahash_impl(std::string_view{""}) ==
122
              0xcbf29ce484222325);
123
static_assert(FNV1A_hash::fnv1ahash_impl(std::string_view{"xyz"}) ==
124
              0xbff4aa198026f420);
125
#if !defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 12
126
// work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113294
127
static_assert(FNV1A_hash::fnv1ahash_impl(std::string{"xyz"}) ==
128
              0xbff4aa198026f420);
129
#endif
130
static_assert(FNV1A_hash::fnv1ahash_impl(std::string_view{"\xFF"}) ==
131
              0xaf64724c8602eb6e);
132
static_assert(FNV1A_hash::fnv1ahash_impl(std::string_view{
133
                  "\x01\x01\x01\x01"}) == 0xb5d0e0774c7d7499);
134
static_assert(FNV1A_hash::fnv1ahash_impl(std::array<unsigned char, 4>{
135
                  0x01, 0x01, 0x01, 0x01}) == 0xb5d0e0774c7d7499);