Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 21 additions & 10 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pycommons/lang/atomic/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .atomic import Atomic
from .boolean import AtomicBoolean

__all__ = ["Atomic", "AtomicBoolean"]
28 changes: 28 additions & 0 deletions pycommons/lang/atomic/atomic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import TypeVar, Generic, Optional

from pycommons.lang.base.synchronized import RLockSynchronized, synchronized
from pycommons.lang.container import Container

_T = TypeVar("_T")


class Atomic(Container[_T], RLockSynchronized, Generic[_T]):
def __init__(self, t: Optional[_T] = None):
super().__init__(t)
RLockSynchronized.__init__(self)

@synchronized
def get(self) -> Optional[_T]:
return super().get()

@synchronized
def set(self, t: _T) -> None:
super().set(t)

@synchronized
def set_and_get(self, t: Optional[_T]) -> Optional[_T]:
return super().set_and_get(t)

@synchronized
def get_and_set(self, t: Optional[_T]) -> Optional[_T]:
return super().get_and_set(t)
31 changes: 31 additions & 0 deletions pycommons/lang/atomic/boolean.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from __future__ import annotations

from pycommons.lang.atomic.atomic import Atomic
from pycommons.lang.base.synchronized import synchronized
from pycommons.lang.container.boolean import BooleanContainer


class AtomicBoolean(BooleanContainer, Atomic[bool]): # pylint: disable=R0901
@synchronized
def true(self) -> bool:
return super().true()

@synchronized
def false(self) -> bool:
return super().false()

@synchronized
def compliment(self) -> bool:
return super().compliment()

@classmethod
def with_true(cls) -> AtomicBoolean:
return cls(True)

@classmethod
def with_false(cls) -> AtomicBoolean:
return cls(False)

@synchronized
def get(self) -> bool:
return super().get()
69 changes: 69 additions & 0 deletions pycommons/lang/atomic/integer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from pycommons.lang.atomic import Atomic
from pycommons.lang.base.synchronized import synchronized
from pycommons.lang.container import IntegerContainer


class AtomicInteger(IntegerContainer, Atomic[int]): # pylint: disable=R0901
@synchronized
def add(self, val: int) -> None:
return super().add(val)

@synchronized
def add_and_get(self, val: int) -> int:
return super().add_and_get(val)

@synchronized
def get_and_add(self, val: int) -> int:
return super().get_and_add(val)

@synchronized
def increment(self) -> None:
return super().increment()

@synchronized
def increment_and_get(self) -> int:
return super().increment_and_get()

@synchronized
def get_and_increment(self) -> int:
return super().get_and_increment()

@synchronized
def subtract(self, val: int) -> None:
return super().subtract(val)

@synchronized
def subtract_and_get(self, val: int) -> int:
return super().subtract_and_get(val)

@synchronized
def get_and_subtract(self, val: int) -> int:
return super().get_and_subtract(val)

@synchronized
def get(self) -> int:
return super().get()

@synchronized
def __int__(self) -> int:
return super().__int__()

@synchronized
def __le__(self, other: int) -> bool:
return super().__le__(other)

@synchronized
def __lt__(self, other: int) -> bool:
return super().__lt__(other)

@synchronized
def __ge__(self, other: int) -> bool:
return super().__ge__(other)

@synchronized
def __gt__(self, other: int) -> bool:
return super().__gt__(other)

@synchronized
def __eq__(self, other: object) -> bool:
return super().__eq__(other)
40 changes: 40 additions & 0 deletions pycommons/lang/base/synchronized.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import functools
from abc import abstractmethod, ABC
from threading import Lock, RLock
from typing import Union, TypeVar, Callable, Any

F = TypeVar("F", bound=Callable[..., Any])


class Synchronized(ABC):
@abstractmethod
def _sync_lock(self) -> Union[Lock, RLock]:
...

@staticmethod
def synchronized(f: F) -> Callable[..., Any]:
@functools.wraps(f)
def wrapped(self: Synchronized, *args: Any, **kwargs: Any) -> Any:
with self._sync_lock(): # pylint: disable=W0212
return f(self, *args, **kwargs)

return wrapped


synchronized = Synchronized.synchronized


class LockSynchronized(Synchronized):
def _sync_lock(self) -> Union[Lock, RLock]:
return self._lock

def __init__(self) -> None:
self._lock = Lock()


class RLockSynchronized(Synchronized):
def _sync_lock(self) -> Union[Lock, RLock]:
return self._lock

def __init__(self) -> None:
self._lock = RLock()
4 changes: 3 additions & 1 deletion pycommons/lang/container/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from .boolean import BooleanContainer
from .container import Container
from .integer import IntegerContainer

__all__ = ["Container"]
__all__ = ["Container", "BooleanContainer", "IntegerContainer"]
3 changes: 3 additions & 0 deletions pycommons/lang/container/boolean.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ def with_false(cls) -> BooleanContainer:

def get(self) -> bool:
return typing.cast(bool, super().get())

def __bool__(self) -> bool:
return self.get()
7 changes: 5 additions & 2 deletions pycommons/lang/container/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ def get(self) -> Optional[_T]:
def __init__(self, t: Optional[_T] = None):
self._object: Optional[_T] = t

def set(self, t: _T) -> None:
def set(self, t: Optional[_T]) -> None:
self._object = t

def set_and_get(self, t: Optional[_T]) -> Optional[_T]:
self._object = t
self.set(t)
return self._object

def get_and_set(self, t: Optional[_T]) -> Optional[_T]:
old_object = self._object
self._object = t
return old_object

def __contains__(self, item: _T) -> bool:
return self._object == item

@classmethod
def with_none(cls) -> Container[Any]:
return cls()
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ poethepoet = "^0.20.0"

pytest = ">=7.2.0"
pytest-cov = "^2.10.1"
mockito = "1.4.0"

pylint = "^2.6.0"
black = "22.3.0"
Expand Down
Empty file.
22 changes: 22 additions & 0 deletions tests/pycommons/lang/atomic/test_atomic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from unittest import TestCase

from pycommons.lang.atomic import Atomic


class TestAtomic(TestCase):
def test_container(self):
container = Atomic.with_none()

self.assertIsNone(container.get())

mock_object1 = object()
container.set(mock_object1)
self.assertEqual(mock_object1, container.get())

mock_object2 = object()
self.assertEqual(mock_object1, container.get_and_set(mock_object2))
self.assertEqual(mock_object2, container.get())

mock_object3 = object()
self.assertEqual(mock_object3, container.set_and_get(mock_object3))
self.assertTrue(mock_object3 in container)
22 changes: 22 additions & 0 deletions tests/pycommons/lang/atomic/test_boolean.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from unittest import TestCase

from pycommons.lang.atomic import AtomicBoolean


class TestAtomicBoolean(TestCase):
def test_container(self):
boolean_container = AtomicBoolean.with_true()
self.assertTrue(boolean_container)

boolean_container.compliment()
self.assertFalse(boolean_container.get())

boolean_container.true()
self.assertTrue(boolean_container)

boolean_container.false()
self.assertFalse(boolean_container)

def test_container_initialized_with_false(self):
boolean_container = AtomicBoolean.with_false()
self.assertFalse(boolean_container)
Empty file.
22 changes: 22 additions & 0 deletions tests/pycommons/lang/container/test_boolean.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from unittest import TestCase

from pycommons.lang.container import BooleanContainer


class TestBooleanContainer(TestCase):
def test_container(self):
boolean_container = BooleanContainer.with_true()
self.assertTrue(boolean_container)

boolean_container.compliment()
self.assertFalse(boolean_container.get())

boolean_container.true()
self.assertTrue(boolean_container)

boolean_container.false()
self.assertFalse(boolean_container)

def test_container_initialized_with_false(self):
boolean_container = BooleanContainer.with_false()
self.assertFalse(boolean_container)
22 changes: 22 additions & 0 deletions tests/pycommons/lang/container/test_container.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from unittest import TestCase

from pycommons.lang.container import Container


class TestContainer(TestCase):
def test_container(self):
container = Container.with_none()

self.assertIsNone(container.get())

mock_object1 = object()
container.set(mock_object1)
self.assertEqual(mock_object1, container.get())

mock_object2 = object()
self.assertEqual(mock_object1, container.get_and_set(mock_object2))
self.assertEqual(mock_object2, container.get())

mock_object3 = object()
self.assertEqual(mock_object3, container.set_and_get(mock_object3))
self.assertTrue(mock_object3 in container)
Loading