makeisprint.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build ignore
  5. //
  6. // usage:
  7. //
  8. // go run makeisprint.go -output isprint.go
  9. //
  10. package main
  11. import (
  12. "bytes"
  13. "flag"
  14. "fmt"
  15. "go/format"
  16. "io/ioutil"
  17. "log"
  18. "unicode"
  19. )
  20. var filename = flag.String("output", "isprint.go", "output file name")
  21. var (
  22. range16 []uint16
  23. except16 []uint16
  24. range32 []uint32
  25. except32 []uint32
  26. )
  27. // bsearch16 returns the smallest i such that a[i] >= x.
  28. // If there is no such i, bsearch16 returns len(a).
  29. func bsearch16(a []uint16, x uint16) int {
  30. i, j := 0, len(a)
  31. for i < j {
  32. h := i + (j-i)/2
  33. if a[h] < x {
  34. i = h + 1
  35. } else {
  36. j = h
  37. }
  38. }
  39. return i
  40. }
  41. // bsearch32 returns the smallest i such that a[i] >= x.
  42. // If there is no such i, bsearch32 returns len(a).
  43. func bsearch32(a []uint32, x uint32) int {
  44. i, j := 0, len(a)
  45. for i < j {
  46. h := i + (j-i)/2
  47. if a[h] < x {
  48. i = h + 1
  49. } else {
  50. j = h
  51. }
  52. }
  53. return i
  54. }
  55. func isPrint(r rune) bool {
  56. // Same algorithm, either on uint16 or uint32 value.
  57. // First, find first i such that rang[i] >= x.
  58. // This is the index of either the start or end of a pair that might span x.
  59. // The start is even (rang[i&^1]) and the end is odd (rang[i|1]).
  60. // If we find x in a range, make sure x is not in exception list.
  61. if 0 <= r && r < 1<<16 {
  62. rr, rang, except := uint16(r), range16, except16
  63. i := bsearch16(rang, rr)
  64. if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr {
  65. return false
  66. }
  67. j := bsearch16(except, rr)
  68. return j >= len(except) || except[j] != rr
  69. }
  70. rr, rang, except := uint32(r), range32, except32
  71. i := bsearch32(rang, rr)
  72. if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr {
  73. return false
  74. }
  75. j := bsearch32(except, rr)
  76. return j >= len(except) || except[j] != rr
  77. }
  78. func scan(min, max rune) (rang, except []uint32) {
  79. lo := rune(-1)
  80. for i := min; ; i++ {
  81. if (i > max || !unicode.IsPrint(i)) && lo >= 0 {
  82. // End range, but avoid flip flop.
  83. if i+1 <= max && unicode.IsPrint(i+1) {
  84. except = append(except, uint32(i))
  85. continue
  86. }
  87. rang = append(rang, uint32(lo), uint32(i-1))
  88. lo = -1
  89. }
  90. if i > max {
  91. break
  92. }
  93. if lo < 0 && unicode.IsPrint(i) {
  94. lo = i
  95. }
  96. }
  97. return
  98. }
  99. func to16(x []uint32) []uint16 {
  100. var y []uint16
  101. for _, v := range x {
  102. if uint32(uint16(v)) != v {
  103. panic("bad 32->16 conversion")
  104. }
  105. y = append(y, uint16(v))
  106. }
  107. return y
  108. }
  109. func main() {
  110. flag.Parse()
  111. rang, except := scan(0, 0xFFFF)
  112. range16 = to16(rang)
  113. except16 = to16(except)
  114. range32, except32 = scan(0x10000, unicode.MaxRune)
  115. for i := rune(0); i <= unicode.MaxRune; i++ {
  116. if isPrint(i) != unicode.IsPrint(i) {
  117. log.Fatalf("%U: isPrint=%v, want %v\n", i, isPrint(i), unicode.IsPrint(i))
  118. }
  119. }
  120. var buf bytes.Buffer
  121. fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved.
  122. // Use of this source code is governed by a BSD-style
  123. // license that can be found in the LICENSE file.`+"\n\n")
  124. fmt.Fprintf(&buf, "// DO NOT EDIT. GENERATED BY\n")
  125. fmt.Fprintf(&buf, "// go run makeisprint.go -output isprint.go\n\n")
  126. fmt.Fprintf(&buf, "package strconv\n\n")
  127. fmt.Fprintf(&buf, "// (%d+%d+%d)*2 + (%d)*4 = %d bytes\n\n",
  128. len(range16), len(except16), len(except32),
  129. len(range32),
  130. (len(range16)+len(except16)+len(except32))*2+
  131. (len(range32))*4)
  132. fmt.Fprintf(&buf, "var isPrint16 = []uint16{\n")
  133. for i := 0; i < len(range16); i += 2 {
  134. fmt.Fprintf(&buf, "\t%#04x, %#04x,\n", range16[i], range16[i+1])
  135. }
  136. fmt.Fprintf(&buf, "}\n\n")
  137. fmt.Fprintf(&buf, "var isNotPrint16 = []uint16{\n")
  138. for _, r := range except16 {
  139. fmt.Fprintf(&buf, "\t%#04x,\n", r)
  140. }
  141. fmt.Fprintf(&buf, "}\n\n")
  142. fmt.Fprintf(&buf, "var isPrint32 = []uint32{\n")
  143. for i := 0; i < len(range32); i += 2 {
  144. fmt.Fprintf(&buf, "\t%#06x, %#06x,\n", range32[i], range32[i+1])
  145. }
  146. fmt.Fprintf(&buf, "}\n\n")
  147. fmt.Fprintf(&buf, "var isNotPrint32 = []uint16{ // add 0x10000 to each entry\n")
  148. for _, r := range except32 {
  149. if r >= 0x20000 {
  150. log.Fatalf("%U too big for isNotPrint32\n", r)
  151. }
  152. fmt.Fprintf(&buf, "\t%#04x,\n", r-0x10000)
  153. }
  154. fmt.Fprintf(&buf, "}\n")
  155. data, err := format.Source(buf.Bytes())
  156. if err != nil {
  157. log.Fatal(err)
  158. }
  159. err = ioutil.WriteFile(*filename, data, 0644)
  160. if err != nil {
  161. log.Fatal(err)
  162. }
  163. }