/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- client_time_heap.c for the Openbox window manager Copyright (c) 2006 Mikael Magnusson Copyright (c) 2003-2007 Dana Jansens 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. See the COPYING file for a copy of the GNU General Public License. */ #include "client_time_heap.h" #include "client.h" #include /* Helper functions for the heap */ #define isroot(n) (n == 0) #define parent(n) ((n-1)/2) #define right(n) ((n+1)*2) #define left(n) (right(n)-1) #define exists(n) (n < h->nodes->len) #define key(n) (((ObClient*)h->nodes->pdata[n])->user_time) static inline void swap(ObClientTimeHeap *h, guint a, guint b) { gpointer c; g_assert(a < h->nodes->len); g_assert(b < h->nodes->len); c = h->nodes->pdata[a]; h->nodes->pdata[a] = h->nodes->pdata[b]; h->nodes->pdata[b] = c; } static inline void heapify(ObClientTimeHeap *h, guint n) { g_assert(exists(n)); /* fix up the heap, move it down below keys it's smaller than */ while ((exists(left(n)) && key(n) < key(left(n))) || (exists(right(n)) && key(n) < key(right(n)))) { if (exists(left(n)) && exists(right(n))) if (key(left(n)) > key(right(n))) { swap(h, n, left(n)); n = left(n); } else { swap(h, n, right(n)); n = right(n); } else { /* its impossible in this structure to have a right child but no left child */ swap(h, n, left(n)); n = left(n); } } } ObClientTimeHeap* client_time_heap_new() { ObClientTimeHeap *h = g_new0(ObClientTimeHeap, 1); h->nodes = g_ptr_array_new(); return h; } void client_time_heap_free(ObClientTimeHeap *h) { if (h != NULL) { /* all the clients should be removed before the heap is destroyed. */ g_assert(h->nodes->len == 0); g_ptr_array_free(h->nodes, TRUE); g_free(h); } } guint32 client_time_heap_maximum(ObClientTimeHeap *h) { if (h->nodes->len == 0) return CurrentTime; else return key(0); } void client_time_heap_add(ObClientTimeHeap *h, ObClient *c) { guint n; /* insert it as the last leaf */ g_ptr_array_add(h->nodes, c); n = h->nodes->len - 1; /* move it up to its proper place */ while (!isroot(n) && key(n) > key(parent(n))) { swap(h, n, parent(n)); n = parent(n); } } void client_time_heap_remove(ObClientTimeHeap *h, ObClient *c) { /* find the client */ guint n; for (n = 0; h->nodes->pdata[n] != c && n < h->nodes->len; ++n); /* if the client is in the heap */ if (n < h->nodes->len) { /* move it to a leaf and delete it from the heap */ swap(h, n, h->nodes->len-1); g_ptr_array_remove_index(h->nodes, h->nodes->len-1); /* move the swapped leaf down to its proper place if it wasn't just deleted */ if (exists(n)) heapify(h, n); } } void client_time_heap_decrease_key(ObClientTimeHeap *h, ObClient *c) { /* find the client */ guint n; for (n = 0; h->nodes->pdata[n] != c && n < h->nodes->len; ++n); /* if the client is in the heap */ if (n < h->nodes->len) { /* move it down to its proper place */ heapify(h, n); } } void client_time_heap_increase_key(ObClientTimeHeap *h, ObClient *c) { /* find the client */ guint n; for (n = 0; h->nodes->pdata[n] != c && n < h->nodes->len; ++n); /* if the client is in the heap */ if (n < h->nodes->len) { /* move it up to its proper place */ while (!isroot(n) && key(n) > key(parent(n))) { swap(h, n, parent(n)); n = parent(n); } } }