예제 #1
0
 public StringId CreateOrUpdateItem(StringId oldItem, bool hasOldItem, out bool remove)
 {
     remove = false;
     return(m_stringTable.AddStringToBuffer(m_sought));
 }
예제 #2
0
        /// <summary>
        /// Determines whether a string matches an entry in the table in an ordinally case-insensitive way.
        /// </summary>
        /// <remarks>
        /// This method is thread-safe.
        /// </remarks>
        internal bool CaseInsensitiveEquals(StringId id1, StringId id2)
        {
            Contract.Requires(id1.IsValid);
            Contract.Requires(id2.IsValid);
            Contract.Requires(IsValid());

            if (id1 == id2)
            {
                return(true);
            }

            int index1 = id1.Value & BytesPerBufferMask;

            byte[] buffer1 = m_byteBuffers[(id1.Value >> BytesPerBufferBits) & NumByteBuffersMask];

            int length1 = buffer1[index1++];

            if (length1 == LongStringMarker)
            {
                Contract.Assume(index1 + 4 <= buffer1.Length);

                length1 = (buffer1[index1++] << 24)
                          | (buffer1[index1++] << 16)
                          | (buffer1[index1++] << 8)
                          | (buffer1[index1++] << 0);
            }

            int index2 = id2.Value & BytesPerBufferMask;

            byte[] buffer2 = m_byteBuffers[(id2.Value >> BytesPerBufferBits) & NumByteBuffersMask];

            int length2 = buffer2[index2++];

            if (length2 == LongStringMarker)
            {
                Contract.Assume(index2 + 4 <= buffer2.Length);

                length2 = (buffer2[index2++] << 24)
                          | (buffer2[index2++] << 16)
                          | (buffer2[index2++] << 8)
                          | (buffer2[index2++] << 0);
            }

            if (length1 != length2)
            {
                // different lengths
                return(false);
            }

            if (buffer1[index1] != Utf16Marker)
            {
                Contract.Assume((index1 + length1) <= buffer1.Length);
                Contract.Assume((index2 + length2) <= buffer2.Length);

                // characters are 8 bits
                for (int i = 0; i < length1; i++)
                {
                    var ch1 = (char)buffer1[index1 + i];
                    var ch2 = (char)buffer2[index2 + i];
                    if (ch1.ToUpperInvariantFast() != ch2.ToUpperInvariantFast())
                    {
                        return(false);
                    }
                }
            }
            else
            {
                if (buffer2[index1] != Utf16Marker)
                {
                    // different marker bytes
                    return(false);
                }

                Contract.Assume((index1 + (length1 * 2) + 1) <= buffer1.Length);
                Contract.Assume((index2 + (length2 * 2) + 1) <= buffer2.Length);

                // characters are 16 bits
                index1++; // skip the marker
                index2++; // skip the marker
                for (int i = 0; i < length1; i++)
                {
                    var ch1 = (char)((buffer1[index1 + (2 * i)] << 8) | buffer1[index1 + (2 * i) + 1]);
                    var ch2 = (char)((buffer2[index2 + (2 * i)] << 8) | buffer2[index2 + (2 * i) + 1]);
                    if (ch1.ToUpperInvariantFast() != ch2.ToUpperInvariantFast())
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
예제 #3
0
 public bool Equals(StringId other)
 {
     return(m_stringTable.Equals(m_sought, other));
 }
예제 #4
0
 /// <summary>
 /// Writes a StringId
 /// </summary>
 public virtual void Write(StringId value)
 {
     Start <StringId>();
     Write(value.Value);
     End();
 }
예제 #5
0
 internal int CopyString(StringId id, char[] destination, int destinationIndex, bool isEndIndex = false)
 {
     return(CopyString(id, ref destination, destinationIndex, isEndIndex: isEndIndex, allowResizeBuffer: false));
 }
예제 #6
0
        private StringId AddStringToBuffer <T>(T seg) where T : struct, ICharSpan <T>
        {
            Contract.Requires(IsValid());
            Contract.Ensures(Contract.Result <StringId>().IsValid);

            // Not in the set, so get some space to hold the string
            //
            // Note that this call is invoked in a racy setting. It's possible for multiple calls to execute concurrently and
            // try to insert the same string N times. We allow this and end up just wasting space in the table when this happens.
            // In this context, m_count thus accounts for the total number of strings inserted into the table, and not the potential
            // smaller of logical strings known to the table.
            bool longString = seg.Length >= 255;

            int space = 1;

            if (longString)
            {
                // if the length >= 255 then we store it as a marker byte followed by a 4-byte length value
                space += 4;
            }

            // see if the string is pure ASCII
            bool isAscii = seg.OnlyContains8BitChars;

            if (isAscii)
            {
                // stored as bytes
                space += seg.Length;
            }
            else
            {
                // stored as UTF-16
                space += (seg.Length * 2) + 1; // *2 for UTF-16, +1 for the 'switch to unicode' marker byte
            }

            // count how many strings are in the buffer
            Interlocked.Increment(ref m_count);

            int byteIndex;
            int bufferNum;

            // loop until we find a suitable location to copy the string to
            while (true)
            {
                // get the next possible location for the string
                int current = Volatile.Read(ref m_nextId);
                bufferNum = (current >> BytesPerBufferBits) & NumByteBuffersMask;
                byteIndex = current & BytesPerBufferMask;

                // is the available space big enough?
                if (space < BytesPerBuffer - byteIndex)
                {
                    // there's room in the buffer so try to claim it
                    int next = (bufferNum << BytesPerBufferBits) | (byteIndex + space);
                    if (Interlocked.CompareExchange(ref m_nextId, next, current) == current)
                    {
                        // got some room, now go fill it in
                        break;
                    }

                    // go try again...
                    continue;
                }

                // the string doesn't fit in the current buffer, we need a new buffer
                int newBufferSize = BytesPerBuffer;
                if (space > BytesPerBuffer)
                {
                    newBufferSize = space;
                }

                bufferNum++;

                // Make sure we don't overflow the buffer we're indexing into
                if (bufferNum >= NumByteBuffers)
                {
                    Contract.Assert(false, $"Exceeded the number of ByteBuffers allowed in this StringTable: {bufferNum} >= {NumByteBuffers}");
                }

                lock (m_byteBuffers)
                {
                    if (m_byteBuffers[bufferNum] != null)
                    {
                        // somebody racily beat us and allocated this buffer, so just retry the whole thing from scratch
                        continue;
                    }

                    // allocate a new buffer
                    m_byteBuffers[bufferNum] = new byte[newBufferSize];

                    if (space >= BytesPerBuffer)
                    {
                        // force writing into a fresh buffer
                        Volatile.Write(ref m_nextId, (bufferNum << BytesPerBufferBits) | BytesPerBufferMask);
                    }
                    else
                    {
                        // force writing into this new buffer
                        Volatile.Write(ref m_nextId, (bufferNum << BytesPerBufferBits) | space);
                    }

                    // go write the string at the base of the new buffer
                    byteIndex = 0;
                    break;
                }
            }

#if DebugStringTable
            var stringId = new StringId((bufferNum << BytesPerBufferBits) + byteIndex, m_debugIndex);
#else
            var stringId = new StringId((bufferNum << BytesPerBufferBits) + byteIndex);
#endif

            Contract.Assert(stringId.IsValid);

            // now copy the string data into the buffer
            byte[] currentBuffer = m_byteBuffers[bufferNum];
            if (longString)
            {
                currentBuffer[byteIndex++] = LongStringMarker;
                Bits.WriteInt32(currentBuffer, ref byteIndex, seg.Length);
            }
            else
            {
                currentBuffer[byteIndex++] = (byte)seg.Length;
            }

            if (isAscii)
            {
                seg.CopyAs8Bit(currentBuffer, byteIndex);
            }
            else
            {
                currentBuffer[byteIndex++] = Utf16Marker;
                seg.CopyAs16Bit(currentBuffer, byteIndex);
            }

            return(stringId);
        }
예제 #7
0
 internal static int GetHashCode(StringId id)
 {
     return(id.Value);
 }