helper_internal.go (3805B)
1 // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved. 2 // Use of this source code is governed by a MIT license found in the LICENSE file. 3 4 package codec 5 6 // maxArrayLen is the size of uint, which determines 7 // the maximum length of any array. 8 const maxArrayLen = 1<<((32<<(^uint(0)>>63))-1) - 1 9 10 // All non-std package dependencies live in this file, 11 // so porting to different environment is easy (just update functions). 12 13 func pruneSignExt(v []byte, pos bool) (n int) { 14 if len(v) < 2 { 15 } else if pos && v[0] == 0 { 16 for ; v[n] == 0 && n+1 < len(v) && (v[n+1]&(1<<7) == 0); n++ { 17 } 18 } else if !pos && v[0] == 0xff { 19 for ; v[n] == 0xff && n+1 < len(v) && (v[n+1]&(1<<7) != 0); n++ { 20 } 21 } 22 return 23 } 24 25 func halfFloatToFloatBits(h uint16) (f uint32) { 26 // retrofitted from: 27 // - OGRE (Object-Oriented Graphics Rendering Engine) 28 // function: halfToFloatI https://www.ogre3d.org/docs/api/1.9/_ogre_bitwise_8h_source.html 29 30 s := uint32(h >> 15) 31 m := uint32(h & 0x03ff) 32 e := int32((h >> 10) & 0x1f) 33 34 if e == 0 { 35 if m == 0 { // plus or minus 0 36 return s << 31 37 } 38 // Denormalized number -- renormalize it 39 for (m & 0x0400) == 0 { 40 m <<= 1 41 e -= 1 42 } 43 e += 1 44 m &= ^uint32(0x0400) 45 } else if e == 31 { 46 if m == 0 { // Inf 47 return (s << 31) | 0x7f800000 48 } 49 return (s << 31) | 0x7f800000 | (m << 13) // NaN 50 } 51 e = e + (127 - 15) 52 m = m << 13 53 return (s << 31) | (uint32(e) << 23) | m 54 } 55 56 func floatToHalfFloatBits(i uint32) (h uint16) { 57 // retrofitted from: 58 // - OGRE (Object-Oriented Graphics Rendering Engine) 59 // function: halfToFloatI https://www.ogre3d.org/docs/api/1.9/_ogre_bitwise_8h_source.html 60 // - http://www.java2s.com/example/java-utility-method/float-to/floattohalf-float-f-fae00.html 61 s := (i >> 16) & 0x8000 62 e := int32(((i >> 23) & 0xff) - (127 - 15)) 63 m := i & 0x7fffff 64 65 var h32 uint32 66 67 if e <= 0 { 68 if e < -10 { // zero 69 h32 = s // track -0 vs +0 70 } else { 71 m = (m | 0x800000) >> uint32(1-e) 72 h32 = s | (m >> 13) 73 } 74 } else if e == 0xff-(127-15) { 75 if m == 0 { // Inf 76 h32 = s | 0x7c00 77 } else { // NAN 78 m >>= 13 79 var me uint32 80 if m == 0 { 81 me = 1 82 } 83 h32 = s | 0x7c00 | m | me 84 } 85 } else { 86 if e > 30 { // Overflow 87 h32 = s | 0x7c00 88 } else { 89 h32 = s | (uint32(e) << 10) | (m >> 13) 90 } 91 } 92 h = uint16(h32) 93 return 94 } 95 96 // growCap will return a new capacity for a slice, given the following: 97 // - oldCap: current capacity 98 // - unit: in-memory size of an element 99 // - num: number of elements to add 100 func growCap(oldCap, unit, num uint) (newCap uint) { 101 // appendslice logic (if cap < 1024, *2, else *1.25): 102 // leads to many copy calls, especially when copying bytes. 103 // bytes.Buffer model (2*cap + n): much better for bytes. 104 // smarter way is to take the byte-size of the appended element(type) into account 105 106 // maintain 1 thresholds: 107 // t1: if cap <= t1, newcap = 2x 108 // else newcap = 1.5x 109 // 110 // t1 is always >= 1024. 111 // This means that, if unit size >= 16, then always do 2x or 1.5x (ie t1, t2, t3 are all same) 112 // 113 // With this, appending for bytes increase by: 114 // 100% up to 4K 115 // 50% beyond that 116 117 // unit can be 0 e.g. for struct{}{}; handle that appropriately 118 maxCap := num + (oldCap * 3 / 2) 119 if unit == 0 || maxCap > maxArrayLen || maxCap < oldCap { // handle wraparound, etc 120 return maxArrayLen 121 } 122 123 var t1 uint = 1024 // default thresholds for large values 124 if unit <= 4 { 125 t1 = 8 * 1024 126 } else if unit <= 16 { 127 t1 = 2 * 1024 128 } 129 130 newCap = 2 + num 131 if oldCap > 0 { 132 if oldCap <= t1 { // [0,t1] 133 newCap = num + (oldCap * 2) 134 } else { // (t1,infinity] 135 newCap = maxCap 136 } 137 } 138 139 // ensure newCap takes multiples of a cache line (size is a multiple of 64) 140 t1 = newCap * unit 141 if t2 := t1 % 64; t2 != 0 { 142 t1 += 64 - t2 143 newCap = t1 / unit 144 } 145 146 return 147 }