...

Source file src/github.com/go-openapi/swag/initialism_index.go

Documentation: github.com/go-openapi/swag

     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  
    15  package swag
    16  
    17  import (
    18  	"sort"
    19  	"strings"
    20  	"sync"
    21  )
    22  
    23  var (
    24  	// commonInitialisms are common acronyms that are kept as whole uppercased words.
    25  	commonInitialisms *indexOfInitialisms
    26  
    27  	// initialisms is a slice of sorted initialisms
    28  	initialisms []string
    29  
    30  	// a copy of initialisms pre-baked as []rune
    31  	initialismsRunes      [][]rune
    32  	initialismsUpperCased [][]rune
    33  
    34  	isInitialism func(string) bool
    35  
    36  	maxAllocMatches int
    37  )
    38  
    39  func init() {
    40  	// Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
    41  	configuredInitialisms := map[string]bool{
    42  		"ACL":   true,
    43  		"API":   true,
    44  		"ASCII": true,
    45  		"CPU":   true,
    46  		"CSS":   true,
    47  		"DNS":   true,
    48  		"EOF":   true,
    49  		"GUID":  true,
    50  		"HTML":  true,
    51  		"HTTPS": true,
    52  		"HTTP":  true,
    53  		"ID":    true,
    54  		"IP":    true,
    55  		"IPv4":  true,
    56  		"IPv6":  true,
    57  		"JSON":  true,
    58  		"LHS":   true,
    59  		"OAI":   true,
    60  		"QPS":   true,
    61  		"RAM":   true,
    62  		"RHS":   true,
    63  		"RPC":   true,
    64  		"SLA":   true,
    65  		"SMTP":  true,
    66  		"SQL":   true,
    67  		"SSH":   true,
    68  		"TCP":   true,
    69  		"TLS":   true,
    70  		"TTL":   true,
    71  		"UDP":   true,
    72  		"UI":    true,
    73  		"UID":   true,
    74  		"UUID":  true,
    75  		"URI":   true,
    76  		"URL":   true,
    77  		"UTF8":  true,
    78  		"VM":    true,
    79  		"XML":   true,
    80  		"XMPP":  true,
    81  		"XSRF":  true,
    82  		"XSS":   true,
    83  	}
    84  
    85  	// a thread-safe index of initialisms
    86  	commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms)
    87  	initialisms = commonInitialisms.sorted()
    88  	initialismsRunes = asRunes(initialisms)
    89  	initialismsUpperCased = asUpperCased(initialisms)
    90  	maxAllocMatches = maxAllocHeuristic(initialismsRunes)
    91  
    92  	// a test function
    93  	isInitialism = commonInitialisms.isInitialism
    94  }
    95  
    96  func asRunes(in []string) [][]rune {
    97  	out := make([][]rune, len(in))
    98  	for i, initialism := range in {
    99  		out[i] = []rune(initialism)
   100  	}
   101  
   102  	return out
   103  }
   104  
   105  func asUpperCased(in []string) [][]rune {
   106  	out := make([][]rune, len(in))
   107  
   108  	for i, initialism := range in {
   109  		out[i] = []rune(upper(trim(initialism)))
   110  	}
   111  
   112  	return out
   113  }
   114  
   115  func maxAllocHeuristic(in [][]rune) int {
   116  	heuristic := make(map[rune]int)
   117  	for _, initialism := range in {
   118  		heuristic[initialism[0]]++
   119  	}
   120  
   121  	var maxAlloc int
   122  	for _, val := range heuristic {
   123  		if val > maxAlloc {
   124  			maxAlloc = val
   125  		}
   126  	}
   127  
   128  	return maxAlloc
   129  }
   130  
   131  // AddInitialisms add additional initialisms
   132  func AddInitialisms(words ...string) {
   133  	for _, word := range words {
   134  		// commonInitialisms[upper(word)] = true
   135  		commonInitialisms.add(upper(word))
   136  	}
   137  	// sort again
   138  	initialisms = commonInitialisms.sorted()
   139  	initialismsRunes = asRunes(initialisms)
   140  	initialismsUpperCased = asUpperCased(initialisms)
   141  }
   142  
   143  // indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms.
   144  // Since go1.9, this may be implemented with sync.Map.
   145  type indexOfInitialisms struct {
   146  	sortMutex *sync.Mutex
   147  	index     *sync.Map
   148  }
   149  
   150  func newIndexOfInitialisms() *indexOfInitialisms {
   151  	return &indexOfInitialisms{
   152  		sortMutex: new(sync.Mutex),
   153  		index:     new(sync.Map),
   154  	}
   155  }
   156  
   157  func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms {
   158  	m.sortMutex.Lock()
   159  	defer m.sortMutex.Unlock()
   160  	for k, v := range initial {
   161  		m.index.Store(k, v)
   162  	}
   163  	return m
   164  }
   165  
   166  func (m *indexOfInitialisms) isInitialism(key string) bool {
   167  	_, ok := m.index.Load(key)
   168  	return ok
   169  }
   170  
   171  func (m *indexOfInitialisms) add(key string) *indexOfInitialisms {
   172  	m.index.Store(key, true)
   173  	return m
   174  }
   175  
   176  func (m *indexOfInitialisms) sorted() (result []string) {
   177  	m.sortMutex.Lock()
   178  	defer m.sortMutex.Unlock()
   179  	m.index.Range(func(key, _ interface{}) bool {
   180  		k := key.(string)
   181  		result = append(result, k)
   182  		return true
   183  	})
   184  	sort.Sort(sort.Reverse(byInitialism(result)))
   185  	return
   186  }
   187  
   188  type byInitialism []string
   189  
   190  func (s byInitialism) Len() int {
   191  	return len(s)
   192  }
   193  func (s byInitialism) Swap(i, j int) {
   194  	s[i], s[j] = s[j], s[i]
   195  }
   196  func (s byInitialism) Less(i, j int) bool {
   197  	if len(s[i]) != len(s[j]) {
   198  		return len(s[i]) < len(s[j])
   199  	}
   200  
   201  	return strings.Compare(s[i], s[j]) > 0
   202  }
   203  

View as plain text