Blame source/vdo/base/ringNode.h

Packit Service d40955
/*
Packit Service d40955
 * Copyright (c) 2020 Red Hat, Inc.
Packit Service d40955
 *
Packit Service d40955
 * This program is free software; you can redistribute it and/or
Packit Service d40955
 * modify it under the terms of the GNU General Public License
Packit Service d40955
 * as published by the Free Software Foundation; either version 2
Packit Service d40955
 * of the License, or (at your option) any later version.
Packit Service d40955
 * 
Packit Service d40955
 * This program is distributed in the hope that it will be useful,
Packit Service d40955
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service d40955
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service d40955
 * GNU General Public License for more details.
Packit Service d40955
 * 
Packit Service d40955
 * You should have received a copy of the GNU General Public License
Packit Service d40955
 * along with this program; if not, write to the Free Software
Packit Service d40955
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service d40955
 * 02110-1301, USA. 
Packit Service d40955
 *
Packit Service d40955
 * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/ringNode.h#1 $
Packit Service d40955
 */
Packit Service d40955
Packit Service d40955
#ifndef RING_NODE_H
Packit Service d40955
#define RING_NODE_H
Packit Service d40955
Packit Service d40955
#include "types.h"
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * A ring node is a member of a doubly-linked circular list.
Packit Service d40955
 *
Packit Service d40955
 * Each node is usually embedded within a data structure that contains the
Packit Service d40955
 * relevant payload. In addition the ring head is also represented by a
Packit Service d40955
 * node where the next field designates the first element of the ring and the
Packit Service d40955
 * prev field designates the last.
Packit Service d40955
 *
Packit Service d40955
 * An empty ring contains next and prev fields that point back to the ring
Packit Service d40955
 * head itself.
Packit Service d40955
 *
Packit Service d40955
 * Typical iteration over a ring, from the front and back:
Packit Service d40955
 *
Packit Service d40955
 * for (RingNode *n = head->next; n != head; n = n->next) { ... }
Packit Service d40955
 * for (RingNode *p = head->prev; p != head; p = p->prev) { ... }
Packit Service d40955
 **/
Packit Service d40955
typedef struct ringNode RingNode;
Packit Service d40955
Packit Service d40955
struct ringNode {
Packit Service d40955
  RingNode *next;
Packit Service d40955
  RingNode *prev;
Packit Service d40955
};
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Initialize a ring to be empty.
Packit Service d40955
 *
Packit Service d40955
 * @param head The head of the ring
Packit Service d40955
 **/
Packit Service d40955
static inline void initializeRing(RingNode *head)
Packit Service d40955
{
Packit Service d40955
  head->next = head->prev = head;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Check whether a ring is empty.
Packit Service d40955
 *
Packit Service d40955
 * @param head The head of the ring
Packit Service d40955
 *
Packit Service d40955
 * @return true if the ring is empty
Packit Service d40955
 **/
Packit Service d40955
static inline bool isRingEmpty(const RingNode *head)
Packit Service d40955
{
Packit Service d40955
  return (head->next == head);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Check whether a ring contains exactly one node.
Packit Service d40955
 *
Packit Service d40955
 * @param head  The head of the ring
Packit Service d40955
 *
Packit Service d40955
 * @return true if the ring contains exactly one member
Packit Service d40955
 **/
Packit Service d40955
static inline bool isRingSingleton(const RingNode *head)
Packit Service d40955
{
Packit Service d40955
  return (!isRingEmpty(head) && (head->prev == head->next));
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Unsplice a contiguous chain of at least one node from its ring.
Packit Service d40955
 *
Packit Service d40955
 * @param first         the first entry in the ring to unsplice
Packit Service d40955
 * @param last          the last entry in the ring to unsplice,
Packit Service d40955
 *                      may be the same as ``first``
Packit Service d40955
 *
Packit Service d40955
 * The effect of this is to create two rings, the one designated
Packit Service d40955
 * by first through last, and the other consisting of anything remaining.
Packit Service d40955
 **/
Packit Service d40955
static inline void unspliceRingChain(RingNode *first,
Packit Service d40955
                                     RingNode *last)
Packit Service d40955
{
Packit Service d40955
  first->prev->next = last->next;
Packit Service d40955
  last->next->prev = first->prev;
Packit Service d40955
  first->prev = last;
Packit Service d40955
  last->next = first;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Remove a ring node from its ring.
Packit Service d40955
 *
Packit Service d40955
 * @param node  the ring node
Packit Service d40955
 *
Packit Service d40955
 * @return the removed node, for convenience
Packit Service d40955
 **/
Packit Service d40955
static inline RingNode *unspliceRingNode(RingNode *node)
Packit Service d40955
{
Packit Service d40955
  unspliceRingChain(node, node);
Packit Service d40955
  return node;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Splice a contiguous chain of at least one node after the specified entry,
Packit Service d40955
 * which may be the head of a ring.
Packit Service d40955
 *
Packit Service d40955
 * @param first         the first entry in a contiguous span of nodes
Packit Service d40955
 * @param last          the last entry in a contiguous span of nodes,
Packit Service d40955
 *                      may be the same as ``first``
Packit Service d40955
 * @param where         the entry after which ``first`` through ``last``
Packit Service d40955
 *                      shall appear
Packit Service d40955
 *
Packit Service d40955
 * The effect of this is to unsplice first through last (if necessary) and
Packit Service d40955
 * insert them after ``where`` so that the previous nodes after ``where``
Packit Service d40955
 * now appear after ``last``.
Packit Service d40955
 **/
Packit Service d40955
static inline void spliceRingChainAfter(RingNode *first,
Packit Service d40955
                                        RingNode *last,
Packit Service d40955
                                        RingNode *where)
Packit Service d40955
{
Packit Service d40955
  if (last->next != first) {
Packit Service d40955
    unspliceRingChain(first, last);
Packit Service d40955
  }
Packit Service d40955
  last->next = where->next;
Packit Service d40955
  first->prev = where;
Packit Service d40955
  where->next->prev = last;
Packit Service d40955
  where->next = first;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Splice a contiguous chain of at least one node before the specified entry,
Packit Service d40955
 * which may be the tail of a list.
Packit Service d40955
 *
Packit Service d40955
 * @param first         the first entry in a contiguous span of nodes
Packit Service d40955
 * @param last          the last entry in a contiguous span of nodes,
Packit Service d40955
 *                      may be the same as ``first``
Packit Service d40955
 * @param where         the entry before which ``first`` through ``last``
Packit Service d40955
 *                      shall appear
Packit Service d40955
 *
Packit Service d40955
 * The effect of this is to unsplice first through last (if necessary) and
Packit Service d40955
 * insert them before ``where`` so that the previous nodes before ``where``
Packit Service d40955
 * now appear before ``first``.
Packit Service d40955
 **/
Packit Service d40955
static inline void spliceRingChainBefore(RingNode *first,
Packit Service d40955
                                         RingNode *last,
Packit Service d40955
                                         RingNode *where)
Packit Service d40955
{
Packit Service d40955
  if (last->next != first) {
Packit Service d40955
    unspliceRingChain(first, last);
Packit Service d40955
  }
Packit Service d40955
  first->prev = where->prev;
Packit Service d40955
  last->next = where;
Packit Service d40955
  where->prev->next = first;
Packit Service d40955
  where->prev = last;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Push a single node on the end of a ring.
Packit Service d40955
 *
Packit Service d40955
 * @param head The ring head
Packit Service d40955
 * @param node The node to push
Packit Service d40955
 **/
Packit Service d40955
static inline void pushRingNode(RingNode *head, RingNode *node)
Packit Service d40955
{
Packit Service d40955
  spliceRingChainBefore(node, node, head);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Pop a single node off the end of a ring.
Packit Service d40955
 *
Packit Service d40955
 * @param head  The ring head
Packit Service d40955
 *
Packit Service d40955
 * @return NULL if the ring was empty, otherwise the node that was
Packit Service d40955
 *         removed from the ring (``head->prev``)
Packit Service d40955
 **/
Packit Service d40955
static inline RingNode *popRingNode(RingNode *head)
Packit Service d40955
{
Packit Service d40955
  return (isRingEmpty(head) ? NULL : unspliceRingNode(head->prev));
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Remove a single node off the front of the list
Packit Service d40955
 **/
Packit Service d40955
static inline RingNode *chopRingNode(RingNode *head)
Packit Service d40955
{
Packit Service d40955
  return (isRingEmpty(head) ? NULL : unspliceRingNode(head->next));
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
#endif // RING_NODE_H