Created
May 28, 2023 02:17
-
-
Save th-in-gs/7f2104440aa02dd36264ed6bc38ce553 to your computer and use it in GitHub Desktop.
Packed PROGMEM Strings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "packedStrings.h" | |
const uint8_t str7CharAtIndex(const uint8_t *data, const uint8_t index) { | |
const size_t bitPosition = index * 7; | |
const uint8_t startByte = bitPosition / 8; | |
const uint8_t startBit = bitPosition % 8; | |
uint8_t ch = pgm_read_byte(&data[startByte]) << startBit; | |
if(startBit > (8-7)) { | |
ch |= pgm_read_byte(&data[startByte + 1]) >> (8 - startBit); | |
} | |
return ch >> 1; | |
} | |
const uint8_t str6CharAtIndex(const uint8_t *data, const uint8_t index) { | |
const size_t bitPosition = index * 6; | |
const uint8_t startByte = bitPosition >>3; | |
const uint8_t startBit = bitPosition % 8; | |
uint8_t ch = pgm_read_byte(&data[startByte]) << startBit; | |
if(startBit > (8-6)) { | |
ch |= pgm_read_byte(&data[startByte + 1]) >> (8 - startBit); | |
} | |
ch = 0x20 + (ch >> 2); | |
if(ch == '^') { | |
ch = '\n'; | |
} | |
if(ch == '!') { | |
ch = '|'; | |
} | |
if(ch == ';') { | |
ch = '\0'; | |
} | |
return ch; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <ctype.h> | |
#include <string.h> | |
#include <math.h> | |
#include <avr/pgmspace.h> | |
// Define a 6 or 7 bit string like this: | |
// uint8_t *sixBitString = STR6("6 bit string"); | |
// uint8_t *sevenBitString = STR7("7 bit string"); | |
// | |
// Access characters from them like this: | |
// | |
// str6CharAtIndex(sixBitString, 3) // returns 'B' (not 'b' because there's only uppercase in the six bit character set). | |
// str7CharAtIndex(sixBitString, 7) // returns 'b'. | |
// | |
// They are still NULL_terminated after unpacking. | |
// | |
// I didn't need a whole-string-unpacking function (str6cpy(char *unpacked, uint8_t packed)?), so they're an exercise fo the reader. | |
// | |
#define STR7(str) (__extension__({ static PROGMEM const PackedStringConstexpr<7, sizeof(str)> __c = PackedStringConstexpr<7, sizeof(str)>(str); __c.data; })) | |
#define STR6(str) (__extension__({ static PROGMEM const PackedStringConstexpr<6, sizeof(str)> __c = PackedStringConstexpr<6, sizeof(str)>(str); __c.data; })) | |
const uint8_t str7CharAtIndex(const uint8_t *data, const uint8_t index); | |
const uint8_t str6CharAtIndex(const uint8_t *data, const uint8_t index); | |
template <size_t bitsPerChar, size_t length> | |
struct PackedStringConstexpr { | |
uint8_t data[((length * bitsPerChar) / 8) + (((length * bitsPerChar) % 8) ? 1 : 0)]; | |
constexpr PackedStringConstexpr(const char (&string)[length]) : data {} | |
{ | |
size_t outBytePosition = 0; | |
size_t outBitPosition = 0; | |
for(size_t inBytePosition = 0; inBytePosition < length; ++inBytePosition) { | |
uint8_t ch = (uint8_t)string[inBytePosition]; | |
if(bitsPerChar == 6) { | |
// Custom encoding scheme for a 64-element subset of the ASCII | |
// set. | |
if(ch >= 'a' && ch <= 'z') { | |
ch = (ch - 'a') + 'A'; | |
} | |
bool wasZero = ch == '\0'; | |
bool wasNewline = ch == '\n'; | |
bool wasPipe = ch == '|'; | |
if(ch < 0x20 || ch > 0x5d) { | |
ch = '?'; | |
} | |
if(wasNewline) { | |
ch = '^'; | |
} | |
if(wasPipe) { | |
ch = '!'; | |
} | |
if(wasZero) { | |
ch = ';'; | |
} | |
ch = ch - 0x20; | |
ch = ch << 2; | |
} else { | |
ch = ch << 1; | |
} | |
data[outBytePosition] |= ch >> outBitPosition; | |
outBitPosition += bitsPerChar; | |
if(outBitPosition >= 8) { | |
++outBytePosition; | |
outBitPosition -= 8; | |
if(outBitPosition > 0) { | |
data[outBytePosition] |= ch << (bitsPerChar - outBitPosition); | |
} | |
} | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment