protected override void GenerateClassReferenceField(messageType message, fieldType field) { var fieldType = FieldType(field); if (field.modifier == modifierType.repeated) { IncludeWriter.WriteLine( @" void add{1}({2}& item); void remove{1}({2}& item); std::vector<{2}*> {0}List(); {2}& get{1}(int index); int {0}Count() const; " , field.name, field.name.Capitalize(), fieldType); CppWriter.WriteLine( @" void Abstract{4}::add{1}({3}& item) {{ assert((""Can't modify an already built object!"", !isBuilt())); if (m_root != item.getRoot()) throw std::runtime_error(""All objects should share the same root""); m_header.add_{2}()->CopyFrom(item.getLocalMessageDescriptor()); }} void Abstract{4}::remove{1}({3}& item) {{ assert((""Can't modify an already built object!"", !isBuilt())); auto vals = m_header.mutable_{2}(); auto newEnd = std::remove_if(vals->begin(), vals->end(), [this, &item](const LocalMessageDescriptor& check) {{ return getRoot()->decode(check) == &item; }}); vals->DeleteSubrange(newEnd - vals->begin(), vals->end() - newEnd); }} std::vector<{3}*> Abstract{4}::{0}List() {{ auto count = {0}Count(); auto list = std::vector<{3}*>(); list.reserve(count); for (auto i = 0; i < count; ++i) {{ list.push_back(&get{1}(i)); }} return list; }} {3}& Abstract{4}::get{1}(int index) {{ return *dynamic_cast<{3}*>(getRoot()->decode(m_header.{2}(index))); }} int Abstract{4}::{0}Count() const {{ return m_header.{2}_size(); }} " , field.name, field.name.Capitalize(), field.name.ToLowerInvariant(), fieldType, message.name); return; } if (field.modifier == modifierType.optional) { IncludeWriter.WriteLine( @" bool has{0}() const {{ return m_header.has_{1}(); }} void clear{0}() {{ m_header.clear_{1}(); }} " , field.name.Capitalize(), field.name.ToLowerInvariant()); } IncludeWriter.WriteLine( @" void set{1}({2}& value); {2}* {0}(); " , field.name, field.name.Capitalize(), fieldType); CppWriter.WriteLine( @" void Abstract{4}::set{1}({3}& value) {{ if (m_root != value.getRoot()) throw std::runtime_error(""All objects should share the same root""); m_header.clear_{2}(); m_header.mutable_{2}()->CopyFrom(value.getLocalMessageDescriptor()); // TODO see if that works // m_header.set_allocated_{2}(value.getLocalMessageDescriptor()); }} {3}* Abstract{4}::{0}() {{ return dynamic_cast<{3}*>(getRoot()->decode(m_header.{2}())); }} " , field.name, field.name.Capitalize(), field.name.ToLowerInvariant(), fieldType, message.name); }
protected override void GenerateClassNestedField(messageType message, fieldType field) { var fieldType = FieldType(field); if (field.modifier == modifierType.repeated) { IncludeWriter.WriteLine( @" {2}& add{1}(); std::vector<{2}*> {0}List(); {2}& get{1}(int index); int {0}Count() const; " , field.name, field.name.Capitalize(), fieldType); CppWriter.WriteLine( @" {3}& Abstract{4}::add{1}() {{ assert((""Can't modify an already built object!"", !isBuilt())); auto index = m_{0}List.size(); auto {0} = std::make_unique<{3}>(); {0}->setFieldId({5}); {0}->setIndex(index); {0}->setParent(this); m_{0}List.set(index, std::move({0})); return *m_{0}List.get(index); }} std::vector<{3}*> Abstract{4}::{0}List() {{ auto count = {0}Count(); auto list = std::vector<{3}*>(); list.reserve(count); for (auto i = 0; i < count; ++i) {{ list.push_back(&get{1}(i)); }} return list; }} {3}& Abstract{4}::get{1}(int index) {{ if (!m_{0}List.get(index)) {{ auto {0} = {3}::ParseFrom(contentStream(), m_header.{2}(index)); {0}->setFieldId({5}); {0}->setIndex(index); {0}->setParent(this); m_{0}List.set(index, std::move({0})); }} return *m_{0}List.get(index); }} int Abstract{4}::{0}Count() const {{ return !isBuilt() ? m_{0}List.size() : m_header.{2}_size(); }}" , field.name, field.name.Capitalize(), field.name.ToLowerInvariant(), fieldType, message.name, field.id); return; } if (field.modifier == modifierType.optional) { IncludeWriter.WriteLine( @" {2}& add{1}(); // adds the optional {1} {2}* {0}(); bool has{1}() const; void clear{1}(); " , field.name, field.name.Capitalize(), fieldType); CppWriter.WriteLine( @" {3}& Abstract{4}::add{1}() {{ if (m_{0} == nullptr) {{ if (isBuilt() && has{1}()) {{ {0}(); // decode from body }} else {{ assert((""Can't modify an already built object!"", !isBuilt())); m_{0} = std::make_unique<{6}::{3}>(); m_{0}->setFieldId({5}); m_{0}->setParent(this); }} }} return *m_{0}; }} {3}* Abstract{4}::{0}() {{ if (isBuilt() && has{1}() && m_{0} == nullptr) {{ m_{0} = {3}::ParseFrom(contentStream(), m_header.{2}()); m_{0}->setFieldId({5}); m_{0}->setParent(this); }} return m_{0}.get(); }} bool Abstract{4}::has{1}() const {{ return (isBuilt() && m_header.has_{2}()) || (!isBuilt() && m_{0} != nullptr); }} void Abstract{4}::clear{1}() {{ assert((""Can't modify an already built object!"", !isBuilt())); m_{0}.reset(); }} " , field.name, field.name.Capitalize(), field.name.ToLowerInvariant(), fieldType, message.name, field.id, Namespace); return; } IncludeWriter.WriteLine(@" {1}& {0}();", field.name, fieldType); CppWriter.WriteLine( @" {2}& Abstract{3}::{0}() {{ if (m_{0} == nullptr) {{ if (isBuilt()) {{ m_{0} = {2}::ParseFrom(contentStream(), m_header.{1}()); }} else {{ m_{0} = std::make_unique<{2}>(); }} m_{0}->setFieldId({4}); m_{0}->setParent(this); }} return *m_{0}; }} " , field.name, field.name.ToLowerInvariant(), fieldType, message.name, field.id); }
protected override void GenerateClassSimpleField(messageType message, fieldType field) { var fieldTypeForList = FieldType(field); var fieldType = fieldTypeForList; if (field.type == typeType.@string) { fieldType = "const " + fieldType + "&"; } // In C++, a repeated enum is stored as a RepeatedField<int> var underlyingType = field.type == typeType.@enum ? "int" : fieldTypeForList; if (field.modifier == modifierType.repeated) { IncludeWriter.WriteLine( @" void add{1}({2} item); void remove{1}({2} item); std::vector<{3}> {0}List(); {2} get{1}(int index); int {0}Count() const; " , field.name, field.name.Capitalize(), fieldType, fieldTypeForList); CppWriter.WriteLine( @" void Abstract{4}::add{1}({3} item) {{ assert((""Can't modify an already built object!"", !isBuilt())); m_header.add_{2}(item); }} void Abstract{4}::remove{1}({3} item) {{ assert((""Can't modify an already built object!"", !isBuilt())); auto vals = m_header.mutable_{2}(); auto newEnd = std::remove_if(vals->begin(), vals->end(), [&item]({6} check) {{ return check != item; }}); vals->Truncate(newEnd - vals->begin()); }} std::vector<{5}> Abstract{4}::{0}List() {{ auto count = {0}Count(); auto list = std::vector<{3}>(); list.reserve(count); for (auto i = 0; i < count; ++i) {{ list.push_back(get{1}(i)); }} return list; }} {3} Abstract{4}::get{1}(int index) {{ return m_header.{2}(index); }} int Abstract{4}::{0}Count() const {{ return m_header.{2}_size(); }} " , field.name, field.name.Capitalize(), field.name.ToLowerInvariant(), fieldType, message.name, fieldTypeForList, underlyingType); return; } if (field.modifier == modifierType.optional) { IncludeWriter.WriteLine( @" bool has{0}() const {{ return m_header.has_{1}(); }} void clear{0}() {{ m_header.clear_{1}(); }} " , field.name.Capitalize(), field.name.ToLowerInvariant()); } IncludeWriter.WriteLine( @" {3} {0}() const {{ return m_header.{2}(); }} void set{1}({3} value) {{ m_header.set_{2}(value); }} " , field.name, field.name.Capitalize(), field.name.ToLowerInvariant(), fieldType); }
protected override void GenerateClassFields(messageType message) { if (!message.IsRoot) { IncludeWriter.WriteLine( @" private: ProtoOrBuilder* m_root; ProtoOrBuilder* m_parent; int m_fieldId = -1; // field's ID as defined in the protozbuf.xml file (=> the .proto file) int m_index = -1; // instance's index in the parent's list public: ProtoOrBuilder* getParent() { return m_parent; } void setParent(ProtoOrBuilder* parent); int fieldId() const { return m_fieldId; } void setFieldId(int fieldId) { m_fieldId = fieldId; } int index() const { return m_index; } void setIndex(int index) { m_index = index; } "); CppWriter.WriteLine( @" void Abstract{0}::setParent(ProtoOrBuilder* parent) {{ m_parent = parent; m_root = parent->getRoot(); }}", message.name); } else { IncludeWriter.WriteLine( @" protected: std::shared_ptr<std::iostream> m_contentStream;"); } IncludeWriter.WriteLine( @" protected: {0}Header m_header; long m_positionInContent; public: int positionInContent() const {{ return m_positionInContent; }} void setPositionInContent(int positionInContent) {{ m_positionInContent = positionInContent; }} protected: " , message.name); var allFields = message.field.OrderBy(_ => _.id); var messageFields = from fld in allFields where fld.messageType != null && fld.type != typeType.referenceMessage select fld; foreach (var field in messageFields) { var fieldtype = FieldType(field); switch (field.modifier) { case modifierType.repeated: IncludeWriter.WriteLine( @" {2}::ArrayList<{0}> m_{1}List;", fieldtype, field.name, ResourceNamespace); break; default: IncludeWriter.WriteLine( @" std::unique_ptr<{0}> m_{1};", fieldtype, field.name); break; } } }
protected override void EndAbstractClass(messageType message) { IncludeWriter.WriteLine( @" }; "); }
internal override void GenerateToStringFormatters() { IncludeWriter.WriteLine( @" class BaseFormat { public: int m_indentation; int getIndentation() const { return m_indentation; } void setIndentation(int indentation) { m_indentation = indentation; } std::string getTabulations() const { return std::string(m_indentation, '\t'); } void formatHeader(std::ostringstream& builder, const std::string& title) { builder << getTabulations() << title << std::endl; builder << getTabulations() << ""{"" << std::endl; m_indentation++; } void formatFooter(std::ostringstream& builder) { m_indentation--; builder << getTabulations() << ""}"" << std::endl; } template<typename T> void formatField(std::ostringstream& builder, const std::string& name, T&& obj, bool has = true) { if (!has) return; builder << getTabulations() << name << "": ""; if (has) builder << obj; else builder << ""not set""; builder << std::endl; } void formatProtoField(std::ostringstream& builder, const std::string& name, ProtoOrBuilder& obj, bool has = true) { if (!has) return; formatHeader(builder, name); builder << (has ? obj.toString(*this) : getTabulations() + ""null"") << std::endl; formatFooter(builder); } void formatProtoField(std::ostringstream& builder, const std::string& name, ProtoOrBuilder* obj, bool has = true) { if (!has || obj == nullptr) return; formatProtoField(builder, name, * obj, has && obj != nullptr); } template<typename T> void formatListField(std::ostringstream& builder, const std::string& name, const std::vector<T>& objs) { if (objs.empty()) return; builder << getTabulations() << name << "": ""; std::copy(objs.begin(), objs.end(), std::ostream_iterator<T>(builder, "", "")); builder << std::endl; } template<typename T> void formatProtoField(std::ostringstream& builder, const std::string& name, const std::vector<T*>& objs) { if (objs.empty()) return; builder << getTabulations() << name << "": "" << std::endl; for (auto* obj : objs) { builder << obj->toString(*this); } builder << std::endl; } }; "); }
protected override void GenerateToString(messageType message) { IncludeWriter.WriteLine( @" using ProtoOrBuilder::toString; std::string toString(BaseFormat& format) override; "); CppWriter.WriteLine( @" std::string Abstract{0}::toString(BaseFormat& format) {{ auto bd = std::ostringstream(); ", message.name); CppWriter.WriteLine( @" format.formatHeader(bd,""{0}""); ", message.name); var fields = message.field.OrderBy(_ => _.id); foreach (var field in fields) { switch (field.modifier) { case modifierType.repeated: if (field.type == typeType.referenceMessage) { CppWriter.WriteLine( @" format.formatField(bd, ""{1}List"", {0}Count()); ", field.name, field.name.Capitalize()); } else if (field.type == typeType.nestedMessage) { CppWriter.WriteLine( @" format.formatProtoField(bd, ""{1}List"", {0}List()); ", field.name, field.name.Capitalize()); } else { CppWriter.WriteLine( @" format.formatListField(bd, ""{1}List"", {0}List()); ", field.name, field.name.Capitalize()); } break; case modifierType.optional: if (field.type == typeType.referenceMessage || field.type == typeType.nestedMessage) { CppWriter.WriteLine( @" format.formatProtoField(bd, ""{1}"", {0}(), has{1}()); ", field.name, field.name.Capitalize()); } else { CppWriter.WriteLine( @" format.formatField(bd, ""{1}"", {0}(), has{1}()); ", field.name, field.name.Capitalize()); } break; default: if (field.type == typeType.referenceMessage || field.type == typeType.nestedMessage) { CppWriter.WriteLine( @" format.formatProtoField(bd, ""{0}"", {0}());", field.name); } else { CppWriter.WriteLine( @" format.formatField(bd, ""{0}"", {0}());", field.name); } break; } } CppWriter.WriteLine( @" format.formatFooter(bd); return bd.str(); } "); }