-
Notifications
You must be signed in to change notification settings - Fork 4
/
StringBuilderExtFormat.cs
214 lines (190 loc) · 9.24 KB
/
StringBuilderExtFormat.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// File: StringBuilderExtFormat.cs
// Date: 11th March 2010
// Author: Gavin Pugh
// Details: Extension methods for the 'StringBuilder' standard .NET class, to allow garbage-free concatenation of
// formatted strings with a variable set of arguments.
//
// Copyright (c) Gavin Pugh 2010 - Released under the zlib license: http://www.opensource.org/licenses/zlib-license.php
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Text;
using UnityEngine;
using Debug = System.Diagnostics.Debug;
namespace GCMonitor
{
public static partial class StringBuilderExtensions
{
//! Concatenate a formatted string with arguments
public static StringBuilder ConcatFormat<A>( this StringBuilder string_builder, String format_string, A arg1 )
where A : IConvertible
{
return string_builder.ConcatFormat<A, int, int, int>( format_string, arg1, 0, 0, 0 );
}
//! Concatenate a formatted string with arguments
public static StringBuilder ConcatFormat<A, B>( this StringBuilder string_builder, String format_string, A arg1, B arg2 )
where A : IConvertible
where B : IConvertible
{
return string_builder.ConcatFormat<A, B, int, int>( format_string, arg1, arg2, 0, 0 );
}
//! Concatenate a formatted string with arguments
public static StringBuilder ConcatFormat<A, B, C>( this StringBuilder string_builder, String format_string, A arg1, B arg2, C arg3 )
where A : IConvertible
where B : IConvertible
where C : IConvertible
{
return string_builder.ConcatFormat<A, B, C, int>( format_string, arg1, arg2, arg3, 0 );
}
//! Concatenate a formatted string with arguments
public static StringBuilder ConcatFormat<A,B,C,D>( this StringBuilder string_builder, String format_string, A arg1, B arg2, C arg3, D arg4 )
where A : IConvertible
where B : IConvertible
where C : IConvertible
where D : IConvertible
{
int verbatim_range_start = 0;
for ( int index = 0; index < format_string.Length; index++ )
{
if ( format_string[index] == '{' )
{
// Formatting bit now, so make sure the last block of the string is written out verbatim.
if ( verbatim_range_start < index )
{
// Write out unformatted string portion
string_builder.Append( format_string, verbatim_range_start, index - verbatim_range_start );
}
uint base_value = 10;
uint padding = 0;
uint decimal_places = 5; // Default decimal places in .NET libs
index++;
char format_char = format_string[index];
if ( format_char == '{' )
{
string_builder.Append( '{' );
index++;
}
else
{
index++;
if ( format_string[index] == ':' )
{
// Extra formatting. This is a crude first pass proof-of-concept. It's not meant to cover
// comprehensively what the .NET standard library Format() can do.
index++;
// Deal with padding
while ( format_string[index] == '0' )
{
index++;
padding++;
}
if ( format_string[index] == 'X' )
{
index++;
// Print in hex
base_value = 16;
// Specify amount of padding ( "{0:X8}" for example pads hex to eight characters
if ( ( format_string[index] >= '0' ) && ( format_string[index] <= '9' ) )
{
padding = (uint)( format_string[index] - '0' );
index++;
}
}
else if ( format_string[index] == '.' )
{
index++;
// Specify number of decimal places
decimal_places = 0;
while ( format_string[index] == '0' )
{
index++;
decimal_places++;
}
}
}
// Scan through to end bracket
while ( format_string[index] != '}' )
{
index++;
}
// Have any extended settings now, so just print out the particular argument they wanted
switch ( format_char )
{
case '0': string_builder.ConcatFormatValue<A>( arg1, padding, base_value, decimal_places ); break;
case '1': string_builder.ConcatFormatValue<B>( arg2, padding, base_value, decimal_places ); break;
case '2': string_builder.ConcatFormatValue<C>( arg3, padding, base_value, decimal_places ); break;
case '3': string_builder.ConcatFormatValue<D>( arg4, padding, base_value, decimal_places ); break;
default: Debug.Assert(false, "Invalid parameter index"); break;
}
}
// Update the verbatim range, start of a new section now
verbatim_range_start = ( index + 1 );
}
}
// Anything verbatim to write out?
if ( verbatim_range_start < format_string.Length )
{
// Write out unformatted string portion
string_builder.Append( format_string, verbatim_range_start, format_string.Length - verbatim_range_start );
}
return string_builder;
}
//! The worker method. This does a garbage-free conversion of a generic type, and uses the garbage-free Concat() to add to the stringbuilder
private static void ConcatFormatValue<T>( this StringBuilder string_builder, T arg, uint padding, uint base_value, uint decimal_places ) where T : IConvertible
{
switch ( arg.GetTypeCode() )
{
case System.TypeCode.String:
{
string_builder.Append( Convert.ToString( arg ) );
break;
}
case TypeCode.Boolean:
MonoBehaviour.print("Boolean");
break;
case TypeCode.Char:
MonoBehaviour.print("Char");
break;
case TypeCode.SByte:
MonoBehaviour.print("SByte");
break;
case TypeCode.Byte:
MonoBehaviour.print("Byte");
break;
case TypeCode.Int16:
case System.TypeCode.Int32:
case TypeCode.Int64:
{
string_builder.Concat(arg.ToInt64(System.Globalization.NumberFormatInfo.CurrentInfo), padding, '0', base_value);
break;
}
case TypeCode.UInt16:
case System.TypeCode.UInt32:
case TypeCode.UInt64:
{
string_builder.Concat(arg.ToUInt64(System.Globalization.NumberFormatInfo.CurrentInfo), padding, '0', base_value);
break;
}
case System.TypeCode.Single:
{
string_builder.Concat(arg.ToSingle(System.Globalization.NumberFormatInfo.CurrentInfo), decimal_places, padding, '0');
break;
}
case TypeCode.Double:
string_builder.Concat(arg.ToDouble(System.Globalization.NumberFormatInfo.CurrentInfo), decimal_places, padding, '0');
break;
case TypeCode.Decimal:
MonoBehaviour.print("Decimal");
break;
case TypeCode.DateTime:
MonoBehaviour.print("DateTime");
break;
default:
{
MonoBehaviour.print("Unknown parameter type" );
break;
}
}
}
}
}