Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Common / Utils / StringUtil.cs
1 //---------------------------------------------------------------------
2 // <copyright file="StringUtil.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10
11 using System;
12 using System.Collections;
13 using System.Collections.Generic;
14 using System.Text;
15 using System.Globalization;
16 using System.Diagnostics;
17
18 namespace System.Data.Common.Utils {
19
20     // This class provides some useful string utilities, e.g., converting a
21     // list to string.
22     internal static class StringUtil {
23         private const string s_defaultDelimiter = ", ";
24
25         #region String Conversion - Unsorted
26         /// <summary>
27         /// Converts an enumeration of values to a delimited string list.
28         /// </summary>
29         /// <typeparam name="T">Type of elements to convert.</typeparam>
30         /// <param name="values">Values. If null, returns empty string.</param>
31         /// <param name="converter">Converter. If null, uses default invariant culture converter.</param>
32         /// <param name="delimiter">Delimiter. If null, uses default (', ')</param>
33         /// <returns>Delimited list of values in string.</returns>
34         internal static string BuildDelimitedList<T>(IEnumerable<T> values, ToStringConverter<T> converter, string delimiter) {
35             if (null == values) { return String.Empty; }
36             if (null == converter) { converter = new ToStringConverter<T>(InvariantConvertToString<T>); }
37             if (null == delimiter) { delimiter = s_defaultDelimiter; }
38
39             StringBuilder sb = new StringBuilder();
40             bool first = true;
41             foreach (T value in values) {
42                 if (first) { first = false; }
43                 else { sb.Append(delimiter); }
44                 sb.Append(converter(value));
45             }
46
47             return sb.ToString();
48         }
49
50         // effects: Converts list to a string separated by a comma with
51         // string.Empty used for null values
52         internal static string ToCommaSeparatedString(IEnumerable list) {
53             return ToSeparatedString(list, s_defaultDelimiter, string.Empty);
54         }
55
56         // effects: Converts list to a string separated by "separator" with
57         // "nullValue" used for null values
58         internal static string ToSeparatedString(IEnumerable list, string separator, string nullValue) {
59             StringBuilder builder = new StringBuilder();
60             ToSeparatedString(builder, list, separator, nullValue);
61             return builder.ToString();
62         }
63         #endregion
64
65         #region String Conversion - Sorted
66         // effects: Converts the list to a list of strings, sorts its
67         // and then converts to a string separated by a comma with
68         // string.Empty used for null values
69         internal static string ToCommaSeparatedStringSorted(IEnumerable list) {
70             return ToSeparatedStringSorted(list, s_defaultDelimiter, string.Empty);
71         }
72
73         // effects: Converts the list to a list of strings, sorts its using
74         // StringComparer.Ordinal
75         // and then converts to a string separated by  "separator" with
76         // with "nullValue" used for null values
77         internal static string ToSeparatedStringSorted(IEnumerable list, string separator, string nullValue) {
78             StringBuilder builder = new StringBuilder();
79             ToSeparatedStringPrivate(builder, list, separator, nullValue, true);
80             return builder.ToString();
81         }
82         #endregion
83
84         #region StringBuilder routines
85
86         internal static string MembersToCommaSeparatedString(IEnumerable members)
87         {
88             StringBuilder builder = new StringBuilder();
89             builder.Append("{");
90             StringUtil.ToCommaSeparatedString(builder, members);
91             builder.Append("}");
92             return builder.ToString();
93         }
94
95         internal static void ToCommaSeparatedString(StringBuilder builder, IEnumerable list) {
96             ToSeparatedStringPrivate(builder, list, s_defaultDelimiter, string.Empty, false);
97         }
98
99         internal static void ToCommaSeparatedStringSorted(StringBuilder builder, IEnumerable list) {
100             ToSeparatedStringPrivate(builder, list, s_defaultDelimiter, string.Empty, true);
101         }
102
103         internal static void ToSeparatedString(StringBuilder builder, IEnumerable list, string separator) {
104             ToSeparatedStringPrivate(builder, list, separator, string.Empty, false);
105         }
106
107         internal static void ToSeparatedStringSorted(StringBuilder builder, IEnumerable list, string separator) {
108             ToSeparatedStringPrivate(builder, list, separator, string.Empty, true);
109         }
110
111         // effects: Modifies stringBuilder to contain a string of values from list
112         // separated by "separator" with "nullValue" used for null values
113         internal static void ToSeparatedString(StringBuilder stringBuilder, IEnumerable list, string separator,
114                                                string nullValue) {
115             ToSeparatedStringPrivate(stringBuilder, list, separator, nullValue, false);
116         }
117
118         // effects: Converts the list to a list of strings, sorts its (if
119         // toSort is true) and then converts to a string separated by
120         // "separator" with "nullValue" used for null values.
121         private static void ToSeparatedStringPrivate(StringBuilder stringBuilder, IEnumerable list, string separator,
122                                                      string nullValue, bool toSort) {
123             if (null == list) {
124                 return;
125             }
126             bool isFirst = true;
127             // Get the list of strings first
128             List<string> elementStrings = new List<string>();
129             foreach (object element in list) {
130                 string str;
131                 // Get the element or its default null value
132                 if (element == null) {
133                     str = nullValue;
134                 } else {
135                     str = FormatInvariant("{0}", element);
136                 }
137                 elementStrings.Add(str);
138             }            
139
140             if (toSort == true) {
141                 // Sort the list
142                 elementStrings.Sort(StringComparer.Ordinal);
143             }
144
145             // Now add the strings to the stringBuilder
146             foreach (string str in elementStrings) {
147                 if (false == isFirst) {
148                     stringBuilder.Append(separator);
149                 }
150                 stringBuilder.Append(str);
151                 isFirst = false;
152             }
153         }
154         #endregion
155
156         #region Some Helper routines
157         /// <summary>
158         ///   This private static method checks a string to make sure that it is not empty.
159         ///   Comparing with String.Empty is not sufficient since a string with nothing
160         ///   but white space isn't considered "empty" by that rationale.
161         /// </summary>
162         internal static bool IsNullOrEmptyOrWhiteSpace(string value)
163         {
164             return IsNullOrEmptyOrWhiteSpace(value, 0);
165         }
166         
167         internal static bool IsNullOrEmptyOrWhiteSpace(string value, int offset)
168         {
169             // don't use Trim(), which will copy the string, which may be large, just to test for emptyness
170             //return String.IsNullOrEmpty(value) || String.IsNullOrEmpty(value.Trim());
171             if (null != value)
172             {
173                 for(int i = offset; i < value.Length; ++i)
174                 {
175                     if (!Char.IsWhiteSpace(value[i]))
176                     {
177                         return false;
178                     }
179                 }
180             }
181             return true;
182         }
183         
184         // separate implementation from IsNullOrEmptyOrWhiteSpace(string, int) because that one will
185         // pick up the jit optimization to avoid boundary checks and the this won't is unknown (most likely not)
186         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] // referenced by System.Data.Entity.Design.dll
187         internal static bool IsNullOrEmptyOrWhiteSpace(string value, int offset, int length)
188         {
189             // don't use Trim(), which will copy the string, which may be large, just to test for emptyness
190             //return String.IsNullOrEmpty(value) || String.IsNullOrEmpty(value.Trim());
191             if (null != value)
192             {
193                 length = Math.Min(value.Length, length);
194                 for(int i = offset; i < length; ++i)
195                 {
196                     if (!Char.IsWhiteSpace(value[i]))
197                     {
198                         return false;
199                     }
200                 }
201             }
202             return true;
203         }
204
205         internal static string FormatInvariant(string format, params object[] args) {
206             Debug.Assert(args.Length > 0, "Formatting utilities must be called with at least one argument");
207             return String.Format(CultureInfo.InvariantCulture, format, args);
208         }
209
210         // effects: Formats args according to the format string and adds it
211         // to builder. Returns the modified builder
212         internal static StringBuilder FormatStringBuilder(StringBuilder builder, string format, params object[] args) {
213             Debug.Assert(args.Length > 0, "Formatting utilities must be called with at least one argument");
214             builder.AppendFormat(CultureInfo.InvariantCulture, format, args);
215             return builder;
216         }
217         
218         // effects: Generates a new line and then indents the new line by
219         // indent steps in builder -- indent steps are determined internally
220         // by this method. Returns the modified builder
221         internal static StringBuilder IndentNewLine(StringBuilder builder, int indent) {
222             builder.AppendLine();
223             for (int i = 0; i < indent; i++) {
224                 builder.Append("    ");
225             }
226             return builder;
227         }
228
229         // effects: returns a string of the form 'arrayVarName[index]'
230         internal static string FormatIndex(string arrayVarName, int index) {
231             System.Text.StringBuilder builder = new System.Text.StringBuilder(arrayVarName.Length + 10 + 2);
232             return builder.Append(arrayVarName).Append('[').Append(index).Append(']').ToString();
233         }
234
235         private static string InvariantConvertToString<T>(T value) {
236             return String.Format(CultureInfo.InvariantCulture, "{0}", value);
237         }
238         #endregion
239
240         #region Delegates
241         internal delegate string ToStringConverter<T>(T value);
242         #endregion
243     }
244 }