mirror of
https://github.com/IBM/fp-go.git
synced 2025-11-23 22:14:53 +02:00
242 lines
6.8 KiB
Go
242 lines
6.8 KiB
Go
// Copyright (c) 2023 - 2025 IBM Corp.
|
|
// All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package bytes
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
A "github.com/IBM/fp-go/v2/array"
|
|
O "github.com/IBM/fp-go/v2/ord"
|
|
)
|
|
|
|
var (
|
|
// Monoid is the Monoid instance for byte slices.
|
|
//
|
|
// This Monoid combines byte slices through concatenation, with an empty
|
|
// byte slice as the identity element. It satisfies the monoid laws:
|
|
//
|
|
// Identity laws:
|
|
// - Monoid.Concat(Monoid.Empty(), x) == x (left identity)
|
|
// - Monoid.Concat(x, Monoid.Empty()) == x (right identity)
|
|
//
|
|
// Associativity law:
|
|
// - Monoid.Concat(Monoid.Concat(a, b), c) == Monoid.Concat(a, Monoid.Concat(b, c))
|
|
//
|
|
// Operations:
|
|
// - Empty(): Returns an empty byte slice []byte{}
|
|
// - Concat(a, b []byte): Concatenates two byte slices
|
|
//
|
|
// Example - Basic concatenation:
|
|
//
|
|
// result := Monoid.Concat([]byte("Hello"), []byte(" World"))
|
|
// // result: []byte("Hello World")
|
|
//
|
|
// Example - Identity element:
|
|
//
|
|
// empty := Monoid.Empty()
|
|
// data := []byte("test")
|
|
// result1 := Monoid.Concat(empty, data) // []byte("test")
|
|
// result2 := Monoid.Concat(data, empty) // []byte("test")
|
|
//
|
|
// Example - Building byte buffers:
|
|
//
|
|
// buffer := Monoid.Empty()
|
|
// buffer = Monoid.Concat(buffer, []byte("Line 1\n"))
|
|
// buffer = Monoid.Concat(buffer, []byte("Line 2\n"))
|
|
// buffer = Monoid.Concat(buffer, []byte("Line 3\n"))
|
|
//
|
|
// Example - Associativity:
|
|
//
|
|
// a := []byte("a")
|
|
// b := []byte("b")
|
|
// c := []byte("c")
|
|
// left := Monoid.Concat(Monoid.Concat(a, b), c) // []byte("abc")
|
|
// right := Monoid.Concat(a, Monoid.Concat(b, c)) // []byte("abc")
|
|
// // left == right
|
|
//
|
|
// See also:
|
|
// - ConcatAll: For concatenating multiple byte slices at once
|
|
// - Empty(): Convenience function for getting empty byte slice
|
|
Monoid = A.Monoid[byte]()
|
|
|
|
// ConcatAll efficiently concatenates multiple byte slices into a single slice.
|
|
//
|
|
// This function takes a variadic number of byte slices and combines them
|
|
// into a single byte slice. It pre-allocates the exact amount of memory
|
|
// needed, making it more efficient than repeated concatenation.
|
|
//
|
|
// Parameters:
|
|
// - slices: Zero or more byte slices to concatenate
|
|
//
|
|
// Returns:
|
|
// - A new byte slice containing all input slices concatenated in order
|
|
//
|
|
// Performance:
|
|
//
|
|
// ConcatAll is more efficient than using Monoid.Concat repeatedly because
|
|
// it calculates the total size upfront and allocates memory once, avoiding
|
|
// multiple allocations and copies.
|
|
//
|
|
// Example - Basic usage:
|
|
//
|
|
// result := ConcatAll(
|
|
// []byte("Hello"),
|
|
// []byte(" "),
|
|
// []byte("World"),
|
|
// )
|
|
// // result: []byte("Hello World")
|
|
//
|
|
// Example - Empty input:
|
|
//
|
|
// result := ConcatAll()
|
|
// // result: []byte{}
|
|
//
|
|
// Example - Single slice:
|
|
//
|
|
// result := ConcatAll([]byte("test"))
|
|
// // result: []byte("test")
|
|
//
|
|
// Example - Building protocol messages:
|
|
//
|
|
// import "encoding/binary"
|
|
//
|
|
// header := []byte{0x01, 0x02}
|
|
// length := make([]byte, 4)
|
|
// binary.BigEndian.PutUint32(length, 100)
|
|
// payload := []byte("data")
|
|
// footer := []byte{0xFF}
|
|
//
|
|
// message := ConcatAll(header, length, payload, footer)
|
|
//
|
|
// Example - With empty slices:
|
|
//
|
|
// result := ConcatAll(
|
|
// []byte("a"),
|
|
// []byte{},
|
|
// []byte("b"),
|
|
// []byte{},
|
|
// []byte("c"),
|
|
// )
|
|
// // result: []byte("abc")
|
|
//
|
|
// Example - Building CSV line:
|
|
//
|
|
// fields := [][]byte{
|
|
// []byte("John"),
|
|
// []byte("Doe"),
|
|
// []byte("30"),
|
|
// }
|
|
// separator := []byte(",")
|
|
//
|
|
// // Interleave fields with separators
|
|
// parts := [][]byte{
|
|
// fields[0], separator,
|
|
// fields[1], separator,
|
|
// fields[2],
|
|
// }
|
|
// line := ConcatAll(parts...)
|
|
// // line: []byte("John,Doe,30")
|
|
//
|
|
// See also:
|
|
// - Monoid.Concat: For concatenating exactly two byte slices
|
|
// - bytes.Join: Standard library function for joining with separator
|
|
ConcatAll = A.ArrayConcatAll[byte]
|
|
|
|
// Ord is the Ord instance for byte slices providing lexicographic ordering.
|
|
//
|
|
// This Ord instance compares byte slices lexicographically (dictionary order),
|
|
// comparing bytes from left to right until a difference is found or one slice
|
|
// ends. It uses the standard library's bytes.Compare and bytes.Equal functions.
|
|
//
|
|
// Comparison rules:
|
|
// - Compares byte-by-byte from left to right
|
|
// - First differing byte determines the order
|
|
// - Shorter slice is less than longer slice if all bytes match
|
|
// - Empty slice is less than any non-empty slice
|
|
//
|
|
// Operations:
|
|
// - Compare(a, b []byte) int: Returns -1 if a < b, 0 if a == b, 1 if a > b
|
|
// - Equals(a, b []byte) bool: Returns true if slices are equal
|
|
//
|
|
// Example - Basic comparison:
|
|
//
|
|
// cmp := Ord.Compare([]byte("abc"), []byte("abd"))
|
|
// // cmp: -1 (abc < abd)
|
|
//
|
|
// cmp = Ord.Compare([]byte("xyz"), []byte("abc"))
|
|
// // cmp: 1 (xyz > abc)
|
|
//
|
|
// cmp = Ord.Compare([]byte("test"), []byte("test"))
|
|
// // cmp: 0 (equal)
|
|
//
|
|
// Example - Length differences:
|
|
//
|
|
// cmp := Ord.Compare([]byte("ab"), []byte("abc"))
|
|
// // cmp: -1 (shorter is less)
|
|
//
|
|
// cmp = Ord.Compare([]byte("abc"), []byte("ab"))
|
|
// // cmp: 1 (longer is greater)
|
|
//
|
|
// Example - Empty slices:
|
|
//
|
|
// cmp := Ord.Compare([]byte{}, []byte("a"))
|
|
// // cmp: -1 (empty is less)
|
|
//
|
|
// cmp = Ord.Compare([]byte{}, []byte{})
|
|
// // cmp: 0 (both empty)
|
|
//
|
|
// Example - Equality check:
|
|
//
|
|
// equal := Ord.Equals([]byte("test"), []byte("test"))
|
|
// // equal: true
|
|
//
|
|
// equal = Ord.Equals([]byte("test"), []byte("Test"))
|
|
// // equal: false (case-sensitive)
|
|
//
|
|
// Example - Sorting byte slices:
|
|
//
|
|
// import "github.com/IBM/fp-go/v2/array"
|
|
//
|
|
// data := [][]byte{
|
|
// []byte("zebra"),
|
|
// []byte("apple"),
|
|
// []byte("mango"),
|
|
// }
|
|
//
|
|
// sorted := array.Sort(Ord)(data)
|
|
// // sorted: [[]byte("apple"), []byte("mango"), []byte("zebra")]
|
|
//
|
|
// Example - Binary data comparison:
|
|
//
|
|
// cmp := Ord.Compare([]byte{0x01, 0x02}, []byte{0x01, 0x03})
|
|
// // cmp: -1 (0x02 < 0x03)
|
|
//
|
|
// Example - Finding minimum:
|
|
//
|
|
// import O "github.com/IBM/fp-go/v2/ord"
|
|
//
|
|
// a := []byte("xyz")
|
|
// b := []byte("abc")
|
|
// min := O.Min(Ord)(a, b)
|
|
// // min: []byte("abc")
|
|
//
|
|
// See also:
|
|
// - bytes.Compare: Standard library comparison function
|
|
// - bytes.Equal: Standard library equality function
|
|
// - array.Sort: For sorting slices using an Ord instance
|
|
Ord = O.MakeOrd(bytes.Compare, bytes.Equal)
|
|
)
|