Skip to content

Commit

Permalink
Populated std.h with common functionalities.
Browse files Browse the repository at this point in the history
  • Loading branch information
dparo committed Aug 11, 2023
1 parent 2485838 commit a58c24f
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 6 deletions.
116 changes: 111 additions & 5 deletions src/std.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,57 @@

#pragma once

#include <stdint.h>
#include <stddef.h>
#include <hedley.h>

typedef uint8_t byte_t;
typedef uint8_t byte8_t;
typedef int8_t i8_t;
typedef uint8_t u8_t;
typedef int16_t i16_t;
typedef uint16_t u16_t;
typedef int32_t i32_t;
typedef uint32_t u32_t;
typedef int64_t i64_t;
typedef uint64_t u64_t;

typedef uint8_t B8;
typedef int8_t I8;
typedef uint8_t U8;
typedef int16_t I16;
typedef uint16_t U16;
typedef int32_t I32;
typedef uint32_t U32;
typedef int64_t I64;
typedef uint64_t U64;

#define BUILTIN_IS_CONSTANT(x) HEDLEY_IS_CONSTANT(x)

#if __cplusplus
extern "C" {
#endif

// typeof
#ifndef __cplusplus
#if __STDC_VERSION__ >= 202311L
// NOTE: typeof() are part of C23
#else
#ifdef __GNUC__
#define typeof(x) __typeof__(x)
#endif
#endif
#else
#define typeof(x) decltype(x)
#endif

#ifndef __cplusplus
#ifdef __GNUC__
#define auto __auto_type
#endif
#else
// NOTE: auto is part of C++
#endif

// In C++, alignas(), alignof() are already part of the language spec
#ifndef __cplusplus
Expand All @@ -19,19 +66,78 @@ extern "C" {
#else
#ifdef __GNUC__
#define alignof(x) (__alignof__(x))
#define alignas(x) __attribute__ ((aligned (x)))
#define alignas(x) __attribute__((aligned(x)))
#else
#include <stdalign.h>
#endif
#endif
#endif

#ifdef MAX
#undef MAX
#endif
#define MAX(a, b) \
({ \
auto _a = (a); \
auto _b = (b); \
_a > _b ? _a : _b; \
})

#ifdef MIN
#undef MIN
#endif
#define MIN(a, b) \
({ \
auto _a = (a); \
auto _b = (b); \
_a < _b ? _a : _b; \
})

#define SWAP(a, b) \
({ \
auto *_a = &(a); \
auto *_b = &(b); \
auto _t = _a; \
*_a = *_b; \
*_b = _t; \
})

#ifdef IS_POW2
#undef IS_POW2
#endif
#define IS_POW2(x) \
({ \
auto _x = (x); \
(((_x - 1) & _x) == 0); \
})

#define PTR_IS_ALIGNED(ptr, alignment) \
({ \
auto _ptr2 = (ptr); \
(uintptr_t) PTR_ALIGN_UP(_ptr2, alignment) == (uintptr_t)_ptr2; \
})

#define PTR_ALIGN_UP(ptr, alignment) \
({ \
auto _ptr = (ptr); \
auto _alignment = MAX((size_t)(alignment), 1U); \
(BUILTIN_IS_CONSTANT(alignment) && IS_POW2(_alignment)) \
? (typeof(_ptr))((((uintptr_t)_ptr + _alignment - 1)) & ~(_alignment - 1)) \
: (typeof(_ptr))(((uintptr_t)_ptr + (size_t)_alignment - 1) / _alignment * \
_alignment); \
})

#define PTR_ALIGN_UP(ptr, alignment) (((void*) (ptr)) + ((void *) (ptr) % (alignment)))
#define PTR_ALIGN_DOWN(ptr, alignment) ((void*) (PTR_ALIGN_UP((ptr), (alignment))) - (alignment))
#define PTR_ALIGN_DOWN(ptr, alignment) \
({ \
auto _ptr = (ptr); \
auto _alignment = (size_t)(alignment); \
(BUILTIN_IS_CONSTANT(alignment) && IS_POW2(_alignment)) \
? (typeof(_ptr))((uintptr_t)_ptr & ~(_alignment - 1)) \
: (typeof(_ptr))(((uintptr_t)_ptr / _alignment) * _alignment); \
})

#define PTR_ALIGN_UP_T(ptr, T) ((T*) PTR_ALIGN_UP((ptr), alignof(T)))
#define PTR_ALIGN_DOWN_T(ptr, T) ((T*) PTR_ALIGN_DOWN((ptr), alignof(T)))
#define PTR_ALIGN_UP_T(ptr) (PTR_ALIGN_UP((ptr), alignof((ptr)[0])))
#define PTR_ALIGN_DOWN_T(ptr) (PTR_ALIGN_DOWN((ptr), alignof((ptr)[0])))

#if __cplusplus
}
Expand Down
2 changes: 1 addition & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: MIT

set(TEST_SOURCES_LIST "simple.c")
set(TEST_SOURCES_LIST "simple.c" "std.c")
set(TEST_PYTHON_LIST "test_py.py")

if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
Expand Down
97 changes: 97 additions & 0 deletions tests/std.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-FileCopyrightText: 2023 Davide Paro
//
// SPDX-License-Identifier: MIT

#include <assert.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <unity.h>

#include "sum.h"
#include <string.h>
#include "std.h"

void setUp(void) { /* This is run before EACH TEST */
}

void tearDown(void) {}

static void test_ptr_is_aligned(void) {
TEST_ASSERT_TRUE(PTR_IS_ALIGNED(NULL, 1));
TEST_ASSERT_TRUE(PTR_IS_ALIGNED(NULL, 2));
TEST_ASSERT_TRUE(PTR_IS_ALIGNED(NULL, 3));
TEST_ASSERT_TRUE(PTR_IS_ALIGNED(NULL, 4));

TEST_ASSERT_TRUE(PTR_IS_ALIGNED(1, 1));
TEST_ASSERT_FALSE(PTR_IS_ALIGNED(1, 2));

TEST_ASSERT_TRUE(PTR_IS_ALIGNED(4, 1));
TEST_ASSERT_TRUE(PTR_IS_ALIGNED(4, 2));
TEST_ASSERT_FALSE(PTR_IS_ALIGNED(4, 3));
TEST_ASSERT_TRUE(PTR_IS_ALIGNED(4, 4));

TEST_ASSERT_TRUE(PTR_IS_ALIGNED(0, 128));
TEST_ASSERT_FALSE(PTR_IS_ALIGNED(1, 128));
TEST_ASSERT_FALSE(PTR_IS_ALIGNED(2, 128));
TEST_ASSERT_FALSE(PTR_IS_ALIGNED(4, 128));
TEST_ASSERT_FALSE(PTR_IS_ALIGNED(64, 128));
TEST_ASSERT_TRUE(PTR_IS_ALIGNED(128, 128));
TEST_ASSERT_TRUE(PTR_IS_ALIGNED(256, 128));
TEST_ASSERT_TRUE(PTR_IS_ALIGNED(512, 128));
}

static void test_ptr_align_up(void) {
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_UP(0, 512));
TEST_ASSERT_EQUAL_PTR(512, PTR_ALIGN_UP(1, 512));
TEST_ASSERT_EQUAL_PTR(512, PTR_ALIGN_UP(2, 512));
TEST_ASSERT_EQUAL_PTR(512, PTR_ALIGN_UP(511, 512));
TEST_ASSERT_EQUAL_PTR(512, PTR_ALIGN_UP(512, 512));
TEST_ASSERT_EQUAL_PTR(1024, PTR_ALIGN_UP(513, 512));

TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_UP(0, 3));
TEST_ASSERT_EQUAL_PTR(3, PTR_ALIGN_UP(1, 3));
TEST_ASSERT_EQUAL_PTR(3, PTR_ALIGN_UP(3, 3));
TEST_ASSERT_EQUAL_PTR(6, PTR_ALIGN_UP(4, 3));


TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_UP_T((uint64_t*) 0));
TEST_ASSERT_EQUAL_PTR(8, PTR_ALIGN_UP_T((uint64_t*) 1));
TEST_ASSERT_EQUAL_PTR(8, PTR_ALIGN_UP_T((uint64_t*) 2));
TEST_ASSERT_EQUAL_PTR(8, PTR_ALIGN_UP_T((uint64_t*) 4));
TEST_ASSERT_EQUAL_PTR(8, PTR_ALIGN_UP_T((uint64_t*) 7));
TEST_ASSERT_EQUAL_PTR(8, PTR_ALIGN_UP_T((uint64_t*) 8));
TEST_ASSERT_EQUAL_PTR(16, PTR_ALIGN_UP_T((uint64_t*) 9));
}

static void test_ptr_align_down(void) {
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN(0, 512));
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN(1, 512));
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN(2, 512));
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN(511, 512));
TEST_ASSERT_EQUAL_PTR(512, PTR_ALIGN_DOWN(512, 512));
TEST_ASSERT_EQUAL_PTR(512, PTR_ALIGN_DOWN(513, 512));

TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN(0, 3));
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN(1, 3));
TEST_ASSERT_EQUAL_PTR(3, PTR_ALIGN_DOWN(3, 3));
TEST_ASSERT_EQUAL_PTR(3, PTR_ALIGN_DOWN(4, 3));

TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN_T((uint64_t*) 0));
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN_T((uint64_t*) 1));
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN_T((uint64_t*) 2));
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN_T((uint64_t*) 4));
TEST_ASSERT_EQUAL_PTR(0, PTR_ALIGN_DOWN_T((uint64_t*) 7));
TEST_ASSERT_EQUAL_PTR(8, PTR_ALIGN_DOWN_T((uint64_t*) 8));
TEST_ASSERT_EQUAL_PTR(8, PTR_ALIGN_DOWN_T((uint64_t*) 9));

}

int main(void) {
UNITY_BEGIN();
RUN_TEST(test_ptr_is_aligned);
RUN_TEST(test_ptr_align_up);
RUN_TEST(test_ptr_align_down);
return UNITY_END();
}

0 comments on commit a58c24f

Please sign in to comment.