refactor: add libtransmission::Values (#6215)

This commit is contained in:
Charles Kerr
2023-11-09 08:39:06 -06:00
committed by GitHub
parent b413beab70
commit 2e32789193
15 changed files with 439 additions and 407 deletions

View File

@@ -54,6 +54,7 @@
#include "libtransmission/tr-assert.h"
#include "libtransmission/tr-strbuf.h"
#include "libtransmission/utils.h"
#include "libtransmission/values.h"
#include "libtransmission/variant.h"
using namespace std::literals;
@@ -664,242 +665,138 @@ uint64_t tr_ntohll(uint64_t netlonglong)
#endif
}
// ---
// --- VALUES / FORMATTER
namespace
{
namespace formatter_impl
namespace libtransmission::Values
{
struct formatter_unit
{
std::array<char, 16> name;
uint64_t value;
};
// default values; can be overridden by client apps
Config::Units<MemoryUnits> Config::Memory{ Config::Base::Kibi, "B"sv, "KiB"sv, "MiB"sv, "GiB"sv, "TiB"sv };
Config::Units<SpeedUnits> Config::Speed{ Config::Base::Kilo, "B/s"sv, "kB/s"sv, "MB/s"sv, "GB/s"sv, "TB/s"sv };
Config::Units<StorageUnits> Config::Storage{ Config::Base::Kilo, "B"sv, "kB"sv, "MB"sv, "GB"sv, "TB"sv };
using formatter_units = std::array<formatter_unit, 4>;
enum
{
TR_FMT_KB,
TR_FMT_MB,
TR_FMT_GB,
TR_FMT_TB
};
void formatter_init(formatter_units& units, uint64_t kilo, char const* kb, char const* mb, char const* gb, char const* tb)
{
uint64_t value = kilo;
tr_strlcpy(std::data(units[TR_FMT_KB].name), kb, std::size(units[TR_FMT_KB].name));
units[TR_FMT_KB].value = value;
value *= kilo;
tr_strlcpy(std::data(units[TR_FMT_MB].name), mb, std::size(units[TR_FMT_MB].name));
units[TR_FMT_MB].value = value;
value *= kilo;
tr_strlcpy(std::data(units[TR_FMT_GB].name), gb, std::size(units[TR_FMT_GB].name));
units[TR_FMT_GB].value = value;
value *= kilo;
tr_strlcpy(std::data(units[TR_FMT_TB].name), tb, std::size(units[TR_FMT_TB].name));
units[TR_FMT_TB].value = value;
}
char* formatter_get_size_str(formatter_units const& u, char* buf, uint64_t bytes, size_t buflen)
{
formatter_unit const* unit = nullptr;
if (bytes < u[1].value)
{
unit = std::data(u);
}
else if (bytes < u[2].value)
{
unit = &u[1];
}
else if (bytes < u[3].value)
{
unit = &u[2];
}
else
{
unit = &u[3];
}
double const value = static_cast<double>(bytes) / unit->value;
auto const* const units = std::data(unit->name);
auto precision = int{};
if (unit->value == 1)
{
precision = 0;
}
else if (value < 100)
{
precision = 2;
}
else
{
precision = 1;
}
auto const [out, len] = fmt::format_to_n(buf, buflen - 1, "{:.{}Lf} {:s}", value, precision, units);
*out = '\0';
return buf;
}
formatter_units size_units;
formatter_units speed_units;
formatter_units mem_units;
} // namespace formatter_impl
} // namespace
size_t tr_speed_K = 0;
void tr_formatter_size_init(uint64_t kilo, char const* kb, char const* mb, char const* gb, char const* tb)
{
using namespace formatter_impl;
formatter_init(size_units, kilo, kb, mb, gb, tb);
}
std::string tr_formatter_size_B(uint64_t bytes)
{
using namespace formatter_impl;
auto buf = std::array<char, 64>{};
return formatter_get_size_str(size_units, std::data(buf), bytes, std::size(buf));
}
void tr_formatter_speed_init(size_t kilo, char const* kb, char const* mb, char const* gb, char const* tb)
{
using namespace formatter_impl;
tr_speed_K = kilo;
formatter_init(speed_units, kilo, kb, mb, gb, tb);
}
std::string tr_formatter_speed_KBps(double kilo_per_second)
{
using namespace formatter_impl;
auto speed = kilo_per_second;
if (speed < 999.95) // 0.0 KB to 999.9 KB (0.0 KiB to 999.9 KiB)
{
return fmt::format("{:.1Lf} {:s}", speed, std::data(speed_units[TR_FMT_KB].name));
}
double const kilo = speed_units[TR_FMT_KB].value;
speed /= kilo;
if (speed < 99.995) // 0.98 MB to 99.99 MB (1.00 MiB to 99.99 MiB)
{
return fmt::format("{:.2Lf} {:s}", speed, std::data(speed_units[TR_FMT_MB].name));
}
if (speed < 999.95) // 100.0 MB to 999.9 MB (100.0 MiB to 999.9 MiB)
{
return fmt::format("{:.1Lf} {:s}", speed, std::data(speed_units[TR_FMT_MB].name));
}
speed /= kilo;
if (speed < 99.995) // 0.98 GB to 99.99 GB (1.00 GiB to 99.99 GiB)
{
return fmt::format("{:.2Lf} {:s}", speed, std::data(speed_units[TR_FMT_GB].name));
}
// 100.0 GB and above (100.0 GiB and above)
return fmt::format("{:.1Lf} {:s}", speed, std::data(speed_units[TR_FMT_GB].name));
}
std::string tr_formatter_speed_compact_KBps(double kilo_per_second)
{
using namespace formatter_impl;
auto speed = kilo_per_second;
if (speed < 99.95) // 0.0 KB to 99.9 KB (0.0 KiB to 99.9 KiB)
{
return fmt::format("{:.1Lf} {:s}", speed, std::data(speed_units[TR_FMT_KB].name));
}
if (speed < 999.5) // 100 KB to 999 KB (100 KiB to 999 KiB)
{
return fmt::format("{:.0Lf} {:s}", speed, std::data(speed_units[TR_FMT_KB].name));
}
double const kilo = speed_units[TR_FMT_KB].value;
speed /= kilo;
if (speed < 9.995) // 0.98 MB to 9.99 MB (1.00 MiB to 9.99 MiB)
{
return fmt::format("{:.2Lf} {:s}", speed, std::data(speed_units[TR_FMT_MB].name));
}
if (speed < 99.95) // 10.0 MB to 99.9 MB (10.0 MiB to 99.9 MiB)
{
return fmt::format("{:.1Lf} {:s}", speed, std::data(speed_units[TR_FMT_MB].name));
}
if (speed < 999.5) // 100 MB to 999 MB (100 MiB to 999 MiB)
{
return fmt::format("{:.0Lf} {:s}", speed, std::data(speed_units[TR_FMT_MB].name));
}
speed /= kilo;
if (speed < 9.995) // 0.98 GB to 9.99 GB (1.00 GiB to 9.99 GiB)
{
return fmt::format("{:.2Lf} {:s}", speed, std::data(speed_units[TR_FMT_GB].name));
}
if (speed < 99.95) // 10.0 GB to 99.9 GB (10.0 GiB to 99.9 GiB)
{
return fmt::format("{:.1Lf} {:s}", speed, std::data(speed_units[TR_FMT_GB].name));
}
// 100 GB and above (100 GiB and above)
return fmt::format("{:.0Lf} {:s}", speed, std::data(speed_units[TR_FMT_GB].name));
}
size_t tr_mem_K = 0;
void tr_formatter_mem_init(size_t kilo, char const* kb, char const* mb, char const* gb, char const* tb)
{
using namespace formatter_impl;
tr_mem_K = kilo;
formatter_init(mem_units, kilo, kb, mb, gb, tb);
}
std::string tr_formatter_mem_B(size_t bytes_per_second)
{
using namespace formatter_impl;
auto buf = std::array<char, 64>{};
return formatter_get_size_str(mem_units, std::data(buf), bytes_per_second, std::size(buf));
}
} // namespace libtransmission::Values
tr_variant tr_formatter_get_units()
{
using namespace formatter_impl;
using namespace libtransmission::Values;
auto const make_units_vec = [](formatter_units const& units)
auto const make_units_vec = [](auto const& units)
{
auto units_vec = tr_variant::Vector{};
units_vec.reserve(std::size(units));
std::transform(
std::begin(units),
std::end(units),
std::back_inserter(units_vec),
[](auto const& unit) { return std::data(unit.name); });
for (size_t i = 0;; ++i)
{
auto const display_name = units.display_name(i);
if (std::empty(display_name))
{
break;
}
units_vec.emplace_back(display_name);
}
return units_vec;
};
auto units_map = tr_variant::Map{ 6U };
units_map.try_emplace(TR_KEY_memory_bytes, mem_units[TR_FMT_KB].value);
units_map.try_emplace(TR_KEY_memory_units, make_units_vec(mem_units));
units_map.try_emplace(TR_KEY_size_bytes, size_units[TR_FMT_KB].value);
units_map.try_emplace(TR_KEY_size_units, make_units_vec(size_units));
units_map.try_emplace(TR_KEY_speed_bytes, speed_units[TR_FMT_KB].value);
units_map.try_emplace(TR_KEY_speed_units, make_units_vec(speed_units));
units_map.try_emplace(TR_KEY_memory_bytes, Memory::units().base());
units_map.try_emplace(TR_KEY_memory_units, make_units_vec(Memory::units()));
units_map.try_emplace(TR_KEY_size_bytes, Storage::units().base());
units_map.try_emplace(TR_KEY_size_units, make_units_vec(Storage::units()));
units_map.try_emplace(TR_KEY_speed_bytes, Speed::units().base());
units_map.try_emplace(TR_KEY_speed_units, make_units_vec(Speed::units()));
return tr_variant{ std::move(units_map) };
}
// --- formatters: storage
void tr_formatter_size_init(size_t base, char const* kb, char const* mb, char const* gb, char const* tb)
{
namespace Values = libtransmission::Values;
auto const kval = base == 1000U ? Values::Config::Base::Kilo : Values::Config::Base::Kibi;
Values::Config::Storage = { kval, "B", kb, mb, gb, tb };
}
std::string tr_formatter_size_B(uint64_t bytes)
{
using Storage = libtransmission::Values::Storage;
return Storage{ bytes, Storage::Units::Bytes }.to_string();
}
// --- formatters: speed
size_t tr_speed_K = 0;
void tr_formatter_speed_init(size_t base, char const* kb, char const* mb, char const* gb, char const* tb)
{
namespace Values = libtransmission::Values;
auto const kval = base == 1000U ? Values::Config::Base::Kilo : Values::Config::Base::Kibi;
Values::Config::Speed = { kval, "B/s", kb, mb, gb, tb };
tr_speed_K = base;
}
std::string tr_formatter_speed_KBps(double kbyps)
{
using Speed = libtransmission::Values::Speed;
return Speed{ kbyps, Speed::Units::KByps }.to_string();
}
uint64_t tr_toSpeedBytes(size_t kbyps)
{
using Speed = libtransmission::Values::Speed;
return Speed{ kbyps, Speed::Units::KByps }.base_quantity();
}
double tr_toSpeedKBps(size_t byps)
{
using Speed = libtransmission::Values::Speed;
return Speed{ byps, Speed::Units::Byps }.count(Speed::Units::KByps);
}
// --- formatters: memory
size_t tr_mem_K = 0;
void tr_formatter_mem_init(size_t base, char const* kb, char const* mb, char const* gb, char const* tb)
{
namespace Values = libtransmission::Values;
auto const kval = base == 1000U ? Values::Config::Base::Kilo : Values::Config::Base::Kibi;
Values::Config::Memory = { kval, "B", kb, mb, gb, tb };
tr_mem_K = base;
}
std::string tr_formatter_mem_B(uint64_t bytes)
{
using Memory = libtransmission::Values::Memory;
return Memory{ bytes, Memory::Units::Bytes }.to_string();
}
std::string tr_formatter_mem_MB(double mbytes)
{
using Memory = libtransmission::Values::Memory;
return Memory{ mbytes, Memory::Units::MBytes }.to_string();
}
uint64_t tr_toMemBytes(size_t mbytes)
{
using Memory = libtransmission::Values::Memory;
return Memory{ mbytes, Memory::Units::MBytes }.base_quantity();
}
double tr_toMemMB(uint64_t bytes)
{
using Memory = libtransmission::Values::Memory;
return Memory{ bytes, Memory::Units::Bytes }.count(Memory::Units::MBytes);
}
// --- ENVIRONMENT
bool tr_env_key_exists(char const* key)