blob: 16f0ac7e0caa08b80dad2d9e0e3588cc9cd3e0b7 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
///////////////////////////////////////////////////////////////
// Distributed under the Boost Software License, Version 1.0.
// (See at http://www.boost.org/LICENSE_1_0.txt)
///////////////////////////////////////////////////////////////
/* Divide and multiply
*
*
* Copyright (c) 2008
* Evan Teran
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appears in all copies and that both the
* copyright notice and this permission notice appear in supporting
* documentation, and that the same name not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. We make no representations about the
* suitability this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
// This file is copied from
// https://github.com/ClickHouse/ClickHouse/blob/master/base/base/wide_integer.h
// and modified by Doris
#pragma once
#include <cstdint>
#include <initializer_list>
#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <type_traits>
// NOLINTBEGIN(*)
namespace wide {
template <size_t Bits, typename Signed>
class integer;
}
namespace std {
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
struct common_type<wide::integer<Bits, Signed>, wide::integer<Bits2, Signed2>>;
template <size_t Bits, typename Signed, typename Arithmetic>
struct common_type<wide::integer<Bits, Signed>, Arithmetic>;
template <typename Arithmetic, size_t Bits, typename Signed>
struct common_type<Arithmetic, wide::integer<Bits, Signed>>;
} // namespace std
namespace wide {
template <size_t Bits, typename Signed>
class integer {
public:
using base_type = uint64_t;
using signed_base_type = int64_t;
// ctors
constexpr integer() noexcept = default;
template <size_t Bits2, typename Signed2>
constexpr integer(const integer<Bits2, Signed2> rhs) noexcept;
template <typename T>
requires(std::is_arithmetic_v<T> || std::is_same_v<T, __int128> ||
std::is_same_v<T, unsigned __int128>)
constexpr integer(T rhs) noexcept;
template <typename T>
constexpr integer(std::initializer_list<T> il) noexcept;
// assignment
template <size_t Bits2, typename Signed2>
constexpr integer<Bits, Signed>& operator=(const integer<Bits2, Signed2>& rhs) noexcept;
template <typename Arithmetic>
constexpr integer<Bits, Signed>& operator=(Arithmetic rhs) noexcept;
template <typename Arithmetic>
constexpr integer<Bits, Signed>& operator*=(const Arithmetic& rhs);
template <typename Arithmetic>
constexpr integer<Bits, Signed>& operator/=(const Arithmetic& rhs);
template <typename Arithmetic>
constexpr integer<Bits, Signed>& operator+=(const Arithmetic& rhs) noexcept(
std::is_same_v<Signed, unsigned>);
template <typename Arithmetic>
constexpr integer<Bits, Signed>& operator-=(const Arithmetic& rhs) noexcept(
std::is_same_v<Signed, unsigned>);
template <typename Integral>
constexpr integer<Bits, Signed>& operator%=(const Integral& rhs);
template <typename Integral>
constexpr integer<Bits, Signed>& operator&=(const Integral& rhs) noexcept;
template <typename Integral>
constexpr integer<Bits, Signed>& operator|=(const Integral& rhs) noexcept;
template <typename Integral>
constexpr integer<Bits, Signed>& operator^=(const Integral& rhs) noexcept;
constexpr integer<Bits, Signed>& operator<<=(int n) noexcept;
constexpr integer<Bits, Signed>& operator>>=(int n) noexcept;
constexpr integer<Bits, Signed>& operator++() noexcept(std::is_same_v<Signed, unsigned>);
constexpr integer<Bits, Signed> operator++(int) noexcept(std::is_same_v<Signed, unsigned>);
constexpr integer<Bits, Signed>& operator--() noexcept(std::is_same_v<Signed, unsigned>);
constexpr integer<Bits, Signed> operator--(int) noexcept(std::is_same_v<Signed, unsigned>);
// observers
constexpr explicit operator bool() const noexcept;
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>, T>>
constexpr operator T() const noexcept;
constexpr operator long double() const noexcept;
constexpr operator double() const noexcept;
constexpr operator float() const noexcept;
std::string to_hex_string() const {
std::ostringstream os;
os << std::setw(16) << std::setfill('0') << std::hex;
for (size_t i = 0; i < _impl::item_count; i++) {
os << items[i];
}
return os.str();
}
struct _impl;
base_type items[_impl::item_count];
uint64_t low() const {
static_assert(_impl::item_count == 2);
return items[0];
}
uint64_t high() const {
static_assert(_impl::item_count == 2);
return items[1];
}
private:
template <size_t Bits2, typename Signed2>
friend class integer;
friend class std::numeric_limits<integer<Bits, signed>>;
friend class std::numeric_limits<integer<Bits, unsigned>>;
};
template <typename T>
static constexpr bool ArithmeticConcept() noexcept;
template <class T1, class T2>
using _only_arithmetic =
typename std::enable_if<ArithmeticConcept<T1>() && ArithmeticConcept<T2>()>::type;
template <typename T>
static constexpr bool IntegralConcept() noexcept;
template <class T, class T2>
using _only_integer = typename std::enable_if<IntegralConcept<T>() && IntegralConcept<T2>()>::type;
// Unary operators
template <size_t Bits, typename Signed>
constexpr integer<Bits, Signed> operator~(const integer<Bits, Signed>& lhs) noexcept;
template <size_t Bits, typename Signed>
constexpr integer<Bits, Signed> operator-(const integer<Bits, Signed>& lhs) noexcept(
std::is_same_v<Signed, unsigned>);
template <size_t Bits, typename Signed>
constexpr integer<Bits, Signed> operator+(const integer<Bits, Signed>& lhs) noexcept(
std::is_same_v<Signed, unsigned>);
// Binary operators
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
std::common_type_t<integer<Bits, Signed>, integer<Bits2, Signed2>> constexpr operator*(
const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
std::common_type_t<Arithmetic, Arithmetic2> constexpr operator*(const Arithmetic& rhs,
const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
std::common_type_t<integer<Bits, Signed>, integer<Bits2, Signed2>> constexpr operator/(
const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
std::common_type_t<Arithmetic, Arithmetic2> constexpr operator/(const Arithmetic& rhs,
const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
std::common_type_t<integer<Bits, Signed>, integer<Bits2, Signed2>> constexpr operator+(
const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
std::common_type_t<Arithmetic, Arithmetic2> constexpr operator+(const Arithmetic& rhs,
const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
std::common_type_t<integer<Bits, Signed>, integer<Bits2, Signed2>> constexpr operator-(
const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
std::common_type_t<Arithmetic, Arithmetic2> constexpr operator-(const Arithmetic& rhs,
const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
std::common_type_t<integer<Bits, Signed>, integer<Bits2, Signed2>> constexpr operator%(
const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Integral, typename Integral2, class = _only_integer<Integral, Integral2>>
std::common_type_t<Integral, Integral2> constexpr operator%(const Integral& rhs,
const Integral2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
std::common_type_t<integer<Bits, Signed>, integer<Bits2, Signed2>> constexpr operator&(
const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Integral, typename Integral2, class = _only_integer<Integral, Integral2>>
std::common_type_t<Integral, Integral2> constexpr operator&(const Integral& rhs,
const Integral2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
std::common_type_t<integer<Bits, Signed>, integer<Bits2, Signed2>> constexpr operator|(
const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Integral, typename Integral2, class = _only_integer<Integral, Integral2>>
std::common_type_t<Integral, Integral2> constexpr operator|(const Integral& rhs,
const Integral2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
std::common_type_t<integer<Bits, Signed>, integer<Bits2, Signed2>> constexpr operator^(
const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Integral, typename Integral2, class = _only_integer<Integral, Integral2>>
std::common_type_t<Integral, Integral2> constexpr operator^(const Integral& rhs,
const Integral2& lhs);
// TODO: Integral
template <size_t Bits, typename Signed>
constexpr integer<Bits, Signed> operator<<(const integer<Bits, Signed>& lhs, int n) noexcept;
template <size_t Bits, typename Signed>
constexpr integer<Bits, Signed> operator>>(const integer<Bits, Signed>& lhs, int n) noexcept;
template <size_t Bits, typename Signed, typename Int,
typename = std::enable_if_t<!std::is_same_v<Int, int>>>
constexpr integer<Bits, Signed> operator<<(const integer<Bits, Signed>& lhs, Int n) noexcept {
return lhs << int(n);
}
template <size_t Bits, typename Signed, typename Int,
typename = std::enable_if_t<!std::is_same_v<Int, int>>>
constexpr integer<Bits, Signed> operator>>(const integer<Bits, Signed>& lhs, Int n) noexcept {
return lhs >> int(n);
}
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
constexpr bool operator<(const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
constexpr bool operator<(const Arithmetic& rhs, const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
constexpr bool operator>(const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
constexpr bool operator>(const Arithmetic& rhs, const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
constexpr bool operator<=(const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
constexpr bool operator<=(const Arithmetic& rhs, const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
constexpr bool operator>=(const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
constexpr bool operator>=(const Arithmetic& rhs, const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
constexpr bool operator==(const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
constexpr bool operator==(const Arithmetic& rhs, const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
constexpr bool operator!=(const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
constexpr bool operator!=(const Arithmetic& rhs, const Arithmetic2& lhs);
template <size_t Bits, typename Signed, size_t Bits2, typename Signed2>
constexpr auto operator<=>(const integer<Bits, Signed>& lhs, const integer<Bits2, Signed2>& rhs);
template <typename Arithmetic, typename Arithmetic2,
class = _only_arithmetic<Arithmetic, Arithmetic2>>
constexpr auto operator<=>(const Arithmetic& rhs, const Arithmetic2& lhs);
} // namespace wide
// NOLINTEND(*)
#include "wide_integer_impl.h"