11namespace ColumnizerLib ;
22
3- public class Column : IColumn
3+ public class Column : IColumnMemory
44{
5+ //TODO Memory Functions need implementation
56 #region Fields
67
78 private const string REPLACEMENT = "..." ;
@@ -10,14 +11,14 @@ public class Column : IColumn
1011 // Can be configured via SetMaxDisplayLength()
1112 private static int _maxDisplayLength = 20_000 ;
1213
13- private static readonly List < Func < string , string > > _replacements = [
14+ private static readonly List < Func < ReadOnlyMemory < char > , ReadOnlyMemory < char > > > _replacementsMemory = [
1415 //replace tab with 3 spaces, from old coding. Needed???
15- input => input . Replace ( " \t " , " " , StringComparison . Ordinal ) ,
16+ ReplaceTab ,
1617
17- //shorten string if it exceeds maxLength
18- input => input . Length > _maxDisplayLength
19- ? string . Concat ( input . AsSpan ( 0 , _maxDisplayLength ) , REPLACEMENT )
20- : input
18+ //shorten string if it exceeds maxLength
19+ input => input . Length > _maxDisplayLength
20+ ? ShortenMemory ( input , _maxDisplayLength )
21+ : input
2122 ] ;
2223
2324 #endregion
@@ -26,43 +27,63 @@ public class Column : IColumn
2627
2728 static Column ( )
2829 {
29- if ( Environment . Version >= Version . Parse ( "6.2" ) )
30- {
31- //Win8 or newer support full UTF8 chars with the preinstalled fonts.
32- //Replace null char with UTF8 Symbol U+2400 (␀)
33- _replacements . Add ( input => input . Replace ( "\0 " , "␀" , StringComparison . Ordinal ) ) ;
34- }
35- else
36- {
37- //Everything below Win8 the installed fonts seems to not to support reliabel
38- //Replace null char with space
39- //.net 10 does no longer support windows lower then windows 10
40- //TODO: remove if with one of the next releases
41- //https://github.com/dotnet/core/blob/main/release-notes/10.0/supported-os.md
42- _replacements . Add ( input => input . Replace ( "\0 " , " " , StringComparison . Ordinal ) ) ;
43- }
30+ //.net 10 only supports Windows10+ which has full UTF8-font support
31+ // Replace null char with UTF-8 Symbol U+2400 (␀)
32+ //https://github.com/dotnet/core/blob/main/release-notes/10.0/supported-os.md
33+ _replacementsMemory . Add ( input => ReplaceNullChar ( input , ' ' ) ) ;
4434
45- EmptyColumn = new Column { FullValue = string . Empty } ;
35+ EmptyColumn = new Column { FullValue = ReadOnlyMemory < char > . Empty } ;
4636 }
4737
4838 #endregion
4939
5040 #region Properties
5141
52- public static IColumn EmptyColumn { get ; }
42+ public static IColumnMemory EmptyColumn { get ; }
43+
44+ [ Obsolete ]
45+ IColumnizedLogLine IColumn . Parent { get ; }
46+
47+ [ Obsolete ]
48+ string IColumn . FullValue
49+ {
50+ get ;
51+ //set
52+ //{
53+ // field = value;
54+
55+ // var temp = FullValue.ToString();
56+
57+ // foreach (var replacement in _replacements)
58+ // {
59+ // temp = replacement(temp);
60+ // }
61+
62+ // DisplayValue = temp.AsMemory();
63+ //}
64+ }
65+
66+ [ Obsolete ( "Use the DisplayValue property of IColumnMemory" ) ]
67+ string IColumn . DisplayValue { get ; }
68+
69+ [ Obsolete ( "Use Text property of ITextValueMemory" ) ]
70+ string ITextValue . Text => DisplayValue . ToString ( ) ;
5371
54- public IColumnizedLogLine Parent { get ; set ; }
72+ public IColumnizedLogLineMemory Parent
73+ {
74+ get ; set => field = value ;
75+ }
5576
56- public string FullValue
77+ public ReadOnlyMemory < char > FullValue
5778 {
5879 get ;
5980 set
6081 {
6182 field = value ;
6283
63- var temp = FullValue ;
84+ var temp = value ;
6485
65- foreach ( var replacement in _replacements )
86+ foreach ( var replacement in _replacementsMemory )
6687 {
6788 temp = replacement ( temp ) ;
6889 }
@@ -71,9 +92,9 @@ public string FullValue
7192 }
7293 }
7394
74- public string DisplayValue { get ; private set ; }
95+ public ReadOnlyMemory < char > DisplayValue { get ; private set ; }
7596
76- public string Text => DisplayValue ;
97+ public ReadOnlyMemory < char > Text => DisplayValue ;
7798
7899 #endregion
79100
@@ -99,12 +120,12 @@ public static void SetMaxDisplayLength (int maxLength)
99120 /// </summary>
100121 public static int GetMaxDisplayLength ( ) => _maxDisplayLength ;
101122
102- public static Column [ ] CreateColumns ( int count , IColumnizedLogLine parent )
123+ public static Column [ ] CreateColumns ( int count , IColumnizedLogLineMemory parent )
103124 {
104- return CreateColumns ( count , parent , string . Empty ) ;
125+ return CreateColumns ( count , parent , ReadOnlyMemory < char > . Empty ) ;
105126 }
106127
107- public static Column [ ] CreateColumns ( int count , IColumnizedLogLine parent , string defaultValue )
128+ public static Column [ ] CreateColumns ( int count , IColumnizedLogLineMemory parent , ReadOnlyMemory < char > defaultValue )
108129 {
109130 var output = new Column [ count ] ;
110131
@@ -118,7 +139,95 @@ public static Column[] CreateColumns (int count, IColumnizedLogLine parent, stri
118139
119140 public override string ToString ( )
120141 {
121- return DisplayValue ?? string . Empty ;
142+ return DisplayValue . ToString ( ) ?? ReadOnlyMemory < char > . Empty . ToString ( ) ;
143+ }
144+
145+ #endregion
146+
147+ #region Private Methods
148+
149+ /// <summary>
150+ /// Replaces tab characters with two spaces in the memory buffer.
151+ /// </summary>
152+ private static ReadOnlyMemory < char > ReplaceTab ( ReadOnlyMemory < char > input )
153+ {
154+ var span = input . Span ;
155+ var tabIndex = span . IndexOf ( '\t ' ) ;
156+
157+ if ( tabIndex == - 1 )
158+ {
159+ return input ;
160+ }
161+
162+ // Count total tabs to calculate new length
163+ var tabCount = 0 ;
164+ foreach ( var c in span )
165+ {
166+ if ( c == '\t ' )
167+ {
168+ tabCount ++ ;
169+ }
170+ }
171+
172+ // Allocate new buffer: original length + (tabCount * 1) since we replace 1 char with 2
173+ var newLength = input . Length + tabCount ;
174+ var buffer = new char [ newLength ] ;
175+ var bufferPos = 0 ;
176+
177+ for ( var i = 0 ; i < span . Length ; i ++ )
178+ {
179+ if ( span [ i ] == '\t ' )
180+ {
181+ buffer [ bufferPos ++ ] = ' ' ;
182+ buffer [ bufferPos ++ ] = ' ' ;
183+ }
184+ else
185+ {
186+ buffer [ bufferPos ++ ] = span [ i ] ;
187+ }
188+ }
189+
190+ return buffer ;
191+ }
192+
193+ /// <summary>
194+ /// Shortens the memory buffer to the specified maximum length and appends "...".
195+ /// </summary>
196+ [ System . Diagnostics . CodeAnalysis . SuppressMessage ( "Globalization" , "CA1303:Do not pass literals as localized parameters" , Justification = "Non Localiced Parameter" ) ]
197+ private static ReadOnlyMemory < char > ShortenMemory ( ReadOnlyMemory < char > input , int maxLength )
198+ {
199+ var buffer = new char [ maxLength + REPLACEMENT . Length ] ;
200+ input . Span [ ..maxLength ] . CopyTo ( buffer ) ;
201+ REPLACEMENT . AsSpan ( ) . CopyTo ( buffer . AsSpan ( maxLength ) ) ;
202+ return buffer ;
203+ }
204+
205+ /// <summary>
206+ /// Replaces null characters with the specified replacement character.
207+ /// </summary>
208+ private static ReadOnlyMemory < char > ReplaceNullChar ( ReadOnlyMemory < char > input , char replacement )
209+ {
210+ var span = input . Span ;
211+ var nullIndex = span . IndexOf ( '\0 ' ) ;
212+
213+ if ( nullIndex == - 1 )
214+ {
215+ return input ;
216+ }
217+
218+ // Need to create a new buffer since we're modifying content
219+ var buffer = new char [ input . Length ] ;
220+ span . CopyTo ( buffer ) ;
221+
222+ for ( var i = 0 ; i < buffer . Length ; i ++ )
223+ {
224+ if ( buffer [ i ] == '\0 ' )
225+ {
226+ buffer [ i ] = replacement ;
227+ }
228+ }
229+
230+ return buffer ;
122231 }
123232
124233 #endregion
0 commit comments