@@ -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
0 commit comments