v/vlib/v/tests/bench/math_big_gcd/prime/maker.v

178 lines
3.6 KiB
V

module prime
import rand
import toml
import os
pub const toml_path = 'vlib/v/tests/bench/math_big_gcd/primes.toml'
pub interface DataI {
to_primeset() PrimeSet
from_primeset(PrimeSet) DataI
}
pub fn (di DataI) cast<T>() DataI {
return T{}.from_primeset(di.to_primeset())
}
pub type PrimeCfg = PrimeSet
pub fn (pc PrimeCfg) short() string {
return "r: '$pc.r' a: '$pc.a' b: '$pc.b'"
}
[heap]
pub struct PrimeSet {
pub mut:
r string [required]
a string [required]
b string [required]
}
pub fn (p PrimeSet) to_primeset() PrimeSet {
return p
}
pub fn (p PrimeSet) from_primeset(ps PrimeSet) DataI {
return ps
}
pub fn (p PrimeSet) predicate(pred fn (data PrimeSet) bool) bool {
return pred(p)
}
pub fn (p PrimeSet) key() string {
return [p.r, p.a, p.b].join('.')
}
pub fn (p PrimeSet) str() string {
return [p.r, p.a, p.b].join(' ')
}
fn extract_count(s string) int {
digits := '0123456789'.split('')
if (s == '') || !s.split('').any(it in digits) {
return 0
}
ds := s.split('').filter(it in digits)
return ds.join('').int()
}
// sizes lists the available names for prime-number sections.
pub fn sizes() []string {
primes := read_toml_file()
return primes.keys()
}
// usage returns section-names and the count of available primes
//
pub fn usage() string {
primes := read_toml_file()
return sizes().map('$it[..${primes[it].len}]').join('\n\t')
}
// reads the Map[string] []string from disk
// and returns the parsed content
fn read_toml_file() map[string][]string {
fp := os.join_path(@VROOT, prime.toml_path)
tm_doc := toml.parse_file(fp) or {
err_msg := 'expected $fp'
eprintln(err_msg)
panic(err)
}
// TODO what happens if this goes wrong ?
tm_primes := tm_doc.value('primes') as map[string]toml.Any
msg := 'expected a map[string][]string in TOML-data ? corrupt ?'
mut p := map[string][]string{}
for k in tm_primes.keys() {
p[k] = []string{}
arr := tm_primes[k] or { panic(msg) }
for _, elem in arr.array() {
p[k] << elem as string
}
}
return p
}
pub fn random_list(cfg []string) []string {
primes := read_toml_file()
mut p_list := []string{}
match cfg.len {
1 { // prime-size e.g. 'xs' given
if cfg[0] !in primes {
return p_list
} else {
return primes[cfg[0]]
}
}
2 { // prime-size and limiter given e.g 'xs.15'
prime_size := cfg[0]
if prime_size !in primes {
return p_list
}
mut prime_count := extract_count(cfg[1])
if prime_count == 0 {
return primes[prime_size]
}
mut num := ''
for prime_count != 0 {
num = primes[prime_size][rand.int_in_range(0, primes[prime_size].len - 1)]
if num in p_list {
continue
}
p_list << num
prime_count -= 1
if prime_count >= primes[prime_size].len {
p_list = primes[prime_size]
break
}
} // eo-for
return p_list
} // cfg not understood
else {
return p_list
}
}
return p_list
}
pub fn random_set(cfg PrimeCfg) ?[]PrimeSet {
p_lists := [
cfg.r.split('.'),
cfg.a.split('.'),
cfg.b.split('.'),
].map(random_list(it.map(it.trim_space().to_lower())))
// test for empty lists
//
if p_lists.any(it.len == 0) {
msg := [
'bad config was :\n\n"$cfg"',
"maybe try e.g { r: 'l.5' a: 'xxl.5 b: 'xl.10' } makes a set of 250",
'your config was { $cfg.short() }',
'sizes $usage()\n',
].join('\n\n')
return error(msg)
}
// filter unique combinations thru map
//
mut tmp := map[string]PrimeSet{}
for r in p_lists[0] {
for a in p_lists[1] {
for b in p_lists[2] {
d := PrimeSet{r, a, b}
if d.key() in tmp {
continue
}
tmp[d.key()] = d
}
}
}
return tmp.keys().map(tmp[it])
}