-
Notifications
You must be signed in to change notification settings - Fork 2
/
slice.go
143 lines (121 loc) · 3.25 KB
/
slice.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package shapes
import (
"fmt"
)
var (
_ Slicelike = Slices{Range{}, Range{}}
)
// Slice represents a slicing range.
type Slice interface {
Start() int
End() int
Step() int
}
// Range is a shape expression representing a slicing range. Coincidentally, Range also implements Slice.
//
// A Range is a shape expression but it doesn't stand alone - resolving it will yield an error.
type Range struct {
start, end, step int
}
func (s Range) isExpr() {}
func (s Range) depth() int { return 1 }
func (s Range) apply(ss substitutions) substitutable { return s }
func (s Range) freevars() varset { return nil }
// Exprs returns nil because we want a Sli to be treated as a monolithic expression term with nothing to unify on the inside.
func (s Range) subExprs() []substitutableExpr { return nil }
// Format allows Sli to implement fmt.Formmatter
func (s Range) Format(st fmt.State, r rune) {
if st.Flag('#') {
fmt.Fprintf(st, "{%d:%d:%d}", s.start, s.end, s.step)
return
}
fmt.Fprintf(st, "[%d", s.start)
if s.end-s.start > 1 {
fmt.Fprintf(st, ":%d", s.end)
}
if s.step > 1 {
fmt.Fprintf(st, "~:%d", s.step)
}
st.Write([]byte("]"))
}
/* Range implements Slice */
// Start returns the start of the slicing range
func (s Range) Start() int { return s.start }
// End returns the end of the slicing range
func (s Range) End() int { return s.end }
// Step returns the steps/jumps to make in the slicing range.
func (s Range) Step() int { return s.step }
// isSlicelike makes Range implement slicelike
func (s Range) isSlicelike() {}
// S creates a Slice. Internally it uses the Range type provided.
func S(start int, opt ...int) *Range {
var end, step int
if len(opt) > 0 {
end = opt[0]
} else {
end = start + 1
}
step = 1
if len(opt) > 1 {
step = opt[1]
}
return &Range{
start: start,
end: end,
step: step,
}
}
// toRange creates a Sli from a Slice.
func toRange(s Slice) Range {
if ss, ok := s.(Range); ok {
return ss
}
if ss, ok := s.(*Range); ok {
return *ss
}
return Range{s.Start(), s.End(), s.Step()}
}
// sliceSize is a support function for slicing a number
func sliceSize(sl Slice, sz int) (retVal int, err error) {
var start, end, step int
if start, end, step, err = SliceDetails(sl, sz); err != nil {
return
}
if step > 1 {
retVal = (end - start) / step
//fix
if retVal <= 0 {
retVal = 1
}
} else {
retVal = (end - start)
}
return
}
// ToSlicelike is a utility function for turning a slice into a Slicelike.
func ToSlicelike(s Slice) Slicelike { return toRange(s) }
// Slices is a list of slices.
type Slices []Slice
func (ss Slices) isSlicelike() {}
func (ss Slices) apply(_ substitutions) substitutable { return ss }
func (ss Slices) freevars() varset { return nil }
func (ss Slices) subExprs() []substitutableExpr { return nil }
func (ss Slices) Format(st fmt.State, r rune) {
st.Write([]byte("["))
for i, s := range ss {
start := s.Start()
end := s.End()
step := s.Step()
fmt.Fprintf(st, "%d", start)
if end-start > 1 {
fmt.Fprintf(st, ":%d", end)
}
if step > 1 {
fmt.Fprintf(st, "~:%d", step)
}
if i < len(ss)-1 {
st.Write([]byte(", "))
}
}
st.Write([]byte("]"))
}