#include #include #include #include #include #include c_err_t c_ByteRingBuffer_Init(c_ByteRingBuffer_t* self, c_size_t capacity) { if (!self || capacity == 0) return C_ERR_PARAM; self->capacity = capacity; self->head = 0; self->tail = 0; self->is_full = C_FALSE; self->buffer = (uint8_t*)C_ALLOC(self->capacity); if (!self->buffer) { self->capacity = 0; return C_ERR_NOMEM; } return C_ERR_SUCCESS; } void c_ByteRingBuffer_Destroy(c_ByteRingBuffer_t* self) { if (!self) return; C_FREE(self->buffer); self->capacity = 0; self->head = 0; self->tail = 0; self->is_full = C_FALSE; } // Writes a single byte. O(1) performance. c_err_t c_ByteRingBuffer_WriteByte(c_ByteRingBuffer_t* self, uint8_t byte) { if (!self || !self->buffer) return C_ERR_PARAM; if (self->is_full) return C_ERR_FULL; self->buffer[self->tail] = byte; self->tail = (self->tail + 1) % self->capacity; if (self->tail == self->head) { self->is_full = C_TRUE; } return C_ERR_SUCCESS; } // Reads a single byte. O(1) performance. c_err_t c_ByteRingBuffer_ReadByte(c_ByteRingBuffer_t* self, uint8_t* out_byte) { if (!self || !self->buffer || !out_byte) return C_ERR_PARAM; if (c_ByteRingBuffer_IsEmpty(self)) return C_ERR_EMPTY; *out_byte = self->buffer[self->head]; self->head = (self->head + 1) % self->capacity; self->is_full = C_FALSE; return C_ERR_SUCCESS; } // Writes an entire chunk of bytes. Returns the total number of bytes successfully written. c_size_t c_ByteRingBuffer_WriteBuffer(c_ByteRingBuffer_t* self, const uint8_t* src, c_size_t len) { if (!self || !self->buffer || !src || len == 0) 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->capacity; if (self->tail == self->head) { self->is_full = C_TRUE; } bytes_written++; } return bytes_written; } // Reads an entire chunk of bytes. Returns the total number of bytes successfully read. c_size_t c_ByteRingBuffer_ReadBuffer(c_ByteRingBuffer_t* self, uint8_t* dest, c_size_t len) { if (!self || !self->buffer || !dest || len == 0) return 0; c_size_t bytes_read = 0; while (bytes_read < len && !c_ByteRingBuffer_IsEmpty(self)) { dest[bytes_read] = self->buffer[self->head]; self->head = (self->head + 1) % self->capacity; self->is_full = C_FALSE; bytes_read++; } return bytes_read; } c_size_t c_ByteRingBuffer_GetSize(const c_ByteRingBuffer_t* self) { if (!self || !self->buffer) return 0; if (self->is_full) return self->capacity; if (self->tail >= self->head) { return self->tail - self->head; } else { return self->capacity + self->tail - self->head; } } c_bool_t c_ByteRingBuffer_IsEmpty(const c_ByteRingBuffer_t* self) { if (!self) return C_TRUE; return (self->head == self->tail) && !self->is_full; } c_bool_t c_ByteRingBuffer_IsFull(const c_ByteRingBuffer_t* self) { if (!self) return C_FALSE; return self->is_full; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ void c_ByteRingBuffer_WriteByteOverwrite(c_ByteRingBuffer_t* self, uint8_t byte) { if (!self || !self->buffer) return; if (self->is_full) { // Advance head position to discard the oldest item before placing the new data self->head = (self->head + 1) % self->capacity; } self->buffer[self->tail] = byte; self->tail = (self->tail + 1) % self->capacity; if (self->tail == self->head) { self->is_full = C_TRUE; } } c_size_t c_ByteRingBuffer_WriteBufferOverwrite(c_ByteRingBuffer_t* self, const uint8_t* src, c_size_t len) { if (!self || !self->buffer || !src || len == 0) return 0; // Boundary edge-case optimization: If incoming payload exceeds entire capacity, // only the absolute last subset window matching 'capacity' will survive anyway. if (len >= self->capacity) { src += (len - self->capacity); len = self->capacity; // Blindly overwrite entire buffer matrix instantly memcpy(self->buffer, src, len); self->head = 0; self->tail = 0; self->is_full = C_TRUE; return len; } c_size_t size = c_ByteRingBuffer_GetSize(self); c_size_t free_space = self->capacity - size; // Track if writing this string length overflows existing configurations if (len > free_space) { c_size_t overwrite_count = len - free_space; self->head = (self->head + overwrite_count) % self->capacity; } // Segment 1: Physical top copy action 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: Physical circular bottom split copy action 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->capacity; } if (self->tail == self->head) { self->is_full = C_TRUE; } else { self->is_full = C_FALSE; // Only set false if it didn't completely fill out layout thresholds } return len; } c_err_t c_ByteRingBuffer_PeekByte(const c_ByteRingBuffer_t* self, uint8_t* out_byte) { if (!self || !self->buffer || !out_byte) return C_ERR_INVALID_PARAM; if (c_ByteRingBuffer_IsEmpty(self)) return -3; // Underflow *out_byte = self->buffer[self->head]; return C_SUCCESS; } c_size_t c_ByteRingBuffer_PeekBuffer(const c_ByteRingBuffer_t* self, uint8_t* dest, c_size_t len) { if (!self || !self->buffer || !dest || len == 0) return 0; c_size_t available_bytes = c_ByteRingBuffer_GetSize(self); if (len > available_bytes) { len = available_bytes; } if (len == 0) return 0; // Duplicate standard ReadBuffer chunk copy patterns without changing the 'head' cursor state 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_ByteRingBuffer_Discard(c_ByteRingBuffer_t* self, c_size_t len) { if (!self || !self->buffer || len == 0) return 0; c_size_t available_bytes = c_ByteRingBuffer_GetSize(self); if (len > available_bytes) { len = available_bytes; } if (len == 0) return 0; self->head = (self->head + len) % self->capacity; self->is_full = C_FALSE; // Dropping bytes guarantees it is no longer full return len; } const uint8_t* c_ByteRingBuffer_GetReadPtr(const c_ByteRingBuffer_t* self, c_size_t* out_contiguous_len) { if (!self || !self->buffer || !out_contiguous_len) return NULL; *out_contiguous_len = 0; if (c_ByteRingBuffer_IsEmpty(self)) return NULL; if (self->tail > self->head) { // Data path is completely linear up to the tail index position *out_contiguous_len = self->tail - self->head; } else { // Data path wraps around; the first contiguous stretch runs to the array tail boundary *out_contiguous_len = self->capacity - self->head; } return self->buffer + self->head; } uint8_t* c_ByteRingBuffer_GetWritePtr(const c_ByteRingBuffer_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) { // Free space path runs from tail up to the absolute array wrap boundary // Special case adjustment: If head is exactly at index 0, we can write up to capacity - 1 // but since is_full flag tracking isolates capacity limits, write blocks up to standard edge boundaries. *out_contiguous_len = self->capacity - self->tail; // Minor modification check: If head index configuration is further up but tail wraps, // don't overlap onto the head index area until the next subsequent hardware layout fetch pass. if (self->head == 0 && *out_contiguous_len == self->capacity) { // Full allocation window available } } else { // Free space path is bounded cleanly between tail position and head position index spaces *out_contiguous_len = self->head - self->tail; } return self->buffer + self->tail; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE uint8_t c_ByteRingBuffer_GetAtRelativeInternal(const c_ByteRingBuffer_t* self, c_size_t relative_offset) { c_size_t absolute_index = (self->head + relative_offset) % self->capacity; return self->buffer[absolute_index]; } c_index_t c_ByteRingBuffer_IndexOfBuffer(const c_ByteRingBuffer_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_ByteRingBuffer_GetSize(self); if (pattern_len > total_size) return C_ERR_NOT_FOUND; // Slide search window across the total available size boundary 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; // Perform relative window byte sequence comparison for (c_size_t p_idx = 0; p_idx < pattern_len; p_idx++) { if (c_ByteRingBuffer_GetAtRelativeInternal(self, offset + p_idx) != pattern[p_idx]) { match_found = C_FALSE; break; } } if (match_found) { return (c_index_t)offset; // Returns offset relative to current head position } } return C_ERR_NOT_FOUND; } c_index_t c_ByteRingBuffer_IndexOfByte(const c_ByteRingBuffer_t* self, uint8_t target) { if (!self || !self->buffer) return C_ERR_NOT_FOUND; c_size_t total_size = c_ByteRingBuffer_GetSize(self); if (total_size == 0) return C_ERR_NOT_FOUND; // Linear pass mapping relative pointers natively across internal split layers for (c_size_t offset = 0; offset < total_size; offset++) { if (c_ByteRingBuffer_GetAtRelativeInternal(self, offset) == target) { return (c_index_t)offset; } } return C_ERR_NOT_FOUND; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ c_index_t c_ByteRingBuffer_LastIndexOfBuffer(const c_ByteRingBuffer_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_ByteRingBuffer_GetSize(self); if (pattern_len > total_size) return C_ERR_NOT_FOUND; // Scan backwards from the largest possible relative offset down to index 0 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_ByteRingBuffer_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; // Secure unsigned loop breakout guard rail } return C_ERR_NOT_FOUND; } c_size_t c_ByteRingBuffer_ReadUntilToken(c_ByteRingBuffer_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; // Step 1: Scan for the token sequence location relative to the head c_index_t match_offset = c_ByteRingBuffer_IndexOfBuffer(self, token, token_len); if (match_offset == C_ERR_NOT_FOUND) { return 0; // Token sequence not currently hosted inside the window pipeline } // Step 2: Compute total structural extraction requirements including the token depth c_size_t aggregate_bytes = (c_size_t)match_offset + token_len; // Absolute safety check: Safeguard against destination memory container overflows if (aggregate_bytes > dest_max_len) { return 0; // Reject processing since target container is too small to safely store the complete payload string } // Step 3: Perform standard destructive consumption via ReadBuffer c_size_t bytes_extracted = c_ByteRingBuffer_ReadBuffer(self, dest, aggregate_bytes); return bytes_extracted; } c_err_t c_ByteRingBuffer_GetAtRelative(const c_ByteRingBuffer_t* self, c_size_t relative_offset, uint8_t* out_byte) { if (!self || !self->buffer || !out_byte) return C_ERR_PARAM; // Validate that the request falls inside the populated byte array span c_size_t active_size = c_ByteRingBuffer_GetSize(self); if (relative_offset >= active_size) { return C_ERR_OUT_OF_BOUNDS; } // Safely fold the relative offset over physical ring buffer wrapping thresholds c_size_t absolute_index = (self->head + relative_offset) % self->capacity; *out_byte = self->buffer[absolute_index]; return C_SUCCESS; } c_bool_t c_ByteRingBuffer_Is(const c_ByteRingBuffer_t* self, c_index_t offset, uint8_t value) { // Return false immediately if the buffer is uninitialized or the offset is negative if (!self || !self->buffer || offset < 0) { return C_FALSE; } // Verify that the requested relative offset falls within the currently readable window c_size_t active_size = c_ByteRingBuffer_GetSize(self); if ((c_size_t)offset >= active_size) { return C_FALSE; } // Map the relative offset to the physical, wrapped array index bounds c_size_t absolute_index = (self->head + (c_size_t)offset) % self->capacity; // Evaluate content identity match condition return (self->buffer[absolute_index] == value) ? C_TRUE : C_FALSE; } int c_ByteRingBuffer_Memcmp(const c_ByteRingBuffer_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; // Empty comparison matches instantly } c_size_t active_size = c_ByteRingBuffer_GetSize(self); // Boundary check: Verify the comparison window falls entirely within readable buffer constraints if (offset >= active_size || (offset + len) > active_size) { return C_ERR_OUT_OF_BOUNDS; } // Resolve the real physical starting index inside the memory array c_size_t absolute_start = (self->head + offset) % self->capacity; // Calculate how many contiguous bytes run in a straight line up to the array boundary edge c_size_t bytes_to_end = self->capacity - absolute_start; if (len <= bytes_to_end) { // Scenario 1: The target verification window is completely contiguous return memcmp(self->buffer + absolute_start, buffer, len); } else { // Scenario 2: The window wraps around the physical edge bounds. Execute a split-block comparison. // Pass A: Compare up to the wrapping array edge boundary int first_segment_match = memcmp(self->buffer + absolute_start, buffer, bytes_to_end); if (first_segment_match != 0) { return first_segment_match; // Return mismatch direction immediately } // Pass B: Wrap around to index 0 and compare the remainder sequence c_size_t remaining_bytes = len - bytes_to_end; return memcmp(self->buffer, buffer + bytes_to_end, remaining_bytes); } } c_err_t c_ByteRingBuffer_Strtoul(const c_ByteRingBuffer_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_ByteRingBuffer_GetSize(self); if (offset >= total_size) return C_ERR_OUT_OF_BOUNDS; // 1. Skip leading whitespace using the internal helper function c_size_t scan_idx = offset; while (scan_idx < total_size) { uint8_t byte = c_ByteRingBuffer_GetAtRelativeInternal(self, scan_idx); if (!isspace(byte)) break; scan_idx++; } if (scan_idx == total_size) return C_ERR_INVALID_PARAM; // Buffer contains only whitespace // 2. Measure the exact alphanumeric chunk layout width boundary c_size_t start_numeric_offset = scan_idx; c_size_t numeric_len = 0; while (scan_idx < total_size) { uint8_t byte = c_ByteRingBuffer_GetAtRelativeInternal(self, scan_idx); // Track hex modifiers (x, X), signs, and alphanumeric digits if (!isalnum(byte) && byte != '+' && byte != '-') { break; } numeric_len++; scan_idx++; } if (numeric_len == 0) return C_ERR_INVALID_PARAM; // 3. Compute absolute pointers and optimize memory operations based on wrap layouts c_size_t absolute_start = (self->head + start_numeric_offset) % self->capacity; c_size_t bytes_to_end = self->capacity - absolute_start; unsigned long result = 0; char* parse_end = NULL; int current_errno = errno; errno = 0; if (numeric_len <= bytes_to_end) { // Linear path optimization: Parse directly out of the contiguous array space 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 { // Fragmented Wrap handling path: Copy across loop slices onto a small stack array if (numeric_len >= 64) return C_ERR_OUT_OF_BOUNDS; // Enforce safe parsing limits char stack_scratch[64]; for (c_size_t i = 0; i < numeric_len; i++) { stack_scratch[i] = (char)c_ByteRingBuffer_GetAtRelativeInternal(self, start_numeric_offset + i); } stack_scratch[numeric_len] = '\0'; // Guarantee safe string boundary 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; // Restore system state integrity flags cleanly return C_SUCCESS; }