You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

761 lines
26 KiB

using System;
using System.Collections.Generic;
namespace ProtoCSStruct
{
public class RepeatedStructWriter
{
Dictionary<string, string> vars = new Dictionary<string, string>();
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());
}
/// <summary>
///
/// </summary>
/// <param name="field"> repeated 字段描述</param>
/// <param name="fw"></param>
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("");
}
}
}