Skip to content

Instantly share code, notes, and snippets.

@ryankurte
Last active October 4, 2020 21:39
Show Gist options
  • Save ryankurte/29c99ef58ae636735f38b1f95da33be9 to your computer and use it in GitHub Desktop.
Save ryankurte/29c99ef58ae636735f38b1f95da33be9 to your computer and use it in GitHub Desktop.
// Unaligned memcopy function
// Source: https://gist.github.com/ryankurte/29c99ef58ae636735f38b1f95da33be9
// Copyright 2020 Ryan Kurte
// Extremely untested, probably don't use this, or, test the h*ck out of it first.
// It should be _reasonably_ easy to extend this to `u32` or `u64` based methods
// for _significant_ performance improvements, however, this would either come with
// extended alignment requirements or need to switch types internally based on copy
// length.
// Copy `copy_bytes` of memory from `in` to `out` with the specified offset in bits.
// Note that where (offset_bits % 8) != 0 the `in` object must have length > (copy_bytes + 1) so
// you're not reading unknown chunks of memory.
void memcpy_unaligned_u8(uint8_t* out, const uint8_t* in, const size_t offset_bits, const size_t copy_bytes) {
size_t offset_base = offset_bits / 8;
size_t offset_shift = offset_bits % 8;
// Calculate bit mask for partial copies
// This exploits the fact that an N bit mask has the decimal value of N+1
// For example, a 3 bit mask (0b0000_0111) has the value 7,
// which we can calculate as (1 << N) - 1;
uint8_t base_mask = ~((1 << (offset_shift)) - 1);
// For each byte we first copy the lower, then upper portion
for (int i=0; i < copy_bytes; i ++) {
// Lower portion is in the same byte, top bits masked and shifted down
out[i] = (in[i + offset_base] & base_mask) >> offset_shift;
if (offset_shift > 0) {
// Upper portion is in the next byte, with the lower bits masked
uint8_t carry = in[i + offset_base + 1] & ~base_mask;
// Shifted _up_ to the top bits of the new byte
out[i] |= carry << (8-offset_shift);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment