mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Merge pull request #1789 from RustPython/coolreader18/decimal-sys_hash
Add sys.hash_info and the decimal module
This commit is contained in:
5 files changed
+6884
No files matched your search
Vendored
+6449
File diff suppressed because it is too large.
Load diff
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
|
||||
try:
|
||||
from _decimal import *
|
||||
from _decimal import __doc__
|
||||
from _decimal import __version__
|
||||
from _decimal import __libmpdec_version__
|
||||
except ImportError:
|
||||
from _pydecimal import *
|
||||
from _pydecimal import __doc__
|
||||
from _pydecimal import __version__
|
||||
from _pydecimal import __libmpdec_version__
|
||||
Vendored
+389
@@ -0,0 +1,389 @@
|
||||
# Copyright 2007 Google, Inc. All Rights Reserved.
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
|
||||
"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141.
|
||||
|
||||
TODO: Fill out more detailed documentation on the operators."""
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
__all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
|
||||
|
||||
class Number(metaclass=ABCMeta):
|
||||
"""All numbers inherit from this class.
|
||||
|
||||
If you just want to check if an argument x is a number, without
|
||||
caring what kind, use isinstance(x, Number).
|
||||
"""
|
||||
__slots__ = ()
|
||||
|
||||
# Concrete numeric types must provide their own hash implementation
|
||||
__hash__ = None
|
||||
|
||||
|
||||
## Notes on Decimal
|
||||
## ----------------
|
||||
## Decimal has all of the methods specified by the Real abc, but it should
|
||||
## not be registered as a Real because decimals do not interoperate with
|
||||
## binary floats (i.e. Decimal('3.14') + 2.71828 is undefined). But,
|
||||
## abstract reals are expected to interoperate (i.e. R1 + R2 should be
|
||||
## expected to work if R1 and R2 are both Reals).
|
||||
|
||||
class Complex(Number):
|
||||
"""Complex defines the operations that work on the builtin complex type.
|
||||
|
||||
In short, those are: a conversion to complex, .real, .imag, +, -,
|
||||
*, /, abs(), .conjugate, ==, and !=.
|
||||
|
||||
If it is given heterogenous arguments, and doesn't have special
|
||||
knowledge about them, it should fall back to the builtin complex
|
||||
type as described below.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def __complex__(self):
|
||||
"""Return a builtin complex instance. Called for complex(self)."""
|
||||
|
||||
def __bool__(self):
|
||||
"""True if self != 0. Called for bool(self)."""
|
||||
return self != 0
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def real(self):
|
||||
"""Retrieve the real component of this number.
|
||||
|
||||
This should subclass Real.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def imag(self):
|
||||
"""Retrieve the imaginary component of this number.
|
||||
|
||||
This should subclass Real.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __add__(self, other):
|
||||
"""self + other"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __radd__(self, other):
|
||||
"""other + self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __neg__(self):
|
||||
"""-self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __pos__(self):
|
||||
"""+self"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __sub__(self, other):
|
||||
"""self - other"""
|
||||
return self + -other
|
||||
|
||||
def __rsub__(self, other):
|
||||
"""other - self"""
|
||||
return -self + other
|
||||
|
||||
@abstractmethod
|
||||
def __mul__(self, other):
|
||||
"""self * other"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rmul__(self, other):
|
||||
"""other * self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __truediv__(self, other):
|
||||
"""self / other: Should promote to float when necessary."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rtruediv__(self, other):
|
||||
"""other / self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __pow__(self, exponent):
|
||||
"""self**exponent; should promote to float or complex when necessary."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rpow__(self, base):
|
||||
"""base ** self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __abs__(self):
|
||||
"""Returns the Real distance from 0. Called for abs(self)."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def conjugate(self):
|
||||
"""(x+y*i).conjugate() returns (x-y*i)."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __eq__(self, other):
|
||||
"""self == other"""
|
||||
raise NotImplementedError
|
||||
|
||||
Complex.register(complex)
|
||||
|
||||
|
||||
class Real(Complex):
|
||||
"""To Complex, Real adds the operations that work on real numbers.
|
||||
|
||||
In short, those are: a conversion to float, trunc(), divmod,
|
||||
%, <, <=, >, and >=.
|
||||
|
||||
Real also provides defaults for the derived operations.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def __float__(self):
|
||||
"""Any Real can be converted to a native float object.
|
||||
|
||||
Called for float(self)."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __trunc__(self):
|
||||
"""trunc(self): Truncates self to an Integral.
|
||||
|
||||
Returns an Integral i such that:
|
||||
* i>0 iff self>0;
|
||||
* abs(i) <= abs(self);
|
||||
* for any Integral j satisfying the first two conditions,
|
||||
abs(i) >= abs(j) [i.e. i has "maximal" abs among those].
|
||||
i.e. "truncate towards 0".
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __floor__(self):
|
||||
"""Finds the greatest Integral <= self."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __ceil__(self):
|
||||
"""Finds the least Integral >= self."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __round__(self, ndigits=None):
|
||||
"""Rounds self to ndigits decimal places, defaulting to 0.
|
||||
|
||||
If ndigits is omitted or None, returns an Integral, otherwise
|
||||
returns a Real. Rounds half toward even.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __divmod__(self, other):
|
||||
"""divmod(self, other): The pair (self // other, self % other).
|
||||
|
||||
Sometimes this can be computed faster than the pair of
|
||||
operations.
|
||||
"""
|
||||
return (self // other, self % other)
|
||||
|
||||
def __rdivmod__(self, other):
|
||||
"""divmod(other, self): The pair (self // other, self % other).
|
||||
|
||||
Sometimes this can be computed faster than the pair of
|
||||
operations.
|
||||
"""
|
||||
return (other // self, other % self)
|
||||
|
||||
@abstractmethod
|
||||
def __floordiv__(self, other):
|
||||
"""self // other: The floor() of self/other."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rfloordiv__(self, other):
|
||||
"""other // self: The floor() of other/self."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __mod__(self, other):
|
||||
"""self % other"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rmod__(self, other):
|
||||
"""other % self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __lt__(self, other):
|
||||
"""self < other
|
||||
|
||||
< on Reals defines a total ordering, except perhaps for NaN."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __le__(self, other):
|
||||
"""self <= other"""
|
||||
raise NotImplementedError
|
||||
|
||||
# Concrete implementations of Complex abstract methods.
|
||||
def __complex__(self):
|
||||
"""complex(self) == complex(float(self), 0)"""
|
||||
return complex(float(self))
|
||||
|
||||
@property
|
||||
def real(self):
|
||||
"""Real numbers are their real component."""
|
||||
return +self
|
||||
|
||||
@property
|
||||
def imag(self):
|
||||
"""Real numbers have no imaginary component."""
|
||||
return 0
|
||||
|
||||
def conjugate(self):
|
||||
"""Conjugate is a no-op for Reals."""
|
||||
return +self
|
||||
|
||||
Real.register(float)
|
||||
|
||||
|
||||
class Rational(Real):
|
||||
""".numerator and .denominator should be in lowest terms."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def numerator(self):
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def denominator(self):
|
||||
raise NotImplementedError
|
||||
|
||||
# Concrete implementation of Real's conversion to float.
|
||||
def __float__(self):
|
||||
"""float(self) = self.numerator / self.denominator
|
||||
|
||||
It's important that this conversion use the integer's "true"
|
||||
division rather than casting one side to float before dividing
|
||||
so that ratios of huge integers convert without overflowing.
|
||||
|
||||
"""
|
||||
return self.numerator / self.denominator
|
||||
|
||||
|
||||
class Integral(Rational):
|
||||
"""Integral adds a conversion to int and the bit-string operations."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def __int__(self):
|
||||
"""int(self)"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __index__(self):
|
||||
"""Called whenever an index is needed, such as in slicing"""
|
||||
return int(self)
|
||||
|
||||
@abstractmethod
|
||||
def __pow__(self, exponent, modulus=None):
|
||||
"""self ** exponent % modulus, but maybe faster.
|
||||
|
||||
Accept the modulus argument if you want to support the
|
||||
3-argument version of pow(). Raise a TypeError if exponent < 0
|
||||
or any argument isn't Integral. Otherwise, just implement the
|
||||
2-argument version described in Complex.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __lshift__(self, other):
|
||||
"""self << other"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rlshift__(self, other):
|
||||
"""other << self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rshift__(self, other):
|
||||
"""self >> other"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rrshift__(self, other):
|
||||
"""other >> self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __and__(self, other):
|
||||
"""self & other"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rand__(self, other):
|
||||
"""other & self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __xor__(self, other):
|
||||
"""self ^ other"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __rxor__(self, other):
|
||||
"""other ^ self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __or__(self, other):
|
||||
"""self | other"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __ror__(self, other):
|
||||
"""other | self"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __invert__(self):
|
||||
"""~self"""
|
||||
raise NotImplementedError
|
||||
|
||||
# Concrete implementations of Rational and Real abstract methods.
|
||||
def __float__(self):
|
||||
"""float(self) == float(int(self))"""
|
||||
return float(int(self))
|
||||
|
||||
@property
|
||||
def numerator(self):
|
||||
"""Integers are their own numerators."""
|
||||
return +self
|
||||
|
||||
@property
|
||||
def denominator(self):
|
||||
"""Integers have a denominator of 1."""
|
||||
return 1
|
||||
|
||||
Integral.register(int)
|
||||
@@ -103,3 +103,31 @@ pub fn hash_bigint(value: &BigInt) -> PyHash {
|
||||
None => (value % MODULUS).to_i64().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
#[pystruct_sequence(name = "sys.hash_info")]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct PyHashInfo {
|
||||
width: usize,
|
||||
modulus: PyUHash,
|
||||
inf: PyHash,
|
||||
nan: PyHash,
|
||||
imag: PyHash,
|
||||
algorithm: &'static str,
|
||||
hash_bits: usize,
|
||||
seed_bits: usize,
|
||||
}
|
||||
impl PyHashInfo {
|
||||
pub const INFO: Self = PyHashInfo {
|
||||
width: BITS,
|
||||
modulus: MODULUS,
|
||||
inf: INF,
|
||||
nan: NAN,
|
||||
imag: IMAG,
|
||||
algorithm: "siphash13",
|
||||
hash_bits: std::mem::size_of::<PyHash>() * 8,
|
||||
// internally hash_map::DefaultHasher uses 2 u64s as the seed, but
|
||||
// that's not guaranteed to be consistent across Rust releases
|
||||
// TODO: use something like the siphasher crate as our hash algorithm
|
||||
seed_bits: std::mem::size_of::<PyHash>() * 2 * 8,
|
||||
};
|
||||
}
|
||||
@@ -4,6 +4,7 @@ use std::{env, mem};
|
||||
use crate::frame::FrameRef;
|
||||
use crate::function::OptionalArg;
|
||||
use crate::obj::objstr::PyStringRef;
|
||||
use crate::pyhash::PyHashInfo;
|
||||
use crate::pyobject::{
|
||||
IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult, TypeProtocol,
|
||||
};
|
||||
@@ -214,6 +215,11 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectR
|
||||
.into_struct_sequence(vm, version_info_type)
|
||||
.unwrap();
|
||||
|
||||
let hash_info_type = PyHashInfo::make_class(ctx);
|
||||
let hash_info = PyHashInfo::INFO
|
||||
.into_struct_sequence(vm, hash_info_type)
|
||||
.unwrap();
|
||||
|
||||
// TODO Add crate version to this namespace
|
||||
let implementation = py_namespace!(vm, {
|
||||
"name" => ctx.new_str("rustpython".to_owned()),
|
||||
@@ -357,6 +363,7 @@ settrace() -- set the global debug tracing function
|
||||
"getdefaultencoding" => ctx.new_function(sys_getdefaultencoding),
|
||||
"getprofile" => ctx.new_function(sys_getprofile),
|
||||
"gettrace" => ctx.new_function(sys_gettrace),
|
||||
"hash_info" => hash_info,
|
||||
"intern" => ctx.new_function(sys_intern),
|
||||
"maxunicode" => ctx.new_int(0x0010_FFFF),
|
||||
"maxsize" => ctx.new_int(std::isize::MAX),
|
||||
|
||||
Reference in new issue
Block a user