brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.7 KiB · 39c6838 Raw
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