Given a write frame and a read frame, copy 'n' cells from after the read frame's cursor to after the write frame's cursor, * Cells in within the write frame beyond 'n' cells after the write frame's cursor may also be overwritten. * * Precondition: '*dst' is a valid write frame for 'n' more cells; * '*src' is a valid read frame for 'n' more cells; * '0 < n'; */
| 187 | * '0 < n'; |
| 188 | */ |
| 189 | static void copyBitsHelper(const frameItem* dst, const frameItem *src, size_t n) { |
| 190 | /* Pointers to the UWORDs of the read and write frame that contain the frame's cursor. */ |
| 191 | UWORD* src_ptr = src->edge - 1 - src->offset / UWORD_BIT; |
| 192 | UWORD* dst_ptr = dst->edge + (dst->offset - 1) / UWORD_BIT; |
| 193 | /* The specific bit within those UWORDs that is immediately in front of their respective cursors. |
| 194 | * That bit is specifically '1 << (src_shift - 1)' for the read frame, |
| 195 | * and '1 << (dst_shift - 1)' for the write frame, unless 'dst_shift == 0', in which case it is '1 << (UWORD_BIT - 1)'. |
| 196 | */ |
| 197 | size_t src_shift = UWORD_BIT - (src->offset % UWORD_BIT); |
| 198 | size_t dst_shift = dst->offset % UWORD_BIT; |
| 199 | if (dst_shift) { |
| 200 | /* The write frame's current UWORD is partially filled. |
| 201 | * Fill the rest of it without overwriting the existing data. |
| 202 | */ |
| 203 | *dst_ptr = LSBclear(*dst_ptr, dst_shift); |
| 204 | |
| 205 | if (src_shift < dst_shift) { |
| 206 | /* The read frame's current UWORD doesn't have enough data to entirely fill the rest of the write frame's current UWORD. |
| 207 | * Fill as much as we can and move src_ptr to the read frame's next UWORD. |
| 208 | */ |
| 209 | *dst_ptr |= (UWORD)(LSBkeep(*src_ptr, src_shift) << (dst_shift - src_shift)); |
| 210 | if (n <= src_shift) return; |
| 211 | n -= src_shift; |
| 212 | dst_shift -= src_shift; |
| 213 | src_ptr--; |
| 214 | src_shift = UWORD_BIT; |
| 215 | } |
| 216 | |
| 217 | /* Fill the rest of the write frame's current UWORD and move dst_ptr to the write frame's next UWORD. */ |
| 218 | *dst_ptr |= LSBkeep((UWORD)(*src_ptr >> (src_shift - dst_shift)), dst_shift); |
| 219 | if (n <= dst_shift) return; |
| 220 | n -= dst_shift; |
| 221 | src_shift -= dst_shift; |
| 222 | dst_ptr--; |
| 223 | } |
| 224 | /* The next cell in the write frame to be filled begins at the boundary of a UWORD. */ |
| 225 | |
| 226 | /* :TODO: Use static analysis to limit the total amount of copied memory. */ |
| 227 | if (0 == src_shift % UWORD_BIT) { |
| 228 | /* The next cell in the read frame to be filled also begins at the boundary of a UWORD. |
| 229 | * We can use 'memcpy' to copy data in bulk. |
| 230 | */ |
| 231 | size_t m = ROUND_UWORD(n); |
| 232 | /* If we went through the previous 'if (dst_shift)' block then 'src_shift == 0' and we need to decrement src_ptr. |
| 233 | * If we did not go through the previous 'if (dst_shift)' block then 'src_shift == UWORD_BIT' |
| 234 | * and we do not need to decrement src_ptr. |
| 235 | * We have folded this conditional decrement into the equation applied to 'src_ptr' below. |
| 236 | */ |
| 237 | memcpy(dst_ptr - (m - 1), src_ptr - (m - src_shift / UWORD_BIT), m * sizeof(UWORD)); |
| 238 | } else { |
| 239 | while(1) { |
| 240 | /* Fill the write frame's UWORD by copying the LSBs of the read frame's current UWORD |
| 241 | * to the MSBs of the write frame's current UWORD, |
| 242 | * and copy the MSBs of the read frame's next UWORD to the LSBs of the write frame's current UWORD. |
| 243 | * Then move both the src_ptr and dst_ptr to their next UWORDs. |
| 244 | */ |
| 245 | *dst_ptr = (UWORD)(LSBkeep(*src_ptr, src_shift) << (UWORD_BIT - src_shift)); |
| 246 | if (n <= src_shift) return; |
no test coverage detected