-
Notifications
You must be signed in to change notification settings - Fork 1
/
eq.go
99 lines (85 loc) · 2.98 KB
/
eq.go
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// This file provides the Eq type, which represents strings that can
// be compared only for equality.
package intern
// An Eq is a string that has been interned to an integer. Eq supports only
// equality and inequality comparisons, not greater than/less than comparisons.
// (No checks are performed to enforce that usage model, unfortunately.)
type Eq symbol
// eq maintains all the state needed to manipulate Eqs.
var eq state
// init initializes our global state.
func init() {
eq.forgetAll()
}
// assignEq assigns the next available Eq symbol to a string and returns the
// new symbol. If the string already has an Eq associated with it, return the
// old Eq without allocating a new one.
func assignEq(s string) Eq {
// Check if the string was already assigned a symbol.
sym, ok := eq.strToSym[s]
if ok {
return Eq(sym)
}
// We haven't seen this string before. Find a symbol for it.
sym = symbol(len(eq.symToStr) + 1)
eq.symToStr[sym] = s
eq.strToSym[s] = sym
return Eq(sym)
}
// NewEq maps a string to an Eq symbol. It guarantees that two equal strings
// will always map to the same Eq.
func NewEq(s string) Eq {
eq.Lock()
defer eq.Unlock()
return assignEq(s)
}
// NewEqMulti performs the same operation as NewEq but accepts a slice of
// strings instead of an individual string. This amortizes some costs when
// allocating a large number of Eqs at once.
func NewEqMulti(ss []string) []Eq {
eq.Lock()
defer eq.Unlock()
syms := make([]Eq, len(ss))
for i, s := range ss {
syms[i] = assignEq(s)
}
return syms
}
// String converts an Eq back to a string. It panics if given an Eq that was
// not created using NewEq.
func (s Eq) String() string {
return eq.toString(symbol(s), "Eq")
}
// ForgetAllEqs discards all existing mappings from strings to Eqs so the
// associated memory can be reclaimed. Use this function only when you know
// for sure that no previously mapped Eqs will subsequently be used.
func ForgetAllEqs() {
eq.Lock()
eq.forgetAll()
eq.Unlock()
}
// MarshalText converts an Eq to a string and that string to a slice of bytes.
// With this method, Eq implements the encoding.TextMarshaler interface.
func (s *Eq) MarshalText() ([]byte, error) {
return []byte(eq.toString(symbol(*s), "Eq")), nil
}
// UnmarshalText converts an slice of bytes to a string then interns that
// string to an Eq. With this method, Eq implements the
// encoding.TextUnmarshaler interface.
func (s *Eq) UnmarshalText(text []byte) error {
*s = NewEq(string(text))
return nil
}
// MarshalBinary converts an Eq to a string and that string to a slice of
// bytes. With this method, Eq implements the encoding.BinaryMarshaler
// interface.
func (s *Eq) MarshalBinary() ([]byte, error) {
return []byte(eq.toString(symbol(*s), "Eq")), nil
}
// UnmarshalBinary converts an slice of bytes to a string then interns that
// string to an Eq. With this method, Eq implements the
// encoding.BinaryUnmarshaler interface.
func (s *Eq) UnmarshalBinary(data []byte) error {
*s = NewEq(string(data))
return nil
}