FIX FAST教程 (4) 字段操作符

3.3.4.6. 默认操作符(Default Operator)

关联此操作符的默认值被添加到输出消息中,除非该值已包含在编码的消息中。
下图显示了用默认操作符定义的字段的解码算法:
请添加图片描述
该算法的实现:

    public int decode(byte[] encodedData, int offset, PresenceMap presenceMap, OutputMessage message) {
        Object decodedValue = null;
        if (presenceMap.hasNextPresenceBit()) {
            offset = dataTypeDecoder.decode(encodedData, offset, templateField);
            decodedValue = getFieldValue();
        } else {
            decodedValue = getInitialValue();
        } 
        if (decodedValue != null) {
            message.addValue(tagId, decodedValue);
        } else {
            if (isMandatory) {
                throw new RuntimeException("Mandatory field decoded value can not be NULL");
        }
        return offset;
    }
    
    public void reset() {
        // Default fields never change their initial value so there is no need to reset them
    }
    
    public boolean isPMapBitExist() {
        // Default fields require presence map bit
        return true;
    }
    
    public boolean isFieldNullable() {
        // If isMandatory false the Default field could has the null representation of field value and does not apear in the output fix message
        return !isMandatory;
    }
3.3.4.7. 差值操作符(Delta Operator)

差值操作符(可变增量操作符)将编码消息中的传入值与“前值”结合起来。因此,如果上次解码的值(前值)为150(对于整数字段),并且编码消息中的传入值为-5,则输出值为145。
下图说明了该运算符的算法。
请添加图片描述
该算法的代码示例:

    public int decode(byte[] encodedData, int offset, PresenceMap presenceMap, OutputMessage message) {
        
        offset = dataTypeDecoder.decode(encodedData, offset, templateField);
        if (getFieldValue() != null) {
            if (getPreviousValue() != null) {
                calculateDeltaFieldValue();
                Object fieldValue = getFieldValue();
                message.addValue(tagId, fieldValue);
                setPreviousValue(fieldValue);
            } else {
                throw new RuntimeException("Mandatory decoded field can not be NULL");
            }
        } else {
            if (isMandatory) {
                throw new RuntimeException("Mandatory field decoded value can not be NULL");
            }
        }       
        return offset;
    }

    public void reset() {
        // This functionality delivers previous value from the undefinite status 
        Object prevValue = getInitialValue();
        if (prevValue == null) {
            prevValue = getFieldBaseValue();
        }
        setPreviousValue(prevValue);
    }
    
    public boolean isPMapBitExist() {
        // Delta fields not require presence map bit. In any casy it should be in encoded message
        return false;
    }
    
    public boolean isFieldNullable() {
        // If isMandatory false the Delta field could has the null representation of field value and does not apear in the output fix message
        return !isMandatory;
    }
2.3.4.8. 递增操作符(Increment Operator)

如果该字段值出现在编码的输入消息中(其PMap位已设置),则将解码出来的值用作输出值。否则,递增操作符(固定增量操作符)使用“前值”并对其加1以产生输出值。为下一次操作,该输出值被更新为“前值”。
该运算符仅适用于整数。

下图演示了递增操作符解码算法:
请添加图片描述
该算法的实现:

    public int decode(byte[] encodedData, int offset, PresenceMap presenceMap, OutputMessage message) {
        if (presenceMap.hasNextPresenceBit()) {
            offset = dataTypeDecoder.decode(encodedData, offset, templateField);
            Object decodedValue = getFieldValue();
            if (decodedValue != null) {
                message.addValue(tagId, decodedValue);
                setPreviousValue(decodedValue);
                isUndefinedPrevValue = false;
            } else {
                if (isMandatory) {
                    throw new RuntimeException("Mandatory field decoded value can not be NULL");
                } else {
                    setPreviousValue(null);
                }
            } 
        } else {
            if (getPreviousValue() != null) {
                if (!isUndefinedPrevValue) {
                    incrementPrevFieldValue();
                }
                // add field into the message
                message.addValue(tagId, getPreviousValue());
            } else {
                if (isMandatory) {
                    throw new RuntimeException("Mandatory field decoded value can not be NULL");
                }
            }
        }
        return offset;
    }
    
    public void reset() {
        // The field delivers previous value from the undefinite status 
        setPreviousValue(getInitialValue());
        isUndefinedPrevValue = true;
    }

    public boolean isPMapBitExist() {
        // Increment fields require presence map bit
        return true;
    }
    
    public boolean isFieldNullable() {
        // If isMandatory false the Increment field could has the null representation of field value and does not apear in the output fix message
        return !isMandatory;
    }
3.3.4.9. 尾部操作符(Tail Operator)

该操作符指定要删除的字符数和要追加到“前值”的字符。也就是说,输出值是通过组合“前值”- ‘n’个字符(其中’n’是来自输入消息的int) +来自输入编码消息的解码字段值(尾值 - tail)获得的。
对于该操作符,尾值是可选的。
此操作符可应用于稍后定义的数据类型字符串(string)和字节向量(byte vector)。

这张图展示了尾部操作符的解码算法:

请添加图片描述
该算法的实现:

    public int decode(byte[] encodedData, int offset, PresenceMap presenceMap, OutputMessage message) {
       if (presenceMap.hasNextPresenceBit()) {
            offset = dataTypeDecoder.decode(encodedData, offset, templateField);
            Object decodedValue = getFieldValue();
            if (decodedValue != null) {
                if (getPreviousValue() == null) {
                    Object prevValue = getInitialValue();
                    if (prevValue == null) {
                        prevValue = getFieldBaseValue();
                    }
                    setPreviousValue(prevValue);
                }
                calculateCombineValue();
                decodedValue = getFieldValue();
                message.addValue(tagId, decodedValue);
                setPreviousValue(decodedValue);
            } else {
                if (isMandatory) {
                    logger.logError("Mandatory field decoded value can not be NULL");
                } else {
                    setPreviousValue(null);
                }
            }
        } else {
            Object prevValue = getPreviousValue();
            if (prevValue != null) {
                message.addValue(tagId, prevValue);
            } else {
                if (isMandatory) {
                    logger.logError("Mandatory field decoded value can not be NULL");
                }
            }
        }
        return offset;
    }
    
    public void reset() {
        // The field delivers previous value from the undefinite status 
        setPreviousValue(getInitialValue());
    }

    public boolean isPMapBitExist() {
        // ~~ Tail fields require presence map bit
        return true;
    }
    
    public boolean isFieldNullable() {
        // If isMandatory false the Delta field could has the null representation of field value and does not apear in the output fix message
        return !isMandatory;
    }
3.3.5. 序列(Sequence)

如前所述,FAST消息模板由模板单元组成。模板单元要么是模板字段,要么是序列。
序列是一组字段,包括:

  • 如果后续有此序列的实例,则表示其数目的序列长度(length)。
  • 字段组(field group)重复“序列长度”次,每个都从自己的PMap开始。

序列的解码算法如下:
请添加图片描述
随着“序列”概念的引入,我们需要扩展字段解码算法,如图所示。

请添加图片描述
下面的例子展示了" sequence "的TemplateUnit接口的一个例子实现:

    private TemplateField sequenceLength;
    private TemplateUnit[] templateFields;
    
    public int decode(byte[] encodedData, int offset, PresenceMap presenceMap, OutputMessage message) {
        offset = sequenceLength.decode(buffer, offset, presenceMap, message);
        if (sequenceLength.getFieldValue() != null) {
            int groupsCount = sequenceLength.getFieldValue();
            if (groupsCount > 0) {
                message.createFieldsSequence(sequenceLength.getTagId(), groupsCount);
                for (int iter = 0; iter < groupsCount; iter++) {
                    presenceMap = new PresenceMap();
                    if (isPMapRequired) {	// 注意此段代码
                        presenceMap.init(buffer, offset);
                        offset = presenceMap.getLastPMapBytePosition() + 1;
                    }

                    for (int i = 1; i < templateFields.length; i++) {
                        offset = templateFields[i].decode(buffer, offset, presenceMap, message);
                    }
                }
            }
        } else {
            if (isMandatory) {
                throw new RuntimeException("A mandatory sequence is missing from the stream.");
            }
        }
        return offset;
    }
        
    public void reset() {
        for (int i = 1; i < templateFields.length; i++) {
            templateFields[i].reset();
        }
    }

注意:

在上面的代码中,如果序列中的任何模板字段需要PMap位,则布尔变量isPMapRequired为true。根据FAST,如果不需要PMap位(即,所有字段将始终存在于已编码的消息中或强制常量),则字段组之前将没有PMap,因此将使用空PMap。

方法isPMapRequired()可以用以下代码片段实现:

   isPMapRequired = false;
    for (TemplateField field : templateFields) {
        if (field.isPMapBitExist()) {
            isPMapRequired = true;
            break;
        }
    }

序列解码示例:
让我们考虑一个具有以下模板的小消息

<templates xmlns="http://www.fixprotocol.org/ns/fast/td/1.1" xmlns:scp="http://www.fixprotocol.org/ns/fast/scp/1.1">
  <template name="Market Data Incremental" id="35">
    <string name="MsgType" id="35">
      <constant value="X"/>
    </string>
    <sequence name="MDIncGrp">
      <length name="NoMDEntries" id="268">
        <constant/>
      </length>
      <string name="TradingSessionID" id="336">
        <default value="2" />
      </string>
      <uInt32 name="MDUpdateAction" id="279">
        <copy/>
      </uInt32>
    </sequence>
  </template>
</templates>

我们输入的FAST消息: 0xC0 0xA3 0x81 0xA0 0x80 = 11000000 10100011 10000001 10100000 10000000
下表显示了此消息的完整解码:

在这里插入图片描述
收集我们的字段后,输出消息将是:35=X|268=1|336=2|279=0

原文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值