| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef TEST_LIBCXX_FUZZING_FUZZ_H |
| #define TEST_LIBCXX_FUZZING_FUZZ_H |
| |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> // std::strlen |
| #include <type_traits> |
| #include <utility> // std::swap |
| |
| |
| // This is a struct we can use to test the stable_XXX algorithms. |
| // Perform the operation on the key, then check the order of the payload. |
| struct ByteWithPayload { |
| std::uint8_t key; |
| std::size_t payload; |
| |
| ByteWithPayload(std::uint8_t k) : key(k), payload(0) { } |
| ByteWithPayload(std::uint8_t k, std::size_t p) : key(k), payload(p) { } |
| |
| friend bool operator==(ByteWithPayload const& x, ByteWithPayload const& y) { |
| return x.key == y.key && x.payload == y.payload; |
| } |
| |
| friend bool operator!=(ByteWithPayload const& x, ByteWithPayload const& y) { |
| return !(x == y); |
| } |
| |
| struct key_less { |
| bool operator()(ByteWithPayload const& x, ByteWithPayload const& y) const |
| { return x.key < y.key; } |
| }; |
| |
| struct payload_less { |
| bool operator()(ByteWithPayload const& x, ByteWithPayload const& y) const |
| { return x.payload < y.payload; } |
| }; |
| |
| struct total_less { |
| bool operator()(ByteWithPayload const& x, ByteWithPayload const& y) const { |
| return x.key == y.key ? x.payload < y.payload : x.key < y.key; |
| } |
| }; |
| |
| friend void swap(ByteWithPayload& lhs, ByteWithPayload& rhs) { |
| std::swap(lhs.key, rhs.key); |
| std::swap(lhs.payload, rhs.payload); |
| } |
| }; |
| |
| // Faster version of std::is_permutation |
| // |
| // Builds a set of buckets for each of the key values, and sums all the payloads. |
| // Not 100% perfect, but _way_ faster. |
| template <typename Iter1, typename Iter2, typename = typename std::enable_if< |
| std::is_same<typename std::iterator_traits<Iter1>::value_type, ByteWithPayload>::value && |
| std::is_same<typename std::iterator_traits<Iter2>::value_type, ByteWithPayload>::value |
| >::type> |
| bool fast_is_permutation(Iter1 first1, Iter1 last1, Iter2 first2) { |
| std::size_t xBuckets[256] = {0}; |
| std::size_t xPayloads[256] = {0}; |
| std::size_t yBuckets[256] = {0}; |
| std::size_t yPayloads[256] = {0}; |
| |
| for (; first1 != last1; ++first1, ++first2) { |
| xBuckets[first1->key]++; |
| xPayloads[first1->key] += first1->payload; |
| |
| yBuckets[first2->key]++; |
| yPayloads[first2->key] += first2->payload; |
| } |
| |
| for (std::size_t i = 0; i < 256; ++i) { |
| if (xBuckets[i] != yBuckets[i]) |
| return false; |
| if (xPayloads[i] != yPayloads[i]) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| template <typename Iter1, typename Iter2, typename = void, typename = typename std::enable_if< |
| std::is_same<typename std::iterator_traits<Iter1>::value_type, std::uint8_t>::value && |
| std::is_same<typename std::iterator_traits<Iter2>::value_type, std::uint8_t>::value |
| >::type> |
| bool fast_is_permutation(Iter1 first1, Iter1 last1, Iter2 first2) { |
| std::size_t xBuckets[256] = {0}; |
| std::size_t yBuckets[256] = {0}; |
| |
| for (; first1 != last1; ++first1, ++first2) { |
| xBuckets[*first1]++; |
| yBuckets[*first2]++; |
| } |
| |
| for (std::size_t i = 0; i < 256; ++i) |
| if (xBuckets[i] != yBuckets[i]) |
| return false; |
| |
| return true; |
| } |
| |
| // When running inside OSS-Fuzz, we link against a fuzzing library that defines |
| // main() and calls LLVMFuzzerTestOneInput. |
| // |
| // Otherwise, when e.g. running the Lit tests, we define main() to run fuzzing |
| // tests on a few inputs. |
| #if !defined(LIBCPP_OSS_FUZZ) |
| extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t*, std::size_t); |
| |
| int main(int, char**) { |
| const char* test_cases[] = { |
| "", |
| "s", |
| "bac", |
| "bacasf", |
| "lkajseravea", |
| "adsfkajdsfjkas;lnc441324513,34535r34525234", |
| "b*c", |
| "ba?sf", |
| "lka*ea", |
| "adsf*kas;lnc441[0-9]1r34525234" |
| }; |
| |
| for (const char* tc : test_cases) { |
| const std::size_t size = std::strlen(tc); |
| const std::uint8_t* data = reinterpret_cast<const std::uint8_t*>(tc); |
| int result = LLVMFuzzerTestOneInput(data, size); |
| assert(result == 0); |
| } |
| |
| return 0; |
| } |
| #endif // !LIBCPP_OSS_FUZZ |
| |
| #endif // TEST_LIBCXX_FUZZING_FUZZ_H |