// The MIT License (MIT) // // Copyright (c) 2018 Mateusz Pusz // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #include "units/physical/si/base/length.h" namespace { /** * @brief Representation type meeting minimum requirements * * This type with a default Mode = 0 provides the minimum set of requirements to * satisfy @c QuantityValue concept which is used for quantity's representation type. * * In case of Mode != 0 only one of mandatory operation is removed which should * result in @c QuantityValue concept not being satisfied. * * @tparam Mode a flag to disable specific type's operations */ template class min_expl { std::intmax_t value_; public: // default construction min_expl() requires (Mode != 1) = default; // construction from std::int64_t explicit constexpr min_expl(std::intmax_t v) noexcept requires (Mode != 2) : value_(v) {} // copy construction min_expl(const min_expl&) requires (Mode != 3) = default; // move construction min_expl(min_expl&&) requires (Mode != 4) = default; min_expl(min_expl&&) requires (Mode == 4) = delete; // copy assignment min_expl& operator=(const min_expl&) requires (Mode != 5) = default; // move assignment min_expl& operator=(min_expl&&) requires (Mode != 6) = default; min_expl& operator=(min_expl&&) requires (Mode == 6) = delete; // equality bool operator==(const min_expl&) const requires (Mode != 7) = default; // scalability - multiplication friend constexpr min_expl operator*(const min_expl& lhs, const min_expl& rhs) requires (Mode != 8) { return min_expl(lhs.value_ * rhs.value_); } // scalability - division friend constexpr min_expl operator/(const min_expl& lhs, const min_expl& rhs) requires (Mode != 9) { return min_expl(lhs.value_ / rhs.value_); } }; } template struct std::common_type> : std::type_identity> {}; template struct std::common_type, std::intmax_t> : std::type_identity> {}; namespace { using namespace units; using namespace units::physical::si; // quantity explicitly constructible (not convertible) from the representation type static_assert(std::constructible_from>, min_expl<>>); static_assert(!std::convertible_to, length>>); // not constructible from an underlying type static_assert(!std::constructible_from>, int>); static_assert(!std::convertible_to>>); // dimensionless quantity implicitly convertible from the representation type static_assert(std::constructible_from>, min_expl<>>); static_assert(std::convertible_to, dimensionless>>); // but not from an underlying type static_assert(!std::constructible_from>, int>); static_assert(!std::convertible_to>>); // or for ratio != 1 static_assert(std::constructible_from>, min_expl<>>); static_assert(!std::convertible_to, dimensionless>>); // quantity convertible from itself static_assert(std::constructible_from>, length>>); static_assert(std::convertible_to>, length>>); // not convertible from an underlying type static_assert(!std::constructible_from>, length>); static_assert(!std::convertible_to, length>>); // quantity convertible from another non truncating unit static_assert(std::constructible_from>, length>>); static_assert(std::convertible_to>, length>>); // quantity not convertible from another truncating unit static_assert(!std::constructible_from>, length>>); static_assert(!std::convertible_to>, length>>); // rep type with explicit constructor - implicit construction of rep not allowed static_assert(!std::constructible_from>, int>); static_assert(!std::convertible_to>>); static_assert(!std::constructible_from>, length>); static_assert(!std::convertible_to, length>>); static_assert(!std::constructible_from, min_expl<>>); static_assert(!std::convertible_to, length>); static_assert(!std::constructible_from, length>>); static_assert(!std::convertible_to>, length>); // all operations needed to satisfy concept static_assert(QuantityValue>); static_assert(!QuantityValue>); static_assert(!QuantityValue>); static_assert(!QuantityValue>); static_assert(!QuantityValue>); static_assert(!QuantityValue>); static_assert(!QuantityValue>); static_assert(!QuantityValue>); static_assert(!QuantityValue>); static_assert(!QuantityValue>); // quantity's operators should mirror the representation type capabilities template concept invalid_member_operations = requires(length lhs) { requires !requires { +lhs; }; requires !requires { -lhs; }; requires !requires { ++lhs; }; requires !requires { lhs++; }; requires !requires { --lhs; }; requires !requires { lhs--; }; requires !requires(length rhs) { lhs += rhs; }; requires !requires(length rhs) { lhs -= rhs; }; requires !requires(Rep rhs) { lhs *= rhs; }; requires !requires(Rep rhs) { lhs /= rhs; }; requires !requires(Rep rhs) { lhs %= rhs; }; requires !requires(length rhs) { lhs %= rhs; }; requires !requires(length rhs) { lhs + rhs; }; requires !requires(length rhs) { lhs - rhs; }; requires !requires(Rep rhs) { lhs % rhs; }; requires !requires(length rhs) { lhs % rhs; }; requires !requires(length rhs) { lhs < rhs; }; requires !requires(length rhs) { lhs > rhs; }; requires !requires(length rhs) { lhs <= rhs; }; requires !requires(length rhs) { lhs >= rhs; }; requires !requires(length rhs) { lhs + rhs; }; requires !requires(length rhs) { lhs - rhs; }; requires !requires(int rhs) { lhs % rhs; }; requires !requires(length rhs) { lhs % rhs; }; requires !requires(length rhs) { lhs == rhs; }; requires !requires(length rhs) { lhs != rhs; }; requires !requires(length rhs) { lhs < rhs; }; requires !requires(length rhs) { lhs > rhs; }; requires !requires(length rhs) { lhs <= rhs; }; requires !requires(length rhs) { lhs >= rhs; }; requires !requires(std::ostream os) { os << lhs; }; }; static_assert(invalid_member_operations>); // equality static_assert(length>(min_expl<>(2)) == length>(min_expl<>(2000))); static_assert(length>(min_expl<>(123)) * min_expl<>(2) == length>(min_expl<>(246))); static_assert(length>(min_expl<>(123)) * quantity{min_expl<>(2)} == length>(min_expl<>(246))); static_assert(min_expl<>(2) * length>(min_expl<>(123)) == length>(min_expl<>(246))); static_assert(quantity{min_expl<>(2)} * length>(min_expl<>(123)) == length>(min_expl<>(246))); static_assert(length>(min_expl<>(246)) / min_expl<>(2) == length>(min_expl<>(123))); static_assert(length>(min_expl<>(246)) / quantity{min_expl<>(2)} == length>(min_expl<>(123))); static_assert(length>(min_expl<>(246)) / length>(min_expl<>(2)) == quantity{min_expl<>(123)}); static_assert(length>(min_expl<>(246)) / length>(min_expl<>(2)) == min_expl<>(123)); } // namespace