Skip to content

Instantly share code, notes, and snippets.

@tomphp
Created October 11, 2023 14:37
Show Gist options
  • Save tomphp/a0dd1d97128b504f8a20674b3a43a264 to your computer and use it in GitHub Desktop.
Save tomphp/a0dd1d97128b504f8a20674b3a43a264 to your computer and use it in GitHub Desktop.
Reference counting example
from collections import defaultdict
class Memory:
MEMORY = {0: None}
@staticmethod
def allocate(value):
address = max(Memory.MEMORY.keys()) + 1
Memory.MEMORY[address] = value
print(f"allocated at address {address}: {value}")
return address
@staticmethod
def deallocatte(address):
del Memory.MEMORY[address]
print(f"deallocated at address {address}")
class Rc:
REFS = defaultdict(lambda: {"count": 0, "borrowed": False})
def __init__(self, address):
self._address = address
self._borrowed = False
self._update_count(lambda current: current + 1)
print(f"Rc::__init__({self._address}) / reference count: {self._get_count()}")
def __del__(self):
self._update_count(lambda current: current - 1)
if self._borrowed:
self.REFS[self._address]["borrowed"] = False
print(f"Rc::__del__({self._address}) / reference count: {self._get_count()}")
if self._get_count() < 1:
Memory.deallocatte(self._address)
def clone(self):
return Rc(self._address)
def borrow(self):
if Rc.REFS[self._address]["borrowed"]:
raise RuntimeError("Can't borrow a reference twice")
Rc.REFS[self._address]["borrowed"] = True
self._borrowed = True
print("performed borrow")
def _update_count(self, update):
Rc.REFS[self._address]["count"] = update(self._get_count())
def _get_count(self):
return Rc.REFS[self._address]["count"]
# Demonstrates the reference counter in action.
# Try removing the r2 and r3 assignments (but keep the .clones()) and see how it
# changes the lifetime of the clones.
def reference_counter_example():
pointer = Memory.allocate("hello world")
r1 = Rc(pointer)
r2 = r1.clone()
r3 = r1.clone()
# This demonstrates that borrow can not been called while a previously borrowed
# reference is still in scope
def borrow_twice_example():
pointer = Memory.allocate("hello world")
r1 = Rc(pointer)
r2 = r1.clone()
r2.borrow()
r1.borrow()
# This demonstrates that borrow can be called repeatedly when the clones are not
# held in scope by an assignment
def line_scoped_borrow_twice_example():
pointer = Memory.allocate("hello world")
r1 = Rc(pointer)
r1.clone().borrow()
r1.clone().borrow()
r1.clone().borrow()
# This demonstrates that a function can be used to limit the time a clone exists for
def function_scoped_borrow_twice_example():
def scoped_borrow(pointer):
pointer.borrow()
pointer = Memory.allocate("hello world")
r1 = Rc(pointer)
scoped_borrow(r1.clone())
r1.borrow()
if __name__ == "__main__":
# Uncomment different examples
#reference_counter_example()
#borrow_twice_example()
#line_scoped_borrow_twice_example()
#function_scoped_borrow_twice_example()
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment