Skip to content

Commit 791beee

Browse files
author
BRUNER Patrick
committed
A lot of Memory
1 parent 1e1e620 commit 791beee

31 files changed

Lines changed: 1120 additions & 313 deletions

src/AutoColumnizer/AutoColumnizer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public string[] GetColumnNames ()
3939
throw new NotImplementedException();
4040
}
4141

42-
public IColumnizedLogLineMemory SplitLine (ILogLineColumnizerCallback callback, ILogLine line)
42+
public IColumnizedLogLine SplitLine (ILogLineColumnizerCallback callback, ILogLine line)
4343
{
4444
throw new NotImplementedException();
4545
}

src/ColumnizerLib/Column.cs

Lines changed: 137 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ public class Column : IColumnMemory
1111
// Can be configured via SetMaxDisplayLength()
1212
private static int _maxDisplayLength = 20_000;
1313

14-
private static readonly List<Func<string, string>> _replacements = [
14+
private static readonly List<Func<ReadOnlyMemory<char>, ReadOnlyMemory<char>>> _replacementsMemory = [
1515
//replace tab with 3 spaces, from old coding. Needed???
16-
input => input.Replace("\t", " ", StringComparison.Ordinal),
16+
ReplaceTab,
1717

18-
//shorten string if it exceeds maxLength
19-
input => input.Length > _maxDisplayLength
20-
? string.Concat(input.AsSpan(0, _maxDisplayLength), REPLACEMENT)
21-
: input
18+
//shorten string if it exceeds maxLength
19+
input => input.Length > _maxDisplayLength
20+
? ShortenMemory(input, _maxDisplayLength)
21+
: input
2222
];
2323

2424
#endregion
@@ -31,7 +31,7 @@ static Column ()
3131
{
3232
//Win8 or newer support full UTF8 chars with the preinstalled fonts.
3333
//Replace null char with UTF8 Symbol U+2400 (␀)
34-
_replacements.Add(input => input.Replace("\0", "␀", StringComparison.Ordinal));
34+
_replacementsMemory.Add(input => ReplaceNullChar(input, '␀'));
3535
}
3636
else
3737
{
@@ -40,10 +40,10 @@ static Column ()
4040
//.net 10 does no longer support windows lower then windows 10
4141
//TODO: remove if with one of the next releases
4242
//https://github.com/dotnet/core/blob/main/release-notes/10.0/supported-os.md
43-
_replacements.Add(input => input.Replace("\0", " ", StringComparison.Ordinal));
43+
_replacementsMemory.Add(input => ReplaceNullChar(input, ' '));
4444
}
4545

46-
EmptyColumn = new Column { FullValue = string.Empty };
46+
EmptyColumn = new Column { FullValue = ReadOnlyMemory<char>.Empty };
4747
}
4848

4949
#endregion
@@ -52,18 +52,49 @@ static Column ()
5252

5353
public static IColumnMemory EmptyColumn { get; }
5454

55-
public IColumnizedLogLineMemory Parent { get; set; }
55+
[Obsolete]
56+
IColumnizedLogLine IColumn.Parent { get; }
5657

57-
public string FullValue
58+
[Obsolete]
59+
string IColumn.FullValue
60+
{
61+
get;
62+
//set
63+
//{
64+
// field = value;
65+
66+
// var temp = FullValue.ToString();
67+
68+
// foreach (var replacement in _replacements)
69+
// {
70+
// temp = replacement(temp);
71+
// }
72+
73+
// DisplayValue = temp.AsMemory();
74+
//}
75+
}
76+
77+
[Obsolete("Use the DisplayValue property of IColumnMemory")]
78+
string IColumn.DisplayValue { get; }
79+
80+
[Obsolete("Use Text property of ITextValueMemory")]
81+
string ITextValue.Text => DisplayValue.ToString();
82+
83+
public IColumnizedLogLineMemory Parent
84+
{
85+
get; set => field = value;
86+
}
87+
88+
public ReadOnlyMemory<char> FullValue
5889
{
5990
get;
6091
set
6192
{
6293
field = value;
6394

64-
var temp = FullValue;
95+
var temp = value;
6596

66-
foreach (var replacement in _replacements)
97+
foreach (var replacement in _replacementsMemory)
6798
{
6899
temp = replacement(temp);
69100
}
@@ -72,22 +103,9 @@ public string FullValue
72103
}
73104
}
74105

75-
public string DisplayValue { get; private set; }
106+
public ReadOnlyMemory<char> DisplayValue { get; private set; }
76107

77-
public string Text => DisplayValue;
78-
79-
public IColumnizedLogLineMemory ParentMemory { get; }
80-
81-
public ReadOnlyMemory<char> FullValueMemory
82-
{
83-
get;
84-
set; //implement
85-
}
86-
87-
public ReadOnlyMemory<char> DisplayValueMemory { get; }
88-
89-
public ReadOnlyMemory<char> TextMemory { get; }
90-
IColumnizedLogLine IColumn.Parent { get; }
108+
public ReadOnlyMemory<char> Text => DisplayValue;
91109

92110
#endregion
93111

@@ -115,10 +133,10 @@ public static void SetMaxDisplayLength (int maxLength)
115133

116134
public static Column[] CreateColumns (int count, IColumnizedLogLineMemory parent)
117135
{
118-
return CreateColumns(count, parent, string.Empty);
136+
return CreateColumns(count, parent, ReadOnlyMemory<char>.Empty);
119137
}
120138

121-
public static Column[] CreateColumns (int count, IColumnizedLogLineMemory parent, string defaultValue)
139+
public static Column[] CreateColumns (int count, IColumnizedLogLineMemory parent, ReadOnlyMemory<char> defaultValue)
122140
{
123141
var output = new Column[count];
124142

@@ -132,7 +150,95 @@ public static Column[] CreateColumns (int count, IColumnizedLogLineMemory parent
132150

133151
public override string ToString ()
134152
{
135-
return DisplayValue ?? string.Empty;
153+
return DisplayValue.ToString() ?? ReadOnlyMemory<char>.Empty.ToString();
154+
}
155+
156+
#endregion
157+
158+
#region Private Methods
159+
160+
/// <summary>
161+
/// Replaces tab characters with two spaces in the memory buffer.
162+
/// </summary>
163+
private static ReadOnlyMemory<char> ReplaceTab (ReadOnlyMemory<char> input)
164+
{
165+
var span = input.Span;
166+
var tabIndex = span.IndexOf('\t');
167+
168+
if (tabIndex == -1)
169+
{
170+
return input;
171+
}
172+
173+
// Count total tabs to calculate new length
174+
var tabCount = 0;
175+
foreach (var c in span)
176+
{
177+
if (c == '\t')
178+
{
179+
tabCount++;
180+
}
181+
}
182+
183+
// Allocate new buffer: original length + (tabCount * 1) since we replace 1 char with 2
184+
var newLength = input.Length + tabCount;
185+
var buffer = new char[newLength];
186+
var bufferPos = 0;
187+
188+
for (var i = 0; i < span.Length; i++)
189+
{
190+
if (span[i] == '\t')
191+
{
192+
buffer[bufferPos++] = ' ';
193+
buffer[bufferPos++] = ' ';
194+
}
195+
else
196+
{
197+
buffer[bufferPos++] = span[i];
198+
}
199+
}
200+
201+
return buffer;
202+
}
203+
204+
/// <summary>
205+
/// Shortens the memory buffer to the specified maximum length and appends "...".
206+
/// </summary>
207+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "Non Localiced Parameter")]
208+
private static ReadOnlyMemory<char> ShortenMemory (ReadOnlyMemory<char> input, int maxLength)
209+
{
210+
var buffer = new char[maxLength + REPLACEMENT.Length];
211+
input.Span[..maxLength].CopyTo(buffer);
212+
REPLACEMENT.AsSpan().CopyTo(buffer.AsSpan(maxLength));
213+
return buffer;
214+
}
215+
216+
/// <summary>
217+
/// Replaces null characters with the specified replacement character.
218+
/// </summary>
219+
private static ReadOnlyMemory<char> ReplaceNullChar (ReadOnlyMemory<char> input, char replacement)
220+
{
221+
var span = input.Span;
222+
var nullIndex = span.IndexOf('\0');
223+
224+
if (nullIndex == -1)
225+
{
226+
return input;
227+
}
228+
229+
// Need to create a new buffer since we're modifying content
230+
var buffer = new char[input.Length];
231+
span.CopyTo(buffer);
232+
233+
for (var i = 0; i < buffer.Length; i++)
234+
{
235+
if (buffer[i] == '\0')
236+
{
237+
buffer[i] = replacement;
238+
}
239+
}
240+
241+
return buffer;
136242
}
137243

138244
#endregion

src/ColumnizerLib/ColumnizedLogLine.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ public class ColumnizedLogLine : IColumnizedLogLineMemory
44
{
55
#region Properties
66

7-
public ILogLine LogLine { get; set; }
7+
[Obsolete("Use the Property of IColumnizedLogLineMemory")]
8+
ILogLine IColumnizedLogLine.LogLine { get; }
89

9-
public IColumn[] ColumnValues { get; set; }
10+
[Obsolete("Use the Property of IColumnizedLogLineMemory")]
11+
IColumn[] IColumnizedLogLine.ColumnValues { get; }
1012

11-
public ILogLineMemory LogLineMemory { get; set; }
13+
public ILogLineMemory LogLine { get; set; }
1214

13-
public IColumnMemory[] ColumnMemoryValues { get; set; }
15+
public IColumnMemory[] ColumnValues { get; set; }
1416

1517
#endregion
1618
}

src/ColumnizerLib/IColumnMemory.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ public interface IColumnMemory : IColumn, ITextValueMemory
44
{
55
#region Properties
66

7-
IColumnizedLogLineMemory ParentMemory { get; }
7+
new IColumnizedLogLineMemory Parent { get; }
88

9-
ReadOnlyMemory<char> FullValueMemory { get; }
9+
new ReadOnlyMemory<char> FullValue { get; }
1010

11-
ReadOnlyMemory<char> DisplayValueMemory { get; }
11+
new ReadOnlyMemory<char> DisplayValue { get; }
1212

1313
#endregion
1414
}

src/ColumnizerLib/IColumnizedLogLineMemory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ public interface IColumnizedLogLineMemory : IColumnizedLogLine
44
{
55
#region Properties
66

7-
ILogLineMemory LogLineMemory { get; }
7+
new ILogLineMemory LogLine { get; }
88

9-
IColumnMemory[] ColumnMemoryValues { get; }
9+
new IColumnMemory[] ColumnValues { get; }
1010

1111
#endregion
1212
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
namespace ColumnizerLib;
2+
3+
/// <summary>
4+
/// A Columnizer can implement this interface if it has to show an own settings dialog to the user.
5+
/// The Config button in LogExpert's columnizer dialog is enabled if a Columnizer implements this interface.
6+
/// If you don't need a config dialog you don't have to implement this interface.
7+
/// </summary>
8+
public interface IColumnizerConfiguratorMemory : IColumnizerConfigurator
9+
{
10+
#region Public methods
11+
12+
/// <summary>
13+
/// This function is called if the user presses the Config button on the Columnizer dialog.
14+
/// Its up to the Columnizer plugin to show an own configuration dialog and store all
15+
/// required settings.
16+
/// </summary>
17+
/// <param name="callback">Callback interface with functions which can be used by the columnizer</param>
18+
/// <param name="configDir">The complete path to the directory where LogExpert stores its settings.
19+
/// You can use this directory, if you want to. Please don't use the file name "settings.dat", because this
20+
/// name is used by LogExpert.
21+
/// </param>
22+
/// <remarks>
23+
/// This is the place to show a configuration dialog to the user. You have to handle all dialog stuff by yourself.
24+
/// It's also your own job to store the configuration in a config file or on the registry.
25+
/// The callback is passed to this function just in case you need the file name of the current log file
26+
/// or the line count etc. You can also use it to store different settings for every log file.
27+
/// You can use the callback to distinguish between different files. Its passed to all important
28+
/// functions in the Columnizer.
29+
/// </remarks>
30+
void Configure (ILogLineMemoryColumnizerCallback callback, string configDir);
31+
32+
#endregion
33+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
namespace ColumnizerLib;
2+
3+
/// <summary>
4+
/// Implement this interface in your columnizer if you need to do some initialization work
5+
/// every time the columnizer is selected.
6+
/// </summary>
7+
/// <remarks>
8+
/// <para>
9+
/// The methods in this interface will be called in the GUI thread. So make sure that there's no
10+
/// heavyweight work to do in your implementations.</para>
11+
/// <para>
12+
/// If a file is reloaded, the current Columnizer is set again. That means that the methods of this
13+
/// interface will be called again. Generally you should do no assumptions about how often the
14+
/// methods will be called. The file is already loaded when the columnizer is set. So
15+
/// you can use the methods in the given callbacks to get informations about the file or to
16+
/// retrieve specific lines.
17+
/// </para>
18+
/// </remarks>
19+
public interface IInitColumnizerMemory : IInitColumnizer
20+
{
21+
#region Public methods
22+
23+
/// <summary>
24+
/// This method is called when the Columnizer is selected as the current columnizer.
25+
/// </summary>
26+
/// <param name="callback">Callback that can be used to retrieve some informations, if needed.</param>
27+
void Selected (ILogLineMemoryColumnizerCallback callback);
28+
29+
/// <summary>
30+
/// This method is called when the Columnizer is de-selected (i.e. when another Columnizer is
31+
/// selected).
32+
/// </summary>
33+
/// <param name="callback">Callback that can be used to retrieve some informations, if needed.</param>
34+
void DeSelected (ILogLineMemoryColumnizerCallback callback);
35+
36+
#endregion
37+
}

0 commit comments

Comments
 (0)