summaryrefslogtreecommitdiff
path: root/ot_vector.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_vector.c')
-rw-r--r--ot_vector.c57
1 files changed, 32 insertions, 25 deletions
diff --git a/ot_vector.c b/ot_vector.c
index 7f18246..a56d55b 100644
--- a/ot_vector.c
+++ b/ot_vector.c
@@ -19,7 +19,7 @@ static int vector_compare_peer4(const void *peer1, const void *peer2) { return m
19 no exact match is found. In that case it sets exactmatch 0 and gives 19 no exact match is found. In that case it sets exactmatch 0 and gives
20 calling functions the chance to insert data 20 calling functions the chance to insert data
21*/ 21*/
22void *binary_search(const void *const key, const void *base, const size_t member_count, const size_t member_size, size_t compare_size, int *exactmatch) { 22void *vector_binary_search(const void *const key, const void *base, const size_t member_count, const size_t member_size, size_t compare_size, int *exactmatch) {
23 size_t interval = member_count; 23 size_t interval = member_count;
24 24
25 while (interval) { 25 while (interval) {
@@ -50,70 +50,75 @@ static uint8_t vector_hash_peer(ot_peer const *peer, size_t compare_size, size_t
50 50
51/* This is the generic insert operation for our vector type. 51/* This is the generic insert operation for our vector type.
52 It tries to locate the object at "key" with size "member_size" by comparing its first "compare_size" bytes with 52 It tries to locate the object at "key" with size "member_size" by comparing its first "compare_size" bytes with
53 those of objects in vector. Our special "binary_search" function does that and either returns the match or a 53 those of objects in vector. Our special "vector_binary_search" function does that and either returns the match or a
54 pointer to where the object is to be inserted. vector_find_or_insert makes space for the object and copies it, 54 pointer to where the object is to be inserted. vector_find_or_insert makes space for the object and copies it,
55 if it wasn't found in vector. Caller needs to check the passed "exactmatch" variable to see, whether an insert 55 if it wasn't found in vector. Caller needs to check the passed "exactmatch" variable to see, whether an insert
56 took place. If resizing the vector failed, NULL is returned, else the pointer to the object in vector. 56 took place. If resizing the vector failed, NULL is returned, else the pointer to the object in vector.
57*/ 57*/
58void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch) { 58void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch) {
59 uint8_t *match = binary_search(key, vector->data, vector->size, member_size, compare_size, exactmatch); 59 uint8_t *match = vector_binary_search(key, vector->data, vector->size, member_size, compare_size, exactmatch);
60 size_t match_offset, bytes_after;
60 61
61 if (*exactmatch) 62 if (*exactmatch)
62 return match; 63 return match;
63 64
65 /* Hold the insertion point as an offset rather than a pointer: it survives
66 the realloc below, and an empty vector has no data pointer to offset from
67 in the first place */
68 match_offset = vector->size ? (size_t)(match - (uint8_t *)vector->data) : 0;
69 bytes_after = member_size * vector->size - match_offset;
70
64 if (vector->size + 1 > vector->space) { 71 if (vector->size + 1 > vector->space) {
65 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; 72 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
66 ptrdiff_t match_off = match - (uint8_t *)vector->data; 73 uint8_t *new_data = realloc(vector->data, new_space * member_size);
67 uint8_t *new_data = realloc(vector->data, new_space * member_size);
68 74
69 if (!new_data) 75 if (!new_data)
70 return NULL; 76 return NULL;
71 77
72 /* Adjust pointer if it moved by realloc */
73 match = new_data + match_off;
74
75 vector->data = new_data; 78 vector->data = new_data;
76 vector->space = new_space; 79 vector->space = new_space;
77 } 80 }
78 memmove(match + member_size, match, ((uint8_t *)vector->data) + member_size * vector->size - match); 81
82 match = (uint8_t *)vector->data + match_offset;
83 memmove(match + member_size, match, bytes_after);
79 84
80 vector->size++; 85 vector->size++;
81 return match; 86 return match;
82} 87}
83 88
84ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch) { 89ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch) {
85 ot_peer *match, *end; 90 ot_peer *match;
86 const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); 91 const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
87 size_t match_to_end; 92 size_t match_offset, bytes_after;
88 93
89 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ 94 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
90 if (vector->space < vector->size) 95 if (vector->space < vector->size)
91 vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size); 96 vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size);
92 match = binary_search(peer, vector->data, vector->size, peer_size, compare_size, exactmatch); 97 match = vector_binary_search(peer, vector->data, vector->size, peer_size, compare_size, exactmatch);
93 98
94 if (*exactmatch) 99 if (*exactmatch)
95 return match; 100 return match;
96 101
97 /* This is the amount of bytes that needs to be pushed backwards by peer_size bytes to make room for new peer */ 102 /* Hold the insertion point as an offset rather than a pointer: it survives
98 end = (ot_peer *)vector->data + vector->size * peer_size; 103 the realloc below, and an empty vector has no data pointer to offset from
99 match_to_end = end - match; 104 in the first place. bytes_after is what has to move up by peer_size to
105 make room for the new peer */
106 match_offset = vector->size ? (size_t)(match - (ot_peer *)vector->data) : 0;
107 bytes_after = vector->size * peer_size - match_offset;
100 108
101 if (vector->size + 1 > vector->space) { 109 if (vector->size + 1 > vector->space) {
102 ptrdiff_t offset = match - (ot_peer *)vector->data; 110 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
103 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; 111 ot_peer *new_data = realloc(vector->data, new_space * peer_size);
104 ot_peer *new_data = realloc(vector->data, new_space * peer_size);
105 112
106 if (!new_data) 113 if (!new_data)
107 return NULL; 114 return NULL;
108 /* Adjust pointer if it moved by realloc */
109 match = new_data + offset;
110 115
111 vector->data = new_data; 116 vector->data = new_data;
112 vector->space = new_space; 117 vector->space = new_space;
113 } 118 }
114 119
115 /* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */ 120 match = (ot_peer *)vector->data + match_offset;
116 memmove(match + peer_size, match, match_to_end); 121 memmove(match + peer_size, match, bytes_after);
117 122
118 vector->size++; 123 vector->size++;
119 return match; 124 return match;
@@ -137,7 +142,7 @@ int vector_remove_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size)
137 vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size); 142 vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size);
138 143
139 end = ((ot_peer *)vector->data) + peer_size * vector->size; 144 end = ((ot_peer *)vector->data) + peer_size * vector->size;
140 match = (ot_peer *)binary_search(peer, vector->data, vector->size, peer_size, compare_size, &exactmatch); 145 match = (ot_peer *)vector_binary_search(peer, vector->data, vector->size, peer_size, compare_size, &exactmatch);
141 if (!exactmatch) 146 if (!exactmatch)
142 return 0; 147 return 0;
143 148
@@ -150,11 +155,13 @@ int vector_remove_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size)
150} 155}
151 156
152void vector_remove_torrent(ot_vector *vector, ot_torrent *match) { 157void vector_remove_torrent(ot_vector *vector, ot_torrent *match) {
153 ot_torrent *end = ((ot_torrent *)vector->data) + vector->size; 158 ot_torrent *end;
154 159
155 if (!vector->size) 160 if (!vector->size)
156 return; 161 return;
157 162
163 end = ((ot_torrent *)vector->data) + vector->size;
164
158 free_peerlist(match->peer_list6); 165 free_peerlist(match->peer_list6);
159 free_peerlist(match->peer_list4); 166 free_peerlist(match->peer_list4);
160 167