diff --git a/src/codegen.inc.php b/src/codegen.inc.php index 683f9bd..787eb2d 100644 --- a/src/codegen.inc.php +++ b/src/codegen.inc.php @@ -122,6 +122,12 @@ function _add_twig_support(\Twig\Environment $twig) return is_primary_field($o, $f); } )); + $twig->addFunction(new \Twig\TwigFunction('get_diff_class_units', + function($meta, $o) + { + return get_diff_class_units($meta, $o); + } + )); } function cs_type(\mtgType $type) @@ -434,3 +440,7 @@ function is_nullable_type(\mtgType $type) ($type instanceof \mtgMetaStruct && !$type->hasToken('POD')); } +function get_diff_class_units(\mtgMetaInfo $meta, \mtgMetaStruct $struct) +{ + return []; +} diff --git a/tpl/codegen_bundle.twig b/tpl/codegen_bundle.twig index 34082e4..4a4e8b8 100644 --- a/tpl/codegen_bundle.twig +++ b/tpl/codegen_bundle.twig @@ -4,9 +4,9 @@ using metagen; {%- import "macro.twig" as macro -%} -{#{% if namespace is defined ~%} +{% if namespace is defined ~%} namespace {{namespace}} { -{% endif %}#} +{% endif %} {{ macro.decl_units(meta) }} @@ -61,6 +61,6 @@ static public class AutogenBundle } } -{#{% if namespace is defined ~%} +{% if namespace is defined ~%} } //namespace {{namespace}} -{% endif %}#} +{% endif %} diff --git a/tpl/macro.twig b/tpl/macro.twig index 28febb4..a02256a 100644 --- a/tpl/macro.twig +++ b/tpl/macro.twig @@ -3,17 +3,17 @@ {%- for u in meta.getunits ~%} {%- if u.object is instanceof('\\mtgMetaStruct') -%} -{{ _self.decl_struct(u.object) }} +{{ _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(u.object) }} +{{ _self.decl_rpc(meta, u.object) }} {%- endif ~%} {%- endfor ~%} {% endmacro %} -{% macro decl_struct(o, extra = '') %} +{% 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 -%} @@ -100,6 +100,17 @@ public {{_self.struct_type(o)}} {{o.name}} {{_self.base_struct_class(o)}} {{_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}} } @@ -282,10 +293,10 @@ public enum {{o.name}} } {% endmacro %} -{% macro decl_rpc(o) %} +{% macro decl_rpc(meta, o) %} -{{_self.decl_struct(o.req)}} -{{_self.decl_struct(o.rsp)}} +{{_self.decl_struct(meta, o.req)}} +{{_self.decl_struct(meta, o.rsp)}} public class {{o.name}} : IRpc { @@ -320,3 +331,154 @@ public class {{o.name}} : IRpc } {% endmacro %} + +{%- macro diffable_support(meta, o) -%} + + {% for u in get_diff_class_units(meta, o) %} + {{_self.diff_methods(u)}} + {% endfor %} + + static public List GetClassRemovedIds(List 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(); + removed_ids.Add(res); + } + return res.ids; + } + + static bool FindClassRemovedIds(List removed_ids, uint class_id, out DataClassIds res) + { + for(int i=0;i items, List<{{u.name}}> old_items, List<{{u.name}}> changed, List 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 %}