config/Data: use std::forward_list to manage params and blocks

This commit is contained in:
Max Kellermann 2018-07-18 11:03:19 +02:00
parent fd80683ade
commit 9ff2606bb8
11 changed files with 85 additions and 116 deletions

View File

@ -88,14 +88,13 @@ listen_global_init(const ConfigData &config, ClientListener &listener)
return; return;
#endif #endif
for (const auto *param = config.GetParam(ConfigOption::BIND_TO_ADDRESS); for (const auto &param : config.GetParamList(ConfigOption::BIND_TO_ADDRESS)) {
param != nullptr; param = param->next) {
try { try {
listen_add_config_param(listener, port, param); listen_add_config_param(listener, port, &param);
} catch (...) { } catch (...) {
std::throw_with_nested(FormatRuntimeError("Failed to listen on %s (line %i)", std::throw_with_nested(FormatRuntimeError("Failed to listen on %s (line %i)",
param->value.c_str(), param.value.c_str(),
param->line)); param.line));
} }
} }

View File

@ -91,37 +91,32 @@ void
initPermissions(const ConfigData &config) initPermissions(const ConfigData &config)
{ {
unsigned permission; unsigned permission;
const ConfigParam *param;
permission_default = PERMISSION_READ | PERMISSION_ADD | permission_default = PERMISSION_READ | PERMISSION_ADD |
PERMISSION_CONTROL | PERMISSION_ADMIN; PERMISSION_CONTROL | PERMISSION_ADMIN;
param = config.GetParam(ConfigOption::PASSWORD); for (const auto &param : config.GetParamList(ConfigOption::PASSWORD)) {
if (param) {
permission_default = 0; permission_default = 0;
do { const char *separator = strchr(param.value.c_str(),
const char *separator = PERMISSION_PASSWORD_CHAR);
strchr(param->value.c_str(),
PERMISSION_PASSWORD_CHAR);
if (separator == NULL) if (separator == NULL)
throw FormatRuntimeError("\"%c\" not found in password string " throw FormatRuntimeError("\"%c\" not found in password string "
"\"%s\", line %i", "\"%s\", line %i",
PERMISSION_PASSWORD_CHAR, PERMISSION_PASSWORD_CHAR,
param->value.c_str(), param.value.c_str(),
param->line); param.line);
std::string password(param->value.c_str(), separator); std::string password(param.value.c_str(), separator);
permission = parsePermissions(separator + 1); permission = parsePermissions(separator + 1);
permission_passwords.insert(std::make_pair(std::move(password), permission_passwords.insert(std::make_pair(std::move(password),
permission)); permission));
} while ((param = param->next) != nullptr);
} }
const ConfigParam *param;
param = config.GetParam(ConfigOption::DEFAULT_PERMS); param = config.GetParam(ConfigOption::DEFAULT_PERMS);
if (param) if (param)

View File

@ -78,11 +78,6 @@ BlockParam::GetBoolValue() const
return value2; return value2;
} }
ConfigBlock::~ConfigBlock()
{
delete next;
}
const BlockParam * const BlockParam *
ConfigBlock::GetBlockParam(const char *name) const noexcept ConfigBlock::GetBlockParam(const char *name) const noexcept
{ {

View File

@ -55,12 +55,6 @@ struct BlockParam {
}; };
struct ConfigBlock { struct ConfigBlock {
/**
* The next #ConfigBlock with the same name. The destructor
* deletes the whole chain.
*/
ConfigBlock *next = nullptr;
int line; int line;
std::vector<BlockParam> block_params; std::vector<BlockParam> block_params;
@ -74,11 +68,8 @@ struct ConfigBlock {
explicit ConfigBlock(int _line=-1) explicit ConfigBlock(int _line=-1)
:line(_line) {} :line(_line) {}
ConfigBlock(const ConfigBlock &) = delete; ConfigBlock(ConfigBlock &&) = default;
ConfigBlock &operator=(ConfigBlock &&) = default;
~ConfigBlock();
ConfigBlock &operator=(const ConfigBlock &) = delete;
/** /**
* Determine if this is a "null" instance, i.e. an empty * Determine if this is a "null" instance, i.e. an empty

View File

@ -19,8 +19,6 @@
#include "config.h" #include "config.h"
#include "Data.hxx" #include "Data.hxx"
#include "Param.hxx"
#include "Block.hxx"
#include "Parser.hxx" #include "Parser.hxx"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
@ -31,35 +29,36 @@
void void
ConfigData::Clear() ConfigData::Clear()
{ {
for (auto &i : params) { for (auto &i : params)
delete i; i.clear();
i = nullptr;
}
for (auto &i : blocks) { for (auto &i : blocks)
delete i; i.clear();
i = nullptr;
}
} }
gcc_nonnull_all template<typename T>
static void gcc_pure
Append(ConfigParam *&head, ConfigParam *p) static auto
FindLast(const std::forward_list<T> &list)
{ {
assert(p->next == nullptr); auto i = list.before_begin();
while (std::next(i) != list.end())
++i;
return i;
}
auto **i = &head; template<typename T>
while (*i != nullptr) static auto
i = &(*i)->next; Append(std::forward_list<T> &list, T &&src)
{
*i = p; return list.emplace_after(FindLast(list), std::move(src));
} }
void void
ConfigData::AddParam(ConfigOption option, ConfigData::AddParam(ConfigOption option,
std::unique_ptr<ConfigParam> param) noexcept std::unique_ptr<ConfigParam> param) noexcept
{ {
Append(params[size_t(option)], param.release()); Append(GetParamList(option), std::move(*param));
} }
const char * const char *
@ -143,39 +142,25 @@ ConfigData::GetBool(ConfigOption option, bool default_value) const
return value; return value;
} }
gcc_nonnull_all ConfigBlock &
static void
Append(ConfigBlock *&head, ConfigBlock *p)
{
assert(p->next == nullptr);
auto **i = &head;
while (*i != nullptr)
i = &(*i)->next;
*i = p;
}
void
ConfigData::AddBlock(ConfigBlockOption option, ConfigData::AddBlock(ConfigBlockOption option,
std::unique_ptr<ConfigBlock> block) noexcept std::unique_ptr<ConfigBlock> block) noexcept
{ {
Append(blocks[size_t(option)], block.release()); return *Append(GetBlockList(option), std::move(*block));
} }
const ConfigBlock * const ConfigBlock *
ConfigData::FindBlock(ConfigBlockOption option, ConfigData::FindBlock(ConfigBlockOption option,
const char *key, const char *value) const const char *key, const char *value) const
{ {
for (const auto *block = GetBlock(option); for (const auto &block : GetBlockList(option)) {
block != nullptr; block = block->next) { const char *value2 = block.GetBlockValue(key);
const char *value2 = block->GetBlockValue(key);
if (value2 == nullptr) if (value2 == nullptr)
throw FormatRuntimeError("block without '%s' in line %d", throw FormatRuntimeError("block without '%s' in line %d",
key, block->line); key, block.line);
if (StringIsEqual(value2, value)) if (StringIsEqual(value2, value))
return block; return &block;
} }
return nullptr; return nullptr;
@ -189,8 +174,7 @@ ConfigData::MakeBlock(ConfigBlockOption option,
if (block == nullptr) { if (block == nullptr) {
auto new_block = std::make_unique<ConfigBlock>(); auto new_block = std::make_unique<ConfigBlock>();
new_block->AddBlockParam(key, value); new_block->AddBlockParam(key, value);
block = new_block.get(); block = &AddBlock(option, std::move(new_block));
AddBlock(option, std::move(new_block));
} }
return *block; return *block;

View File

@ -21,9 +21,12 @@
#define MPD_CONFIG_DATA_HXX #define MPD_CONFIG_DATA_HXX
#include "Option.hxx" #include "Option.hxx"
#include "Param.hxx"
#include "Block.hxx"
#include <array> #include <array>
#include <chrono> #include <chrono>
#include <forward_list>
#include <memory> #include <memory>
struct ConfigParam; struct ConfigParam;
@ -31,17 +34,26 @@ struct ConfigBlock;
class AllocatedPath; class AllocatedPath;
struct ConfigData { struct ConfigData {
std::array<ConfigParam *, std::size_t(ConfigOption::MAX)> params{{nullptr}}; std::array<std::forward_list<ConfigParam>, std::size_t(ConfigOption::MAX)> params;
std::array<ConfigBlock *, std::size_t(ConfigBlockOption::MAX)> blocks{{nullptr}}; std::array<std::forward_list<ConfigBlock>, std::size_t(ConfigBlockOption::MAX)> blocks;
void Clear(); void Clear();
auto &GetParamList(ConfigOption option) noexcept {
return params[size_t(option)];
}
const auto &GetParamList(ConfigOption option) const noexcept {
return params[size_t(option)];
}
void AddParam(ConfigOption option, void AddParam(ConfigOption option,
std::unique_ptr<ConfigParam> param) noexcept; std::unique_ptr<ConfigParam> param) noexcept;
gcc_pure gcc_pure
const ConfigParam *GetParam(ConfigOption option) const noexcept { const ConfigParam *GetParam(ConfigOption option) const noexcept {
return params[size_t(option)]; const auto &list = GetParamList(option);
return list.empty() ? nullptr : &list.front();
} }
gcc_pure gcc_pure
@ -81,12 +93,21 @@ struct ConfigData {
bool GetBool(ConfigOption option, bool default_value) const; bool GetBool(ConfigOption option, bool default_value) const;
void AddBlock(ConfigBlockOption option, auto &GetBlockList(ConfigBlockOption option) noexcept {
std::unique_ptr<ConfigBlock> block) noexcept; return blocks[size_t(option)];
}
const auto &GetBlockList(ConfigBlockOption option) const noexcept {
return blocks[size_t(option)];
}
ConfigBlock &AddBlock(ConfigBlockOption option,
std::unique_ptr<ConfigBlock> block) noexcept;
gcc_pure gcc_pure
const ConfigBlock *GetBlock(ConfigBlockOption option) const noexcept { const ConfigBlock *GetBlock(ConfigBlockOption option) const noexcept {
return blocks[size_t(option)]; const auto &list = GetBlockList(option);
return list.empty() ? nullptr : &list.front();
} }
/** /**

View File

@ -72,9 +72,9 @@ Check(const ConfigBlock &block)
void config_global_check(void) void config_global_check(void)
{ {
for (auto i : config_data.blocks) for (const auto &list : config_data.blocks)
for (const auto *p = i; p != nullptr; p = p->next) for (const auto &block : list)
Check(*p); Check(block);
} }
const char * const char *

View File

@ -25,11 +25,6 @@
#include <stdexcept> #include <stdexcept>
ConfigParam::~ConfigParam()
{
delete next;
}
AllocatedPath AllocatedPath
ConfigParam::GetPath() const ConfigParam::GetPath() const
{ {

View File

@ -28,12 +28,6 @@
class AllocatedPath; class AllocatedPath;
struct ConfigParam { struct ConfigParam {
/**
* The next ConfigParam with the same name. The destructor
* deletes the whole chain.
*/
ConfigParam *next = nullptr;
std::string value; std::string value;
int line; int line;
@ -46,11 +40,8 @@ struct ConfigParam {
explicit ConfigParam(V &&_value, int _line=-1) noexcept explicit ConfigParam(V &&_value, int _line=-1) noexcept
:value(std::forward<V>(_value)), line(_line) {} :value(std::forward<V>(_value)), line(_line) {}
ConfigParam(const ConfigParam &) = delete; ConfigParam(ConfigParam &&) = default;
ConfigParam &operator=(ConfigParam &&) = default;
~ConfigParam();
ConfigParam &operator=(const ConfigParam &) = delete;
/** /**
* Determine if this is a "null" instance, i.e. an empty * Determine if this is a "null" instance, i.e. an empty

View File

@ -53,17 +53,16 @@ void
NeighborGlue::Init(const ConfigData &config, NeighborGlue::Init(const ConfigData &config,
EventLoop &loop, NeighborListener &listener) EventLoop &loop, NeighborListener &listener)
{ {
for (const auto *block = config.GetBlock(ConfigBlockOption::NEIGHBORS); for (const auto &block : config.GetBlockList(ConfigBlockOption::NEIGHBORS)) {
block != nullptr; block = block->next) { block.SetUsed();
block->SetUsed();
try { try {
explorers.emplace_front(CreateNeighborExplorer(loop, explorers.emplace_front(CreateNeighborExplorer(loop,
listener, listener,
*block)); block));
} catch (...) { } catch (...) {
std::throw_with_nested(FormatRuntimeError("Line %i: ", std::throw_with_nested(FormatRuntimeError("Line %i: ",
block->line)); block.line));
} }
} }
} }

View File

@ -91,13 +91,12 @@ MultipleOutputs::Configure(EventLoop &event_loop,
const ReplayGainConfig &replay_gain_config, const ReplayGainConfig &replay_gain_config,
AudioOutputClient &client) AudioOutputClient &client)
{ {
for (const auto *param = config.GetBlock(ConfigBlockOption::AUDIO_OUTPUT); for (const auto &block : config.GetBlockList(ConfigBlockOption::AUDIO_OUTPUT)) {
param != nullptr; param = param->next) { block.SetUsed();
param->SetUsed();
auto *output = LoadOutputControl(event_loop, auto *output = LoadOutputControl(event_loop,
replay_gain_config, replay_gain_config,
mixer_listener, mixer_listener,
client, *param); client, block);
if (FindByName(output->GetName()) != nullptr) if (FindByName(output->GetName()) != nullptr)
throw FormatRuntimeError("output devices with identical " throw FormatRuntimeError("output devices with identical "
"names: %s", output->GetName()); "names: %s", output->GetName());