File: common.h

package info (click to toggle)
simdutf 7.7.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,244 kB
  • sloc: cpp: 60,074; ansic: 14,226; python: 3,364; sh: 321; makefile: 12
file content (135 lines) | stat: -rw-r--r-- 4,409 bytes parent folder | download | duplicates (2)
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
// fuzzer helper functions
//
// by Paul Dreik 2024

#pragma once

#include <algorithm>
#include <charconv>
#include <iostream>
#include <span>
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>

#include "simdutf.h"

#include "nameof.hpp"

/// checks that the given type is a member function pointer
template <typename T>
concept member_function_pointer = std::is_member_function_pointer_v<T>;

/// gets a list of implementations to fuzz
inline std::span<const simdutf::implementation* const>
get_supported_implementations() {
  static const auto impl = []() -> auto {
    std::vector<const simdutf::implementation*> ret;
    for (auto e : simdutf::get_available_implementations()) {
      std::cerr << "implementation " << e->name() << " is available? "
                << e->supported_by_runtime_system() << '\n';
      if (e->supported_by_runtime_system()) {
        ret.push_back(e);
      }
    }
    return ret;
  }();
  return {impl.data(), impl.size()};
}

/// this should go into the library instead
inline bool operator!=(const simdutf::result& a, const simdutf::result& b) {
  return a.count != b.count || a.error != b.error;
}
inline bool operator==(const simdutf::result& a, const simdutf::result& b) {
  return a.count == b.count && a.error == b.error;
}
auto operator<=>(const simdutf::result& a, const simdutf::result& b) {
  return std::tie(a.error, a.count) <=> std::tie(b.error, a.count);
}

inline std::ostream& operator<<(std::ostream& os, const simdutf::result& a) {
  os << "[count=" << a.count << ", error=" << NAMEOF_ENUM(a.error) << "]";
  return os;
}

template <typename Data>
constexpr bool is_hashable = std::is_arithmetic_v<Data>;

struct FNV1A_hash {
  static constexpr std::uint64_t prime = 0x00000100000001B3;
  static constexpr std::uint64_t offset = 0xcbf29ce484222325;

  static constexpr std::uint64_t
  fnv1ahash_impl(std::span<const unsigned char> bytes) {
    auto hash = offset;

    for (std::uint64_t byte : bytes) {
      hash ^= byte;
      hash *= prime;
    }

    return hash;
  }
  static constexpr std::uint64_t fnv1ahash_impl(std::span<const char> bytes) {
    auto hash = offset;

    for (auto byte : bytes) {
      hash ^= static_cast<unsigned char>(byte);
      hash *= prime;
    }

    return hash;
  }

  template <typename Basic, std::size_t N>
    requires(is_hashable<Basic> && !std::is_same_v<Basic, char> &&
             !std::is_same_v<Basic, unsigned char>)
  static constexpr std::uint64_t fnv1ahash_impl(std::span<Basic, N> data) {
    return fnv1ahash_impl({reinterpret_cast<const unsigned char*>(data.data()),
                           data.size_bytes()});
  }

  template <typename Data>
    requires is_hashable<Data>
  static constexpr std::uint64_t fnv1ahash_impl(const std::vector<Data>& data) {
    return fnv1ahash_impl(std::span(data));
  }

  template <typename... Data> static std::string as_str(const Data&... data) {
    static_assert(sizeof...(Data) > 0, "must hash with at least one argument");
    std::uint64_t h;
    if constexpr (sizeof...(Data) > 1) {
      const std::array hashes{fnv1ahash_impl(data)...};
      const auto s = std::span(hashes);
      h = fnv1ahash_impl(s);
    } else {
      h = fnv1ahash_impl(data...);
    }
    constexpr std::size_t expected_chars = 16;
    std::string ret(expected_chars, '0');
    auto c = std::to_chars(ret.data(), ret.data() + ret.size(), h, 16);
    assert(c.ec == std::errc{});
    auto nwritten = c.ptr - ret.data();
    assert(nwritten <= expected_chars);
    std::rotate(ret.data(), c.ptr, ret.data() + expected_chars);
    return ret;
  }
};

static_assert(FNV1A_hash::fnv1ahash_impl(std::string_view{""}) ==
              0xcbf29ce484222325);
static_assert(FNV1A_hash::fnv1ahash_impl(std::string_view{"xyz"}) ==
              0xbff4aa198026f420);
#if !defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 12
// work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113294
static_assert(FNV1A_hash::fnv1ahash_impl(std::string{"xyz"}) ==
              0xbff4aa198026f420);
#endif
static_assert(FNV1A_hash::fnv1ahash_impl(std::string_view{"\xFF"}) ==
              0xaf64724c8602eb6e);
static_assert(FNV1A_hash::fnv1ahash_impl(std::string_view{
                  "\x01\x01\x01\x01"}) == 0xb5d0e0774c7d7499);
static_assert(FNV1A_hash::fnv1ahash_impl(std::array<unsigned char, 4>{
                  0x01, 0x01, 0x01, 0x01}) == 0xb5d0e0774c7d7499);