| /* The Clear BSD License | |
| * | |
| * Copyright (c) 2025 EdgeImpulse Inc. | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted (subject to the limitations in the disclaimer | |
| * below) provided that the following conditions are met: | |
| * | |
| * * Redistributions of source code must retain the above copyright notice, | |
| * this list of conditions and the following disclaimer. | |
| * | |
| * * Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * | |
| * * Neither the name of the copyright holder nor the names of its | |
| * contributors may be used to endorse or promote products derived from this | |
| * software without specific prior written permission. | |
| * | |
| * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY | |
| * THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | |
| * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | |
| * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR | |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | |
| * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| * POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| namespace { | |
| /** | |
| * Based on https://github.com/embeddedartistry/embedded-resources/blob/master/examples/c/malloc_aligned.c | |
| */ | |
| /** | |
| * Simple macro for making sure memory addresses are aligned | |
| * to the nearest power of two | |
| */ | |
| //Number of bytes we're using for storing the aligned pointer offset | |
| typedef uint16_t offset_t; | |
| /** | |
| * aligned_malloc takes in the requested alignment and size | |
| * We will call malloc with extra bytes for our header and the offset | |
| * required to guarantee the desired alignment. | |
| */ | |
| __attribute__((unused)) void * ei_aligned_calloc(size_t align, size_t size) | |
| { | |
| void * ptr = NULL; | |
| //We want it to be a power of two since align_up operates on powers of two | |
| assert((align & (align - 1)) == 0); | |
| if(align && size) | |
| { | |
| /* | |
| * We know we have to fit an offset value | |
| * We also allocate extra bytes to ensure we can meet the alignment | |
| */ | |
| uint32_t hdr_size = PTR_OFFSET_SZ + (align - 1); | |
| void * p = ei_calloc(size + hdr_size, 1); | |
| if(p) | |
| { | |
| /* | |
| * Add the offset size to malloc's pointer (we will always store that) | |
| * Then align the resulting value to the arget alignment | |
| */ | |
| ptr = (void *) align_up(((uintptr_t)p + PTR_OFFSET_SZ), align); | |
| //Calculate the offset and store it behind our aligned pointer | |
| *((offset_t *)ptr - 1) = (offset_t)((uintptr_t)ptr - (uintptr_t)p); | |
| } // else NULL, could not malloc | |
| } //else NULL, invalid arguments | |
| return ptr; | |
| } | |
| /** | |
| * aligned_free works like free(), but we work backwards from the returned | |
| * pointer to find the correct offset and pointer location to return to free() | |
| * Note that it is VERY BAD to call free() on an aligned_malloc() pointer. | |
| */ | |
| __attribute__((unused)) void ei_aligned_free(void * ptr) | |
| { | |
| assert(ptr); | |
| /* | |
| * Walk backwards from the passed-in pointer to get the pointer offset | |
| * We convert to an offset_t pointer and rely on pointer math to get the data | |
| */ | |
| offset_t offset = *((offset_t *)ptr - 1); | |
| /* | |
| * Once we have the offset, we can get our original pointer and call free | |
| */ | |
| void * p = (void *)((uint8_t *)ptr - offset); | |
| ei_free(p); | |
| } | |
| } | |