metagen_cs/tpl/macro.twig

485 lines
11 KiB
Twig

{% macro decl_units(meta) %}
{%- for u in meta.getunits ~%}
{%- if u.object is instanceof('\\mtgMetaStruct') -%}
{{ _self.decl_struct(meta, u.object) }}
{%- elseif u.object is instanceof('\\mtgMetaEnum') -%}
{{ _self.decl_enum(u.object) }}
{%- elseif u.object is instanceof('\\mtgMetaRPC') -%}
{{ _self.decl_rpc(meta, u.object) }}
{%- endif ~%}
{%- endfor ~%}
{% endmacro %}
{% macro decl_struct(meta, o, extra = '') %}
{%- if o.parent and has_token(o, 'POD') -%}
{{Error("@POD structs can't have a parent: " ~ o.name)}}
{%- endif -%}
{%- if o.parent and has_token(o, 'bitfields') -%}
{{Error("@bitfields structs can't have a parent: " ~ o.name)}}
{%- endif -%}
{{_self.attributes(o)}}
public {{_self.struct_type(o)}} {{o.name}} {{_self.base_struct_class(o)}}
{
{{_self.decl_struct_fields(o)}}
public {{o.parent ? 'new'}} const uint STATIC_CLASS_ID = {{o.classid}};
public {{_self.override(o)}} uint CLASS_ID()
{
return {{o.classid}};
}
{{_self.comment_POD_begin(o)}}
public {{o.name}}()
{
reset();
}
{{_self.comment_POD_end(o)}}
public {{_self.override(o)}} void reset()
{
{{_self.struct_fields_reset(o)}}
}
{{_self.comment_non_cloneable_begin(o)}}
public {{_self.virtual_clone(o)}} void copy(IMetaStruct other)
{
copyFrom(({{o.name}})other);
}
public void copyFrom({{o.name}} other)
{
var ctx = Meta.PrepareForClone(ref other);
ctx.factory = AutogenBundle.createById;
ctx.reader.BeginContainer();
reset();
syncFields(ctx);
ctx.reader.EndContainer();
{%- if has_token(o, 'bitfields') ~%}
fields_mask = other.fields_mask;
{%- endif ~%}
}
public {{_self.virtual_clone(o)}} IMetaStruct clone()
{
var copy = new {{o.name}}();
copy.copy(this);
return copy;
}
{{_self.comment_non_cloneable_end(o)}}
public {{_self.override(o)}} void syncFields(MetaSyncContext ctx)
{
{{_self.sync_fields(o)}}
}
public {{_self.override(o)}} int getFieldsCount()
{
return {{fields_count(o)}};
}
public {{_self.override(o)}} int getWritableFieldsCount()
{
{%~ if has_token(o, 'bitfields') ~%}
return Meta.GetDirtyFieldsCount(fields_mask, fields_count: {{fields_count(o)}})
+ Meta.MASK_HEADER_FIELDS_COUNT;
{% else %}
return {{fields_count(o)}};
{%- endif ~%}
}
{%- if has_token(o, 'bitfields') ~%}
{{_self.bitmask_helpers(o)}}
{%- endif -%}
{%- if has_token(o, 'bhl_bind') ~%}
{{_self.get_itype(o)}}
{%- endif -%}
{%- if has_token(o, 'id') ~%}
public ulong getPrimaryId()
{
return (ulong){{token(o, 'id')}};
}
{%- endif -%}
{%- if has_token(o, 'diffable') ~%}
{{_self.diffable_support(meta, o)}}
{%- endif -%}
{{extra}}
}
{% endmacro %}
{%- macro decl_struct_fields(o) -%}
{%- if has_token(o, 'bitfields') ~%}
public long fields_mask;
{%- endif -%}
{%- for f in o.fields ~%}
{{_self.decl_struct_field(o, f)}}
{%- endfor -%}
{%- endmacro -%}
{%- macro decl_struct_field(o, f) -%}
{{_self.attributes(f)}}
public {{f.type|cs_type}} {{f.name}} {% if not has_token(o, 'POD') -%} {{_self.decl_init_value(f.type)}} {%- endif -%};
{%- endmacro -%}
{% macro decl_init_value(type) %}
{%- if type is instanceof('\\mtgBuiltinType') -%}
{%- if type.isstring -%} = ""{%- endif -%}
{%- else -%}
= new {{type|cs_type}}()
{%- endif -%}
{% endmacro %}
{% macro struct_fields_reset(o) %}
{%- if o.parent ~%}
base.reset();
{%- endif -%}
{%- for f in o.fields ~%}
{{var_reset(f.name, f.type, token_or(f, 'default', null))}}
{%- endfor -%}
{%- if has_token(o, 'bitfields') ~%}
fields_mask = 0L;
{%- endif -%}
{% endmacro %}
{%- macro attributes(o) %}
{%- if has_token(o, 'cs_attributes') -%}
{%- for attr in token(o, 'cs_attributes')|split(',') -%}
[{{attr}}]
{%- endfor -%}
{%- endif -%}
{%- endmacro %}
{%- macro struct_type(o) -%}
{{has_token(o, 'POD') ? 'struct' : 'class'}}
{%- endmacro -%}
{%- macro base_struct_class(o) -%}
{%- if has_token(o, 'POD') -%}
: IMetaStruct
{%- else -%}
: {{o.parent ? o.parent.name : 'BaseMetaStruct'}}
{{- has_token(o, 'cloneable') and not o.parent ? ', IMetaCloneable' -}}
{{- has_token(o, 'bhl_bind') and not o.parent ? ', bhl.ITyped' -}}
{%- endif -%}
{%- endmacro -%}
{%- macro override(o) -%}
{%- if not has_token(o, 'POD') -%}
override
{%- endif -%}
{%- endmacro -%}
{%- macro virtual(o) -%}
{%- if not has_token(o, 'POD') -%}
{{o.parent ? 'override' : 'virtual'}}
{%- endif -%}
{%- endmacro -%}
{%- macro comment_POD_begin(o) -%}
{%- if has_token(o, 'POD') -%}
/* commented in POD
{%- endif -%}
{%- endmacro -%}
{%- macro comment_POD_end(o) -%}
{%- if has_token(o, 'POD') -%}
*/
{%- endif -%}
{%- endmacro -%}
{%- macro comment_non_cloneable_begin(o) -%}
{%- if not has_token(o, 'cloneable') -%}
/* commented in non-cloneable
{%- endif -%}
{%- endmacro -%}
{%- macro comment_non_cloneable_end(o) -%}
{%- if not has_token(o, 'cloneable') -%}
*/
{%- endif -%}
{%- endmacro -%}
{%- macro virtual_clone(o) -%}
{%- if has_token(o, 'cloneable') -%}
{%- if has_token(o, 'POD') -%}
{%- elseif o.parent and has_token_in_parent(o.parent, 'cloneable') -%}
override
{%- else -%}
virtual
{%- endif -%}
{%- endif -%}
{%- endmacro -%}
{%- macro sync_fields(o) -%}
{%- if has_token(o, 'bitfields') ~%}
var bitctx = new Meta.BitfieldsContext(ctx, fields_mask);
bitctx.SyncMaskHeader();
{%- endif -%}
{%- if o.parent ~%}
base.syncFields(ctx);
{%- endif -%}
{%- for f in o.fields ~%}
{{var_sync(f.name, f.type, 'ctx', f.tokens, get_sync_opts(o, 'bitctx'))}}
{%- endfor -%}
{%- endmacro -%}
{%- macro bitmask_helpers(o) ~%}
public void ResetFieldMask()
{
fields_mask = 0L;
}
public void SetPrimaryFieldsChanged()
{
{%- for f in o.fields ~%}
{%- if is_primary_field(o, f) ~%}
Meta.SetFieldDirty(ref fields_mask, {{loop.index0}});
{%- endif -%}
{%- endfor ~%}
}
public void SetDirtyMask()
{
fields_mask = ~0L;
}
public void SetDirtyMaskDeep()
{
SetDirtyMask();
{%- for f in o.fields ~%}
{%- if f.type is instanceof('\\mtgMetaStruct') and has_token(f.type, 'bitfields') ~%}
{{f.name}}.SetDirtyMaskDeep();
{%- elseif f.type is instanceof('\\mtgArrType') and f.type.value is instanceof('\\mtgMetaStruct') and has_token(f.type.value, "bitfields") ~%}
{
for(int i=0;i<{{f.name}}.Count;++i)
{
var __tmp = {{f.name}}[i];
__tmp.SetDirtyMaskDeep();
{{f.name}}[i] = __tmp;
}
}
{%- endif -%}
{%- endfor ~%}
}
{%- endmacro -%}
{% macro get_itype(o) %}
public {{_self.virtual(o)}} bhl.IType GetIType()
{
return bhl.BHL_Types.Type_{{o.name}};
}
{%- endmacro -%}
{% macro decl_enum(o) %}
{{_self.attributes(o)}}
public enum {{o.name}}
{
{%- for n,v in o.values ~%}
{{n}} = {{v}},
{%- endfor ~%}
}
{% endmacro %}
{% macro decl_rpc(meta, o) %}
{{_self.decl_struct(meta, o.req)}}
{{_self.decl_struct(meta, o.rsp)}}
public class {{o.name}} : IRpc
{
public IRpcError error = null;
public {{o.req.name}} req = new {{o.req.name}}();
public {{o.rsp.name}} rsp = new {{o.rsp.name}}();
public int getCode()
{
return {{o.code}};
}
public void setError(IRpcError error)
{
this.error = error;
}
public IRpcError getError()
{
return error;
}
public IMetaStruct getRequest()
{
return req as IMetaStruct;
}
public IMetaStruct getResponse()
{
return rsp as IMetaStruct;
}
}
{% endmacro %}
{%- macro diffable_support(meta, o) -%}
{% for u in get_diff_class_units(meta, o) %}
{{_self.diff_methods(u)}}
{% endfor %}
static public List<ulong> GetClassRemovedIds(List<DataClassIds> removed_ids, uint class_id)
{
if(removed_ids == null)
return null;
DataClassIds res;
if(!FindClassRemovedIds(removed_ids, class_id, out res))
{
res = new DataClassIds();
res.class_id = class_id;
res.ids = new List<ulong>();
removed_ids.Add(res);
}
return res.ids;
}
static bool FindClassRemovedIds(List<DataClassIds> removed_ids, uint class_id, out DataClassIds res)
{
for(int i=0;i<removed_ids.Count;++i)
{
if(removed_ids[i].class_id == class_id)
{
res = removed_ids[i];
return true;
}
}
res = default(DataClassIds);
return false;
}
{% endmacro %}
{%- macro diff_methods(u) -%}
static public bool DiffOne(ref {{u.name}} curr, {{u.name}} old)
{
return !{{_self.compare_func_name(u)}}(ref curr, old);
}
static public bool DiffCollection(List<{{u.name}}> items, List<{{u.name}}> old_items, List<{{u.name}}> changed, List<DataClassIds> removed)
{
bool has_diff = false;
if(changed != null)
changed.Clear();
SortByPrimaryId(ref items);
SortByPrimaryId(ref old_items);
int i = 0;
int old_i = 0;
for(; i < items.Count && old_i < old_items.Count;)
{
var old = old_items[old_i];
var item = items[i];
if(old.getPrimaryId() < item.getPrimaryId())
{
var removed_ids = GetClassRemovedIds(removed, {{u.name}}.STATIC_CLASS_ID);
if(removed_ids != null)
removed_ids.Add(old.getPrimaryId());
old_i++;
has_diff = true;
}
else if(old.getPrimaryId() > item.getPrimaryId())
{
item.SetDirtyMask();
if(changed != null)
changed.Add(item);
i++;
has_diff = true;
}
else
{
if(!{{_self.compare_func_name(u)}}(ref item, old))
{
if(changed != null)
changed.Add(item);
has_diff = true;
}
i++;
old_i++;
}
}
//items leftovers are considered changed
for(; i < items.Count; i++)
{
var item = items[i];
item.SetDirtyMask();
if(changed != null)
changed.Add(item);
has_diff = true;
}
//old items leftovers are considered removed
for(; old_i < old_items.Count; old_i++)
{
var removed_ids = GetClassRemovedIds(removed, {{u.name}}.STATIC_CLASS_ID);
if(removed_ids != null)
removed_ids.Add(old_items[old_i].getPrimaryId());
has_diff = true;
}
//if(changed.Count > 0)
// Meta.LogDebug("Changed in collection {{u.name}}");
//if(removed_ids.Count > 0)
// Meta.LogDebug("Removed in collection {{u.name}}");
return has_diff;
}
class {{u.name}}Compare : IComparer<{{u.name}}>
{
public int Compare({{u.name}} o1, {{u.name}} o2)
{
var id1 = o1.getPrimaryId();
var id2 = o2.getPrimaryId();
if(id1 == id2)
return 0;
return id1 > id2 ? 1 : -1;
}
}
static {{u.name}}Compare {{u.name}}_compare = new {{u.name}}Compare();
static void SortByPrimaryId(ref List<{{u.name}}> list)
{
list.Sort({{u.name}}_compare);
}
public static bool {{_self.compare_func_name(u)}}(ref {{u.name}} a, {{u.name}} b)
{
bool is_equal = true;
$compare_fn_str
return is_equal;
}
{% endmacro %}
{% macro compare_func_name(o) %}
{{has_token(u, 'bitfields')?'CompareAndMarkFields':'IsEqual'}}
{% endmacro %}