Data Unit Converter — C++ source
Convert between digital data units - B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. Switch between decimal (1000) and binary (1024) bases, runs entirely in your browser.
This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// =============================================================================
// data-unit-converter.cpp — CosmoDev polyglot showcase port of the
// `data-unit-converter` tool
// -----------------------------------------------------------------------------
// Language : C++ (C++17, standard library only)
// Source: ported from src/lib/dataUnits.ts (the canonical, live TypeScript
// lib); mirrors src/tool-sources/data-unit-converter/{python.py,rust.rs}
// License : display source — part of CosmoDev's polyglot tool pages
// (dev.cosmolabs.org). Shown verbatim alongside the JS/TS/Go/Rust/
// Python ports and the other language ports.
// -----------------------------------------------------------------------------
// Pure digital-data unit conversion. Convert between B, KB/KiB, MB/MiB,
// GB/GiB, TB/TiB: the decimal base 1000 pairs with KB/MB/GB/TB (SI) and the
// binary base 1024 with KiB/MiB/GiB/TiB (IEC). Deterministic and
// side-effect free; convertData returns NaN for non-finite input, unknown
// unit symbols, or an invalid base — never throws.
// =============================================================================
#include <array>
#include <cmath>
#include <optional>
#include <string_view>
namespace cosmodev {
/// Supported conversion radix: decimal (`Decimal = 1000`, SI units) or binary
/// (`Binary = 1024`, IEC units).
enum class Base {
Decimal = 1000,
Binary = 1024,
};
/// Numeric radix as a double, ready for `std::pow`.
constexpr double radix(Base base) noexcept {
return base == Base::Decimal ? 1000.0 : 1024.0;
}
/// Units available under each base, ordered smallest (B) to largest. The UI
/// uses these to populate the per-base unit pickers.
constexpr std::array<std::string_view, 5> unitsFor(Base base) noexcept {
return base == Base::Decimal
? std::array<std::string_view, 5>{"B", "KB", "MB", "GB", "TB"}
: std::array<std::string_view, 5>{"B", "KiB", "MiB", "GiB", "TiB"};
}
/// Power-of-base rank for a unit symbol: "B" is rank 0 and each prefix step
/// adds 1. KB and KiB are both rank 1 — the unit picks the rank, the base
/// decides whether a rank means ×1000 or ×1024. Unknown symbols miss the
/// table (std::nullopt), mirroring the TS dictionary miss.
constexpr std::optional<int> unitExponent(std::string_view unit) noexcept {
if (unit == "B") return 0;
if (unit == "KB" || unit == "KiB") return 1;
if (unit == "MB" || unit == "MiB") return 2;
if (unit == "GB" || unit == "GiB") return 3;
if (unit == "TB" || unit == "TiB") return 4;
return std::nullopt;
}
/// Convert a value between two digital-data units under the given base.
///
/// Strategy: reduce to bytes via `value × base^fromExp`, then divide by
/// `base^toExp`. Non-finite values (Inf/NaN) or unknown symbols return NaN —
/// never throws (mirrors the TypeScript contract). `Base` is already
/// constrained by its enum type; the int-based overload below preserves the
/// original "invalid base → NaN" behavior for raw numeric bases.
double convertData(double value, std::string_view from, std::string_view to, Base base) noexcept {
// Reject Inf/NaN early so they don't propagate through the multiplication.
if (!std::isfinite(value)) return std::nan("");
// Unknown unit symbols miss the table (nullopt) — treat as invalid.
const std::optional<int> fromExp = unitExponent(from);
const std::optional<int> toExp = unitExponent(to);
if (!fromExp || !toExp) return std::nan("");
const double r = radix(base);
return (value * std::pow(r, static_cast<double>(*fromExp))) /
std::pow(r, static_cast<double>(*toExp));
}
/// Int-based entry point mirroring the TypeScript signature
/// (`convertData(value, fromUnit, toUnit, base)`) where the base arrives as a
/// plain number from the URL/share state. Returns NaN for a base other than
/// 1000/1024 (anything else is a caller bug).
double convertData(double value, std::string_view from, std::string_view to, int base) noexcept {
if (base != 1000 && base != 1024) return std::nan("");
return convertData(value, from, to, base == 1000 ? Base::Decimal : Base::Binary);
}
} // namespace cosmodev
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →