using System.Collections.Generic; using System.Runtime.CompilerServices; using UnityEngine; //#define DBG // gstring (gcfreestring) is a string wrapper that uses pointers to mutate the string when performing misc string operations // the purpose is to be able to perform most the common operations we do no strings (concat, format, replace, etc) // without any allocation. // gstring is not meant to be stored as member variables, but to quickly declare them in a 'gstring block', use them // for whatever string operation you want, then dispose of them. // The nice thing is that you don't have to manually dispose of gstrings, once you're in a block all assignments are // registered so that when the block/scope ends all used gstrings are disposed. // // But what if you wanted to keep/store the result you calculated and not dispose of them? // Well this is where 'intern' comes in - basically there's a runtime intern (cache) table // of strings (similar to .NET's string const intern table). // string str = result.Intern(); // Which basically says, if the string is in the intern (cache) table, return it // otherwise allocate new memory for it and store it in the table, next time we ask for it, it's there. // The nice thing about interning is that you could pre-intern your strings via the static method gstring.Intern // // NOTES: // 1- The class is not designed with concurrency/threading in mind, it's meant to be used in Unity // 2- Cultural stuff I did not consider as well // 3- Again, you shouldn't have gstring members in your class. All gstring instances are meant to be disposed. // You just quickly open up a gstring.Block() and use gstrings in it, if you want to store a result you get // back from a gstring operation use Intern namespace System { public class gstring { static Dictionary> g_cache; static Stack g_blocks; static List g_intern_table; static gstring_block g_current_block; static List g_finds; static gstring[] g_format_args; const int INITIAL_BLOCK_CAPACITY = 32; const int INITIAL_CACHE_CAPACITY = 128; const int INITIAL_STACK_CAPACITY = 48; const int INITIAL_INTERN_CAPACITY = 256; const char NEW_ALLOC_CHAR = 'X'; [NonSerialized] string _value; [NonSerialized] bool _disposed; internal gstring() { throw new NotSupportedException(); } internal gstring(int length) { _value = new string(NEW_ALLOC_CHAR, length); } static gstring() { Initialize(INITIAL_CACHE_CAPACITY, INITIAL_STACK_CAPACITY, INITIAL_BLOCK_CAPACITY, INITIAL_INTERN_CAPACITY); g_finds = new List(10); g_format_args = new gstring[10]; } internal void dispose() { if (_disposed) throw new ObjectDisposedException(this); // At this point there *must* be a stack whose length is equal to ours // otherwise we wouldn't exist var stack = g_cache[Length]; stack.Push(this); #if DBG if (log != null) log("Disposed: " + _value + " Length=" + Length + " Stack=" + stack.Count); #endif memcpy(_value, NEW_ALLOC_CHAR); _disposed = true; } internal static gstring get(string value) { if (value == null) return null; #if DBG if (log != null) log("Getting: " + value); #endif var result = get(value.Length); memcpy(dst: result, src: value); return result; } internal static string __intern(string value) { int idx = g_intern_table.IndexOf(value); if (idx != -1) return g_intern_table[idx]; string interned = new string(NEW_ALLOC_CHAR, value.Length); memcpy(interned, value); g_intern_table.Add(interned); #if DBG if (log != null) log("Interned: " + value); #endif return interned; } internal static gstring get(int length) { if (g_current_block == null) throw new InvalidOperationException("Getting gstrings must be done in a gstring_block. Make sure you do a using(gstring.block())"); if (length <= 0) throw new InvalidOperationException("Invalid length: " + length); gstring result; Stack stack; if (!g_cache.TryGetValue(length, out stack)) { stack = new Stack(INITIAL_STACK_CAPACITY); for (int i = 0; i < INITIAL_STACK_CAPACITY; i++) stack.Push(new gstring(length)); g_cache[length] = stack; result = stack.Pop(); } else { if (stack.Count == 0) { if (Log != null) Log("Stack=0 Allocating new gstring Length=" + length); result = new gstring(length); } else { result = stack.Pop(); #if DBG if (log != null) log("Popped Length=" + length + " Stack=" + stack.Count); #endif } } result._disposed = false; g_current_block.push(result); return result; } internal static int get_digit_count(int value) { int cnt; for (cnt = 1; (value /= 10) > 0; cnt++) ; return cnt; } internal static int internal_index_of(string input, char value, int start) { return internal_index_of(input, value, start, input.Length - start); } internal static int internal_index_of(string input, string value) { return internal_index_of(input, value, 0, input.Length); } internal static int internal_index_of(string input, string value, int start) { return internal_index_of(input, value, start, input.Length - start); } internal unsafe static gstring internal_format(string input, int num_args) { // "{0} {1}", "Hello", "World" -> // "xxxxxxxxxxx" // "Helloxxxxxx" // "Hello xxxxx" // "Hello World" // "Player={0} Id={1}", "Jon", 10 -> // "xxxxxxxxxxxxxxxx" // "Player=xxxxxxxxx" // "Player=Jonxxxxxx" // "Player=Jon Id=xx" // "Player=Jon Id=10" if (input == null) throw new ArgumentNullException("value"); int new_len = input.Length - 3 * num_args; for (int i = 0; i < num_args; i++) { gstring arg = g_format_args[i]; new_len += arg.Length; } gstring result = get(new_len); string res_value = result._value; int brace_idx = -3; for (int i = 0, j = 0, x = 0; x < num_args; x++) { string arg = g_format_args[x]._value; brace_idx = internal_index_of(input, '{', brace_idx + 3); if (brace_idx == -1) throw new InvalidOperationException("Couldn't find open brace for argument " + arg); if (brace_idx + 2 >= input.Length || input[brace_idx + 2] != '}') throw new InvalidOperationException("Couldn't find close brace for argument " + arg); fixed (char* ptr_input = input) { fixed (char* ptr_result = res_value) { for (int k = 0; i < new_len;) { if (j < brace_idx) ptr_result[i++] = ptr_input[j++]; else { ptr_result[i++] = arg[k++]; if (k == arg.Length) { j += 3; break; } } } } } } return result; } internal unsafe static int internal_index_of(string input, char value, int start, int count) { if (start < 0 || start >= input.Length) throw new ArgumentOutOfRangeException("start"); if (start + count > input.Length) throw new ArgumentOutOfRangeException("count=" + count + " start+count=" + start + count); fixed (char* ptr_this = input) { int end = start + count; for (int i = start; i < end; i++) if (ptr_this[i] == value) return i; return -1; } } internal unsafe static int internal_index_of(string input, string value, int start, int count) { int input_len = input.Length; if (start < 0 || start >= input_len) throw new ArgumentOutOfRangeException("start"); if (count < 0 || start + count > input_len) throw new ArgumentOutOfRangeException("count=" + count + " start+count=" + (start + count)); if (count == 0) return -1; fixed (char* ptr_input = input) { fixed (char* ptr_value = value) { int found = 0; int end = start + count; for (int i = start; i < end; i++) { for (int j = 0; j < value.Length && i + j < input_len; j++) { if (ptr_input[i + j] == ptr_value[j]) { found++; if (found == value.Length) return i; continue; } if (found > 0) break; } } return -1; } } } internal unsafe static gstring internal_remove(string input, int start, int count) { if (start < 0 || start >= input.Length) throw new ArgumentOutOfRangeException("start=" + start + " Length=" + input.Length); if (count < 0 || start + count > input.Length) throw new ArgumentOutOfRangeException("count=" + count + " start+count=" + (start + count) + " Length=" + input.Length); if (count == 0) return input; gstring result = get(input.Length - count); internal_remove(result, input, start, count); return result; } internal unsafe static void internal_remove(string dst, string src, int start, int count) { fixed (char* src_ptr = src) { fixed (char* dst_ptr = dst) { for (int i = 0, j = 0; i < dst.Length; i++) { if (i >= start && i < start + count) // within removal range continue; dst_ptr[j++] = src_ptr[i]; } } } } internal unsafe static gstring internal_replace(string value, string old_value, string new_value) { // "Hello, World. There World" | World->Jon = // "000000000000000000000" (len = orig - 2 * (world-jon) = orig - 4 // "Hello, 00000000000000" // "Hello, Jon00000000000" // "Hello, Jon. There 000" // "Hello, Jon. There Jon" // "Hello, World. There World" | World->Alexander = // "000000000000000000000000000000000" (len = orig + 2 * (alexander-world) = orig + 8 // "Hello, 00000000000000000000000000" // "Hello, Alexander00000000000000000" // "Hello, Alexander. There 000000000" // "Hello, Alexander. There Alexander" if (old_value == null) throw new ArgumentNullException("old_value"); if (new_value == null) throw new ArgumentNullException("new_value"); int idx = internal_index_of(value, old_value); if (idx == -1) return value; g_finds.Clear(); g_finds.Add(idx); // find all the indicies beforehand while (idx + old_value.Length < value.Length) { idx = internal_index_of(value, old_value, idx + old_value.Length); if (idx == -1) break; g_finds.Add(idx); } // calc the right new total length int new_len; int dif = old_value.Length - new_value.Length; if (dif > 0) new_len = value.Length - (g_finds.Count * dif); else new_len = value.Length + (g_finds.Count * -dif); gstring result = get(new_len); fixed (char* ptr_this = value) { fixed (char* ptr_result = result._value) { for (int i = 0, x = 0, j = 0; i < new_len;) { if (x == g_finds.Count || g_finds[x] != j) { ptr_result[i++] = ptr_this[j++]; } else { for (int n = 0; n < new_value.Length; n++) ptr_result[i + n] = new_value[n]; x++; i += new_value.Length; j += old_value.Length; } } } } return result; } internal unsafe static gstring internal_insert(string value, char to_insert, int start, int count) { // "HelloWorld" (to_insert=x, start=5, count=3) -> "HelloxxxWorld" if (start < 0 || start >= value.Length) throw new ArgumentOutOfRangeException("start=" + start + " Length=" + value.Length); if (count < 0) throw new ArgumentOutOfRangeException("count=" + count); if (count == 0) return get(value); int new_len = value.Length + count; gstring result = get(new_len); fixed (char* ptr_value = value) { fixed (char* ptr_result = result._value) { for (int i = 0, j = 0; i < new_len; i++) { if (i >= start && i < start + count) ptr_result[i] = to_insert; else ptr_result[i] = ptr_value[j++]; } } } return result; } internal unsafe static gstring internal_insert(string input, string to_insert, int start) { if (input == null) throw new ArgumentNullException("input"); if (to_insert == null) throw new ArgumentNullException("to_insert"); if (start < 0 || start >= input.Length) throw new ArgumentOutOfRangeException("start=" + start + " Length=" + input.Length); if (to_insert.Length == 0) return get(input); int new_len = input.Length + to_insert.Length; gstring result = get(new_len); internal_insert(result, input, to_insert, start); return result; } internal unsafe static gstring internal_concat(string s1, string s2) { int total_length = s1.Length + s2.Length; gstring result = get(total_length); fixed (char* ptr_result = result._value) { fixed (char* ptr_s1 = s1) { fixed (char* ptr_s2 = s2) { memcpy(dst: ptr_result, src: ptr_s1, length: s1.Length, src_offset: 0); memcpy(dst: ptr_result, src: ptr_s2, length: s2.Length, src_offset: s1.Length); } } } return result; } internal unsafe static void internal_insert(string dst, string src, string to_insert, int start) { fixed (char* ptr_src = src) { fixed (char* ptr_dst = dst) { fixed (char* ptr_to_insert = to_insert) { for (int i = 0, j = 0, k = 0; i < dst.Length; i++) { if (i >= start && i < start + to_insert.Length) ptr_dst[i] = ptr_to_insert[k++]; else ptr_dst[i] = ptr_src[j++]; } } } } } internal unsafe static void intcpy(char* dst, int value, int start, int count) { int end = start + count; for (int i = end - 1; i >= start; i--, value /= 10) *(dst + i) = (char)(value % 10 + 48); } internal unsafe static void memcpy(char* dst, char* src, int count) { for (int i = 0; i < count; i++) *(dst++) = *(src++); } internal unsafe static void memcpy(string dst, char src) { fixed (char* ptr_dst = dst) { int len = dst.Length; for (int i = 0; i < len; i++) ptr_dst[i] = src; } } internal unsafe static void memcpy(string dst, char src, int index) { fixed (char* ptr = dst) ptr[index] = src; } internal unsafe static void memcpy(string dst, string src) { if (dst.Length != src.Length) throw new InvalidOperationException("Length mismatch"); memcpy(dst, src, dst.Length, 0); } internal unsafe static void memcpy(char* dst, char* src, int length, int src_offset) { for (int i = 0; i < length; i++) *(dst + i + src_offset) = *(src + i); } internal unsafe static void memcpy(string dst, string src, int length, int src_offset) { fixed (char* ptr_dst = dst) { fixed (char* ptr_src = src) { for (int i = 0; i < length; i++) ptr_dst[i + src_offset] = ptr_src[i]; } } } internal class gstring_block : IDisposable { readonly Stack stack; internal gstring_block(int capacity) { stack = new Stack(capacity); } internal void push(gstring str) { stack.Push(str); } internal IDisposable begin() { #if DBG if (log != null) log("Began block"); #endif return this; } void IDisposable.Dispose() { #if DBG if (log != null) log("Disposing block"); #endif while (stack.Count > 0) { var str = stack.Pop(); str.dispose(); } gstring.g_blocks.Push(this); } } // Public API #region public static Action Log = null; public static int DecimalAccuracy = 3; // digits after the decimal point public int Length { get { return _value.Length; } } public static void Initialize(int cache_capacity, int stack_capacity, int block_capacity, int intern_capacity) { g_cache = new Dictionary>(cache_capacity); g_blocks = new Stack(block_capacity); g_intern_table = new List(intern_capacity); for (int c = 1; c < cache_capacity; c++) { var stack = new Stack(stack_capacity); for (int j = 0; j < stack_capacity; j++) stack.Push(new gstring(c)); g_cache[c] = stack; } for (int i = 0; i < block_capacity; i++) { var block = new gstring_block(block_capacity * 2); g_blocks.Push(block); } } public static IDisposable Block() { if (g_blocks.Count == 0) g_current_block = new gstring_block(INITIAL_BLOCK_CAPACITY * 2); else g_current_block = g_blocks.Pop(); return g_current_block.begin(); } public string Intern() { return __intern(_value); } public static string Intern(string value) { return __intern(value); } public static void Intern(string[] values) { for (int i = 0; i < values.Length; i++) __intern(values[i]); } public char this[int i] { get { return _value[i]; } set { memcpy(this, value, i); } } public override int GetHashCode() { return RuntimeHelpers.GetHashCode(_value); } public override bool Equals(object obj) { if (obj == null) return ReferenceEquals(this, null); var gstr = obj as gstring; if (gstr != null) return gstr._value == this._value; var str = obj as string; if (str != null) return str == this._value; return false; } public override string ToString() { return _value; } public static implicit operator gstring(bool value) { return get(value ? "True" : "False"); } public unsafe static implicit operator gstring(int value) { // e.g. 125 // first pass: count the number of digits // then: get a gstring with length = num digits // finally: iterate again, get the char of each digit, memcpy char to result bool negative = value < 0; value = Math.Abs(value); int num_digits = get_digit_count(value); gstring result; if (negative) { result = get(num_digits + 1); fixed (char* ptr = result._value) { *ptr = '-'; intcpy(ptr, value, 1, num_digits); } } else { result = get(num_digits); fixed (char* ptr = result._value) intcpy(ptr, value, 0, num_digits); } return result; } public unsafe static implicit operator gstring(float value) { // e.g. 3.148 bool negative = value < 0; if (negative) value = -value; int mul = (int)Math.Pow(10, DecimalAccuracy); int number = (int)(value * mul); // gets the number as a whole, e.g. 3148 int left_num = number / mul; // left part of the decimal point, e.g. 3 int right_num = number % mul; // right part of the decimal pnt, e.g. 148 int left_digit_count = get_digit_count(left_num); // e.g. 1 int right_digit_count = get_digit_count(right_num); // e.g. 3 int total = left_digit_count + right_digit_count + 1; // +1 for '.' gstring result; if (negative) { result = get(total + 1); // +1 for '-' fixed (char* ptr = result._value) { *ptr = '-'; intcpy(ptr, left_num, 1, left_digit_count); *(ptr + left_digit_count + 1) = '.'; intcpy(ptr, right_num, left_digit_count + 2, right_digit_count); } } else { result = get(total); fixed (char* ptr = result._value) { intcpy(ptr, left_num, 0, left_digit_count); *(ptr + left_digit_count) = '.'; intcpy(ptr, right_num, left_digit_count + 1, right_digit_count); } } return result; } public static implicit operator gstring(string value) { return get(value); } public static implicit operator string(gstring value) { return value._value; } public static gstring operator +(gstring left, gstring right) { return internal_concat(left, right); } public static bool operator ==(gstring left, gstring right) { if (ReferenceEquals(left, null)) return ReferenceEquals(right, null); if (ReferenceEquals(right, null)) return false; return left._value == right._value; } public static bool operator !=(gstring left, gstring right) { return !(left._value == right._value); } public unsafe gstring ToUpper() { var result = get(Length); fixed (char* ptr_this = this._value) { fixed (char* ptr_result = result._value) { for (int i = 0; i < _value.Length; i++) { var ch = ptr_this[i]; if (char.IsLower(ch)) ptr_result[i] = char.ToUpper(ch); else ptr_result[i] = ptr_this[i]; } } } return result; } public unsafe gstring ToLower() { var result = get(Length); fixed (char* ptr_this = this._value) { fixed (char* ptr_result = result._value) { for (int i = 0; i < _value.Length; i++) { var ch = ptr_this[i]; if (char.IsUpper(ch)) ptr_result[i] = char.ToLower(ch); else ptr_result[i] = ptr_this[i]; } } } return result; } public gstring Remove(int start) { return Remove(start, Length - start); } public gstring Remove(int start, int count) { return internal_remove(this._value, start, count); } public gstring Insert(char value, int start, int count) { return internal_insert(this._value, value, start, count); } public gstring Insert(string value, int start) { return internal_insert(this._value, value, start); } public unsafe gstring Replace(char old_value, char new_value) { gstring result = get(Length); fixed (char* ptr_this = this._value) { fixed (char* ptr_result = result._value) { for (int i = 0; i < Length; i++) { if (ptr_this[i] == old_value) ptr_result[i] = new_value; else ptr_result[i] = ptr_this[i]; } } } return result; } public gstring Replace(string old_value, string new_value) { return internal_replace(this._value, old_value, new_value); } public gstring Substring(int start) { return Substring(start, Length - start); } public unsafe gstring Substring(int start, int count) { if (start < 0 || start >= Length) throw new ArgumentOutOfRangeException("start"); if (count > Length) throw new ArgumentOutOfRangeException("count"); gstring result = get(count); fixed (char* src = this._value) fixed (char* dst = result._value) memcpy(dst, src + start, count); return result; } public bool Contains(string value) { return IndexOf(value) != -1; } public bool Contains(char value) { return IndexOf(value) != -1; } public int LastIndexOf(string value) { int idx = -1; int last_find = -1; while (true) { idx = internal_index_of(this._value, value, idx + value.Length); last_find = idx; if (idx == -1 || idx + value.Length >= this._value.Length) break; } return last_find; } public int LastIndexOf(char value) { int idx = -1; int last_find = -1; while (true) { idx = internal_index_of(this._value, value, idx + 1); last_find = idx; if (idx == -1 || idx + 1 >= this._value.Length) break; } return last_find; } public int IndexOf(char value) { return IndexOf(value, 0, Length); } public int IndexOf(char value, int start) { return internal_index_of(this._value, value, start); } public int IndexOf(char value, int start, int count) { return internal_index_of(this._value, value, start, count); } public int IndexOf(string value) { return IndexOf(value, 0, Length); } public int IndexOf(string value, int start) { return IndexOf(value, start, Length - start); } public int IndexOf(string value, int start, int count) { return internal_index_of(this._value, value, start, count); } public unsafe bool EndsWith(string postfix) { if (postfix == null) throw new ArgumentNullException("postfix"); if (this.Length < postfix.Length) return false; fixed (char* ptr_this = this._value) { fixed (char* ptr_postfix = postfix) { for (int i = this._value.Length - 1, j = postfix.Length - 1; j >= 0; i--, j--) if (ptr_this[i] != ptr_postfix[j]) return false; } } return true; } public unsafe bool StartsWith(string prefix) { if (prefix == null) throw new ArgumentNullException("prefix"); if (this.Length < prefix.Length) return false; fixed (char* ptr_this = this._value) { fixed (char* ptr_prefix = prefix) { for (int i = 0; i < prefix.Length; i++) if (ptr_this[i] != ptr_prefix[i]) return false; } } return true; } public static int GetCacheCount(int length) { Stack stack; if (!g_cache.TryGetValue(length, out stack)) return -1; return stack.Count; } public gstring Concat(gstring value) { return internal_concat(this, value); } public static gstring Concat(gstring s0, gstring s1) { return s0 + s1; } public static gstring Concat(gstring s0, gstring s1, gstring s2) { return s0 + s1 + s2; } public static gstring Concat(gstring s0, gstring s1, gstring s2, gstring s3) { return s0 + s1 + s2 + s3; } public static gstring Concat(gstring s0, gstring s1, gstring s2, gstring s3, gstring s4) { return s0 + s1 + s2 + s3 + s4; } public static gstring Concat(gstring s0, gstring s1, gstring s2, gstring s3, gstring s4, gstring s5) { return s0 + s1 + s2 + s3 + s4 + s5; } public static gstring Concat(gstring s0, gstring s1, gstring s2, gstring s3, gstring s4, gstring s5, gstring s6) { return s0 + s1 + s2 + s3 + s4 + s5 + s6; } public static gstring Concat(gstring s0, gstring s1, gstring s2, gstring s3, gstring s4, gstring s5, gstring s6, gstring s7) { return s0 + s1 + s2 + s3 + s4 + s5 + s6 + s7; } public static gstring Concat(gstring s0, gstring s1, gstring s2, gstring s3, gstring s4, gstring s5, gstring s6, gstring s7, gstring s8) { return s0 + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8; } public static gstring Concat(gstring s0, gstring s1, gstring s2, gstring s3, gstring s4, gstring s5, gstring s6, gstring s7, gstring s8, gstring s9) { return s0 + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9; } public static gstring Format(string input, gstring arg0, gstring arg1, gstring arg2, gstring arg3, gstring arg4, gstring arg5, gstring arg6, gstring arg7, gstring arg8, gstring arg9) { if (arg0 == null) throw new ArgumentNullException("arg0"); if (arg1 == null) throw new ArgumentNullException("arg1"); if (arg2 == null) throw new ArgumentNullException("arg2"); if (arg3 == null) throw new ArgumentNullException("arg3"); if (arg4 == null) throw new ArgumentNullException("arg4"); if (arg5 == null) throw new ArgumentNullException("arg5"); if (arg6 == null) throw new ArgumentNullException("arg6"); if (arg7 == null) throw new ArgumentNullException("arg7"); if (arg8 == null) throw new ArgumentNullException("arg8"); if (arg9 == null) throw new ArgumentNullException("arg9"); g_format_args[0] = arg0; g_format_args[1] = arg1; g_format_args[2] = arg2; g_format_args[3] = arg3; g_format_args[4] = arg4; g_format_args[5] = arg5; g_format_args[6] = arg6; g_format_args[7] = arg7; g_format_args[8] = arg8; g_format_args[9] = arg9; return internal_format(input, 10); } public static gstring Format(string input, gstring arg0, gstring arg1, gstring arg2, gstring arg3, gstring arg4, gstring arg5, gstring arg6, gstring arg7, gstring arg8) { if (arg0 == null) throw new ArgumentNullException("arg0"); if (arg1 == null) throw new ArgumentNullException("arg1"); if (arg2 == null) throw new ArgumentNullException("arg2"); if (arg3 == null) throw new ArgumentNullException("arg3"); if (arg4 == null) throw new ArgumentNullException("arg4"); if (arg5 == null) throw new ArgumentNullException("arg5"); if (arg6 == null) throw new ArgumentNullException("arg6"); if (arg7 == null) throw new ArgumentNullException("arg7"); if (arg8 == null) throw new ArgumentNullException("arg8"); g_format_args[0] = arg0; g_format_args[1] = arg1; g_format_args[2] = arg2; g_format_args[3] = arg3; g_format_args[4] = arg4; g_format_args[5] = arg5; g_format_args[6] = arg6; g_format_args[7] = arg7; g_format_args[8] = arg8; return internal_format(input, 9); } public static gstring Format(string input, gstring arg0, gstring arg1, gstring arg2, gstring arg3, gstring arg4, gstring arg5, gstring arg6, gstring arg7) { if (arg0 == null) throw new ArgumentNullException("arg0"); if (arg1 == null) throw new ArgumentNullException("arg1"); if (arg2 == null) throw new ArgumentNullException("arg2"); if (arg3 == null) throw new ArgumentNullException("arg3"); if (arg4 == null) throw new ArgumentNullException("arg4"); if (arg5 == null) throw new ArgumentNullException("arg5"); if (arg6 == null) throw new ArgumentNullException("arg6"); if (arg7 == null) throw new ArgumentNullException("arg7"); g_format_args[0] = arg0; g_format_args[1] = arg1; g_format_args[2] = arg2; g_format_args[3] = arg3; g_format_args[4] = arg4; g_format_args[5] = arg5; g_format_args[6] = arg6; g_format_args[7] = arg7; return internal_format(input, 8); } public static gstring Format(string input, gstring arg0, gstring arg1, gstring arg2, gstring arg3, gstring arg4, gstring arg5, gstring arg6) { if (arg0 == null) throw new ArgumentNullException("arg0"); if (arg1 == null) throw new ArgumentNullException("arg1"); if (arg2 == null) throw new ArgumentNullException("arg2"); if (arg3 == null) throw new ArgumentNullException("arg3"); if (arg4 == null) throw new ArgumentNullException("arg4"); if (arg5 == null) throw new ArgumentNullException("arg5"); if (arg6 == null) throw new ArgumentNullException("arg6"); g_format_args[0] = arg0; g_format_args[1] = arg1; g_format_args[2] = arg2; g_format_args[3] = arg3; g_format_args[4] = arg4; g_format_args[5] = arg5; g_format_args[6] = arg6; return internal_format(input, 7); } public static gstring Format(string input, gstring arg0, gstring arg1, gstring arg2, gstring arg3, gstring arg4, gstring arg5) { if (arg0 == null) throw new ArgumentNullException("arg0"); if (arg1 == null) throw new ArgumentNullException("arg1"); if (arg2 == null) throw new ArgumentNullException("arg2"); if (arg3 == null) throw new ArgumentNullException("arg3"); if (arg4 == null) throw new ArgumentNullException("arg4"); if (arg5 == null) throw new ArgumentNullException("arg5"); g_format_args[0] = arg0; g_format_args[1] = arg1; g_format_args[2] = arg2; g_format_args[3] = arg3; g_format_args[4] = arg4; g_format_args[5] = arg5; return internal_format(input, 6); } public static gstring Format(string input, gstring arg0, gstring arg1, gstring arg2, gstring arg3, gstring arg4) { if (arg0 == null) throw new ArgumentNullException("arg0"); if (arg1 == null) throw new ArgumentNullException("arg1"); if (arg2 == null) throw new ArgumentNullException("arg2"); if (arg3 == null) throw new ArgumentNullException("arg3"); if (arg4 == null) throw new ArgumentNullException("arg4"); g_format_args[0] = arg0; g_format_args[1] = arg1; g_format_args[2] = arg2; g_format_args[3] = arg3; g_format_args[4] = arg4; return internal_format(input, 5); } public static gstring Format(string input, gstring arg0, gstring arg1, gstring arg2, gstring arg3) { if (arg0 == null) throw new ArgumentNullException("arg0"); if (arg1 == null) throw new ArgumentNullException("arg1"); if (arg2 == null) throw new ArgumentNullException("arg2"); if (arg3 == null) throw new ArgumentNullException("arg3"); g_format_args[0] = arg0; g_format_args[1] = arg1; g_format_args[2] = arg2; g_format_args[3] = arg3; return internal_format(input, 4); } public static gstring Format(string input, gstring arg0, gstring arg1, gstring arg2) { if (arg0 == null) throw new ArgumentNullException("arg0"); if (arg1 == null) throw new ArgumentNullException("arg1"); if (arg2 == null) throw new ArgumentNullException("arg2"); g_format_args[0] = arg0; g_format_args[1] = arg1; g_format_args[2] = arg2; return internal_format(input, 3); } public static gstring Format(string input, gstring arg0, gstring arg1) { if (arg0 == null) throw new ArgumentNullException("arg0"); if (arg1 == null) throw new ArgumentNullException("arg1"); g_format_args[0] = arg0; g_format_args[1] = arg1; return internal_format(input, 2); } public static gstring Format(string input, gstring arg0) { if (arg0 == null) throw new ArgumentNullException("arg0"); g_format_args[0] = arg0; return internal_format(input, 1); } #endregion } public static class GStringExtensions { public static bool IsNullOrEmpty(this gstring str) { return str == null || str.Length == 0; } public static bool IsPrefix(this gstring str, string value) { return str.StartsWith(value); } public static bool ispostfix(this gstring str, string postfix) { return str.EndsWith(postfix); } } }