-
Notifications
You must be signed in to change notification settings - Fork 0
/
dring.c
153 lines (135 loc) · 3.58 KB
/
dring.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
* dring.c
*
* @autors Stefan Tombers, Alexander Bunte, Jonas Bürse
*
* Implementation of a double ring.
*
* It is used for cyclic sequence numbers whereas the number of different sequence
* numbers should be at least twice as large as the window size.
*
* The double ring stores data in two sorted queues. The first queue always
* contains the "smaller" elements of the two queues. Elements are added to
* the second queue if they are "larger" than elements of the first queue.
* This is the case if they are numerically smaller AND the difference to the
* largest element of the first queue is larger than the window size.
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "squeue.h"
#include "dring.h"
/**
* Data structure for the double ring.
*/
typedef struct _DRING
{
SQUEUE s; // queue with the "smaller" elements
SQUEUE l; // queue with the "larger" elements
int windowSize; // size of the window
int maxFirstRing; // greatest element in s
} _DRING;
/**
* Creates a new double ring of size <code>windowSize</code>.
*
* @param windowSize Size of the window.
* @return returns the created ring.
*/
DRING dring_new(int windowSize)
{
_DRING *dring = malloc(sizeof(*dring));
dring->s = squeue_new();
dring->l = squeue_new();
dring->windowSize = windowSize;
dring->maxFirstRing = -1;
return (DRING)dring;
}
/**
* Frees all resources allocated for the given double ring.
*
* @param d Handle of double ring to destroy.
*/
void dring_free(DRING d)
{
_DRING *dring = (_DRING *)d;
squeue_free(dring->s);
squeue_free(dring->l);
free(dring);
}
/**
* Insert an element in the double ring.
* The data is inserted in the ring with the smallest distance to the existing data.
* This ensures that data are handled correctly.
*
* @param d Handle of the double ring.
* @param data The Data to be added to the ring.
*/
void dring_insert(DRING d, int data)
{
_DRING *dring = (_DRING *)d;
if(dring->maxFirstRing == -1 || data > dring->maxFirstRing ||
abs(data - dring->maxFirstRing) < dring->windowSize) {
squeue_insert(dring->s, data);
dring->maxFirstRing = squeue_peek_tail(dring->s);
}
else {
squeue_insert(dring->l, data);
}
}
/**
* Returns (but keeps) the "smallest" value of the double ring.
* Returns -1 if double ring is empty.
* @param d Double ring.
* @return "Smallest" value of the given double ring or -1 if it is empty.
*/
int dring_peek(DRING d)
{
_DRING *dring = (_DRING *)d;
if(squeue_nitems(dring->s) > 0) {
return squeue_peek(dring->s);
}
else if (squeue_nitems(dring->l)) {
return squeue_peek(dring->l);
} else {
/* dring empty */
assert(squeue_nitems(dring->l) == 0);
return -1;
}
}
/**
* Returns the "smallest" element from the double ring.
*
* @param d Handle of the double ring.
* @return The "smallest" element of the double ring.
*/
int dring_pop(DRING d)
{
_DRING *dring = (_DRING *)d;
if(squeue_nitems(dring->s) > 0) {
return squeue_pop(dring->s);
}
else if (squeue_nitems(dring->l)) {
/* dring has become empty -> switch rings */
SQUEUE *tmp = dring->l;
dring->l = dring->s;
dring->s = tmp;
dring->maxFirstRing = squeue_peek_tail(dring->s);
return squeue_pop(dring->s);
} else {
/* dring empty */
assert(squeue_nitems(dring->l) == 0);
return -1;
}
}
/**
* Returns the number of elements of the double ring.
* This is the total number of elements of both rings.
*
* @param d Handle of the double ring.
* @return Number of elements of the double ring.
*/
int dring_nitems(DRING d)
{
_DRING *dring = (_DRING *)d;
return squeue_nitems(dring->s) + squeue_nitems(dring->l);
}