C# Client Library
A C# Client Library for the AnalyzeRe REST API
Loading...
Searching...
No Matches
Output.cs
Go to the documentation of this file.
1using System;
2using System.Collections;
3using System.Globalization;
4using System.Linq;
5
6using AnalyzeRe;
8
10{
12 public static class Output
13 {
14 #region Functions
16 public static string AutoFormat(object obj)
17 {
18 if (obj == null)
19 return "(null)";
20 if (obj is string s)
21 return $"\"{s}\"";
22 if (obj is double d)
24 if (obj is int i)
25 return i.ToString("#,##0");
26 if (obj is DateTime dt)
27 return dt.ToString("O");
28 if (obj is Type t)
29 return t.NiceTypeName();
30 if (obj is IEnumerable items)
31 return "{" + String.Join(",", items.Cast<object>().Select(AutoFormat)) + "}";
32 if (obj is IReference<IAPIResource> reference && reference.ref_id != null)
33 return reference.ToString();
34 if (obj is IAPIType apiObject)
35 return $"{apiObject} (JSON:{apiObject.Serialize()})";
36 return obj.ToString();
37 }
38
39 public static string RandomString(int minLength, int maxLength, Random randomGenerator = null)
40 {
41 // TODO: No longer have to trim strings
42 // UntilRelease.Unscheduled();
43 // The server will currently trim white space around strings, causing
44 // equivalency tests to fail. The workaround is just to not supply any strings
45 // that start or end in white space, but this might violate the above
46 // minLength, maxLength constraints, so retry if that's the case.
47 // We use only allowed set of characters
48 // https://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings
49 string random;
50 const string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.";
51 randomGenerator = randomGenerator ?? new Random();
52 do
53 {
54 int randomLength = randomGenerator.Next(minLength, maxLength + 1);
55 random = new string(Enumerable.Repeat(allowedChars, randomLength)
56 .Select(s => s[randomGenerator.Next(s.Length)]).ToArray()).Trim();
57 } while (random.Length < minLength);
58 return random;
59 }
60 #endregion Functions
61
62 #region DoubleConverter
69 public static class DoubleConverter
70 {
77 public static string ToExactString(double d)
78 {
79 if (Double.IsPositiveInfinity(d))
80 return "+Infinity";
81 if (Double.IsNegativeInfinity(d))
82 return "-Infinity";
83 if (Double.IsNaN(d))
84 return "NaN";
85
86 // Translate the double into sign, exponent and mantissa.
87 long bits = BitConverter.DoubleToInt64Bits(d);
88 // Note that the shift is sign-extended, hence the test against -1 not 1
89 bool negative = (bits < 0);
90 int exponent = (int)((bits >> 52) & 0x7ffL);
91 long mantissa = bits & 0xfffffffffffffL;
92
93 // Subnormal numbers; exponent is effectively one higher,
94 // but there's no extra normalization bit in the mantissa
95 if (exponent == 0)
96 {
97 exponent++;
98 }
99 // Normal numbers; leave exponent as it is but add extra
100 // bit to the front of the mantissa
101 else
102 {
103 mantissa = mantissa | (1L << 52);
104 }
105
106 // Bias the exponent. It's actually biased by 1023, but we're
107 // treating the mantissa as m.0 rather than 0.m, so we need
108 // to subtract another 52 from it.
109 exponent -= 1075;
110
111 if (mantissa == 0)
112 {
113 return "0";
114 }
115
116 /* Normalize */
117 while ((mantissa & 1) == 0)
118 { /* i.e., Mantissa is even */
119 mantissa >>= 1;
120 exponent++;
121 }
122
123 // Construct a new decimal expansion with the mantissa
124 ArbitraryDecimal ad = new ArbitraryDecimal(mantissa);
125
126 // If the exponent is less than 0, we need to repeatedly
127 // divide by 2 - which is the equivalent of multiplying
128 // by 5 and dividing by 10.
129 if (exponent < 0)
130 {
131 for (int i = 0; i < -exponent; i++)
132 ad.MultiplyBy(5);
133 ad.Shift(-exponent);
134 }
135 // Otherwise, we need to repeatedly multiply by 2
136 else
137 {
138 for (int i = 0; i < exponent; i++)
139 ad.MultiplyBy(2);
140 }
141
142 // Finally, return the string with an appropriate sign
143 if (negative)
144 return "-" + ad.ToString();
145 else
146 return ad.ToString();
147 }
148
150 private class ArbitraryDecimal
151 {
153 private byte[] _digits;
157 private int _decimalPoint = 0;
158
163 internal ArbitraryDecimal(long x)
164 {
165 string tmp = x.ToString(CultureInfo.InvariantCulture);
166 _digits = new byte[tmp.Length];
167 for (int i = 0; i < tmp.Length; i++)
168 _digits[i] = (byte)(tmp[i] - '0');
169 Normalize();
170 }
171
176 internal void MultiplyBy(int amount)
177 {
178 byte[] result = new byte[_digits.Length + 1];
179 for (int i = _digits.Length - 1; i >= 0; i--)
180 {
181 int resultDigit = _digits[i] * amount + result[i + 1];
182 result[i] = (byte)(resultDigit / 10);
183 result[i + 1] = (byte)(resultDigit % 10);
184 }
185 if (result[0] != 0)
186 {
187 _digits = result;
188 }
189 else
190 {
191 Array.Copy(result, 1, _digits, 0, _digits.Length);
192 }
193 Normalize();
194 }
195
202 internal void Shift(int amount)
203 {
204 _decimalPoint += amount;
205 }
206
210 private void Normalize()
211 {
212 int first;
213 for (first = 0; first < _digits.Length; first++)
214 if (_digits[first] != 0)
215 break;
216 int last;
217 for (last = _digits.Length - 1; last >= 0; last--)
218 if (_digits[last] != 0)
219 break;
220
221 if (first == 0 && last == _digits.Length - 1)
222 return;
223
224 byte[] tmp = new byte[last - first + 1];
225 for (int i = 0; i < tmp.Length; i++)
226 tmp[i] = _digits[i + first];
227
228 _decimalPoint -= _digits.Length - (last + 1);
229 _digits = tmp;
230 }
231
235 public override string ToString()
236 {
237 char[] digitString = new char[_digits.Length];
238 for (int i = 0; i < _digits.Length; i++)
239 digitString[i] = (char)(_digits[i] + '0');
240
241 // Simplest case - nothing after the decimal point,
242 // and last real digit is non-zero, e.g. value=35
243 if (_decimalPoint == 0)
244 {
245 return new string(digitString);
246 }
247
248 // Fairly simple case - nothing after the decimal
249 // point, but some 0s to add, e.g. value=350
250 if (_decimalPoint < 0)
251 {
252 return new string(digitString) +
253 new string('0', -_decimalPoint);
254 }
255
256 // Nothing before the decimal point, e.g. 0.035
257 if (_decimalPoint >= digitString.Length)
258 {
259 return "0." +
260 new string('0', (_decimalPoint - digitString.Length)) +
261 new string(digitString);
262 }
263
264 // Most complicated case - part of the string comes
265 // before the decimal point, part comes after it,
266 // e.g. 3.5
267 return new string(digitString, 0,
268 digitString.Length - _decimalPoint) +
269 "." +
270 new string(digitString,
271 digitString.Length - _decimalPoint,
272 _decimalPoint);
273 }
274 }
275 }
276 #endregion DoubleConverter
277 }
278}
A class to allow the conversion of doubles to string representations of their exact decimal values....
Definition Output.cs:70
static string ToExactString(double d)
Converts the given double to a string representation of its exact decimal value.
Definition Output.cs:77
A series of generated messages and formatted strings for use in unit tests.
Definition Output.cs:13
static string AutoFormat(object obj)
Format a value as a string for output in a message.
Definition Output.cs:16
static string RandomString(int minLength, int maxLength, Random randomGenerator=null)
Definition Output.cs:39
Interface shared by all object types and resources returned by the Analyze Re server.
Definition IAPIType.cs:6
Base interface for all reference entities.
string ref_id
The id of the object being referred to.
Definition IReference.cs:17