import
This commit is contained in:
+125
@@ -0,0 +1,125 @@
|
||||
#include <arena.h>
|
||||
#include <string.h>
|
||||
#include <os_align.h>
|
||||
#include "os_macros.h"
|
||||
|
||||
|
||||
#define IS_POWER_OF_2(n) ((n) != 0 && (((n) & ((n) - 1)) == 0))
|
||||
#define DEFAULT_ALIGNMENT OS_ALIGN_SIZE
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
static
|
||||
os_uintptr_t align_forward(os_uintptr_t ptr, os_size_t align) {
|
||||
os_uintptr_t p, a, modulo;
|
||||
|
||||
OS_ASSERT(IS_POWER_OF_2(align));
|
||||
|
||||
p = ptr;
|
||||
a = (os_uintptr_t )align;
|
||||
// Same as (p % a) but faster as 'a' is a power of two
|
||||
modulo = p & (a-1);
|
||||
|
||||
if (modulo != 0) {
|
||||
// If 'p' address is not aligned, push the address to the
|
||||
// next value which is aligned
|
||||
p += a - modulo;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static void *arena_alloc_align(arena_t *a, os_size_t size, os_size_t align) {
|
||||
// Align 'curr_offset' forward to the specified alignment
|
||||
os_uintptr_t curr_ptr = (os_uintptr_t) a->buf + (os_uintptr_t) a->curr_offset;
|
||||
os_uintptr_t offset = align_forward(curr_ptr, align);
|
||||
offset -= (os_uintptr_t) a->buf; // Change to relative offset
|
||||
|
||||
// Check to see if the backing memory has space left
|
||||
if (offset+size <= a->buf_size) {
|
||||
void *ptr = &a->buf[offset];
|
||||
a->prev_offset = offset;
|
||||
a->curr_offset = offset+size;
|
||||
|
||||
// Zero new memory by default
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
// Return NULL if the arena is out of memory (or handle differently)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *arena_resize_align(arena_t *a, void *old_memory, size_t old_size, size_t new_size, size_t align) {
|
||||
unsigned char *old_mem = (unsigned char *)old_memory;
|
||||
|
||||
OS_ASSERT(IS_POWER_OF_2(align));
|
||||
|
||||
if (old_mem == NULL || old_size == 0) {
|
||||
return arena_alloc_align(a, new_size, align);
|
||||
} else if (a->buf <= old_mem && old_mem < a->buf+a->buf_size) {
|
||||
if (a->buf+a->prev_offset == old_mem) {
|
||||
a->curr_offset = a->prev_offset + new_size;
|
||||
if (new_size > old_size) {
|
||||
// Zero the new memory by default
|
||||
memset(&a->buf[a->curr_offset], 0, new_size-old_size);
|
||||
}
|
||||
return old_memory;
|
||||
} else {
|
||||
void *new_memory = arena_alloc_align(a, new_size, align);
|
||||
size_t copy_size = old_size < new_size ? old_size : new_size;
|
||||
// Copy across old memory to the new memory
|
||||
memmove(new_memory, old_memory, copy_size);
|
||||
return new_memory;
|
||||
}
|
||||
|
||||
} else {
|
||||
OS_ASSERT(0 && "Memory is out of bounds of the buffer in this arena");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
void arena_init(arena_t* self, uint8_t * buf, os_size_t buf_size){
|
||||
self->buf = buf;
|
||||
self->buf_size = buf_size;
|
||||
self->prev_offset = 0;
|
||||
self->curr_offset = 0;
|
||||
}
|
||||
|
||||
void* arena_alloc(arena_t* self, os_size_t size){
|
||||
return arena_alloc_align(self, size, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
void* arena_realloc(arena_t* self, void* old, os_size_t old_size, os_size_t new_size){
|
||||
return arena_resize_align(self, old, old_size, new_size, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
void arena_free(arena_t* self, void* ptr)
|
||||
{}
|
||||
|
||||
void arean_destroy(arena_t* self){
|
||||
self->curr_offset = 0;
|
||||
self->prev_offset = 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
temp_arena_memory_t temp_arena_memory_begin(arena_t *a) {
|
||||
temp_arena_memory_t temp;
|
||||
temp.arena = a;
|
||||
temp.prev_offset = a->prev_offset;
|
||||
temp.curr_offset = a->curr_offset;
|
||||
return temp;
|
||||
}
|
||||
|
||||
void temp_arena_memory_end(temp_arena_memory_t temp) {
|
||||
temp.arena->prev_offset = temp.prev_offset;
|
||||
temp.arena->curr_offset = temp.curr_offset;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef INCLUDED_ARENA_H
|
||||
#define INCLUDED_ARENA_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* https://www.gingerbill.org/article/2019/02/08/memory-allocation-strategies-002/ */
|
||||
|
||||
typedef struct arena_t{
|
||||
uint8_t * buf;
|
||||
os_size_t buf_size;
|
||||
os_size_t prev_offset;
|
||||
os_size_t curr_offset;
|
||||
}arena_t;
|
||||
|
||||
typedef struct temp_arena_memory_t {
|
||||
arena_t *arena;
|
||||
size_t prev_offset;
|
||||
size_t curr_offset;
|
||||
}temp_arena_memory_t;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
void arena_init(arena_t* self, uint8_t * buf, os_size_t buf_size);
|
||||
|
||||
void* arena_alloc(arena_t* self, os_size_t size);
|
||||
|
||||
void* arena_realloc(arena_t* self, void* old, os_size_t old_size, os_size_t new_size);
|
||||
|
||||
// 不支持的操作
|
||||
//void arena_free(arena_t* self, void* ptr);
|
||||
|
||||
void arean_destroy(arena_t* self);
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
temp_arena_memory_t temp_arena_memory_begin(arena_t *a);
|
||||
|
||||
void temp_arena_memory_end(temp_arena_memory_t temp);
|
||||
|
||||
#endif /*INCLUDED_ARENA_H*/
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
#include <buddy.h>
|
||||
#include <os_macros.h>
|
||||
#include <string.h>
|
||||
#include <os_compiler.h>
|
||||
|
||||
|
||||
#define IS_POWER_OF_2(n) ((n) != 0 && (((n) & ((n) - 1)) == 0))
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
buddy_block_t* buddy_block_next(buddy_block_t* block){
|
||||
return (buddy_block_t*)((uint8_t*)block + block->size);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
buddy_block_t *buddy_block_split(buddy_block_t *block, size_t size) {
|
||||
if (block != NULL && size != 0) {
|
||||
// Recursive split
|
||||
while (size < block->size) {
|
||||
size_t sz = block->size >> 1;
|
||||
block->size = sz;
|
||||
block = buddy_block_next(block);
|
||||
block->size = sz;
|
||||
block->is_free = OS_TRUE;
|
||||
}
|
||||
|
||||
if (size <= block->size) {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
// Block cannot fit the requested allocation size
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
buddy_block_t *buddy_block_find_best(buddy_block_t *head, buddy_block_t *tail, size_t size) {
|
||||
// Assumes size != 0
|
||||
|
||||
buddy_block_t *best_block = NULL;
|
||||
buddy_block_t *block = head; // Left Buddy
|
||||
buddy_block_t *buddy = buddy_block_next(block); // Right Buddy
|
||||
|
||||
// The entire memory section between head and tail is free,
|
||||
// just call 'buddy_block_split' to get the allocation
|
||||
if (buddy == tail && block->is_free) {
|
||||
return buddy_block_split(block, size);
|
||||
}
|
||||
|
||||
// Find the block which is the 'best_block' to requested allocation sized
|
||||
while (block < tail && buddy < tail) { // make sure the buddies are within the range
|
||||
// If both buddies are free, coalesce them together
|
||||
// NOTE: this is an optimization to reduce fragmentation
|
||||
// this could be completely ignored
|
||||
if (block->is_free && buddy->is_free && block->size == buddy->size) {
|
||||
block->size <<= 1;
|
||||
if (size <= block->size && (best_block == NULL || block->size <= best_block->size)) {
|
||||
best_block = block;
|
||||
}
|
||||
|
||||
block = buddy_block_next(buddy);
|
||||
if (block < tail) {
|
||||
// Delay the buddy block for the next iteration
|
||||
buddy = buddy_block_next(block);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (block->is_free && size <= block->size &&
|
||||
(best_block == NULL || block->size <= best_block->size)) {
|
||||
best_block = block;
|
||||
}
|
||||
|
||||
if (buddy->is_free && size <= buddy->size &&
|
||||
(best_block == NULL || buddy->size < best_block->size)) {
|
||||
// If each buddy are the same size, then it makes more sense
|
||||
// to pick the buddy as it "bounces around" less
|
||||
best_block = buddy;
|
||||
}
|
||||
|
||||
if (block->size <= buddy->size) {
|
||||
block = buddy_block_next(buddy);
|
||||
if (block < tail) {
|
||||
// Delay the buddy block for the next iteration
|
||||
buddy = buddy_block_next(block);
|
||||
}
|
||||
} else {
|
||||
// Buddy was split into smaller blocks
|
||||
block = buddy;
|
||||
buddy = buddy_block_next(buddy);
|
||||
}
|
||||
}
|
||||
|
||||
if (best_block != NULL) {
|
||||
// This will handle the case if the 'best_block' is also the perfect fit
|
||||
return buddy_block_split(best_block, size);
|
||||
}
|
||||
|
||||
// Maybe out of memory
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_size_t align_forward_size(os_size_t ptr, os_size_t align) {
|
||||
os_size_t a, p, modulo;
|
||||
|
||||
OS_ASSERT(IS_POWER_OF_2((os_uintptr_t)align));
|
||||
|
||||
a = align;
|
||||
p = ptr;
|
||||
modulo = p & (a-1);
|
||||
if (modulo != 0) {
|
||||
p += a - modulo;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_size_t buddy_block_size_required(buddy_t *b, size_t size) {
|
||||
os_size_t actual_size = b->alignment;
|
||||
|
||||
size += sizeof(buddy_block_t);
|
||||
size = align_forward_size(size, b->alignment);
|
||||
|
||||
while (size > actual_size) {
|
||||
actual_size <<= 1;
|
||||
}
|
||||
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
static
|
||||
void buddy_block_coalescence(buddy_block_t *head, buddy_block_t *tail) {
|
||||
for (;;) {
|
||||
// Keep looping until there are no more buddies to coalesce
|
||||
|
||||
buddy_block_t *block = head;
|
||||
buddy_block_t *buddy = buddy_block_next(block);
|
||||
|
||||
#if 0
|
||||
// 原版有bug
|
||||
bool no_coalescence = OS_TRUE;
|
||||
while (block < tail && buddy < tail) { // make sure the buddies are within the range
|
||||
if (block->is_free && buddy->is_free && block->size == buddy->size) {
|
||||
// Coalesce buddies into one
|
||||
block->size <<= 1;
|
||||
block = buddy_block_next(block);
|
||||
if (block < tail) {
|
||||
buddy = buddy_block_next(block);
|
||||
no_coalescence = C_FALSE;
|
||||
}
|
||||
} else if (block->size < buddy->size) {
|
||||
// The buddy block is split into smaller blocks
|
||||
block = buddy;
|
||||
buddy = buddy_block_next(buddy);
|
||||
} else {
|
||||
block = buddy_block_next(buddy);
|
||||
if (block < tail) {
|
||||
// Leave the buddy block for the next iteration
|
||||
buddy = buddy_block_next(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool no_coalescence = OS_TRUE;
|
||||
while (block < tail && buddy < tail) { // make sure the buddies are within the range
|
||||
if (block->is_free && buddy->is_free && block->size == buddy->size) {
|
||||
// Coalesce buddies into one
|
||||
block->size <<= 1;
|
||||
// block = buddy_block_next(buddy);
|
||||
if (block < tail) {
|
||||
buddy = buddy_block_next(block);
|
||||
no_coalescence = OS_FALSE;
|
||||
}
|
||||
} else if (block->size <= buddy->size) {
|
||||
block = buddy_block_next(buddy);
|
||||
if (block < tail) {
|
||||
// Leave the buddy block for the next iteration
|
||||
buddy = buddy_block_next(block);
|
||||
}
|
||||
} else {
|
||||
// The buddy block is split into smaller blocks
|
||||
block = buddy;
|
||||
buddy = buddy_block_next(buddy);
|
||||
}
|
||||
}
|
||||
|
||||
if (no_coalescence) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
void buddy_init(buddy_t* self, void* block, os_size_t block_size, os_size_t alignment){
|
||||
OS_ASSERT(block != NULL);
|
||||
OS_ASSERT(IS_POWER_OF_2(block_size) && "size is not a power-of-two");
|
||||
OS_ASSERT(IS_POWER_OF_2(alignment) && "alignment is not a power-of-two");
|
||||
|
||||
// The minimum alignment depends on the size of the `budy_block_t` header
|
||||
alignment = OS_MAX(alignment, sizeof(buddy_block_t));
|
||||
// if (alignment < sizeof(buddy_block_t)) {
|
||||
// alignment = sizeof(buddy_block_t);
|
||||
// }
|
||||
OS_ASSERT((uintptr_t)block % alignment == 0 && "block is not aligned to minimum alignment");
|
||||
|
||||
self->head = (buddy_block_t *)block;
|
||||
self->head->size = block_size;
|
||||
self->head->is_free = OS_TRUE;
|
||||
|
||||
// The tail here is a sentinel value and not a true block
|
||||
self->tail = buddy_block_next(self->head);
|
||||
|
||||
self->alignment = alignment;
|
||||
}
|
||||
|
||||
void buddy_destroy(buddy_t* self){
|
||||
self->head = 0;
|
||||
self->tail = 0;
|
||||
self->alignment = 0;
|
||||
}
|
||||
|
||||
void* buddy_alloc(buddy_t* b, os_size_t size){
|
||||
if (size != 0) {
|
||||
size_t actual_size = buddy_block_size_required(b, size);
|
||||
|
||||
buddy_block_t *found = buddy_block_find_best(b->head, b->tail, actual_size);
|
||||
if (found == NULL) {
|
||||
// Try to coalesce all the free buddy blocks and then search again
|
||||
buddy_block_coalescence(b->head, b->tail);
|
||||
found = buddy_block_find_best(b->head, b->tail, actual_size);
|
||||
}
|
||||
|
||||
if (found != NULL) {
|
||||
found->is_free = OS_FALSE;
|
||||
return (void *)((uint8_t *)found + b->alignment);
|
||||
}
|
||||
|
||||
// Out of memory (possibly due to too much internal fragmentation)
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* buddy_calloc(buddy_t* b, os_size_t count, os_size_t size){
|
||||
void* mem = buddy_alloc(b, size * count);
|
||||
if(mem){
|
||||
memset(mem, 0, size);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
void* buddy_realloc(buddy_t* self, void* ptr, os_size_t size){
|
||||
void* mem = buddy_alloc(self, size);
|
||||
if(!mem){
|
||||
return NULL;
|
||||
}
|
||||
buddy_block_t *block =(buddy_block_t *)((uint8_t *)ptr - self->alignment);
|
||||
size = OS_MIN(size, block->size);
|
||||
memcpy(mem, ptr, size);
|
||||
buddy_free(self, ptr);
|
||||
return mem;
|
||||
}
|
||||
|
||||
void buddy_free(buddy_t* b, void* data){
|
||||
if (data != NULL) {
|
||||
buddy_block_t *block;
|
||||
|
||||
OS_ASSERT(b->head <= (buddy_block_t*)data);
|
||||
OS_ASSERT((buddy_block_t*)data < b->tail);
|
||||
|
||||
block = (buddy_block_t *)((uint8_t *)data - b->alignment);
|
||||
block->is_free = OS_TRUE;
|
||||
|
||||
// NOTE: Coalescence could be done now but it is optional
|
||||
// buddy_block_coalescence(b->head, b->tail);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef INCLUDED_BUDDY_H
|
||||
#define INCLUDED_BUDDY_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* https://www.gingerbill.org/article/2021/12/02/memory-allocation-strategies-006/ */
|
||||
|
||||
typedef struct buddy_block_t{
|
||||
os_size_t size;
|
||||
os_bool_t is_free;
|
||||
}buddy_block_t;
|
||||
|
||||
typedef struct buddy_t{
|
||||
buddy_block_t* head;
|
||||
buddy_block_t* tail;
|
||||
int alignment;
|
||||
}buddy_t;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
void buddy_init(buddy_t* self, void* buf, os_size_t buf_size /*POWER_OF_2*/, os_size_t alignment /*POWER_OF_2*/);
|
||||
|
||||
void buddy_destroy(buddy_t* self);
|
||||
|
||||
void* buddy_alloc(buddy_t* self, os_size_t size);
|
||||
|
||||
void* buddy_calloc(buddy_t* b, os_size_t count, os_size_t size);
|
||||
|
||||
void* buddy_realloc(buddy_t* self, void* ptr, os_size_t size);
|
||||
|
||||
void buddy_free(buddy_t* self, void* ptr);
|
||||
|
||||
#endif /*INCLUDED_BUDDY_H*/
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <os_memory.h>
|
||||
#include "buddy.h"
|
||||
#include "os_align.h"
|
||||
#include "os_compiler.h"
|
||||
|
||||
// 默认使用 buddy
|
||||
static buddy_t s_buddy;
|
||||
|
||||
OS_WEAK
|
||||
void os_memory_init(void* block, os_size_t block_size){
|
||||
buddy_init(&s_buddy, block, block_size, OS_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
void* os_memory_alloc(os_size_t nBytes, const char* file, os_size_t line){
|
||||
return buddy_alloc(&s_buddy, nBytes);
|
||||
}
|
||||
|
||||
void* os_memory_realloc(void* ptr, os_size_t nBytes, const char* file, os_size_t line){
|
||||
return buddy_realloc(&s_buddy, ptr, nBytes);
|
||||
}
|
||||
|
||||
void* os_memory_calloc(os_size_t nCount, os_size_t nBytes, const char* file, os_size_t line){
|
||||
return buddy_calloc(&s_buddy, nCount, nBytes);
|
||||
}
|
||||
|
||||
void os_memory_free(void* ptr, const char* file, os_size_t line){
|
||||
if(!ptr) return;
|
||||
buddy_free(&s_buddy, ptr);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#include <debounce.h>
|
||||
|
||||
void Debounce_Init(Debounce_t* self){
|
||||
self->state = kButtonState_IDLE;
|
||||
self->debounce_cnt = 0;
|
||||
self->long_press_cnt = 0;
|
||||
self->double_click_cnt = 0;
|
||||
self->is_pressed = 0;
|
||||
self->last_pressed = 0;
|
||||
}
|
||||
|
||||
|
||||
ButtonEvent_t Debounce_Handle(Debounce_t* self, uint8_t cur_state){
|
||||
ButtonEvent_t event = kButtonEvent_NONE;
|
||||
self->is_pressed = cur_state;
|
||||
switch (self->state) {
|
||||
case kButtonState_IDLE:{
|
||||
if(cur_state == 1){
|
||||
self->state = kButtonState_DEBOUNCE;
|
||||
self->debounce_cnt = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kButtonState_DEBOUNCE:{
|
||||
if(cur_state==1){
|
||||
self->debounce_cnt++;
|
||||
if(self->debounce_cnt >= DEBOUNCE_TICKS){
|
||||
self->state = kButtonState_PRESS;
|
||||
self->debounce_cnt = 0;
|
||||
event = kButtonEvent_PRESS; /* 触发下按事件 */
|
||||
}
|
||||
}else{
|
||||
self->state = kButtonState_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kButtonState_PRESS:{
|
||||
if(cur_state==1){
|
||||
self->long_press_cnt++;
|
||||
if(self->long_press_cnt >= DEBOUNCE_LONG_TICKS){
|
||||
self->state = kButtonState_LONG_PRESS;
|
||||
event = kButtonEvent_LONG_PRESS;
|
||||
}
|
||||
}else{
|
||||
// 第一击释放,进入释放消抖,防止触摸屏抖动误判
|
||||
self->state = kButtonState_RELEASE_DEBOUNCE;
|
||||
self->debounce_cnt = 0;
|
||||
self->long_press_cnt = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kButtonState_LONG_PRESS:{
|
||||
if(cur_state==0){
|
||||
self->state = kButtonState_IDLE;
|
||||
self->long_press_cnt = 0;
|
||||
event = kButtonEvent_RELEASE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kButtonState_WAIT_DOUBLE:{
|
||||
if(cur_state==1){ /* 在规定时间内再次按下,判定为双击 */
|
||||
self->state = kButtonState_DOUBLE_DEBOUNCE; /* 去除第二次抖动 */
|
||||
self->debounce_cnt = 0;
|
||||
}else{
|
||||
self->double_click_cnt++;
|
||||
if(self->double_click_cnt>=DEBOUNCE_DOUBLE_TICKS){ // 超时未按下,判定为普通的独立单击
|
||||
self->state = kButtonState_LONG_PRESS;
|
||||
event = kButtonEvent_CLICK;
|
||||
self->double_click_cnt = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kButtonState_DOUBLE_DEBOUNCE:{
|
||||
if(cur_state==1){
|
||||
self->debounce_cnt++;
|
||||
if(self->debounce_cnt >= DEBOUNCE_TICKS){
|
||||
self->state = kButtonState_LONG_PRESS; /* 等待释放 */
|
||||
self->debounce_cnt = 0;
|
||||
event = kButtonEvent_DOUBLE_CLICK; /* 确认双击 */
|
||||
}
|
||||
}else{
|
||||
self->state = kButtonState_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kButtonState_RELEASE_DEBOUNCE:{
|
||||
if(cur_state==0){
|
||||
self->debounce_cnt++;
|
||||
if(self->debounce_cnt >= DEBOUNCE_TICKS){
|
||||
// 确认释放,开始计时等待第二击
|
||||
self->state = kButtonState_WAIT_DOUBLE;
|
||||
self->double_click_cnt = 0;
|
||||
}
|
||||
}else{
|
||||
self->state = kButtonState_PRESS; // 抖动,返回按下状态
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
self->last_pressed = cur_state;
|
||||
|
||||
return event;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef INCLUDED_DEBOUNCE_H
|
||||
#define INCLUDED_DEBOUNCE_H
|
||||
|
||||
#ifndef INCLUDED_STDINT_H
|
||||
#define INCLUDED_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif /*INCLUDED_STDINT_H*/
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
typedef enum {
|
||||
kButtonEvent_NONE = 0,
|
||||
kButtonEvent_PRESS,
|
||||
kButtonEvent_CLICK,
|
||||
kButtonEvent_DOUBLE_CLICK,
|
||||
kButtonEvent_LONG_PRESS,
|
||||
kButtonEvent_RELEASE,
|
||||
}ButtonEvent_t;
|
||||
|
||||
typedef enum{
|
||||
kButtonState_IDLE = 0,
|
||||
kButtonState_DEBOUNCE, /* 按下消抖 */
|
||||
kButtonState_PRESS, /* 确认按下,等待释放或长按 */
|
||||
kButtonState_LONG_PRESS, /* 处于长按状态 */
|
||||
kButtonState_WAIT_DOUBLE, /* 等待第二次按下 */
|
||||
kButtonState_DOUBLE_DEBOUNCE, /* 第二次消抖 */
|
||||
kButtonState_RELEASE_DEBOUNCE, /* 释放消抖 */
|
||||
}ButtonState_t;
|
||||
|
||||
typedef struct {
|
||||
ButtonState_t state;
|
||||
uint8_t debounce_cnt; /* 消抖计数器 */
|
||||
uint16_t long_press_cnt; /* 长按计数器 */
|
||||
uint16_t double_click_cnt; /* 双击等待计数器 */
|
||||
uint8_t is_pressed; /* 经过消抖后当前的电平: (1:按下, 0:松开) */
|
||||
uint8_t last_pressed; /* 上一次物理电平 */
|
||||
}Debounce_t;
|
||||
|
||||
#define DEBOUNCE_INIT {kButtonState_IDLE, 0, 0, 0, 0, 0}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
// 核心参数配置(基于 10ms 状态机轮询周期)
|
||||
#define DEBOUNCE_TICKS 3 // 消抖时间: 3 * 10ms = 30ms
|
||||
#define DEBOUNCE_LONG_TICKS 150 // 长按判定: 150 * 10ms = 1.5s
|
||||
#define DEBOUNCE_DOUBLE_TICKS 35 // 双击间隔: 35 * 10ms = 350ms
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
void Debounce_Init(Debounce_t* self);
|
||||
|
||||
/**
|
||||
* @brief 状态机核心处理函数(需在 10ms 定时器中断或主循环定时中调用)
|
||||
* @param self: 消抖结构体指针
|
||||
* @param cur_state: 当前按键状态,1:按下, 0:松开
|
||||
* @return 检测到的事件类型
|
||||
*/
|
||||
ButtonEvent_t Debounce_Handle(Debounce_t* self, uint8_t cur_state);
|
||||
|
||||
|
||||
#endif /*INCLUDED_DEBOUNCE_H*/
|
||||
+399
@@ -0,0 +1,399 @@
|
||||
#include <fifo.h>
|
||||
#include <os_macros.h>
|
||||
#include <ctype.h> // isspace
|
||||
#include <limits.h> // ULONG_MAX
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
// 在尾部写入数据
|
||||
os_err_t fifo_put(fifo_t* self, uint8_t data){
|
||||
|
||||
os_size_t write_idx = self->write_idx;
|
||||
|
||||
os_size_t next_write_idx = write_idx + 1;
|
||||
if(next_write_idx >= self->buffer_size){
|
||||
next_write_idx = 0;
|
||||
}
|
||||
|
||||
if(next_write_idx == self->read_idx){
|
||||
return OS_ERR_FULL;
|
||||
}
|
||||
|
||||
self->buffer[write_idx] = data;
|
||||
self->write_idx = next_write_idx;
|
||||
|
||||
return OS_ERR_OK;
|
||||
}
|
||||
|
||||
// 从头部获取数据
|
||||
os_err_t fifo_get(fifo_t* self, uint8_t* data){
|
||||
os_size_t read_idx = self->read_idx;
|
||||
if(read_idx==self->write_idx){
|
||||
return OS_ERR_EMPTY;
|
||||
}
|
||||
|
||||
if(data){
|
||||
*data = self->buffer[read_idx];
|
||||
}
|
||||
|
||||
os_size_t next_read_idx = read_idx + 1;
|
||||
if(next_read_idx >= self->buffer_size){
|
||||
next_read_idx = 0;
|
||||
}
|
||||
self->read_idx = next_read_idx;
|
||||
return OS_ERR_OK;
|
||||
}
|
||||
|
||||
// 批量写入数据
|
||||
os_size_t fifo_write(fifo_t* self, uint8_t* data, os_size_t size){
|
||||
os_size_t i;
|
||||
for(i=0; i<size; i++){
|
||||
if(fifo_put(self, data[i])!=OS_ERR_OK){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// 批量读取数据
|
||||
os_size_t fifo_read(fifo_t* self, uint8_t* buf, os_size_t size){
|
||||
os_size_t i;
|
||||
for(i=0; i<size; i++){
|
||||
if(fifo_get(self, buf++)!=OS_ERR_OK){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
os_size_t fifo_write_fast(fifo_t* rb, const uint8_t * data, os_size_t len){
|
||||
if (rb == NULL || data == NULL || len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 如果写入数据超过剩余空间,则只写入剩余空间部分(或者可以选择报错/覆盖,这里选择截断) */
|
||||
os_size_t free_sp = fifo_space(rb);
|
||||
if (len > free_sp) {
|
||||
len = free_sp;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
// 没有空间了
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 分段写入
|
||||
// buf_size: 8
|
||||
// 0, 1, 2, 3, 4, 5, 6, 7
|
||||
// r w
|
||||
// w r
|
||||
os_size_t write_idx = rb->write_idx;
|
||||
os_size_t read_idx = rb->read_idx;
|
||||
os_size_t size = rb->buffer_size;
|
||||
|
||||
if(write_idx > read_idx){
|
||||
os_size_t first_part = size - write_idx;
|
||||
if(first_part >= len){
|
||||
// 一次就可以拷贝完成
|
||||
memcpy(&rb->buffer[write_idx], data, first_part);
|
||||
}else{
|
||||
// 分成两个部分
|
||||
memcpy(&rb->buffer[write_idx], data, first_part);
|
||||
os_size_t second_part = len - first_part;
|
||||
memcpy(&rb->buffer, &data[first_part], second_part);
|
||||
}
|
||||
}else{
|
||||
// 这里不会有 write_idx == read_idx 的情况,这种情况,free_sp=0
|
||||
// 前面已经计算过 len 就是最多可以存下的字节数,因此这里直接拷贝
|
||||
memcpy(&rb->buffer[write_idx], data, len);
|
||||
}
|
||||
|
||||
rb->write_idx = (write_idx + len) % size;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
os_size_t fifo_read_fast(fifo_t* rb, uint8_t * data, os_size_t len){
|
||||
if (rb == NULL || data == NULL || len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 如果读取长度超过有效数据长度,则只读取有效部分 */
|
||||
os_size_t data_sz = fifo_count(rb);
|
||||
if (len > data_sz) {
|
||||
len = data_sz;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
os_size_t read_idx = rb->read_idx;
|
||||
os_size_t write_idx = rb->write_idx;
|
||||
os_size_t size = rb->buffer_size;
|
||||
|
||||
// 分段读取
|
||||
// buf_size: 8
|
||||
// 0, 1, 2, 3, 4, 5, 6, 7
|
||||
// r w
|
||||
// w r
|
||||
|
||||
if(write_idx > read_idx){
|
||||
memcpy(&data, &rb->buffer[read_idx], len);
|
||||
}else{
|
||||
os_size_t first_part = size - read_idx;
|
||||
if(first_part >= len){
|
||||
// 一次就可以拷贝完成
|
||||
memcpy(data, &rb->buffer[read_idx], first_part);
|
||||
}else{
|
||||
// 分成两个部分
|
||||
memcpy(data, &rb->buffer[read_idx], first_part);
|
||||
os_size_t second_part = len - first_part;
|
||||
memcpy(&data[first_part], &rb->buffer, second_part);
|
||||
}
|
||||
}
|
||||
|
||||
rb->read_idx = (read_idx + len) % size;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
os_err_t fifo_peek_at(fifo_t* self, os_size_t offset, uint8_t * data){
|
||||
os_size_t data_sz = fifo_count(self);
|
||||
if(offset >= data_sz){
|
||||
return OS_ERR_FULL;
|
||||
}
|
||||
if(data){
|
||||
os_size_t index = (self->read_idx + offset) % self->buffer_size;
|
||||
*data = self->buffer[index];
|
||||
}
|
||||
return OS_ERR_OK;
|
||||
}
|
||||
|
||||
os_size_t fifo_peek_bulk(fifo_t* rb, os_size_t offset, uint8_t* data, os_size_t len){
|
||||
if (rb == NULL || data == NULL || len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 如果读取长度超过有效数据长度,则只读取有效部分 */
|
||||
os_size_t data_sz = fifo_count(rb);
|
||||
|
||||
if(offset >= data_sz){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > (data_sz - offset)) {
|
||||
len = data_sz - offset;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
os_size_t size = rb->buffer_size;
|
||||
os_size_t read_idx = (rb->read_idx + offset) % size;
|
||||
os_size_t write_idx = rb->write_idx;
|
||||
|
||||
// 分段读取
|
||||
// buf_size: 8
|
||||
// 0, 1, 2, 3, 4, 5, 6, 7
|
||||
// r w
|
||||
// w r
|
||||
|
||||
if(write_idx > read_idx){
|
||||
memcpy(&data, &rb->buffer[read_idx], len);
|
||||
}else{
|
||||
os_size_t first_part = size - read_idx;
|
||||
if(first_part >= len){
|
||||
// 一次就可以拷贝完成
|
||||
memcpy(data, &rb->buffer[read_idx], first_part);
|
||||
}else{
|
||||
// 分成两个部分
|
||||
memcpy(data, &rb->buffer[read_idx], first_part);
|
||||
os_size_t second_part = len - first_part;
|
||||
memcpy(&data[first_part], &rb->buffer, second_part);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int fifo_memcmp(fifo_t *rb, os_size_t offset, const void *ptr, os_size_t len) {
|
||||
os_size_t data_sz = fifo_count(rb);
|
||||
OS_ASSERT(offset < data_sz);
|
||||
OS_ASSERT(ptr);
|
||||
|
||||
if (len > (data_sz - offset)) {
|
||||
// 如果请求比较的长度超过缓冲区现有数据量,可根据需求返回错误或只比较现有部分
|
||||
// 这里假设调用者确保len <= fifo_count,或者我们只比较有效部分
|
||||
len = data_sz - offset;
|
||||
}
|
||||
|
||||
uint8_t rb_byte=0xff;
|
||||
const uint8_t *external_ptr = (const uint8_t *)ptr;
|
||||
for (os_size_t i = 0; i < len; i++) {
|
||||
fifo_peek_at(rb, i + offset, &rb_byte);
|
||||
if (rb_byte != external_ptr[i]) {
|
||||
return (int)rb_byte - (int)external_ptr[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在FIFO中查找特定模式
|
||||
* @return: 找到则返回模式起始位置相对于head的偏移量,未找到返回-1
|
||||
*/
|
||||
os_size_t fifo_find(fifo_t *rb, os_size_t offset, const void *pattern, os_size_t pattern_len) {
|
||||
if (!rb || !pattern || pattern_len == 0) {
|
||||
return -1u;
|
||||
}
|
||||
|
||||
os_size_t data_size = fifo_count(rb);
|
||||
if(offset > data_size){
|
||||
return -1u; // 开始查找位置错误了
|
||||
}
|
||||
|
||||
if (pattern_len > (data_size - offset) ) {
|
||||
return -1u; // 模式长度超过缓冲区数据量,不可能找到
|
||||
}
|
||||
|
||||
// 遍历缓冲区中所有可能的起始位置
|
||||
// 最大起始偏移为 count - pattern_len
|
||||
os_size_t max_offset = data_size - offset - pattern_len;
|
||||
|
||||
for (os_size_t i = 0; i <= max_offset; i++) {
|
||||
// 构造一个临时的“视图”或使用辅助函数比较从offset开始的pattern_len个字节
|
||||
// 由于fifo_memcmp是从head开始比较,我们需要一种方法从任意offset开始比较
|
||||
|
||||
// 方法:逐字节比较
|
||||
os_bool_t match = OS_TRUE;
|
||||
const uint8_t *pat = (const uint8_t *)pattern;
|
||||
|
||||
for (os_size_t j = 0; j < pattern_len; j++) {
|
||||
uint8_t rb_byte;
|
||||
if (fifo_peek_at(rb, i + offset + j, &rb_byte)!=OS_ERR_OK) {
|
||||
match = OS_FALSE;
|
||||
break;
|
||||
}
|
||||
if (rb_byte != pat[j]) {
|
||||
match = OS_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1u;
|
||||
}
|
||||
|
||||
unsigned long fifo_strtoul(fifo_t* self, os_size_t* endptr /*从哪里开始转换*/, int base) {
|
||||
os_size_t idx = endptr?(*endptr):0;
|
||||
unsigned long acc = 0;
|
||||
uint8_t c = 0xff;
|
||||
unsigned long cutoff;
|
||||
int neg = 0, any, cutlim;
|
||||
((void)neg);
|
||||
|
||||
fifo_peek_at(self, idx, &c);
|
||||
// 1. 跳过前导空白字符
|
||||
while (isspace((unsigned char)c)) {
|
||||
idx++;
|
||||
}
|
||||
|
||||
// 2. 处理可选的正负号 (strtoul 忽略负号,但会消耗它)
|
||||
if (/* *s == '-'*/ fifo_offset_is(self, idx, '-')) {
|
||||
neg = 1;
|
||||
idx++;
|
||||
} else if (/* *s == '+' */ fifo_offset_is(self, idx, '+')) {
|
||||
idx++;
|
||||
}
|
||||
|
||||
// 3. 确定基数
|
||||
if (base == 0) {
|
||||
if (/* *s == '0' */ fifo_offset_is(self, idx, '0')) {
|
||||
if (/* *(s + 1) == 'x' || *(s + 1) == 'X' */
|
||||
fifo_offset_is(self, idx+1, 'x')
|
||||
|| fifo_offset_is(self, idx+1, 'X') )
|
||||
{
|
||||
base = 16;
|
||||
idx += 2; // 跳过 0x
|
||||
} else {
|
||||
base = 8;
|
||||
idx++; // 跳过 0
|
||||
}
|
||||
} else {
|
||||
base = 10;
|
||||
}
|
||||
} else if (base == 16) {
|
||||
if (/* *s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X') */
|
||||
fifo_offset_is(self, idx, '0')
|
||||
&& (fifo_offset_is(self, idx+1, 'x') || fifo_offset_is(self, idx+1, 'X')) )
|
||||
{
|
||||
idx += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 预计算溢出检查边界
|
||||
cutoff = ULONG_MAX / (unsigned long)base;
|
||||
cutlim = ULONG_MAX % (unsigned long)base;
|
||||
|
||||
// 5. 转换数字
|
||||
any = 0; // 标记是否已读取到有效数字
|
||||
for (; ; idx++) {
|
||||
// c = (unsigned char)*s;
|
||||
fifo_peek_at(self, idx, &c);
|
||||
|
||||
// 将字符转换为数值
|
||||
if (c >= '0' && c <= '9') {
|
||||
c -= '0';
|
||||
} else if (c >= 'A' && c <= 'Z') {
|
||||
c -= 'A' - 10;
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
c -= 'a' - 10;
|
||||
} else {
|
||||
break; // 非数字字符,停止解析
|
||||
}
|
||||
|
||||
// 检查字符是否在当前基数范围内
|
||||
if (c >= base) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查溢出
|
||||
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) {
|
||||
any = -1;
|
||||
break;
|
||||
} else {
|
||||
any = 1;
|
||||
acc *= base;
|
||||
acc += c;
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 处理结果和错误
|
||||
if (any < 0) {
|
||||
acc = ULONG_MAX;
|
||||
// errno = ERANGE;
|
||||
} else if (!any) {
|
||||
// 没有进行任何转换
|
||||
// if (endptr) {
|
||||
// *endptr = (char *)nptr;
|
||||
// }
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 设置 endptr 指向第一个未转换的字符
|
||||
if (endptr) {
|
||||
*endptr = idx;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
#ifndef INCLUDED_FIFO_H
|
||||
#define INCLUDED_FIFO_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
#ifndef INCLUDED_OS_COMPILER_H
|
||||
#include <os_compiler.h>
|
||||
#endif /*INCLUDED_OS_COMPILER_H*/
|
||||
|
||||
#ifndef INCLUDED_OS_MACROS_H
|
||||
#include <os_macros.h>
|
||||
#endif /*INCLUDED_OS_MACROS_H*/
|
||||
|
||||
|
||||
|
||||
/* ==================================================================================================== */
|
||||
/* 类型 */
|
||||
|
||||
|
||||
typedef struct fifo_t{
|
||||
uint8_t* buffer;
|
||||
os_size_t buffer_size;
|
||||
os_size_t write_idx;
|
||||
os_size_t read_idx;
|
||||
}fifo_t;
|
||||
|
||||
/* ==================================================================================================== */
|
||||
/* 接口 */
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void fifo_init(fifo_t* self, uint8_t* buffer, os_size_t buffer_size){
|
||||
OS_ASSERT(self);
|
||||
OS_ASSERT(buffer);
|
||||
OS_ASSERT(buffer_size>1);
|
||||
|
||||
self->buffer = buffer;
|
||||
self->buffer_size = buffer_size;
|
||||
self->write_idx = 0;
|
||||
self->read_idx = 0;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void fifo_clear(fifo_t* self){
|
||||
self->read_idx = self->write_idx = 0;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_bool_t fifo_is_empty(fifo_t* self){
|
||||
return (self->write_idx==self->read_idx);
|
||||
}
|
||||
|
||||
// 容量,实际可以存放的字节数
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_size_t fifo_capacity(fifo_t* self){
|
||||
return self->buffer_size-1;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_bool_t fifo_is_full(fifo_t* self){
|
||||
os_size_t next_write_idx = self->write_idx + 1;
|
||||
if(next_write_idx>=self->buffer_size){
|
||||
next_write_idx = 0;
|
||||
}
|
||||
return (next_write_idx==self->read_idx)?OS_TRUE:OS_FALSE;
|
||||
}
|
||||
|
||||
// 数量, 当前buffer里已经有的数据量
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_size_t fifo_count(fifo_t* self){
|
||||
if(self->write_idx >= self->read_idx){
|
||||
return (self->write_idx - self->read_idx);
|
||||
}else{
|
||||
return (self->buffer_size - self->read_idx) + self->write_idx;
|
||||
}
|
||||
}
|
||||
|
||||
// 空间, 还可以写入多少字节数据
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_size_t fifo_space(fifo_t* self){
|
||||
os_size_t count = 0;
|
||||
if(self->write_idx >= self->read_idx){
|
||||
count = (self->write_idx - self->read_idx);
|
||||
}else{
|
||||
count = (self->buffer_size - self->read_idx) + self->write_idx;
|
||||
}
|
||||
return self->buffer_size - 1 - count;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_err_t fifo_skip(fifo_t* self, os_size_t offset){
|
||||
os_size_t data_sz = fifo_count(self);
|
||||
if(offset > data_sz){
|
||||
return OS_ERR_FULL;
|
||||
}
|
||||
|
||||
os_size_t read_idx = self->read_idx;
|
||||
self->read_idx = (read_idx + offset) % self->buffer_size;
|
||||
|
||||
return OS_ERR_OK;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
os_bool_t fifo_offset_is(fifo_t* self, os_size_t offset, uint8_t data){
|
||||
OS_ASSERT(offset < fifo_count(self));
|
||||
os_size_t read_idx = (self->read_idx + offset) % self->buffer_size;
|
||||
return (data == self->buffer[read_idx])?OS_TRUE:OS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
// 在尾部写入数据
|
||||
os_err_t fifo_put(fifo_t* self, uint8_t data);
|
||||
|
||||
// 从头部获取数据
|
||||
os_err_t fifo_get(fifo_t* self, uint8_t* data);
|
||||
|
||||
// 批量写入数据
|
||||
os_size_t fifo_write(fifo_t* self, uint8_t* data, os_size_t size);
|
||||
|
||||
// 批量读取数据
|
||||
os_size_t fifo_read(fifo_t* self, uint8_t* buf, os_size_t size);
|
||||
|
||||
os_size_t fifo_write_fast(fifo_t* rb, const uint8_t * data, os_size_t len);
|
||||
|
||||
os_size_t fifo_read_fast(fifo_t* rb, uint8_t * data, os_size_t len);
|
||||
|
||||
int fifo_memcmp(fifo_t *rb, os_size_t offset, const void *ptr, os_size_t len);
|
||||
|
||||
os_size_t fifo_peek_bulk(fifo_t* rb, os_size_t offset, uint8_t* data, os_size_t len);
|
||||
|
||||
os_err_t fifo_peek_at(fifo_t* self, os_size_t offset, uint8_t * data);
|
||||
|
||||
os_size_t fifo_find(fifo_t *rb, os_size_t offset, const void *pattern, os_size_t pattern_len);
|
||||
|
||||
unsigned long fifo_strtoul(fifo_t* self, os_size_t* endptr /*从哪里开始转换, 可以为空*/, int base /*0, 8, 10, 16 进制*/);
|
||||
|
||||
#endif /*INCLUDED_FIFO_H*/
|
||||
@@ -0,0 +1,485 @@
|
||||
#include <fixed_rbtree.h>
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
#define RED 'R'
|
||||
#define BLACK 'B'
|
||||
|
||||
typedef fixed_rbtree_t rbtree_t;
|
||||
typedef fixed_rbtree_node_t rbtree_node_t;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_init(rbtree_t* tree, rbtree_node_t* self, void* key, void* val){
|
||||
self->left = self->right = self->parent = 0;
|
||||
self->color = RED;
|
||||
self->key = key;
|
||||
self->val = val;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_destroy(rbtree_t* tree, rbtree_node_t* x){
|
||||
pool_free(&tree->node_pool, x);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void rotate_left(rbtree_t* self, rbtree_node_t* x){
|
||||
rbtree_node_t * y = x->right;
|
||||
x->right = y->left;
|
||||
if(y->left){
|
||||
y->left->parent = x;
|
||||
}
|
||||
y->parent = x->parent;
|
||||
if(!x->parent){
|
||||
self->root = y;
|
||||
} else{
|
||||
if(x->parent->left==x){
|
||||
x->parent->left = y;
|
||||
}else{
|
||||
x->parent->right = y;
|
||||
}
|
||||
}
|
||||
y->left = x;
|
||||
x->parent = y;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void rotate_right(rbtree_t* self, rbtree_node_t* y){
|
||||
rbtree_node_t * x = y->left;
|
||||
y->left = x->right;
|
||||
if(x->right){
|
||||
x->right->parent = y;
|
||||
}
|
||||
x->parent = y->parent;
|
||||
if(!y->parent){
|
||||
self->root = x;
|
||||
}else{
|
||||
if(y==y->parent->left){
|
||||
y->parent->left = x;
|
||||
}else{
|
||||
y->parent->right = x;
|
||||
}
|
||||
}
|
||||
x->right = y;
|
||||
y->parent = x;
|
||||
}
|
||||
|
||||
static fixed_rbtree_node_t* find(rbtree_t* self, const void* key, rbtree_node_t* x){
|
||||
while(x){
|
||||
int cmp = self->ops.cmp(key, x->key, self->ops.args);
|
||||
if(cmp < 0){
|
||||
x = x->left;
|
||||
}else if(cmp > 0){
|
||||
x = x->right;
|
||||
}else{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
rbtree_node_t * node_parent(rbtree_node_t* x){
|
||||
return (x!=NULL)?x->parent:NULL;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
char node_color(rbtree_node_t* x){
|
||||
return (x!=NULL)?x->color:BLACK;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
bool node_is_red(rbtree_node_t* x){
|
||||
return (node_color(x)==RED)?true:false;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
bool node_is_black(rbtree_node_t* x){
|
||||
return !node_is_red(x);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_set_black(rbtree_node_t* x){
|
||||
if(x){
|
||||
x->color = BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_set_red(rbtree_node_t* x){
|
||||
if(x){
|
||||
x->color = RED;
|
||||
}
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_set_color(rbtree_node_t* x, char color){
|
||||
if(x){
|
||||
x->color = color;
|
||||
}
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_set_parent(rbtree_node_t* x, rbtree_node_t* parent){
|
||||
if(x){
|
||||
x->parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_insert_fixup(rbtree_t * tree, rbtree_node_t* node){
|
||||
rbtree_node_t * parent=0;
|
||||
rbtree_node_t * gparent=0;
|
||||
|
||||
while(((parent = node->parent)!=NULL) && node_is_red(parent)){
|
||||
gparent = node_parent(parent);
|
||||
if(parent==gparent->left){
|
||||
rbtree_node_t * pUncle = gparent->right;
|
||||
if((pUncle!=NULL) && node_is_red(pUncle)){
|
||||
// Case 1条件:叔叔节点是红色
|
||||
node_set_black(pUncle);
|
||||
node_set_black(parent);
|
||||
node_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(parent->right==node){
|
||||
// Case 3条件:叔叔是黑色,且当前节点是右孩子
|
||||
rbtree_node_t * pTmp;
|
||||
rotate_left(tree, parent);
|
||||
pTmp = parent;
|
||||
parent = node;
|
||||
node = pTmp;
|
||||
}
|
||||
|
||||
// Case 2条件:叔叔是黑色,且当前节点是左孩子。
|
||||
node_set_black(parent);
|
||||
node_set_red(gparent);
|
||||
rotate_right(tree, gparent);
|
||||
}else{
|
||||
//若“z的父节点”是“z的祖父节点的右孩子”
|
||||
rbtree_node_t * pUncle = gparent->left;
|
||||
if((pUncle!=NULL) && node_is_red(pUncle)) {
|
||||
// Case 1条件:叔叔节点是红色
|
||||
node_set_black(pUncle);
|
||||
node_set_black(parent);
|
||||
node_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Case 2条件:叔叔是黑色,且当前节点是左孩子
|
||||
if(parent->left == node){
|
||||
rbtree_node_t * pTmp;
|
||||
rotate_right(tree, parent);
|
||||
pTmp = parent;
|
||||
parent = node;
|
||||
node = pTmp;
|
||||
}
|
||||
|
||||
// Case 3条件:叔叔是黑色,且当前节点是右孩子。
|
||||
node_set_black(parent);
|
||||
node_set_red(gparent);
|
||||
rotate_left(tree, gparent);
|
||||
}
|
||||
}
|
||||
node_set_black(tree->root);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_insert(rbtree_t* tree, rbtree_node_t* node){
|
||||
int cmp = 0;
|
||||
rbtree_node_t * y = NULL;
|
||||
rbtree_node_t * x = tree->root;
|
||||
|
||||
// 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。
|
||||
while (x) {
|
||||
y = x;
|
||||
cmp = tree->ops.cmp(node->key, x->key, tree->ops.args);
|
||||
if (cmp < 0)
|
||||
x = x->left;
|
||||
else
|
||||
x = x->right;
|
||||
}
|
||||
// y 是要插入的父节点
|
||||
node->parent = y;
|
||||
if(!y){
|
||||
// 插入根节点
|
||||
tree->root = node;
|
||||
}else{
|
||||
// 判断插入父节点的左边还是右边
|
||||
cmp = tree->ops.cmp(node->key, y->key, tree->ops.args);
|
||||
if(cmp < 0){
|
||||
y->left = node;
|
||||
}else{
|
||||
y->right = node;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 设置节点的颜色为红色
|
||||
node->color = RED;
|
||||
|
||||
// 3. 将它重新修正为一颗二叉查找树
|
||||
node_insert_fixup(tree, node);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_remove_fixeup(rbtree_t* tree, rbtree_node_t* node, rbtree_node_t* parent){
|
||||
rbtree_node_t * other;
|
||||
|
||||
while(parent!=NULL && (node==NULL || node_is_black(node)) && (node!=tree->root) ){
|
||||
if(parent->left == node){
|
||||
other= parent->right;
|
||||
if(node_is_red(other)){
|
||||
// Case 1: x的兄弟w是红色的
|
||||
node_set_black(other);
|
||||
node_set_red(parent);
|
||||
rotate_left(tree, parent);
|
||||
other = parent->right;
|
||||
}
|
||||
|
||||
if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL ||
|
||||
node_is_black(other->right))){
|
||||
// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
|
||||
node_set_red(other);
|
||||
node = parent;
|
||||
parent = node_parent(node);
|
||||
}else{
|
||||
if(other->right==NULL || node_is_black(other->right)){
|
||||
// Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
|
||||
node_set_black(other->left);
|
||||
node_set_red(other);
|
||||
rotate_right(tree, other);
|
||||
other = parent->right;
|
||||
}
|
||||
// Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
|
||||
node_set_color(other, node_color(parent));
|
||||
node_set_black(parent);
|
||||
node_set_black(other->right);
|
||||
rotate_left(tree, parent);
|
||||
node = tree->root;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
other= parent->left;
|
||||
if(node_is_red(other)){
|
||||
// Case 1: x的兄弟w是红色的
|
||||
node_set_black(other);
|
||||
node_set_red(parent);
|
||||
rotate_right(tree, parent);
|
||||
other = parent->left;
|
||||
}
|
||||
|
||||
if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL ||
|
||||
node_is_black(other->right))){
|
||||
// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
|
||||
node_set_red(other);
|
||||
node = parent;
|
||||
parent = node_parent(node);
|
||||
}else{
|
||||
if(other->left==NULL || node_is_black(other->left)){
|
||||
// Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
|
||||
node_set_black(other->right);
|
||||
node_set_red(other);
|
||||
rotate_left(tree, other);
|
||||
other= parent->left;
|
||||
}
|
||||
|
||||
// Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
|
||||
node_set_color(other, node_color(parent));
|
||||
node_set_black(parent);
|
||||
node_set_black(other->left);
|
||||
rotate_right(tree, parent);
|
||||
node = tree->root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node){
|
||||
node_set_black(node);
|
||||
}
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_remove(rbtree_t* tree, rbtree_node_t* node){
|
||||
rbtree_node_t * child=NULL;
|
||||
rbtree_node_t * parent=NULL;
|
||||
char color;
|
||||
|
||||
// 被删除节点的"左右孩子都不为空"的情况。
|
||||
if((node->left!=NULL) && (node->right!=NULL)){
|
||||
// 被删节点的后继节点。(称为"取代节点")
|
||||
// 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。
|
||||
|
||||
rbtree_node_t * replace = node;
|
||||
|
||||
// 获取后继节点
|
||||
replace = replace->right;
|
||||
while(replace->left){
|
||||
replace = replace->left;
|
||||
}
|
||||
|
||||
// "node节点"不是根节点(只有根节点不存在父节点)
|
||||
if(node_parent(node)!=NULL){
|
||||
if(node->parent->left == node){
|
||||
node->parent->left = replace;
|
||||
}else{
|
||||
node->parent->right = replace;
|
||||
}
|
||||
}else{
|
||||
// "node节点"是根节点,更新根节点。
|
||||
tree->root = replace;
|
||||
}
|
||||
|
||||
// child是"取代节点"的右孩子,也是需要"调整的节点"。
|
||||
// "取代节点"肯定不存在左孩子!因为它是一个后继节点。
|
||||
|
||||
child = replace->right;
|
||||
parent= node_parent(replace);
|
||||
|
||||
// 保存"取代节点"的颜色
|
||||
color = node_color(replace);
|
||||
|
||||
// "被删除节点"是"它的后继节点的父节点"
|
||||
if(parent == node){
|
||||
parent = replace;
|
||||
}else {
|
||||
// child 不为空
|
||||
if(child!=NULL){
|
||||
node_set_parent(child, parent);
|
||||
}
|
||||
parent->left = child;
|
||||
|
||||
replace->right = node->right;
|
||||
node_set_parent(node->right, replace);
|
||||
}
|
||||
|
||||
replace->parent = node->parent;
|
||||
replace->color = node->color;
|
||||
replace->left= node->left;
|
||||
node->left->parent = replace;
|
||||
|
||||
if(color==BLACK){
|
||||
node_remove_fixeup(tree, child, parent);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(node->left!=NULL){
|
||||
child = node->left;
|
||||
}else{
|
||||
child= node->right;
|
||||
}
|
||||
|
||||
parent = node->parent;
|
||||
color = node->color;
|
||||
if(child!=NULL){
|
||||
child->parent = parent;
|
||||
}
|
||||
|
||||
// "node节点"不是根节点
|
||||
if(parent){
|
||||
if(parent->left==node){
|
||||
parent->left = child;
|
||||
}else{
|
||||
parent->right = child;
|
||||
}
|
||||
}else{
|
||||
tree->root = child;
|
||||
}
|
||||
|
||||
|
||||
if(color==BLACK){
|
||||
node_remove_fixeup(tree, child, parent);
|
||||
}
|
||||
|
||||
}
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
void fixed_rbtree_init(fixed_rbtree_t* self, void* node_block, os_size_t node_block_size, fixed_rbtree_ops_t ops){
|
||||
pool_init(&self->node_pool, sizeof(fixed_rbtree_node_t));
|
||||
pool_add_block(&self->node_pool, node_block, node_block_size);
|
||||
self->ops = ops;
|
||||
self->root = 0;
|
||||
}
|
||||
|
||||
void fixed_rbtree_add_node_pool(fixed_rbtree_t* self, void* node_block, os_size_t node_block_size){
|
||||
pool_add_block(&self->node_pool, node_block, node_block_size);
|
||||
}
|
||||
|
||||
void fixed_rbtree_destroy(fixed_rbtree_t* self){
|
||||
while(self->root){
|
||||
fixed_rbtree_node_t* p = self->root;
|
||||
node_remove(self, self->root);
|
||||
node_destroy(self, p);
|
||||
}
|
||||
}
|
||||
|
||||
fixed_rbtree_node_t* fixed_rbtree_find(fixed_rbtree_t* self, const void* key){
|
||||
if(key==NULL) return NULL;
|
||||
return find(self, key, self->root);
|
||||
}
|
||||
|
||||
fixed_rbtree_node_t* fixed_rbtree_custom_find(fixed_rbtree_t* self, const void* key
|
||||
, fixed_rbtree_node_t* (*custom_find)(fixed_rbtree_t* tree, const void* key, fixed_rbtree_node_t* x, void* args)
|
||||
, void* args)
|
||||
{
|
||||
if(key==NULL) return NULL;
|
||||
return custom_find(self, key, self->root, args);
|
||||
}
|
||||
|
||||
os_err_t fixed_rbtree_insert(fixed_rbtree_t* self, void* key, void* val){
|
||||
fixed_rbtree_node_t* p = pool_alloc(&self->node_pool);
|
||||
if(!p){
|
||||
return OS_ERR_FAIL;
|
||||
}
|
||||
node_init(self, p, key, val);
|
||||
node_insert(self, p);
|
||||
return OS_ERR_OK;
|
||||
}
|
||||
|
||||
void fixed_rbtree_remove(fixed_rbtree_t* self, const void* key){
|
||||
fixed_rbtree_node_t * pNode = fixed_rbtree_find(self, key);
|
||||
if(pNode==NULL){
|
||||
return;
|
||||
}
|
||||
node_remove(self, pNode);
|
||||
node_destroy(self, pNode);
|
||||
}
|
||||
|
||||
void fixed_rbtree_remove_node(fixed_rbtree_t* self, fixed_rbtree_node_t* x){
|
||||
if(x==NULL) return;
|
||||
node_remove(self, x);
|
||||
node_destroy(self, x);
|
||||
}
|
||||
|
||||
static void in_order(fixed_rbtree_t* self, fixed_rbtree_node_t* x,
|
||||
int (*apply)(fixed_rbtree_t* tree, fixed_rbtree_node_t* x, void* args), void* args){
|
||||
if(x){
|
||||
in_order(self, x->left, apply, args);
|
||||
if(apply(self, x, args)==0){
|
||||
return;
|
||||
}
|
||||
in_order(self, x->right, apply, args);
|
||||
}
|
||||
}
|
||||
|
||||
void fixed_rbtree_inorder(fixed_rbtree_t* self
|
||||
, int (*apply)(fixed_rbtree_t* tree, fixed_rbtree_node_t* x, void* args), void* args){
|
||||
in_order(self, self->root, apply, args);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef INCLUDED_FIXED_RBTREE_H
|
||||
#define INCLUDED_FIXED_RBTREE_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
#ifndef INCLUDED_POOL_H
|
||||
#include <pool.h>
|
||||
#endif /*INCLUDED_POOL_H*/
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
typedef struct fixed_rbtree_node_s{
|
||||
struct fixed_rbtree_node_s* left;
|
||||
struct fixed_rbtree_node_s* right;
|
||||
struct fixed_rbtree_node_s* parent;
|
||||
char color;
|
||||
void* key;
|
||||
void* val;
|
||||
}fixed_rbtree_node_t;
|
||||
|
||||
typedef struct {
|
||||
int (*cmp)(const void* key_a, const void* key_b, void* args);
|
||||
void* args;
|
||||
}fixed_rbtree_ops_t;
|
||||
|
||||
typedef struct {
|
||||
fixed_rbtree_node_t* root;
|
||||
fixed_rbtree_ops_t ops;
|
||||
pool_t node_pool;
|
||||
}fixed_rbtree_t;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
// 初始化时指定一个 node 的对象池,最大只能容纳这些 node
|
||||
void fixed_rbtree_init(fixed_rbtree_t* self, void* node_block, os_size_t node_block_size, fixed_rbtree_ops_t ops);
|
||||
void fixed_rbtree_add_node_pool(fixed_rbtree_t* self, void* node_block, os_size_t node_block_size);
|
||||
void fixed_rbtree_destroy(fixed_rbtree_t* self);
|
||||
fixed_rbtree_node_t* fixed_rbtree_find(fixed_rbtree_t* self, const void* key);
|
||||
fixed_rbtree_node_t* fixed_rbtree_custom_find(fixed_rbtree_t* self, const void* key
|
||||
, fixed_rbtree_node_t* (*custom_find)(fixed_rbtree_t* tree, const void* key, fixed_rbtree_node_t* x, void* args)
|
||||
, void* args);
|
||||
os_err_t fixed_rbtree_insert(fixed_rbtree_t* self, void* key, void* val);
|
||||
void fixed_rbtree_remove(fixed_rbtree_t* self, const void* key);
|
||||
void fixed_rbtree_remove_node(fixed_rbtree_t* self, fixed_rbtree_node_t* x);
|
||||
void fixed_rbtree_inorder(fixed_rbtree_t* self
|
||||
, int (*apply)(fixed_rbtree_t* tree, fixed_rbtree_node_t* x, void* args), void* args);
|
||||
|
||||
#endif /*INCLUDED_FIXED_RBTREE_H*/
|
||||
@@ -0,0 +1,471 @@
|
||||
#include <fixed_rbtree_pool.h>
|
||||
#include "os_macros.h"
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
typedef fixed_rbtree_pool_t rbtree_t;
|
||||
typedef fixed_rbtree_pool_node_t rbtree_node_t;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
#define RED 'R'
|
||||
#define BLACK 'B'
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_init(rbtree_t* tree, rbtree_node_t* self, os_size_t obj_size, void* block, os_size_t block_size){
|
||||
self->left = self->right = self->parent = 0;
|
||||
self->color = RED;
|
||||
pool_init(&self->pool, obj_size);
|
||||
pool_add_block(&self->pool, block, block_size);
|
||||
}
|
||||
|
||||
static
|
||||
int node_cmp(const os_size_t obj_size, const rbtree_node_t* x, void* args){
|
||||
return (obj_size == x->pool.obj_size)?0:((obj_size > x->pool.obj_size)?1:-1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_destroy(rbtree_t* tree, rbtree_node_t* x){
|
||||
pool_free(&tree->node_pool, x);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void rotate_left(rbtree_t* self, rbtree_node_t* x){
|
||||
rbtree_node_t * y = x->right;
|
||||
x->right = y->left;
|
||||
if(y->left){
|
||||
y->left->parent = x;
|
||||
}
|
||||
y->parent = x->parent;
|
||||
if(!x->parent){
|
||||
self->root = y;
|
||||
} else{
|
||||
if(x->parent->left==x){
|
||||
x->parent->left = y;
|
||||
}else{
|
||||
x->parent->right = y;
|
||||
}
|
||||
}
|
||||
y->left = x;
|
||||
x->parent = y;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void rotate_right(rbtree_t* self, rbtree_node_t* y){
|
||||
rbtree_node_t * x = y->left;
|
||||
y->left = x->right;
|
||||
if(x->right){
|
||||
x->right->parent = y;
|
||||
}
|
||||
x->parent = y->parent;
|
||||
if(!y->parent){
|
||||
self->root = x;
|
||||
}else{
|
||||
if(y==y->parent->left){
|
||||
y->parent->left = x;
|
||||
}else{
|
||||
y->parent->right = x;
|
||||
}
|
||||
}
|
||||
x->right = y;
|
||||
y->parent = x;
|
||||
}
|
||||
|
||||
static rbtree_node_t* find(rbtree_t* self, const os_size_t obj_size, rbtree_node_t* x){
|
||||
while(x){
|
||||
int cmp = node_cmp(obj_size, x, 0);
|
||||
if(cmp < 0){
|
||||
x = x->left;
|
||||
}else if(cmp > 0){
|
||||
x = x->right;
|
||||
}else{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
rbtree_node_t * node_parent(rbtree_node_t* x){
|
||||
return (x!=NULL)?x->parent:NULL;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
char node_color(rbtree_node_t* x){
|
||||
return (x!=NULL)?x->color:BLACK;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
bool node_is_red(rbtree_node_t* x){
|
||||
return (node_color(x)==RED)?true:false;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
bool node_is_black(rbtree_node_t* x){
|
||||
return !node_is_red(x);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_set_black(rbtree_node_t* x){
|
||||
if(x){
|
||||
x->color = BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_set_red(rbtree_node_t* x){
|
||||
if(x){
|
||||
x->color = RED;
|
||||
}
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_set_color(rbtree_node_t* x, char color){
|
||||
if(x){
|
||||
x->color = color;
|
||||
}
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_set_parent(rbtree_node_t* x, rbtree_node_t* parent){
|
||||
if(x){
|
||||
x->parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_insert_fixup(rbtree_t* tree, rbtree_node_t* node){
|
||||
rbtree_node_t * parent=0;
|
||||
rbtree_node_t * gparent=0;
|
||||
|
||||
while(((parent = node->parent)!=NULL) && node_is_red(parent)){
|
||||
gparent = node_parent(parent);
|
||||
if(parent==gparent->left){
|
||||
rbtree_node_t * pUncle = gparent->right;
|
||||
if((pUncle!=NULL) && node_is_red(pUncle)){
|
||||
// Case 1条件:叔叔节点是红色
|
||||
node_set_black(pUncle);
|
||||
node_set_black(parent);
|
||||
node_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(parent->right==node){
|
||||
// Case 3条件:叔叔是黑色,且当前节点是右孩子
|
||||
rbtree_node_t * pTmp;
|
||||
rotate_left(tree, parent);
|
||||
pTmp = parent;
|
||||
parent = node;
|
||||
node = pTmp;
|
||||
}
|
||||
|
||||
// Case 2条件:叔叔是黑色,且当前节点是左孩子。
|
||||
node_set_black(parent);
|
||||
node_set_red(gparent);
|
||||
rotate_right(tree, gparent);
|
||||
}else{
|
||||
//若“z的父节点”是“z的祖父节点的右孩子”
|
||||
rbtree_node_t * pUncle = gparent->left;
|
||||
if((pUncle!=NULL) && node_is_red(pUncle)) {
|
||||
// Case 1条件:叔叔节点是红色
|
||||
node_set_black(pUncle);
|
||||
node_set_black(parent);
|
||||
node_set_red(gparent);
|
||||
node = gparent;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Case 2条件:叔叔是黑色,且当前节点是左孩子
|
||||
if(parent->left == node){
|
||||
rbtree_node_t * pTmp;
|
||||
rotate_right(tree, parent);
|
||||
pTmp = parent;
|
||||
parent = node;
|
||||
node = pTmp;
|
||||
}
|
||||
|
||||
// Case 3条件:叔叔是黑色,且当前节点是右孩子。
|
||||
node_set_black(parent);
|
||||
node_set_red(gparent);
|
||||
rotate_left(tree, gparent);
|
||||
}
|
||||
}
|
||||
node_set_black(tree->root);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_insert(rbtree_t* tree, rbtree_node_t* node){
|
||||
int cmp = 0;
|
||||
rbtree_node_t * y = NULL;
|
||||
rbtree_node_t * x = tree->root;
|
||||
|
||||
// 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。
|
||||
while (x) {
|
||||
y = x;
|
||||
cmp = node_cmp(node->pool.obj_size, x,0);
|
||||
if (cmp < 0)
|
||||
x = x->left;
|
||||
else
|
||||
x = x->right;
|
||||
}
|
||||
// y 是要插入的父节点
|
||||
node->parent = y;
|
||||
if(!y){
|
||||
// 插入根节点
|
||||
tree->root = node;
|
||||
}else{
|
||||
// 判断插入父节点的左边还是右边
|
||||
cmp = node_cmp(node->pool.obj_size, y, 0);
|
||||
if(cmp < 0){
|
||||
y->left = node;
|
||||
}else{
|
||||
y->right = node;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 设置节点的颜色为红色
|
||||
node->color = RED;
|
||||
|
||||
// 3. 将它重新修正为一颗二叉查找树
|
||||
node_insert_fixup(tree, node);
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_remove_fixeup(rbtree_t* tree, rbtree_node_t* node, rbtree_node_t* parent){
|
||||
rbtree_node_t * other;
|
||||
|
||||
while(parent!=NULL && (node==NULL || node_is_black(node)) && (node!=tree->root) ){
|
||||
if(parent->left == node){
|
||||
other= parent->right;
|
||||
if(node_is_red(other)){
|
||||
// Case 1: x的兄弟w是红色的
|
||||
node_set_black(other);
|
||||
node_set_red(parent);
|
||||
rotate_left(tree, parent);
|
||||
other = parent->right;
|
||||
}
|
||||
|
||||
if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL ||
|
||||
node_is_black(other->right))){
|
||||
// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
|
||||
node_set_red(other);
|
||||
node = parent;
|
||||
parent = node_parent(node);
|
||||
}else{
|
||||
if(other->right==NULL || node_is_black(other->right)){
|
||||
// Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
|
||||
node_set_black(other->left);
|
||||
node_set_red(other);
|
||||
rotate_right(tree, other);
|
||||
other = parent->right;
|
||||
}
|
||||
// Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
|
||||
node_set_color(other, node_color(parent));
|
||||
node_set_black(parent);
|
||||
node_set_black(other->right);
|
||||
rotate_left(tree, parent);
|
||||
node = tree->root;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
other= parent->left;
|
||||
if(node_is_red(other)){
|
||||
// Case 1: x的兄弟w是红色的
|
||||
node_set_black(other);
|
||||
node_set_red(parent);
|
||||
rotate_right(tree, parent);
|
||||
other = parent->left;
|
||||
}
|
||||
|
||||
if((other->left==NULL || node_is_black(other->left)) && (other->right==NULL ||
|
||||
node_is_black(other->right))){
|
||||
// Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
|
||||
node_set_red(other);
|
||||
node = parent;
|
||||
parent = node_parent(node);
|
||||
}else{
|
||||
if(other->left==NULL || node_is_black(other->left)){
|
||||
// Case 4: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
|
||||
node_set_black(other->right);
|
||||
node_set_red(other);
|
||||
rotate_left(tree, other);
|
||||
other= parent->left;
|
||||
}
|
||||
|
||||
// Case 3: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
|
||||
node_set_color(other, node_color(parent));
|
||||
node_set_black(parent);
|
||||
node_set_black(other->left);
|
||||
rotate_right(tree, parent);
|
||||
node = tree->root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node){
|
||||
node_set_black(node);
|
||||
}
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void node_remove(rbtree_t* tree, rbtree_node_t* node){
|
||||
rbtree_node_t * child=NULL;
|
||||
rbtree_node_t * parent=NULL;
|
||||
char color;
|
||||
|
||||
// 被删除节点的"左右孩子都不为空"的情况。
|
||||
if((node->left!=NULL) && (node->right!=NULL)){
|
||||
// 被删节点的后继节点。(称为"取代节点")
|
||||
// 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。
|
||||
|
||||
rbtree_node_t * replace = node;
|
||||
|
||||
// 获取后继节点
|
||||
replace = replace->right;
|
||||
while(replace->left){
|
||||
replace = replace->left;
|
||||
}
|
||||
|
||||
// "node节点"不是根节点(只有根节点不存在父节点)
|
||||
if(node_parent(node)!=NULL){
|
||||
if(node->parent->left == node){
|
||||
node->parent->left = replace;
|
||||
}else{
|
||||
node->parent->right = replace;
|
||||
}
|
||||
}else{
|
||||
// "node节点"是根节点,更新根节点。
|
||||
tree->root = replace;
|
||||
}
|
||||
|
||||
// child是"取代节点"的右孩子,也是需要"调整的节点"。
|
||||
// "取代节点"肯定不存在左孩子!因为它是一个后继节点。
|
||||
|
||||
child = replace->right;
|
||||
parent= node_parent(replace);
|
||||
|
||||
// 保存"取代节点"的颜色
|
||||
color = node_color(replace);
|
||||
|
||||
// "被删除节点"是"它的后继节点的父节点"
|
||||
if(parent == node){
|
||||
parent = replace;
|
||||
}else {
|
||||
// child 不为空
|
||||
if(child!=NULL){
|
||||
node_set_parent(child, parent);
|
||||
}
|
||||
parent->left = child;
|
||||
|
||||
replace->right = node->right;
|
||||
node_set_parent(node->right, replace);
|
||||
}
|
||||
|
||||
replace->parent = node->parent;
|
||||
replace->color = node->color;
|
||||
replace->left= node->left;
|
||||
node->left->parent = replace;
|
||||
|
||||
if(color==BLACK){
|
||||
node_remove_fixeup(tree, child, parent);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(node->left!=NULL){
|
||||
child = node->left;
|
||||
}else{
|
||||
child= node->right;
|
||||
}
|
||||
|
||||
parent = node->parent;
|
||||
color = node->color;
|
||||
if(child!=NULL){
|
||||
child->parent = parent;
|
||||
}
|
||||
|
||||
// "node节点"不是根节点
|
||||
if(parent){
|
||||
if(parent->left==node){
|
||||
parent->left = child;
|
||||
}else{
|
||||
parent->right = child;
|
||||
}
|
||||
}else{
|
||||
tree->root = child;
|
||||
}
|
||||
|
||||
|
||||
if(color==BLACK){
|
||||
node_remove_fixeup(tree, child, parent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
void fixed_rbtree_pool_init(fixed_rbtree_pool_t* self, void* node_block, os_size_t node_block_size){
|
||||
self->root = 0;
|
||||
pool_init(&self->node_pool, sizeof(fixed_rbtree_pool_node_t));
|
||||
pool_add_block(&self->node_pool, node_block, node_block_size);
|
||||
}
|
||||
|
||||
void fixed_rbtree_pool_add_node_pool(fixed_rbtree_pool_t* self, void* node_block, os_size_t node_block_size){
|
||||
pool_add_block(&self->node_pool, node_block, node_block_size);
|
||||
}
|
||||
|
||||
void fixed_rbtree_pool_destroy(fixed_rbtree_pool_t* self){
|
||||
while(self->root){
|
||||
rbtree_node_t * p = self->root;
|
||||
node_remove(self, p);
|
||||
node_destroy(self, p);
|
||||
}
|
||||
}
|
||||
|
||||
void fixed_rbtree_pool_add(fixed_rbtree_pool_t* self, os_size_t obj_size, void* block, os_size_t block_size){
|
||||
rbtree_node_t* x = find(self, obj_size, self->root);
|
||||
if(x==NULL){
|
||||
x = pool_alloc(&self->node_pool);
|
||||
node_init(self, x, obj_size, block, block_size);
|
||||
node_insert(self, x);
|
||||
}else{
|
||||
pool_add_block(&x->pool, block, block_size);
|
||||
}
|
||||
}
|
||||
|
||||
void* fixed_rbtree_pool_alloc(fixed_rbtree_pool_t* self, os_size_t obj_size){
|
||||
rbtree_node_t * x = find(self, obj_size, self->root);
|
||||
OS_ASSERT(x, "No pool exist for obj_size: %"OS_PRIu, obj_size);
|
||||
if(x==NULL){
|
||||
return NULL;
|
||||
}
|
||||
return pool_alloc(&x->pool);
|
||||
}
|
||||
|
||||
void fixed_rbtree_pool_free(fixed_rbtree_pool_t* self, os_size_t obj_size, void* ptr){
|
||||
if(!ptr) return;
|
||||
rbtree_node_t * x = find(self, obj_size, self->root);
|
||||
OS_ASSERT(x, "No pool exist for obj_size: %"OS_PRIu, obj_size);
|
||||
if(x==NULL){
|
||||
return;
|
||||
}
|
||||
pool_free(&self->node_pool, ptr);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef INCLUDED_FIXED_RBTREE_POOL_H
|
||||
#define INCLUDED_FIXED_RBTREE_POOL_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
#ifndef INCLUDED_POOL_H
|
||||
#include <pool.h>
|
||||
#endif /*INCLUDED_POOL_H*/
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/*
|
||||
* 1. 只能支持固定数量的 node 节点
|
||||
* 2. 根据 obj_size 建立不同的对象池,同样大小的对象都通过同一个池进行分配
|
||||
*/
|
||||
|
||||
typedef struct fixed_rbtree_pool_block_s{
|
||||
struct fixed_rbtree_pool_block_s* left;
|
||||
struct fixed_rbtree_pool_block_s* right;
|
||||
struct fixed_rbtree_pool_block_s* parent;
|
||||
char color;
|
||||
pool_t pool;
|
||||
}fixed_rbtree_pool_node_t;
|
||||
|
||||
typedef struct {
|
||||
fixed_rbtree_pool_node_t* root;
|
||||
pool_t node_pool;
|
||||
}fixed_rbtree_pool_t;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
void fixed_rbtree_pool_init(fixed_rbtree_pool_t* self, void* node_block, os_size_t node_block_size);
|
||||
void fixed_rbtree_pool_add_node_pool(fixed_rbtree_pool_t* self, void* node_block, os_size_t node_block_size);
|
||||
void fixed_rbtree_pool_destroy(fixed_rbtree_pool_t* self);
|
||||
|
||||
void fixed_rbtree_pool_add(fixed_rbtree_pool_t* self, os_size_t obj_size, void* block, os_size_t block_size);
|
||||
void* fixed_rbtree_pool_alloc(fixed_rbtree_pool_t* self, os_size_t obj_size);
|
||||
void fixed_rbtree_pool_free(fixed_rbtree_pool_t* self, os_size_t obj_size, void* ptr);
|
||||
|
||||
#endif /*INCLUDED_FIXED_RBTREE_POOL_H*/
|
||||
@@ -0,0 +1,68 @@
|
||||
#include <ieee_float.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int ieee_float_cmp(const float a, const float b, const float maxDiff){
|
||||
float diff = a-b;
|
||||
if(fabsf(diff) <= maxDiff){
|
||||
return 0;
|
||||
}else{
|
||||
return (diff > maxDiff)?1:-1;
|
||||
}
|
||||
}
|
||||
|
||||
int ieee_double_cmp(const double a, const double b, const double maxDiff){
|
||||
double diff = a-b;
|
||||
if(fabs(diff) <= maxDiff){
|
||||
return 0;
|
||||
}else{
|
||||
return (diff > maxDiff)?1:-1;
|
||||
}
|
||||
}
|
||||
|
||||
int ieee_float_UlpsCmp(const float a, const float b, const float maxFloatDiff, const int maxUlpsDiff){
|
||||
const float absDiff = fabsf(a-b);
|
||||
if(absDiff <= maxFloatDiff){
|
||||
return 0;
|
||||
}
|
||||
ieee_float_t A;
|
||||
ieee_float_t B;
|
||||
A.value.f = a;
|
||||
B.value.f = b;
|
||||
if(A.value.IEEE754.sign != B.value.IEEE754.sign){
|
||||
return (int)(B.value.IEEE754.sign - A.value.IEEE754.sign);
|
||||
}
|
||||
|
||||
const int ulpsDiff = abs((int)(A.value.uint - B.value.uint));
|
||||
if(ulpsDiff <= maxUlpsDiff){
|
||||
return 0;
|
||||
}
|
||||
return (ulpsDiff > maxUlpsDiff)?1:-1;
|
||||
}
|
||||
|
||||
int ieee_double_UlpsCmp(const double a, const double b, const double maxFloatDiff, const int maxUlpsDiff){
|
||||
const double absDiff = fabs(a-b);
|
||||
if(absDiff <= maxFloatDiff){
|
||||
return 0;
|
||||
}
|
||||
ieee_double_t A = {.value.f = a};
|
||||
ieee_double_t B = {.value.f = b};
|
||||
if(A.value.IEEE754.sign != B.value.IEEE754.sign){
|
||||
return (int)(B.value.IEEE754.sign - A.value.IEEE754.sign);
|
||||
}
|
||||
|
||||
const int ulpsDiff = abs((int)(A.value.uint - B.value.uint));
|
||||
if(ulpsDiff <= maxUlpsDiff){
|
||||
return 0;
|
||||
}
|
||||
return (ulpsDiff > maxUlpsDiff)?1:-1;
|
||||
}
|
||||
|
||||
bool ieee_float_is_zero(const float a, const float maxDiff){
|
||||
return (fabsf(a) <= maxDiff)?true:false;
|
||||
}
|
||||
|
||||
bool ieee_double_is_zero(const double a, const double maxDiff){
|
||||
return (fabs(a) <= maxDiff)?true:false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#ifndef INCLUDED_IEEE_FLOAT_H
|
||||
#define INCLUDED_IEEE_FLOAT_H
|
||||
|
||||
#ifndef INCLUDED_STDINT_H
|
||||
#define INCLUDED_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif /*INCLUDED_STDINT_H*/
|
||||
|
||||
#ifndef INCLUDED_FLOAT_H
|
||||
#define INCLUDED_FLOAT_H
|
||||
#include <float.h>
|
||||
#endif /*INCLUDED_FLOAT_H*/
|
||||
|
||||
#ifndef INCLUDED_STDBOOL_H
|
||||
#define INCLUDED_STDBOOL_H
|
||||
#include <stdbool.h>
|
||||
#endif /*INCLUDED_STDBOOL_H*/
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
typedef struct {
|
||||
union{
|
||||
struct{
|
||||
uint32_t sign:1;
|
||||
uint32_t exponent:8;
|
||||
uint32_t mantissa:23;
|
||||
}IEEE754;
|
||||
uint32_t uint;
|
||||
float f;
|
||||
}value;
|
||||
}ieee_float_t;
|
||||
|
||||
typedef struct {
|
||||
union{
|
||||
struct{
|
||||
uint64_t sign:1;
|
||||
uint64_t exponent:11;
|
||||
uint64_t mantissa:52;
|
||||
}IEEE754;
|
||||
uint64_t uint;
|
||||
double f;
|
||||
}value;
|
||||
}ieee_double_t;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
#define IEEE_FLOAT_POSITIVE_INFINITY (1.0f/0.0f)
|
||||
#define IEEE_FLOAT_NEGATIVE_INFINITY (-1.0f/0.0f)
|
||||
#define IEEE_FLOAT_NAN (0.0f/0.0f)
|
||||
|
||||
#define IEEE_FLOAT_EPSILON (FLT_EPSILON)
|
||||
#define IEEE_DOUBLE_EPSILON (DBL_EPSILON)
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
int ieee_float_cmp(const float a, const float b, const float maxDiff);
|
||||
int ieee_double_cmp(const double a, const double b, const double maxDiff);
|
||||
|
||||
// 当将 float 看作 uint32 时进行比较,maxUlpsDiff 就是作为无符号整数允许的最大差异,一般取 `1` 就可以
|
||||
// maxFloatDiff 一般取 IEEE_FLOAT_EPSILON, 是将数值作为 float 进行比较,但是如果两个 float 无法完成比较,就可以通过
|
||||
// 无符号整数的形式来进行比较
|
||||
int ieee_float_UlpsCmp(const float a, const float b, const float maxFloatDiff, const int maxUlpsDiff);
|
||||
int ieee_double_UlpsCmp(const double a, const double b, const double maxFloatDiff, const int maxUlpsDiff);
|
||||
|
||||
bool ieee_float_is_zero(const float a, const float maxDiff);
|
||||
bool ieee_double_is_zero(const double a, const double maxDiff);
|
||||
|
||||
#endif /*INCLUDED_IEEE_FLOAT_H*/
|
||||
@@ -0,0 +1,23 @@
|
||||
#include <pool.h>
|
||||
#include "os_macros.h"
|
||||
#include "os_align.h"
|
||||
|
||||
void pool_add_block(pool_t* self, void* block, os_size_t block_size){
|
||||
// 对齐
|
||||
os_uintptr_t init_start = (os_uintptr_t)block; // 初始的位置
|
||||
os_uintptr_t start = OS_ALIGN_UP(init_start, OS_ALIGN_SIZE); // 向上对齐后的位置
|
||||
block_size -= (start - init_start); // 实际使用的块大小
|
||||
|
||||
OS_ASSERT(block_size > self->obj_size);
|
||||
|
||||
// 将内存块拆成 obj_size 大小
|
||||
os_size_t count = block_size/self->obj_size;
|
||||
uint8_t * last = &(((uint8_t*)start)[(count - 1) * self->obj_size]);
|
||||
for(uint8_t * p = (uint8_t*)start; p<last; p+=self->obj_size){
|
||||
((pool_link_t*)p)->next = (pool_link_t*)(p+self->obj_size);
|
||||
}
|
||||
((pool_link_t*)last)->next = 0;
|
||||
self->free_list_p = (pool_link_t*)start;
|
||||
self->capacity += count;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef INCLUDED_POOL_H
|
||||
#define INCLUDED_POOL_H
|
||||
|
||||
#ifndef INCLUDED_OS_TYPES_H
|
||||
#include <os_types.h>
|
||||
#endif /*INCLUDED_OS_TYPES_H*/
|
||||
|
||||
#ifndef INCLUDED_OS_COMPILER_H
|
||||
#include <os_compiler.h>
|
||||
#endif /*INCLUDED_OS_COMPILER_H*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* https://www.gingerbill.org/article/2019/02/16/memory-allocation-strategies-004/ */
|
||||
|
||||
typedef struct pool_link_s {
|
||||
struct pool_link_s* next;
|
||||
}pool_link_t;
|
||||
|
||||
typedef struct {
|
||||
pool_link_t* free_list_p; /* 对象内存链表,每个节点指向一个对象内存地址 */
|
||||
os_size_t obj_size; /* 每个对象的大小 */
|
||||
os_size_t capacity; /* 池中最大能分配的对象数量 */
|
||||
os_size_t count; /* 已分配的对象数量 */
|
||||
}pool_t;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
void pool_add_block(pool_t* self, void* block, os_size_t block_size);
|
||||
|
||||
/*
|
||||
* pool_t pool;
|
||||
* uint8_t block1[512];
|
||||
* uint8_t block2[1024];
|
||||
* uint8_t block3[256];
|
||||
*
|
||||
* pool_init(&pool, 16);
|
||||
* pool_add_block(&pool, block1, 512);
|
||||
* pool_add_block(&pool, block2, 1024);
|
||||
* pool_add_block(&pool, block3, 256);
|
||||
*
|
||||
* void* obj1 = pool_alloc(&pool);
|
||||
* ...
|
||||
* pool_free(&pool, obj1);
|
||||
*
|
||||
*/
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void pool_init(pool_t* self, os_size_t obj_size){
|
||||
self->free_list_p = 0;
|
||||
self->obj_size = obj_size;
|
||||
self->count = 0;
|
||||
self->capacity = 0;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void* pool_alloc(pool_t* self){
|
||||
if(!self->free_list_p){
|
||||
return NULL;
|
||||
}
|
||||
pool_link_t* p = self->free_list_p;
|
||||
self->free_list_p = p->next;
|
||||
self->count++;
|
||||
return p;
|
||||
}
|
||||
|
||||
OS_STATIC_FORCE_INLINE
|
||||
void pool_free(pool_t* self, void* obj){
|
||||
pool_link_t* p_link = (pool_link_t*) obj;
|
||||
p_link->next = self->free_list_p;
|
||||
self->free_list_p = p_link;
|
||||
self->count--;
|
||||
}
|
||||
|
||||
|
||||
#endif /*INCLUDED_POOL_H*/
|
||||
Reference in New Issue
Block a user