linkedlist.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # vim: set fileencoding=utf-8 :
  2. #
  3. # (C) 2012 Intel Corporation <markus.lehtonen@linux.intel.com>
  4. # This program is free software; you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation; either version 2 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, please see
  16. # <http://www.gnu.org/licenses/>
  17. """Simple implementation of a doubly linked list"""
  18. import collections
  19. import gbp.log
  20. class LinkedListNode(object):
  21. """Node of the linked list"""
  22. def __init__(self, data="", prev_node=None, next_node=None):
  23. self.prev = prev_node
  24. self.next = next_node
  25. self._data = data
  26. def __str__(self):
  27. return str(self.data)
  28. @property
  29. def data(self):
  30. """Get data stored into node"""
  31. if self._data is None:
  32. gbp.log.debug("BUG: referencing a deleted node!")
  33. return("")
  34. return self._data
  35. def set_data(self, data):
  36. """
  37. Set data stored into node
  38. >>> node = LinkedListNode('foo')
  39. >>> node.data
  40. 'foo'
  41. >>> node.set_data('bar')
  42. >>> node.data
  43. 'bar'
  44. >>> node.set_data(None)
  45. >>> node.data
  46. ''
  47. """
  48. if data is None:
  49. gbp.log.debug("BUG: trying to store 'None', not allowed")
  50. data = ""
  51. self._data = data
  52. def delete(self):
  53. """Delete node"""
  54. if self.prev:
  55. self.prev.next = self.next
  56. if self.next:
  57. self.next.prev = self.prev
  58. self._data = None
  59. class LinkedListIterator(collections.Iterator):
  60. """Iterator for the linked list"""
  61. def __init__(self, obj):
  62. self._next = obj.first
  63. def __next__(self):
  64. ret = self._next
  65. if ret:
  66. self._next = ret.next
  67. else:
  68. raise StopIteration
  69. return ret
  70. def next(self):
  71. return self.__next__()
  72. class LinkedList(collections.Iterable):
  73. """Doubly linked list"""
  74. def __init__(self):
  75. self._first = None
  76. self._last = None
  77. def __iter__(self):
  78. return LinkedListIterator(self)
  79. def __len__(self):
  80. for num, data in enumerate(self):
  81. pass
  82. return num + 1
  83. @property
  84. def first(self):
  85. """Get the first node of the list"""
  86. return self._first
  87. def prepend(self, data):
  88. """
  89. Insert to the beginning of list
  90. >>> list = LinkedList()
  91. >>> [str(data) for data in list]
  92. []
  93. >>> node = list.prepend("foo")
  94. >>> len(list)
  95. 1
  96. >>> node = list.prepend("bar")
  97. >>> [str(data) for data in list]
  98. ['bar', 'foo']
  99. """
  100. if self._first is None:
  101. new = self._first = self._last = LinkedListNode(data)
  102. else:
  103. new = self.insert_before(self._first, data)
  104. return new
  105. def append(self, data):
  106. """
  107. Insert to the end of list
  108. >>> list = LinkedList()
  109. >>> node = list.append('foo')
  110. >>> len(list)
  111. 1
  112. >>> node = list.append('bar')
  113. >>> [str(data) for data in list]
  114. ['foo', 'bar']
  115. """
  116. if self._last is None:
  117. return self.prepend(data)
  118. else:
  119. return self.insert_after(self._last, data)
  120. def insert_before(self, node, data=""):
  121. """
  122. Insert before a node
  123. >>> list = LinkedList()
  124. >>> node1 = list.append('foo')
  125. >>> node2 = list.insert_before(node1, 'bar')
  126. >>> node3 = list.insert_before(node1, 'baz')
  127. >>> [str(data) for data in list]
  128. ['bar', 'baz', 'foo']
  129. """
  130. new = LinkedListNode(data, prev_node=node.prev, next_node=node)
  131. if node.prev:
  132. node.prev.next = new
  133. else:
  134. self._first = new
  135. node.prev = new
  136. return new
  137. def insert_after(self, node, data=""):
  138. """
  139. Insert after a node
  140. >>> list = LinkedList()
  141. >>> node1 = list.prepend('foo')
  142. >>> node2 = list.insert_after(node1, 'bar')
  143. >>> node3 = list.insert_after(node1, 'baz')
  144. >>> [str(data) for data in list]
  145. ['foo', 'baz', 'bar']
  146. """
  147. new = LinkedListNode(data, prev_node=node, next_node=node.next)
  148. if node.next:
  149. node.next.prev = new
  150. else:
  151. self._last = new
  152. node.next = new
  153. return new
  154. def delete(self, node):
  155. """
  156. Delete node
  157. >>> list = LinkedList()
  158. >>> node1 = list.prepend('foo')
  159. >>> node2 = list.insert_after(node1, 'bar')
  160. >>> node3 = list.insert_before(node2, 'baz')
  161. >>> [str(data) for data in list]
  162. ['foo', 'baz', 'bar']
  163. >>> str(list.delete(node3))
  164. 'foo'
  165. >>> [str(data) for data in list]
  166. ['foo', 'bar']
  167. >>> print("%s" % node3)
  168. <BLANKLINE>
  169. >>> str(list.delete(node1))
  170. 'bar'
  171. >>> [str(data) for data in list]
  172. ['bar']
  173. >>> list.delete(node2)
  174. >>> [str(data) for data in list]
  175. []
  176. """
  177. ret = node.prev
  178. if node is self._first:
  179. ret = self._first = self._first.next
  180. if node is self._last:
  181. self._last = self._last.prev
  182. node.delete()
  183. return ret
  184. # vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: