// Copyright 2019 The Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef TESTS_PARAMGENERATOR_H_ #define TESTS_PARAMGENERATOR_H_ #include #include // ParamStruct is a custom struct which ParamStruct will yield when iterating. // The types Params... should be the same as the types passed to the constructor // of ParamStruct. template class ParamGenerator { using ParamTuple = std::tuple...>; using Index = std::array; static constexpr auto s_indexSequence = std::make_index_sequence{}; // Using an N-dimensional Index, extract params from ParamTuple and pass // them to the constructor of ParamStruct. template static ParamStruct GetParam(const ParamTuple& params, const Index& index, std::index_sequence) { return ParamStruct(std::get(params)[std::get(index)]...); } // Get the last value index into a ParamTuple. template static Index GetLastIndex(const ParamTuple& params, std::index_sequence) { return Index{std::get(params).size() - 1 ...}; } public: using value_type = ParamStruct; ParamGenerator(std::vector... params) : mParams(params...) { } class Iterator : public std::iterator { public: Iterator& operator++() { // Increment the Index by 1. If the i'th place reaches the maximum, // reset it to 0 and continue with the i+1'th place. for (int i = mIndex.size() - 1; i >= 0; --i) { if (mIndex[i] >= mLastIndex[i]) { mIndex[i] = 0; } else { mIndex[i]++; return *this; } } // Set a marker that the iterator has reached the end. mEnd = true; return *this; } bool operator==(const Iterator& other) const { return mEnd == other.mEnd && mIndex == other.mIndex; } bool operator!=(const Iterator& other) const { return !(*this == other); } ParamStruct operator*() const { return GetParam(mParams, mIndex, s_indexSequence); } private: friend class ParamGenerator; Iterator(ParamTuple params, Index index) : mParams(params), mIndex(index), mLastIndex{GetLastIndex(params, s_indexSequence)} { } ParamTuple mParams; Index mIndex; Index mLastIndex; bool mEnd = false; }; Iterator begin() const { return Iterator(mParams, {}); } Iterator end() const { Iterator iter(mParams, GetLastIndex(mParams, s_indexSequence)); ++iter; return iter; } private: ParamTuple mParams; }; template auto MakeParamGenerator(std::vector&& first, std::initializer_list&&... params) { return ParamGenerator( ::detail::GetAvailableAdapterTestParamsForBackends(first.data(), first.size()), std::forward&&>(params)...); } #endif // TESTS_PARAMGENERATOR_H_