From 968a6afe1aa0773f1d16b9f3040d6cc39d7345e1 Mon Sep 17 00:00:00 2001 From: Youmu Liu <105042599+Nitload-NSI@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:53:34 +0800 Subject: [PATCH] world timer supports numa and thread affinity binding --- .../Collections/CapacityFixedStack.cs | 22 ++++++- .../Environment/GlobalSetting.cs | 20 +++--- .../Environment/IStaticModule.cs | 65 ++++++++++--------- src/StgSharp.Common/Environment/Platform.cs | 27 ++++++-- .../Memory/SlabAllocator.Fixed.cs | 22 +++---- .../ProcessorAbstraction/Numa.cs | 3 +- src/StgSharp.Common/Timing/StgSharpTime.cs | 17 +++-- .../Timing/TimeSourceProvider.cs | 21 +++++- .../Timing/TimeThreadProfile.cs | 12 ++++ src/StgSharp.Graphics/GraphicInitializer.cs | 2 +- src/StgSharp.Graphics/glfw.cs | 2 +- .../Numeric/NumericalModule.cs | 2 +- .../Text/RegexAnalyzer.ASTGenerate.cs | 30 +++++++++ .../Text/RegexAnalyzer.ASTOptimize.cs | 32 ++++++--- .../Text/RegexAstNode.AdditionalPayload.cs | 9 +++ .../Text/RegexElementLabel.cs | 5 +- .../Text/TextRegexSourceGen.GenClass.cs | 3 + test/StgSharpDebug/Program.cs | 12 +++- test/StgSharpDebug/TestRegexAnalyse.cs | 5 -- 19 files changed, 223 insertions(+), 88 deletions(-) create mode 100644 src/StgSharp.Common/Timing/TimeThreadProfile.cs diff --git a/src/StgSharp.Common/Collections/CapacityFixedStack.cs b/src/StgSharp.Common/Collections/CapacityFixedStack.cs index d98d0d7a..34871971 100644 --- a/src/StgSharp.Common/Collections/CapacityFixedStack.cs +++ b/src/StgSharp.Common/Collections/CapacityFixedStack.cs @@ -6,9 +6,11 @@ // ----------------------------------------------------------------------------- using System; +using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Security.Cryptography; using System.Threading; namespace StgSharp.Collections @@ -122,6 +124,24 @@ namespace StgSharp.Collections _index += span.Length; } + public void PushRange( + SpanAction filling, + int count + ) + { + if (count == 0) { + return; + } + if (_index + count > _values.Length) { + throw new InvalidOperationException("Not enough space in the stack to push the entire span."); + } + if (filling is not null) + { + filling(_values.AsSpan()[_index..(_index + count)], count); + _index += count; + } + } + public bool TryPop( out T value ) @@ -163,4 +183,4 @@ namespace StgSharp.Collections } } -} \ No newline at end of file +} diff --git a/src/StgSharp.Common/Environment/GlobalSetting.cs b/src/StgSharp.Common/Environment/GlobalSetting.cs index a663f45a..60c5ac13 100644 --- a/src/StgSharp.Common/Environment/GlobalSetting.cs +++ b/src/StgSharp.Common/Environment/GlobalSetting.cs @@ -21,8 +21,6 @@ namespace StgSharp internal const int ssdSegmentLength = 16; - private static byte[] _currentHash = []; - private static bool _inited; public static byte[] CurrentAssemblyHash @@ -32,12 +30,10 @@ namespace StgSharp if (_currentHash == null) { string route = Assembly.GetExecutingAssembly().Location; - string time = DateTime.UtcNow.ToString(); - using (SHA256 sh = SHA256.Create()) - { - byte[] bytes = Encoding.UTF8.GetBytes(route); - _currentHash = sh.ComputeHash(bytes); - } + + // string time = DateTime.UtcNow.ToString(); + byte[] bytes = Encoding.UTF8.GetBytes(route); + _currentHash = SHA256.HashData(bytes); } return _currentHash; } @@ -52,6 +48,8 @@ namespace StgSharp internal set => _mainThreadID = value; } + private static byte[] _currentHash { get; set; } = []; + private static int _mainThreadID { get; set; } = -1; public static class GlobalSetting @@ -62,12 +60,10 @@ namespace StgSharp public static bool VSyncActivated { get => vsyncActivated; - set => - // GraphicFramework.glfwSwapInterval(value ? 1 : 0); - vsyncActivated = value; + set => vsyncActivated = value; // GraphicFramework.glfwSwapInterval(value ? 1 : 0); } } }//-------------------------------------- End of Class ---------------------------------------// -} \ No newline at end of file +} diff --git a/src/StgSharp.Common/Environment/IStaticModule.cs b/src/StgSharp.Common/Environment/IStaticModule.cs index 0cd31d14..7ebe9506 100644 --- a/src/StgSharp.Common/Environment/IStaticModule.cs +++ b/src/StgSharp.Common/Environment/IStaticModule.cs @@ -27,11 +27,11 @@ namespace StgSharp /// Performs all initialization work for this module using the provided profile. /// /// - /// The configuration profile supplied at registration time. Use if no configuration is required. + /// The configuration profile supplied at registration time. Use if no configuration is required. /// void InitializeModule( - IModuleInitializeProfile profile + IModuleInitializeConfiguration profile ); /// @@ -46,15 +46,15 @@ namespace StgSharp /// Marker interface for module initialization configuration. Implementations are plain data /// carriers; no static factory is required. /// - public interface IModuleInitializeProfile + public interface IModuleInitializeConfiguration { /// /// A shared, allocation-free empty profile for modules that require no configuration. /// - static readonly IModuleInitializeProfile Empty = EmptyModuleInitializeProfile.Instance; + static readonly IModuleInitializeConfiguration Empty = EmptyModuleInitializeProfile.Instance; - private sealed class EmptyModuleInitializeProfile : IModuleInitializeProfile + private sealed class EmptyModuleInitializeProfile : IModuleInitializeConfiguration { public static readonly EmptyModuleInitializeProfile Instance = new(); @@ -66,8 +66,8 @@ namespace StgSharp } /// - /// Pairs an with its , - /// ensuring the two are never stored or iterated independently. + /// Pairs an with its , ensuring the two are never stored or iterated independently. /// /// /// Using a avoids the boxing overhead that would occur if @@ -77,20 +77,20 @@ namespace StgSharp { /// - /// Initializes a new using as the profile. + /// Initializes a new using as the profile. /// public ModuleDescriptor( IStaticModule module ) - : this(module, IModuleInitializeProfile.Empty) { } + : this(module, IModuleInitializeConfiguration.Empty) { } /// /// Initializes a new with an explicit profile. /// public ModuleDescriptor( IStaticModule module, - IModuleInitializeProfile profile + IModuleInitializeConfiguration profile ) { Module = module; @@ -100,7 +100,7 @@ namespace StgSharp /// /// Gets the configuration profile associated with the module. /// - public IModuleInitializeProfile Profile { get; } + public IModuleInitializeConfiguration Profile { get; } /// /// Gets the module to be initialized. @@ -127,8 +127,8 @@ namespace StgSharp /// /// An ordered collection of modules to be initialized during application startup and - /// uninitialized on shutdown. Supports three registration strategies so that the new() - /// generic constraint is never a hard requirement. + /// uninitialized on shutdown. Supports three registration strategies so that the new() + /// /// generic constraint is never a hard requirement. /// public sealed class ModuleToInitializeCollection : IEnumerable, IStaticModule { @@ -136,10 +136,11 @@ namespace StgSharp private readonly List _descriptors = []; internal ModuleToInitializeCollection( - World.Initializer i + World.Initializer init, + World.InitializeConfiguration config ) { - _descriptors.Add(new ModuleDescriptor(i)); + _descriptors.Add(new ModuleDescriptor(init, config)); } // ── IEnumerable ─────────────────────────────────────────── @@ -189,11 +190,11 @@ namespace StgSharp /// public parameterless constructor. /// /// - /// Optional initialization profile. Defaults to when . + /// Optional initialization profile. Defaults to when . /// public ModuleToInitializeCollection UseModule( - IModuleInitializeProfile? profile = null + IModuleInitializeConfiguration? profile = null ) where T : IStaticModule, new() { return UseModule(static() => new T(), profile); @@ -206,17 +207,17 @@ namespace StgSharp /// /// /// A delegate that constructs and returns the module instance. The delegate is invoked - /// once, immediately at registration time. If is is or returns , the call is silently ignored /// and the collection is returned unchanged. /// /// - /// Optional initialization profile. Defaults to when . + /// Optional initialization profile. Defaults to when . /// public ModuleToInitializeCollection UseModule( Func factory, - IModuleInitializeProfile? profile = null + IModuleInitializeConfiguration? profile = null ) { if (factory is null) { @@ -228,7 +229,7 @@ namespace StgSharp } _descriptors.Add(new ModuleDescriptor( mod, - profile ?? IModuleInitializeProfile.Empty)); + profile ?? IModuleInitializeConfiguration.Empty)); return this; } @@ -240,17 +241,17 @@ namespace StgSharp /// The module instance to register. /// /// - /// Optional initialization profile. Defaults to when . + /// Optional initialization profile. Defaults to when . /// public ModuleToInitializeCollection UseModule( IStaticModule module, - IModuleInitializeProfile? profile = null + IModuleInitializeConfiguration? profile = null ) { _descriptors.Add(new ModuleDescriptor( module, - profile ?? IModuleInitializeProfile.Empty)); + profile ?? IModuleInitializeConfiguration.Empty)); return this; } @@ -263,12 +264,12 @@ namespace StgSharp // ── IStaticModule explicit implementation ──────────────────────────────── /// - /// Explicit implementation. Delegates to implementation. Delegates to , ignoring the supplied profile because each contained module uses /// its own registered profile. /// void IStaticModule.InitializeModule( - IModuleInitializeProfile profile + IModuleInitializeConfiguration profile ) { InitializeModule(); @@ -278,4 +279,4 @@ namespace StgSharp string IStaticModule.ModuleName => "Module Initializer"; } -} \ No newline at end of file +} diff --git a/src/StgSharp.Common/Environment/Platform.cs b/src/StgSharp.Common/Environment/Platform.cs index e55225ea..d81677af 100644 --- a/src/StgSharp.Common/Environment/Platform.cs +++ b/src/StgSharp.Common/Environment/Platform.cs @@ -7,6 +7,7 @@ using StgSharp.HighPerformance; using StgSharp.HighPerformance.ProcessorAbstraction; +using StgSharp.Timing; using System; using System.Reflection; using System.Runtime.CompilerServices; @@ -36,9 +37,11 @@ namespace StgSharp private static uint markCount = 0; internal static GraphicAPI API = default; - public static ModuleToInitializeCollection Initialize() + public static ModuleToInitializeCollection Initialize( + InitializeConfiguration config + ) { - return new ModuleToInitializeCollection(new Initializer()); + return new ModuleToInitializeCollection(new Initializer(), config); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -177,10 +180,12 @@ namespace StgSharp } } - internal static unsafe void InternalInitialize() + internal static unsafe void InternalInitialize( + InitializeConfiguration config + ) { // Initialize time provider and start providing time - MainTimeProvider.StartProvidingTime(); + MainTimeProvider.StartProvidingTime(config.TimingConfig); DefaultLog.InternalAppendLog("\n\n\n"); DefaultLog.InternalWriteLog( $"Program {Assembly.GetEntryAssembly()!.FullName} on {Environment.MachineName} Started.", LogType.Info); @@ -197,16 +202,26 @@ namespace StgSharp /**/ } + public class InitializeConfiguration : IModuleInitializeConfiguration + { + + public TimeSourceStartupConfiguration TimingConfig { get; set; } + + } + internal class Initializer : IStaticModule { public string ModuleName => "StgSharpCore"; public void InitializeModule( - IModuleInitializeProfile profile + IModuleInitializeConfiguration config ) { - World.InternalInitialize(); + if (config is not InitializeConfiguration world_init) { + throw new InvalidCastException(); + } + World.InternalInitialize(world_init); } public void UninitializeModule() diff --git a/src/StgSharp.Common/HighPerformance/Memory/SlabAllocator.Fixed.cs b/src/StgSharp.Common/HighPerformance/Memory/SlabAllocator.Fixed.cs index 032e744a..1486f784 100644 --- a/src/StgSharp.Common/HighPerformance/Memory/SlabAllocator.Fixed.cs +++ b/src/StgSharp.Common/HighPerformance/Memory/SlabAllocator.Fixed.cs @@ -40,19 +40,19 @@ namespace StgSharp.HighPerformance.Memory _buffer = buffer; _Capacity = count; - int initCount = count switch + _recycle = new((int)_Capacity); + _recycle.PushRange(init, (int)count); + _currentIndex = _Capacity; + + static void init( + Span arr, + int _ + ) { - <= 4 => 4, - > 64 => 64, - _ => (int)count - }; - Span span = stackalloc nuint[initCount]; - for (int i = 0; i < initCount; i++) { - span[i] = _buffer + ((nuint)(i * _elementSize)); + for (int i = 0; i < arr.Length; i++) { + arr[i] = (nuint)i; + } } - _recycle = CapacityFixedStackBuilder.Create(span); - _Capacity = count; - _currentIndex = (nuint)initCount; } public override nuint Allocate() diff --git a/src/StgSharp.Common/HighPerformance/ProcessorAbstraction/Numa.cs b/src/StgSharp.Common/HighPerformance/ProcessorAbstraction/Numa.cs index 20258831..bbf5383f 100644 --- a/src/StgSharp.Common/HighPerformance/ProcessorAbstraction/Numa.cs +++ b/src/StgSharp.Common/HighPerformance/ProcessorAbstraction/Numa.cs @@ -123,7 +123,8 @@ namespace StgSharp.HighPerformance.ProcessorAbstraction [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)] internal static partial void SetThreadAffinity( - int coreId + int coreId, + int numaId ); [MethodImpl(MethodImplOptions.NoInlining)] diff --git a/src/StgSharp.Common/Timing/StgSharpTime.cs b/src/StgSharp.Common/Timing/StgSharpTime.cs index 76c38e7a..7875ca0a 100644 --- a/src/StgSharp.Common/Timing/StgSharpTime.cs +++ b/src/StgSharp.Common/Timing/StgSharpTime.cs @@ -6,6 +6,7 @@ // ----------------------------------------------------------------------------- using StgSharp.Collections; +using StgSharp.HighPerformance.ProcessorAbstraction; using StgSharp.Timing; using System; using System.Diagnostics; @@ -39,7 +40,9 @@ namespace StgSharp return mainProvider.ElapsedTicks; } - public sealed override void StartProvidingTime() + public sealed override void StartProvidingTime( + TimeSourceStartupConfiguration threadConfig + ) { if (mainProvider.IsRunning) { return; @@ -49,9 +52,10 @@ namespace StgSharp timeProvideThread = new Thread(ProvideTime) { IsBackground = true, - Name = "StgSharpTime" + Name = "StgSharpTime", + Priority = threadConfig.Priority, }; - timeProvideThread.Start(); + timeProvideThread.Start(threadConfig); } public override void StopProvidingTime() @@ -82,13 +86,18 @@ namespace StgSharp _subscribers.Remove(subscriber); } - private void ProvideTime() + private void ProvideTime( + object? param + ) { + TimeSourceStartupConfiguration threadConfig = (TimeSourceStartupConfiguration)param!; long internalFrequency = Stopwatch.Frequency; // ticks per second lock (mainProvider) { mainProvider.Restart(); } + Thread.Sleep(10); + Numa.SetThreadAffinity((int)threadConfig.BindedCoreIndex, (int)threadConfig.BindedNumaNode); while (mainProvider.IsRunning) { long elapsedTicks; diff --git a/src/StgSharp.Common/Timing/TimeSourceProvider.cs b/src/StgSharp.Common/Timing/TimeSourceProvider.cs index ca881787..a0ba5b91 100644 --- a/src/StgSharp.Common/Timing/TimeSourceProvider.cs +++ b/src/StgSharp.Common/Timing/TimeSourceProvider.cs @@ -6,13 +6,28 @@ // ----------------------------------------------------------------------------- using StgSharp; - +using StgSharp.HighPerformance.ProcessorAbstraction; using System; using System.Linq; using System.Threading; namespace StgSharp.Timing { + public class TimeSourceStartupConfiguration( + nuint bindedNumaNode = 0, + nuint bindedCoreIndex = 0, + ThreadPriority threadPriority = ThreadPriority.Highest + ) + { + + public nuint BindedNumaNode { get; } = bindedNumaNode; + + public nuint BindedCoreIndex { get; } = bindedCoreIndex; + + public ThreadPriority Priority { get; } = threadPriority; + + } + public abstract class TimeSourceProviderBase { @@ -40,7 +55,9 @@ namespace StgSharp.Timing } } - public abstract void StartProvidingTime(); + public abstract void StartProvidingTime( + TimeSourceStartupConfiguration threadConfig + ); public abstract void StopProvidingTime(); diff --git a/src/StgSharp.Common/Timing/TimeThreadProfile.cs b/src/StgSharp.Common/Timing/TimeThreadProfile.cs new file mode 100644 index 00000000..8929d33d --- /dev/null +++ b/src/StgSharp.Common/Timing/TimeThreadProfile.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StgSharp.Common.Timing +{ + internal class TimeThreadProfile + { + } +} diff --git a/src/StgSharp.Graphics/GraphicInitializer.cs b/src/StgSharp.Graphics/GraphicInitializer.cs index de3f26e8..afa99c5e 100644 --- a/src/StgSharp.Graphics/GraphicInitializer.cs +++ b/src/StgSharp.Graphics/GraphicInitializer.cs @@ -21,7 +21,7 @@ namespace StgSharp.Graphics public string ModuleName => "Graphics"; public void InitializeModule( - IModuleInitializeProfile profile + IModuleInitializeConfiguration profile ) { GraphicFramework.LoadGlfw(); diff --git a/src/StgSharp.Graphics/glfw.cs b/src/StgSharp.Graphics/glfw.cs index 7906278c..b0cbbd56 100644 --- a/src/StgSharp.Graphics/glfw.cs +++ b/src/StgSharp.Graphics/glfw.cs @@ -20,7 +20,7 @@ namespace StgSharp.Graphics [MethodImpl(MethodImplOptions.AggressiveInlining)] public void InitializeModule( - IModuleInitializeProfile profile + IModuleInitializeConfiguration profile ) { GraphicFramework.LoadGlfw(); diff --git a/src/StgSharp.Mathematics/Numeric/NumericalModule.cs b/src/StgSharp.Mathematics/Numeric/NumericalModule.cs index 23b51996..898473be 100644 --- a/src/StgSharp.Mathematics/Numeric/NumericalModule.cs +++ b/src/StgSharp.Mathematics/Numeric/NumericalModule.cs @@ -52,7 +52,7 @@ namespace StgSharp.Mathematics.Numeric [MethodImpl(MethodImplOptions.AggressiveInlining)] public void InitializeModule( - IModuleInitializeProfile profile + IModuleInitializeConfiguration profile ) { try diff --git a/src/StgSharp.RegularAnalysis/Text/RegexAnalyzer.ASTGenerate.cs b/src/StgSharp.RegularAnalysis/Text/RegexAnalyzer.ASTGenerate.cs index a23b7830..565faf69 100644 --- a/src/StgSharp.RegularAnalysis/Text/RegexAnalyzer.ASTGenerate.cs +++ b/src/StgSharp.RegularAnalysis/Text/RegexAnalyzer.ASTGenerate.cs @@ -26,6 +26,8 @@ namespace StgSharp.RegularAnalysis.Text AbstractSyntaxTree _tree = new(); RegexTokenReader reader = new(_source); TokenParser lexer = reader.Pipe(() => new RegexTokenParser()); + Stack outerLastTokens = []; + RegexElementLabel lastToken = RegexElementLabel.NONE; while (lexer.TryReadToken(out Token token)) { @@ -38,8 +40,13 @@ namespace StgSharp.RegularAnalysis.Text { _stack.PushOperator(new RegexAstNode(token)); _stack.IncreaseDepth(0); + outerLastTokens.Push(lastToken); + lastToken = RegexElementLabel.GROUP_BEGIN; } else if ((token.Flag & RegexElementLabel.GROUP_END) != 0) { + if (lastToken == RegexElementLabel.ALT) { + PushEpsilon(token.Line, token.Column); + } // close all nodes here RegexAstNode op; while (_stack.TryPopOperator(out op)) { @@ -58,8 +65,17 @@ namespace StgSharp.RegularAnalysis.Text op.Right = _stack.PopOperand(); _stack.PushOperand(op); } + _ = outerLastTokens.Pop(); + lastToken = RegexElementLabel.GROUP_END; } else if ((token.Flag & RegexElementLabel.OPERATOR) != 0) { + if (token.Flag == RegexElementLabel.ALT && + lastToken is RegexElementLabel.NONE or + RegexElementLabel.GROUP_BEGIN or + RegexElementLabel.ALT) + { + PushEpsilon(token.Line, token.Column); + } if (_stack.OperatorInDepthCount == 0) { // the first operator in stack @@ -87,6 +103,13 @@ namespace StgSharp.RegularAnalysis.Text _stack.PushOperator(new RegexAstNode(token)); } } + if (token.Flag != RegexElementLabel.GROUP_BEGIN && + token.Flag != RegexElementLabel.GROUP_END) { + lastToken = token.Flag; + } + } + if (lastToken == RegexElementLabel.ALT) { + PushEpsilon(0, _source.Length); } if (_stack.Depth == 1) { @@ -104,6 +127,13 @@ namespace StgSharp.RegularAnalysis.Text } throw new InvalidOperationException("Invalid regular expression syntax."); + void PushEpsilon(int row, int column) + { + RegexAstNode epsilon = new(new RegexEpsilonPayload(row, column)); + _stack.PushOperand(epsilon); + _ = _tree.AddNode(epsilon); + } + void ProcessOperator( RegexAstNode op diff --git a/src/StgSharp.RegularAnalysis/Text/RegexAnalyzer.ASTOptimize.cs b/src/StgSharp.RegularAnalysis/Text/RegexAnalyzer.ASTOptimize.cs index 310b5fec..a7a74d4b 100644 --- a/src/StgSharp.RegularAnalysis/Text/RegexAnalyzer.ASTOptimize.cs +++ b/src/StgSharp.RegularAnalysis/Text/RegexAnalyzer.ASTOptimize.cs @@ -145,21 +145,22 @@ namespace StgSharp.RegularAnalysis.Text TreeEnumerator enumerator = new(tree.Root); RegexAstNode current; - // phase1: ALT flatten - // phase2: CONCAT normalize - int i = 0; + // phase1: normalize associative binary operators, then flatten ALT List altNodes = []; while (enumerator.MoveNext()) { current = enumerator.Current; + if (current.EqualityTypeConvert is RegexElementLabel.CONCAT or + RegexElementLabel.ALT) + { + RotateAssociativeOperator(current, current.EqualityTypeConvert); + } if (current.EqualityTypeConvert == RegexElementLabel.ALT) { RegexAstNode union = FlattenAlt(current); altNodes.Add(current); current.Right = union; current.Left = RegexAstNode.Empty; - } else if (current.EqualityTypeConvert == RegexElementLabel.CONCAT) { - RotateConcat(current); } } @@ -195,13 +196,28 @@ namespace StgSharp.RegularAnalysis.Text } } - private static void RotateConcat( - RegexAstNode root + /// + /// Converts a left-associated binary operator tree to a right spine while preserving + /// operand order. For example, (a op b) op c becomes + /// a op (b op c). + /// + /// + /// A child with another label is an operand and is not rotated across. Keeping the target + /// label explicit allows later associative operators to reuse the same tree operation. + /// + private static void RotateAssociativeOperator( + RegexAstNode root, + RegexElementLabel operatorLabel ) { + if (root.EqualityTypeConvert != operatorLabel) { + throw new ArgumentException("The root does not match the requested operator.", + nameof(operatorLabel)); + } + RegexAstNode left = root.Left; while (!RegexAstNode.IsNullOrEmpty(left) && - left.EqualityTypeConvert == RegexElementLabel.CONCAT) + left.EqualityTypeConvert == operatorLabel) { /* * root → root diff --git a/src/StgSharp.RegularAnalysis/Text/RegexAstNode.AdditionalPayload.cs b/src/StgSharp.RegularAnalysis/Text/RegexAstNode.AdditionalPayload.cs index a48ec9af..32ed26b4 100644 --- a/src/StgSharp.RegularAnalysis/Text/RegexAstNode.AdditionalPayload.cs +++ b/src/StgSharp.RegularAnalysis/Text/RegexAstNode.AdditionalPayload.cs @@ -23,6 +23,15 @@ namespace StgSharp.RegularAnalysis.Text public sealed record RegexEmptyPayload() : RegexAstPayload(string.Empty, 0, 0, RegexElementLabel.NONE); + /// + /// A semantic empty expression. Unlike , this is a real AST + /// node and represents a successful match that consumes no input. + /// + public sealed record RegexEpsilonPayload( + int Row, + int Column + ) : RegexAstPayload(string.Empty, Row, Column, RegexElementLabel.EPSILON); + /// /// A deterministic literal sequence. Escapes represented as literals are consumed here. /// diff --git a/src/StgSharp.RegularAnalysis/Text/RegexElementLabel.cs b/src/StgSharp.RegularAnalysis/Text/RegexElementLabel.cs index 39044b88..7a7769a9 100644 --- a/src/StgSharp.RegularAnalysis/Text/RegexElementLabel.cs +++ b/src/StgSharp.RegularAnalysis/Text/RegexElementLabel.cs @@ -26,12 +26,13 @@ namespace StgSharp.RegularAnalysis.Text COUNT = 32, CONCAT = 64, ALT = 128, + EPSILON = 256, SEQUENCE = UNIT | UNIT_SPAN | UNIT_SET, UNIT_SINGLE = UNIT | UNIT_SET, OPERATOR = COUNT | ALT | CONCAT, VAST_OPERATOR = OPERATOR | GROUP_BEGIN, - ATOM_BEGIN = SEQUENCE | GROUP_BEGIN , - ATOM_END = SEQUENCE | GROUP_END | COUNT, + ATOM_BEGIN = SEQUENCE | GROUP_BEGIN | EPSILON, + ATOM_END = SEQUENCE | GROUP_END | COUNT | EPSILON, #pragma warning restore CA1707 } diff --git a/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs b/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs index 3747dfdc..c035b73f 100644 --- a/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs +++ b/src/StgSharp.RegularAnalysis/Text/TextRegexSourceGen.GenClass.cs @@ -29,6 +29,9 @@ namespace StgSharp.RegularAnalysis.Text ) { RegexAstNode root = ast; + if (root.Label == RegexElementLabel.EPSILON) { + return; + } RegexElementLabel op = root.Label & (RegexElementLabel.VAST_OPERATOR); if (op != 0) { diff --git a/test/StgSharpDebug/Program.cs b/test/StgSharpDebug/Program.cs index f423d6c5..0576f3a4 100644 --- a/test/StgSharpDebug/Program.cs +++ b/test/StgSharpDebug/Program.cs @@ -13,6 +13,7 @@ using StgSharp.Mathematics.Numeric; using StgSharp.Timing; using StgSharp.Timing; using System; +using System.Runtime.InteropServices; namespace StgSharp { @@ -29,12 +30,21 @@ namespace StgSharp { try { - World.Initialize() + World.Initialize(new() + { + TimingConfig = new TimeSourceStartupConfiguration() + }) // .UseModule() // .UseModule() .InitializeModule(); + _ = SlabAllocator.FromBuffer( + (nuint)NativeMemory.AlignedAlloc(65536 * 4, 4), + 65536, + buffer => NativeMemory.AlignedFree((void*)buffer) + ); + TestRegexAnalyse.Run(); // TestHlsf(); diff --git a/test/StgSharpDebug/TestRegexAnalyse.cs b/test/StgSharpDebug/TestRegexAnalyse.cs index 4e9f6d57..a40b6d1c 100644 --- a/test/StgSharpDebug/TestRegexAnalyse.cs +++ b/test/StgSharpDebug/TestRegexAnalyse.cs @@ -46,11 +46,6 @@ namespace StgSharp Console.WriteLine($"\t{node.Value}\t{node.Source.Flag}"); } Console.WriteLine(interpreterSource.AnalyseException?.ToString() ?? "No error"); - RegexInfo info = interpreterSource.Info; - Console.WriteLine("-----Regex Info-----"); - Console.WriteLine($"Min length: {info.MinPredictLength}"); - Console.WriteLine($"Region count: {info.RegionCount}"); - Console.WriteLine($"Single line dependency: {info.SingleLineResultCount}"); Console.WriteLine(); Console.WriteLine(); Console.WriteLine();