#pragma once #include #include #include #include #include #include "storage/common/types/property_value.hpp" namespace snapshot_generation { // Helper class for property value generation. class ValueGenerator { using json = nlohmann::json; public: // Generates the whole property map based on the given config. std::unordered_map MakeProperties( const json &config) { std::unordered_map props; if (config.is_null()) return props; CHECK(config.is_object()) << "Properties config must be a dict"; for (auto it = config.begin(); it != config.end(); it++) { auto value = MakeValue(it.value()); if (value) props.emplace(it.key(), *value); } return props; } // Generates a single value based on the given config. std::experimental::optional MakeValue(const json &config) { if (config.is_object()) { const std::string &type = config["type"]; const auto ¶m = config["param"]; if (type == "primitive") return Primitive(param); if (type == "counter") return Counter(param); if (type == "optional") return Optional(param); if (type == "bernoulli") return Bernoulli(param); if (type == "randint") return RandInt(param); if (type == "randstring") return RandString(param); LOG(FATAL) << "Unknown value type"; } else { return Primitive(config); } } // Returns whatever value is stored in the JSON PropertyValue Primitive(const json &config) { if (config.is_string()) return config.get(); if (config.is_number_integer()) return config.get(); if (config.is_number_float()) return config.get(); if (config.is_boolean()) return config.get(); LOG(FATAL) << "Unsupported primitive type"; } // Increments the counter and returns its current value int64_t Counter(const std::string &name) { return counters_[name]++; } // Generates a random integer in range specified by JSON config int64_t RandInt(const json &range) { CHECK(range.is_array() && range.size() == 2) << "RandInt value gen config must be a list with 2 elements"; auto from = MakeValue(range[0])->Value(); auto to = MakeValue(range[1])->Value(); CHECK(from < to) << "RandInt lower range must be lesser than upper range"; return (int64_t)(rand_(gen_) * (to - from)) + from; } // Generates a random alphanumeric string with length specified by JSON config std::string RandString(const json &length) { static const char alphanum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; int length_int = MakeValue(length)->Value(); std::string r_val(length_int, 'a'); for (int i = 0; i < length_int; ++i) r_val[i] = alphanum[(int64_t)(rand_(gen_) * strlen(alphanum))]; return r_val; } // Returns true with given probability bool Bernoulli(double p) { return rand_(gen_) < p; } // Returns a value specified by config with some probability, and nullopt // otherwise std::experimental::optional Optional(const json &config) { CHECK(config.is_array() && config.size() == 2) << "Optional value gen config must be a list with 2 elements"; return Bernoulli(config[0]) ? MakeValue(config[1]) : std::experimental::nullopt; } private: std::mt19937 gen_{std::random_device{}()}; std::uniform_real_distribution<> rand_{0.0, 1.0}; std::unordered_map counters_; }; } // namespace snapshot_generation