1

Context:
Some code I found which implements a XOR linked list. In XOR linked list, instead of each node having a next pointer, it has a both attribute which is the XOR of prev and next node.

import ctypes


# This is hacky. It's a data structure for C, not python.
class Node(object):
    def __init__(self, val):
        self.val = val
        self.both = 0


class XorLinkedList(object):
    def __init__(self):
        self.head = self.tail = None
        self.__nodes = [] # This is to prevent garbage collection

    def add(self, node):
        if self.head is None:
            self.head = self.tail = node
        else:
            self.tail.both = id(node) ^ self.tail.both
            node.both = id(self.tail)
            self.tail = node

        # Without this line, Python thinks there is no way to reach nodes between
        # head and tail.
        self.__nodes.append(node)


    def get(self, index):
        prev_id = 0
        node = self.head
        for i in range(index):
            next_id = prev_id ^ node.both

            if next_id:
                prev_id = id(node)
                node = _get_obj(next_id)
            else:
                raise IndexError('Linked list index out of range')
        return node


def _get_obj(id):
    return ctypes.cast(id, ctypes.py_object).value

Questions:

  1. Don't understand the need of _get_obj() function and what it is trying to do here?
  2. How is self.__nodes = [] useful? And how it implements garbage collection here?
  3. I have no idea what the following code is doing:

    # Without this line, Python thinks there is no way to reach nodes between
    # head and tail.
    self.__nodes.append(node)`
    
martineau
  • 119,623
  • 25
  • 170
  • 301
Abhishek Bhatia
  • 9,404
  • 26
  • 87
  • 142

1 Answers1

1

I can answer most of the sub-questions within your question.

  1. the _get_obj() function is the inverse Python's own id() function (with the CPython interpreter anyway). There are other ways to do it. See for example the question Is it possible to dereference variable id's?.

  2. & 3. The self.__nodes.append(node) adds the Node instance to a private list because adding it to the XOR linked-list doesn't create a reference to it as would likely happen in a more common normal implementation (the XOR trick eliminates the need for them). Without this, the Python garbage-collector might delete the Node instance while it was still part of the linked-list.

martineau
  • 119,623
  • 25
  • 170
  • 301