<commit_before>﻿// Nu Game Engine.
// Copyright (C) <NAME>, 2013-2015.

namespace Nu
open System
open System.Configuration
open System.ComponentModel
open System.Reflection
open System.Text
open Prime
open Nu

/// A name key for optimized look-up in hashing containers.
/// OPTIMIZATION: OptHashCode is lazy for speed.
type [<CustomEquality; NoComparison>] NameKey =
    private
        { Name : string
          mutable OptHashCode : int option }

    interface NameKey IEquatable with
        member this.Equals that =
            this.Name = that.Name

    override this.Equals that =
        match that with
        | :? NameKey as that -> this.Name = that.Name
        | _ -> false

    override this.GetHashCode () =
        match this.OptHashCode with
        | Some hashCode -> hashCode
        | None ->
            let hashCode = hash this.Name
            this.OptHashCode <- Some hashCode
            hashCode

    override this.ToString () =
        this.Name

[<RequireQualifiedAccess; CompilationRepresentation (CompilationRepresentationFlags.ModuleSuffix)>]
module NameKey =

    /// Make a name key from a single address name string.
    let make addressName =
        { Name = addressName
          OptHashCode = None }

    /// Get the name of a name key.
    let getName nameKey =
        nameKey.Name

/// Specifies the address of an element in a game, or name of an event.
/// OPTIMIZATION: NameKeys are used in case we can manage some sort of hashing look-up with them.
/// OPTIMIZATION: Comparison is done using the full string of names for speed.
/// OPTIMIZATION: OptNamesStr and OptHashCode are lazy for speed.
type [<CustomEquality; CustomComparison; TypeConverter (typeof<AddressConverter>)>] 'a Address =
    private
        { NameKeys : NameKey list
          mutable OptNamesStr : string option
          mutable OptHashCode : int option
          TypeCarrier : 'a -> unit }

    static member internal join (seq : string seq) =
        String.Join ("/", seq)

    static member internal split (str : string) =
        List.ofArray <| str.Split '/'

    static member internal getNamesStr (address : 'a Address) =
        match address.OptNamesStr with
        | Some namesStr -> namesStr
        | None ->
            let namesStr = address.NameKeys |> Seq.map (fun nameKey -> nameKey.Name) |> Address<'a>.join
            address.OptNamesStr <- Some namesStr
            namesStr

    static member internal getHashCode (address : 'a Address) =
        match address.OptHashCode with
        | Some hashCode -> hashCode
        | None ->
            let hashCode = hash <| Address<'a>.getNamesStr address
            address.OptHashCode <- Some hashCode
            hashCode

    interface 'a Address IComparable with
        member this.CompareTo that =
            String.Compare (Address<'a>.getNamesStr this, Address<'a>.getNamesStr that)

    interface IComparable with
        member this.CompareTo that =
            match that with
            | :? ('a Address) as that -> String.Compare (Address<'a>.getNamesStr this, Address<'a>.getNamesStr that)
            | _ -> failwith "Invalid Address comparison (comparee not of type Address)."

    interface 'a Address IEquatable with
        member this.Equals that =
            Address<'a>.getNamesStr this = Address<'a>.getNamesStr that

    override this.Equals that =
        match that with
        | :? ('a Address) as that -> Address<'a>.getNamesStr this = Address<'a>.getNamesStr that
        | _ -> false

    override this.GetHashCode () =
        Address<'a>.getHashCode this
    
    override this.ToString () =
        Address<'a>.getNamesStr this

/// Converts Address types.
and AddressConverter (targetType : Type) =
    inherit TypeConverter ()
    
    override this.CanConvertTo (_, destType) =
        destType = typeof<string> ||
        destType = targetType
        
    override this.ConvertTo (_, _, source, destType) =
        if destType = typeof<string> then
            let toStringMethod = targetType.GetMethod "ToString"
            toStringMethod.Invoke (source, null)
        elif destType = targetType then source
        else failwith "Invalid AddressConverter conversion to source."
        
    override this.CanConvertFrom (_, sourceType) =
        sourceType = typeof<string> ||
        sourceType = targetType
        
    override this.ConvertFrom (_, _, source) =
        match source with
        | :? string ->
            let stoaFunction = targetType.GetMethod ("stoa", BindingFlags.Static ||| BindingFlags.Public)
            stoaFunction.Invoke (null, [|source|])
        | _ ->
            if targetType.IsInstanceOfType source then source
            else failwith "Invalid AddressConverter conversion from source."

[<RequireQualifiedAccess>]
module Address =

    /// The empty address.
    let empty<'a> =
        { NameKeys = []; OptNamesStr = Some String.Empty; OptHashCode = Some 0; TypeCarrier = fun (_ : 'a) -> () }

    /// Make an address from name keys.
    let makeFromNameKeys<'a> nameKeys =
        { NameKeys = nameKeys; OptNamesStr = None; OptHashCode = None; TypeCarrier = fun (_ : 'a) -> () }

    /// Make an address from a list of names.
    let makeFromNamesList<'a> namesList =
        let nameKeys = List.map NameKey.make namesList
        makeFromNameKeys<'a> nameKeys

    /// Make an address from a '/' delimited string.
    let makeFromNamesString<'a> namesStr =
        let namesList = Address<'a>.split namesStr
        let nameKeys = List.map NameKey.make namesList
        { NameKeys = nameKeys; OptNamesStr = Some namesStr; OptHashCode = None; TypeCarrier = fun (_ : 'a) -> () }

    /// Convert a names string into an address.
    let stoa<'a> (namesStr : string) =
        makeFromNamesString<'a> namesStr
<commit_msg>Bit of code re-org for clarity.<commit_after>﻿// Nu Game Engine.
// Copyright (C) <NAME>, 2013-2015.

namespace Nu
open System
open System.Configuration
open System.ComponentModel
open System.Reflection
open System.Text
open Prime
open Nu

/// A name key for optimized look-up in hashing containers.
/// OPTIMIZATION: OptHashCode is lazy for speed.
type [<CustomEquality; NoComparison>] NameKey =
    private
        { Name : string
          mutable OptHashCode : int option }

    interface NameKey IEquatable with
        member this.Equals that =
            this.Name = that.Name

    override this.Equals that =
        match that with
        | :? NameKey as that -> this.Name = that.Name
        | _ -> false

    override this.GetHashCode () =
        match this.OptHashCode with
        | Some hashCode -> hashCode
        | None ->
            let hashCode = hash this.Name
            this.OptHashCode <- Some hashCode
            hashCode

    override this.ToString () =
        this.Name

[<RequireQualifiedAccess; CompilationRepresentation (CompilationRepresentationFlags.ModuleSuffix)>]
module NameKey =

    /// Make a name key from a single address name string.
    let make addressName =
        { Name = addressName
          OptHashCode = None }

    /// Get the name of a name key.
    let getName nameKey =
        nameKey.Name

/// Converts Address types.
type AddressConverter (targetType : Type) =
    inherit TypeConverter ()
    
    override this.CanConvertTo (_, destType) =
        destType = typeof<string> ||
        destType = targetType
        
    override this.ConvertTo (_, _, source, destType) =
        if destType = typeof<string> then
            let toStringMethod = targetType.GetMethod "ToString"
            toStringMethod.Invoke (source, null)
        elif destType = targetType then source
        else failwith "Invalid AddressConverter conversion to source."
        
    override this.CanConvertFrom (_, sourceType) =
        sourceType = typeof<string> ||
        sourceType = targetType
        
    override this.ConvertFrom (_, _, source) =
        match source with
        | :? string ->
            let stoaFunction = targetType.GetMethod ("stoa", BindingFlags.Static ||| BindingFlags.Public)
            stoaFunction.Invoke (null, [|source|])
        | _ ->
            if targetType.IsInstanceOfType source then source
            else failwith "Invalid AddressConverter conversion from source."

/// Specifies the address of an element in a game, or name of an event.
/// OPTIMIZATION: NameKeys are used in case we can manage some sort of hashing look-up with them.
/// OPTIMIZATION: Comparison is done using the full string of names for speed.
/// OPTIMIZATION: OptNamesStr and OptHashCode are lazy for speed.
and [<CustomEquality; CustomComparison; TypeConverter (typeof<AddressConverter>)>] 'a Address =
    private
        { NameKeys : NameKey list
          mutable OptNamesStr : string option
          mutable OptHashCode : int option
          TypeCarrier : 'a -> unit }

    static member internal join (seq : string seq) =
        String.Join ("/", seq)

    static member internal split (str : string) =
        List.ofArray <| str.Split '/'

    static member internal getNamesStr (address : 'a Address) =
        match address.OptNamesStr with
        | Some namesStr -> namesStr
        | None ->
            let namesStr = address.NameKeys |> Seq.map (fun nameKey -> nameKey.Name) |> Address<'a>.join
            address.OptNamesStr <- Some namesStr
            namesStr

    static member internal getHashCode (address : 'a Address) =
        match address.OptHashCode with
        | Some hashCode -> hashCode
        | None ->
            let hashCode = hash <| Address<'a>.getNamesStr address
            address.OptHashCode <- Some hashCode
            hashCode

    interface 'a Address IComparable with
        member this.CompareTo that =
            String.Compare (Address<'a>.getNamesStr this, Address<'a>.getNamesStr that)

    interface IComparable with
        member this.CompareTo that =
            match that with
            | :? ('a Address) as that -> String.Compare (Address<'a>.getNamesStr this, Address<'a>.getNamesStr that)
            | _ -> failwith "Invalid Address comparison (comparee not of type Address)."

    interface 'a Address IEquatable with
        member this.Equals that =
            Address<'a>.getNamesStr this = Address<'a>.getNamesStr that

    override this.Equals that =
        match that with
        | :? ('a Address) as that -> Address<'a>.getNamesStr this = Address<'a>.getNamesStr that
        | _ -> false

    override this.GetHashCode () =
        Address<'a>.getHashCode this
    
    override this.ToString () =
        Address<'a>.getNamesStr this

[<RequireQualifiedAccess>]
module Address =

    /// The empty address.
    let empty<'a> =
        { NameKeys = []; OptNamesStr = Some String.Empty; OptHashCode = Some 0; TypeCarrier = fun (_ : 'a) -> () }

    /// Make an address from name keys.
    let makeFromNameKeys<'a> nameKeys =
        { NameKeys = nameKeys; OptNamesStr = None; OptHashCode = None; TypeCarrier = fun (_ : 'a) -> () }

    /// Make an address from a list of names.
    let makeFromNamesList<'a> namesList =
        let nameKeys = List.map NameKey.make namesList
        makeFromNameKeys<'a> nameKeys

    /// Make an address from a '/' delimited string.
    let makeFromNamesString<'a> namesStr =
        let namesList = Address<'a>.split namesStr
        let nameKeys = List.map NameKey.make namesList
        { NameKeys = nameKeys; OptNamesStr = Some namesStr; OptHashCode = None; TypeCarrier = fun (_ : 'a) -> () }

    /// Convert a names string into an address.
    let stoa<'a> (namesStr : string) =
        makeFromNamesString<'a> namesStr

{'fraction_non_alphanumeric': 0.09137931034482759, 'fraction_numerical': 0.0015517241379310344, 'mean_word_length': 2.3684668989547037, 'pattern_counts': {'":': 0, '<': 71, '<?xml version=': 0, '>': 103, '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': '2313720', 'n_tokens_mistral': 3128, 'n_tokens_neox': 3085, 'n_words': 1027}