From f12a379760f80dc396f1b0fa30a9fddaff66e48b Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Mon, 8 Sep 2025 20:07:54 +0800 Subject: [PATCH] add maxlen for deque --- python/collections.py | 42 ++++++++++++++++++++++++++++++----------- src/common/_generated.c | 2 +- tests/72_collections.py | 28 +++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/python/collections.py b/python/collections.py index 8739d837..34df4c65 100644 --- a/python/collections.py +++ b/python/collections.py @@ -27,20 +27,29 @@ class defaultdict(dict): class deque[T]: - _data: list[T] _head: int _tail: int + _maxlen: int | None _capacity: int + _data: list[T] + + def __init__(self, iterable: Iterable[T] = None, maxlen: int | None = None): + if maxlen is not None: + assert maxlen > 0 - def __init__(self, iterable: Iterable[T] = None): - self._data = [None] * 8 # type: ignore self._head = 0 self._tail = 0 - self._capacity = len(self._data) + self._maxlen = maxlen + self._capacity = 8 if maxlen is None else maxlen + 1 + self._data = [None] * self._capacity # type: ignore if iterable is not None: self.extend(iterable) + @property + def maxlen(self) -> int | None: + return self._maxlen + def __resize_2x(self): backup = list(self) self._capacity *= 2 @@ -51,19 +60,25 @@ class deque[T]: self._data.extend([None] * (self._capacity - len(backup))) def append(self, x: T): + if (self._tail + 1) % self._capacity == self._head: + if self._maxlen is None: + self.__resize_2x() + else: + self.popleft() self._data[self._tail] = x self._tail = (self._tail + 1) % self._capacity - if (self._tail + 1) % self._capacity == self._head: - self.__resize_2x() def appendleft(self, x: T): + if (self._tail + 1) % self._capacity == self._head: + if self._maxlen is None: + self.__resize_2x() + else: + self.pop() self._head = (self._head - 1) % self._capacity self._data[self._head] = x - if (self._tail + 1) % self._capacity == self._head: - self.__resize_2x() def copy(self): - return deque(self) + return deque(self, maxlen=self.maxlen) def count(self, x: T) -> int: n = 0 @@ -84,12 +99,15 @@ class deque[T]: if self._head == self._tail: raise IndexError("pop from an empty deque") self._tail = (self._tail - 1) % self._capacity - return self._data[self._tail] + x = self._data[self._tail] + self._data[self._tail] = None + return x def popleft(self) -> T: if self._head == self._tail: raise IndexError("pop from an empty deque") x = self._data[self._head] + self._data[self._head] = None self._head = (self._head + 1) % self._capacity return x @@ -144,5 +162,7 @@ class deque[T]: return not self == other def __repr__(self) -> str: - return f"deque({list(self)!r})" + if self.maxlen is None: + return f"deque({list(self)!r})" + return f"deque({list(self)!r}, maxlen={self.maxlen})" diff --git a/src/common/_generated.c b/src/common/_generated.c index fb970f52..75316f7b 100644 --- a/src/common/_generated.c +++ b/src/common/_generated.c @@ -4,7 +4,7 @@ const char kPythonLibs_bisect[] = "\"\"\"Bisection algorithms.\"\"\"\n\ndef insort_right(a, x, lo=0, hi=None):\n \"\"\"Insert item x in list a, and keep it sorted assuming a is sorted.\n\n If x is already in a, insert it to the right of the rightmost x.\n\n Optional args lo (default 0) and hi (default len(a)) bound the\n slice of a to be searched.\n \"\"\"\n\n lo = bisect_right(a, x, lo, hi)\n a.insert(lo, x)\n\ndef bisect_right(a, x, lo=0, hi=None):\n \"\"\"Return the index where to insert item x in list a, assuming a is sorted.\n\n The return value i is such that all e in a[:i] have e <= x, and all e in\n a[i:] have e > x. So if x already appears in the list, a.insert(x) will\n insert just after the rightmost x already there.\n\n Optional args lo (default 0) and hi (default len(a)) bound the\n slice of a to be searched.\n \"\"\"\n\n if lo < 0:\n raise ValueError('lo must be non-negative')\n if hi is None:\n hi = len(a)\n while lo < hi:\n mid = (lo+hi)//2\n if x < a[mid]: hi = mid\n else: lo = mid+1\n return lo\n\ndef insort_left(a, x, lo=0, hi=None):\n \"\"\"Insert item x in list a, and keep it sorted assuming a is sorted.\n\n If x is already in a, insert it to the left of the leftmost x.\n\n Optional args lo (default 0) and hi (default len(a)) bound the\n slice of a to be searched.\n \"\"\"\n\n lo = bisect_left(a, x, lo, hi)\n a.insert(lo, x)\n\n\ndef bisect_left(a, x, lo=0, hi=None):\n \"\"\"Return the index where to insert item x in list a, assuming a is sorted.\n\n The return value i is such that all e in a[:i] have e < x, and all e in\n a[i:] have e >= x. So if x already appears in the list, a.insert(x) will\n insert just before the leftmost x already there.\n\n Optional args lo (default 0) and hi (default len(a)) bound the\n slice of a to be searched.\n \"\"\"\n\n if lo < 0:\n raise ValueError('lo must be non-negative')\n if hi is None:\n hi = len(a)\n while lo < hi:\n mid = (lo+hi)//2\n if a[mid] < x: lo = mid+1\n else: hi = mid\n return lo\n\n# Create aliases\nbisect = bisect_right\ninsort = insort_right\n"; const char kPythonLibs_builtins[] = "def all(iterable):\n for i in iterable:\n if not i:\n return False\n return True\n\ndef any(iterable):\n for i in iterable:\n if i:\n return True\n return False\n\ndef enumerate(iterable, start=0):\n n = start\n for elem in iterable:\n yield n, elem\n n += 1\n\ndef __minmax_reduce(op, args):\n if len(args) == 2: # min(1, 2)\n return args[0] if op(args[0], args[1]) else args[1]\n if len(args) == 0: # min()\n raise TypeError('expected 1 arguments, got 0')\n if len(args) == 1: # min([1, 2, 3, 4]) -> min(1, 2, 3, 4)\n args = args[0]\n args = iter(args)\n try:\n res = next(args)\n except StopIteration:\n raise ValueError('args is an empty sequence')\n while True:\n try:\n i = next(args)\n except StopIteration:\n break\n if op(i, res):\n res = i\n return res\n\ndef min(*args, key=None):\n key = key or (lambda x: x)\n return __minmax_reduce(lambda x,y: key(x)key(y), args)\n\ndef sum(iterable):\n res = 0\n for i in iterable:\n res += i\n return res\n\ndef map(f, iterable):\n for i in iterable:\n yield f(i)\n\ndef filter(f, iterable):\n for i in iterable:\n if f(i):\n yield i\n\ndef zip(a, b):\n a = iter(a)\n b = iter(b)\n while True:\n try:\n ai = next(a)\n bi = next(b)\n except StopIteration:\n break\n yield ai, bi\n\ndef reversed(iterable):\n a = list(iterable)\n a.reverse()\n return a\n\ndef sorted(iterable, key=None, reverse=False):\n a = list(iterable)\n a.sort(key=key, reverse=reverse)\n return a\n\n##### str #####\ndef __format_string(self: str, *args, **kwargs) -> str:\n def tokenizeString(s: str):\n tokens = []\n L, R = 0,0\n \n mode = None\n curArg = 0\n # lookingForKword = False\n \n while(R list[str]:\n tp_module = type(__import__('math'))\n if isinstance(obj, tp_module):\n return [k for k, _ in obj.__dict__.items()]\n names = set()\n if not isinstance(obj, type):\n obj_d = obj.__dict__\n if obj_d is not None:\n names.update([k for k, _ in obj_d.items()])\n cls = type(obj)\n else:\n cls = obj\n while cls is not None:\n names.update([k for k, _ in cls.__dict__.items()])\n cls = cls.__base__\n return sorted(list(names))\n\nclass set:\n def __init__(self, iterable=None):\n iterable = iterable or []\n self._a = {}\n self.update(iterable)\n\n def add(self, elem):\n self._a[elem] = None\n \n def discard(self, elem):\n self._a.pop(elem, None)\n\n def remove(self, elem):\n del self._a[elem]\n \n def clear(self):\n self._a.clear()\n\n def update(self, other):\n for elem in other:\n self.add(elem)\n\n def __len__(self):\n return len(self._a)\n \n def copy(self):\n return set(self._a.keys())\n \n def __and__(self, other):\n return {elem for elem in self if elem in other}\n\n def __sub__(self, other):\n return {elem for elem in self if elem not in other}\n \n def __or__(self, other):\n ret = self.copy()\n ret.update(other)\n return ret\n\n def __xor__(self, other): \n _0 = self - other\n _1 = other - self\n return _0 | _1\n\n def union(self, other):\n return self | other\n\n def intersection(self, other):\n return self & other\n\n def difference(self, other):\n return self - other\n\n def symmetric_difference(self, other): \n return self ^ other\n \n def __eq__(self, other):\n if not isinstance(other, set):\n return NotImplemented\n return len(self ^ other) == 0\n \n def __ne__(self, other):\n if not isinstance(other, set):\n return NotImplemented\n return len(self ^ other) != 0\n\n def isdisjoint(self, other):\n return len(self & other) == 0\n \n def issubset(self, other):\n return len(self - other) == 0\n \n def issuperset(self, other):\n return len(other - self) == 0\n\n def __contains__(self, elem):\n return elem in self._a\n \n def __repr__(self):\n if len(self) == 0:\n return 'set()'\n return '{'+ ', '.join([repr(i) for i in self._a.keys()]) + '}'\n \n def __iter__(self):\n return iter(self._a.keys())"; const char kPythonLibs_cmath[] = "import math\n\nclass complex:\n def __init__(self, real, imag=0):\n self._real = float(real)\n self._imag = float(imag)\n\n @property\n def real(self):\n return self._real\n \n @property\n def imag(self):\n return self._imag\n\n def conjugate(self):\n return complex(self.real, -self.imag)\n \n def __repr__(self):\n s = ['(', str(self.real)]\n s.append('-' if self.imag < 0 else '+')\n s.append(str(abs(self.imag)))\n s.append('j)')\n return ''.join(s)\n \n def __eq__(self, other):\n if type(other) is complex:\n return self.real == other.real and self.imag == other.imag\n if type(other) in (int, float):\n return self.real == other and self.imag == 0\n return NotImplemented\n \n def __ne__(self, other):\n res = self == other\n if res is NotImplemented:\n return res\n return not res\n \n def __add__(self, other):\n if type(other) is complex:\n return complex(self.real + other.real, self.imag + other.imag)\n if type(other) in (int, float):\n return complex(self.real + other, self.imag)\n return NotImplemented\n \n def __radd__(self, other):\n return self.__add__(other)\n \n def __sub__(self, other):\n if type(other) is complex:\n return complex(self.real - other.real, self.imag - other.imag)\n if type(other) in (int, float):\n return complex(self.real - other, self.imag)\n return NotImplemented\n \n def __rsub__(self, other):\n if type(other) is complex:\n return complex(other.real - self.real, other.imag - self.imag)\n if type(other) in (int, float):\n return complex(other - self.real, -self.imag)\n return NotImplemented\n \n def __mul__(self, other):\n if type(other) is complex:\n return complex(self.real * other.real - self.imag * other.imag,\n self.real * other.imag + self.imag * other.real)\n if type(other) in (int, float):\n return complex(self.real * other, self.imag * other)\n return NotImplemented\n \n def __rmul__(self, other):\n return self.__mul__(other)\n \n def __truediv__(self, other):\n if type(other) is complex:\n denominator = other.real ** 2 + other.imag ** 2\n real_part = (self.real * other.real + self.imag * other.imag) / denominator\n imag_part = (self.imag * other.real - self.real * other.imag) / denominator\n return complex(real_part, imag_part)\n if type(other) in (int, float):\n return complex(self.real / other, self.imag / other)\n return NotImplemented\n \n def __pow__(self, other: int | float):\n if type(other) in (int, float):\n return complex(self.__abs__() ** other * math.cos(other * phase(self)),\n self.__abs__() ** other * math.sin(other * phase(self)))\n return NotImplemented\n \n def __abs__(self) -> float:\n return math.sqrt(self.real ** 2 + self.imag ** 2)\n\n def __neg__(self):\n return complex(-self.real, -self.imag)\n \n def __hash__(self):\n return hash((self.real, self.imag))\n\n\n# Conversions to and from polar coordinates\n\ndef phase(z: complex):\n return math.atan2(z.imag, z.real)\n\ndef polar(z: complex):\n return z.__abs__(), phase(z)\n\ndef rect(r: float, phi: float):\n return r * math.cos(phi) + r * math.sin(phi) * 1j\n\n# Power and logarithmic functions\n\ndef exp(z: complex):\n return math.exp(z.real) * rect(1, z.imag)\n\ndef log(z: complex, base=2.718281828459045):\n return math.log(z.__abs__(), base) + phase(z) * 1j\n\ndef log10(z: complex):\n return log(z, 10)\n\ndef sqrt(z: complex):\n return z ** 0.5\n\n# Trigonometric functions\n\ndef acos(z: complex):\n return -1j * log(z + sqrt(z * z - 1))\n\ndef asin(z: complex):\n return -1j * log(1j * z + sqrt(1 - z * z))\n\ndef atan(z: complex):\n return 1j / 2 * log((1 - 1j * z) / (1 + 1j * z))\n\ndef cos(z: complex):\n return (exp(z) + exp(-z)) / 2\n\ndef sin(z: complex):\n return (exp(z) - exp(-z)) / (2 * 1j)\n\ndef tan(z: complex):\n return sin(z) / cos(z)\n\n# Hyperbolic functions\n\ndef acosh(z: complex):\n return log(z + sqrt(z * z - 1))\n\ndef asinh(z: complex):\n return log(z + sqrt(z * z + 1))\n\ndef atanh(z: complex):\n return 1 / 2 * log((1 + z) / (1 - z))\n\ndef cosh(z: complex):\n return (exp(z) + exp(-z)) / 2\n\ndef sinh(z: complex):\n return (exp(z) - exp(-z)) / 2\n\ndef tanh(z: complex):\n return sinh(z) / cosh(z)\n\n# Classification functions\n\ndef isfinite(z: complex):\n return math.isfinite(z.real) and math.isfinite(z.imag)\n\ndef isinf(z: complex):\n return math.isinf(z.real) or math.isinf(z.imag)\n\ndef isnan(z: complex):\n return math.isnan(z.real) or math.isnan(z.imag)\n\ndef isclose(a: complex, b: complex):\n return math.isclose(a.real, b.real) and math.isclose(a.imag, b.imag)\n\n# Constants\n\npi = math.pi\ne = math.e\ntau = 2 * pi\ninf = math.inf\ninfj = complex(0, inf)\nnan = math.nan\nnanj = complex(0, nan)\n"; -const char kPythonLibs_collections[] = "from typing import TypeVar, Iterable\n\ndef Counter[T](iterable: Iterable[T]):\n a: dict[T, int] = {}\n for x in iterable:\n if x in a:\n a[x] += 1\n else:\n a[x] = 1\n return a\n\n\nclass defaultdict(dict):\n def __init__(self, default_factory, *args):\n super().__init__(*args)\n self.default_factory = default_factory\n\n def __missing__(self, key):\n self[key] = self.default_factory()\n return self[key]\n\n def __repr__(self) -> str:\n return f\"defaultdict({self.default_factory}, {super().__repr__()})\"\n\n def copy(self):\n return defaultdict(self.default_factory, self)\n\n\nclass deque[T]:\n _data: list[T]\n _head: int\n _tail: int\n _capacity: int\n\n def __init__(self, iterable: Iterable[T] = None):\n self._data = [None] * 8 # type: ignore\n self._head = 0\n self._tail = 0\n self._capacity = len(self._data)\n\n if iterable is not None:\n self.extend(iterable)\n\n def __resize_2x(self):\n backup = list(self)\n self._capacity *= 2\n self._head = 0\n self._tail = len(backup)\n self._data.clear()\n self._data.extend(backup)\n self._data.extend([None] * (self._capacity - len(backup)))\n\n def append(self, x: T):\n self._data[self._tail] = x\n self._tail = (self._tail + 1) % self._capacity\n if (self._tail + 1) % self._capacity == self._head:\n self.__resize_2x()\n\n def appendleft(self, x: T):\n self._head = (self._head - 1) % self._capacity\n self._data[self._head] = x\n if (self._tail + 1) % self._capacity == self._head:\n self.__resize_2x()\n\n def copy(self):\n return deque(self)\n \n def count(self, x: T) -> int:\n n = 0\n for item in self:\n if item == x:\n n += 1\n return n\n \n def extend(self, iterable: Iterable[T]):\n for x in iterable:\n self.append(x)\n\n def extendleft(self, iterable: Iterable[T]):\n for x in iterable:\n self.appendleft(x)\n \n def pop(self) -> T:\n if self._head == self._tail:\n raise IndexError(\"pop from an empty deque\")\n self._tail = (self._tail - 1) % self._capacity\n return self._data[self._tail]\n \n def popleft(self) -> T:\n if self._head == self._tail:\n raise IndexError(\"pop from an empty deque\")\n x = self._data[self._head]\n self._head = (self._head + 1) % self._capacity\n return x\n \n def clear(self):\n i = self._head\n while i != self._tail:\n self._data[i] = None # type: ignore\n i = (i + 1) % self._capacity\n self._head = 0\n self._tail = 0\n\n def rotate(self, n: int = 1):\n if len(self) == 0:\n return\n if n > 0:\n n = n % len(self)\n for _ in range(n):\n self.appendleft(self.pop())\n elif n < 0:\n n = -n % len(self)\n for _ in range(n):\n self.append(self.popleft())\n\n def __len__(self) -> int:\n return (self._tail - self._head) % self._capacity\n\n def __contains__(self, x: object) -> bool:\n for item in self:\n if item == x:\n return True\n return False\n \n def __iter__(self):\n i = self._head\n while i != self._tail:\n yield self._data[i]\n i = (i + 1) % self._capacity\n\n def __eq__(self, other: object) -> bool:\n if not isinstance(other, deque):\n return NotImplemented\n if len(self) != len(other):\n return False\n for x, y in zip(self, other):\n if x != y:\n return False\n return True\n \n def __ne__(self, other: object) -> bool:\n if not isinstance(other, deque):\n return NotImplemented\n return not self == other\n \n def __repr__(self) -> str:\n return f\"deque({list(self)!r})\"\n\n"; +const char kPythonLibs_collections[] = "from typing import TypeVar, Iterable\n\ndef Counter[T](iterable: Iterable[T]):\n a: dict[T, int] = {}\n for x in iterable:\n if x in a:\n a[x] += 1\n else:\n a[x] = 1\n return a\n\n\nclass defaultdict(dict):\n def __init__(self, default_factory, *args):\n super().__init__(*args)\n self.default_factory = default_factory\n\n def __missing__(self, key):\n self[key] = self.default_factory()\n return self[key]\n\n def __repr__(self) -> str:\n return f\"defaultdict({self.default_factory}, {super().__repr__()})\"\n\n def copy(self):\n return defaultdict(self.default_factory, self)\n\n\nclass deque[T]:\n _head: int\n _tail: int\n _maxlen: int | None\n _capacity: int\n _data: list[T]\n\n def __init__(self, iterable: Iterable[T] = None, maxlen: int | None = None):\n if maxlen is not None:\n assert maxlen > 0\n\n self._head = 0\n self._tail = 0\n self._maxlen = maxlen\n self._capacity = 8 if maxlen is None else maxlen + 1\n self._data = [None] * self._capacity # type: ignore\n\n if iterable is not None:\n self.extend(iterable)\n\n @property\n def maxlen(self) -> int | None:\n return self._maxlen\n\n def __resize_2x(self):\n backup = list(self)\n self._capacity *= 2\n self._head = 0\n self._tail = len(backup)\n self._data.clear()\n self._data.extend(backup)\n self._data.extend([None] * (self._capacity - len(backup)))\n\n def append(self, x: T):\n if (self._tail + 1) % self._capacity == self._head:\n if self._maxlen is None:\n self.__resize_2x()\n else:\n self.popleft()\n self._data[self._tail] = x\n self._tail = (self._tail + 1) % self._capacity\n\n def appendleft(self, x: T):\n if (self._tail + 1) % self._capacity == self._head:\n if self._maxlen is None:\n self.__resize_2x()\n else:\n self.pop()\n self._head = (self._head - 1) % self._capacity\n self._data[self._head] = x\n\n def copy(self):\n return deque(self, maxlen=self.maxlen)\n \n def count(self, x: T) -> int:\n n = 0\n for item in self:\n if item == x:\n n += 1\n return n\n \n def extend(self, iterable: Iterable[T]):\n for x in iterable:\n self.append(x)\n\n def extendleft(self, iterable: Iterable[T]):\n for x in iterable:\n self.appendleft(x)\n \n def pop(self) -> T:\n if self._head == self._tail:\n raise IndexError(\"pop from an empty deque\")\n self._tail = (self._tail - 1) % self._capacity\n x = self._data[self._tail]\n self._data[self._tail] = None\n return x\n \n def popleft(self) -> T:\n if self._head == self._tail:\n raise IndexError(\"pop from an empty deque\")\n x = self._data[self._head]\n self._data[self._head] = None\n self._head = (self._head + 1) % self._capacity\n return x\n \n def clear(self):\n i = self._head\n while i != self._tail:\n self._data[i] = None # type: ignore\n i = (i + 1) % self._capacity\n self._head = 0\n self._tail = 0\n\n def rotate(self, n: int = 1):\n if len(self) == 0:\n return\n if n > 0:\n n = n % len(self)\n for _ in range(n):\n self.appendleft(self.pop())\n elif n < 0:\n n = -n % len(self)\n for _ in range(n):\n self.append(self.popleft())\n\n def __len__(self) -> int:\n return (self._tail - self._head) % self._capacity\n\n def __contains__(self, x: object) -> bool:\n for item in self:\n if item == x:\n return True\n return False\n \n def __iter__(self):\n i = self._head\n while i != self._tail:\n yield self._data[i]\n i = (i + 1) % self._capacity\n\n def __eq__(self, other: object) -> bool:\n if not isinstance(other, deque):\n return NotImplemented\n if len(self) != len(other):\n return False\n for x, y in zip(self, other):\n if x != y:\n return False\n return True\n \n def __ne__(self, other: object) -> bool:\n if not isinstance(other, deque):\n return NotImplemented\n return not self == other\n \n def __repr__(self) -> str:\n if self.maxlen is None:\n return f\"deque({list(self)!r})\"\n return f\"deque({list(self)!r}, maxlen={self.maxlen})\"\n\n"; const char kPythonLibs_dataclasses[] = "def _get_annotations(cls: type):\n inherits = []\n while cls is not object:\n inherits.append(cls)\n cls = cls.__base__\n inherits.reverse()\n res = {}\n for cls in inherits:\n res.update(cls.__annotations__)\n return res.keys()\n\ndef _wrapped__init__(self, *args, **kwargs):\n cls = type(self)\n cls_d = cls.__dict__\n fields = _get_annotations(cls)\n i = 0 # index into args\n for field in fields:\n if field in kwargs:\n setattr(self, field, kwargs.pop(field))\n else:\n if i < len(args):\n setattr(self, field, args[i])\n i += 1\n elif field in cls_d: # has default value\n setattr(self, field, cls_d[field])\n else:\n raise TypeError(f\"{cls.__name__} missing required argument {field!r}\")\n if len(args) > i:\n raise TypeError(f\"{cls.__name__} takes {len(fields)} positional arguments but {len(args)} were given\")\n if len(kwargs) > 0:\n raise TypeError(f\"{cls.__name__} got an unexpected keyword argument {next(iter(kwargs))!r}\")\n\ndef _wrapped__repr__(self):\n fields = _get_annotations(type(self))\n obj_d = self.__dict__\n args: list = [f\"{field}={obj_d[field]!r}\" for field in fields]\n return f\"{type(self).__name__}({', '.join(args)})\"\n\ndef _wrapped__eq__(self, other):\n if type(self) is not type(other):\n return False\n fields = _get_annotations(type(self))\n for field in fields:\n if getattr(self, field) != getattr(other, field):\n return False\n return True\n\ndef _wrapped__ne__(self, other):\n return not self.__eq__(other)\n\ndef dataclass(cls: type):\n assert type(cls) is type\n cls_d = cls.__dict__\n if '__init__' not in cls_d:\n cls.__init__ = _wrapped__init__\n if '__repr__' not in cls_d:\n cls.__repr__ = _wrapped__repr__\n if '__eq__' not in cls_d:\n cls.__eq__ = _wrapped__eq__\n if '__ne__' not in cls_d:\n cls.__ne__ = _wrapped__ne__\n fields = _get_annotations(cls)\n has_default = False\n for field in fields:\n if field in cls_d:\n has_default = True\n else:\n if has_default:\n raise TypeError(f\"non-default argument {field!r} follows default argument\")\n return cls\n\ndef asdict(obj) -> dict:\n fields = _get_annotations(type(obj))\n obj_d = obj.__dict__\n return {field: obj_d[field] for field in fields}"; const char kPythonLibs_datetime[] = "from time import localtime\nimport operator\n\nclass timedelta:\n def __init__(self, days=0, seconds=0):\n self.days = days\n self.seconds = seconds\n\n def __repr__(self):\n return f\"datetime.timedelta(days={self.days}, seconds={self.seconds})\"\n\n def __eq__(self, other) -> bool:\n if not isinstance(other, timedelta):\n return NotImplemented\n return (self.days, self.seconds) == (other.days, other.seconds)\n\n def __ne__(self, other) -> bool:\n if not isinstance(other, timedelta):\n return NotImplemented\n return (self.days, self.seconds) != (other.days, other.seconds)\n\n\nclass date:\n def __init__(self, year: int, month: int, day: int):\n self.year = year\n self.month = month\n self.day = day\n\n @staticmethod\n def today():\n t = localtime()\n return date(t.tm_year, t.tm_mon, t.tm_mday)\n \n def __cmp(self, other, op):\n if not isinstance(other, date):\n return NotImplemented\n if self.year != other.year:\n return op(self.year, other.year)\n if self.month != other.month:\n return op(self.month, other.month)\n return op(self.day, other.day)\n\n def __eq__(self, other) -> bool:\n return self.__cmp(other, operator.eq)\n \n def __ne__(self, other) -> bool:\n return self.__cmp(other, operator.ne)\n\n def __lt__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.lt)\n\n def __le__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.le)\n\n def __gt__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.gt)\n\n def __ge__(self, other: 'date') -> bool:\n return self.__cmp(other, operator.ge)\n\n def __str__(self):\n return f\"{self.year}-{self.month:02}-{self.day:02}\"\n\n def __repr__(self):\n return f\"datetime.date({self.year}, {self.month}, {self.day})\"\n\n\nclass datetime(date):\n def __init__(self, year: int, month: int, day: int, hour: int, minute: int, second: int):\n super().__init__(year, month, day)\n # Validate and set hour, minute, and second\n if not 0 <= hour <= 23:\n raise ValueError(\"Hour must be between 0 and 23\")\n self.hour = hour\n if not 0 <= minute <= 59:\n raise ValueError(\"Minute must be between 0 and 59\")\n self.minute = minute\n if not 0 <= second <= 59:\n raise ValueError(\"Second must be between 0 and 59\")\n self.second = second\n\n def date(self) -> date:\n return date(self.year, self.month, self.day)\n\n @staticmethod\n def now():\n t = localtime()\n tm_sec = t.tm_sec\n if tm_sec == 60:\n tm_sec = 59\n return datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, tm_sec)\n\n def __str__(self):\n return f\"{self.year}-{self.month:02}-{self.day:02} {self.hour:02}:{self.minute:02}:{self.second:02}\"\n\n def __repr__(self):\n return f\"datetime.datetime({self.year}, {self.month}, {self.day}, {self.hour}, {self.minute}, {self.second})\"\n\n def __cmp(self, other, op):\n if not isinstance(other, datetime):\n return NotImplemented\n if self.year != other.year:\n return op(self.year, other.year)\n if self.month != other.month:\n return op(self.month, other.month)\n if self.day != other.day:\n return op(self.day, other.day)\n if self.hour != other.hour:\n return op(self.hour, other.hour)\n if self.minute != other.minute:\n return op(self.minute, other.minute)\n return op(self.second, other.second)\n\n def __eq__(self, other) -> bool:\n return self.__cmp(other, operator.eq)\n \n def __ne__(self, other) -> bool:\n return self.__cmp(other, operator.ne)\n \n def __lt__(self, other) -> bool:\n return self.__cmp(other, operator.lt)\n \n def __le__(self, other) -> bool:\n return self.__cmp(other, operator.le)\n \n def __gt__(self, other) -> bool:\n return self.__cmp(other, operator.gt)\n \n def __ge__(self, other) -> bool:\n return self.__cmp(other, operator.ge)\n\n\n"; const char kPythonLibs_functools[] = "class cache:\n def __init__(self, f):\n self.f = f\n self.cache = {}\n\n def __call__(self, *args):\n if args not in self.cache:\n self.cache[args] = self.f(*args)\n return self.cache[args]\n \nclass lru_cache:\n def __init__(self, maxsize=128):\n self.maxsize = maxsize\n self.cache = {}\n\n def __call__(self, f):\n def wrapped(*args):\n if args in self.cache:\n res = self.cache.pop(args)\n self.cache[args] = res\n return res\n \n res = f(*args)\n if len(self.cache) >= self.maxsize:\n first_key = next(iter(self.cache))\n self.cache.pop(first_key)\n self.cache[args] = res\n return res\n return wrapped\n \ndef reduce(function, sequence, initial=...):\n it = iter(sequence)\n if initial is ...:\n try:\n value = next(it)\n except StopIteration:\n raise TypeError(\"reduce() of empty sequence with no initial value\")\n else:\n value = initial\n for element in it:\n value = function(value, element)\n return value\n\nclass partial:\n def __init__(self, f, *args, **kwargs):\n self.f = f\n if not callable(f):\n raise TypeError(\"the first argument must be callable\")\n self.args = args\n self.kwargs = kwargs\n\n def __call__(self, *args, **kwargs):\n kwargs.update(self.kwargs)\n return self.f(*self.args, *args, **kwargs)\n\n"; diff --git a/tests/72_collections.py b/tests/72_collections.py index 5c75782e..07fa888b 100644 --- a/tests/72_collections.py +++ b/tests/72_collections.py @@ -516,3 +516,31 @@ d = deque() for i in range(100): d.append(1) gc.collect() + +# test maxlen +q = deque(maxlen=3) +assertEqual(q.maxlen, 3) +q.append(1) +q.append(2) +q.append(3) +assertEqual(list(q), [1, 2, 3]) +assertEqual(q._data, [1, 2, 3, None]) +q.append(4) +assertEqual(list(q), [2, 3, 4]) +assertEqual(q._data, [None, 2, 3, 4]) +q.appendleft(1) +assertEqual(list(q), [1, 2, 3]) +assertEqual(q._data, [1, 2, 3, None]) +q.appendleft(0) +assertEqual(list(q), [0, 1, 2]) +assertEqual(q._data, [1, 2, None, 0]) +q.pop() +assertEqual(list(q), [0, 1]) +assertEqual(q._data, [1, None, None, 0]) +assertEqual(len(q), 2) +assertEqual(q._capacity, 4) +q.popleft() +assertEqual(list(q), [1]) +assertEqual(q._data, [1, None, None, None]) + +