2
0

initialism_index.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Copyright 2015 go-swagger maintainers
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package swag
  15. import (
  16. "sort"
  17. "strings"
  18. "sync"
  19. )
  20. var (
  21. // commonInitialisms are common acronyms that are kept as whole uppercased words.
  22. commonInitialisms *indexOfInitialisms
  23. // initialisms is a slice of sorted initialisms
  24. initialisms []string
  25. // a copy of initialisms pre-baked as []rune
  26. initialismsRunes [][]rune
  27. initialismsUpperCased [][]rune
  28. isInitialism func(string) bool
  29. maxAllocMatches int
  30. )
  31. func init() {
  32. // Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
  33. configuredInitialisms := map[string]bool{
  34. "ACL": true,
  35. "API": true,
  36. "ASCII": true,
  37. "CPU": true,
  38. "CSS": true,
  39. "DNS": true,
  40. "EOF": true,
  41. "GUID": true,
  42. "HTML": true,
  43. "HTTPS": true,
  44. "HTTP": true,
  45. "ID": true,
  46. "IP": true,
  47. "IPv4": true,
  48. "IPv6": true,
  49. "JSON": true,
  50. "LHS": true,
  51. "OAI": true,
  52. "QPS": true,
  53. "RAM": true,
  54. "RHS": true,
  55. "RPC": true,
  56. "SLA": true,
  57. "SMTP": true,
  58. "SQL": true,
  59. "SSH": true,
  60. "TCP": true,
  61. "TLS": true,
  62. "TTL": true,
  63. "UDP": true,
  64. "UI": true,
  65. "UID": true,
  66. "UUID": true,
  67. "URI": true,
  68. "URL": true,
  69. "UTF8": true,
  70. "VM": true,
  71. "XML": true,
  72. "XMPP": true,
  73. "XSRF": true,
  74. "XSS": true,
  75. }
  76. // a thread-safe index of initialisms
  77. commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms)
  78. initialisms = commonInitialisms.sorted()
  79. initialismsRunes = asRunes(initialisms)
  80. initialismsUpperCased = asUpperCased(initialisms)
  81. maxAllocMatches = maxAllocHeuristic(initialismsRunes)
  82. // a test function
  83. isInitialism = commonInitialisms.isInitialism
  84. }
  85. func asRunes(in []string) [][]rune {
  86. out := make([][]rune, len(in))
  87. for i, initialism := range in {
  88. out[i] = []rune(initialism)
  89. }
  90. return out
  91. }
  92. func asUpperCased(in []string) [][]rune {
  93. out := make([][]rune, len(in))
  94. for i, initialism := range in {
  95. out[i] = []rune(upper(trim(initialism)))
  96. }
  97. return out
  98. }
  99. func maxAllocHeuristic(in [][]rune) int {
  100. heuristic := make(map[rune]int)
  101. for _, initialism := range in {
  102. heuristic[initialism[0]]++
  103. }
  104. var maxAlloc int
  105. for _, val := range heuristic {
  106. if val > maxAlloc {
  107. maxAlloc = val
  108. }
  109. }
  110. return maxAlloc
  111. }
  112. // AddInitialisms add additional initialisms
  113. func AddInitialisms(words ...string) {
  114. for _, word := range words {
  115. // commonInitialisms[upper(word)] = true
  116. commonInitialisms.add(upper(word))
  117. }
  118. // sort again
  119. initialisms = commonInitialisms.sorted()
  120. initialismsRunes = asRunes(initialisms)
  121. initialismsUpperCased = asUpperCased(initialisms)
  122. }
  123. // indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms.
  124. // Since go1.9, this may be implemented with sync.Map.
  125. type indexOfInitialisms struct {
  126. sortMutex *sync.Mutex
  127. index *sync.Map
  128. }
  129. func newIndexOfInitialisms() *indexOfInitialisms {
  130. return &indexOfInitialisms{
  131. sortMutex: new(sync.Mutex),
  132. index: new(sync.Map),
  133. }
  134. }
  135. func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms {
  136. m.sortMutex.Lock()
  137. defer m.sortMutex.Unlock()
  138. for k, v := range initial {
  139. m.index.Store(k, v)
  140. }
  141. return m
  142. }
  143. func (m *indexOfInitialisms) isInitialism(key string) bool {
  144. _, ok := m.index.Load(key)
  145. return ok
  146. }
  147. func (m *indexOfInitialisms) add(key string) *indexOfInitialisms {
  148. m.index.Store(key, true)
  149. return m
  150. }
  151. func (m *indexOfInitialisms) sorted() (result []string) {
  152. m.sortMutex.Lock()
  153. defer m.sortMutex.Unlock()
  154. m.index.Range(func(key, _ interface{}) bool {
  155. k := key.(string)
  156. result = append(result, k)
  157. return true
  158. })
  159. sort.Sort(sort.Reverse(byInitialism(result)))
  160. return
  161. }
  162. type byInitialism []string
  163. func (s byInitialism) Len() int {
  164. return len(s)
  165. }
  166. func (s byInitialism) Swap(i, j int) {
  167. s[i], s[j] = s[j], s[i]
  168. }
  169. func (s byInitialism) Less(i, j int) bool {
  170. if len(s[i]) != len(s[j]) {
  171. return len(s[i]) < len(s[j])
  172. }
  173. return strings.Compare(s[i], s[j]) > 0
  174. }