184 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// vim: set sts=8 ts=2 sw=2 tw=99 et:
 | 
						|
//
 | 
						|
// Copyright (C) 2013, David Anderson and AlliedModders LLC
 | 
						|
// All rights reserved.
 | 
						|
// 
 | 
						|
// Redistribution and use in source and binary forms, with or without
 | 
						|
// modification, are permitted provided that the following conditions are met:
 | 
						|
// 
 | 
						|
//  * Redistributions of source code must retain the above copyright notice, this
 | 
						|
//    list of conditions and the following disclaimer.
 | 
						|
//  * Redistributions in binary form must reproduce the above copyright notice,
 | 
						|
//    this list of conditions and the following disclaimer in the documentation
 | 
						|
//    and/or other materials provided with the distribution.
 | 
						|
//  * Neither the name of AlliedModders LLC nor the names of its contributors
 | 
						|
//    may be used to endorse or promote products derived from this software
 | 
						|
//    without specific prior written permission.
 | 
						|
//
 | 
						|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
						|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
						|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
						|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
						|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
						|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
						|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
						|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
						|
// POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
#ifndef _include_amtl_inline_list_h_
 | 
						|
#define _include_amtl_inline_list_h_
 | 
						|
 | 
						|
#include <stddef.h>
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
namespace ke {
 | 
						|
 | 
						|
template <typename T> class InlineList;
 | 
						|
 | 
						|
// Objects can recursively inherit from InlineListNode in order to have
 | 
						|
// membership in an InlineList<T>.
 | 
						|
template <typename T>
 | 
						|
class InlineListNode
 | 
						|
{
 | 
						|
  friend class InlineList<T>;
 | 
						|
 | 
						|
  public:
 | 
						|
  InlineListNode()
 | 
						|
   : next_(NULL),
 | 
						|
     prev_(NULL)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  InlineListNode(InlineListNode *next, InlineListNode *prev)
 | 
						|
   : next_(next),
 | 
						|
     prev_(prev)
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  protected:
 | 
						|
  InlineListNode *next_;
 | 
						|
  InlineListNode *prev_;
 | 
						|
};
 | 
						|
 | 
						|
// An InlineList is a linked list that threads link pointers through objects,
 | 
						|
// rather than allocating node memory. A node can be in at most one list at
 | 
						|
// any time.
 | 
						|
//
 | 
						|
// Since InlineLists are designed to be very cheap, there is no requirement
 | 
						|
// that elements be removed from a list once the list is destructed. However,
 | 
						|
// for as long as the list is alive, all of its contained nodes must also
 | 
						|
// be alive.
 | 
						|
template <typename T>
 | 
						|
class InlineList
 | 
						|
{
 | 
						|
  typedef InlineListNode<T> Node;
 | 
						|
 | 
						|
  Node head_;
 | 
						|
 | 
						|
  // Work around a clang bug where we can't initialize with &head_ in the ctor.
 | 
						|
  inline Node *head() {
 | 
						|
    return &head_;
 | 
						|
  }
 | 
						|
 | 
						|
 public:
 | 
						|
  InlineList()
 | 
						|
    : head_(head(), head())
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  ~InlineList()
 | 
						|
  {
 | 
						|
#if !defined(NDEBUG)
 | 
						|
    // Remove all items to clear their next/prev fields.
 | 
						|
    while (begin() != end())
 | 
						|
      remove(*begin());
 | 
						|
#endif
 | 
						|
  }
 | 
						|
 | 
						|
 public:
 | 
						|
  class iterator
 | 
						|
  {
 | 
						|
    friend class InlineList;
 | 
						|
    Node *iter_;
 | 
						|
 | 
						|
   public:
 | 
						|
    iterator(Node *iter)
 | 
						|
      : iter_(iter)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    iterator & operator ++() {
 | 
						|
      iter_ = iter_->next;
 | 
						|
      return *this;
 | 
						|
    }
 | 
						|
    iterator operator ++(int) {
 | 
						|
      iterator old(*this);
 | 
						|
      iter_ = iter_->next_;
 | 
						|
      return old;
 | 
						|
    }
 | 
						|
    T * operator *() {
 | 
						|
      return static_cast<T *>(iter_);
 | 
						|
    }
 | 
						|
    T * operator ->() {
 | 
						|
      return static_cast<T *>(iter_);
 | 
						|
    }
 | 
						|
    bool operator !=(const iterator &where) const {
 | 
						|
      return iter_ != where.iter_;
 | 
						|
    }
 | 
						|
    bool operator ==(const iterator &where) const {
 | 
						|
      return iter_ == where.iter_;
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  iterator begin() {
 | 
						|
    return iterator(head_.next_);
 | 
						|
  }
 | 
						|
 | 
						|
  iterator end() {
 | 
						|
    return iterator(&head_);
 | 
						|
  }
 | 
						|
 | 
						|
  iterator erase(iterator &at) {
 | 
						|
    iterator next = at;
 | 
						|
    next++;
 | 
						|
 | 
						|
    remove(at.iter_);
 | 
						|
 | 
						|
    // Iterator is no longer valid.
 | 
						|
    at.iter_ = NULL;
 | 
						|
 | 
						|
    return next;
 | 
						|
  }
 | 
						|
 | 
						|
  bool empty() const {
 | 
						|
    return head_.next_ == &head_;
 | 
						|
  }
 | 
						|
 | 
						|
  void remove(Node *t) {
 | 
						|
    t->prev_->next_ = t->next_;
 | 
						|
    t->next_->prev_ = t->prev_;
 | 
						|
 | 
						|
#if !defined(NDEBUG)
 | 
						|
    t->next_ = NULL;
 | 
						|
    t->prev_ = NULL;
 | 
						|
#endif
 | 
						|
  }
 | 
						|
 | 
						|
  void append(Node *t) {
 | 
						|
    assert(!t->next_);
 | 
						|
    assert(!t->prev_);
 | 
						|
 | 
						|
    t->prev_ = head_.prev_;
 | 
						|
    t->next_ = &head_;
 | 
						|
    head_.prev_->next_ = t;
 | 
						|
    head_.prev_ = t;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#endif // _include_amtl_inline_list_h_
 | 
						|
 |