#ifndef wasm_tools_fuzzing_random_h
#define wasm_tools_fuzzing_random_h
#include <cstdint>
#include <map>
#include <vector>
#include "wasm-features.h"
namespace wasm {
class Random {
std::vector<char> bytes;
size_t pos = 0;
bool finishedInput = false;
int xorFactor = 0;
FeatureSet features;
public:
Random(std::vector<char>&& bytes, FeatureSet features);
Random(std::vector<char>&& bytes)
: Random(std::move(bytes), FeatureSet::All) {}
int8_t get();
int16_t get16();
int32_t get32();
int64_t get64();
float getFloat();
double getDouble();
uint32_t upTo(uint32_t x);
bool oneIn(uint32_t x) { return upTo(x) == 0; }
uint32_t upToSquared(uint32_t x) { return upTo(upTo(x)); }
bool finished() { return finishedInput; }
template<typename T> const typename T::value_type& pick(const T& vec) {
assert(!vec.empty());
auto index = upTo(vec.size());
return vec[index];
}
template<typename T, typename... Args> T pick(T first, Args... args) {
auto num = sizeof...(Args) + 1;
auto temp = upTo(num);
return pickGivenNum<T>(temp, first, args...);
}
template<typename T> T pickGivenNum(size_t num, T first) {
assert(num == 0);
return first;
}
#define GCC_VERSION \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if GCC_VERSION > 70000 && GCC_VERSION < 70300
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template<typename T, typename... Args>
T pickGivenNum(size_t num, T first, Args... args) {
if (num == 0) {
return first;
}
return pickGivenNum<T>(num - 1, args...);
}
#if GCC_VERSION > 70000 && GCC_VERSION < 70300
#pragma GCC diagnostic pop
#endif
template<typename T> struct FeatureOptions {
template<typename... Ts>
FeatureOptions<T>& add(FeatureSet feature, T option, Ts... rest) {
options[feature].push_back(option);
return add(feature, rest...);
}
struct WeightedOption {
T option;
size_t weight;
};
template<typename... Ts>
FeatureOptions<T>&
add(FeatureSet feature, WeightedOption weightedOption, Ts... rest) {
for (size_t i = 0; i < weightedOption.weight; i++) {
options[feature].push_back(weightedOption.option);
}
return add(feature, rest...);
}
FeatureOptions<T>& add(FeatureSet feature) { return *this; }
std::map<FeatureSet, std::vector<T>> options;
};
template<typename T> std::vector<T> items(FeatureOptions<T>& picker) {
std::vector<T> matches;
for (const auto& item : picker.options) {
if (features.has(item.first)) {
matches.reserve(matches.size() + item.second.size());
matches.insert(matches.end(), item.second.begin(), item.second.end());
}
}
return matches;
}
template<typename T> const T pick(FeatureOptions<T>& picker) {
return pick(items(picker));
}
};
}
#endif