I'm looking for ways to have str representations of ranges of integers without allocating. My current best attempt is to manually match on each value:
match i
{
0 => "0",
1 => "1",
2 => "2",
...
n => "n"
}
which works, but has the obvious problem of not scaling. I've tried to automate this with macros, but i couldn't get it to work with declarative macros and procedural macros seemed too involved for me.
If you think about this for a second, doing this for u32 requires you to have ~4 billion statically allocated strings up to 10 bytes in length. Arguably you could overlap and share prefixes, but that is only likely to save you around 10%, so you're looking down the barrel of 40 GB here.
Obviously that's not tenable.
Instead if by "not allocating" you simply mean "not requiring a heap allocation" you could instead write into a buffer/small string type that can hold up to 10 bytes and be dereferenced to &str, but even that's pretty pointless since what you nearly certainly want to do with this string is print or otherwise format it, and that's directly supported by the integer itself using Display.
Nonetheless, format_into() gives you the whole range without using any additional memory. Its only problem is it's not const yet. Is it really important for you for some reason to have the numerals hard-coded in the executable as static strings?
I had preferred statics because I'm also doing a fair amount of cross-thread communication and I didn't want the additional lifetime considerations or dealing with Arcs
I wonder if you really need all these strings, or could simply have
const DIGITS: &str = "0123456789";
and cherry-pick substrings from it, but it depends on your needs.
I mean
use std::io::{Write, stdout};
const DIGITS: &str = "0123456789";
fn main() {
let mut num = 1234;
let mut divisor = 1u32;
while num / divisor >= 10 {
divisor *= 10;
}
while divisor > 0 {
let i = (num / divisor) as usize;
let c = &DIGITS[i..i + 1];
stdout().lock().write(c.as_bytes()).unwrap();
num %= divisor;
divisor /= 10;
}
}
``
You don't need to store a precomputed string of all possible digits to be able to trivially turn a number 0..=9 into a digit. b'0' + x (or b'0' | x) will do it.
The repeating pattern of the decimal representation of 1/10_000_000_019 contains every zero-padded ten-digit number at least once, so you "only" need ~10G (at the cost of non-constant lookup).
Yeah there's going to be some pigeon hole principle or something. It's just that it's one of the specific types of maths that my brain fits into a "wanting to know this is a sign of a diseased mind" bucket for some reason. It's like an Ignobel prize but for the Fields medal.
Isn't this the problem of superpermutations, which has a lower bound of n! + (n-1)! + (n-2)! + n-3 as proven by the famous 4chan post (/sci/ - Science & Math - #3751105)? In the case of n=10, the lower bound should be around 4 million. I don't know how to find the index into this array tho.