github.com/ugorji/go/codec@v1.2.13-0.20240307214044-07c54c229a5a/helper_internal.go (about)

     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  }