I've just completed a CodeWars kata on vowel-counting in C & Rust. The sample code is easy & obvious. Arrays can be used as fast mappings. Here, I map characters to logical values (0 or 1).
C implementation:
#include <stddef.h>
#include <stdint.h>
// :) This const array design looks smart & IMO-readable. Use of C99 feature.
const uint8_t areVowels[256]= {['a']=1, ['e']=1, ['i']=1, ['o']=1, ['u']=1};
size_t get_count(const unsigned char *s)
{
auto size_t count= 0;
for (;*s!='\0';s ){
count = areVowels[*s];
}
return count;
}
Rust implementation:
// :( Here is me pain. Unreadable, python3-generated array content.
const ARE_VOWELS:[u8;256]= [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
fn get_count(s: &str) -> usize {
let mut vowels_count: usize = 0;
for c in s.bytes(){
vowels_count = ARE_VOWELS[c as usize] as usize;
}
return vowels_count;
}
I wish I knew an alternative for array designators in Rust, which are a useful C99 feature. Initialization of the same byte array is much more awkward in my Rust code.
CodePudding user response:
static mut
is unnecessary here (and also bad practice). You can assign the value of a constant to the value of a code block which is capable of being evaluated in a const
context
const ARE_VOWELS: [u8;256] = {
let mut data = [0u8; 256];
data['a' as usize] = 1;
data['e' as usize] = 1;
data['i' as usize] = 1;
data['o' as usize] = 1;
data['u' as usize] = 1;
data
};
See this answer for prettying this up with a macro.
CodePudding user response:
An alternative is a macro that provides the syntax you want, its actually not too hard to make a general purpose implementation:
macro_rules! array {
($def:expr; $len:expr; $([$idx:expr]=$val:expr),* $(,)?) => { {
let mut a = [$def; $len];
$(a[$idx] = $val;)*
a
} }
}
let data = array![0; 256; ['a' as usize]=1, ['e' as usize]=1];
You can of course move the as usize
into the macro if you like.
CodePudding user response:
I found some (unsafe ⇒ amusing) work around with "mut static value runtime initialization".
const VOWELS:&[u8;5]= b"aeiou";
static mut ARE_VOWELS:[u8;256]= [0;256];
fn init(){
unsafe{
let ptr: *mut u8= &mut ARE_VOWELS[0];
for b in VOWELS{
*(ptr.offset(*b as isize))= 1;
}
}
}
fn get_count(s: &str) -> usize {
init();
let mut vowels_count: usize = 0;
for c in s.bytes(){
unsafe{
vowels_count = ARE_VOWELS[c as usize] as usize;
}
}
return vowels_count;
}
Although I have serious doubts about the performance & maintainability of such piece of code.