/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MAPLE_UTIL_INCLUDE_MPL_NUMBER_H #define MAPLE_UTIL_INCLUDE_MPL_NUMBER_H #include #include #include "utils/meta.h" namespace maple { namespace utils { template class Number { public: static_assert(std::is_integral::value, "Type for Number should be an integral."); using ElementType = T; Number() = default; explicit Number(ElementType data) : val(data) {} template ::value>> explicit Number(U data) : val(static_cast(data)) { } Number(const Number &num) : val(num.val) {} Number(Number &&num) noexcept : val(std::move(num.val)) {} ~Number() = default; // As the implicit T cast is enabled, disable it to avoid implicit cast for `Number num = Number()` which should be two types and should not be able to neither convert to each other nor compare with each // other. Number &operator=(ElementType data) = delete; Number &operator=(const Number &num) noexcept { if (&num != this) { val = num.val; } return *this; } Number &operator=(Number &&num) noexcept { if (&num != this) { val = std::move(num.val); } return *this; } void reset(ElementType data = 0) noexcept { val = data; } void swap(Number &other) noexcept { std::swap(val, other.val); } ElementType get() const noexcept { return val; } template operator std::enable_if_t::value, U>() const noexcept { return val; } template operator std::enable_if_t>, std::is_same>::value, U>() const noexcept { return static_cast(val); } template >, meta_not>>::value>> explicit operator U() const noexcept { return static_cast(val); } Number &operator+=(const T &data) noexcept { val += data; } Number &operator+=(const Number &num) noexcept { val += num.val; } Number &operator-=(const T &data) noexcept { val -= data; } Number &operator-=(const Number &num) noexcept { val -= num.val; } Number &operator++() noexcept { ++val; return *this; } const Number operator++(int) { auto tmp = val; this->operator++(); return Number(tmp); } Number &operator--() noexcept { --val; return *this; } const Number operator--(int) { auto tmp = val; this->operator--; return Number(tmp); } T GetIdx() const { return val; } void SetIdx(T i) { val = i; } private: ElementType val = 0; }; template inline bool operator==(const Number &lhs, const Number &rhs) { return lhs.get() == rhs.get(); } template inline bool operator!=(const Number &lhs, const Number &rhs) { return !(lhs == rhs); } template inline bool operator<(const Number &lhs, const Number &rhs) { return lhs.get() < rhs.get(); } template inline bool operator<=(const Number &lhs, const Number &rhs) { return lhs.get() <= rhs.get(); } template inline bool operator>(const Number &lhs, const Number &rhs) { return !(lhs <= rhs); } template inline bool operator>=(const Number &lhs, const Number &rhs) { return !(lhs < rhs); } template inline Number operator+(const Number &lhs, const Number &rhs) { return Number(lhs.get() + rhs.get()); } template inline Number operator-(const Number &lhs, const Number &rhs) { return Number(lhs.get() - rhs.get()); } template , std::is_enum>::value>> inline bool operator==(const Number &lhs, const U &rhs) { return lhs.get() == rhs; } template , std::is_enum>::value>> inline bool operator==(const U &lhs, const Number &rhs) { return lhs == rhs.get(); } template , std::is_enum>::value>> inline bool operator!=(const Number &lhs, const U &rhs) { return !(lhs == rhs); } template , std::is_enum>::value>> inline bool operator!=(const U &lhs, const Number &rhs) { return !(lhs == rhs); } template , std::is_enum>::value>> inline bool operator<(const Number &lhs, const U &rhs) { return lhs.get() < rhs; } template , std::is_enum>::value>> inline bool operator<(const U &lhs, const Number &rhs) { return lhs < rhs.get(); } template , std::is_enum>::value>> inline bool operator<=(const Number &lhs, const U &rhs) { return lhs.get() <= rhs; } template , std::is_enum>::value>> inline bool operator<=(const U &lhs, const Number &rhs) { return lhs <= rhs.get(); } template , std::is_enum>::value>> inline bool operator>(const Number &lhs, const U &rhs) { return !(lhs <= rhs); } template , std::is_enum>::value>> inline bool operator>(const U &lhs, const Number &rhs) { return !(lhs <= rhs); } template , std::is_enum>::value>> inline bool operator>=(const Number &lhs, const U &rhs) { return !(lhs < rhs); } template , std::is_enum>::value>> inline bool operator>=(const U &lhs, const Number &rhs) { return !(lhs < rhs); } template ::value>> inline Number operator+(const Number &lhs, const U &rhs) { return Number(lhs.get() + rhs); } template ::value>> inline Number operator+(const U &lhs, const Number &rhs) { return Number(lhs + rhs.get()); } template ::value>> inline Number operator-(const Number &lhs, const U &rhs) { return Number(lhs.get() - rhs); } template ::value>> inline Number operator-(const U &lhs, const Number &rhs) { return Number(lhs - rhs.get()); } template inline OS &operator<<(OS &os, const Number &num) { os << num.get(); return os; } template using Index = Number; } // namespace utils } // namespace maple namespace std { template inline string to_string(maple::utils::Number val) { return std::to_string(val.get()); } template inline void hash_combine(std::size_t &seed, const T &v) { std::hash hasher; size_t hasecode = 0x9e3779b9; size_t leftShift = 6; size_t rightShift = 2; seed ^= hasher(v) + hasecode + (seed << leftShift) + (seed >> rightShift); } } // namespace std #endif // MAPLE_UTIL_INCLUDE_MPL_NUMBER_H