nimphea/nimphea_fixedstr

Source   Edit  

Fixed-Capacity String Module

This module provides a stack-allocated, fixed-capacity string type for embedded systems. Unlike Nim's standard string type which uses heap allocation, FixedStr stores all data on the stack with compile-time determined capacity.

Key Features:

  • Zero heap allocation (all data on stack)
  • Compile-time capacity via static int parameter
  • Safe bounds checking on all operations
  • Compatible with standard string operations via $ operator
  • Ideal for OLED/LCD displays, serial output, and embedded UI
  • Audio-rate safe (no memory allocation)

Usage Example:

import nimphea_fixedstr

# Create 32-character fixed string
var displayText: FixedStr[32]
displayText.init()

# Add text
displayText.add("Frequency: ")
displayText.add("440")
displayText.add(" Hz")

# Convert to regular string for display
echo $displayText  # "Frequency: 440 Hz"

# Set new content (replaces existing)
displayText.set("Volume: 75%")

# Check length
if displayText.len() < displayText.capacity():
  displayText.add("!")

# Clear for reuse
displayText.clear()

Performance Notes:

  • All operations are O(1) or O(n) where n is string length (not capacity)
  • No dynamic memory allocation ever occurs
  • Safe to use in interrupt handlers and audio callbacks
  • Capacity is fixed at compile time - cannot grow
  • Attempting to add beyond capacity truncates (no panic)

Types

FixedStr[N] = object

Fixed-capacity string with compile-time size.

Template Parameters:

  • N: Maximum capacity in bytes (must be > 0)

Fields:

  • data: Fixed array storing characters
  • length: Current number of valid characters (0 to N-1)

Note: Capacity N should leave room for null terminator if interfacing with C functions. For display purposes, full N can be used.

Source   Edit  

Procs

proc `$`[N: static int](this: FixedStr[N]): string

Convert FixedStr to regular Nim string.

Parameters:

  • this: The FixedStr instance

Returns: String containing the current contents

Note: This allocates a new string on the heap. Use for display/debugging only, not in audio callbacks.

Example:

var s: FixedStr[16]
s.init()
s.add("test")
echo $s  # Prints "test"
Source   Edit  
proc `[]`[N: static int](this: FixedStr[N]; index: int): char {.inline.}

Get character at specified index.

Parameters:

  • this: The FixedStr instance
  • index: Index of character to retrieve (0-based)

Returns: Character at the specified index

Note: No bounds checking - caller must ensure index < len()

Example:

var s: FixedStr[16]
s.init()
s.add("hello")
assert s[0] == 'h'
assert s[4] == 'o'
Source   Edit  
proc `[]=`[N: static int](this: var FixedStr[N]; index: int; c: char) {.inline.}

Set character at specified index.

Parameters:

  • this: The FixedStr instance
  • index: Index of character to set (0-based)
  • c: New character value

Note: No bounds checking - caller must ensure index < len() Does not change string length.

Example:

var s: FixedStr[16]
s.init()
s.add("hello")
s[0] = 'H'
assert $s == "Hello"
Source   Edit  
proc add[N: static int](this: var FixedStr[N]; c: char): bool {.inline.}

Add a single character to the end of the string.

Parameters:

  • this: The FixedStr instance
  • c: Character to add

Returns: true if character was added, false if string was full

Example:

var s: FixedStr[4]
s.init()
assert s.add('H')
assert s.add('i')
assert s.len() == 2
Source   Edit  
proc add[N: static int](this: var FixedStr[N]; str: string): int {.inline.}

Add a string to the end of the fixed string.

Parameters:

  • this: The FixedStr instance
  • str: String to add

Returns: Number of characters actually added (may be less than str.len if capacity reached)

Note: If string doesn't fit completely, adds as many characters as possible.

Example:

var s: FixedStr[8]
s.init()
let added = s.add("Hello")
assert added == 5
let more = s.add("World")  # Only 3 chars fit
assert more == 3
assert s.len() == 8
Source   Edit  
proc add[N: static int](this: var FixedStr[N]; value: float): int {.inline.}

Add a float value as string to the end of the fixed string.

Parameters:

  • this: The FixedStr instance
  • value: Float to convert and add

Returns: Number of characters actually added

Example:

var s: FixedStr[16]
s.init()
s.add("Freq: ")
s.add(440.0)
assert $s == "Freq: 440.0"
Source   Edit  
proc add[N: static int](this: var FixedStr[N]; value: int): int {.inline.}

Add an integer value as string to the end of the fixed string.

Parameters:

  • this: The FixedStr instance
  • value: Integer to convert and add

Returns: Number of characters actually added

Example:

var s: FixedStr[16]
s.init()
s.add("Value: ")
s.add(42)
assert $s == "Value: 42"
Source   Edit  
proc capacity[N: static int](this: FixedStr[N]): int {.inline.}

Get maximum capacity of the string.

Parameters:

  • this: The FixedStr instance

Returns: Maximum number of characters this string can hold (always N)

Example:

var s: FixedStr[32]
assert s.capacity() == 32
Source   Edit  
proc clear[N: static int](this: var FixedStr[N]) {.inline.}

Clear the string (set length to 0).

Parameters:

  • this: The FixedStr instance to clear

Note: This is O(1) - just resets length, doesn't zero memory.

Example:

var s: FixedStr[16]
s.init()
s.add("hello")
s.clear()
assert s.len() == 0
Source   Edit  
proc init[N: static int](this: var FixedStr[N]) {.inline.}

Initialize the fixed string to empty state.

Parameters:

  • this: The FixedStr instance to initialize

Example:

var s: FixedStr[16]
s.init()
assert s.len() == 0
Source   Edit  
proc isEmpty[N: static int](this: FixedStr[N]): bool {.inline.}

Check if the string is empty.

Parameters:

  • this: The FixedStr instance

Returns: true if length is 0, false otherwise

Example:

var s: FixedStr[16]
s.init()
assert s.isEmpty()
s.add("x")
assert not s.isEmpty()
Source   Edit  
proc isFull[N: static int](this: FixedStr[N]): bool {.inline.}

Check if the string is at full capacity.

Parameters:

  • this: The FixedStr instance

Returns: true if length equals capacity, false otherwise

Example:

var s: FixedStr[4]
s.init()
s.add("test")
assert s.isFull()
Source   Edit  
proc len[N: static int](this: FixedStr[N]): int {.inline.}

Get current length of the string.

Parameters:

  • this: The FixedStr instance

Returns: Current number of characters in the string (0 to capacity)

Example:

var s: FixedStr[16]
s.init()
assert s.len() == 0
s.add("test")
assert s.len() == 4
Source   Edit  
proc set[N: static int](this: var FixedStr[N]; str: string): int {.inline.}

Replace entire contents with new string.

Parameters:

  • this: The FixedStr instance
  • str: New string content

Returns: Number of characters actually set (may be less than str.len if capacity exceeded)

Note: This clears existing content first, then adds new string.

Example:

var s: FixedStr[16]
s.init()
s.add("old")
s.set("new content")
assert $s == "new content"
Source   Edit  
proc toCString[N: static int](this: var FixedStr[N]): cstring {.inline.}

Get a null-terminated C string pointer.

Parameters:

  • this: The FixedStr instance

Returns: Pointer to null-terminated character array

Warning: Only safe if capacity N was allocated with room for null terminator and string length < N. This does NOT automatically add null terminator. User must ensure datalength is set to '0' before calling.

Example:

var s: FixedStr[17]  # 16 chars + null
s.init()
s.add("display text")
s.data[s.len()] = '\0'  # Add null terminator
let cs = s.toCString()  # Safe for C functions
Source   Edit