120 lines · plain
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file contains the definition of the ExhaustiveGenerator class, a11/// concrete range-based generator that exhaustively creates inputs from a12/// given sequence of ranges.13///14//===----------------------------------------------------------------------===//15 16#ifndef MATHTEST_EXHAUSTIVEGENERATOR_HPP17#define MATHTEST_EXHAUSTIVEGENERATOR_HPP18 19#include "mathtest/IndexedRange.hpp"20#include "mathtest/RangeBasedGenerator.hpp"21 22#include <array>23#include <cassert>24#include <cstddef>25#include <cstdint>26#include <optional>27#include <tuple>28 29namespace mathtest {30 31template <typename... InTypes>32class [[nodiscard]] ExhaustiveGenerator final33 : public RangeBasedGenerator<ExhaustiveGenerator<InTypes...>, InTypes...> {34 35 friend class RangeBasedGenerator<ExhaustiveGenerator<InTypes...>, InTypes...>;36 37 using Base = RangeBasedGenerator<ExhaustiveGenerator<InTypes...>, InTypes...>;38 using IndexArrayType = std::array<uint64_t, Base::NumInputs>;39 40 using Base::RangesTuple;41 using Base::Size;42 43public:44 explicit constexpr ExhaustiveGenerator(45 const IndexedRange<InTypes> &...Ranges) noexcept46 : Base(Ranges...) {47 const auto MaybeSize = getInputSpaceSize(Ranges...);48 49 assert(MaybeSize.has_value() && "The size is too large");50 Size = *MaybeSize;51 52 assert((Size > 0) && "The size must be at least 1");53 54 IndexArrayType DimSizes = {};55 std::size_t DimIndex = 0;56 ((DimSizes[DimIndex++] = Ranges.getSize()), ...);57 58 Strides[Base::NumInputs - 1] = 1;59 if constexpr (Base::NumInputs > 1)60 for (int Index = static_cast<int>(Base::NumInputs) - 2; Index >= 0;61 --Index)62 Strides[Index] = Strides[Index + 1] * DimSizes[Index + 1];63 }64 65private:66 [[nodiscard]] constexpr IndexArrayType67 getNDIndex(uint64_t FlatIndex) const noexcept {68 IndexArrayType NDIndex;69 70 for (std::size_t Index = 0; Index < Base::NumInputs; ++Index) {71 NDIndex[Index] = FlatIndex / Strides[Index];72 FlatIndex -= NDIndex[Index] * Strides[Index];73 }74 75 return NDIndex;76 }77 78 template <typename BufferPtrsTupleType>79 void writeInputs(uint64_t CurrentFlatIndex, uint64_t Offset,80 BufferPtrsTupleType BufferPtrsTuple) const noexcept {81 auto NDIndex = getNDIndex(CurrentFlatIndex + Offset);82 writeInputsImpl<0>(NDIndex, Offset, BufferPtrsTuple);83 }84 85 template <std::size_t Index, typename BufferPtrsTupleType>86 void writeInputsImpl(IndexArrayType NDIndex, uint64_t Offset,87 BufferPtrsTupleType BufferPtrsTuple) const noexcept {88 if constexpr (Index < Base::NumInputs) {89 const auto &Range = std::get<Index>(RangesTuple);90 std::get<Index>(BufferPtrsTuple)[Offset] = Range[NDIndex[Index]];91 92 writeInputsImpl<Index + 1>(NDIndex, Offset, BufferPtrsTuple);93 }94 }95 96 [[nodiscard]] static constexpr std::optional<uint64_t>97 getInputSpaceSize(const IndexedRange<InTypes> &...Ranges) noexcept {98 uint64_t InputSpaceSize = 1;99 bool Overflowed = false;100 101 auto Multiplier = [&](const uint64_t RangeSize) {102 if (!Overflowed)103 Overflowed =104 __builtin_mul_overflow(InputSpaceSize, RangeSize, &InputSpaceSize);105 };106 107 (Multiplier(Ranges.getSize()), ...);108 109 if (Overflowed)110 return std::nullopt;111 112 return InputSpaceSize;113 }114 115 IndexArrayType Strides = {};116};117} // namespace mathtest118 119#endif // MATHTEST_EXHAUSTIVEGENERATOR_HPP120