All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.co.real_logic.sbe.generation.cpp98.Cpp98Generator Maven / Gradle / Ivy

/*
 * Copyright 2013 Real Logic Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.co.real_logic.sbe.generation.cpp98;

import uk.co.real_logic.sbe.PrimitiveType;
import uk.co.real_logic.sbe.generation.CodeGenerator;
import uk.co.real_logic.agrona.generation.OutputManager;
import uk.co.real_logic.sbe.ir.*;
import uk.co.real_logic.agrona.Verify;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import static uk.co.real_logic.sbe.generation.cpp98.Cpp98Util.*;
import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups;
import static uk.co.real_logic.sbe.ir.GenerationUtil.collectRootFields;

public class Cpp98Generator implements CodeGenerator
{
    private static final String BASE_INDENT = "";
    private static final String INDENT = "    ";

    private final Ir ir;
    private final OutputManager outputManager;

    public Cpp98Generator(final Ir ir, final OutputManager outputManager)
        throws IOException
    {
        Verify.notNull(ir, "ir");
        Verify.notNull(outputManager, "outputManager");

        this.ir = ir;
        this.outputManager = outputManager;
    }

    public void generateMessageHeaderStub() throws IOException
    {
        final String messageHeader = "MessageHeader";

        try (final Writer out = outputManager.createOutput(messageHeader))
        {
            final List tokens = ir.headerStructure().tokens();
            out.append(generateFileHeader(ir.applicableNamespace().replace('.', '_'), messageHeader, null));
            out.append(generateClassDeclaration(messageHeader));
            out.append(generateFixedFlyweightCode(messageHeader, tokens.get(0).encodedLength()));
            out.append(generatePrimitivePropertyEncodings(
                messageHeader, tokens.subList(1, tokens.size() - 1), BASE_INDENT));

            out.append("};\n}\n#endif\n");
        }
    }

    public List generateTypeStubs() throws IOException
    {
        final List typesToInclude = new ArrayList<>();

        for (final List tokens : ir.types())
        {
            switch (tokens.get(0).signal())
            {
                case BEGIN_ENUM:
                    generateEnum(tokens);
                    break;

                case BEGIN_SET:
                    generateChoiceSet(tokens);
                    break;

                case BEGIN_COMPOSITE:
                    generateComposite(tokens);
                    break;
            }

            typesToInclude.add(tokens.get(0).name());
        }

        return typesToInclude;
    }

    public void generate() throws IOException
    {
        generateMessageHeaderStub();
        final List typesToInclude = generateTypeStubs();

        for (final List tokens : ir.messages())
        {
            final Token msgToken = tokens.get(0);
            final String className = formatClassName(msgToken.name());

            try (final Writer out = outputManager.createOutput(className))
            {
                out.append(generateFileHeader(ir.applicableNamespace().replace('.', '_'), className, typesToInclude));
                out.append(generateClassDeclaration(className));
                out.append(generateMessageFlyweightCode(className, msgToken));

                final List messageBody = tokens.subList(1, tokens.size() - 1);
                int offset = 0;

                final List rootFields = new ArrayList<>();
                offset = collectRootFields(messageBody, offset, rootFields);
                out.append(generateFields(className, rootFields, BASE_INDENT));

                final List groups = new ArrayList<>();
                offset = collectGroups(messageBody, offset, groups);
                final StringBuilder sb = new StringBuilder();
                generateGroups(sb, groups, 0, BASE_INDENT);
                out.append(sb);

                final List varData = messageBody.subList(offset, messageBody.size());
                out.append(generateVarData(varData));

                out.append("};\n}\n#endif\n");
            }
        }
    }

    private int generateGroups(final StringBuilder sb, final List tokens, int index, final String indent)
    {
        for (int size = tokens.size(); index < size; index++)
        {
            if (tokens.get(index).signal() == Signal.BEGIN_GROUP)
            {
                final Token groupToken = tokens.get(index);
                final String groupName = groupToken.name();

                generateGroupClassHeader(sb, groupName, tokens, index, indent + INDENT);

                final List rootFields = new ArrayList<>();
                index = collectRootFields(tokens, ++index, rootFields);
                sb.append(generateFields(groupName, rootFields, indent + INDENT));

                if (tokens.get(index).signal() == Signal.BEGIN_GROUP)
                {
                    index = generateGroups(sb, tokens, index, indent + INDENT);
                }

                sb.append(indent).append("    };\n");
                sb.append(generateGroupProperty(groupName, groupToken, indent));
            }
        }

        return index;
    }

    private void generateGroupClassHeader(
        final StringBuilder sb, final String groupName, final List tokens, final int index, final String indent)
    {
        final String dimensionsClassName = formatClassName(tokens.get(index + 1).name());
        final int dimensionHeaderLength = tokens.get(index + 1).encodedLength();

        sb.append(String.format(
            "\n" +
            indent + "class %1$s\n" +
            indent + "{\n" +
            indent + "private:\n" +
            indent + "    char *buffer_;\n" +
            indent + "    int bufferLength_;\n" +
            indent + "    int *positionPtr_;\n" +
            indent + "    int blockLength_;\n" +
            indent + "    int count_;\n" +
            indent + "    int index_;\n" +
            indent + "    int offset_;\n" +
            indent + "    int actingVersion_;\n" +
            indent + "    %2$s dimensions_;\n\n" +
            indent + "public:\n\n",
            formatClassName(groupName),
            dimensionsClassName
        ));

        sb.append(String.format(
            indent + "    inline void wrapForDecode(char *buffer, int *pos, const int actingVersion," +
            indent + " const int bufferLength)\n" +
            indent + "    {\n" +
            indent + "        buffer_ = buffer;\n" +
            indent + "        bufferLength_ = bufferLength;\n" +
            indent + "        dimensions_.wrap(buffer_, *pos, actingVersion, bufferLength);\n" +
            indent + "        blockLength_ = dimensions_.blockLength();\n" +
            indent + "        count_ = dimensions_.numInGroup();\n" +
            indent + "        index_ = -1;\n" +
            indent + "        actingVersion_ = actingVersion;\n" +
            indent + "        positionPtr_ = pos;\n" +
            indent + "        *positionPtr_ = *positionPtr_ + %1$d;\n" +
            indent + "    }\n\n",
            dimensionHeaderLength
        ));

        final int blockLength = tokens.get(index).encodedLength();
        final String cpp98TypeForBlockLength = cpp98TypeName(tokens.get(index + 2).encoding().primitiveType());
        final String cpp98TypeForNumInGroup = cpp98TypeName(tokens.get(index + 3).encoding().primitiveType());

        sb.append(String.format(
            indent + "    inline void wrapForEncode(char *buffer, const int count," +
            indent + " int *pos, const int actingVersion, const int bufferLength)\n" +
            indent + "    {\n" +
            indent + "        buffer_ = buffer;\n" +
            indent + "        bufferLength_ = bufferLength;\n" +
            indent + "        dimensions_.wrap(buffer_, *pos, actingVersion, bufferLength);\n" +
            indent + "        dimensions_.blockLength((%1$s)%2$d);\n" +
            indent + "        dimensions_.numInGroup((%3$s)count);\n" +
            indent + "        index_ = -1;\n" +
            indent + "        count_ = count;\n" +
            indent + "        blockLength_ = %2$d;\n" +
            indent + "        actingVersion_ = actingVersion;\n" +
            indent + "        positionPtr_ = pos;\n" +
            indent + "        *positionPtr_ = *positionPtr_ + %4$d;\n" +
            indent + "    }\n\n",
            cpp98TypeForBlockLength, blockLength, cpp98TypeForNumInGroup, dimensionHeaderLength
        ));

        sb.append(String.format(
            indent + "    static const int sbeHeaderSize()\n" +
            indent + "    {\n" +
            indent + "        return %1$d;\n" +
            indent + "    }\n\n" +
            indent + "    static const int sbeBlockLength()\n" +
            indent + "    {\n" +
            indent + "        return %2$d;\n" +
            indent + "    }\n\n" +
            indent + "    inline int count(void) const\n" +
            indent + "    {\n" +
            indent + "        return count_;\n" +
            indent + "    }\n\n" +
            indent + "    inline bool hasNext(void) const\n" +
            indent + "    {\n" +
            indent + "        return index_ + 1 < count_;\n" +
            indent + "    }\n\n" +
            indent + "    inline %3$s &next(void)\n" +
            indent + "    {\n" +
            indent + "        offset_ = *positionPtr_;\n" +
            indent + "        if (SBE_BOUNDS_CHECK_EXPECT(( (offset_ + blockLength_) > bufferLength_ ), false))\n" +
            indent + "        {\n" +
            indent + "            throw std::runtime_error(\"buffer too short to support next group index [E108]\");\n" +
            indent + "        }\n" +
            indent + "        *positionPtr_ = offset_ + blockLength_;\n" +
            indent + "        ++index_;\n\n" +
            indent + "        return *this;\n" +
            indent + "    }\n\n",
            dimensionHeaderLength, blockLength, formatClassName(groupName)
        ));

        sb.append(String.format(
            indent + "#if __cplusplus < 201103L\n" +
            indent + "    template\n" +
            indent + "    inline void forEach(Func& func)\n" +
            indent + "    {\n" +
            indent + "        while(hasNext())\n" +
            indent + "        {\n" +
            indent + "            next(); func(*this);\n" +
            indent + "        }\n" +
            indent + "    }\n\n" +
            indent + "#else\n" +
            indent + "    inline void forEach(std::function func)\n" +
            indent + "    {\n" +
            indent + "        while(hasNext())\n" +
            indent + "        {\n" +
            indent + "            next(); func(*this);\n" +
            indent + "        }\n" +
            indent + "    }\n\n" +
            indent + "#endif\n\n",
            formatClassName(groupName)
        ));
    }

    private CharSequence generateGroupProperty(final String groupName, final Token token, final String indent)
    {
        final StringBuilder sb = new StringBuilder();

        final String className = formatClassName(groupName);
        final String propertyName = formatPropertyName(groupName);

        sb.append(String.format(
            "\n" +
            "private:\n" +
            indent + "    %1$s %2$s_;\n\n" +
            "public:\n",
            className,
            propertyName
        ));

        sb.append(String.format(
            "\n" +
            indent + "    static const int %1$sId(void)\n" +
            indent + "    {\n" +
            indent + "        return %2$d;\n" +
            indent + "    }\n\n",
            groupName,
            (long)token.id()
        ));

        sb.append(String.format(
            "\n" +
            indent + "    inline %1$s &%2$s(void)\n" +
            indent + "    {\n" +
            indent + "        %2$s_.wrapForDecode(buffer_, positionPtr_, actingVersion_, bufferLength_);\n" +
            indent + "        return %2$s_;\n" +
            indent + "    }\n",
            className,
            propertyName
        ));

        sb.append(String.format(
            "\n" +
            indent + "    %1$s &%2$sCount(const int count)\n" +
            indent + "    {\n" +
            indent + "        %2$s_.wrapForEncode(buffer_, count, positionPtr_, actingVersion_, bufferLength_);\n" +
            indent + "        return %2$s_;\n" +
            indent + "    }\n",
            className,
            propertyName
        ));

        return sb;
    }

    private CharSequence generateVarData(final List tokens)
    {
        final StringBuilder sb = new StringBuilder();

        for (int i = 0, size = tokens.size(); i < size; i++)
        {
            final Token token = tokens.get(i);
            if (token.signal() == Signal.BEGIN_VAR_DATA)
            {
                final String propertyName = toUpperFirstChar(token.name());
                final String characterEncoding = tokens.get(i + 3).encoding().characterEncoding();
                final Token lengthToken = tokens.get(i + 2);
                final int lengthOfLengthField = lengthToken.encodedLength();
                final String lengthCpp98Type = cpp98TypeName(lengthToken.encoding().primitiveType());

                generateFieldMetaAttributeMethod(sb, token, BASE_INDENT);

                generateVarDataDescriptors(
                    sb, token, propertyName, characterEncoding, lengthToken, lengthOfLengthField, lengthCpp98Type);

                sb.append(String.format(
                    "    const char *%1$s(void)\n" +
                    "    {\n" +
                             "%2$s" +
                    "         const char *fieldPtr = (buffer_ + position() + %3$d);\n" +
                    "         position(position() + %3$d + *((%4$s *)(buffer_ + position())));\n" +
                    "         return fieldPtr;\n" +
                    "    }\n\n",
                    formatPropertyName(propertyName),
                    generateTypeFieldNotPresentCondition(token.version(), BASE_INDENT),
                    lengthOfLengthField,
                    lengthCpp98Type
                ));

                sb.append(String.format(
                    "    int get%1$s(char *dst, const int length)\n" +
                    "    {\n" +
                            "%2$s" +
                    "        sbe_uint64_t lengthOfLengthField = %3$d;\n" +
                    "        sbe_uint64_t lengthPosition = position();\n" +
                    "        position(lengthPosition + lengthOfLengthField);\n" +
                    "        sbe_int64_t dataLength = %4$s(*((%5$s *)(buffer_ + lengthPosition)));\n" +
                    "        int bytesToCopy = (length < dataLength) ? length : dataLength;\n" +
                    "        sbe_uint64_t pos = position();\n" +
                    "        position(position() + (sbe_uint64_t)dataLength);\n" +
                    "        ::memcpy(dst, buffer_ + pos, bytesToCopy);\n" +
                    "        return bytesToCopy;\n" +
                    "    }\n\n",
                    propertyName,
                    generateArrayFieldNotPresentCondition(token.version(), BASE_INDENT),
                    lengthOfLengthField,
                    formatByteOrderEncoding(lengthToken.encoding().byteOrder(), lengthToken.encoding().primitiveType()),
                    lengthCpp98Type
                ));

                sb.append(String.format(
                    "    int put%1$s(const char *src, const int length)\n" +
                    "    {\n" +
                    "        sbe_uint64_t lengthOfLengthField = %2$d;\n" +
                    "        sbe_uint64_t lengthPosition = position();\n" +
                    "        *((%3$s *)(buffer_ + lengthPosition)) = %4$s((%3$s)length);\n" +
                    "        position(lengthPosition + lengthOfLengthField);\n" +
                    "        sbe_uint64_t pos = position();\n" +
                    "        position(position() + (sbe_uint64_t)length);\n" +
                    "        ::memcpy(buffer_ + pos, src, length);\n" +
                    "        return length;\n" +
                    "    }\n",
                    propertyName,
                    lengthOfLengthField,
                    lengthCpp98Type,
                    formatByteOrderEncoding(lengthToken.encoding().byteOrder(), lengthToken.encoding().primitiveType())
                ));
            }
        }

        return sb;
    }

    private void generateVarDataDescriptors(
        final StringBuilder sb,
        final Token token,
        final String propertyName,
        final String characterEncoding,
        final Token lengthToken,
        final Integer sizeOfLengthField,
        final String lengthCpp98Type)
    {
        sb.append(String.format(
            "\n"  +
            "    static const char *%1$sCharacterEncoding()\n" +
            "    {\n" +
            "        return \"%2$s\";\n" +
            "    }\n\n",
            formatPropertyName(propertyName),
            characterEncoding
        ));

        sb.append(String.format(
            "    static const int %1$sSinceVersion(void)\n" +
            "    {\n" +
            "         return %2$d;\n" +
            "    }\n\n" +
            "    bool %1$sInActingVersion(void)\n" +
            "    {\n" +
            "        return (actingVersion_ >= %2$s) ? true : false;\n" +
            "    }\n\n" +
            "    static const int %1$sId(void)\n" +
            "    {\n" +
            "        return %3$d;\n" +
            "    }\n\n",
            formatPropertyName(propertyName),
            (long)token.version(),
            token.id()
        ));

        sb.append(String.format(
            "\n" +
            "    static const int %sHeaderSize()\n" +
            "    {\n" +
            "        return %d;\n" +
            "    }\n",
            toLowerFirstChar(propertyName),
            sizeOfLengthField
        ));

        sb.append(String.format(
            "\n" +
            "    sbe_int64_t %1$sLength(void) const\n" +
            "    {\n" +
                    "%2$s" +
            "        return %3$s(*((%4$s *)(buffer_ + position())));\n" +
            "    }\n\n",
            formatPropertyName(propertyName),
            generateArrayFieldNotPresentCondition(token.version(), BASE_INDENT),
            formatByteOrderEncoding(lengthToken.encoding().byteOrder(), lengthToken.encoding().primitiveType()),
            lengthCpp98Type
        ));
    }

    private void generateChoiceSet(final List tokens) throws IOException
    {
        final String bitSetName = formatClassName(tokens.get(0).name());

        try (final Writer out = outputManager.createOutput(bitSetName))
        {
            out.append(generateFileHeader(ir.applicableNamespace().replace('.', '_'), bitSetName, null));
            out.append(generateClassDeclaration(bitSetName));
            out.append(generateFixedFlyweightCode(bitSetName, tokens.get(0).encodedLength()));

            out.append(String.format(
                "\n" +
                "    %1$s &clear(void)\n" +
                "    {\n" +
                "        *((%2$s *)(buffer_ + offset_)) = 0;\n" +
                "        return *this;\n" +
                "    }\n\n",
                bitSetName,
                cpp98TypeName(tokens.get(0).encoding().primitiveType())
            ));

            out.append(generateChoices(bitSetName, tokens.subList(1, tokens.size() - 1)));

            out.append("};\n}\n#endif\n");
        }
    }

    private void generateEnum(final List tokens) throws IOException
    {
        final Token enumToken = tokens.get(0);
        final String enumName = formatClassName(tokens.get(0).name());

        try (final Writer out = outputManager.createOutput(enumName))
        {
            out.append(generateFileHeader(ir.applicableNamespace().replace('.', '_'), enumName, null));
            out.append(generateEnumDeclaration(enumName));

            out.append(generateEnumValues(tokens.subList(1, tokens.size() - 1), enumToken));

            out.append(generateEnumLookupMethod(tokens.subList(1, tokens.size() - 1), enumToken));

            out.append("};\n}\n#endif\n");
        }
    }

    private void generateComposite(final List tokens) throws IOException
    {
        final String compositeName = formatClassName(tokens.get(0).name());

        try (final Writer out = outputManager.createOutput(compositeName))
        {
            out.append(generateFileHeader(ir.applicableNamespace().replace('.', '_'), compositeName, null));
            out.append(generateClassDeclaration(compositeName));
            out.append(generateFixedFlyweightCode(compositeName, tokens.get(0).encodedLength()));

            out.append(generatePrimitivePropertyEncodings(compositeName, tokens.subList(1, tokens.size() - 1), BASE_INDENT));

            out.append("};\n}\n#endif\n");
        }
    }

    private CharSequence generateChoiceNotPresentCondition(final int sinceVersion, final String indent)
    {
        if (0 == sinceVersion)
        {
            return "";
        }

        return String.format(
            indent + "        if (actingVersion_ < %1$d)\n" +
            indent + "        {\n" +
            indent + "            return false;\n" +
            indent + "        }\n\n",
            sinceVersion
        );
    }

    private CharSequence generateChoices(final String bitsetClassName, final List tokens)
    {
        final StringBuilder sb = new StringBuilder();

        for (final Token token : tokens)
        {
            if (token.signal() == Signal.CHOICE)
            {
                final String choiceName = token.name();
                final String typeName = cpp98TypeName(token.encoding().primitiveType());
                final String choiceBitPosition = token.encoding().constValue().toString();
                final String byteOrderStr = formatByteOrderEncoding(
                    token.encoding().byteOrder(), token.encoding().primitiveType());

                sb.append(String.format(
                    "\n" +
                    "    bool %1$s(void) const\n" +
                    "    {\n" +
                            "%2$s" +
                    "        return (%3$s(*((%4$s *)(buffer_ + offset_))) & (0x1L << %5$s)) ? true : false;\n" +
                    "    }\n\n",
                    choiceName,
                    generateChoiceNotPresentCondition(token.version(), BASE_INDENT),
                    byteOrderStr,
                    typeName,
                    choiceBitPosition
                ));

                sb.append(String.format(
                    "    %1$s &%2$s(const bool value)\n" +
                    "    {\n" +
                    "        %3$s bits = %4$s(*((%3$s *)(buffer_ + offset_)));\n" +
                    "        bits = value ? (bits | (0x1L << %5$s)) : (bits & ~(0x1L << %5$s));\n" +
                    "        *((%3$s *)(buffer_ + offset_)) = %4$s(bits);\n" +
                    "        return *this;\n" +
                    "    }\n",
                    bitsetClassName,
                    choiceName,
                    typeName,
                    byteOrderStr,
                    choiceBitPosition
                ));
            }
        }

        return sb;
    }

    private CharSequence generateEnumValues(final List tokens, final Token encodingToken)
    {
        final StringBuilder sb = new StringBuilder();
        final Encoding encoding = encodingToken.encoding();

        sb.append(
            "    enum Value \n" +
            "    {\n"
        );

        for (final Token token : tokens)
        {
            final CharSequence constVal = generateLiteral(
                token.encoding().primitiveType(), token.encoding().constValue().toString());
            sb.append("        ").append(token.name()).append(" = ").append(constVal).append(",\n");
        }

        sb.append(String.format(
            "        NULL_VALUE = %1$s",
            generateLiteral(encoding.primitiveType(), encoding.applicableNullValue().toString())
        ));

        sb.append("\n    };\n\n");

        return sb;
    }

    private CharSequence generateEnumLookupMethod(final List tokens, final Token encodingToken)
    {
        final String enumName = formatClassName(encodingToken.name());
        final StringBuilder sb = new StringBuilder();

        sb.append(String.format(
           "    static %1$s::Value get(const %2$s value)\n" +
           "    {\n" +
           "        switch (value)\n" +
           "        {\n",
           enumName,
           cpp98TypeName(tokens.get(0).encoding().primitiveType())
        ));

        for (final Token token : tokens)
        {
            sb.append(String.format(
                "            case %1$s: return %2$s;\n",
                token.encoding().constValue().toString(),
                token.name())
            );
        }

        sb.append(String.format(
            "            case %1$s: return NULL_VALUE;\n" +
            "        }\n\n" +
            "        throw std::runtime_error(\"unknown value for enum %2$s [E103]\");\n" +
            "    }\n",
            encodingToken.encoding().applicableNullValue().toString(),
            enumName
        ));

        return sb;
    }

    private CharSequence generateFieldNotPresentCondition(final int sinceVersion, final Encoding encoding, final String indent)
    {
        if (0 == sinceVersion)
        {
            return "";
        }

        return String.format(
            indent + "        if (actingVersion_ < %1$d)\n" +
            indent + "        {\n" +
            indent + "            return %2$s;\n" +
            indent + "        }\n\n",
            sinceVersion,
            generateLiteral(encoding.primitiveType(), encoding.applicableNullValue().toString())
        );
    }

    private CharSequence generateArrayFieldNotPresentCondition(final int sinceVersion, final String indent)
    {
        if (0 == sinceVersion)
        {
            return "";
        }

        return String.format(
            indent + "        if (actingVersion_ < %1$d)\n" +
            indent + "        {\n" +
            indent + "            return 0;\n" +
            indent + "        }\n\n",
            sinceVersion
        );
    }

    private CharSequence generateTypeFieldNotPresentCondition(final int sinceVersion, final String indent)
    {
        if (0 == sinceVersion)
        {
            return "";
        }

        return String.format(
            indent + "        if (actingVersion_ < %1$d)\n" +
            indent + "        {\n" +
            indent + "            return NULL;\n" +
            indent + "        }\n\n",
            sinceVersion
        );
    }

    private CharSequence generateFileHeader(final String namespaceName, final String className, final List typesToInclude)
    {
        final StringBuilder sb = new StringBuilder();

        sb.append("/* Generated SBE (Simple Binary Encoding) message codec */\n");

        sb.append(String.format(
            "#ifndef _%1$s_%2$s_HPP_\n" +
            "#define _%1$s_%2$s_HPP_\n\n" +
            "#if defined(SBE_HAVE_CMATH)\n" +
            "/* cmath needed for std::numeric_limits::quiet_NaN() */\n" +
            "#  include \n" +
            "#  define SBE_FLOAT_NAN std::numeric_limits::quiet_NaN()\n" +
            "#  define SBE_DOUBLE_NAN std::numeric_limits::quiet_NaN()\n" +
            "#else\n" +
            "/* math.h needed for NAN */\n" +
            "#  include \n" +
            "#  define SBE_FLOAT_NAN NAN\n" +
            "#  define SBE_DOUBLE_NAN NAN\n" +
            "#endif\n\n" +
            "#include \n\n",
            namespaceName.toUpperCase(),
            className.toUpperCase()
        ));

        if (typesToInclude != null)
        {
            for (final String incName : typesToInclude)
            {
                sb.append(String.format(
                    "#include <%1$s/%2$s.hpp>\n",
                    namespaceName,
                    toUpperFirstChar(incName)
                ));
            }
            sb.append("\n");
        }

        sb.append(String.format(
            "using namespace sbe;\n\n" +
            "namespace %1$s {\n\n",
            namespaceName
        ));

        return sb;
    }

    private CharSequence generateClassDeclaration(final String className)
    {
        return String.format(
            "class %s\n" +
            "{\n",
            className
        );
    }

    private CharSequence generateEnumDeclaration(final String name)
    {
        return "class " + name + "\n{\npublic:\n\n";
    }

    private CharSequence generatePrimitivePropertyEncodings(
        final String containingClassName, final List tokens, final String indent)
    {
        final StringBuilder sb = new StringBuilder();

        for (final Token token : tokens)
        {
            if (token.signal() == Signal.ENCODING)
            {
                sb.append(generatePrimitiveProperty(containingClassName, token.name(), token, indent));
            }
        }

       return sb;
    }

    private CharSequence generatePrimitiveProperty(
        final String containingClassName, final String propertyName, final Token token, final String indent)
    {
        final StringBuilder sb = new StringBuilder();

        sb.append(generatePrimitiveFieldMetaData(propertyName, token, indent));

        if (token.isConstantEncoding())
        {
            sb.append(generateConstPropertyMethods(propertyName, token, indent));
        }
        else
        {
            sb.append(generatePrimitivePropertyMethods(containingClassName, propertyName, token, indent));
        }

        return sb;
    }

    private CharSequence generatePrimitivePropertyMethods(
        final String containingClassName, final String propertyName, final Token token, final String indent)
    {
        final int arrayLength = token.arrayLength();

        if (arrayLength == 1)
        {
            return generateSingleValueProperty(containingClassName, propertyName, token, indent);
        }
        else if (arrayLength > 1)
        {
            return generateArrayProperty(containingClassName, propertyName, token, indent);
        }

        return "";
    }

    private CharSequence generatePrimitiveFieldMetaData(final String propertyName, final Token token, final String indent)
    {
        final StringBuilder sb = new StringBuilder();

        final Encoding encoding = token.encoding();
        final PrimitiveType primitiveType = encoding.primitiveType();
        final String cpp98TypeName = cpp98TypeName(primitiveType);
        final CharSequence nullValueString = generateNullValueLiteral(primitiveType, encoding);

        sb.append(String.format(
            "\n" +
            indent + "    static const %1$s %2$sNullValue()\n" +
            indent + "    {\n" +
            indent + "        return %3$s;\n" +
            indent + "    }\n",
            cpp98TypeName,
            propertyName,
            nullValueString
        ));

        sb.append(String.format(
            "\n" +
            indent + "    static const %1$s %2$sMinValue()\n" +
            indent + "    {\n" +
            indent + "        return %3$s;\n" +
            indent + "    }\n",
            cpp98TypeName,
            propertyName,
            generateLiteral(primitiveType, token.encoding().applicableMinValue().toString())
        ));

        sb.append(String.format(
            "\n" +
            indent + "    static const %1$s %2$sMaxValue()\n" +
            indent + "    {\n" +
            indent + "        return %3$s;\n" +
            indent + "    }\n",
            cpp98TypeName,
            propertyName,
            generateLiteral(primitiveType, token.encoding().applicableMaxValue().toString())
        ));

        return sb;
    }

    private CharSequence generateSingleValueProperty(
        final String containingClassName, final String propertyName, final Token token, final String indent)
    {
        final String cpp98TypeName = cpp98TypeName(token.encoding().primitiveType());
        final int offset = token.offset();
        final StringBuilder sb = new StringBuilder();

        sb.append(String.format(
            "\n" +
            indent + "    %1$s %2$s(void) const\n" +
            indent + "    {\n" +
                              "%3$s" +
            indent + "        return %4$s(*((%1$s *)(buffer_ + offset_ + %5$d)));\n" +
            indent + "    }\n\n",
            cpp98TypeName,
            propertyName,
            generateFieldNotPresentCondition(token.version(), token.encoding(), indent),
            formatByteOrderEncoding(token.encoding().byteOrder(), token.encoding().primitiveType()),
            offset
        ));

        sb.append(String.format(
            indent + "    %1$s &%2$s(const %3$s value)\n" +
            indent + "    {\n" +
            indent + "        *((%3$s *)(buffer_ + offset_ + %4$d)) = %5$s(value);\n" +
            indent + "        return *this;\n" +
            indent + "    }\n",
            formatClassName(containingClassName),
            propertyName,
            cpp98TypeName,
            offset,
            formatByteOrderEncoding(token.encoding().byteOrder(), token.encoding().primitiveType())
        ));

        return sb;
    }

    private CharSequence generateArrayProperty(
        final String containingClassName, final String propertyName, final Token token, final String indent)
    {
        final String cpp98TypeName = cpp98TypeName(token.encoding().primitiveType());
        final int offset = token.offset();

        final StringBuilder sb = new StringBuilder();

        sb.append(String.format(
            "\n" +
            indent + "    static const int %1$sLength(void)\n" +
            indent + "    {\n" +
            indent + "        return %2$d;\n" +
            indent + "    }\n\n",
            propertyName,
            token.arrayLength()
        ));

        sb.append(String.format(
            indent + "    const char *%1$s(void) const\n" +
            indent + "    {\n" +
                              "%2$s" +
            indent + "        return (buffer_ + offset_ + %3$d);\n" +
            indent + "    }\n\n",
            propertyName,
            generateTypeFieldNotPresentCondition(token.version(), indent),
            offset
        ));

        sb.append(String.format(
            indent + "    %1$s %2$s(const int index) const\n" +
            indent + "    {\n" +
            indent + "        if (index < 0 || index >= %3$d)\n" +
            indent + "        {\n" +
            indent + "            throw std::runtime_error(\"index out of range for %2$s [E104]\");\n" +
            indent + "        }\n\n" +
                             "%4$s" +
            indent + "        return %5$s(*((%1$s *)(buffer_ + offset_ + %6$d + (index * %7$d))));\n" +
            indent + "    }\n\n",
            cpp98TypeName,
            propertyName,
            token.arrayLength(),
            generateFieldNotPresentCondition(token.version(), token.encoding(), indent),
            formatByteOrderEncoding(token.encoding().byteOrder(), token.encoding().primitiveType()),
            offset,
            token.encoding().primitiveType().size()
        ));

        sb.append(String.format(
            indent + "    void %1$s(const int index, const %2$s value)\n" +
            indent + "    {\n" +
            indent + "        if (index < 0 || index >= %3$d)\n" +
            indent + "        {\n" +
            indent + "            throw std::runtime_error(\"index out of range for %1$s [E105]\");\n" +
            indent + "        }\n\n" +
            indent + "        *((%2$s *)(buffer_ + offset_ + %4$d + (index * %5$d))) = %6$s(value);\n" +
            indent + "    }\n\n",
            propertyName,
            cpp98TypeName,
            token.arrayLength(),
            offset,
            token.encoding().primitiveType().size(),
            formatByteOrderEncoding(token.encoding().byteOrder(), token.encoding().primitiveType())
        ));

        sb.append(String.format(
            indent + "    int get%1$s(char *dst, const int length) const\n" +
            indent + "    {\n" +
            indent + "        if (length > %2$d)\n" +
            indent + "        {\n" +
            indent + "             throw std::runtime_error(\"length too large for get%1$s [E106]\");\n" +
            indent + "        }\n\n" +
                             "%3$s" +
            indent + "        ::memcpy(dst, buffer_ + offset_ + %4$d, length);\n" +
            indent + "        return length;\n" +
            indent + "    }\n\n",
            toUpperFirstChar(propertyName),
            token.arrayLength(),
            generateArrayFieldNotPresentCondition(token.version(), indent),
            offset
        ));

        sb.append(String.format(
            indent + "    %1$s &put%2$s(const char *src)\n" +
            indent + "    {\n" +
            indent + "        ::memcpy(buffer_ + offset_ + %3$d, src, %4$d);\n" +
            indent + "        return *this;\n" +
            indent + "    }\n",
            containingClassName,
            toUpperFirstChar(propertyName),
            offset,
            token.arrayLength()
        ));

        return sb;
    }

    private CharSequence generateConstPropertyMethods(final String propertyName, final Token token, final String indent)
    {
        final String cpp98TypeName = cpp98TypeName(token.encoding().primitiveType());

        if (token.encoding().primitiveType() != PrimitiveType.CHAR)
        {
            return String.format(
                "\n" +
                indent + "    %1$s %2$s(void) const\n" +
                indent + "    {\n" +
                indent + "        return %3$s;\n" +
                indent + "    }\n",
                cpp98TypeName,
                propertyName,
                generateLiteral(token.encoding().primitiveType(), token.encoding().constValue().toString())
            );
        }

        final StringBuilder sb = new StringBuilder();

        final byte[] constantValue = token.encoding().constValue().byteArrayValue(token.encoding().primitiveType());
        final StringBuilder values = new StringBuilder();
        for (final byte b : constantValue)
        {
            values.append(b).append(", ");
        }
        if (values.length() > 0)
        {
            values.setLength(values.length() - 2);
        }

        sb.append(String.format(
            "\n" +
            indent + "    static const int %1$sLength(void)\n" +
            indent + "    {\n" +
            indent + "        return %2$d;\n" +
            indent + "    }\n\n",
            propertyName,
            constantValue.length
        ));

        sb.append(String.format(
            indent + "    const char *%1$s(void) const\n" +
            indent + "    {\n" +
            indent + "        static sbe_uint8_t %1$sValues[] = {%2$s};\n\n" +
            indent + "        return (const char *)%1$sValues;\n" +
            indent + "    }\n\n",
            propertyName,
            values
        ));

        sb.append(String.format(
            indent + "    %1$s %2$s(const int index) const\n" +
            indent + "    {\n" +
            indent + "        static sbe_uint8_t %2$sValues[] = {%3$s};\n\n" +
            indent + "        return %2$sValues[index];\n" +
            indent + "    }\n\n",
            cpp98TypeName,
            propertyName,
            values
        ));

        sb.append(String.format(
            indent + "    int get%1$s(char *dst, const int length) const\n" +
            indent + "    {\n" +
            indent + "        static sbe_uint8_t %2$sValues[] = {%3$s};\n" +
            indent + "        int bytesToCopy = (length < (int)sizeof(%2$sValues)) ? length : (int)sizeof(%2$sValues);\n\n" +
            indent + "        ::memcpy(dst, %2$sValues, bytesToCopy);\n" +
            indent + "        return bytesToCopy;\n" +
            indent + "    }\n",
            toUpperFirstChar(propertyName),
            propertyName,
            values
        ));

        return sb;
    }

    private CharSequence generateFixedFlyweightCode(final String className, final int size)
    {
        return String.format(
            "private:\n" +
            "    char *buffer_;\n" +
            "    int offset_;\n" +
            "    int actingVersion_;\n\n" +
            "    inline void reset(char *buffer, const int offset, const int bufferLength, const int actingVersion)\n" +
            "    {\n" +
            "        if (SBE_BOUNDS_CHECK_EXPECT((offset > (bufferLength - %2$s)), false))\n" +
            "        {\n" +
            "            throw std::runtime_error(\"buffer too short for flyweight [E107]\");\n" +
            "        }\n" +
            "        buffer_ = buffer;\n" +
            "        offset_ = offset;\n" +
            "        actingVersion_ = actingVersion;\n" +
            "    }\n\n" +
            "public:\n" +
            "    %1$s(void) : buffer_(NULL), offset_(0) {}\n\n" +
            "    %1$s(char *buffer, const int bufferLength, const int actingVersion)\n" +
            "    {\n" +
            "        reset(buffer, 0, bufferLength, actingVersion);\n" +
            "    }\n\n" +
            "    %1$s(const %1$s& codec) :\n" +
            "        buffer_(codec.buffer_), offset_(codec.offset_), actingVersion_(codec.actingVersion_) {}\n\n" +
            "#if __cplusplus >= 201103L\n" +
            "    %1$s(%1$s&& codec) = default;\n" +
            "    %1$s& operator=(const %1$s&& codec) = default;\n" +
            "#endif\n\n" +
            "    %1$s& operator=(const %1$s& codec)\n" +
            "    {\n" +
            "        buffer_ = codec.buffer_;\n" +
            "        offset_ = codec.offset_;\n" +
            "        actingVersion_ = codec.actingVersion_;\n" +
            "        return *this;\n" +
            "    }\n\n" +
            "    %1$s &wrap(char *buffer, const int offset, const int actingVersion, const int bufferLength)\n" +
            "    {\n" +
            "        reset(buffer, offset, bufferLength, actingVersion);\n" +
            "        return *this;\n" +
            "    }\n\n" +
            "    static const int size(void)\n" +
            "    {\n" +
            "        return %2$s;\n" +
            "    }\n\n",
            className,
            size
        );
    }

    private CharSequence generateConstructorsAndOperators(final String className)
    {
        return String.format(
            "    %1$s(void) : buffer_(NULL), bufferLength_(0), offset_(0) {}\n\n" +
            "    %1$s(char *buffer, const int bufferLength, const int actingBlockLength, const int actingVersion)\n" +
            "    {\n" +
            "        reset(buffer, 0, bufferLength, actingBlockLength, actingVersion);\n" +
            "    }\n\n" +
            "    %1$s(const %1$s& codec)\n" +
            "    {\n" +
            "        reset(codec.buffer_, codec.offset_, codec.bufferLength_, codec.actingBlockLength_," +
            " codec.actingVersion_);\n" +
            "    }\n\n" +
            "#if __cplusplus >= 201103L\n" +
            "    %1$s(%1$s&& codec)\n" +
            "    {\n" +
            "        reset(codec.buffer_, codec.offset_, codec.bufferLength_, codec.actingBlockLength_," +
            " codec.actingVersion_);\n" +
            "    }\n\n" +
            "    %1$s& operator=(const %1$s&& codec)\n" +
            "    {\n" +
            "        reset(codec.buffer_, codec.offset_, codec.bufferLength_, codec.actingBlockLength_," +
            " codec.actingVersion_);\n" +
            "        return *this;\n" +
            "    }\n\n" +
            "#endif\n\n" +
            "    %1$s& operator=(const %1$s& codec)\n" +
            "    {\n" +
            "        reset(codec.buffer_, codec.offset_, codec.bufferLength_, codec.actingBlockLength_," +
            " codec.actingVersion_);\n" +
            "        return *this;\n" +
            "    }\n\n" +
            "",
            className
        );
    }

    private CharSequence generateMessageFlyweightCode(final String className, final Token token)
    {
        final String blockLengthType = cpp98TypeName(ir.headerStructure().blockLengthType());
        final String templateIdType = cpp98TypeName(ir.headerStructure().templateIdType());
        final String schemaIdType = cpp98TypeName(ir.headerStructure().schemaIdType());
        final String schemaVersionType = cpp98TypeName(ir.headerStructure().schemaVersionType());
        final String semanticType = token.encoding().semanticType() == null ? "" : token.encoding().semanticType();

        return String.format(
            "private:\n" +
            "    char *buffer_;\n" +
            "    int bufferLength_;\n" +
            "    int *positionPtr_;\n" +
            "    int offset_;\n" +
            "    int position_;\n" +
            "    int actingBlockLength_;\n" +
            "    int actingVersion_;\n\n" +
            "    inline void reset(char *buffer, const int offset, const int bufferLength, const int actingBlockLength," +
            " const int actingVersion)\n" +
            "    {\n" +
            "        buffer_ = buffer;\n" +
            "        offset_ = offset;\n" +
            "        bufferLength_ = bufferLength;\n" +
            "        actingBlockLength_ = actingBlockLength;\n" +
            "        actingVersion_ = actingVersion;\n" +
            "        positionPtr_ = &position_;\n" +
            "        position(offset + actingBlockLength_);\n" +
            "    }\n\n" +
            "public:\n\n" +
            "%11$s" +
            "    static const %1$s sbeBlockLength(void)\n" +
            "    {\n" +
            "        return %2$s;\n" +
            "    }\n\n" +
            "    static const %3$s sbeTemplateId(void)\n" +
            "    {\n" +
            "        return %4$s;\n" +
            "    }\n\n" +
            "    static const %5$s sbeSchemaId(void)\n" +
            "    {\n" +
            "        return %6$s;\n" +
            "    }\n\n" +
            "    static const %7$s sbeSchemaVersion(void)\n" +
            "    {\n" +
            "        return %8$s;\n" +
            "    }\n\n" +
            "    static const char *sbeSemanticType(void)\n" +
            "    {\n" +
            "        return \"%9$s\";\n" +
            "    }\n\n" +
            "    sbe_uint64_t offset(void) const\n" +
            "    {\n" +
            "        return offset_;\n" +
            "    }\n\n" +
            "    %10$s &wrapForEncode(char *buffer, const int offset, const int bufferLength)\n" +
            "    {\n" +
            "        reset(buffer, offset, bufferLength, sbeBlockLength(), sbeSchemaVersion());\n" +
            "        return *this;\n" +
            "    }\n\n" +
            "    %10$s &wrapForDecode(char *buffer, const int offset, const int actingBlockLength, const int actingVersion," +
            " const int bufferLength)\n" +
            "    {\n" +
            "        reset(buffer, offset, bufferLength, actingBlockLength, actingVersion);\n" +
            "        return *this;\n" +
            "    }\n\n" +
            "    sbe_uint64_t position(void) const\n" +
            "    {\n" +
            "        return position_;\n" +
            "    }\n\n" +
            "    void position(const int position)\n" +
            "    {\n" +
            "        if (SBE_BOUNDS_CHECK_EXPECT((position > bufferLength_), false))\n" +
            "        {\n" +
            "            throw std::runtime_error(\"buffer too short [E100]\");\n" +
            "        }\n" +
            "        position_ = position;\n" +
            "    }\n\n" +
            "    int size(void) const\n" +
            "    {\n" +
            "        return position() - offset_;\n" +
            "    }\n\n" +
            "    char *buffer(void)\n" +
            "    {\n" +
            "        return buffer_;\n" +
            "    }\n\n" +
            "    int actingVersion(void) const\n" +
            "    {\n" +
            "        return actingVersion_;\n" +
            "    }\n",
            blockLengthType,
            generateLiteral(ir.headerStructure().blockLengthType(), Integer.toString(token.encodedLength())),
            templateIdType,
            generateLiteral(ir.headerStructure().templateIdType(), Integer.toString(token.id())),
            schemaIdType,
            generateLiteral(ir.headerStructure().schemaIdType(), Integer.toString(ir.id())),
            schemaVersionType,
            generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(token.version())),
            semanticType,
            className,
            generateConstructorsAndOperators(className)
        );
    }

    private CharSequence generateFields(final String containingClassName, final List tokens, final String indent)
    {
        final StringBuilder sb = new StringBuilder();

        for (int i = 0, size = tokens.size(); i < size; i++)
        {
            final Token signalToken = tokens.get(i);
            if (signalToken.signal() == Signal.BEGIN_FIELD)
            {
                final Token encodingToken = tokens.get(i + 1);
                final String propertyName = formatPropertyName(signalToken.name());

                sb.append(String.format(
                    "\n" +
                    indent + "    static const int %1$sId(void)\n" +
                    indent + "    {\n" +
                    indent + "        return %2$d;\n" +
                    indent + "    }\n\n",
                    propertyName,
                    signalToken.id()
                ));

                sb.append(String.format(
                    indent + "    static const int %1$sSinceVersion(void)\n" +
                    indent + "    {\n" +
                    indent + "         return %2$d;\n" +
                    indent + "    }\n\n" +
                    indent + "    bool %1$sInActingVersion(void)\n" +
                    indent + "    {\n" +
                    indent + "        return (actingVersion_ >= %2$d) ? true : false;\n" +
                    indent + "    }\n\n",
                    propertyName,
                    (long)signalToken.version()
                ));

                generateFieldMetaAttributeMethod(sb, signalToken, indent);

                switch (encodingToken.signal())
                {
                    case ENCODING:
                        sb.append(generatePrimitiveProperty(containingClassName, propertyName, encodingToken, indent));
                        break;

                    case BEGIN_ENUM:
                        sb.append(generateEnumProperty(containingClassName, propertyName, encodingToken, indent));
                        break;

                    case BEGIN_SET:
                        sb.append(generateBitsetProperty(propertyName, encodingToken, indent));
                        break;

                    case BEGIN_COMPOSITE:
                        sb.append(generateCompositeProperty(propertyName, encodingToken, indent));
                        break;
                }
            }
        }

        return sb;
    }

    private void generateFieldMetaAttributeMethod(final StringBuilder sb, final Token token, final String indent)
    {
        final Encoding encoding = token.encoding();
        final String epoch = encoding.epoch() == null ? "" : encoding.epoch();
        final String timeUnit = encoding.timeUnit() == null ? "" : encoding.timeUnit();
        final String semanticType = encoding.semanticType() == null ? "" : encoding.semanticType();

        sb.append(String.format(
            "\n" +
            indent + "    static const char *%sMetaAttribute(const MetaAttribute::Attribute metaAttribute)\n" +
            indent + "    {\n" +
            indent + "        switch (metaAttribute)\n" +
            indent + "        {\n" +
            indent + "            case MetaAttribute::EPOCH: return \"%s\";\n" +
            indent + "            case MetaAttribute::TIME_UNIT: return \"%s\";\n" +
            indent + "            case MetaAttribute::SEMANTIC_TYPE: return \"%s\";\n" +
            indent + "        }\n\n" +
            indent + "        return \"\";\n" +
            indent + "    }\n",
            token.name(),
            epoch,
            timeUnit,
            semanticType
        ));
    }

    private CharSequence generateEnumFieldNotPresentCondition(final int sinceVersion, final String enumName, final String indent)
    {
        if (0 == sinceVersion)
        {
            return "";
        }

        return String.format(
            indent + "        if (actingVersion_ < %1$d)\n" +
            indent + "        {\n" +
            indent + "            return %2$s::NULL_VALUE;\n" +
            indent + "        }\n\n",
            sinceVersion,
            enumName
        );
    }

    private CharSequence generateEnumProperty(
        final String containingClassName, final String propertyName, final Token token, final String indent)
    {
        final String enumName = token.name();
        final String typeName = cpp98TypeName(token.encoding().primitiveType());
        final int offset = token.offset();

        final StringBuilder sb = new StringBuilder();

        sb.append(String.format(
            "\n" +
            indent + "    %1$s::Value %2$s(void) const\n" +
            indent + "    {\n" +
                             "%3$s" +
            indent + "        return %1$s::get(%4$s(*((%5$s *)(buffer_ + offset_ + %6$d))));\n" +
            indent + "    }\n\n",
            enumName,
            propertyName,
            generateEnumFieldNotPresentCondition(token.version(), enumName, indent),
            formatByteOrderEncoding(token.encoding().byteOrder(), token.encoding().primitiveType()),
            typeName,
            offset
        ));

        sb.append(String.format(
            indent + "    %1$s &%2$s(const %3$s::Value value)\n" +
            indent + "    {\n" +
            indent + "        *((%4$s *)(buffer_ + offset_ + %5$d)) = %6$s(value);\n" +
            indent + "        return *this;\n" +
            indent + "    }\n",
            formatClassName(containingClassName),
            propertyName,
            enumName,
            typeName,
            offset,
            formatByteOrderEncoding(token.encoding().byteOrder(), token.encoding().primitiveType())
        ));

        return sb;
    }

    private Object generateBitsetProperty(final String propertyName, final Token token, final String indent)
    {
        final StringBuilder sb = new StringBuilder();

        final String bitsetName = formatClassName(token.name());
        final int offset = token.offset();

        sb.append(String.format(
            "\n" +
            indent + "private:\n" +
            indent + "    %1$s %2$s_;\n\n" +
            indent + "public:\n",
            bitsetName,
            propertyName
        ));

        sb.append(String.format(
            "\n" +
            indent + "    %1$s &%2$s()\n" +
            indent + "    {\n" +
            indent + "        %2$s_.wrap(buffer_, offset_ + %3$d, actingVersion_, bufferLength_);\n" +
            indent + "        return %2$s_;\n" +
            indent + "    }\n",
            bitsetName,
            propertyName,
            offset
        ));

        return sb;
    }

    private Object generateCompositeProperty(final String propertyName, final Token token, final String indent)
    {
        final String compositeName = formatClassName(token.name());
        final int offset = token.offset();

        final StringBuilder sb = new StringBuilder();

        sb.append(String.format(
            "\n" +
            "private:\n" +
            indent + "    %1$s %2$s_;\n\n" +
            "public:\n",
            compositeName,
            propertyName
        ));

        sb.append(String.format(
            "\n" +
            indent + "    %1$s &%2$s(void)\n" +
            indent + "    {\n" +
            indent + "        %2$s_.wrap(buffer_, offset_ + %3$d, actingVersion_, bufferLength_);\n" +
            indent + "        return %2$s_;\n" +
            indent + "    }\n",
            compositeName,
            propertyName,
            offset
        ));

        return sb;
    }

    private CharSequence generateNullValueLiteral(final PrimitiveType primitiveType, final Encoding encoding)
    {
        // Visual C++ does not handle minimum integer values properly
        // See: http://msdn.microsoft.com/en-us/library/4kh09110.aspx
        // So some of the null values get special handling
        if (null == encoding.nullValue())
        {
            switch (primitiveType)
            {
                case CHAR:
                case FLOAT:
                case DOUBLE:
                    break; // no special handling
                case INT8:
                    return "SBE_NULLVALUE_INT8";
                case INT16:
                    return "SBE_NULLVALUE_INT16";
                case INT32:
                    return "SBE_NULLVALUE_INT32";
                case INT64:
                    return "SBE_NULLVALUE_INT64";
                case UINT8:
                    return "SBE_NULLVALUE_UINT8";
                case UINT16:
                    return "SBE_NULLVALUE_UINT16";
                case UINT32:
                    return "SBE_NULLVALUE_UINT32";
                case UINT64:
                    return "SBE_NULLVALUE_UINT64";
            }
        }
        return generateLiteral(primitiveType, encoding.applicableNullValue().toString());
    }

    private CharSequence generateLiteral(final PrimitiveType type, final String value)
    {
        String literal = "";

        final String castType = cpp98TypeName(type);
        switch (type)
        {
            case CHAR:
            case UINT8:
            case UINT16:
            case INT8:
            case INT16:
                literal = "(" + castType + ")" + value;
                break;

            case UINT32:
            case INT32:
                literal = value;
                break;

            case FLOAT:
                if (value.endsWith("NaN"))
                {
                    literal = "SBE_FLOAT_NAN";
                }
                else
                {
                    literal = value + "f";
                }
                break;

            case INT64:
                literal = value + "L";
                break;

            case UINT64:
                literal = "0x" + Long.toHexString(Long.parseLong(value)) + "L";
                break;

            case DOUBLE:
                if (value.endsWith("NaN"))
                {
                    literal = "SBE_DOUBLE_NAN";
                }
                else
                {
                    literal = value;
                }
                break;
        }

        return literal;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy