github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/network/stream/intervals/intervals.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:48</date> 10 //</624342675423760384> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 package intervals 29 30 import ( 31 "bytes" 32 "fmt" 33 "strconv" 34 "sync" 35 ) 36 37 // 38 // 39 // 40 // 41 // 42 type Intervals struct { 43 start uint64 44 ranges [][2]uint64 45 mu sync.RWMutex 46 } 47 48 // 49 // 50 // 51 // 52 // 53 // 54 // 55 func NewIntervals(start uint64) *Intervals { 56 return &Intervals{ 57 start: start, 58 } 59 } 60 61 // 62 // 63 func (i *Intervals) Add(start, end uint64) { 64 i.mu.Lock() 65 defer i.mu.Unlock() 66 67 i.add(start, end) 68 } 69 70 func (i *Intervals) add(start, end uint64) { 71 if start < i.start { 72 start = i.start 73 } 74 if end < i.start { 75 return 76 } 77 minStartJ := -1 78 maxEndJ := -1 79 j := 0 80 for ; j < len(i.ranges); j++ { 81 if minStartJ < 0 { 82 if (start <= i.ranges[j][0] && end+1 >= i.ranges[j][0]) || (start <= i.ranges[j][1]+1 && end+1 >= i.ranges[j][1]) { 83 if i.ranges[j][0] < start { 84 start = i.ranges[j][0] 85 } 86 minStartJ = j 87 } 88 } 89 if (start <= i.ranges[j][1] && end+1 >= i.ranges[j][1]) || (start <= i.ranges[j][0] && end+1 >= i.ranges[j][0]) { 90 if i.ranges[j][1] > end { 91 end = i.ranges[j][1] 92 } 93 maxEndJ = j 94 } 95 if end+1 <= i.ranges[j][0] { 96 break 97 } 98 } 99 if minStartJ < 0 && maxEndJ < 0 { 100 i.ranges = append(i.ranges[:j], append([][2]uint64{{start, end}}, i.ranges[j:]...)...) 101 return 102 } 103 if minStartJ >= 0 { 104 i.ranges[minStartJ][0] = start 105 } 106 if maxEndJ >= 0 { 107 i.ranges[maxEndJ][1] = end 108 } 109 if minStartJ >= 0 && maxEndJ >= 0 && minStartJ != maxEndJ { 110 i.ranges[maxEndJ][0] = start 111 i.ranges = append(i.ranges[:minStartJ], i.ranges[maxEndJ:]...) 112 } 113 } 114 115 // 116 func (i *Intervals) Merge(m *Intervals) { 117 m.mu.RLock() 118 defer m.mu.RUnlock() 119 i.mu.Lock() 120 defer i.mu.Unlock() 121 122 for _, r := range m.ranges { 123 i.add(r[0], r[1]) 124 } 125 } 126 127 // 128 // 129 // 130 // 131 // 132 // 133 // 134 func (i *Intervals) Next() (start, end uint64) { 135 i.mu.RLock() 136 defer i.mu.RUnlock() 137 138 l := len(i.ranges) 139 if l == 0 { 140 return i.start, 0 141 } 142 if i.ranges[0][0] != i.start { 143 return i.start, i.ranges[0][0] - 1 144 } 145 if l == 1 { 146 return i.ranges[0][1] + 1, 0 147 } 148 return i.ranges[0][1] + 1, i.ranges[1][0] - 1 149 } 150 151 // 152 func (i *Intervals) Last() (end uint64) { 153 i.mu.RLock() 154 defer i.mu.RUnlock() 155 156 l := len(i.ranges) 157 if l == 0 { 158 return 0 159 } 160 return i.ranges[l-1][1] 161 } 162 163 // 164 // 165 func (i *Intervals) String() string { 166 return fmt.Sprint(i.ranges) 167 } 168 169 // 170 // 171 // 172 func (i *Intervals) MarshalBinary() (data []byte, err error) { 173 d := make([][]byte, len(i.ranges)+1) 174 d[0] = []byte(strconv.FormatUint(i.start, 36)) 175 for j := range i.ranges { 176 r := i.ranges[j] 177 d[j+1] = []byte(strconv.FormatUint(r[0], 36) + "," + strconv.FormatUint(r[1], 36)) 178 } 179 return bytes.Join(d, []byte(";")), nil 180 } 181 182 // 183 func (i *Intervals) UnmarshalBinary(data []byte) (err error) { 184 d := bytes.Split(data, []byte(";")) 185 l := len(d) 186 if l == 0 { 187 return nil 188 } 189 if l >= 1 { 190 i.start, err = strconv.ParseUint(string(d[0]), 36, 64) 191 if err != nil { 192 return err 193 } 194 } 195 if l == 1 { 196 return nil 197 } 198 199 i.ranges = make([][2]uint64, 0, l-1) 200 for j := 1; j < l; j++ { 201 r := bytes.SplitN(d[j], []byte(","), 2) 202 if len(r) < 2 { 203 return fmt.Errorf("range %d has less then 2 elements", j) 204 } 205 start, err := strconv.ParseUint(string(r[0]), 36, 64) 206 if err != nil { 207 return fmt.Errorf("parsing the first element in range %d: %v", j, err) 208 } 209 end, err := strconv.ParseUint(string(r[1]), 36, 64) 210 if err != nil { 211 return fmt.Errorf("parsing the second element in range %d: %v", j, err) 212 } 213 i.ranges = append(i.ranges, [2]uint64{start, end}) 214 } 215 216 return nil 217 } 218