diff --git a/include/pros/detail.hpp b/include/pros/detail.hpp new file mode 100644 index 00000000..e55cfe25 --- /dev/null +++ b/include/pros/detail.hpp @@ -0,0 +1,79 @@ +/** + * \file pros/detail.hpp + * + * Contains PROS internal functions used in port literal functions. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * Copyright (c) 2017-2024 Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License v. 2.0. If a copy of the MPL was not distributed with this + * file You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ +#ifndef _PROS_DETAIL_HPP_ +#define _PROS_DETAIL_HPP_ + +#include +#include +#include + +namespace pros::detail { +template +consteval uint8_t parse_port() { + const std::array chars{Chars...}; + const char* str = chars.begin(); + int base = 10; + uint8_t port_num{0}; + if (chars.size() >= 2 && chars[0] == '0') { + str += 2; + // from_chars doesn't seem to handle hex/binary/octal prefixes, + // so we handle them ourselves + switch (chars[1]) { + case 'X': case 'x': + // hex literal + base = 16; + break; + case 'B': case 'b': + // binary literal + base = 2; + break; + default: + // octal literal + str -= 1; + base = 8; + } + } + auto result = std::from_chars(str, chars.end(), port_num, base); + if (result.ptr != chars.end() || result.ec != std::errc{}) { + return 0; + } + return port_num; +} + +template +consteval bool is_valid_port() { + auto port_num = parse_port(); + return port_num >= 1 && port_num <= 21; +} + +// Tests: +static_assert(is_valid_port<'1'>() == true, "Kernel test failed"); +static_assert(is_valid_port<'0'>() == false, "Kernel test failed"); +// 0x16 = 22 +static_assert(is_valid_port<'0','x','1','6'>() == false, "Kernel test failed"); +// 0x15 = 21 +static_assert(is_valid_port<'0','x','1','5'>() == true, "Kernel test failed"); +// 025 = 21 +static_assert(is_valid_port<'0','2','5'>() == true, "Kernel test failed"); +// 0b1 = 1 +static_assert(is_valid_port<'0','b','1'>() == true, "Kernel test failed"); +// 0x1 = 1 +static_assert(is_valid_port<'0','x','1'>() == true, "Kernel test failed"); +static_assert(is_valid_port<'2','2'>() == false, "Kernel test failed"); + +} + +#endif // _PROS_DETAIL_HPP_ diff --git a/include/pros/distance.hpp b/include/pros/distance.hpp index ae93928b..e5596fcf 100644 --- a/include/pros/distance.hpp +++ b/include/pros/distance.hpp @@ -24,6 +24,7 @@ #include "pros/device.hpp" #include "pros/distance.h" +#include "pros/detail.hpp" namespace pros { inline namespace v5 { @@ -239,7 +240,12 @@ namespace literals { * } * \endcode */ -const pros::Distance operator"" _dist(const unsigned long long int d); +template +const pros::Distance operator"" _dist() { + static_assert(pros::detail::is_valid_port(), "Invalid port number!"); + constexpr int num = pros::detail::parse_port(); + return pros::Distance(num); +} } // namespace literals } // namespace v5 } // namespace pros diff --git a/include/pros/gps.hpp b/include/pros/gps.hpp index 332e60b0..1ffd52c2 100644 --- a/include/pros/gps.hpp +++ b/include/pros/gps.hpp @@ -27,6 +27,7 @@ #include "pros/device.hpp" #include "pros/gps.h" +#include "pros/detail.hpp" namespace pros { inline namespace v5 { @@ -924,7 +925,12 @@ namespace literals { * } * \endcode */ -const pros::Gps operator""_gps(const unsigned long long int g); +template +const pros::Gps operator"" _gps() { + static_assert(pros::detail::is_valid_port(), "Invalid port number!"); + constexpr int num = pros::detail::parse_port(); + return pros::Gps(num); +} } // namespace literals /// @brief diff --git a/include/pros/imu.hpp b/include/pros/imu.hpp index 19240220..ad2e31d0 100644 --- a/include/pros/imu.hpp +++ b/include/pros/imu.hpp @@ -23,6 +23,7 @@ #include "pros/device.hpp" #include "pros/imu.h" +#include "pros/detail.hpp" namespace pros { /** @@ -1067,7 +1068,12 @@ namespace literals { * } * \endcode */ -const pros::Imu operator"" _imu(const unsigned long long int i); +template +const pros::Imu operator"" _imu() { + static_assert(pros::detail::is_valid_port(), "Invalid port number!"); + constexpr int num = pros::detail::parse_port(); + return pros::Imu(num); +} } // namespace literals using IMU = Imu; diff --git a/include/pros/motors.hpp b/include/pros/motors.hpp index b6469116..682824d7 100644 --- a/include/pros/motors.hpp +++ b/include/pros/motors.hpp @@ -26,6 +26,7 @@ #include "pros/abstract_motor.hpp" #include "pros/device.hpp" #include "pros/motors.h" +#include "pros/detail.hpp" #include "rtos.hpp" namespace pros { @@ -2405,7 +2406,13 @@ namespace literals { * } * \endcode */ -const pros::Motor operator"" _mtr(const unsigned long long int m); +template +const pros::Motor operator"" _mtr() { + static_assert(pros::detail::is_valid_port(), "Invalid port number!"); + constexpr int num = pros::detail::parse_port(); + return pros::Motor(num); +} + /** * Constructs a reversed Motor from a literal ending in _rmtr * @@ -2419,7 +2426,12 @@ const pros::Motor operator"" _mtr(const unsigned long long int m); * } * \endcode */ -const pros::Motor operator"" _rmtr(const unsigned long long int m); +template +const pros::Motor operator"" _rmtr() { + static_assert(pros::detail::is_valid_port(), "Invalid port number!"); + constexpr int num = pros::detail::parse_port(); + return pros::Motor(-num); +} } // namespace literals } // namespace v5 } // namespace pros diff --git a/include/pros/optical.hpp b/include/pros/optical.hpp index 463daa8a..3cb02093 100644 --- a/include/pros/optical.hpp +++ b/include/pros/optical.hpp @@ -26,6 +26,7 @@ #include "pros/device.hpp" #include "pros/optical.h" +#include "pros/detail.hpp" namespace pros { inline namespace v5 { @@ -431,7 +432,12 @@ namespace literals { * } * \endcode */ -const pros::Optical operator"" _opt(const unsigned long long int o); + template +const pros::Optical operator"" _opt() { + static_assert(pros::detail::is_valid_port(), "Invalid port number!"); + constexpr int num = pros::detail::parse_port(); + return pros::Optical(num); +} } // namespace literals } // namespace v5 } // namespace pros diff --git a/include/pros/rotation.hpp b/include/pros/rotation.hpp index e7743aa4..7a309c4d 100644 --- a/include/pros/rotation.hpp +++ b/include/pros/rotation.hpp @@ -23,6 +23,7 @@ #include "pros/device.hpp" #include "pros/rotation.h" +#include "pros/detail.hpp" namespace pros { inline namespace v5 { @@ -369,6 +370,23 @@ class Rotation : public Device { */ friend std::ostream& operator<<(std::ostream& os, const pros::Rotation& rotation); + /** + * Returns a rotation sesnor that has the same port as the original, but reversed. + * + * This can only be used on a temporary object (such as a device literal). + * + * \b Example + * \code + * using namespace pros::literals; + * + * void opcontrol() { + * pros::Rotation rotation_sensor = -1_rot; + * printf("Reversed: %d \n", rotation_sensor.get_reversed()); + * } + * \endcode + */ + Rotation operator-() && { return Rotation(-this->get_port()); } + ///@} }; @@ -386,7 +404,12 @@ namespace literals { * } * \endcode */ -const pros::Rotation operator"" _rot(const unsigned long long int r); +template +const pros::Rotation operator"" _rot() { + static_assert(pros::detail::is_valid_port(), "Invalid port number!"); + constexpr int num = pros::detail::parse_port(); + return pros::Rotation(num); +} } // namespace literals } // namespace v5 } // namespace pros diff --git a/include/pros/serial.hpp b/include/pros/serial.hpp index 3880f61b..c5cc8cce 100644 --- a/include/pros/serial.hpp +++ b/include/pros/serial.hpp @@ -338,7 +338,12 @@ namespace literals { * } * \endcode */ -const pros::Serial operator"" _ser(const unsigned long long int m); +template +const pros::Serial operator"" _ser() { + static_assert(pros::detail::is_valid_port(), "Invalid port number!"); + constexpr int num = pros::detail::parse_port(); + return pros::Serial(num); +} } // namespace literals } // namespace pros #endif // _PROS_SERIAL_HPP_ diff --git a/include/pros/vision.hpp b/include/pros/vision.hpp index ab4a61d6..fe0829da 100644 --- a/include/pros/vision.hpp +++ b/include/pros/vision.hpp @@ -781,7 +781,12 @@ namespace literals { * } * \endcode */ -const pros::Vision operator"" _vis(const unsigned long long int m); +template +const pros::Vision operator"" _vis() { + static_assert(pros::detail::is_valid_port(), "Invalid port number!"); + constexpr int num = pros::detail::parse_port(); + return pros::Vision(num); +} } // namespace literals } // namespace pros #endif // _PROS_VISION_HPP_ diff --git a/src/devices/vdml_distance.cpp b/src/devices/vdml_distance.cpp index 51a89ae1..be7b008c 100644 --- a/src/devices/vdml_distance.cpp +++ b/src/devices/vdml_distance.cpp @@ -59,10 +59,5 @@ std::ostream& operator<<(std::ostream& os, pros::Distance& distance) { return os; } -namespace literals { -const pros::Distance operator"" _dist(const unsigned long long int d) { - return pros::Distance(d); -} -} // namespace literals } // namespace v5 } // namespace pros diff --git a/src/devices/vdml_gps.cpp b/src/devices/vdml_gps.cpp index 4c0817c8..84663343 100644 --- a/src/devices/vdml_gps.cpp +++ b/src/devices/vdml_gps.cpp @@ -150,10 +150,5 @@ pros::Gps pros::Gps::get_gps() { return Gps(PROS_ERR_BYTE); } -namespace literals { -const pros::Gps operator""_gps(const unsigned long long int g) { - return pros::Gps(g); -} -} // namespace literals } // namespace v5 } // namespace pros diff --git a/src/devices/vdml_imu.cpp b/src/devices/vdml_imu.cpp index 7d15169d..78942c14 100644 --- a/src/devices/vdml_imu.cpp +++ b/src/devices/vdml_imu.cpp @@ -176,10 +176,5 @@ std::ostream& operator<<(std::ostream& os, const pros::Imu& imu) { return os; } -namespace literals { -const pros::Imu operator"" _imu(const unsigned long long int i) { - return pros::Imu(i); -} -} // namespace literals } // namespace v5 } // namespace pros diff --git a/src/devices/vdml_motors.cpp b/src/devices/vdml_motors.cpp index 079b391a..b17022e4 100644 --- a/src/devices/vdml_motors.cpp +++ b/src/devices/vdml_motors.cpp @@ -551,12 +551,4 @@ std::ostream& operator<<(std::ostream& os, pros::Motor& motor) { } } // namespace v5 -namespace literals { -const pros::Motor operator"" _mtr(const unsigned long long int m) { - return pros::Motor(m); -} -const pros::Motor operator"" _rmtr(const unsigned long long int m) { - return pros::Motor(-m); -} -} // namespace literals } // namespace pros diff --git a/src/devices/vdml_optical.cpp b/src/devices/vdml_optical.cpp index 78e448f1..6534219c 100644 --- a/src/devices/vdml_optical.cpp +++ b/src/devices/vdml_optical.cpp @@ -90,11 +90,5 @@ std::ostream& operator<<(std::ostream& os, pros::Optical& optical) { return os; } -namespace literals { -const pros::Optical operator"" _opt(const unsigned long long int o) { - return pros::Optical(o); -} -} // - } // namespace v5 } // namespace pros diff --git a/src/devices/vdml_rotation.cpp b/src/devices/vdml_rotation.cpp index cbfafab6..b1df1fff 100644 --- a/src/devices/vdml_rotation.cpp +++ b/src/devices/vdml_rotation.cpp @@ -84,11 +84,5 @@ std::ostream& operator<<(std::ostream& os, const pros::Rotation& rotation) { return os; } -namespace literals { -const pros::Rotation operator"" _rot(const unsigned long long int r) { - return pros::Rotation(r); -} -} // namespace literals - } // namespace v5 } // namespace pros diff --git a/src/devices/vdml_serial.cpp b/src/devices/vdml_serial.cpp index d9934cce..2630bc05 100644 --- a/src/devices/vdml_serial.cpp +++ b/src/devices/vdml_serial.cpp @@ -62,9 +62,4 @@ std::int32_t Serial::write(std::uint8_t* buffer, std::int32_t length) const { return serial_write(_port, buffer, length); } -namespace literals { -const pros::Serial operator"" _ser(const unsigned long long int m) { - return pros::Serial(m); -} -} // namespace literals } // namespace pros diff --git a/src/devices/vdml_vision.cpp b/src/devices/vdml_vision.cpp index 162a18d3..92e7e0a1 100644 --- a/src/devices/vdml_vision.cpp +++ b/src/devices/vdml_vision.cpp @@ -140,10 +140,4 @@ Vision Vision::get_vision() { } } // namespace v5 -namespace literals { -const pros::Vision operator"" _vis(const unsigned long long int m) { - return Vision(m); -} - -} // namespace literals } // namespace pros