using System; using System.Collections.Generic; namespace ProtoCSStruct { public class RepeatedStructWriter { Dictionary vars = new Dictionary(); private void InitVars(ProtoMessageField field) { vars.Add("$TypeName$", field.GetFiledTypeNameInCSharp()); vars.Add("$StructName$", field.RepeatedFiledTypeNameInCSharp); vars.Add("$RepeatedCount$", field.RepeatedCount.ToString()); vars.Add("$RepeatedFiledBuffSize$", field.RepeatedFiledBuffSize.ToString()); } /// /// /// /// repeated 字段描述 /// public void Write(ProtoMessageField field, FileWriter fw) { InitVars(field); fw.Write(vars, "unsafe public struct $StructName$", "{"); fw.Indent(); fw.Write(vars, "const int BuffSize = $RepeatedFiledBuffSize$;", "public const int MaxCount = $RepeatedCount$;", "public int Count;", "public fixed byte Buffer[BuffSize];" ); WriteFun_GetCount(fw); //WriteFun_IsEmpty(fw); WriteFun_GetMaxCount(fw); WriteFun_Get(fw); WriteFun_Contains(field, fw); WriteFun_Add(field, fw); WriteFun_CopyFrom(field, fw); WriteFun_Remove(fw); WriteFun_RemoveAt(fw); WriteFun_RemoveAll(fw); WriteFun_Clear(fw); WriteFun_CalculateSize(field, fw); WriteFun_WriteTo(field, fw); WriteFun_ReadFrom(field, fw); WriteFun_ToString(field, fw); fw.Outdent(); fw.Write("}"); fw.Write(""); } private void WriteFun_GetCount(FileWriter fw) { fw.Write( "public int GetCount()", "{", " return Count;", "}" ); } private void WriteFun_IsEmpty(FileWriter fw) { fw.Write( "public bool IsEmpty()", "{", " return Count == 0;", "}", "" ); } private void WriteFun_GetMaxCount(FileWriter fw) { fw.Write( "public int GetMaxCount()", "{", " return MaxCount;", "}" ); } private void WriteFun_Get(FileWriter fw) { fw.Write(vars, "public ref $TypeName$ Get(int index)", "{", " if (index < 0 || index >= Count)", " {", " string message = string.Format(\"class $StructName$ index{0} count{1}\", index, Count);", " throw new ArgumentOutOfRangeException(message);", " }", " fixed (byte* pb = Buffer)", " {", " $TypeName$* pbs = ($TypeName$*)pb;", " return ref pbs[index];", " }", "}" ); fw.Write(vars, "public ref $TypeName$ this[int index]", "{", " get", " {", " if (index < 0 || index >= Count)", " {", " string message = string.Format(\"class $StructName$ index{0} count{1}\", index, Count);", " throw new ArgumentOutOfRangeException(message);", " }", " fixed (byte* pb = Buffer)", " {", " $TypeName$* pbs = ($TypeName$*)pb;", " return ref pbs[index];", " }", " }", "}" ); } private void WriteFun_Contains(ProtoMessageField field, FileWriter fw) { if (field.FieldType == FieldType.Bool || field.FieldType == FieldType.Bytes || field.FieldType == FieldType.Enum || field.FieldType == FieldType.Int32 || field.FieldType == FieldType.UInt32 || field.FieldType == FieldType.Int64 || field.FieldType == FieldType.UInt64) { fw.Write(vars, "public bool Contains($TypeName$ item)", "{", " fixed (byte* pb = Buffer)", " {", " $TypeName$* pbs = ($TypeName$*)pb;", " for (int i = 0; i < Count; i++)", " {", " if (pbs[i] == item)", " {", " return true;", " }", " }", " }", " return false;", "}" ); } } private void WriteFun_Add(ProtoMessageField field, FileWriter fw) { if (field.FieldType == FieldType.Bool || field.FieldType == FieldType.Bytes || field.FieldType == FieldType.Enum || field.FieldType == FieldType.Int32 || field.FieldType == FieldType.UInt32 || field.FieldType == FieldType.Int64 || field.FieldType == FieldType.UInt64) { fw.Write(vars, "public void Add(ref $TypeName$ item)", "{", " if (Count >= MaxCount)", " {", " string message = string.Format(\"class $StructName$ count{0}\", Count);", " throw new ArgumentOutOfRangeException(message);", " }", " ref $TypeName$ my = ref Get(Count++);", " my = item;", "}" ); fw.Write(vars, "public void Add($TypeName$ item)", "{", " if (Count >= MaxCount)", " {", " string message = string.Format(\"class $StructName$ count{0}\", Count);", " throw new ArgumentOutOfRangeException(message);", " }", " ref $TypeName$ my = ref Get(Count++);", " my = item;", "}" ); } else { fw.Write(vars, "public void Add(ref $TypeName$ item)", "{", " if (Count >= MaxCount)", " {", " string message = string.Format(\"class $StructName$ count{0}\", Count);", " throw new ArgumentOutOfRangeException(message);", " }", " ref $TypeName$ my = ref Get(Count++);", " my = item;", "}" ); fw.Write(vars, "//low performance call, not recommend!!!", "public void Add($TypeName$ item)", "{", " if (Count >= MaxCount)", " {", " string message = string.Format(\"class $StructName$ count{0}\", Count);", " throw new ArgumentOutOfRangeException(message);", " }", " ref $TypeName$ my = ref Get(Count++);", " my = item;", "}" ); if (field.FieldType == FieldType.String) { fw.Write(vars, "public void Add(string item)", "{", " if (Count >= MaxCount)", " {", " string message = string.Format(\"class $StructName$ count{0}\", Count);", " throw new ArgumentOutOfRangeException(message);", " }", " ref $TypeName$ my = ref Get(Count++);", " my.SetString(item);", "}" ); } } } private void WriteFun_CopyFrom(ProtoMessageField field, FileWriter fw) { if (field.FieldType == FieldType.Bool || field.FieldType == FieldType.Bytes || field.FieldType == FieldType.Enum || field.FieldType == FieldType.Int32 || field.FieldType == FieldType.UInt32 || field.FieldType == FieldType.Int64 || field.FieldType == FieldType.UInt64) { fw.Write(vars, "public void CopyFrom(ref $StructName$ other)", "{", " Count = other.Count;", " for(int i = 0; i < Count; i++)", " {", " this[i] = other[i];", " }", "}" ); } else { fw.Write(vars, "public void CopyFrom(ref $StructName$ other)", "{", " Count = other.Count;", " for(int i = 0; i < Count; i++)", " {", " this[i].CopyFrom(ref other[i]);", " }", "}" ); } } private void WriteFun_Remove(FileWriter fw) { fw.Write(vars, "public void Remove(ref $TypeName$ item)", "{", " fixed ($TypeName$* p = &item)", " {", " fixed (byte* pb = Buffer)", " {", " $TypeName$* pbs = ($TypeName$*)pb;", " for (int i = 0; i < Count; i++)\n", " {", " if(p == pbs + i)", " {", " Count--;", " for(; i < Count; i++ )", " {", " pbs[i] = pbs[i + 1];", " }", " return;", " }", " }", " }", " }", "}" ); } private void WriteFun_RemoveAt(FileWriter fw) { fw.Write(vars, "public void RemoveAt(int index)", "{", " if (index < 0 || index >= Count)", " {", " string message = string.Format(\"class $StructName$ index{0} count{1}\", index, Count);", " throw new ArgumentOutOfRangeException(message);", " }", " fixed (byte* pb = Buffer)", " {", " $TypeName$* pbs = ($TypeName$*)pb;", " Count--;", " for (int i = index; i < Count; i++)", " {", " pbs[i] = pbs[i + 1];", " }", " return;", " }", "}" ); } private void WriteFun_RemoveAll(FileWriter fw) { fw.Write( "public void RemoveAll()", "{", " Count = 0;", "}" ); } private void WriteFun_Clear(FileWriter fw) { fw.Write( "public void Clear()", "{", " if (Count != 0)", " {", " Count = 0;", " }", "}" ); } private void WriteFun_CalculateSize(ProtoMessageField field, FileWriter fw) { fw.Write( "public int CalculateSize(uint tag)", "{", " if(Count == 0)", " {", " return 0;", " }" ); fw.Indent(); if (field.FieldType == FieldType.Bool || field.FieldType == FieldType.Bytes || field.FieldType == FieldType.Enum || field.FieldType == FieldType.Int32 || field.FieldType == FieldType.UInt32 || field.FieldType == FieldType.Int64 || field.FieldType == FieldType.UInt64) { string computesizevalue = ""; if (field.FieldType == FieldType.Bool) { computesizevalue = "WireFormat.ComputeBoolSize(pbs[i]);"; } if (field.FieldType == FieldType.Bytes) { computesizevalue = "1;"; } if (field.FieldType == FieldType.Enum) { computesizevalue = "WireFormat.ComputeEnumSize((int)pbs[i]);"; } if (field.FieldType == FieldType.Int32) { computesizevalue = "WireFormat.ComputeInt32Size(pbs[i]);"; } if (field.FieldType == FieldType.UInt32) { computesizevalue = "WireFormat.ComputeUInt32Size(pbs[i]);"; } if (field.FieldType == FieldType.Int64) { computesizevalue = "WireFormat.ComputeInt64Size(pbs[i]);"; } if (field.FieldType == FieldType.UInt64) { computesizevalue = "WireFormat.ComputeUInt64Size(pbs[i]);"; } fw.Write(vars, "int datasize = CalculateDataSize();", "return WireFormat.ComputeLengthSize(datasize) +", " WireFormat.ComputeTagSize(tag) +", " datasize;" ); fw.Outdent(); fw.Write("}"); fw.Write(""); fw.Write(vars, "public int CalculateDataSize()", "{", " if(Count == 0)", " {", " return 0;", " }", " int datasize = 0;", " fixed (byte* pb = Buffer)", " {", " $TypeName$* pbs = ($TypeName$*)pb;", " for(int i = 0; i < Count; i++)", " {", " datasize += " + computesizevalue, " }", " }", " return datasize;", "}" ); } else { fw.Write(vars, "int size = 0;", "size += Count * WireFormat.ComputeTagSize(tag);", "fixed (byte* pb = Buffer)", "{", " $TypeName$* pbs = ($TypeName$*)pb;", " for(int i = 0; i < Count; i++)", " {", " int length = pbs[i].CalculateSize();", " size += length + WireFormat.ComputeLengthSize(length);", " }", "}", "return size;" ); fw.Outdent(); fw.Write("}"); fw.Write(""); } } //原生类型缺省packed,message,string类型需要按数量循环处理 private void WriteFun_WriteTo(ProtoMessageField field, FileWriter fw) { fw.Write( "public void WriteTo(CodedOutputStream output, uint tag)", "{", " if(Count == 0)", " {", " return;", " }" ); fw.Indent(); if (field.FieldType == FieldType.Bool || field.FieldType == FieldType.Bytes || field.FieldType == FieldType.Enum || field.FieldType == FieldType.Int32 || field.FieldType == FieldType.UInt32 || field.FieldType == FieldType.Int64 || field.FieldType == FieldType.UInt64) { string output_writevalue = ""; if (field.FieldType == FieldType.Bool) { output_writevalue = "output.WriteBool(pbs[i]);"; } if (field.FieldType == FieldType.Bytes) { output_writevalue = "output.WriteRawByte(pbs[i]);"; } if (field.FieldType == FieldType.Enum) { output_writevalue = "output.WriteEnum((int)pbs[i]);"; } if (field.FieldType == FieldType.Int32) { output_writevalue = "output.WriteInt32(pbs[i]);"; } if (field.FieldType == FieldType.UInt32) { output_writevalue = "output.WriteUInt32(pbs[i]);"; } if (field.FieldType == FieldType.Int64) { output_writevalue = "output.WriteInt64(pbs[i]);"; } if (field.FieldType == FieldType.UInt64) { output_writevalue = "output.WriteUInt64(pbs[i]);"; } fw.Write(vars, "int datasize = CalculateDataSize();", "output.WriteTag(tag);", "output.WriteLength(datasize);", "fixed (byte* pb = Buffer)", "{", " $TypeName$* pbs = ($TypeName$*)pb;", " for(int i = 0; i < Count; i++)", " {", " " + output_writevalue, " }", "}" ); } else if (field.FieldType == FieldType.String) //String的WriteTo自己会写长度信息 { fw.Write(vars, "fixed (byte* pb = Buffer)", "{", " $TypeName$* pbs = ($TypeName$*)pb;", " for(int i = 0; i < Count; i++)", " {", " output.WriteTag(tag);", " pbs[i].WriteTo(output);", " }", "}" ); } else if (field.FieldType == FieldType.Message) { fw.Write(vars, "fixed (byte* pb = Buffer)", "{", " $TypeName$* pbs = ($TypeName$*)pb;", " for(int i = 0; i < Count; i++)", " {", " output.WriteTag(tag);", " int datasize = pbs[i].CalculateSize();", " output.WriteLength(datasize);", " pbs[i].WriteTo(output);", " }", "}" ); } fw.Outdent(); fw.Write("}"); fw.Write(""); } //原生类型缺省packed,message,string类型需要按数量循环处理 //注意这里的struct的list读取之前需要先clear一下,原因是struct内存本身有可能是复用的,不clear的话会出错 private void WriteFun_ReadFrom(ProtoMessageField field, FileWriter fw) { fw.Write( "public void ReadFrom(CodedInputStream input, uint tag)", "{" ); fw.Indent(); if (field.FieldType == FieldType.Bool || field.FieldType == FieldType.Bytes || field.FieldType == FieldType.Enum || field.FieldType == FieldType.Int32 || field.FieldType == FieldType.UInt32 || field.FieldType == FieldType.Int64 || field.FieldType == FieldType.UInt64) { string input_readvalue = ""; if (field.FieldType == FieldType.Bool) { input_readvalue = "var value = input.ReadBool();"; } if (field.FieldType == FieldType.Bytes) { input_readvalue = "var value = input.ReadRawByte();"; } if (field.FieldType == FieldType.Enum) { input_readvalue = "var value = input.ReadEnum();"; } if (field.FieldType == FieldType.Int32) { input_readvalue = "var value = input.ReadInt32();"; } if (field.FieldType == FieldType.UInt32) { input_readvalue = "var value = input.ReadUInt32();"; } if (field.FieldType == FieldType.Int64) { input_readvalue = "var value = input.ReadInt64();"; } if (field.FieldType == FieldType.UInt64) { input_readvalue = "var value = input.ReadUInt64();"; } fw.Write(vars, "int length = input.ReadLength();", "if(length > 0)", "{", " int oldLimit = input.PushLimit(length);", " fixed (byte* pb = Buffer)", " {", " $TypeName$* pbs = ($TypeName$*)pb;", " while(!input.ReachedLimit)", " {", " " + input_readvalue, " if( Count < MaxCount)", " {", " pbs[Count++] = value;", " }", " else", " {", " throw InvalidProtocolBufferException.MoreDataAvailable();", " }", " }", " }", " input.PopLimit(oldLimit);", "}" ); } else if (field.FieldType == FieldType.Message) { fw.Write(vars, "fixed (byte* pb = Buffer)", "{", " $TypeName$* pbs = ($TypeName$*)pb;", " do", " {", " int length = input.ReadLength();", " int oldLimit = input.PushLimit(length);", " if( Count < MaxCount)", " {", " pbs[Count].Clear();", " pbs[Count].ReadFrom(input);", " Count++;", " }", " else", " {", " throw InvalidProtocolBufferException.MoreDataAvailable();", " }", " input.CheckReadEndOfStreamTag();", " if (!input.ReachedLimit)", " {", " throw InvalidProtocolBufferException.TruncatedMessage();", " }", " input.PopLimit(oldLimit);", " } while (input.MaybeConsumeTag(tag));", "}" ); } else if (field.FieldType == FieldType.String) { fw.Write(vars, "fixed (byte* pb = Buffer)", "{", " $TypeName$* pbs = ($TypeName$*)pb;", " do", " {", " if( Count < MaxCount)", " {", " pbs[Count++].ReadFrom(input);", " }", " else", " {", " throw InvalidProtocolBufferException.MoreDataAvailable();", " }", " } while (input.MaybeConsumeTag(tag));", "}" ); } fw.Outdent(); fw.Write("}"); fw.Write(""); } private void WriteFun_ToString(ProtoMessageField field, FileWriter fw) { fw.Write( "public override string ToString()", "{", " StringBuilder sb = new StringBuilder();" ); fw.Indent(); if (field.FieldType == FieldType.Int32 || field.FieldType == FieldType.UInt32 || field.FieldType == FieldType.Int64 || field.FieldType == FieldType.UInt64 || field.FieldType == FieldType.Bool || field.FieldType == FieldType.Enum || field.FieldType == FieldType.Bytes ) { fw.Write( "sb.Append('{');", "for (int i = 0; i < Count; i++)", "{", " sb.Append(Get(i).ToString());", " sb.Append(',');", "}", "sb.Append('}');" ); } else if (field.FieldType == FieldType.String) { fw.Write( "sb.Append('{');", "for (int i = 0; i < Count; i++)", "{", " sb.Append('\"');", " sb.Append(Get(i).ToString());", " sb.Append('\"');", " sb.Append(',');", "}", "sb.Append('}');" ); } else if (field.FieldType == FieldType.Message)// { fw.Write( "sb.Append(\"{\\n\");", "for (int i = 0; i < Count; i++)", "{", " sb.Append(\"" + "[\" + i.ToString() + \"]:\");", " sb.Append(Get(i).ToString());", "}", "sb.Append('}');" ); } fw.Write("return sb.ToString();"); fw.Outdent(); fw.Write("}"); fw.Write(""); } } }