private static void generateGroupClassHeader(
        final StringBuilder sb,
        final String groupClassName,
        final List<Token> tokens,
        final int index,
        final String indent,
        final List<Token> fields,
        final List<Token> groups)
    {
        final String dimensionsClassName = formatClassName(tokens.get(index + 1).name());
        final int dimensionHeaderLength = tokens.get(index + 1).encodedLength();
        final int blockLength = tokens.get(index).encodedLength();
        final Token blockLengthToken = Generators.findFirst("blockLength", tokens, index);
        final Token numInGroupToken = Generators.findFirst("numInGroup", tokens, index);
        final String golangTypeBlockLength = goTypeName(blockLengthToken.encoding().primitiveType());
        final String golangTypeNumInGroup = goTypeName(numInGroupToken.encoding().primitiveType());

        new Formatter(sb).format("\n" +
            indent + "type %1$s struct {\n" +
            indent + "    buffer         []byte\n" +
            indent + "    bufferLength   uint64\n" +
            indent + "    initialPosition uint64\n" +
            indent + "    positionPtr    *uint64\n" +
            indent + "    blockLength    uint64\n" +
            indent + "    count          uint64\n" +
            indent + "    index          uint64\n" +
            indent + "    offset         uint64\n" +
            indent + "    actingVersion  uint64\n",
            groupClassName);

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

                switch (encodingToken.signal())
                {
                    case BEGIN_SET:
                    case BEGIN_COMPOSITE:
                        new Formatter(sb).format(indent + "    _%1$s %2$s\n",
                            propertyName,
                            typeName);
                        break;

                    default:
                        break;
                }
            }
        }

        for (int i = 0, size = groups.size(); i < size; )
        {
            final Token token = groups.get(i);
            if (token.signal() == Signal.BEGIN_GROUP)
            {
                final String propertyName = formatPropertyName(token.name());
                final String groupName = groupClassName + formatClassName(token.name());

                new Formatter(sb).format(indent + "    _%1$s %2$s\n",
                    propertyName,
                    groupName);
                i += token.componentTokenCount();
            }
        }

        new Formatter(sb).format(
            indent + "}\n\n" +
            indent + "func (g *%1$s) sbePositionPtr() *uint64 {\n" +
            indent + "    return g.positionPtr\n" +
            indent + "}\n\n",
            groupClassName);

        new Formatter(sb).format(
            indent + "func (g *%3$s) WrapForDecode(\n" +
            indent + "    buffer []byte,\n" +
            indent + "    pos *uint64,\n" +
            indent + "    actingVersion uint64,\n" +
            indent + "    bufferLength uint64) {\n" +
            indent + "    dimensions := %2$s{}\n" +
            indent + "    dimensions.Wrap(buffer, *pos, actingVersion, bufferLength)\n" +
            indent + "    g.buffer = buffer\n" +
            indent + "    g.bufferLength = bufferLength\n" +
            indent + "    g.blockLength = uint64(dimensions.BlockLength())\n" +
            indent + "    g.count = uint64(dimensions.NumInGroup())\n" +
            indent + "    g.index = 0\n" +
            indent + "    g.actingVersion = actingVersion\n" +
            indent + "    g.initialPosition = *pos\n" +
            indent + "    g.positionPtr = pos\n" +
            indent + "    *g.positionPtr = *g.positionPtr + %1$d\n" +
            indent + "}\n",
            dimensionHeaderLength, dimensionsClassName, groupClassName);

        final long minCount = numInGroupToken.encoding().applicableMinValue().longValue();
        final String minCheck = minCount > 0 ? "count < " + minCount + " || " : "";

        new Formatter(sb).format("\n" +
            indent + "func (g *%8$s) WrapForEncode(\n" +
            indent + "    buffer []byte,\n" +
            indent + "    count %3$s,\n" +
            indent + "    pos *uint64,\n" +
            indent + "    actingVersion uint64,\n" +
            indent + "    bufferLength uint64) {\n" +
            indent + "    if %5$scount > %6$d {\n" +
            indent + "        panic(\"count outside of allowed range [E110]\")\n" +
            indent + "    }\n" +
            indent + "    g.buffer = buffer\n" +
            indent + "    g.bufferLength = bufferLength\n" +
            indent + "    dimensions := %7$s{}\n" +
            indent + "    dimensions.Wrap(buffer, *pos, actingVersion, bufferLength)\n" +
            indent + "    dimensions.SetBlockLength(%2$d)\n" +
            indent + "    dimensions.SetNumInGroup(count)\n" +
            indent + "    g.index = 0\n" +
            indent + "    g.count = uint64(count)\n" +
            indent + "    g.blockLength = %2$d\n" +
            indent + "    g.actingVersion = actingVersion\n" +
            indent + "    g.initialPosition = *pos\n" +
            indent + "    g.positionPtr = pos\n" +
            indent + "    *g.positionPtr = *g.positionPtr + %4$d\n" +
            indent + "}\n",
            golangTypeBlockLength,
            blockLength,
            golangTypeNumInGroup,
            dimensionHeaderLength,
            minCheck,
            numInGroupToken.encoding().applicableMaxValue().longValue(),
            dimensionsClassName,
            groupClassName);

        new Formatter(sb).format("\n" +
            indent + "func (g *%3$s) SbeHeaderSize() uint64 {\n" +
            indent + "    return %1$d\n" +
            indent + "}\n\n" +

            indent + "func (g *%3$s) SbeBlockLength() uint64 {\n" +
            indent + "    return %2$d\n" +
            indent + "}\n\n" +

            indent + "func (g *%3$s) SbePosition() uint64 {\n" +
            indent + "    return *g.positionPtr\n" +
            indent + "}\n\n" +

            indent + "func (g *%3$s) SbeCheckPosition(position uint64) uint64 {\n" +
            indent + "    if position > g.bufferLength {\n" +
            indent + "        panic(\"buffer too short [E100]\")\n" +
            indent + "    }\n" +
            indent + "    return position\n" +
            indent + "}\n\n" +

            indent + "func (g *%3$s) SetSbePosition(position uint64) {\n" +
            indent + "    *g.positionPtr = g.SbeCheckPosition(position)\n" +
            indent + "}\n\n" +

            indent + "func (g *%3$s) Count() uint64 {\n" +
            indent + "    return g.count\n" +
            indent + "}\n\n" +

            indent + "func (g *%3$s) HasNext() bool {\n" +
            indent + "    return g.index < g.count\n" +
            indent + "}\n\n" +

            indent + "func (g *%3$s) Next() *%3$s {\n" +
            indent + "    if g.index >= g.count {\n" +
            indent + "        panic(\"index >= count [E108]\")\n" +
            indent + "    }\n" +
            indent + "    g.offset = *g.positionPtr\n" +
            indent + "    if g.offset+g.blockLength > g.bufferLength {\n" +
            indent + "        panic(\"buffer too short for next group index [E108]\")\n" +
            indent + "    }\n" +
            indent + "    *g.positionPtr = g.offset + g.blockLength\n" +
            indent + "    g.index++\n\n" +

            indent + "    return g\n" +
            indent + "}\n",
            dimensionHeaderLength,
            blockLength,
            groupClassName);
        sb.append("\n")
            .append(indent).append("func (g *").append(groupClassName)
            .append(") ResetCountToIndex() uint64 {\n")
            .append(indent).append("    g.count = g.index\n")
            .append(indent).append("    dimensions := ").append(dimensionsClassName).append("{}\n")
            .append(indent).append("    dimensions.Wrap")
            .append("(g.buffer, g.initialPosition, g.actingVersion, g.bufferLength)\n")
            .append(indent)
            .append("    dimensions.SetNumInGroup(").append(golangTypeNumInGroup).append("(g.count))\n")
            .append(indent).append("    return g.count\n")
            .append(indent).append("}\n\n");

        sb.append("\n")
            .append(indent).append("func (g *").append(groupClassName)
            .append(") ForEach(fn func(group *").append(groupClassName).append(")) {\n")
            .append(indent).append("    for g.HasNext() {\n")
            .append(indent).append("        g.Next()\n")
            .append(indent).append("        fn(g)\n")
            .append(indent).append("    }\n")
            .append(indent).append("}\n\n");
    }
Create a new Golang language {@link CodeGenerator}.

@param ir                            for the messages and types.
@param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding.
@param outputManager                 for generating the codecs to.
sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java