aboutsummaryrefslogtreecommitdiff
path: root/gen/string/scale-norm.c
blob: 148f0a39206fd38937bd679c2c456d456cadcd67 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#if 0
cd "${0%/*}/../.."
trap 'rm -f /tmp/scale-norm' EXIT
cc -Iinclude -std=c23 -Wno-attributes -fsanitize=address,undefined \
	-o /tmp/scale-norm gen/string/scale-norm.c libmlib.a
/tmp/scale-norm
exit 0
#endif

#include <stdio.h>

#include <macros.h>
#include <rune.h>
#include <unicode/prop.h>

static double scale(rune ch);
static int bcnt(rune ch);
static int hscnt(rune ch);
static int scale2(rune ch);

int
main(void)
{
	double maxscale = 1;
	for (rune ch = 0; ch <= RUNE_MAX; ch++) {
		double n = scale(ch);
		maxscale = MAX(n, maxscale);
	}
	printf("%g\n", maxscale);
}

double
scale(rune ch)
{
	int old, new;
	old = bcnt(ch);
	new = scale2(ch);
	return (double)new / (double)old;
}

int
scale2(rune ch)
{
	if (uprop_get_hst(ch) != HST_NA)
		return hscnt(ch);
#if 0 /* NFKD */
	if (uprop_get_dt(ch) == DT_NONE)
#elif 1 /* NFD */
	if (uprop_get_dt(ch) != DT_CAN)
#endif
		return bcnt(ch);
	int acc = 0;
	struct rview rv = uprop_get_dm(ch);
	for (size_t i = 0; i < rv.len; i++)
		acc += scale2(rv.p[i]);
	return acc;
}

int
bcnt(rune ch)
{
	return ch < 0x80 ? 1 : ch < 0x800 ? 2 : ch < 0x10'000 ? 3 : 4;
}

int
hscnt(rune s)
{
	const rune sbase = 0xAC00, lbase = 0x1100, vbase = 0x1161, tbase = 0x11A7;
	const int lcnt = 19, vcnt = 21, tcnt = 28, ncnt = 588, scnt = 11172;

	int sidx = s - sbase;
	if (sidx < 0 || sidx > scnt)
		return bcnt(s);
	rune l = lbase + sidx / ncnt;
	rune v = vbase + (sidx % ncnt) / tcnt;
	rune t = tbase + sidx % tcnt;
	int acc = bcnt(l) + bcnt(v);
	if (t != tbase)
		acc += bcnt(t);
	return acc;
}