github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/aeron/util/bits.go (about)

     1  /*
     2  Copyright 2016 Stanislav Liberman
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package util
    18  
    19  import (
    20  	"fmt"
    21  	"unsafe"
    22  )
    23  
    24  var i32 int32
    25  var i64 int64
    26  
    27  const (
    28  	// CacheLineLength is a constant for the size of a CPU cache line
    29  	CacheLineLength int32 = 64
    30  
    31  	// SizeOfInt32 is a constant for the size of int32. Ha. Just for Clarity
    32  	SizeOfInt32 int32 = int32(unsafe.Sizeof(i32))
    33  
    34  	// SizeOfInt64 is a constant for the size of int64
    35  	SizeOfInt64 int32 = int32(unsafe.Sizeof(i64))
    36  )
    37  
    38  // AlignInt32 will return a number rounded up to the alignment boundary
    39  func AlignInt32(value, alignment int32) int32 {
    40  	return (value + (alignment - 1)) & ^(alignment - 1)
    41  }
    42  
    43  // NumberOfTrailingZeroes is HD recipe for determining the number of leading zeros on 32 bit integer
    44  func NumberOfTrailingZeroes(value uint32) uint8 {
    45  	table := [32]uint8{
    46  		0, 1, 2, 24, 3, 19, 6, 25,
    47  		22, 4, 20, 10, 16, 7, 12, 26,
    48  		31, 23, 18, 5, 21, 9, 15, 11,
    49  		30, 17, 8, 14, 29, 13, 28, 27}
    50  
    51  	if value == 0 {
    52  		return 32
    53  	}
    54  
    55  	value = (value & -value) * 0x04D7651F
    56  
    57  	return table[value>>27]
    58  }
    59  
    60  // FastMod3 is HD recipe for faster division by 3 for 32 bit integers
    61  func FastMod3(value uint64) int32 {
    62  
    63  	table := [62]int32{0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2,
    64  		0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2,
    65  		0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2,
    66  		0, 1, 2, 0, 1, 2, 0, 1}
    67  
    68  	value = (value >> 16) + (value & 0xFFFF) // Max 0x1FFFE.
    69  	value = (value >> 8) + (value & 0x00FF)  // Max 0x2FD.
    70  	value = (value >> 4) + (value & 0x000F)  // Max 0x3D.
    71  	return table[value]
    72  }
    73  
    74  // IsPowerOfTwo checks that the argument number is a power of two
    75  func IsPowerOfTwo(value int64) bool {
    76  	return value > 0 && ((value & (^value + 1)) == value)
    77  }
    78  
    79  // Memcpy will copy length bytes from pointer src to dest
    80  //go:nocheckptr
    81  func Memcpy(dest uintptr, src uintptr, length int32) {
    82  	var i int32
    83  
    84  	// batches of 8
    85  	i8 := length >> 3
    86  	for ; i < i8; i += 8 {
    87  		destPtr := unsafe.Pointer(dest + uintptr(i))
    88  		srcPtr := unsafe.Pointer(src + uintptr(i))
    89  
    90  		*(*uint64)(destPtr) = *(*uint64)(srcPtr)
    91  	}
    92  
    93  	// batches of 4
    94  	i4 := (length - i) >> 2
    95  	for ; i < i4; i += 4 {
    96  		destPtr := unsafe.Pointer(dest + uintptr(i))
    97  		srcPtr := unsafe.Pointer(src + uintptr(i))
    98  
    99  		*(*uint32)(destPtr) = *(*uint32)(srcPtr)
   100  	}
   101  
   102  	// remainder
   103  	for ; i < length; i++ {
   104  		destPtr := unsafe.Pointer(dest + uintptr(i))
   105  		srcPtr := unsafe.Pointer(src + uintptr(i))
   106  
   107  		*(*int8)(destPtr) = *(*int8)(srcPtr)
   108  	}
   109  }
   110  
   111  func MemPrint(ptr uintptr, len int) string {
   112  	var output string
   113  
   114  	for i := 0; i < len; i += 1 {
   115  		ptr := unsafe.Pointer(ptr + uintptr(i))
   116  		output += fmt.Sprintf("%02x ", *(*int8)(ptr))
   117  	}
   118  
   119  	return output
   120  }
   121  
   122  func Print(bytes []byte) {
   123  	for i, b := range bytes {
   124  		if i > 0 && i%16 == 0 && i%32 != 0 {
   125  			fmt.Print(" :  ")
   126  		}
   127  		if i > 0 && i%32 == 0 {
   128  			fmt.Print("\n")
   129  		}
   130  		fmt.Printf("%02x ", b)
   131  	}
   132  	fmt.Print("\n")
   133  }