ByteRingBuffer 接口完善
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
#include <c_FastByteRingBuffer.h>
|
||||
#include <c_Memory.h>
|
||||
#include <c_Alignment.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
C_STATIC_FORCE_INLINE
|
||||
c_size_t round_up_to_pow2(c_size_t v) {
|
||||
@@ -82,23 +87,46 @@ c_err_t c_FastByteRingBuffer_ReadByte(c_FastByteRingBuffer_t* self, uint8_t* out
|
||||
return C_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
// 區塊寫入
|
||||
|
||||
c_size_t c_FastByteRingBuffer_WriteBuffer(c_FastByteRingBuffer_t* self, const uint8_t* src, c_size_t len) {
|
||||
if (!self || !self->buffer || !src || len == 0) return 0;
|
||||
if (self->is_full) return 0;
|
||||
|
||||
c_size_t bytes_written = 0;
|
||||
while (bytes_written < len && !self->is_full) {
|
||||
self->buffer[self->tail] = src[bytes_written];
|
||||
self->tail = (self->tail + 1) & self->mask;
|
||||
// Calculate free space directly using fast size validation tracking
|
||||
c_size_t current_size = c_FastByteRingBuffer_GetSize(self);
|
||||
c_size_t free_space = self->capacity - current_size;
|
||||
|
||||
if (self->tail == self->head) {
|
||||
self->is_full = C_TRUE;
|
||||
}
|
||||
bytes_written++;
|
||||
// Clamp write operations to avoid overrunning existing readable elements
|
||||
if (len > free_space) {
|
||||
len = free_space;
|
||||
}
|
||||
return bytes_written;
|
||||
|
||||
if (len == 0) return 0;
|
||||
|
||||
// Segment 1: Write from tail index up to the physical end boundary of the backing array
|
||||
c_size_t space_to_end = self->capacity - self->tail;
|
||||
c_size_t first_chunk = (len < space_to_end) ? len : space_to_end;
|
||||
memcpy(self->buffer + self->tail, src, first_chunk);
|
||||
|
||||
// Segment 2: Wrap around to index 0 using bitwise optimizations if a split block configuration is required
|
||||
c_size_t second_chunk = len - first_chunk;
|
||||
if (second_chunk > 0) {
|
||||
memcpy(self->buffer, src + first_chunk, second_chunk);
|
||||
self->tail = second_chunk; // The wrapped tail calculation reduces cleanly to second_chunk
|
||||
} else {
|
||||
// Fast tail stepping path utilizing the mask constant
|
||||
self->tail = (self->tail + first_chunk) & self->mask;
|
||||
}
|
||||
|
||||
// Set the full status flag if the cursors perfectly intersect
|
||||
if (self->tail == self->head) {
|
||||
self->is_full = C_TRUE;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
// 區塊讀取
|
||||
c_size_t c_FastByteRingBuffer_ReadBuffer(c_FastByteRingBuffer_t* self, uint8_t* dest, c_size_t len) {
|
||||
if (!self || !self->buffer || !dest || len == 0) return 0;
|
||||
@@ -133,3 +161,370 @@ c_bool_t c_FastByteRingBuffer_IsFull(const c_FastByteRingBuffer_t* self) {
|
||||
if (!self) return C_FALSE;
|
||||
return self->is_full;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
/* */
|
||||
|
||||
|
||||
|
||||
C_STATIC_FORCE_INLINE
|
||||
uint8_t c_FastByteRingBuffer_GetAtRelativeInternal(const c_FastByteRingBuffer_t* self, c_size_t relative_offset) {
|
||||
c_size_t absolute_index = (self->head + relative_offset) & self->mask;
|
||||
return self->buffer[absolute_index];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
void c_FastByteRingBuffer_WriteByteOverwrite(c_FastByteRingBuffer_t* self, uint8_t byte) {
|
||||
if (!self || !self->buffer) return;
|
||||
|
||||
if (self->is_full) {
|
||||
// 環形陣列已滿時,強制將讀取指標向前推一格,拋棄最舊數據
|
||||
self->head = (self->head + 1) & self->mask;
|
||||
}
|
||||
|
||||
self->buffer[self->tail] = byte;
|
||||
self->tail = (self->tail + 1) & self->mask;
|
||||
|
||||
if (self->tail == self->head) {
|
||||
self->is_full = C_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
c_size_t c_FastByteRingBuffer_WriteBufferOverwrite(c_FastByteRingBuffer_t* self, const uint8_t* src, c_size_t len) {
|
||||
if (!self || !self->buffer || !src || len == 0) return 0;
|
||||
|
||||
// 邊界極端優化:如果寫入長度超過總容量,只有最後符合容量大小的數據能存活
|
||||
if (len >= self->capacity) {
|
||||
src += (len - self->capacity);
|
||||
len = self->capacity;
|
||||
|
||||
memcpy(self->buffer, src, len);
|
||||
self->head = 0;
|
||||
self->tail = 0;
|
||||
self->is_full = C_TRUE;
|
||||
return len;
|
||||
}
|
||||
|
||||
c_size_t size = c_FastByteRingBuffer_GetSize(self);
|
||||
c_size_t free_space = self->capacity - size;
|
||||
|
||||
// 若寫入長度大於剩餘空間,計算溢出量並自動同步前推 head 指標
|
||||
if (len > free_space) {
|
||||
c_size_t overwrite_count = len - free_space;
|
||||
self->head = (self->head + overwrite_count) & self->mask;
|
||||
}
|
||||
|
||||
// 分段一:從 tail 寫入到物理內存陣列末尾
|
||||
c_size_t space_to_end = self->capacity - self->tail;
|
||||
c_size_t first_chunk = (len < space_to_end) ? len : space_to_end;
|
||||
memcpy(self->buffer + self->tail, src, first_chunk);
|
||||
|
||||
// 分段二:折返到內存陣列開頭寫入剩餘數據
|
||||
c_size_t second_chunk = len - first_chunk;
|
||||
if (second_chunk > 0) {
|
||||
memcpy(self->buffer, src + first_chunk, second_chunk);
|
||||
self->tail = second_chunk;
|
||||
} else {
|
||||
self->tail = (self->tail + first_chunk) & self->mask;
|
||||
}
|
||||
|
||||
if (self->tail == self->head) {
|
||||
self->is_full = C_TRUE;
|
||||
} else {
|
||||
self->is_full = C_FALSE;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
c_err_t c_FastByteRingBuffer_PeekByte(const c_FastByteRingBuffer_t* self, uint8_t* out_byte) {
|
||||
if (!self || !self->buffer || !out_byte) return C_ERR_INVALID_PARAM;
|
||||
if (c_FastByteRingBuffer_IsEmpty(self)) return C_ERR_OUT_OF_BOUNDS;
|
||||
|
||||
*out_byte = self->buffer[self->head];
|
||||
return C_SUCCESS;
|
||||
}
|
||||
|
||||
c_size_t c_FastByteRingBuffer_PeekBuffer(const c_FastByteRingBuffer_t* self, uint8_t* dest, c_size_t len) {
|
||||
if (!self || !self->buffer || !dest || len == 0) return 0;
|
||||
|
||||
c_size_t available_bytes = c_FastByteRingBuffer_GetSize(self);
|
||||
if (len > available_bytes) {
|
||||
len = available_bytes;
|
||||
}
|
||||
|
||||
if (len == 0) return 0;
|
||||
|
||||
// 複製標準讀取邏輯,但完全不變動真實核心 head 指標狀態
|
||||
c_size_t bytes_to_end = self->capacity - self->head;
|
||||
c_size_t first_chunk = (len < bytes_to_end) ? len : bytes_to_end;
|
||||
memcpy(dest, self->buffer + self->head, first_chunk);
|
||||
|
||||
c_size_t second_chunk = len - first_chunk;
|
||||
if (second_chunk > 0) {
|
||||
memcpy(dest + first_chunk, self->buffer, second_chunk);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
c_size_t c_FastByteRingBuffer_Discard(c_FastByteRingBuffer_t* self, c_size_t len) {
|
||||
if (!self || !self->buffer || len == 0) return 0;
|
||||
|
||||
c_size_t available_bytes = c_FastByteRingBuffer_GetSize(self);
|
||||
if (len > available_bytes) {
|
||||
len = available_bytes;
|
||||
}
|
||||
|
||||
if (len == 0) return 0;
|
||||
|
||||
self->head = (self->head + len) & self->mask;
|
||||
self->is_full = C_FALSE;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
const uint8_t* c_FastByteRingBuffer_GetReadPtr(const c_FastByteRingBuffer_t* self, c_size_t* out_contiguous_len) {
|
||||
if (!self || !self->buffer || !out_contiguous_len) return NULL;
|
||||
|
||||
*out_contiguous_len = 0;
|
||||
if (c_FastByteRingBuffer_IsEmpty(self)) return NULL;
|
||||
|
||||
if (self->tail > self->head) {
|
||||
*out_contiguous_len = self->tail - self->head;
|
||||
} else {
|
||||
*out_contiguous_len = self->capacity - self->head;
|
||||
}
|
||||
|
||||
return self->buffer + self->head;
|
||||
}
|
||||
|
||||
uint8_t* c_FastByteRingBuffer_GetWritePtr(const c_FastByteRingBuffer_t* self, c_size_t* out_contiguous_len) {
|
||||
if (!self || !self->buffer || !out_contiguous_len) return NULL;
|
||||
|
||||
*out_contiguous_len = 0;
|
||||
if (self->is_full) return NULL;
|
||||
|
||||
if (self->tail >= self->head) {
|
||||
*out_contiguous_len = self->capacity - self->tail;
|
||||
} else {
|
||||
*out_contiguous_len = self->head - self->tail;
|
||||
}
|
||||
|
||||
return self->buffer + self->tail;
|
||||
}
|
||||
|
||||
c_index_t c_FastByteRingBuffer_IndexOfByte(const c_FastByteRingBuffer_t* self, uint8_t target) {
|
||||
if (!self || !self->buffer) return C_ERR_NOT_FOUND;
|
||||
|
||||
c_size_t total_size = c_FastByteRingBuffer_GetSize(self);
|
||||
for (c_size_t offset = 0; offset < total_size; offset++) {
|
||||
if (c_FastByteRingBuffer_GetAtRelativeInternal(self, offset) == target) {
|
||||
return (c_index_t)offset;
|
||||
}
|
||||
}
|
||||
return C_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
c_index_t c_FastByteRingBuffer_IndexOfBuffer(const c_FastByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len) {
|
||||
if (!self || !self->buffer || !pattern || pattern_len == 0) return C_ERR_NOT_FOUND;
|
||||
|
||||
c_size_t total_size = c_FastByteRingBuffer_GetSize(self);
|
||||
if (pattern_len > total_size) return C_ERR_NOT_FOUND;
|
||||
|
||||
c_size_t max_search_offset = total_size - pattern_len;
|
||||
|
||||
for (c_size_t offset = 0; offset <= max_search_offset; offset++) {
|
||||
c_bool_t match_found = C_TRUE;
|
||||
|
||||
for (c_size_t p_idx = 0; p_idx < pattern_len; p_idx++) {
|
||||
if (c_FastByteRingBuffer_GetAtRelativeInternal(self, offset + p_idx) != pattern[p_idx]) {
|
||||
match_found = C_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match_found) {
|
||||
return (c_index_t)offset;
|
||||
}
|
||||
}
|
||||
return C_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
c_index_t c_FastByteRingBuffer_LastIndexOfBuffer(const c_FastByteRingBuffer_t* self, const uint8_t* pattern, c_size_t pattern_len) {
|
||||
if (!self || !self->buffer || !pattern || pattern_len == 0) return C_ERR_NOT_FOUND;
|
||||
|
||||
c_size_t total_size = c_FastByteRingBuffer_GetSize(self);
|
||||
if (pattern_len > total_size) return C_ERR_NOT_FOUND;
|
||||
|
||||
c_size_t max_search_offset = total_size - pattern_len;
|
||||
|
||||
for (c_size_t offset = max_search_offset; ; offset--) {
|
||||
c_bool_t match_found = C_TRUE;
|
||||
|
||||
for (c_size_t p_idx = 0; p_idx < pattern_len; p_idx++) {
|
||||
if (c_FastByteRingBuffer_GetAtRelativeInternal(self, offset + p_idx) != pattern[p_idx]) {
|
||||
match_found = C_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match_found) {
|
||||
return (c_index_t)offset;
|
||||
}
|
||||
|
||||
if (offset == 0) break;
|
||||
}
|
||||
return C_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
c_size_t c_FastByteRingBuffer_ReadUntilToken(c_FastByteRingBuffer_t* self, const uint8_t* token, c_size_t token_len, uint8_t* dest, c_size_t dest_max_len) {
|
||||
if (!self || !self->buffer || !token || token_len == 0 || !dest || dest_max_len == 0) return 0;
|
||||
|
||||
c_index_t match_offset = c_FastByteRingBuffer_IndexOfBuffer(self, token, token_len);
|
||||
if (match_offset == C_ERR_NOT_FOUND) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
c_size_t aggregate_bytes = (c_size_t)match_offset + token_len;
|
||||
if (aggregate_bytes > dest_max_len) {
|
||||
return 0; // 避免目標緩衝區溢出
|
||||
}
|
||||
|
||||
return c_FastByteRingBuffer_ReadBuffer(self, dest, aggregate_bytes);
|
||||
}
|
||||
|
||||
c_err_t c_FastByteRingBuffer_GetAtRelative(const c_FastByteRingBuffer_t* self, c_size_t relative_offset, uint8_t* out_byte) {
|
||||
if (!self || !self->buffer || !out_byte) return C_ERR_INVALID_PARAM;
|
||||
|
||||
c_size_t active_size = c_FastByteRingBuffer_GetSize(self);
|
||||
if (relative_offset >= active_size) {
|
||||
return C_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
*out_byte = c_FastByteRingBuffer_GetAtRelativeInternal(self, relative_offset);
|
||||
return C_SUCCESS;
|
||||
}
|
||||
|
||||
c_bool_t c_FastByteRingBuffer_Is(const c_FastByteRingBuffer_t* self, c_index_t offset, uint8_t value) {
|
||||
if (!self || !self->buffer || offset < 0) return C_FALSE;
|
||||
|
||||
c_size_t active_size = c_FastByteRingBuffer_GetSize(self);
|
||||
if ((c_size_t)offset >= active_size) return C_FALSE;
|
||||
|
||||
return (c_FastByteRingBuffer_GetAtRelativeInternal(self, (c_size_t)offset) == value) ? C_TRUE : C_FALSE;
|
||||
}
|
||||
|
||||
int c_FastByteRingBuffer_Memcmp(const c_FastByteRingBuffer_t* self, c_size_t offset, const uint8_t* buffer, c_size_t len) {
|
||||
if (!self || !self->buffer || !buffer) return C_ERR_INVALID_PARAM;
|
||||
if (len == 0) return 0;
|
||||
|
||||
c_size_t active_size = c_FastByteRingBuffer_GetSize(self);
|
||||
if (offset >= active_size || (offset + len) > active_size) {
|
||||
return C_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
c_size_t absolute_start = (self->head + offset) & self->mask;
|
||||
c_size_t bytes_to_end = self->capacity - absolute_start;
|
||||
|
||||
if (len <= bytes_to_end) {
|
||||
return memcmp(self->buffer + absolute_start, buffer, len);
|
||||
} else {
|
||||
int first_segment_match = memcmp(self->buffer + absolute_start, buffer, bytes_to_end);
|
||||
if (first_segment_match != 0) {
|
||||
return first_segment_match;
|
||||
}
|
||||
return memcmp(self->buffer, buffer + bytes_to_end, len - bytes_to_end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
c_err_t c_FastByteRingBuffer_Strtoul(const c_FastByteRingBuffer_t* self, c_size_t offset, int base, unsigned long* out_value, c_size_t* out_end_offset) {
|
||||
if (!self || !self->buffer || !out_value) return C_ERR_INVALID_PARAM;
|
||||
|
||||
c_size_t total_size = c_FastByteRingBuffer_GetSize(self);
|
||||
if (offset >= total_size) return C_ERR_OUT_OF_BOUNDS;
|
||||
|
||||
// 1. Skip leading spaces safely using fast inline relative scans
|
||||
c_size_t scan_idx = offset;
|
||||
while (scan_idx < total_size) {
|
||||
uint8_t byte = c_FastByteRingBuffer_GetAtRelativeInternal(self, scan_idx);
|
||||
if (!isspace(byte)) break;
|
||||
scan_idx++;
|
||||
}
|
||||
|
||||
if (scan_idx == total_size) return C_ERR_INVALID_PARAM; // Contains only whitespace
|
||||
|
||||
// 2. Locate trailing delimiters to calculate numeric chunk span width
|
||||
c_size_t start_numeric_offset = scan_idx;
|
||||
c_size_t numeric_len = 0;
|
||||
while (scan_idx < total_size) {
|
||||
uint8_t byte = c_FastByteRingBuffer_GetAtRelativeInternal(self, scan_idx);
|
||||
// Include numerical modifiers (+, -), hex identifiers (x, X) and alphanumeric bases
|
||||
if (!isalnum(byte) && byte != '+' && byte != '-') {
|
||||
break;
|
||||
}
|
||||
numeric_len++;
|
||||
scan_idx++;
|
||||
}
|
||||
|
||||
if (numeric_len == 0) return C_ERR_INVALID_PARAM;
|
||||
|
||||
// 3. Resolve the starting index using bitwise mask instead of slow % operators
|
||||
c_size_t absolute_start = (self->head + start_numeric_offset) & self->mask;
|
||||
c_size_t bytes_to_end = self->capacity - absolute_start;
|
||||
|
||||
unsigned long result = 0;
|
||||
char* parse_end = NULL;
|
||||
int current_errno = errno;
|
||||
errno = 0;
|
||||
|
||||
// Fast-path: Segment runs contiguous without wrapping lines
|
||||
if (numeric_len <= bytes_to_end) {
|
||||
const char* flat_ptr = (const char*)(self->buffer + absolute_start);
|
||||
result = strtoul(flat_ptr, &parse_end, base);
|
||||
|
||||
c_size_t parsed_bytes = (c_size_t)(parse_end - flat_ptr);
|
||||
if (parsed_bytes == 0 || parse_end == flat_ptr) {
|
||||
errno = current_errno;
|
||||
return C_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (errno == ERANGE) return C_ERR_OUT_OF_BOUNDS;
|
||||
|
||||
*out_value = result;
|
||||
if (out_end_offset) {
|
||||
*out_end_offset = start_numeric_offset + parsed_bytes;
|
||||
}
|
||||
} else {
|
||||
// Slow-path: Structural wrap configuration requires localized stack flattening
|
||||
if (numeric_len >= 64) return C_ERR_OUT_OF_BOUNDS;
|
||||
|
||||
char stack_scratch[64];
|
||||
for (c_size_t i = 0; i < numeric_len; i++) {
|
||||
stack_scratch[i] = (char)c_FastByteRingBuffer_GetAtRelativeInternal(self, start_numeric_offset + i);
|
||||
}
|
||||
stack_scratch[numeric_len] = '\0'; // Guarantee absolute zero string termination
|
||||
|
||||
result = strtoul(stack_scratch, &parse_end, base);
|
||||
c_size_t parsed_bytes = (c_size_t)(parse_end - stack_scratch);
|
||||
|
||||
if (parsed_bytes == 0 || parse_end == stack_scratch) {
|
||||
errno = current_errno;
|
||||
return C_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (errno == ERANGE) return C_ERR_OUT_OF_BOUNDS;
|
||||
|
||||
*out_value = result;
|
||||
if (out_end_offset) {
|
||||
*out_end_offset = start_numeric_offset + parsed_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
errno = current_errno; // Preserve runtime environment variables smoothly
|
||||
return C_SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user