<commit_before>namespace FSharpx.Collections

open System
open System.Collections
open System.Collections.Generic

/// An ArraySegment with structural comparison and equality.
[<CustomEquality; CustomComparison; SerializableAttribute; StructAttribute>]
type ByteString(array: byte[], offset: int, count: int) =
    new(array: byte[]) = ByteString(array, 0, array.Length)

    member x.Array = array

    member x.Offset = offset

    member x.Count = count

    /// Compares two byte strings based on their structure.
    static member Compare(a: ByteString, b: ByteString) =
        let x, o, l = a.Array, a.Offset, a.Count
        let x', o', l' = b.Array, b.Offset, b.Count

        if LanguagePrimitives.PhysicalEquality x x' && o = o' then
            if l = l' then 0
            elif l < l' then -1
            else 1
        else if l < l' then
            -1
        elif l > l' then
            1
        else
            let left, right = x.[o .. (o + l - 1)], x'.[o' .. (o' + l' - 1)]
            LanguagePrimitives.GenericComparison left right

    /// Compares two objects for equality. When both are byte strings, structural equality is used.
    override x.Equals(other) =
        match other with
        | :? ByteString as other' -> ByteString.Compare(x, other') = 0
        | _ -> false

    /// Gets the hash code for the byte string.
    override x.GetHashCode() =
        hash(x.Array, x.Offset, x.Count)

    /// Gets an enumerator for the bytes stored in the byte string.
    member x.GetEnumerator() =
        if x.Count = 0 then
            { new IEnumerator<_> with
                member self.Current = invalidOp "!"
              interface System.Collections.IEnumerator with
                  member self.Current = invalidOp "!"
                  member self.MoveNext() = false
                  member self.Reset() = ()
              interface System.IDisposable with
                  member self.Dispose() = ()
            }
        else
            let segment = x.Array
            let minIndex = x.Offset
            let maxIndex = x.Offset + x.Count - 1
            let mutable currentIndex = minIndex - 1

            { new IEnumerator<_> with
                member self.Current =
                    if currentIndex < minIndex then
                        invalidOp "Enumeration has not started. Call MoveNext."
                    elif currentIndex > maxIndex then
                        invalidOp "Enumeration already finished."
                    else
                        segment.[currentIndex]
              interface System.Collections.IEnumerator with
                  member self.Current =
                      if currentIndex < minIndex then
                          invalidOp "Enumeration has not started. Call MoveNext."
                      elif currentIndex > maxIndex then
                          invalidOp "Enumeration already finished."
                      else
                          box segment.[currentIndex]

                  member self.MoveNext() =
                      if currentIndex < maxIndex then
                          currentIndex <- currentIndex + 1
                          true
                      else
                          false

                  member self.Reset() =
                      currentIndex <- minIndex - 1
              interface System.IDisposable with
                  member self.Dispose() = ()
            }

    member this.Item
        with get pos = this.Array.[this.Offset + pos]

    interface System.IComparable with
        member x.CompareTo(other) =
            match other with
            | :? ByteString as other' -> ByteString.Compare(x, other')
            | _ -> invalidArg "other" "Cannot compare a value of another type."

    interface IEnumerable<byte> with
        // Gets an enumerator for the bytes stored in the byte string.
        member this.GetEnumerator() =
            this.GetEnumerator()

    interface IEnumerable with
        // Gets an enumerator for the bytes stored in the byte string.
        member this.GetEnumerator() =
            this.GetEnumerator() :> IEnumerator

    interface IReadOnlyList<byte> with
        member this.Item
            with get pos = this.[pos]

        member this.Count = this.Count



[<RequireQualifiedAccess>]
module ByteString =
    /// An active pattern for conveniently retrieving the properties of a ByteString.
    let (|BS|)(x: ByteString) =
        x.Array, x.Offset, x.Count

    /// needs .fsi file
    let empty = ByteString()

    /// needs .fsi file
    let singleton c =
        ByteString(Array.create 1 c, 0, 1)

    /// needs .fsi file
    let create arr =
        ByteString(arr, 0, arr.Length)

#if !FABLE_COMPILER
    /// needs .fsi file
    let findIndex pred (bs: ByteString) =
        Array.FindIndex(bs.Array, bs.Offset, bs.Count, Predicate<_>(pred))
#endif

#if !FABLE_COMPILER
    /// needs .fsi file
    let ofArraySegment(segment: ArraySegment<byte>) =
        ByteString(segment.Array, segment.Offset, segment.Count)
#endif<commit_msg>Fix ByteString.empty<commit_after>namespace FSharpx.Collections

open System
open System.Collections
open System.Collections.Generic

/// An ArraySegment with structural comparison and equality.
[<CustomEquality; CustomComparison; SerializableAttribute; StructAttribute>]
type ByteString(array: byte[], offset: int, count: int) =
    new(array: byte[]) = ByteString(array, 0, array.Length)

    member x.Array = array

    member x.Offset = offset

    member x.Count = count

    /// Compares two byte strings based on their structure.
    static member Compare(a: ByteString, b: ByteString) =
        let x, o, l = a.Array, a.Offset, a.Count
        let x', o', l' = b.Array, b.Offset, b.Count

        if LanguagePrimitives.PhysicalEquality x x' && o = o' then
            if l = l' then 0
            elif l < l' then -1
            else 1
        else if l < l' then
            -1
        elif l > l' then
            1
        else
            let left, right = x.[o .. (o + l - 1)], x'.[o' .. (o' + l' - 1)]
            LanguagePrimitives.GenericComparison left right

    /// Compares two objects for equality. When both are byte strings, structural equality is used.
    override x.Equals(other) =
        match other with
        | :? ByteString as other' -> ByteString.Compare(x, other') = 0
        | _ -> false

    /// Gets the hash code for the byte string.
    override x.GetHashCode() =
        hash(x.Array, x.Offset, x.Count)

    /// Gets an enumerator for the bytes stored in the byte string.
    member x.GetEnumerator() =
        if x.Count = 0 then
            { new IEnumerator<_> with
                member self.Current = invalidOp "!"
              interface System.Collections.IEnumerator with
                  member self.Current = invalidOp "!"
                  member self.MoveNext() = false
                  member self.Reset() = ()
              interface System.IDisposable with
                  member self.Dispose() = ()
            }
        else
            let segment = x.Array
            let minIndex = x.Offset
            let maxIndex = x.Offset + x.Count - 1
            let mutable currentIndex = minIndex - 1

            { new IEnumerator<_> with
                member self.Current =
                    if currentIndex < minIndex then
                        invalidOp "Enumeration has not started. Call MoveNext."
                    elif currentIndex > maxIndex then
                        invalidOp "Enumeration already finished."
                    else
                        segment.[currentIndex]
              interface System.Collections.IEnumerator with
                  member self.Current =
                      if currentIndex < minIndex then
                          invalidOp "Enumeration has not started. Call MoveNext."
                      elif currentIndex > maxIndex then
                          invalidOp "Enumeration already finished."
                      else
                          box segment.[currentIndex]

                  member self.MoveNext() =
                      if currentIndex < maxIndex then
                          currentIndex <- currentIndex + 1
                          true
                      else
                          false

                  member self.Reset() =
                      currentIndex <- minIndex - 1
              interface System.IDisposable with
                  member self.Dispose() = ()
            }

    member this.Item
        with get pos = this.Array.[this.Offset + pos]

    interface System.IComparable with
        member x.CompareTo(other) =
            match other with
            | :? ByteString as other' -> ByteString.Compare(x, other')
            | _ -> invalidArg "other" "Cannot compare a value of another type."

    interface IEnumerable<byte> with
        // Gets an enumerator for the bytes stored in the byte string.
        member this.GetEnumerator() =
            this.GetEnumerator()

    interface IEnumerable with
        // Gets an enumerator for the bytes stored in the byte string.
        member this.GetEnumerator() =
            this.GetEnumerator() :> IEnumerator

    interface IReadOnlyList<byte> with
        member this.Item
            with get pos = this.[pos]

        member this.Count = this.Count



[<RequireQualifiedAccess>]
module ByteString =
    /// An active pattern for conveniently retrieving the properties of a ByteString.
    let (|BS|)(x: ByteString) =
        x.Array, x.Offset, x.Count

    /// needs .fsi file
    let empty = ByteString([||])

    /// needs .fsi file
    let singleton c =
        ByteString(Array.create 1 c, 0, 1)

    /// needs .fsi file
    let create arr =
        ByteString(arr, 0, arr.Length)

#if !FABLE_COMPILER
    /// needs .fsi file
    let findIndex pred (bs: ByteString) =
        Array.FindIndex(bs.Array, bs.Offset, bs.Count, Predicate<_>(pred))
#endif

#if !FABLE_COMPILER
    /// needs .fsi file
    let ofArraySegment(segment: ArraySegment<byte>) =
        ByteString(segment.Array, segment.Offset, segment.Count)
#endif
{'fraction_non_alphanumeric': 0.08446112812407389, 'fraction_numerical': 0.0035562580262767955, 'mean_word_length': 1.6221186221186221, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5815529', 'n_tokens_mistral': 2657, 'n_tokens_neox': 2524, 'n_words': 866}