| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package bindings | |
| 6 | |
| 7 import ( | |
| 8 "encoding/binary" | |
| 9 "fmt" | |
| 10 "math" | |
| 11 "sort" | |
| 12 | |
| 13 "mojo/public/go/system" | |
| 14 ) | |
| 15 | |
| 16 // encodingState has information required to encode/decode a one-level value. | |
| 17 type encodingState struct { | |
| 18 // Index of the first unprocessed byte. | |
| 19 offset int | |
| 20 | |
| 21 // Index of the first unprocessed bit of buffer[offset] byte. | |
| 22 bitOffset uint32 | |
| 23 | |
| 24 // Index of the first byte after the claimed buffer block for the curren
t | |
| 25 // one-level value. | |
| 26 limit int | |
| 27 | |
| 28 // Number of elements declared in the data header for the current one-le
vel | |
| 29 // value. | |
| 30 elements uint32 | |
| 31 | |
| 32 // Number of elements already encoded/decoded of the current one-level | |
| 33 // value. | |
| 34 elementsProcessed uint32 | |
| 35 | |
| 36 // Whether the number of elements processed should be checked. | |
| 37 checkElements bool | |
| 38 } | |
| 39 | |
| 40 func (s *encodingState) alignOffsetToBytes() { | |
| 41 if s.bitOffset > 0 { | |
| 42 s.offset++ | |
| 43 s.bitOffset = 0 | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 func (s *encodingState) skipBits(count uint32) { | |
| 48 s.bitOffset += count | |
| 49 s.offset += int(s.bitOffset >> 3) // equal to s.bitOffset / 8 | |
| 50 s.bitOffset &= 7 // equal to s.bitOffset % 8 | |
| 51 } | |
| 52 | |
| 53 func (s *encodingState) skipBytes(count int) { | |
| 54 s.bitOffset = 0 | |
| 55 s.offset += count | |
| 56 } | |
| 57 | |
| 58 // Encoder is a helper to encode mojo complex elements into mojo archive format. | |
| 59 type Encoder struct { | |
| 60 // Buffer containing encoded data. | |
| 61 buf []byte | |
| 62 | |
| 63 // Index of the first unclaimed byte in buf. | |
| 64 end int | |
| 65 | |
| 66 // Array containing encoded handles. | |
| 67 handles []system.UntypedHandle | |
| 68 | |
| 69 // A stack of encoder states matching current one-level value stack | |
| 70 // of the encoding data structure. | |
| 71 stateStack []encodingState | |
| 72 | |
| 73 // By default encoding is non-deterministic because the encoding of | |
| 74 // a mojom map does not specify the order of the keys and values. | |
| 75 // If |deterministic| is true then keys and values will be sorted | |
| 76 // in ascending key order. | |
| 77 deterministic bool | |
| 78 } | |
| 79 | |
| 80 func ensureElementBitSizeAndCapacity(state *encodingState, bitSize uint32) error
{ | |
| 81 if state == nil { | |
| 82 return fmt.Errorf("empty state stack") | |
| 83 } | |
| 84 if state.checkElements && state.elementsProcessed >= state.elements { | |
| 85 return fmt.Errorf("can't process more than elements defined in h
eader(%d)", state.elements) | |
| 86 } | |
| 87 byteSize := bytesForBits(uint64(state.bitOffset + bitSize)) | |
| 88 if align(state.offset+byteSize, byteSize) > state.limit { | |
| 89 return fmt.Errorf("buffer size limit exceeded") | |
| 90 } | |
| 91 return nil | |
| 92 } | |
| 93 | |
| 94 // claimData claims a block of |size| bytes for a one-level value, resizing | |
| 95 // buffer if needed. | |
| 96 func (e *Encoder) claimData(size int) { | |
| 97 e.end += size | |
| 98 if e.end < len(e.buf) { | |
| 99 return | |
| 100 } | |
| 101 newLen := e.end | |
| 102 if l := 2 * len(e.buf); newLen < l { | |
| 103 newLen = l | |
| 104 } | |
| 105 tmp := make([]byte, newLen) | |
| 106 copy(tmp, e.buf) | |
| 107 e.buf = tmp | |
| 108 } | |
| 109 | |
| 110 func (e *Encoder) popState() { | |
| 111 if len(e.stateStack) != 0 { | |
| 112 e.stateStack = e.stateStack[:len(e.stateStack)-1] | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 func (e *Encoder) pushState(header DataHeader, checkElements bool) { | |
| 117 oldEnd := e.end | |
| 118 e.claimData(align(int(header.Size), defaultAlignment)) | |
| 119 elements := uint32(0) | |
| 120 if checkElements { | |
| 121 elements = header.ElementsOrVersion | |
| 122 } | |
| 123 e.stateStack = append(e.stateStack, encodingState{ | |
| 124 offset: oldEnd, | |
| 125 limit: e.end, | |
| 126 elements: elements, | |
| 127 checkElements: checkElements, | |
| 128 }) | |
| 129 } | |
| 130 | |
| 131 // state returns encoder state of the top-level value. | |
| 132 func (e *Encoder) state() *encodingState { | |
| 133 if len(e.stateStack) == 0 { | |
| 134 return nil | |
| 135 } | |
| 136 return &e.stateStack[len(e.stateStack)-1] | |
| 137 } | |
| 138 | |
| 139 // NewEncoder returns a new instance of encoder. | |
| 140 func NewEncoder() *Encoder { | |
| 141 return &Encoder{} | |
| 142 } | |
| 143 | |
| 144 // SetDeterministic sets whether or not this encoder is deterministic. | |
| 145 // By default encoding is non-deterministic because the encoding of | |
| 146 // a mojom map does not specify the order of the keys and values. | |
| 147 // If SetDeterministic(true) is invoked then this encoder will, from then on, | |
| 148 // have the property that keys and values will be sorted in ascending key order. | |
| 149 // Warning: This causes encoding to be more expensive. | |
| 150 func (e *Encoder) SetDeterministic(deterministic bool) { | |
| 151 e.deterministic = deterministic | |
| 152 } | |
| 153 | |
| 154 func (e *Encoder) Deterministic() bool { | |
| 155 return e.deterministic | |
| 156 } | |
| 157 | |
| 158 // StartArray starts encoding an array and writes its data header. | |
| 159 // Note: it doesn't write a pointer to the encoded array. | |
| 160 // Call |Finish()| after writing all array elements. | |
| 161 func (e *Encoder) StartArray(length, elementBitSize uint32) { | |
| 162 dataSize := dataHeaderSize + bytesForBits(uint64(length)*uint64(elementB
itSize)) | |
| 163 header := DataHeader{uint32(dataSize), length} | |
| 164 e.pushState(header, true) | |
| 165 e.writeDataHeader(header) | |
| 166 } | |
| 167 | |
| 168 // StartMap starts encoding a map and writes its data header. | |
| 169 // Note: it doesn't write a pointer to the encoded map. | |
| 170 // Call |Finish()| after writing keys array and values array. | |
| 171 func (e *Encoder) StartMap() { | |
| 172 e.pushState(mapHeader, false) | |
| 173 e.writeDataHeader(mapHeader) | |
| 174 } | |
| 175 | |
| 176 // StartStruct starts encoding a struct and writes its data header. | |
| 177 // Note: it doesn't write a pointer to the encoded struct. | |
| 178 // Call |Finish()| after writing all fields. | |
| 179 func (e *Encoder) StartStruct(size, version uint32) { | |
| 180 dataSize := dataHeaderSize + int(size) | |
| 181 header := DataHeader{uint32(dataSize), version} | |
| 182 e.pushState(header, false) | |
| 183 e.writeDataHeader(header) | |
| 184 } | |
| 185 | |
| 186 // StartNestedUnion starts encoding a nested union. | |
| 187 // Note: it doesn't write a pointer or a union header. | |
| 188 // Call |Finish()| after writing all fields. | |
| 189 func (e *Encoder) StartNestedUnion() { | |
| 190 header := DataHeader{uint32(16), uint32(0)} | |
| 191 e.pushState(header, false) | |
| 192 } | |
| 193 | |
| 194 func (e *Encoder) writeDataHeader(header DataHeader) { | |
| 195 binary.LittleEndian.PutUint32(e.buf[e.state().offset:], header.Size) | |
| 196 binary.LittleEndian.PutUint32(e.buf[e.state().offset+4:], header.Element
sOrVersion) | |
| 197 e.state().offset += 8 | |
| 198 } | |
| 199 | |
| 200 // WriteUnionHeader writes a union header for a non-null union. | |
| 201 // (See. WriteNullUnion) | |
| 202 func (e *Encoder) WriteUnionHeader(tag uint32) error { | |
| 203 if err := ensureElementBitSizeAndCapacity(e.state(), 64); err != nil { | |
| 204 return err | |
| 205 } | |
| 206 e.state().alignOffsetToBytes() | |
| 207 e.state().offset = align(e.state().offset, 8) | |
| 208 binary.LittleEndian.PutUint32(e.buf[e.state().offset:], 16) | |
| 209 binary.LittleEndian.PutUint32(e.buf[e.state().offset+4:], tag) | |
| 210 e.state().offset += 8 | |
| 211 if err := ensureElementBitSizeAndCapacity(e.state(), 64); err != nil { | |
| 212 return err | |
| 213 } | |
| 214 return nil | |
| 215 } | |
| 216 | |
| 217 // FinishWritingUnionValue should call after the union value has been read in | |
| 218 // order to indicate to move the encoder past the union value field. | |
| 219 func (e *Encoder) FinishWritingUnionValue() { | |
| 220 e.state().offset = align(e.state().offset, 8) | |
| 221 e.state().alignOffsetToBytes() | |
| 222 } | |
| 223 | |
| 224 // Finish indicates the encoder that you have finished writing elements of | |
| 225 // a one-level value. | |
| 226 func (e *Encoder) Finish() error { | |
| 227 if e.state() == nil { | |
| 228 return fmt.Errorf("state stack is empty") | |
| 229 } | |
| 230 if e.state().checkElements && e.state().elementsProcessed != e.state().e
lements { | |
| 231 return fmt.Errorf("unexpected number of elements written: define
d in header %d, but written %d", e.state().elements, e.state().elementsProcessed
) | |
| 232 } | |
| 233 e.popState() | |
| 234 return nil | |
| 235 } | |
| 236 | |
| 237 // Data returns an encoded message with attached handles. | |
| 238 // Call this method after finishing encoding of a value. | |
| 239 func (e *Encoder) Data() ([]byte, []system.UntypedHandle, error) { | |
| 240 if len(e.stateStack) != 0 { | |
| 241 return nil, nil, fmt.Errorf("can't return data when encoder has
non-empty state stack") | |
| 242 } | |
| 243 return e.buf[:e.end], e.handles, nil | |
| 244 } | |
| 245 | |
| 246 // WriteBool writes a bool value. | |
| 247 func (e *Encoder) WriteBool(value bool) error { | |
| 248 if err := ensureElementBitSizeAndCapacity(e.state(), 1); err != nil { | |
| 249 return err | |
| 250 } | |
| 251 if value { | |
| 252 e.buf[e.state().offset] |= 1 << e.state().bitOffset | |
| 253 } | |
| 254 e.state().skipBits(1) | |
| 255 e.state().elementsProcessed++ | |
| 256 return nil | |
| 257 } | |
| 258 | |
| 259 // WriteBool writes an int8 value. | |
| 260 func (e *Encoder) WriteInt8(value int8) error { | |
| 261 return e.WriteUint8(uint8(value)) | |
| 262 } | |
| 263 | |
| 264 // WriteUint8 writes an uint8 value. | |
| 265 func (e *Encoder) WriteUint8(value uint8) error { | |
| 266 if err := ensureElementBitSizeAndCapacity(e.state(), 8); err != nil { | |
| 267 return err | |
| 268 } | |
| 269 e.state().alignOffsetToBytes() | |
| 270 e.buf[e.state().offset] = value | |
| 271 e.state().skipBytes(1) | |
| 272 e.state().elementsProcessed++ | |
| 273 return nil | |
| 274 } | |
| 275 | |
| 276 // WriteInt16 writes an int16 value. | |
| 277 func (e *Encoder) WriteInt16(value int16) error { | |
| 278 return e.WriteUint16(uint16(value)) | |
| 279 } | |
| 280 | |
| 281 // WriteUint16 writes an uint16 value. | |
| 282 func (e *Encoder) WriteUint16(value uint16) error { | |
| 283 if err := ensureElementBitSizeAndCapacity(e.state(), 16); err != nil { | |
| 284 return err | |
| 285 } | |
| 286 e.state().alignOffsetToBytes() | |
| 287 e.state().offset = align(e.state().offset, 2) | |
| 288 binary.LittleEndian.PutUint16(e.buf[e.state().offset:], value) | |
| 289 e.state().skipBytes(2) | |
| 290 e.state().elementsProcessed++ | |
| 291 return nil | |
| 292 } | |
| 293 | |
| 294 // WriteInt32 writes an int32 value. | |
| 295 func (e *Encoder) WriteInt32(value int32) error { | |
| 296 return e.WriteUint32(uint32(value)) | |
| 297 } | |
| 298 | |
| 299 // WriteUint32 writes an uint32 value. | |
| 300 func (e *Encoder) WriteUint32(value uint32) error { | |
| 301 if err := ensureElementBitSizeAndCapacity(e.state(), 32); err != nil { | |
| 302 return err | |
| 303 } | |
| 304 e.state().alignOffsetToBytes() | |
| 305 e.state().offset = align(e.state().offset, 4) | |
| 306 binary.LittleEndian.PutUint32(e.buf[e.state().offset:], value) | |
| 307 e.state().skipBytes(4) | |
| 308 e.state().elementsProcessed++ | |
| 309 return nil | |
| 310 } | |
| 311 | |
| 312 // WriteInt64 writes an int64 value. | |
| 313 func (e *Encoder) WriteInt64(value int64) error { | |
| 314 return e.WriteUint64(uint64(value)) | |
| 315 } | |
| 316 | |
| 317 // WriteUint64 writes an uint64 value. | |
| 318 func (e *Encoder) WriteUint64(value uint64) error { | |
| 319 if err := ensureElementBitSizeAndCapacity(e.state(), 64); err != nil { | |
| 320 return err | |
| 321 } | |
| 322 e.state().alignOffsetToBytes() | |
| 323 e.state().offset = align(e.state().offset, 8) | |
| 324 binary.LittleEndian.PutUint64(e.buf[e.state().offset:], value) | |
| 325 e.state().skipBytes(8) | |
| 326 e.state().elementsProcessed++ | |
| 327 return nil | |
| 328 } | |
| 329 | |
| 330 // WriteFloat32 writes a float32 value. | |
| 331 func (e *Encoder) WriteFloat32(value float32) error { | |
| 332 return e.WriteUint32(math.Float32bits(value)) | |
| 333 } | |
| 334 | |
| 335 // WriteFloat64 writes a float64 value. | |
| 336 func (e *Encoder) WriteFloat64(value float64) error { | |
| 337 return e.WriteUint64(math.Float64bits(value)) | |
| 338 } | |
| 339 | |
| 340 // WriteNullUnion writes a null union. | |
| 341 func (e *Encoder) WriteNullUnion() error { | |
| 342 if err := e.WriteUint64(0); err != nil { | |
| 343 return err | |
| 344 } | |
| 345 e.state().elementsProcessed-- | |
| 346 return e.WriteUint64(0) | |
| 347 } | |
| 348 | |
| 349 // WriteNullPointer writes a null pointer. | |
| 350 func (e *Encoder) WriteNullPointer() error { | |
| 351 return e.WriteUint64(0) | |
| 352 } | |
| 353 | |
| 354 // WriteString writes a string value. It doesn't write a pointer to the encoded | |
| 355 // string. | |
| 356 func (e *Encoder) WriteString(value string) error { | |
| 357 bytes := []byte(value) | |
| 358 e.StartArray(uint32(len(bytes)), 8) | |
| 359 for _, b := range bytes { | |
| 360 if err := e.WriteUint8(b); err != nil { | |
| 361 return err | |
| 362 } | |
| 363 } | |
| 364 return e.Finish() | |
| 365 } | |
| 366 | |
| 367 // WritePointer writes a pointer to first unclaimed byte index. | |
| 368 func (e *Encoder) WritePointer() error { | |
| 369 e.state().alignOffsetToBytes() | |
| 370 e.state().offset = align(e.state().offset, 8) | |
| 371 return e.WriteUint64(uint64(e.end - e.state().offset)) | |
| 372 } | |
| 373 | |
| 374 // WriteInvalidHandle an invalid handle. | |
| 375 func (e *Encoder) WriteInvalidHandle() error { | |
| 376 return e.WriteInt32(-1) | |
| 377 } | |
| 378 | |
| 379 // WriteHandle writes a handle and invalidates the passed handle object. | |
| 380 func (e *Encoder) WriteHandle(handle system.Handle) error { | |
| 381 if !handle.IsValid() { | |
| 382 return fmt.Errorf("can't write an invalid handle") | |
| 383 } | |
| 384 UntypedHandle := handle.ToUntypedHandle() | |
| 385 e.handles = append(e.handles, UntypedHandle) | |
| 386 return e.WriteUint32(uint32(len(e.handles) - 1)) | |
| 387 } | |
| 388 | |
| 389 // WriteInvalidInterface writes an invalid interface. | |
| 390 func (e *Encoder) WriteInvalidInterface() error { | |
| 391 if err := e.WriteInvalidHandle(); err != nil { | |
| 392 return err | |
| 393 } | |
| 394 e.state().elementsProcessed-- | |
| 395 return e.WriteUint32(0) | |
| 396 } | |
| 397 | |
| 398 // WriteInterface writes an interface and invalidates the passed handle object. | |
| 399 func (e *Encoder) WriteInterface(handle system.Handle) error { | |
| 400 if err := e.WriteHandle(handle); err != nil { | |
| 401 return err | |
| 402 } | |
| 403 e.state().elementsProcessed-- | |
| 404 // Set the version field to 0 for now. | |
| 405 return e.WriteUint32(0) | |
| 406 } | |
| 407 | |
| 408 // SortMapKeys will sort the slice pointed to by |slicePointer| | |
| 409 // if |slicePointer| is a pointer to a slice of a type that | |
| 410 // may be the key of a Mojo map. Otherwise SortMapKeys will do nothing. | |
| 411 func SortMapKeys(slicePointer interface{}) { | |
| 412 switch slicePointer := slicePointer.(type) { | |
| 413 case *[]bool: | |
| 414 sort.Sort(boolSlice(*slicePointer)) | |
| 415 case *[]float32: | |
| 416 sort.Sort(float32Slice(*slicePointer)) | |
| 417 case *[]float64: | |
| 418 sort.Float64s(*slicePointer) | |
| 419 case *[]int: | |
| 420 sort.Ints(*slicePointer) | |
| 421 case *[]int8: | |
| 422 sort.Sort(int8Slice(*slicePointer)) | |
| 423 case *[]int16: | |
| 424 sort.Sort(int16Slice(*slicePointer)) | |
| 425 case *[]int32: | |
| 426 sort.Sort(int32Slice(*slicePointer)) | |
| 427 case *[]int64: | |
| 428 sort.Sort(int64Slice(*slicePointer)) | |
| 429 case *[]string: | |
| 430 sort.Strings(*slicePointer) | |
| 431 case *[]uint8: | |
| 432 sort.Sort(uint8Slice(*slicePointer)) | |
| 433 case *[]uint16: | |
| 434 sort.Sort(uint16Slice(*slicePointer)) | |
| 435 case *[]uint32: | |
| 436 sort.Sort(uint32Slice(*slicePointer)) | |
| 437 case *[]uint64: | |
| 438 sort.Sort(uint64Slice(*slicePointer)) | |
| 439 default: | |
| 440 // Note(rudominer) Currently enums may not be used as map keys b
ut | |
| 441 // that may change in the future in which case we should handle
them | |
| 442 // here. | |
| 443 } | |
| 444 } | |
| 445 | |
| 446 // boolSlice | |
| 447 type boolSlice []bool | |
| 448 | |
| 449 func (s boolSlice) Len() int { | |
| 450 return len(s) | |
| 451 } | |
| 452 | |
| 453 func (s boolSlice) Less(i, j int) bool { | |
| 454 return s[i] && !s[j] | |
| 455 } | |
| 456 | |
| 457 func (s boolSlice) Swap(i, j int) { | |
| 458 s[i], s[j] = s[j], s[i] | |
| 459 } | |
| 460 | |
| 461 // float32Slice | |
| 462 type float32Slice []float32 | |
| 463 | |
| 464 func (s float32Slice) Len() int { | |
| 465 return len(s) | |
| 466 } | |
| 467 | |
| 468 func (s float32Slice) Less(i, j int) bool { | |
| 469 return s[i] < s[j] | |
| 470 } | |
| 471 | |
| 472 func (s float32Slice) Swap(i, j int) { | |
| 473 s[i], s[j] = s[j], s[i] | |
| 474 } | |
| 475 | |
| 476 // int8Slice | |
| 477 type int8Slice []int8 | |
| 478 | |
| 479 func (s int8Slice) Len() int { | |
| 480 return len(s) | |
| 481 } | |
| 482 | |
| 483 func (s int8Slice) Less(i, j int) bool { | |
| 484 return s[i] < s[j] | |
| 485 } | |
| 486 | |
| 487 func (s int8Slice) Swap(i, j int) { | |
| 488 s[i], s[j] = s[j], s[i] | |
| 489 } | |
| 490 | |
| 491 // int16Slice | |
| 492 type int16Slice []int16 | |
| 493 | |
| 494 func (s int16Slice) Len() int { | |
| 495 return len(s) | |
| 496 } | |
| 497 | |
| 498 func (s int16Slice) Less(i, j int) bool { | |
| 499 return s[i] < s[j] | |
| 500 } | |
| 501 | |
| 502 func (s int16Slice) Swap(i, j int) { | |
| 503 s[i], s[j] = s[j], s[i] | |
| 504 } | |
| 505 | |
| 506 // int32Slice | |
| 507 type int32Slice []int32 | |
| 508 | |
| 509 func (s int32Slice) Len() int { | |
| 510 return len(s) | |
| 511 } | |
| 512 | |
| 513 func (s int32Slice) Less(i, j int) bool { | |
| 514 return s[i] < s[j] | |
| 515 } | |
| 516 | |
| 517 func (s int32Slice) Swap(i, j int) { | |
| 518 s[i], s[j] = s[j], s[i] | |
| 519 } | |
| 520 | |
| 521 // int64Slice | |
| 522 type int64Slice []int64 | |
| 523 | |
| 524 func (s int64Slice) Len() int { | |
| 525 return len(s) | |
| 526 } | |
| 527 | |
| 528 func (s int64Slice) Less(i, j int) bool { | |
| 529 return s[i] < s[j] | |
| 530 } | |
| 531 | |
| 532 func (s int64Slice) Swap(i, j int) { | |
| 533 s[i], s[j] = s[j], s[i] | |
| 534 } | |
| 535 | |
| 536 // uint8Slice | |
| 537 type uint8Slice []uint8 | |
| 538 | |
| 539 func (s uint8Slice) Len() int { | |
| 540 return len(s) | |
| 541 } | |
| 542 | |
| 543 func (s uint8Slice) Less(i, j int) bool { | |
| 544 return s[i] < s[j] | |
| 545 } | |
| 546 | |
| 547 func (s uint8Slice) Swap(i, j int) { | |
| 548 s[i], s[j] = s[j], s[i] | |
| 549 } | |
| 550 | |
| 551 // uint16Slice | |
| 552 type uint16Slice []uint16 | |
| 553 | |
| 554 func (s uint16Slice) Len() int { | |
| 555 return len(s) | |
| 556 } | |
| 557 | |
| 558 func (s uint16Slice) Less(i, j int) bool { | |
| 559 return s[i] < s[j] | |
| 560 } | |
| 561 | |
| 562 func (s uint16Slice) Swap(i, j int) { | |
| 563 s[i], s[j] = s[j], s[i] | |
| 564 } | |
| 565 | |
| 566 // uint32Slice | |
| 567 type uint32Slice []uint32 | |
| 568 | |
| 569 func (s uint32Slice) Len() int { | |
| 570 return len(s) | |
| 571 } | |
| 572 | |
| 573 func (s uint32Slice) Less(i, j int) bool { | |
| 574 return s[i] < s[j] | |
| 575 } | |
| 576 | |
| 577 func (s uint32Slice) Swap(i, j int) { | |
| 578 s[i], s[j] = s[j], s[i] | |
| 579 } | |
| 580 | |
| 581 // uint64Slice | |
| 582 type uint64Slice []uint64 | |
| 583 | |
| 584 func (s uint64Slice) Len() int { | |
| 585 return len(s) | |
| 586 } | |
| 587 | |
| 588 func (s uint64Slice) Less(i, j int) bool { | |
| 589 return s[i] < s[j] | |
| 590 } | |
| 591 | |
| 592 func (s uint64Slice) Swap(i, j int) { | |
| 593 s[i], s[j] = s[j], s[i] | |
| 594 } | |
| OLD | NEW |