<commit_before>//
// Copyright (c) XSharp B.V.  All Rights Reserved.  
// Licensed under the Apache License, Version 2.0.  
// See License.txt in the project root for license information.
//



USING XSharp.Internal
USING System.Reflection
USING System.Collections.Generic
USING System.Linq
USING System.Runtime.CompilerServices

INTERNAL STATIC CLASS OOPHelpers
    STATIC INTERNAL EnableOptimizations AS LOGIC
	STATIC METHOD FindOurAssemblies AS IEnumerable<Assembly>
		RETURN	FROM asm IN AppDomain.CurrentDomain:GetAssemblies() ;
				WHERE asm:IsDefined(TYPEOF( ClassLibraryAttribute ), FALSE) ;
				SELECT asm

	STATIC METHOD FindClipperFunctions(cFunction AS STRING) AS MethodInfo[]
		VAR cla := TYPEOF( ClassLibraryAttribute )
		LOCAL aMethods AS List<MethodInfo>
		aMethods := List<MethodInfo>{}
		FOREACH asm AS Assembly IN FindOurAssemblies()
			LOCAL atr := (ClassLibraryAttribute) (asm:GetCustomAttributes(cla,FALSE) [1]) AS ClassLibraryAttribute
			LOCAL oType AS System.Type
			oType := asm:GetType(atr:GlobalClassName,FALSE, TRUE)
			IF oType != NULL_OBJECT
				LOCAL oMI AS MethodInfo
				LOCAL bf AS BindingFlags
				bf := BindingFlags.Static | BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.DeclaredOnly 
				TRY 
					oMI := oType:GetMethod(cFunction,bf)
					IF oMI != NULL_OBJECT
						aMethods:Add( (MethodInfo) oMI)
					ENDIF
				CATCH AS AmbiguousMatchException
					LOCAL aMI AS MethodInfo[]
					aMI := oType:GetMethods(bf)
					FOREACH oM AS MethodInfo IN aMI
						IF String.Compare(oM:Name, cFunction, TRUE) == 0
							aMethods:Add( oM )
						ENDIF
					NEXT
				END TRY 
			ENDIF
		NEXT
		RETURN aMethods:ToArray()
		
	STATIC METHOD FindClass(cName AS STRING) AS System.Type 
	RETURN FindClass(cName, TRUE)
	STATIC METHOD FindClass(cName AS STRING, lOurAssembliesOnly AS LOGIC) AS System.Type 
		// TOdo Optimize
		LOCAL ret := NULL AS System.Type
		LOCAL aAssemblies AS IEnumerable<Assembly>
		
		IF String.IsNullOrWhiteSpace(cName)
			// otherwise asm:GetType() will throw an exception with empty name
			RETURN ret
		END IF

		IF lOurAssembliesOnly
			aAssemblies := FindOurAssemblies()
		ELSE
			aAssemblies := AppDomain.CurrentDomain:GetAssemblies()
		END IF
		
		FOREACH asm AS Assembly IN aAssemblies
			ret := asm:GetType( cName, FALSE, TRUE )
			IF ret != NULL
				EXIT 
			ENDIF
			// The class could be prefixed with a Namespace. 
			// If there is a class library attribute and we prefixed all classes with a namespace then
            // this is visible in the ClassLibraryAttribute
			// We don't know if the current assembly is compiler with /INS, but we assume it is when they
			// use the 'old fashioned' CreateInstance().
			VAR ins := TYPEOF( ClassLibraryAttribute )
			IF asm:IsDefined(  ins, FALSE )
                // there should be only one but it does not hurt to be cautious
                FOREACH VAR attribute IN asm:GetCustomAttributes(ins,FALSE)
				    VAR atr := (ClassLibraryAttribute) attribute
                    IF !String.IsNullOrEmpty(atr:DefaultNamespace)
				        VAR cFullName := atr:DefaultNamespace +"."+cName
				        ret := asm:GetType( cFullName, FALSE, TRUE )
				        IF ret != NULL
					        RETURN ret
                        ENDIF
                    ENDIF
                NEXT
            ENDIF
            // If there is an Implicit Namespace Attribute
            ins := TYPEOF( ImplicitNamespaceAttribute )
			IF asm:IsDefined(  ins, FALSE )
                FOREACH VAR attribute IN asm:GetCustomAttributes(ins,FALSE)
				    VAR atr := (ImplicitNamespaceAttribute) attribute
                    IF !String.IsNullOrEmpty(atr:Namespace)
				        VAR cFullName := atr:Namespace+"."+cName
				        ret := asm:GetType( cFullName, FALSE, TRUE )
				        IF ret != NULL
					        RETURN ret
                        ENDIF
                    ENDIF
                 NEXT
             ENDIF
		NEXT   <commit_msg>[runtime] Added caching for OOPHelpers.FindClass()<commit_after>//
// Copyright (c) <NAME>.V.  All Rights Reserved.  
// Licensed under the Apache License, Version 2.0.  
// See License.txt in the project root for license information.
//



USING XSharp.Internal
USING System.Reflection
USING System.Collections.Generic
USING System.Linq
USING System.Runtime.CompilerServices

INTERNAL STATIC CLASS OOPHelpers
    STATIC INTERNAL EnableOptimizations AS LOGIC
    STATIC INTERNAL cacheClassesAll AS Dictionary<STRING,Type>
    STATIC INTERNAL cacheClassesOurAssemblies AS Dictionary<STRING,Type>

    STATIC CONSTRUCTOR()
	    cacheClassesAll := Dictionary<STRING,Type>{Stringcomparer.OrdinalIgnoreCase}
	    cacheClassesOurAssemblies := Dictionary<STRING,Type>{Stringcomparer.OrdinalIgnoreCase}
	RETURN
    
	STATIC METHOD FindOurAssemblies AS IEnumerable<Assembly>
		RETURN	FROM asm IN AppDomain.CurrentDomain:GetAssemblies() ;
				WHERE asm:IsDefined(TYPEOF( ClassLibraryAttribute ), FALSE) ;
				SELECT asm

	STATIC METHOD FindClipperFunctions(cFunction AS STRING) AS MethodInfo[]
		VAR cla := TYPEOF( ClassLibraryAttribute )
		LOCAL aMethods AS List<MethodInfo>
		aMethods := List<MethodInfo>{}
		FOREACH asm AS Assembly IN FindOurAssemblies()
			LOCAL atr := (ClassLibraryAttribute) (asm:GetCustomAttributes(cla,FALSE) [1]) AS ClassLibraryAttribute
			LOCAL oType AS System.Type
			oType := asm:GetType(atr:GlobalClassName,FALSE, TRUE)
			IF oType != NULL_OBJECT
				LOCAL oMI AS MethodInfo
				LOCAL bf AS BindingFlags
				bf := BindingFlags.Static | BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.DeclaredOnly 
				TRY 
					oMI := oType:GetMethod(cFunction,bf)
					IF oMI != NULL_OBJECT
						aMethods:Add( (MethodInfo) oMI)
					ENDIF
				CATCH AS AmbiguousMatchException
					LOCAL aMI AS MethodInfo[]
					aMI := oType:GetMethods(bf)
					FOREACH oM AS MethodInfo IN aMI
						IF String.Compare(oM:Name, cFunction, TRUE) == 0
							aMethods:Add( oM )
						ENDIF
					NEXT
				END TRY 
			ENDIF
		NEXT
		RETURN aMethods:ToArray()
		
	STATIC METHOD FindClass(cName AS STRING) AS System.Type 
	RETURN FindClass(cName, TRUE)
	STATIC METHOD FindClass(cName AS STRING, lOurAssembliesOnly AS LOGIC) AS System.Type 
		// TOdo Optimize
		LOCAL ret := NULL AS System.Type
		LOCAL aAssemblies AS IEnumerable<Assembly>
		
		IF String.IsNullOrWhiteSpace(cName)
			// otherwise asm:GetType() will throw an exception with empty name
			RETURN ret
		END IF

		IF lOurAssembliesOnly
			IF cacheClassesOurAssemblies:ContainsKey(cName)
				RETURN cacheClassesOurAssemblies[cName]
			END IF
			aAssemblies := FindOurAssemblies()
		ELSE
			IF cacheClassesAll:ContainsKey(cName)
				RETURN cacheClassesAll[cName]
			END IF
			aAssemblies := AppDomain.CurrentDomain:GetAssemblies()
		END IF
		
		FOREACH asm AS Assembly IN aAssemblies
			ret := asm:GetType( cName, FALSE, TRUE )
			IF ret != NULL
				EXIT 
			ENDIF
			// The class could be prefixed with a Namespace. 
			// If there is a class library attribute and we prefixed all classes with a namespace then
            // this is visible in the ClassLibraryAttribute
			// We don't know if the current assembly is compiler with /INS, but we assume it is when they
			// use the 'old fashioned' CreateInstance().
			VAR ins := TYPEOF( ClassLibraryAttribute )
			IF asm:IsDefined(  ins, FALSE )
                // there should be only one but it does not hurt to be cautious
                FOREACH VAR attribute IN asm:GetCustomAttributes(ins,FALSE)
				    VAR atr := (ClassLibraryAttribute) attribute
                    IF !String.IsNullOrEmpty(atr:DefaultNamespace)
				        VAR cFullName := atr:DefaultNamespace +"."+cName
				        ret := asm:GetType( cFullName, FALSE, TRUE )
				        IF ret != NULL
					        EXIT
                        ENDIF
                    ENDIF
                NEXT
            ENDIF
            IF ret != NULL
            	EXIT
            END IF
            // If there is an Implicit Namespace Attribute
            ins := TYPEOF( ImplicitNamespaceAttribute )
			IF asm:IsDefined(  ins, FALSE )
                FOREACH VAR attribute IN asm:GetCustomAttributes(ins,FALSE)
				    VAR atr := (ImplicitNamespaceAttribute) attribute
                    IF !String.IsNullOrEmpty(atr:Namespace)
				        VAR cFullName := atr:Namespace+"."+cName
				        ret := asm:GetType( cFullName, FALSE, TRUE )
				        IF ret != NULL
					        EXIT
                        ENDIF
                    ENDIF
                 NEXT
             ENDIF
             IF ret != NULL
             	EXIT
             ENDIF
		NEXT
		
		IF ret != NULL
			IF lOurAssembliesOnly
				IF .not. cacheClassesOurAssemblies:ContainsKey(cName)
					cacheClassesOurAssemblies:Add(cName , ret)
				END IF
			ELSE
				IF .not. cacheClassesAll:ContainsKey(cName)
					cacheClassesAll:Add(cName , ret)
				END IF
			END IF
		END IF
		
{'fraction_non_alphanumeric': 0.06866515837104073, 'fraction_numerical': 0.0009049773755656109, 'mean_word_length': 2.6293103448275863, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 16, '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': '346738', 'n_tokens_mistral': 3014, 'n_tokens_neox': 2504, 'n_words': 803}