Skip to content

Commit

Permalink
Added FrozenOrderedSet implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
rindPHI committed Apr 4, 2022
1 parent 60b9290 commit affda40
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 9 deletions.
97 changes: 91 additions & 6 deletions orderedset/orderedset.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from collections.abc import Set, Iterator, Iterable
from typing import TypeVar, Generic, Optional, Union, Any, Dict
from typing import TypeVar, Generic, Optional, Any, Dict

from frozendict import frozendict

T = TypeVar("T")
S = TypeVar("S")


class OrderedSet(Set[T], Generic[T]):
def __init__(self, base: Optional[Union[Dict[T, None], Iterable[T]]] = None):
def __init__(self, base: Optional[Dict[T, None] | Iterable[T]] = None):
self.the_dict: Dict[T, None]
if not base:
self.the_dict = {}
Expand Down Expand Up @@ -104,10 +106,10 @@ def __iand__(self, s: Set[T]) -> 'OrderedSet[T]':
self.the_dict = result.the_dict
return result

def __or__(self, s: Set[S]) -> 'OrderedSet[Union[T, S]]':
def __or__(self, s: Set[S]) -> 'OrderedSet[T| S]':
return self.union(s)

def __ior__(self, s: Set[S]) -> 'OrderedSet[Union[T, S]]':
def __ior__(self, s: Set[S]) -> 'OrderedSet[T| S]':
result = self.union(s)
self.the_dict = result.the_dict
return result
Expand All @@ -120,10 +122,10 @@ def __isub__(self, s: Set[Optional[T]]) -> 'OrderedSet[T]':
self.the_dict = result.the_dict
return result

def __xor__(self, s: Set[S]) -> 'OrderedSet[Union[T, S]]':
def __xor__(self, s: Set[S]) -> 'OrderedSet[T| S]':
return self.symmetric_difference(s)

def __ixor__(self, s: Set[S]) -> 'OrderedSet[Union[T, S]]':
def __ixor__(self, s: Set[S]) -> 'OrderedSet[T| S]':
result = self.symmetric_difference(s)
self.the_dict = result.the_dict
return result
Expand All @@ -139,3 +141,86 @@ def __ge__(self, s: Set[T]) -> bool:

def __gt__(self, s: Set[T]) -> bool:
return set(self) > set(s)


class FrozenOrderedSet(OrderedSet[T]):
def __init__(self, base: Dict[T, None] | Iterable[T]):
super().__init__()
self.the_dict: frozendict[T, None]
if not base:
self.the_dict = frozendict({})
elif isinstance(base, frozendict):
self.the_dict = base
else:
self.the_dict = frozendict.fromkeys(base)

def __repr__(self) -> str:
return f"FrozenOrderedSet({repr(self.the_dict)})"

def add(self, element: T) -> None:
raise NotImplementedError('Cannot add to FrozenOrderedSet')

def clear(self) -> None:
raise NotImplementedError('Cannot clear FrozenOrderedSet')

def copy(self) -> 'FrozenOrderedSet[T]':
return FrozenOrderedSet(self.the_dict)

def difference(self, s: Iterable[Any]) -> 'FrozenOrderedSet[T]':
return FrozenOrderedSet(frozendict({e: None for e in self.the_dict if e not in s}))

def difference_update(self, s: Iterable[Any]) -> None:
self.the_dict = frozendict({e: None for e in self.the_dict if e not in s})

def discard(self, element: T) -> None:
raise NotImplementedError('Cannot discard from FrozenOrderedSet')

def intersection(self, s: Iterable[Any]) -> 'FrozenOrderedSet[T]':
return FrozenOrderedSet(frozendict({e: None for e in self.the_dict if e in s}))

def intersection_update(self, s: Iterable[Any]) -> None:
self.the_dict = FrozenOrderedSet(frozendict({e: None for e in self.the_dict if e in s}))

def pop(self) -> T:
raise NotImplementedError('Cannot pop from FrozenOrderedSet')

def remove(self, element: T) -> None:
raise NotImplementedError('Cannot remove from FrozenOrderedSet')

def symmetric_difference(self, s: Iterable[T]) -> 'FrozenOrderedSet[T]':
return FrozenOrderedSet(
frozendict.fromkeys([e for e in self.the_dict if e not in s] +
[e for e in s if e not in self.the_dict]))

def symmetric_difference_update(self, s: Iterable[T]) -> None:
raise NotImplementedError('Cannot update FrozenOrderedSet')

def union(self, s: Iterable[T]) -> 'FrozenOrderedSet[T]':
return FrozenOrderedSet(frozendict({**self.the_dict, **dict.fromkeys(s)}))

def update(self, s: Iterable[T]) -> None:
raise NotImplementedError('Cannot update FrozenOrderedSet')

def __and__(self, s: Set[T]) -> 'FrozenOrderedSet[T]':
return self.intersection(s)

def __iand__(self, s: Set[T]) -> 'FrozenOrderedSet[T]':
raise NotImplementedError('Cannot update FrozenOrderedSet')

def __or__(self, s: Set[S]) -> 'FrozenOrderedSet[T | S]':
return self.union(s)

def __ior__(self, s: Set[S]) -> 'FrozenOrderedSet[T | S]':
raise NotImplementedError('Cannot update FrozenOrderedSet')

def __sub__(self, s: Set[Optional[T]]) -> 'FrozenOrderedSet[T]':
return self.difference(s)

def __isub__(self, s: Set[Optional[T]]) -> 'FrozenOrderedSet[T]':
raise NotImplementedError('Cannot update FrozenOrderedSet')

def __xor__(self, s: Set[S]) -> 'FrozenOrderedSet[T | S]':
return self.symmetric_difference(s)

def __ixor__(self, s: Set[S]) -> 'FrozenOrderedSet[T | S]':
raise NotImplementedError('Cannot update FrozenOrderedSet')
4 changes: 4 additions & 0 deletions orderedset/tests/test_orderedset.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import unittest

from orderedset import OrderedSet
from orderedset.orderedset import FrozenOrderedSet


class TestOrderedset(unittest.TestCase):
Expand All @@ -25,6 +26,9 @@ def test_ne(self):
def test_str(self):
self.assertEqual("{3, 1, 2}", str(OrderedSet([3, 1, 2])))

def test_str_frozen(self):
self.assertEqual("{3, 1, 2}", str(FrozenOrderedSet([3, 1, 2])))

def test_repr(self):
self.assertEqual("OrderedSet({3: None, 1: None, 2: None})", repr(OrderedSet([3, 1, 2])))

Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
attrs>=21.2.0
frozendict>=2.3.1
iniconfig>=1.1.1
packaging>=21.0
pluggy>=0.12.0
py>=1.11.0
pyparsing>=2.4.7
pytest>=6.2.5
pytest-html>=3.1.1
pytest-metadata>=1.11.0
pytest>=6.2.5
toml>=0.10.2
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

setup(
name='proxyorderedset',
version='0.1',
version='0.2',
packages=['orderedset'],
url='https://projects.cispa.saarland/c01dost/islearn',
license='GNU GPLv3',
author='Dominic Steinhoefel',
author_email='dominic.steinhoefel@cispa.de',
description='OrderedSet implementation as a proxy to dict',
description='OrderedSet/FrozenOrderedSet implementation as a proxy to dict/frozendict',
install_requires=[
"attrs>=21.2.0",
"iniconfig>=1.1.1",
"frozendict>=2.3.1",
"packaging>=21.0",
"pluggy>=0.12.0",
"py>=1.11.0",
Expand Down

0 comments on commit affda40

Please sign in to comment.