Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
BC
public
external
sofia-sip
Commits
d756db75
Commit
d756db75
authored
Jul 04, 2007
by
Pekka Pessi
Browse files
sofia-sip/heap.h: made heap type private. updated interface.
darcs-hash:20070704094233-65a35-fcf28389f363e82f0cf5816f96ec294b0906405d.gz
parent
499ef29d
Changes
2
Hide whitespace changes
Inline
Side-by-side
libsofia-sip-ua/su/sofia-sip/heap.h
View file @
d756db75
...
...
@@ -28,19 +28,20 @@
/**@file sofia-sip/heap.h
*
* Heap implemented with dynamic array.
* Heap
template
implemented with dynamic array.
*
* This file contain template macros implementing heap in C. The @a heap
* This file contain template macros implementing
@a
heap in C. The @a heap
* keeps its element in a known order and it can be used to implement, for
* example, a prioritye queue or an ordered queue.
*
* The ordering within the heap is defined as follows:
* - indexing starts from 1
* - for each element with index @a [i] in the heap there are two descendant
* elements with indices @a [2*i
+1
] and @a [2*i+
2
],
* elements with indices @a [2*i] and @a [2*i+
1
],
* - the heap guarantees that the descendant elements are never smaller than
* their parent element.
* There is no element smaller than element at
index [0] in the
* rest of the heap.
* There
fore it follows that there
is no element smaller than element at
*
index [1] in the
rest of the heap.
*
* Adding and removing elements to the heap is an @a O(logN)
* operation.
...
...
@@ -52,10 +53,11 @@
* to be removed. The template defines also a predicate used to check if the
* heap is full, and a function used to resize the heap.
*
* The heap user must define
three
primitives:
* The heap user must define
four
primitives:
* - less than comparison
* - array setter
* - heap array allocator
* - empty element
*
* Please note that in order to remove an entry in the heap, the application
* must know its index in the heap array.
...
...
@@ -76,65 +78,65 @@
/** Declare heap structure type.
*
* The macro HEAP_DECLARE() expands to the declaration of the heap
* structure. The field names start with @a pr. The type of heap array
* element is @a entrytype.
*
* @param sname name of struct
* @param pr heap type prefix
* @param entrytype entry type
* The macro #HEAP_TYPE contains declaration of the heap structure.
*
* @showinitializer
*/
#define HEAP_DECLARE(sname, pr, entrytype) \
struct sname { \
size_t pr##size;
/**< Number of elements in pr##heap */
\
size_t pr##used;
/**< Number of elements used from pr##heap */
\
entrytype *pr##heap;
/**< Array of entries in the heap */
\
}
#define HEAP_TYPE struct { void *private; }
/** Prototypes for heap.
*
* The macro HEAP_PROTOS() expands to the prototypes of heap functions:
* - prefix ## resize(argument, heap, size)
* - prefix ## resize(argument, in_out_heap, size)
* - prefix ## free(argument, in_heap)
* - prefix ## is_full(heap)
* - prefix ## size(heap)
* - prefix ## used(heap)
* - prefix ## add(heap, entry)
* - prefix ## remove(heap, index)
* - prefix ## get(heap, index)
*
* @param scope scope of functions
* @param
type
heap
type
or
type
def
* @param heaptype type
of heap
* @param prefix function prefix
* @param
entry
type entr
y type
* @param
type
type
of
entr
ies
*
* The declared functions will have scope @a scope (for example, @c static
* or @c static inline). The declared function names will have prefix @a
* prefix. The heap structure has type @a type. The heap element type is
@a
* entrytype.
* prefix. The heap structure has type @a
heap
type. The heap element type is
*
@a
entrytype.
*
* @showinitializer
*/
#define HEAP_PROTOS(scope, type, prefix, entrytype) \
scope int prefix##resize(void *argument, type heap[1], size_t size); \
scope int prefix##is_full(type const *heap); \
scope int prefix##add(type *heap, entrytype entry); \
scope int prefix##remove(type *heap, size_t index)
#define HEAP_DECLARE(scope, heaptype, prefix, type) \
scope int prefix##resize(void *, heaptype *, size_t); \
scope int prefix##free(void *, heaptype *); \
scope int prefix##is_full(heaptype const); \
scope size_t prefix##size(heaptype const); \
scope size_t prefix##used(heaptype const); \
scope int prefix##add(heaptype, type); \
scope type prefix##remove(heaptype, size_t); \
scope type prefix##get(heaptype, size_t)
/**Heap implementation.
*
* The macro HEAP_BODIES() expands to the bodies of heap functions:
* - prefix ## resize(argument, heap, size)
* - prefix ## free(argument, in_heap)
* - prefix ## is_full(heap)
* - prefix ## size(heap)
* - prefix ## used(heap)
* - prefix ## add(heap, entry)
* - prefix ## remove(heap, index)
* - prefix ## get(heap, index)
*
* @param scope scope of functions
* @param type hash table type
* @param prefix function prefix for heap
* @param pr field prefix for heap structure
* @param entrytype type of element
* @param type type of heaped elements
* @param less function or macro comparing two entries
* @param set function or macro assigning entry to array
* @param halloc function allocating or freeing memory
* @param alloc function allocating or freeing memory
* @param null empty element (returned when index is invalid)
*
* Functions have scope @a scope, e.g., @c static @c inline.
* The heap structure has type @a type.
...
...
@@ -154,85 +156,108 @@ scope int prefix##remove(type *heap, size_t index)
* resize(), second the pointer to existing heap and third is the number of
* bytes in the heap.
*/
#define HEAP_BODIES(scope, type, prefix, pr, entrytype, less, set, alloc) \
/** Resize heap. */
\
scope int prefix##resize(void *realloc_arg, \
type pr[1], \
size_t new_size) \
#define HEAP_BODIES(scope, heaptype, prefix, type, less, set, alloc, null) \
scope int prefix##resize(void *realloc_arg, heaptype h[1], size_t new_size) \
{ \
entrytype *heap; \
size_t bytes; \
\
(void)realloc_arg; \
\
if (new_size == 0) \
new_size = 2 * pr->pr##size + 1; \
if (new_size < HEAP_MIN_SIZE) \
new_size = HEAP_MIN_SIZE; \
\
bytes = new_size * (sizeof heap[0]); \
\
heap = alloc(realloc_arg, pr->pr##heap, bytes); \
if (!heap) \
struct prefix##priv { size_t _size, _used; type _heap[2]; }; \
struct prefix##priv *_priv; \
size_t _offset = \
(offsetof(struct prefix##priv, _heap[1]) - 1) / sizeof (type); \
size_t _min_size = 32 - _offset; \
size_t _bytes; \
size_t _used = 0; \
\
_priv = *(void **)h; \
\
if (_priv) { \
if (new_size == 0) \
new_size = 2 * _priv->_size + _offset + 1; \
_used = _priv->_used; \
if (new_size < _used) \
new_size = _used; \
} \
\
if (new_size < _min_size) \
new_size = _min_size; \
\
_bytes = (_offset + 1 + new_size) * sizeof (type); \
\
(void)realloc_arg;
/* avoid warning */
\
_priv = alloc(realloc_arg, *(struct prefix##priv **)h, _bytes); \
if (!_priv) \
return -1; \
\
pr->pr##size = new_size; \
if (pr->pr##used > new_size) \
pr->pr##used = new_size; \
pr->pr##heap = heap; \
\
\
*(struct prefix##priv **)h = _priv; \
_priv->_size = new_size; \
_priv->_used = _used; \
\
return 0; \
} \
\
\
/** Free heap. */
\
scope int prefix##free(void *realloc_arg, heaptype h[1]) \
{ \
(void)realloc_arg; \
*(void **)h = alloc(realloc_arg, *(void **)h, 0); \
return 0; \
} \
\
/** Check if heap is full */
\
scope \
int prefix##is_full(type const *pr) \
scope int prefix##is_full(heaptype h) \
{ \
return pr->pr##heap == NULL || pr->pr##used >= pr->pr##size; \
struct prefix##priv { size_t _size, _used; type _heap[1];}; \
struct prefix##priv *_priv = *(void **)&h; \
\
return _priv == NULL || _priv->_used >= _priv->_size; \
} \
\
\
/** Add an element to the heap */
\
scope \
int prefix##add(type *pr, entrytype e) \
scope int prefix##add(heaptype h, type e) \
{ \
struct prefix##priv { size_t _size, _used; type _heap[1];}; \
struct prefix##priv *_priv = *(void **)&h; \
type *heap = _priv->_heap - 1; \
size_t i, parent; \
entrytype *heap = pr->pr##heap; \
\
if (pr->pr##used >= pr->pr##size) \
\
if (_priv == NULL || _priv->_used >= _priv->_size) \
return -1; \
\
for (i =
pr->pr##
used
++
; i >
0
; i = parent) { \
parent =
(i - 1)
/ 2; \
\
for (i =
++_priv->_
used; i >
1
; i = parent) { \
parent =
i
/ 2; \
if (!less(e, heap[parent])) \
break; \
set(heap, i, heap[parent]); \
} \
\
\
set(heap, i, e); \
\
\
return 0; \
} \
\
\
/** Remove element from heap */
\
scope \
int prefix##remove(type *pr, size_t index) \
scope type prefix##remove(heaptype h, size_t index) \
{ \
entrytype *heap = pr->pr##heap; \
entrytype e; \
size_t top, left, right; \
size_t used = pr->pr##used; \
\
if (index >= used) \
return -1; \
\
pr->pr##used = --used; \
top = index; \
\
struct prefix##priv { size_t _size, _used; type _heap[1];}; \
struct prefix##priv *_priv = *(void **)&h; \
type *heap = _priv->_heap - 1; \
type retval; \
type e; \
\
size_t top, left, right, move; \
\
move = _priv->_used; \
\
if (index - 1 >= _priv->_used) \
return (null); \
\
move = _priv->_used--; \
retval = heap[top = index]; \
\
for (;;) { \
left = 2 * top
+ 1
; \
right = 2 * top +
2
; \
\
if (right >=
used
) \
left = 2 * top; \
right = 2 * top +
1
; \
\
if (right >=
move
) \
break; \
if (less(heap[right], heap[left])) \
top = right; \
...
...
@@ -241,21 +266,49 @@ int prefix##remove(type *pr, size_t index) \
set(heap, index, heap[top]); \
index = top; \
} \
\
if (index ==
used
) \
return
0
; \
\
e = heap[
used
]; \
for (; index >
0
; index = top) { \
top =
(
index
- 1)
/ 2; \
\
if (index ==
move
) \
return
retval
; \
\
e = heap[
move
]; \
for (; index >
1
; index = top) { \
top = index / 2; \
if (!less(e, heap[top])) \
break; \
set(heap, index, heap[top]); \
} \
\
\
set(heap, index, e); \
\
return 0; \
\
return retval; \
} \
\
scope \
type prefix##get(heaptype h, size_t index) \
{ \
struct prefix##priv { size_t _size, _used; type _heap[1];}; \
struct prefix##priv *_priv = *(void **)&h; \
\
if (--index >= _priv->_used) \
return (null); \
\
return _priv->_heap[index]; \
} \
\
scope \
size_t prefix##size(heaptype const h) \
{ \
struct prefix##priv { size_t _size, _used; type _heap[1];}; \
struct prefix##priv *_priv = *(void **)&h; \
return _priv ? _priv->_size : 0; \
} \
\
scope \
size_t prefix##used(heaptype const h) \
{ \
struct prefix##priv { size_t _size, _used; type _heap[1];}; \
struct prefix##priv *_priv = *(void **)&h; \
return _priv ? _priv->_used : 0; \
} \
extern int const prefix##dummy_heap
...
...
libsofia-sip-ua/su/torture_heap.c
View file @
d756db75
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2007 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
/**
* @file torture_heap.c
* @brief Test heap
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*/
#include "config.h"
#include <sofia-sip/heap.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
...
...
@@ -11,33 +44,55 @@
typedef
struct
{
unsigned
key
,
value
;
size_t
index
;
}
entry
type
;
}
type1
,
*
type
2
;
#include <sofia-sip/heap.h>
static
type1
const
null
=
{
0
,
0
,
0
};
typedef
struct
Heap
Heap
;
static
inline
int
less1
(
type1
a
,
type1
b
)
{
return
a
.
key
<
b
.
key
;
}
HEAP_DECLARE
(
Heap
,
pr_
,
entrytype
);
static
inline
void
set1
(
type1
*
heap
,
size_t
index
,
type1
e
)
{
assert
(
index
>
0
);
e
.
index
=
index
;
heap
[
index
]
=
e
;
}
HEAP_PROTOS
(
static
inline
,
Heap
,
heapXX_
,
entrytyp
e
)
;
#define alloc(a, o, size) realloc((o), (siz
e)
)
static
inline
int
less
_than
(
entry
type
a
,
entry
type
b
)
int
less
2
(
type
2
a
,
type
2
b
)
{
return
a
.
key
<
b
.
key
;
return
a
->
key
<
b
->
key
;
}
static
inline
void
set
_entry
(
entry
type
*
heap
,
size_t
index
,
entry
type
e
ntry
)
void
set
2
(
type
2
*
heap
,
size_t
index
,
type
2
e
)
{
entry
.
index
=
index
;
heap
[
index
]
=
entry
;
}
assert
(
index
>
0
);
e
->
index
=
index
;
heap
[
index
]
=
e
;
}
#define alloc(a, o, size) realloc((o), (size))
#define scope static
/* Define heap having structs as its elements */
HEAP_BODIES
(
static
inline
,
Heap
,
heapXX_
,
pr_
,
entrytype
,
less_than
,
set_entry
,
alloc
);
typedef
HEAP_TYPE
Heap1
;
HEAP_DECLARE
(
static
,
Heap1
,
heap1_
,
type1
);
HEAP_BODIES
(
static
,
Heap1
,
heap1_
,
type1
,
less1
,
set1
,
alloc
,
null
);
/* Define heap having pointers as its elements */
typedef
HEAP_TYPE
Heap2
;
HEAP_DECLARE
(
static
,
Heap2
,
heap2_
,
type1
*
);
HEAP_BODIES
(
static
,
Heap2
,
heap2_
,
type1
*
,
less2
,
set2
,
alloc
,
NULL
);
/* ====================================================================== */
...
...
@@ -49,109 +104,249 @@ int tstflags;
char
name
[]
=
"torture_heap"
;
int
test_
speed
()
int
test_
value
()
{
BEGIN
();
Heap
heap
[
1
]
;
Heap
1
heap
=
{
NULL
}
;
unsigned
i
,
previous
,
n
,
N
;
unsigned
char
*
tests
;
N
=
300000
;
memset
(
heap
,
0
,
sizeof
heap
);
TEST_1
(
tests
=
calloc
(
sizeof
(
unsigned
char
),
N
+
1
));
TEST
(
heap
XX
_resize
(
NULL
,
heap
,
0
),
0
);
TEST
(
heap
1
_resize
(
NULL
,
&
heap
,
0
),
0
);
/* Add N entries in reverse order */
for
(
i
=
N
;
i
>
0
;
i
--
)
{
entry
type
e
=
{
i
/
10
,
i
};
if
(
heap
XX
_is_full
(
heap
))
TEST
(
heap
XX
_resize
(
NULL
,
heap
,
0
),
0
);
TEST
(
heap
XX
_is_full
(
heap
),
0
);
TEST
(
heap
XX
_add
(
heap
,
e
),
0
);
type
1
e
=
{
i
/
10
,
i
,
0
};
if
(
heap
1
_is_full
(
heap
))
TEST
(
heap
1
_resize
(
NULL
,
&
heap
,
0
),
0
);
TEST
(
heap
1
_is_full
(
heap
),
0
);
TEST
(
heap
1
_add
(
heap
,
e
),
0
);
tests
[
i
]
|=
1
;
}
TEST
(
heap
->
pr_used
,
N
);
TEST
(
heap1_used
(
heap
),
N
);
for
(
i
=
1
;
i
<=
N
;
i
++
)
{
type1
const
e
=
heap1_get
(
heap
,
i
);
TEST
(
e
.
index
,
i
);
TEST
(
tests
[
e
.
value
]
&
2
,
0
);
tests
[
e
.
value
]
|=
2
;
if
(
2
*
i
<=
N
)
{
type1
const
left
=
heap1_get
(
heap
,
2
*
i
);
TEST_1
(
e
.
key
<=
left
.
key
);
}
if
(
2
*
i
+
1
<=
N
)
{
type1
const
right
=
heap1_get
(
heap
,
2
*
i
+
1
);
TEST_1
(
e
.
key
<=
right
.
key
);
}
}
/* Remove N entries */
previous
=
0
;
for
(
n
=
0
;
heap1_used
(
heap
)
>
0
;
n
++
)
{
type1
const
e
=
heap1_get
(
heap
,
1
);
TEST_1
(
previous
<=
e
.
key
);
TEST
(
tests
[
e
.
value
]
&
4
,
0
);
tests
[
e
.
value
]
|=
4
;
previous
=
e
.
key
;
TEST
(
heap1_remove
(
heap
,
1
).
index
,
1
);
}
TEST
(
n
,
N
);
/* Add N entries in reverse order */
for
(
i
=
N
;
i
>
0
;
i
--
)
{
type1
e
=
{
i
/
10
,
i
,
0
};
if
(
heap1_is_full
(
heap
))
TEST
(
heap1_resize
(
NULL
,
&
heap
,
0
),
0
);
TEST
(
heap1_is_full
(
heap
),
0
);
TEST
(
heap1_add
(
heap
,
e
),
0
);
}
TEST
(
heap1_used
(
heap
),
N
);
for
(
i
=
0
;
i
<
N
;
i
++
)
{
TEST
(
heap
->
pr_heap
[
i
].
index
,
i
);
TEST
(
tests
[
heap
->
pr_heap
[
i
].
value
]
&
2
,
0
);
tests
[
heap
->
pr_heap
[
i
].
value
]
|=
2
;
/* Remove 1000 entries from random places */
previous
=
0
;
for
(
i
=
0
;
i
<
1000
&&
heap1_used
(
heap
)
>
0
;
i
++
)
{
type1
e
;
n
=
i
*
397651
%
heap1_used
(
heap
)
+
1
;
e
=
heap1_get
(
heap
,
n
);
TEST
(
e
.
index
,
n
);
TEST
(
tests
[
e
.
value
]
&
8
,
0
);
tests
[
e
.
value
]
|=
8
;
TEST
(
heap1_remove
(
heap
,
n
).
index
,
n
);
}
for
(
i
=
0
;
i
<
N
;
i
++
)
{
size_t
left
=
2
*
i
+
1
,
right
=
left
+
1
;
if
(
left
<
heap
->
pr_used
)
TEST_1
(
heap
->
pr_heap
[
i
].
key
<=
heap
->
pr_heap
[
left
].
key
);
if
(
right
<
heap
->
pr_used
)
TEST_1
(
heap
->
pr_heap
[
i
].
key
<=
heap
->
pr_heap
[
right
]
.
key
);
for
(
i
=
1
;
i
<
=
heap1_used
(
heap
)
;
i
++
)
{
type1
e
=
heap1_get
(
heap
,
i
)
;
type1
left
=
heap
1_get
(
heap
,
2
*
i
);
type1
right
=
heap1_get
(
heap
,
2
*
i
+
1
);
TEST_1
(
left
.
index
==
0
||
e
.
key
<=
left
.
key
);
TEST_1
(
right
.
index
==
0
||
e
.
key
<=
right
.
key
);
}
for
(
i
=
0
;
i
<
N
;
i
++
)
{
TEST
(
heap
->
pr_heap
[
i
].
index
,
i
);
/* Remove rest */
for
(
n
=
0
,
previous
=
0
;
heap1_used
(
heap
)
>
0
;
n
++
)
{
type1
e
=
heap1_get
(
heap
,
1
);
TEST
(
e
.
index
,
1
);
TEST
(
tests
[
e
.
value
]
&
8
,
0
);
tests
[
e
.
value
]
|=
8
;
TEST_1
(
previous
<=
e
.
key
);
previous
=
e
.
key
;
TEST
(
heap1_remove
(
heap
,
1
).
index
,
1
);
}
for
(
i
=
1
;
i
<=
N
;
i
++
)
{
TEST
(
tests
[
i
],
8
|
4
|
2
|
1
);
}
TEST
(
heap1_resize
(
NULL
,
&
heap
,
63
),
0
);
TEST
(
heap1_size
(
heap
),
63
);
TEST
(
heap1_free
(
NULL
,
&
heap
),
0
);
free
(
tests
);
END
();
}
int
test_ref
()
{
BEGIN
();
Heap2
heap
=
{
NULL
};
unsigned
i
,
previous
,
n
,
N
;
unsigned
char
*
tests
;
type1
*
items
;
N
=
300000
;
TEST_1
(
tests