cachelib/cachebench/util/JSONConfig.h (102 lines of code) (raw):
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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.
*/
#pragma once
#include <folly/dynamic.h>
#include <folly/json.h>
#include <string>
#include <unordered_map>
#include <vector>
#define JSONSetVal(configJson, field) \
do { \
const auto* ptr = configJson.get_ptr(#field); \
if ((ptr)) { \
setValImpl(field, *ptr); \
} \
} while (false)
namespace facebook {
namespace cachelib {
namespace cachebench {
struct JSONConfig {
static void setValImpl(uint32_t& field, const folly::dynamic& val) {
field = val.asInt();
}
static void setValImpl(uint64_t& field, const folly::dynamic& val) {
field = val.asInt();
}
// On some platforms (e.g Mac OS 12) 'size_t' and 'uint64_t' are not the same
// type: while both are unsigned 64bit integers, size_t is "unsigned long"
// while "uint64_t" is "unsigned long long". In C they are automatically
// converted from one to the other. In C++ with templates, they result in
// different types and require explicit specialization.
// BUT,
// On platforms where "size_t" is the same as "uint64_t" (e.g. Linux/amd64),
// template specializing of "size_t" will cause compilation error (due to a
// duplicated type). The template code below will safely create the size_t
// specialization only if it differs from uint64_t. See here:
// https://techoverflow.net/2019/06/13/stdenable_if-and-stdis_same-minimal-example/
// and https://eli.thegreenplace.net/2014/sfinae-and-enable_if/
// TODO: use std::is_integral<T> to merge uint32/uint64/size_t etc.
template <
class T = uint64_t,
typename std::enable_if<std::negation<std::is_same<size_t, T>>::value,
void*>::type = nullptr>
static void setValImpl(size_t& field, const folly::dynamic& val) {
field = val.asInt();
}
static void setValImpl(double& field, const folly::dynamic& val) {
field = val.asDouble();
}
static void setValImpl(bool& field, const folly::dynamic& val) {
field = val.asBool();
}
static void setValImpl(std::string& field, const folly::dynamic& val) {
field = val.asString();
}
template <typename ValType>
static void setMapValImpl(
std::unordered_map<uint32_t, std::vector<ValType>>& field,
const folly::dynamic& key,
std::vector<ValType>&& vals) {
field[key.asInt()] = vals;
}
template <typename ValType>
static void setValImpl(std::vector<ValType>& field,
const folly::dynamic& val) {
if (val.isArray()) {
field.clear();
for (const auto& v : val) {
ValType tmp;
setValImpl(tmp, v);
field.push_back(tmp);
}
}
}
template <typename KeyType, typename ValType>
static void setValImpl(std::unordered_map<KeyType, ValType>& field,
const folly::dynamic& val) {
if (val.isObject()) {
field.clear();
for (const auto& pair : val.items()) {
KeyType key;
setValImpl(key, pair.first);
ValType value;
setValImpl(value, pair.second);
field[key] = value;
}
}
}
template <typename KeyType, typename ValType>
static void setValImpl(
std::unordered_map<KeyType, std::vector<ValType>>& field,
const folly::dynamic& val) {
if (val.isObject()) {
field.clear();
for (const auto& pair : val.items()) {
if (pair.second.isArray()) {
std::vector<ValType> tmp;
setValImpl(tmp, pair.second);
setMapValImpl(field, pair.first, std::move(tmp));
}
}
}
}
};
namespace {
template <size_t s>
struct Options {};
} // namespace
template <typename Type, size_t size>
constexpr void checkCorrectSize() {
#ifndef SKIP_OPTION_SIZE_VERIFY
Options<sizeof(Type)> var = Options<size>{};
(void)var;
#endif
}
} // namespace cachebench
} // namespace cachelib
} // namespace facebook