Low level child removal from node. 'childptr' must point to the child * pointer stored inside the parent node, and is used directly instead of * searching by child value. The new node pointer (after the child * removal) is returned. Note that this function does not fix the pointer * of the parent node in its parent, so this task is up to the caller. * The function never fails for out of memor
| 1139 | * of the parent node in its parent, so this task is up to the caller. |
| 1140 | * The function never fails for out of memory. */ |
| 1141 | static inline raxNode *raxRemoveChildAtPtr(raxNode *parent, raxNode **childptr) { |
| 1142 | debugnode("raxRemoveChild before", parent); |
| 1143 | /* If parent is a compressed node (having a single child, as for definition |
| 1144 | * of the data structure), the removal of the child consists into turning |
| 1145 | * it into a normal node without children. */ |
| 1146 | if (parent->iscompr) { |
| 1147 | void *data = NULL; |
| 1148 | if (parent->iskey) data = raxGetData(parent); |
| 1149 | parent->isnull = 0; |
| 1150 | parent->iscompr = 0; |
| 1151 | parent->size = 0; |
| 1152 | parent->leafbitmap = 0; |
| 1153 | if (parent->iskey) raxSetData(parent,data); |
| 1154 | debugnode("raxRemoveChild after", parent); |
| 1155 | return parent; |
| 1156 | } |
| 1157 | |
| 1158 | /* Otherwise we need to scan for the child pointer and memmove() |
| 1159 | * accordingly. |
| 1160 | * |
| 1161 | * 1. To start we seek the first element in both the children |
| 1162 | * pointers and edge bytes in the node. */ |
| 1163 | raxNode **cp = raxNodeFirstChildPtr(parent); |
| 1164 | raxNode **c = childptr; |
| 1165 | unsigned char *e = parent->data + (c - cp); |
| 1166 | |
| 1167 | /* 3. Remove the edge and the pointer by memmoving the remaining children |
| 1168 | * pointer and edge bytes one position before. */ |
| 1169 | int taillen = parent->size - (e - parent->data) - 1; |
| 1170 | debugf("raxRemoveChild tail len: %d\n", taillen); |
| 1171 | memmove(e,e+1,taillen); |
| 1172 | |
| 1173 | /* Compute the shift, that is the amount of bytes we should move our |
| 1174 | * child pointers to the left, since the removal of one edge character |
| 1175 | * and the corresponding padding change, may change the layout. |
| 1176 | * We just check if in the old version of the node there was at the |
| 1177 | * end just a single byte and all padding: in that case removing one char |
| 1178 | * will remove a whole sizeof(void*) word. */ |
| 1179 | size_t shift = ((parent->size+4) % sizeof(void*)) == 1 ? sizeof(void*) : 0; |
| 1180 | |
| 1181 | /* Move the children pointers before the deletion point. */ |
| 1182 | if (shift) |
| 1183 | memmove(((char*)cp)-shift,cp,(parent->size-taillen-1)*sizeof(raxNode**)); |
| 1184 | |
| 1185 | /* Move the remaining "tail" pointers at the right position as well. */ |
| 1186 | size_t valuelen = (parent->iskey && !parent->isnull) ? sizeof(void*) : 0; |
| 1187 | memmove(((char*)c)-shift,c+1,taillen*sizeof(raxNode**)+valuelen); |
| 1188 | |
| 1189 | /* 4. Update size and shift the leaf bitmap accordingly. Bits above |
| 1190 | * the removed position shift down by one. */ |
| 1191 | int pos = (int)(e - parent->data); |
| 1192 | parent->size--; |
| 1193 | if (parent->leafbitmap && pos < 13) { |
| 1194 | uint16_t above = parent->leafbitmap & ~((1u << (pos+1)) - 1); |
| 1195 | uint16_t below = pos ? (parent->leafbitmap & ((1u << pos) - 1)) : 0; |
| 1196 | parent->leafbitmap = below | (above >> 1); |
| 1197 | } |
| 1198 |
no test coverage detected