|
1
|
|
|
"""Implementation of the object pool""" |
|
2
|
|
|
import types |
|
3
|
|
|
import attr |
|
4
|
|
|
|
|
5
|
|
|
__all__ = ['ObjectsPool'] |
|
6
|
|
|
|
|
7
|
|
|
|
|
8
|
|
|
def _convert_to_method(function): |
|
9
|
|
|
def _function(_self, *args, **kwargs): |
|
10
|
|
|
return function(*args, **kwargs) |
|
11
|
|
|
return _function |
|
12
|
|
|
|
|
13
|
|
|
|
|
14
|
|
|
@attr.s |
|
15
|
|
|
class ObjectsPool: |
|
16
|
|
|
"""Class of objects that are able to return a reference to an object upon request. |
|
17
|
|
|
|
|
18
|
|
|
Whenever an object is requested, it is checked whether it exists in the pool. |
|
19
|
|
|
Then if it exists, a reference is returned, otherwise a new object is |
|
20
|
|
|
constructed (given the provided callable) and its reference is returned. |
|
21
|
|
|
|
|
22
|
|
|
Arguments: |
|
23
|
|
|
constructor (callable): able to construct the object given arguments |
|
24
|
|
|
objects (dict): the data structure representing the object pool |
|
25
|
|
|
""" |
|
26
|
|
|
@staticmethod |
|
27
|
|
|
def __build_hash(*args, **kwargs): |
|
28
|
|
|
r"""Construct a unique string out of the input \*args and \*\*kwargs.""" |
|
29
|
|
|
return hash('-'.join([str(_) for _ in args] + ['{key}={value}'.format(key=k, value=str(v)) for k, v in kwargs])) |
|
30
|
|
|
|
|
31
|
|
|
constructor = attr.ib(init=True) |
|
32
|
|
|
_objects = attr.ib(init=True, default={}) |
|
33
|
|
|
_build_hash = attr.ib(default=attr.Factory(lambda self: types.MethodType( |
|
34
|
|
|
_convert_to_method(ObjectsPool.__build_hash), self), takes_self=True)) |
|
35
|
|
|
|
|
36
|
|
|
def get_object(self, *args, **kwargs): |
|
37
|
|
|
r"""Request an object from the pool. |
|
38
|
|
|
|
|
39
|
|
|
Get or create an object given the input parameters. Existence in the pool is done using the |
|
40
|
|
|
python-build-in hash function. The input \*args and \*\*kwargs serve as |
|
41
|
|
|
input in the hash function to create unique keys with which to "query" the object pool. |
|
42
|
|
|
|
|
43
|
|
|
Returns: |
|
44
|
|
|
object: the reference to the object that corresponds to the input |
|
45
|
|
|
arguments, regardless of whether it was found in the pool or not |
|
46
|
|
|
""" |
|
47
|
|
|
key = self._build_hash(*args, **kwargs) |
|
48
|
|
|
if key not in self._objects: |
|
49
|
|
|
self._objects[key] = self.constructor(*args, **kwargs) |
|
50
|
|
|
return self._objects[key] |
|
51
|
|
|
|
|
52
|
|
|
@classmethod |
|
53
|
|
|
def new_empty(cls, constructor, build_hash=None): |
|
54
|
|
|
if build_hash is None: |
|
55
|
|
|
build_hash = ObjectsPool.__build_hash |
|
56
|
|
|
return ObjectsPool(constructor, {}, build_hash) |
|
57
|
|
|
|