public static object Repeat(UnaryOpStorage/*!*/ allocateStorage, JoinConversionStorage/*!*/ conversions, IList/*!*/ self, [DefaultProtocol, NotNull]Union<MutableString, int> repeat) { if (repeat.IsFixnum()) { return Repeat(allocateStorage, self, repeat.Fixnum()); } else { return Repeat(conversions, self, repeat.String()); } }
public static MutableString Repeat(JoinConversionStorage/*!*/ conversions, IList/*!*/ self, [NotNull]MutableString/*!*/ separator) { return Join(conversions, self, separator); }
public static MutableString/*!*/ JoinWithLazySeparatorConversion( JoinConversionStorage/*!*/ conversions, ConversionStorage<MutableString>/*!*/ toStr, IList/*!*/ self, object separator) { if (self.Count == 0) { return MutableString.CreateEmpty(); } return Join(conversions, self, separator != null ? Protocols.CastToString(toStr, separator) : null); }
public static MutableString/*!*/ Join(JoinConversionStorage/*!*/ conversions, IList/*!*/ self) { return Join(conversions, self, conversions.Context.ItemSeparator); }
public static MutableString/*!*/ Join(JoinConversionStorage/*!*/ conversions, IList/*!*/ self, MutableString separator) { var parts = new List<MutableString>(self.Count); bool? isBinary = (separator != null) ? separator.IsBinary : (bool?)null; Dictionary<object, bool> seen = null; // build a list of strings to join: JoinRecursive(conversions, self, parts, ref isBinary, ref seen); if (parts.Count == 0) { return MutableString.CreateEmpty(); } if (separator != null && separator.IsBinary != isBinary && !separator.IsAscii()) { isBinary = true; } // calculate length: MutableString any = separator; int length = (separator != null) ? (isBinary.HasValue && isBinary.Value ? separator.GetByteCount() : separator.GetCharCount()) * (parts.Count - 1) : 0; for (int i = 0, n = parts.Count; i < n; i++) { var part = parts[i]; if (part != null) { length += (isBinary.HasValue && isBinary.Value) ? part.GetByteCount() : part.GetCharCount(); if (any == null) { any = part; } } } if (any == null) { return MutableString.CreateEmpty(); } var result = isBinary.HasValue && isBinary.Value ? MutableString.CreateBinary(length, any.Encoding) : MutableString.CreateMutable(length, any.Encoding); for (int i = 0, n = parts.Count; i < n; i++) { var part = parts[i]; if (separator != null && i > 0) { result.Append(separator); } if (part != null) { result.Append(part); result.TaintBy(part); } } if (separator != null) { result.TaintBy(separator); } if (!result.IsTainted || !result.IsUntrusted) { result.TaintBy(self, conversions.Context); } return result; }
private static void JoinRecursive(JoinConversionStorage/*!*/ conversions, IList/*!*/ list, List<MutableString/*!*/>/*!*/ parts, ref bool? isBinary, ref Dictionary<object, bool> seen) { foreach (object item in list) { if (item == null) { parts.Add(null); continue; } IList listItem = conversions.ToAry.Target(conversions.ToAry, item); if (listItem != null) { bool _; if (ReferenceEquals(listItem, list) || seen != null && seen.TryGetValue(listItem, out _)) { throw RubyExceptions.CreateArgumentError("recursive array join"); } if (seen == null) { seen = new Dictionary<object, bool>(ReferenceEqualityComparer<object>.Instance); } seen.Add(listItem, true); JoinRecursive(conversions, listItem, parts, ref isBinary, ref seen); seen.Remove(listItem); continue; } // try to_str first, then to_s: MutableString strItem = conversions.ToStr.Target(conversions.ToStr, item) ?? conversions.ToS.Target(conversions.ToS, item); parts.Add(strItem); isBinary = isBinary.HasValue ? (isBinary | strItem.IsBinary) : strItem.IsBinary; } }