Provides a managed, resizable buffer.
| 9 | |
| 10 | |
| 11 | class Buffer: |
| 12 | """ |
| 13 | Provides a managed, resizable buffer. |
| 14 | """ |
| 15 | |
| 16 | class MemoryLimitExceeded(Error, OSError): |
| 17 | """Requested buffer size {} is above the limit of {}.""" |
| 18 | |
| 19 | def __init__(self, allocator, size=4096, limit=None): |
| 20 | """ |
| 21 | Initialize the buffer by using allocator(size) to allocate a buffer. |
| 22 | Optionally, set an upper limit for the buffer size. |
| 23 | """ |
| 24 | assert callable(allocator), "must give alloc(size) function as first param" |
| 25 | assert limit is None or size <= limit, "initial size must be <= limit" |
| 26 | self.allocator = allocator |
| 27 | self.limit = limit |
| 28 | self.resize(size, init=True) |
| 29 | |
| 30 | def __len__(self): |
| 31 | return len(self.buffer) |
| 32 | |
| 33 | def resize(self, size, init=False): |
| 34 | """ |
| 35 | Resize the buffer. To avoid frequent reallocation, we usually grow (if needed). |
| 36 | By giving init=True it is possible to initialize for the first time or shrink the buffer. |
| 37 | If a buffer size beyond the limit is requested, raise Buffer.MemoryLimitExceeded (OSError). |
| 38 | """ |
| 39 | size = int(size) |
| 40 | if self.limit is not None and size > self.limit: |
| 41 | raise Buffer.MemoryLimitExceeded(size, self.limit) |
| 42 | if init or len(self) < size: |
| 43 | self.buffer = self.allocator(size) |
| 44 | |
| 45 | def get(self, size=None, init=False): |
| 46 | """ |
| 47 | Return a buffer of at least the requested size (None: any current size). |
| 48 | init=True can be given to trigger shrinking of the buffer to the given size. |
| 49 | """ |
| 50 | if size is not None: |
| 51 | self.resize(size, init) |
| 52 | return self.buffer |
| 53 | |
| 54 | |
| 55 | class EfficientCollectionQueue: |
no outgoing calls