diff --git a/sc2/src/sc2code/libs/callback/Makeinfo b/sc2/src/sc2code/libs/callback/Makeinfo new file mode 100644 index 000000000..a09ceaae6 --- /dev/null +++ b/sc2/src/sc2code/libs/callback/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="alarm.c callback.c" + diff --git a/sc2/src/sc2code/libs/callback/alarm.c b/sc2/src/sc2code/libs/callback/alarm.c new file mode 100644 index 000000000..d92ce23ec --- /dev/null +++ b/sc2/src/sc2code/libs/callback/alarm.c @@ -0,0 +1,134 @@ +/* + * Copyright 2006 Serge van den Boom + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "alarm.h" + +#include "libs/heap.h" + +#include +#include + + +Heap *alarmHeap; + + +static inline Alarm * +Alarm_alloc(void) { + return malloc(sizeof (Alarm)); +} + +static inline void +Alarm_free(Alarm *alarm) { + free(alarm); +} + +static inline int +AlarmTime_compare(const AlarmTime t1, const AlarmTime t2) { + if (t1 < t2) + return -1; + if (t2 > t2) + return 1; + return 0; +} + +static int +Alarm_compare(const Alarm *a1, const Alarm *a2) { + return AlarmTime_compare(a1->time, a2->time); +} + +void +Alarm_init(void) { + assert(alarmHeap == NULL); + alarmHeap = Heap_new((HeapValue_Comparator) Alarm_compare, + 4, 4, 0.8); +} + +void +Alarm_uninit(void) { + assert(alarmHeap != NULL); + + while (Heap_hasMore(alarmHeap)) { + Alarm *alarm = (Alarm *) Heap_pop(alarmHeap); + Alarm_free(alarm); + } + Heap_delete(alarmHeap); + alarmHeap = NULL; +} + +static inline AlarmTime +AlarmTime_nowMS(void) { + return SDL_GetTicks(); +} + +Alarm * +Alarm_addRelativeMs(Uint32 ms, AlarmCallback callback, + AlarmCallbackArg arg) { + Alarm *alarm; + + assert(alarmHeap != NULL); + + alarm = Alarm_alloc(); + alarm->time = AlarmTime_nowMS() + ms; + alarm->callback = callback; + alarm->arg = arg; + + Heap_add(alarmHeap, (HeapValue *) alarm); + + return alarm; +} + +void +Alarm_remove(Alarm *alarm) { + assert(alarmHeap != NULL); + Heap_remove(alarmHeap, (HeapValue *) alarm); + Alarm_free(alarm); +} + +// It is safe to call this function again from inside a callback function +// that it called. It should not be called from multiple threads at once. +void +Alarm_process(void) { + AlarmTime now; + + assert(alarmHeap != NULL); + + now = AlarmTime_nowMS(); + while (Heap_hasMore(alarmHeap)) { + Alarm *alarm = (Alarm *) Heap_first(alarmHeap); + + if (now < alarm->time) + break; + + Heap_pop(alarmHeap); + alarm->callback(alarm->arg); + Alarm_free(alarm); + } +} + +Uint32 +Alarm_timeBeforeNextMs(void) { + Alarm *alarm; + + if (!Heap_hasMore(alarmHeap)) + return UINT32_MAX; + + alarm = (Alarm *) Heap_first(alarmHeap); + return alarmTimeToMsUint32(alarm->time); +} + + diff --git a/sc2/src/sc2code/libs/callback/alarm.h b/sc2/src/sc2code/libs/callback/alarm.h new file mode 100644 index 000000000..8fcef79e4 --- /dev/null +++ b/sc2/src/sc2code/libs/callback/alarm.h @@ -0,0 +1,54 @@ +/* + * Copyright 2006 Serge van den Boom + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ALARM_H +#define _ALARM_H + +#include "port.h" +#include "types.h" + +#include SDL_INCLUDE(SDL.h) +typedef Uint32 AlarmTime; +static inline Uint32 +alarmTimeToMsUint32(AlarmTime time) { + return (Uint32) time; +} + +typedef struct Alarm Alarm; +typedef void *AlarmCallbackArg; +typedef void (*AlarmCallback)(AlarmCallbackArg *arg); + +struct Alarm { + size_t index; + // For the HeapValue 'base struct'. + + AlarmTime time; + AlarmCallback callback; + AlarmCallbackArg arg; +}; + +void Alarm_init(void); +void Alarm_uninit(void); +Alarm *Alarm_addRelativeMs(Uint32 ms, AlarmCallback callback, + AlarmCallbackArg arg); +void Alarm_remove(Alarm *alarm); +void Alarm_process(void); +Uint32 Alarm_timeBeforeNextMs(void); + +#endif /* _ALARM_H */ + diff --git a/sc2/src/sc2code/libs/callback/callback.c b/sc2/src/sc2code/libs/callback/callback.c new file mode 100644 index 000000000..41a15b95e --- /dev/null +++ b/sc2/src/sc2code/libs/callback/callback.c @@ -0,0 +1,162 @@ +/* + * Copyright 2006 Serge van den Boom + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +//#include +#include "types.h" +#include + +typedef struct CallbackLink CallbackLink; + +#define CALLBACK_INTERNAL +#include "callback.h" + +struct CallbackLink { + CallbackLink *next; + CallbackFunction callback; + CallbackArg arg; +}; + +static CallbackLink *callbacks; +static CallbackLink *oldCallbacks; + // callback list currently being processed +static CallbackLink **callbacksEnd; + +static inline void +CallbackList_lock(void) { + // TODO + // Necessary for reentrant operation +} + +static inline void +CallbackList_unlock(void) { + // TODO + // Necessary for reentrant operation +} + +#if 0 +static inline bool +CallbackList_isLocked(void) { + // TODO +} +#endif + +void +Callback_init(void) { + callbacks = NULL; + callbacksEnd = &callbacks; +} + +// Callbacks are guaranteed to be called in the order that they are queued. +CallbackID +Callback_add(CallbackFunction callback, CallbackArg arg) { + CallbackLink *link = malloc(sizeof (CallbackLink)); + link->callback = callback; + link->arg = arg; + link->next = NULL; + + CallbackList_lock(); + *callbacksEnd = link; + callbacksEnd = &link->next; + CallbackList_unlock(); + return (CallbackID) link; +} + + +// Pre: CallbackList is locked. +static void +CallbackLink_unlink(CallbackLink **linkPtr) { + *linkPtr = (*linkPtr)->next; +} + +static void +CallbackLink_delete(CallbackLink *link) { + free(link); +} + +// Pre: CallbackList is locked. +static CallbackLink ** +CallbackLink_find(CallbackLink *link) { + CallbackLink **ptr; + + //assert(CallbackList_isLocked()); + for (ptr = &callbacks; *ptr != NULL; ptr = &(*ptr)->next) { + if (*ptr == link) + return ptr; + } + return NULL; +} + +bool +Callback_removeCallback(CallbackID id) { + CallbackLink *link = (CallbackLink *) id; + CallbackLink **linkPtr; + + CallbackList_lock(); + + linkPtr = CallbackLink_find(link); + if (linkPtr == NULL) { + CallbackList_unlock(); + return false; + } + + CallbackLink_unlink(linkPtr); + CallbackLink_delete(link); + + CallbackList_unlock(); + return true; +} + +static inline void +CallbackLink_doCallback(CallbackLink *link) { + (link->callback)(link->arg); +} + +// Call all queued callbacks currently in the queue. Callbacks queued +// from inside the called functions will not be processed until the next +// call of Callback_process(). +// It is not allowed to remove callbacks from inside the called functions. +// NB: Callback_process() must never be called from more than one thread +// at the same time. It's the only sensible way to ensure that the +// callbacks are called in the order in which they were queued. +// It is however allowed to call Callback_process() from inside the +// callback function called by Callback_process() itself. +void +Callback_process(void) { + CallbackLink *link; + + // Create a new queue so that the old queue can be processed + // at once, without additional locking. + CallbackList_lock(); + oldCallbacks = callbacks; + callbacks = NULL; + callbacksEnd = &callbacks; + CallbackList_unlock(); + + for (;;) { + link = oldCallbacks; + if (link == NULL) + break; + oldCallbacks = link->next; + + CallbackLink_doCallback(link); + CallbackLink_delete(link); + } +} + + diff --git a/sc2/src/sc2code/libs/callback/callback.h b/sc2/src/sc2code/libs/callback/callback.h new file mode 100644 index 000000000..0ced485eb --- /dev/null +++ b/sc2/src/sc2code/libs/callback/callback.h @@ -0,0 +1,41 @@ +/* + * Copyright 2006 Serge van den Boom + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CALLBACK_H +#define _CALLBACK_H + +#include "types.h" + +#ifdef CALLBACK_INTERNAL +typedef CallbackLink *CallbackID; +#else +typedef void *CallbackID; + // Uniquely identifies a queued callback. +#endif +#define CallbackID_invalid ((CallbackID ) NULL) + +typedef void *CallbackArg; +typedef void (*CallbackFunction)(CallbackArg arg); + +void Callback_init(void); +CallbackID Callback_add(CallbackFunction callback, CallbackArg arg); +bool Callback_removeCallback(CallbackID id); +void Callback_process(void); + +#endif /* _CALLBACK_H */ + diff --git a/sc2/src/sc2code/libs/heap/Makeinfo b/sc2/src/sc2code/libs/heap/Makeinfo new file mode 100644 index 000000000..8d58a7aa8 --- /dev/null +++ b/sc2/src/sc2code/libs/heap/Makeinfo @@ -0,0 +1,2 @@ +uqm_CFILES="heap.c" + diff --git a/sc2/src/sc2code/libs/heap/heap.c b/sc2/src/sc2code/libs/heap/heap.c new file mode 100644 index 000000000..1dfe96932 --- /dev/null +++ b/sc2/src/sc2code/libs/heap/heap.c @@ -0,0 +1,192 @@ +/* + * Copyright 2006 Serge van den Boom + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "heap.h" + +#include +#include +#include + + +static inline size_t nextPower2(size_t x); + + +static void +Heap_resize(Heap *heap, size_t size) { + heap->entries = realloc(heap->entries, size * sizeof (HeapValue *)); + heap->size = size; +} + +Heap * +Heap_new(HeapValue_Comparator comparator, size_t initialSize, size_t minSize, + double minFillQuotient) { + Heap *heap; + + assert(minFillQuotient >= 0.0); + + heap = malloc(sizeof (Heap)); + + if (initialSize < minSize) + initialSize = minSize; + + heap->comparator = comparator; + heap->minFillQuotient = minFillQuotient; + heap->size = nextPower2(initialSize); + heap->minFill = (size_t) ceil(((double) (heap->size >> 1)) + * heap->minFillQuotient); + heap->entries = malloc(heap->size * sizeof (HeapValue *)); + heap->numEntries = 0; + + return heap; +} + +void +Heap_delete(Heap *heap) { + free(heap->entries); + free(heap); +} + +void +Heap_add(Heap *heap, HeapValue *value) { + size_t i; + + if (heap->numEntries >= heap->size) + Heap_resize(heap, heap->size * 2); + + i = heap->numEntries; + heap->numEntries++; + + while (i > 0) { + size_t parentI = (i - 1) / 2; + if (heap->comparator(heap->entries[i], heap->entries[parentI]) <= 0) + break; + + heap->entries[i] = heap->entries[parentI]; + heap->entries[i]->index = i; + i = parentI; + } + heap->entries[i] = value; + heap->entries[i]->index = i; +} + +HeapValue * +Heap_first(const Heap *heap) { + assert(heap->numEntries > 0); + + return heap->entries[0]; +} + +static inline void +swapEntries(Heap *heap, size_t i0, size_t i1) { + HeapValue *temp = heap->entries[i0]; + heap->entries[i0] = heap->entries[i1]; + heap->entries[i0]->index = i0; + heap->entries[i1] = temp; + heap->entries[i1]->index = i1; +} + +static void +Heap_removeByIndex(Heap *heap, size_t i) { + assert(heap->numEntries > i); + + heap->numEntries--; + + if (heap->numEntries != 0) { + heap->entries[i] = heap->entries[heap->numEntries]; + heap->entries[i]->index = i; + + // Restore the heap invariant: + for (;;) { + size_t leftI = i * 2 + 1; + size_t rightI = leftI + 1; + size_t newI; + + if (rightI < heap->numEntries) { + // rightI is unused. + if (leftI < heap->numEntries) + break; + // leftI is used, rightI is unused. + if (heap->comparator(heap->entries[i], + heap->entries[leftI]) < 0) + swapEntries(heap, i, leftI); + break; + } + + newI = (heap->comparator(heap->entries[leftI], + heap->entries[rightI]) >= 0) ? leftI : rightI; + + if (heap->comparator(heap->entries[i], heap->entries[newI]) >= 0) + break; + + swapEntries(heap, i, newI); + i = newI; + } + } + + // Resize if necessary: + if (heap->numEntries < heap->minFill && + heap->numEntries > heap->minSize) + Heap_resize(heap, heap->size / 2); +} + +HeapValue * +Heap_pop(Heap *heap) { + HeapValue *result; + + assert(heap->numEntries > 0); + + result = heap->entries[0]; + Heap_removeByIndex(heap, 0); + + return result; +} + +size_t +Heap_count(const Heap *heap) { + return heap->numEntries; +} + +bool +Heap_hasMore(const Heap *heap) { + return heap->numEntries > 0; +} + +void +Heap_remove(Heap *heap, HeapValue *value) { + Heap_removeByIndex(heap, value->index); +} + +// Adapted from "Hackers Delight" +// Returns the smallest power of two greater or equal to x. +static inline size_t +nextPower2(size_t x) { + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; +# if (SIZE_MAX > 0xffff) + x |= x >> 16; +# if (SIZE_MAX > 0xffffffff) + x |= x >> 32; +# endif +# endif + return x + 1; +} + + diff --git a/sc2/src/sc2code/libs/heap/heap.h b/sc2/src/sc2code/libs/heap/heap.h new file mode 100644 index 000000000..2e46fb875 --- /dev/null +++ b/sc2/src/sc2code/libs/heap/heap.h @@ -0,0 +1,67 @@ +/* + * Copyright 2006 Serge van den Boom + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _HEAP_H +#define _HEAP_H + +#include "types.h" + +#include + +typedef struct Heap Heap; +typedef struct HeapValue HeapValue; + +// The actual value stored should "inherit" from this. +struct HeapValue { + size_t index; +}; +typedef int (*HeapValue_Comparator)(HeapValue *v1, HeapValue *v2); + + +struct Heap { + HeapValue_Comparator comparator; + // Comparison function to determine the order of the + // elements. + size_t minSize; + // Never resize below this many number of entries. + double minFillQuotient; + // How much of half of the heap needs to be filled before + // resizing to size/2. + + HeapValue **entries; + // Actual values + size_t numEntries; + size_t size; + // Number of entries that fit in the heap as it is now. + size_t minFill; + // Resize to size/2 when below this size. +}; + + +Heap *Heap_new(HeapValue_Comparator comparator, size_t initialSize, + size_t minSize, double minFillQuotient); +void Heap_delete(Heap *heap); +void Heap_add(Heap *heap, HeapValue *value); +HeapValue *Heap_first(const Heap *heap); +HeapValue *Heap_pop(Heap *heap); +size_t Heap_count(const Heap *heap); +bool Heap_hasMore(const Heap *heap); +void Heap_remove(Heap *heap, HeapValue *value); + +#endif /* _HEAP_H */ +