protected override void GenerateFlush(messageType message)
        {
            IncludeWriter.WriteLine(@"        void flush();");
            CppWriter.WriteLine(
                @"
        void Abstract{0}::flush()
        {{", message.name.Capitalize());

            var allFields = message.field.OrderBy(_ => _.id);

            var messageFields = from fld in allFields
                                where fld.messageType != null &&
                                fld.type == typeType.nestedMessage
                                select fld;

            var has = false;

            foreach (var field in messageFields)
            {
                has = true;
                CppWriter.WriteLine(
                    field.modifier == modifierType.repeated
                        ? @"            m_{0}List.clear();"
                        : @"            m_{0}.reset();", field.name);
            }

            if (!has)
            {
                CppWriter.WriteLine(@"            // NOP");
            }

            CppWriter.WriteLine(@"        }");
            CppWriter.WriteLine();
        }
        internal override void GenerateFinalClientClasses(protozbuffType node)
        {
            // close file .lazy.h
            IncludeWriter.WriteLine(GetNamespaceEnd(GeneratedNamespace));
            IncludeWriter.Dispose();
            IncludeWriter = null;

            // close file .lazy.cpp
            CppWriter.WriteLine(GetNamespaceEnd(GeneratedNamespace));
            CppWriter.Dispose();
            CppWriter = null;

            base.GenerateFinalClientClasses(node);
        }
        protected override void GenerateSerialization(messageType message)
        {
            if (message.IsRoot)
            {
                IncludeWriter.WriteLine(
                    @"        static std::unique_ptr<{0}> ParseFrom(std::shared_ptr<std::iostream> s);
"
                    , message.name);

                CppWriter.WriteLine(
                    @"        std::unique_ptr<{0}> Abstract{0}::ParseFrom(std::shared_ptr<std::iostream> s)
        {{
            {0}Header header;
            auto success = Util::readDelimited(*s, header, true); // the root is always at the end of the stream
            assert((""Can't decode header!"", success));
            
            auto parsed = std::make_unique<{0}>(header, (long)s->tellg());
            parsed->setContentStream(s);
            return parsed;
        }}
"
                    , message.name);
                return;
            }

            IncludeWriter.WriteLine(
                @"        static std::unique_ptr<{0}> ParseFrom(std::iostream& s, int pos);
"
                , message.name);

            CppWriter.WriteLine(
                @"        std::unique_ptr<{0}> Abstract{0}::ParseFrom(std::iostream& s, int pos)
        {{
            s.seekg(pos, std::ios::beg);

            {0}Header header;
            auto success = Util::readDelimited(s, header);
            assert((""Can't decode header!"", success));

            auto parsed = std::make_unique<{0}>(header, pos);
            return parsed;
        }}
"
                , message.name);
        }
        protected override bool GenerateLazyImplementation(protozbuffType p)
        {
            var baseName = DocumentName + ".lazy";

            IncludeWriter = GetStream(IncludesFolder, baseName + ".h", GeneratedNamespace);
            CppWriter     = GetStream(CppFolder, baseName + ".cpp", GeneratedNamespace);

            WriteAutoGenerationWarning(IncludeWriter);
            WriteAutoGenerationWarning(CppWriter);

            IncludeWriter.WriteLine(@"
#pragma once
#include <memory>
#include <sstream>
#include <string>
#include ""{1}.pb.h""
#include ""{0}/ArrayList.h""
", GetNamespacePathSlash(ResourceNamespace), DocumentName);

            // forward declaration for final client classes
            IncludeWriter.WriteLine(GetNamespaceBegin(Namespace));
            foreach (var message in p.Items.OfType <messageType>())
            {
                IncludeWriter.WriteLine(@"class {0};", message.name.Capitalize());
            }
            IncludeWriter.WriteLine(GetNamespaceEnd(Namespace));
            IncludeWriter.WriteLine();
            IncludeWriter.WriteLine(GetNamespaceBegin(GeneratedNamespace));

            CppWriter.WriteLine(@"#include ""stdafx.h""");
            CppWriter.WriteLine("#include <sstream>");
            CppWriter.WriteLine("#include <{0}/{1}.h>", GetNamespacePathSlash(GeneratedNamespace), baseName);
            CppWriter.WriteLine("#include <{0}/Util.inc>", GetNamespacePathSlash(ResourceNamespace));
            foreach (var message in p.Items.OfType <messageType>())
            {
                CppWriter.WriteLine(@"#include <{0}/{1}.h>", GetNamespacePathSlash(Namespace), message.name.Capitalize());
            }

            CppWriter.WriteLine(@"using namespace {0};", ResourceNamespace);
            CppWriter.WriteLine(GetNamespaceBegin(GeneratedNamespace));

            return(base.GenerateLazyImplementation(p));
        }
        internal override void GenerateProtoOrBuilderInterface()
        {
            IncludeWriter.WriteLine(
                @"    typedef ::google::protobuf::RepeatedField< ::google::protobuf::int32 > CoordinateList;
    class BaseFormat; 
    class ProtoOrBuilder
    {
    public:
        virtual ProtoOrBuilder* getRoot() = 0;
        virtual void addCoordinates(CoordinateList& coordinates) = 0;
        virtual LocalMessageDescriptor getLocalMessageDescriptor() = 0;
        virtual ProtoOrBuilder* decode(const CoordinateList& coordinates, int index) = 0;
        virtual ProtoOrBuilder* decode(const LocalMessageDescriptor& field) = 0;
        virtual std::iostream& contentStream() = 0;
        virtual std::string toString();
        virtual std::string toString(BaseFormat& format) = 0;
        virtual ~ProtoOrBuilder();
    };

    std::ostream& operator<<(std::ostream& out, ProtoOrBuilder& proto);
");

            CppWriter.WriteLine(
                @"        std::string ProtoOrBuilder::toString()
        {
            auto format = BaseFormat();
            return toString(format);
        }
        
        ProtoOrBuilder::~ProtoOrBuilder()
        {
        }

        std::ostream& operator<<(std::ostream& out, ProtoOrBuilder& proto)
        {
            out << proto.toString();
            return out;
        }
");
        }
        protected override void GenerateClassConstructor(messageType message)
        {
            IncludeWriter.WriteLine(
                @"    protected: 
        Abstract{0}();
        Abstract{0}(const {0}Header& header, int posInContent);

        Abstract{0}(const Abstract{0}&) = delete;
        Abstract{0}& operator=(const Abstract{0}&) = delete;
", message.name);

            CppWriter.WriteLine(
                @"        
        Abstract{0}::Abstract{0}() : {1} m_positionInContent(-1)
        {{
        }}        

        Abstract{0}::Abstract{0}(const {0}Header& header, int pos) : {1} m_header(header), m_positionInContent(pos)
        {{
        }}

        ", message.name, message.IsRoot ? "" : "m_parent(nullptr), m_root(nullptr),");
        }
        protected override void GenerateBuild(messageType message)
        {
            IncludeWriter.WriteLine(
                @"        virtual void preBuild() {} // use this method to customize the build process
        std::iostream& contentStream() override;
        void build();
        void build(std::ostream& output, bool saveToOutput);
");

            if (!message.IsRoot)
            {
                CppWriter.WriteLine(
                    @"        
        std::iostream& Abstract{0}::contentStream() 
        {{
            return getRoot()->contentStream();
        }}", message.name);
            }
            else
            {
                IncludeWriter.WriteLine(@"        void setContentStream(std::shared_ptr<std::iostream> contentStream);");
                CppWriter.WriteLine(
                    @"
        std::iostream& Abstract{0}::contentStream() 
        {{
            if (m_contentStream == nullptr)
                m_contentStream.reset(new std::stringstream());
            return *m_contentStream;
        }}

        void Abstract{0}::setContentStream(std::shared_ptr<std::iostream> contentStream)
        {{
            assert(m_contentStream == nullptr);
            m_contentStream = contentStream;
        }}
", message.name);
            }

            CppWriter.WriteLine(
                @"
        void Abstract{0}::build()
        {{
            build(contentStream(), false);
        }}

        void Abstract{0}::build(std::ostream& content, bool saveToOutput)
        {{
            auto alreadyBuilt = isBuilt();
            if (alreadyBuilt && !saveToOutput)
                return;

            // prebuild hook
            preBuild();

            std::unique_ptr<{0}Header> headerCopy;
            auto* builder = &m_header;
            if (alreadyBuilt)
            {{
                headerCopy = std::make_unique<{0}Header>(m_header);
                builder = headerCopy.get();
            }}
            ", message.name);

            foreach (var field in message.field.Where(_ => _.type == typeType.nestedMessage))
            {
                CppWriter.WriteLine(@"            builder->clear_{0}();", field.name.ToLowerInvariant());
            }

            foreach (var index in message.index)
            {
                CppWriter.WriteLine(@"            builder->clear_{0}();", index.name.ToLowerInvariant());
            }

            CppWriter.WriteLine(
                @"
            // build all nested messages to have their position in the content stream");

            // do nothing for reference messages and pod types: the builder is already the owner of those fields

            foreach (var field in message.field.Where(_ => _.type == typeType.nestedMessage))
            {
                if (field.modifier == modifierType.repeated)
                {
                    CppWriter.WriteLine(
                        @"            auto tmp_{0}List = {0}List();
            for (auto* {0} : tmp_{0}List)
            {{
                auto oldPos = {0}->positionInContent();
                {0}->build(content, saveToOutput);
                builder->add_{1}({0}->positionInContent());
                if (alreadyBuilt || saveToOutput)
                    {0}->setPositionInContent(oldPos);
            }}"
                        , field.name, field.name.ToLowerInvariant());
                }
                else if (field.modifier == modifierType.optional)
                {
                    CppWriter.WriteLine(
                        @"
            auto* tmp_{0} = {0}();
            if (tmp_{0} != nullptr) 
            {{ 
                auto oldPos = tmp_{0}->positionInContent();
                tmp_{0}->build(content, saveToOutput); 
                builder->set_{1}(tmp_{0}->positionInContent());
                if (alreadyBuilt)
                    tmp_{0}->setPositionInContent(oldPos);
            }}"
                        , field.name, field.name.ToLowerInvariant());
                }
                else
                {
                    CppWriter.WriteLine(
                        @"
            auto* tmp_{0} = &{0}();
            if (tmp_{0} != nullptr) 
            {{ 
                auto oldPos = tmp_{0}->positionInContent();
                tmp_{0}->build(content, saveToOutput); 
                builder->set_{1}(tmp_{0}->positionInContent());
                if (alreadyBuilt)
                    tmp_{0}->setPositionInContent(oldPos);
            }}"
                        , field.name, field.name.ToLowerInvariant());
                }
            }

            // create indexes
            foreach (var index in message.index)
            {
                CppWriter.WriteLine(
                    @"
            std::sort(tmp_{0}List.begin(), tmp_{0}List.end(), []({1}* left, {1}* right) {{ return left->{2}() < right->{2}(); }});
            for (auto* {0} : tmp_{0}List)
            {{
                builder->add_{3}()->CopyFrom({0}->getLocalMessageDescriptor());
            }}
", index.ReferenceField.name, index.ReferenceField.messageType, index.SortingField.name, index.name.ToLowerInvariant());
            }

            CppWriter.WriteLine(
                @"
            // write the header
            content.seekp(0, std::ios::end);

            // if we write to output, the position in the content stream
            // will be restored when writing the parent header
            // => this is not possible (and not needed) for root message
            auto isRoot = {1};
            auto dontSavePos = saveToOutput && isRoot;
            if (!dontSavePos)
                setPositionInContent((long)content.tellp());

            {0}::Util::writeDelimited(*builder, content, isRoot);

            if ((!alreadyBuilt && !saveToOutput) || (alreadyBuilt && saveToOutput))
            {{
                flush();
            }}
        }}
", ResourceNamespace, message.IsRoot ? "true" : "false");

            if (!message.IsRoot)
            {
                return;
            }

            IncludeWriter.WriteLine(@"        void writeDelimitedTo(std::ostream& output);");

            CppWriter.WriteLine(
                @"        void Abstract{0}::writeDelimitedTo(std::ostream& output)
        {{
            build(output, true);
        }}
"
                , message.name);
        }
        protected override void GeneratePrivateOrBuilderImpl(messageType message)
        {
            IncludeWriter.WriteLine(@"    public:
");

            IncludeWriter.Write("        ProtoOrBuilder* getRoot() override { return ");
            IncludeWriter.Write(message.IsRoot ? @"this" : "m_root");
            IncludeWriter.WriteLine("; }");

            IncludeWriter.WriteLine(@"        ProtoOrBuilder* decode(const LocalMessageDescriptor& field) override;
        ProtoOrBuilder* decode(const CoordinateList& coordinates, int index) override;");
            CppWriter.WriteLine(
                @"
        ProtoOrBuilder* Abstract{0}::decode(const LocalMessageDescriptor& field)
        {{
            return decode(field.coordinate(), 0);
        }}

        ProtoOrBuilder* Abstract{0}::decode(const CoordinateList& coordinates, int index)
        {{
            if (coordinates.size() == 0)
                return nullptr;
            
            auto fieldIdIdx = index;
            auto fieldIndexIdx = index + 1;
            auto remainderIdx = index + 2;
            switch(coordinates.Get(fieldIdIdx))
            {{", message.name);
            var allFields = message.field.Where(_ => _.type == typeType.nestedMessage || _.type == typeType.referenceMessage).OrderBy(_ => _.id);

            foreach (var field in allFields)
            {
                CppWriter.WriteLine(
                    @"              case {0}:", field.id);

                if (field.modifier == modifierType.repeated)
                {
                    CppWriter.WriteLine(
                        field.type != typeType.nestedMessage
                            ?
                        @"                  return &this->get{0}(coordinates.Get(fieldIndexIdx));"
                            :
                        @"                  return coordinates.size() == remainderIdx ? &this->get{0}(coordinates.Get(fieldIndexIdx)) : this->get{0}(coordinates.Get(fieldIndexIdx)).decode(coordinates, remainderIdx);",
                        field.name.Capitalize());
                }
                else if (field.modifier == modifierType.optional)
                {
                    CppWriter.WriteLine(
                        field.type != typeType.nestedMessage
                            ?
                        @"                  return this->{0}();"
                            :
                        @"                  return coordinates.size() == remainderIdx ? &this->add{1}() : this->{0}()->decode(coordinates, remainderIdx);",
                        field.name, field.name.Capitalize());
                }
                else
                {
                    CppWriter.WriteLine(
                        field.type != typeType.nestedMessage
                            ?
                        @"                  return this->{0}();"
                            :
                        @"                  return coordinates.size() == remainderIdx ? &this->{0}() : this->{0}().decode(coordinates, remainderIdx);",
                        field.name);
                }
            }
            CppWriter.WriteLine(
                @"              default:
                  return nullptr;
            }
        }
");
            IncludeWriter.WriteLine(@"        void addCoordinates(CoordinateList& coordinates) override;");
            CppWriter.WriteLine(
                @"        void Abstract{0}::addCoordinates(CoordinateList& coordinates)
        {{", message.name);

            if (!message.IsRoot)
            {
                CppWriter.WriteLine(
                    @"            
            coordinates.Add(0);
            coordinates.Add(0);
            for (auto i = coordinates.size() - 1; i >= 2; --i)
            {
                coordinates.Set(i, coordinates.Get(i - 2));
            }

            coordinates.Set(0, fieldId());
            coordinates.Set(1, index());

            if (getParent() == nullptr)
                return;

            getParent()->addCoordinates(coordinates);");
            }

            CppWriter.WriteLine(@"        }
");

            IncludeWriter.WriteLine(@"        LocalMessageDescriptor getLocalMessageDescriptor() override;");

            CppWriter.WriteLine(
                @"        LocalMessageDescriptor Abstract{0}::getLocalMessageDescriptor()
        {{
            auto b = LocalMessageDescriptor();
            addCoordinates(*b.mutable_coordinate());
            return b;
        }}", message.name);

            IncludeWriter.WriteLine(@"        bool isBuilt() const { return m_positionInContent != -1; }");
        }
        protected override void GenerateClassIndex(messageType message, indexType index)
        {
            // indexes are build at build time
            var field      = index.ReferenceField;
            var fieldType  = FieldType(field);
            var sortByType = FieldType(index.SortingField);

            if (index.SortingField.type == typeType.@string)
            {
                sortByType = "const " + sortByType + "&";
            }

            IncludeWriter.WriteLine(
                @"        // Note: indexes are built during the build process, and aren't available before
        std::vector<{2}*> {0}List();
        {2}& get{1}(int index);
        int {0}Count() const;
        {2}* search{1}({3} item);
        {2}* search{1}({3} item, int min, int max);
"
                , index.name, index.name.Capitalize(), fieldType, sortByType);

            CppWriter.WriteLine(
                @"        std::vector<{3}*> Abstract{4}::{0}List()
        {{
            assert((""Index is not built yet!"", isBuilt()));

            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)
        {{
            assert((""Index is not built yet!"", isBuilt()));
            return *dynamic_cast<{3}*>(getRoot()->decode(m_header.{2}(index)));
        }}

        int Abstract{4}::{0}Count() const
        {{
            assert((""Index is not built yet!"", isBuilt()));
            return m_header.{2}_size();
        }}

        {3}* Abstract{4}::search{1}({5} item)
        {{
            assert((""Index is not built yet!"", isBuilt()));

            // note: we don't use std::find so that 
            // we decode a minimum number of items
            return search{1}(item, 0, {0}Count() - 1);
        }}

        {3}* Abstract{4}::search{1}({5} item, int min, int max)
        {{
            assert((""Index is not built yet!"", isBuilt()));

            if (max < min)
                return nullptr;

            int avg = (min + max) >> 1;

            auto& candidate = get{1}(avg);
            {5} candidateKey = candidate.{6}();
            if (candidateKey == item)
                return &candidate;

            if (candidateKey < item)
                return search{1}(item, avg + 1, max);

            return search{1}(item, min, avg - 1);
        }}
"
                , index.name, index.name.Capitalize(), index.name.ToLowerInvariant(), fieldType, message.name, sortByType, index.sortBy);
        }
        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 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 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 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();
        }
");
        }