private static Encoder choiceEncoder(final Encoding encoding)
    {
        final long choiceBitIdx = encoding.constValue().longValue();
        final PrimitiveType type = encoding.primitiveType();
        switch (type)
        {
            case UINT8:
            case INT8:
                return (builder, buffer, offset, limit) ->
                {
                    buffer.checkLimit(offset + BitUtil.SIZE_OF_BYTE);
                    final byte oldValue = buffer.getByte(offset);
                    final byte newValue = (byte)(oldValue | (1 << choiceBitIdx));
                    buffer.putByte(offset, newValue);
                    builder.appendLine().append("oldValue: ").append(oldValue);
                    builder.appendLine().append(newValue).append(" @ ").append(offset)
                        .append("[").append(BitUtil.SIZE_OF_BYTE).append("]");
                };

            case UINT16:
            case INT16:
                return (builder, buffer, offset, limit) ->
                {
                    buffer.checkLimit(offset + BitUtil.SIZE_OF_SHORT);
                    final short oldValue = buffer.getShort(offset, encoding.byteOrder());
                    final short newValue = (short)(oldValue | (1 << choiceBitIdx));
                    buffer.putShort(offset, newValue, encoding.byteOrder());
                    builder.appendLine().append("oldValue: ").append(oldValue);
                    builder.appendLine().append(newValue).append(" @ ").append(offset)
                        .append("[").append(BitUtil.SIZE_OF_SHORT).append("]");
                };

            case UINT32:
            case INT32:
                return (builder, buffer, offset, limit) ->
                {
                    buffer.checkLimit(offset + BitUtil.SIZE_OF_INT);
                    final int oldValue = buffer.getInt(offset, encoding.byteOrder());
                    final int newValue = oldValue | (1 << choiceBitIdx);
                    buffer.putInt(offset, newValue, encoding.byteOrder());
                    builder.appendLine().append("oldValue: ").append(oldValue);
                    builder.appendLine().append(newValue).append(" @ ").append(offset)
                        .append("[").append(BitUtil.SIZE_OF_INT).append("]");
                };

            case UINT64:
            case INT64:
                return (builder, buffer, offset, limit) ->
                {
                    buffer.checkLimit(offset + BitUtil.SIZE_OF_LONG);
                    final long oldValue = buffer.getLong(offset, encoding.byteOrder());
                    final long newValue = oldValue | (1L << choiceBitIdx);
                    buffer.putLong(offset, newValue, encoding.byteOrder());
                    builder.appendLine().append("oldValue: ").append(oldValue);
                    builder.appendLine().append(newValue).append(" @ ").append(offset)
                        .append("[").append(BitUtil.SIZE_OF_LONG).append("]");
                };

            default:
                throw new IllegalArgumentException("Unsupported type: " + type);
        }
    }
This combinator adds duplicates to an arbitrary list. We prefer this to JQwik's built-in functionality,
as that is inefficient and dominates test runs.
<p>
This method works by generating a list of integers, which represent, in an alternating manner,
the number of items to skip before <i>selecting</i> an item to duplicate
and the number of items to skip before <i>inserting</i> the duplicate.

@param maxDuplicates the maximum number of duplicates to add
@param arbitrary     the arbitrary list to duplicate items in
@param <T>           the type of the list
@return an arbitrary list with duplicates
sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java