blob: 8f81b6bafaac94c8540e84eac337a4020a15366d [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
/// \file iceberg/util/config.h
/// \brief Provide typed configuration helpers.
#include <format>
#include <functional>
#include <string>
#include <unordered_map>
#include "iceberg/exception.h"
#include "iceberg/util/macros.h"
#include "iceberg/util/string_util.h"
namespace iceberg {
namespace internal {
// Default conversion functions
template <typename U>
std::string DefaultToString(const U& val) {
if constexpr ((std::is_signed_v<U> && std::is_integral_v<U>) ||
std::is_floating_point_v<U>) {
return std::to_string(val);
} else if constexpr (std::is_same_v<U, bool>) {
return val ? "true" : "false";
} else if constexpr (std::is_same_v<U, std::string> ||
std::is_same_v<U, std::string_view>) {
return val;
} else {
throw IcebergError(
std::format("Explicit to_str() is required for {}", typeid(U).name()));
}
}
template <typename U>
U DefaultFromString(const std::string& val) {
if constexpr (std::is_same_v<U, std::string>) {
return val;
} else if constexpr (std::is_same_v<U, bool>) {
return StringUtils::ParseBoolean(val);
} else if constexpr ((std::is_signed_v<U> && std::is_integral_v<U>) ||
std::is_floating_point_v<U>) {
ICEBERG_ASSIGN_OR_THROW(auto res, StringUtils::ParseNumber<U>(val));
return res;
} else {
throw IcebergError(
std::format("Explicit from_str() is required for {}", typeid(U).name()));
}
}
} // namespace internal
template <class ConcreteConfig>
class ConfigBase {
public:
template <typename T>
class Entry {
public:
Entry(std::string key, T val,
std::function<std::string(const T&)> to_str = internal::DefaultToString<T>,
std::function<T(const std::string&)> from_str = internal::DefaultFromString<T>)
: key_{std::move(key)},
default_{std::move(val)},
to_str_{std::move(to_str)},
from_str_{std::move(from_str)} {}
private:
const std::string key_;
const T default_;
const std::function<std::string(const T&)> to_str_;
const std::function<T(const std::string&)> from_str_;
friend ConfigBase;
friend ConcreteConfig;
public:
const std::string& key() const { return key_; }
const T& value() const { return default_; }
};
template <typename T>
ConfigBase& Set(const Entry<T>& entry, const T& val) {
configs_[entry.key_] = entry.to_str_(val);
return *this;
}
template <typename T>
ConfigBase& Unset(const Entry<T>& entry) {
configs_.erase(entry.key_);
return *this;
}
ConfigBase& Reset() {
configs_.clear();
return *this;
}
template <typename T>
T Get(const Entry<T>& entry) const {
auto iter = configs_.find(entry.key_);
return iter != configs_.cend() ? entry.from_str_(iter->second) : entry.default_;
}
const std::unordered_map<std::string, std::string>& configs() const { return configs_; }
std::unordered_map<std::string, std::string>& mutable_configs() { return configs_; }
/// \brief Extracts the prefix from the configuration.
/// \param prefix The prefix to extract.
/// \return A map of entries that match the prefix with prefix removed.
std::unordered_map<std::string, std::string> Extract(std::string_view prefix) const {
std::unordered_map<std::string, std::string> extracted;
for (const auto& [key, value] : configs_) {
if (key.starts_with(prefix)) {
extracted[key.substr(prefix.length())] = value;
}
}
return extracted;
}
protected:
std::unordered_map<std::string, std::string> configs_;
};
} // namespace iceberg