Last active
October 4, 2020 21:39
-
-
Save ryankurte/29c99ef58ae636735f38b1f95da33be9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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