/// <summary> /// Store a delta of delta for the rest of the values in one of the /// following ways /// /// '0' = delta of delta did not change /// '10' followed by a value length of 7 /// '110' followed by a value length of 9 /// '1110' followed by a value length of 12 /// '1111' followed by a value length of 32 /// </summary> /// <param name="date"></param> public bool AppendTimestamp(DateTime date) { int timestamp = ToUnixTime(date); int delta = timestamp - _previousTimestamp; if (delta < MinTimeStampDelta && _previousTimestamp != 0) { return(false); } if (_hasStoredFirstValue == false) { // Store the first timestamp as it. _buffer.AddValue(timestamp, Constants.BitsForFirstTimestamp); _previousTimestamp = timestamp; _previousTimestampDelta = Constants.DefaultDelta; _hasStoredFirstValue = true; return(true); } int deltaOfDelta = delta - _previousTimestampDelta; if (deltaOfDelta == 0) { _previousTimestamp = timestamp; _buffer.AddValue(0, 1); return(true); } if (deltaOfDelta > 0) { // We don't use zero (its handled above). Shift down 1 so we fit in X number of bits. deltaOfDelta--; } int absValue = Math.Abs(deltaOfDelta); foreach (var timestampEncoding in TimestampEncodingDetails.Encodings) { if (absValue < timestampEncoding.MaxValueForEncoding) { _buffer.AddValue(timestampEncoding.ControlValue, timestampEncoding.ControlValueBitLength); // Make this value between [0, 2^timestampEncodings[i].bitsForValue - 1] long encodedValue = deltaOfDelta + timestampEncoding.MaxValueForEncoding; _buffer.AddValue(encodedValue, timestampEncoding.BitsForValue); break; } } _previousTimestamp = timestamp; _previousTimestampDelta = delta; return(true); }
/// <summary> /// Doubles are encoded by XORing them with the previous value. If /// XORing results in a zero value (value is the same as the previous /// value), only a single zero bit is stored, otherwise 1 bit is /// stored. /// /// For non-zero XORred results, there are two choices: /// /// 1) If the block of meaningful bits falls in between the block of /// previous meaningful bits, i.e., there are at least as many /// leading zeros and as many trailing zeros as with the previous /// value, use that information for the block position and just /// store the XORred value. /// /// 2) Length of the number of leading zeros is stored in the next 5 /// bits, then length of the XORred value is stored in the next 6 /// bits and finally the XORred value is stored. /// </summary> /// <param name="value"></param> public void AppendValue(double value) { long longValue = BitConverter.DoubleToInt64Bits(value); long xorWithPrevious = _previousValue ^ longValue; if (xorWithPrevious == 0) { // It's the same value. _buffer.AddValue(0, 1); return; } _buffer.AddValue(1, 1); var currentBlockInfo = BlockInfo.CalulcateBlockInfo((ulong)xorWithPrevious); int expectedSize = Constants.LeadingZerosLengthBits + Constants.BlockSizeLengthBits + currentBlockInfo.BlockSize; if (currentBlockInfo.LeadingZeros >= _previousBlockInfo.LeadingZeros && currentBlockInfo.TrailingZeros >= _previousBlockInfo.TrailingZeros && _previousBlockInfo.BlockSize < expectedSize) { // Control bit saying we should use the previous block information _buffer.AddValue(1, 1); // Write the parts of the value that changed. long blockValue = xorWithPrevious >> _previousBlockInfo.TrailingZeros; _buffer.AddValue(blockValue, _previousBlockInfo.BlockSize); } else { // Control bit saying we need to provide new block information _buffer.AddValue(0, 1); // Details about the new block information _buffer.AddValue(currentBlockInfo.LeadingZeros, Constants.LeadingZerosLengthBits); _buffer.AddValue(currentBlockInfo.BlockSize - Constants.BlockSizeAdjustment, Constants.BlockSizeLengthBits); // Write the parts of the value that changed. long blockValue = xorWithPrevious >> currentBlockInfo.TrailingZeros; _buffer.AddValue(blockValue, currentBlockInfo.BlockSize); _previousBlockInfo = currentBlockInfo; } _previousValue = longValue; }