wow. that was easy: git mv core nucleus
[feisty_meow.git] / nucleus / library / nodes / list.cpp
diff --git a/nucleus/library/nodes/list.cpp b/nucleus/library/nodes/list.cpp
new file mode 100644 (file)
index 0000000..3429f8e
--- /dev/null
@@ -0,0 +1,270 @@
+
+
+
+/*****************************************************************************\
+*                                                                             *
+*  Name   : list                                                              *
+*  Author : Chris Koeritz                                                     *
+*                                                                             *
+*******************************************************************************
+* Copyright (c) 1998-$now By Author.  This program is free software; you can  *
+* redistribute it and/or modify it under the terms of the GNU General Public  *
+* License as published by the Free Software Foundation; either version 2 of   *
+* the License or (at your option) any later version.  This is online at:      *
+*     http://www.fsf.org/copyleft/gpl.html                                    *
+* Please send any updates to: fred@gruntose.com                               *
+\*****************************************************************************/
+
+// POLICIES:
+//
+// the cursor should never be stored to or deleted; it is merely a scanner that
+// runs through the list.
+//
+// the cursor can point at the head or tail.  any storage action is taken to
+// mean that it applies to the closest real object, if one exists.  any query
+// action is taken similarly.
+
+#include "list.h"
+#include "node.h"
+
+#include <basis/functions.h>
+
+namespace nodes {
+
+// nice names for the positions of the next link and the previous link in
+// our node's indices.
+const int PREVIOUS = 0;
+const int NEXT = 1;
+
+//////////////
+
+// iterator functions:
+
+void list::iterator::operator ++()
+{
+  if (is_tail()) return;  // already at the end.
+  _cursor = _cursor->get_link(NEXT);
+}
+
+void list::iterator::operator --()
+{
+  if (is_head()) return;  // already at the front.
+  _cursor = _cursor->get_link(PREVIOUS);
+}
+
+bool list::iterator::operator ==(const iterator &to_compare) const
+{ return _cursor == to_compare._cursor; }
+
+const node *list::iterator::observe()
+{
+  if (!_manager || _manager->empty()) return NIL;
+  if (*this == _manager->head()) next();
+  if (*this == _manager->tail()) previous();
+  return _cursor;
+}
+
+node *list::iterator::access()
+{
+  if (!_manager || _manager->empty()) return NIL;
+  if (*this == _manager->head()) next();
+  if (*this == _manager->tail()) previous();
+  return _cursor;
+}
+
+bool list::iterator::is_head() const
+{
+  if (!_manager) return false;
+  return _cursor == _manager->_head;
+}
+
+bool list::iterator::is_tail() const
+{ 
+  if (!_manager) return false;
+  return _cursor == _manager->_tail;
+}
+
+void list::iterator::jump_head()
+{
+  if (!_manager) return;
+  _cursor = _manager->_head;
+}
+
+void list::iterator::jump_tail()
+{
+  if (!_manager) return;
+  _cursor = _manager->_tail;
+}
+
+//////////////
+
+list::list()
+: _head(NIL), _tail(NIL)
+{
+  _head = new node(2);
+  _tail = new node(2);
+  _head->set_link(NEXT, _tail);
+  _tail->set_link(PREVIOUS, _head);
+}
+
+list::~list()
+{
+  iterator zapper = head();
+  while (!empty())
+    zap(zapper);
+  WHACK(_head);
+  WHACK(_tail);
+}
+
+bool list::empty() const
+{
+  if (_head->get_link(NEXT) == _tail) return true;
+  return false;
+}
+
+bool list::set_index(iterator &where, int new_index)
+{
+  if (where._manager != this) return false;
+  if (empty()) return false;
+  node *skipper = _head->get_link(NEXT);
+  for (int i = 0; i < new_index; i++) {
+    skipper = skipper->get_link(NEXT);
+    if (skipper == _tail) return false;  // out of bounds now.
+  }
+  where._cursor = skipper;
+  return true;
+}
+
+bool list::forward(iterator &where, int count)
+{ 
+  if (where._manager != this) return false;
+  if (count <= 0) return true;
+  if (items_from_tail(where) < count) return false;
+  if (where.is_head()) where.next();  // skip the head guard.
+  for (int i = 0; i < count; i++) where.next();
+  return true;
+}
+
+bool list::backward(iterator &where, int count)
+{
+  if (where._manager != this) return false;
+  if (count <= 0) return true;
+  if (items_from_head(where) < count) return false;
+  if (where.is_tail()) where.previous();  // skip the tail guard.
+  for (int i = 0; i < count; i++) where.previous();
+  return true;
+}
+
+int list::elements() const
+{
+  if (empty()) return 0;
+  int to_return = 0;
+  node *skipper = _head->get_link(NEXT);
+  while (skipper != _tail) {
+    to_return++;
+    skipper = skipper->get_link(NEXT);
+  }
+  return to_return;
+}
+
+int list::items_from_head(const iterator &where) const
+{
+  if (where._manager != this) return 0;
+  if (where.is_head()) return 0;  // make sure it's not there already.
+  int index = 0;
+  node *skipper = _head->get_link(NEXT);
+  while ( (where._cursor != skipper) && (skipper != _tail) ) {
+    index++;
+    skipper = skipper->get_link(NEXT);
+  }
+  return index;
+}
+
+int list::items_from_tail(const iterator &where) const
+{
+  if (where._manager != this) return 0;
+  if (where.is_tail()) return 0;  // make sure it's not there already.
+  int index = 0;
+  node *skipper = _tail->get_link(PREVIOUS);
+  while ( (where._cursor != skipper) && (skipper != _head) ) {
+    index++;
+    skipper = skipper->get_link(PREVIOUS);
+  }
+  return index;
+}
+
+/*
+node *list::get()
+{
+  if (empty()) return NIL;  // make sure the list isn't empty.
+  if (_cursor == _head) return _head->get_link(NEXT);
+    // check special case for pointing at the head.
+  if (_cursor == _tail) return _tail->get_link(PREVIOUS);
+    // check special case for pointing at the tail.
+  return _cursor;
+}
+*/
+
+node *list::remove(iterator &where)
+{
+  if (where._manager != this) return NIL;
+  if (empty()) return NIL;
+  if (where._cursor == _head)
+    where._cursor = _head->get_link(NEXT);
+  if (where._cursor == _tail)
+    where._cursor = _tail->get_link(PREVIOUS);
+  node *old_cursor = where._cursor;
+  node *old_previous = old_cursor->get_link(PREVIOUS);
+  node *old_next = old_cursor->get_link(NEXT);
+  old_cursor->set_link(PREVIOUS, NIL);
+  old_cursor->set_link(NEXT, NIL);
+  old_previous->set_link(NEXT, old_next);
+  old_next->set_link(PREVIOUS, old_previous);
+  where._cursor = old_next;
+  return old_cursor;
+}
+
+void list::zap(iterator &where) { delete remove(where); }
+
+void list::append(iterator &where, node *new_node)
+{
+  if (where._manager != this) return;
+  while (new_node->links() < 2) new_node->insert_link(0, NIL);
+  if (empty()) where._cursor = _head;
+  if (where._cursor == _tail)
+    where._cursor = _tail->get_link(PREVIOUS);
+    // shift from the tail sentinel to the tail element.
+  node *save_next = where._cursor->get_link(NEXT);
+  where._cursor->set_link(NEXT, new_node);
+  new_node->set_link(PREVIOUS, where._cursor);
+  new_node->set_link(NEXT, save_next);
+  save_next->set_link(PREVIOUS, new_node);
+  where._cursor = new_node;
+}
+
+void list::insert(iterator &where, node *new_node)
+{
+  if (where._manager != this) return;
+  while (new_node->links() < 2) new_node->insert_link(0, NIL);
+  if (empty()) where._cursor = _tail;
+  if (where._cursor == _head)
+    where._cursor = _head->get_link(NEXT);
+    // shift from head sentinel to the head element.
+  node *save_prior = where._cursor->get_link(PREVIOUS);
+  where._cursor->set_link(PREVIOUS, new_node);
+  new_node->set_link(NEXT, where._cursor);
+  new_node->set_link(PREVIOUS, save_prior);
+  save_prior->set_link(NEXT, new_node);
+  where._cursor = new_node;
+}
+
+void list::zap_all()
+{
+  iterator zapper = head();
+  while (!empty()) zap(zapper);
+}
+
+} // namespace.
+
+
+
+