Skip to content

Commit

Permalink
Merge pull request #37 from LemLib/feat/std-format
Browse files Browse the repository at this point in the history
✨ `std::format` support
  • Loading branch information
SizzinSeal authored Jan 8, 2025
2 parents a0aa6d8 + dc8f67f commit 67b9e4b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 27 deletions.
11 changes: 4 additions & 7 deletions .github/workflows/pros-build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build Template
name: PROS Build Template

on:
push:
Expand All @@ -16,14 +16,11 @@ jobs:
uses: actions/checkout@v4

- name: Run LemLib/pros-build
id: build-template
uses: LemLib/[email protected]
with:
copy_readme_and_license_to_include: true
lib_folder_name: units
id: test
uses: LemLib/[email protected]

- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.build-template.outputs.name }}
name: ${{ steps.test.outputs.name }}
path: ${{ github.workspace }}/template/*
7 changes: 7 additions & 0 deletions include/units/Angle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ template <> struct LookupName<Quantity<std::ratio<0>, std::ratio<0>, std::ratio<
using Named = Angle;
};

template <> struct std::formatter<Angle> : std::formatter<double> {
auto format(const Angle& number, std::format_context& ctx) const {
auto formatted_double = std::formatter<double>::format(number.internal(), ctx);
return std::format_to(formatted_double, "_stRad");
}
};

inline std::ostream& operator<<(std::ostream& os, const Angle& quantity) {
os << quantity.internal() << " rad";
return os;
Expand Down
6 changes: 6 additions & 0 deletions include/units/Temperature.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ template <> struct LookupName<Quantity<std::ratio<0>, std::ratio<0>, std::ratio<
using Named = Temperature;
};

template <> struct std::formatter<Temperature> : std::formatter<double> {
auto format(const Temperature& quantity, std::format_context& ctx) const {
return std::format_to(ctx.out(), "{}_k", quantity.internal());
}
};

inline std::ostream& operator<<(std::ostream& os, const Temperature& quantity) {
os << quantity.internal() << " k";
return os;
Expand Down
74 changes: 62 additions & 12 deletions include/units/units.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <type_traits>
#include <utility>
#include <algorithm>
#include <format>

// define M_PI if not already defined
#ifndef M_PI
Expand Down Expand Up @@ -183,6 +184,38 @@ template <isQuantity Q, typename quotient> using Rooted = Named<
std::ratio_divide<typename Q::angle, quotient>, std::ratio_divide<typename Q::temperature, quotient>,
std::ratio_divide<typename Q::luminosity, quotient>, std::ratio_divide<typename Q::moles, quotient>>>;

template <isQuantity Q> struct std::formatter<Q> : std::formatter<double> {
auto format(const Q& quantity, std::format_context& ctx) const {
constinit static std::array<std::pair<intmax_t, intmax_t>, 8> dims {{
{Q::mass::num, Q::mass::den},
{Q::length::num, Q::length::den},
{Q::time::num, Q::time::den},
{Q::current::num, Q::current::den},
{Q::angle::num, Q::angle::den},
{Q::temperature::num, Q::temperature::den},
{Q::luminosity::num, Q::luminosity::den},
{Q::moles::num, Q::moles::den},
}};
std::array<const char*, 8> prefixes {"_kg", "_m", "_s", "_A", "_rad", "_K", "_cd", "_mol"};

auto out = ctx.out();

// Format the quantity value
out = std::formatter<double>::format(quantity.internal(), ctx);

// Add dimensions and prefixes
for (size_t i = 0; i != 8; i++) {
if (dims[i].first != 0) {
out = std::format_to(out, "{}", prefixes[i]);
if (dims[i].first != 1 || dims[i].second != 1) { out = std::format_to(out, "^{}", dims[i].first); }
if (dims[i].second != 1) { out = std::format_to(out, "/{}", dims[i].second); }
}
}

return out;
}
};

inline void unit_printer_helper(std::ostream& os, double quantity,
const std::array<std::pair<intmax_t, intmax_t>, 8>& dims) {
static constinit std::array<const char*, 8> prefixes {"_kg", "_m", "_s", "_A", "_rad", "_K", "_cd", "_mol"};
Expand Down Expand Up @@ -313,6 +346,12 @@ template <isQuantity Q, isQuantity R> constexpr bool operator>(const Q& lhs, con
return Name(Quantity<std::ratio<m>, std::ratio<l>, std::ratio<t>, std::ratio<i>, std::ratio<a>, std::ratio<o>, \
std::ratio<j>, std::ratio<n>>(static_cast<double>(value))); \
} \
template <> struct std::formatter<Name> : std::formatter<double> { \
auto format(const Name& number, std::format_context& ctx) const { \
auto formatted_double = std::formatter<double>::format(number.internal(), ctx); \
return std::format_to(formatted_double, "_" #suffix); \
} \
}; \
inline std::ostream& operator<<(std::ostream& os, const Name& quantity) { \
os << quantity.internal() << " " << #suffix; \
return os; \
Expand Down Expand Up @@ -355,6 +394,12 @@ constexpr Number operator""_num(unsigned long long value) {
std::ratio<0>, std::ratio<0>>(static_cast<double>(value)));
}

template <> struct std::formatter<Number> : std::formatter<double> {
auto format(const Number& number, std::format_context& ctx) const {
return std::formatter<double>::format(number.internal(), ctx);
}
};

inline std::ostream& operator<<(std::ostream& os, const Number& quantity) {
os << quantity.internal() << " " << num;
return os;
Expand Down Expand Up @@ -598,25 +643,30 @@ template <isQuantity Q, isQuantity R> constexpr Q round(const Q& lhs, const R& r

// Convert an angular unit `Q` to a linear unit correctly;
// mostly useful for velocities
template <isQuantity Q> Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current,
typename Q::length, typename Q::temperature, typename Q::luminosity, typename Q::moles>
toLinear(Quantity<typename Q::mass, typename Q::length, typename Q::time, typename Q::current, typename Q::angle,
typename Q::temperature, typename Q::luminosity, typename Q::moles>
angular,
Length diameter) {
template <isQuantity Q>
Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current, typename Q::length,
typename Q::temperature, typename Q::luminosity,
typename Q::moles> constexpr toLinear(Quantity<typename Q::mass, typename Q::length, typename Q::time,
typename Q::current, typename Q::angle, typename Q::temperature,
typename Q::luminosity, typename Q::moles>
angular,
Length diameter) {
return unit_cast<Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current,
typename Q::length, typename Q::temperature, typename Q::luminosity, typename Q::moles>>(
angular * (diameter / 2.0));
}

// Convert an linear unit `Q` to a angular unit correctly;
// mostly useful for velocities
template <isQuantity Q> Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current,
typename Q::length, typename Q::temperature, typename Q::luminosity, typename Q::moles>
toAngular(Quantity<typename Q::mass, typename Q::length, typename Q::time, typename Q::current, typename Q::angle,
typename Q::temperature, typename Q::luminosity, typename Q::moles>
linear,
Length diameter) {
template <isQuantity Q>
Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current, typename Q::length,
typename Q::temperature, typename Q::luminosity,
typename Q::moles> constexpr toAngular(Quantity<typename Q::mass, typename Q::length, typename Q::time,
typename Q::current, typename Q::angle,
typename Q::temperature, typename Q::luminosity,
typename Q::moles>
linear,
Length diameter) {
return unit_cast<Quantity<typename Q::mass, typename Q::angle, typename Q::time, typename Q::current,
typename Q::length, typename Q::temperature, typename Q::luminosity, typename Q::moles>>(
linear / (diameter / 2.0));
Expand Down
29 changes: 21 additions & 8 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@

constexpr int r2i(double value) { return static_cast<int>(value >= 0.0 ? value + 0.5 : value - 0.5); }

/**
* Runs initialization code. This occurs as soon as the program is started.
*
* All other competition modes are blocked by initialize; it is recommended
* to keep execution time for this mode under a few seconds.
*/
void initialize() {
std::cout << std::format("{:.2f}", 15.2_cm) << std::endl; // should output 0.15_m
std::cout << std::format("{:.2f}", 180_stDeg) << std::endl; // should output 3.14_stRad
std::cout << std::format("{:.2f}", 0_celsius) << std::endl; // should output 273.15
std::cout << std::format("{:.2f}", 1.2345) << std::endl;
std::cout << units::pow<5>(505_cm) * 15_celsius << std::endl;
std::cout << std::format("{:.2f}", units::pow<5>(505_cm) * 15_celsius) << std::endl;
Number a(2.123);
std::cout << std::format("{:.2f}", a) << std::endl;
}

constexpr void miscTests() {
units::AccelerationPose a(1_mps2, 2_mps2);
Number num = Number(1.0);
num = Number(0.0);
Expand All @@ -30,12 +35,18 @@ void initialize() {
std::ratio<0>, std::ratio<0>, std::ratio<0>>(5.0));
units::max(10_celsius, Quantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>,
std::ratio<1>, std::ratio<0>, std::ratio<0>>(1.0));
}

constexpr void v3dTests() {
// check Vector3D overloads
units::Vector3D<Length> v3a = 2 * units::V3Position(2_in, 2_in, 2_in) * 2;
units::Vector3D<Length> v3b = units::V3Position(2_in, 2_in, 2_in) / 2.0;
units::Vector3D<Area> v3c = 2_in * units::V3Position(2_in, 2_in, 2_in);
units::Vector3D<Area> v3d = units::V3Position(2_in, 2_in, 2_in) * 2_in;
units::Vector3D<Number> v3e = units::V3Position(2_in, 2_in, 2_in) / 2_in;
}

constexpr void v2dTests() {
// check Vector2D overloads
units::Vector2D<Length> v2a = units::V2Position(2_in, 2_in) / 2;
units::Vector2D<Length> v2b = 2 * units::V2Position(2_in, 2_in) * 2;
Expand Down Expand Up @@ -81,12 +92,14 @@ constexpr double doubleAssignmentTests() {
return d;
}

void numberOperatorTests() {
constexpr void numberOperatorTests() {
using namespace units_double_ops;
static_assert(1_num + 2 == 3);
static_assert(1 + 2_num <= 3);
static_assert(1 / 2_num >= 0);

static_assert(numAssignmentTests() == 0);
static_assert(doubleAssignmentTests() == 1);
}
}

constexpr void formatTests() {}

0 comments on commit 67b9e4b

Please sign in to comment.