public void Index(ushort id, ByteBlock oldValue, ByteBlock newValue) { RangeSet oldValueWords = _splitter.Split(oldValue); RangeSet newValueWords = _splitter.Split(newValue); for (int i = 0; i < oldValueWords.Count; ++i) { Range word = oldValueWords.Ranges[i]; ByteBlock wordBlock = new ByteBlock(oldValue.Array, word.Index, word.Length); RemoveWord(id, wordBlock); } for (int i = 0; i < newValueWords.Count; ++i) { Range word = newValueWords.Ranges[i]; ByteBlock wordBlock = new ByteBlock(newValue.Array, word.Index, word.Length); AddWord(id, wordBlock); } }
/// <summary> /// Get the IDs listed in the set for a given word and add them /// to a result ShortSet. /// </summary> /// <param name="setId">ID of set/word to add</param> /// <param name="result">ShortSet to which to add results</param> public unsafe void GetInSet(ushort setId, ShortSet result) { ByteBlock set = _sets[setId]; fixed(byte *array = set.Array) { if (set.Length < DenseSetLengthCutoff) { // Sparse Set: Add values as individual ushorts. ushort *valuesForWord = (ushort *)(array + set.Index); ushort usedLength = FindUsedLength(valuesForWord, (ushort)(set.Length / 2)); result.Or(valuesForWord, usedLength); } else { // Dense Set: Add values as ulong bits. ulong *bitsForWord = (ulong *)(array + set.Index); result.Or(bitsForWord, (ushort)(set.Length / 8)); } } }
/// <summary> /// Return the ByteBlock representation of the current value (cached). /// </summary> /// <returns>ByteBlock equivalent of value</returns> private ByteBlock ToByteBlock() { if (_cachedByteBlock.IsZero()) { if (_value is ByteBlock) { _cachedByteBlock = (ByteBlock)_value; } if (_value is ValueTypeReference <ByteBlock> ) { _cachedByteBlock = (_value as ValueTypeReference <ByteBlock>).Value; } else if (_value is string) { _cachedByteBlock = (ByteBlock)(string)_value; } else if (_value is byte[]) { _cachedByteBlock = (ByteBlock)(byte[])_value; } else if (_value is DateTime) { _cachedByteBlock = (ByteBlock)(((DateTime)_value).ToString("u", CultureInfo.InvariantCulture)); } else if (_value is ValueTypeReference <DateTime> ) { _cachedByteBlock = (ByteBlock)((_value as ValueTypeReference <DateTime>).Value.ToString("u", CultureInfo.InvariantCulture)); } else { _cachedByteBlock = (ByteBlock)_value.ToString(); } } return(_cachedByteBlock); }
/// <summary> /// Add a given item to a given set. /// </summary> /// <param name="setId">SetID (WordID) of word to add item to.</param> /// <param name="itemId">ItemID to add for word</param> public unsafe void AddToSet(ushort setId, ushort itemId) { ByteBlock set = _sets[setId]; fixed(byte *array = set.Array) { if (set.Length < DenseSetLengthCutoff) { // Sparse Set: Add values as individual ushorts. ushort *valuesForWord = (ushort *)(array + set.Index); ushort availableLength = (ushort)(set.Length / 2); ushort usedLength = FindUsedLength(valuesForWord, availableLength); // If this value was already added, stop if (usedLength > 0 && valuesForWord[usedLength - 1] == itemId) { return; } if (usedLength < availableLength) { // Set not full - append the new value valuesForWord[usedLength] = itemId; } else { // Set is full - create a new one if (set.Length * 2 >= DenseSetLengthCutoff) { // At cutoff - convert to dense set byte[] newDenseBlock = new byte[ushort.MaxValue / 8]; fixed(byte *newArray = newDenseBlock) { ulong *newBits = (ulong *)(newArray); for (int i = 0; i < usedLength; ++i) { ushort id = valuesForWord[i]; newBits[id / 64] |= (ShortSet.FirstBit >> id % 64); } newBits[itemId / 64] |= (ShortSet.FirstBit >> itemId % 64); } _sets[setId] = newDenseBlock; } else { // Below cutoff - keep sparse set byte[] newBlock = new byte[Math.Max(2, set.Length * 2)]; // Copy current values set.CopyTo(newBlock); fixed(byte *newArray = newBlock) { ushort *newValues = (ushort *)newArray; // Add new value newValues[usedLength] = itemId; // Pad remainder with sentinel maxvalue for (int i = usedLength + 1; i < newBlock.Length / 2; ++i) { newValues[i] = ushort.MaxValue; } } _sets[setId] = newBlock; } } } else { // Dense Set: Turn on the bit for the value ulong *bitsForWord = (ulong *)(array + set.Index); bitsForWord[itemId / 64] |= (ShortSet.FirstBit >> itemId % 64); } } }