diff options
Diffstat (limited to 'ot_vector.c')
| -rw-r--r-- | ot_vector.c | 57 |
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 | */ |
| 22 | void *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) { | 22 | void *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 | */ |
| 58 | void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch) { | 58 | void *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 | ||
| 84 | ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch) { | 89 | ot_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 | ||
| 152 | void vector_remove_torrent(ot_vector *vector, ot_torrent *match) { | 157 | void 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 | ||
