Beispiel #1
0
        public ByteString From(short value, ByteStringType type = ByteStringType.Mutable)
        {
            var result = AllocateInternal(sizeof(short), type);

            ((short *)result._pointer->Ptr)[0] = value;

            RegisterForValidation(result);
            return(result);
        }
Beispiel #2
0
        public ByteString From(byte value, ByteStringType type = ByteStringType.Mutable)
        {
            var result = AllocateInternal(1, type);

            result._pointer->Ptr[0] = value;

            RegisterForValidation(result);
            return(result);
        }
Beispiel #3
0
        public ByteStringContext.InternalScope ToSlice(ByteStringContext context, ByteStringType type, out Slice str)
        {
            var        buffer = ToBuffer();
            ByteString byteString;
            var        scope = context.From(buffer, 0, buffer.Length, type, out byteString);

            str = new Slice(byteString);
            return(scope);
        }
Beispiel #4
0
        public void SetUserDefinedFlags(ByteStringType flags)
        {
            if ((flags & ByteStringType.ByteStringMask) != 0)
            {
                throw new ArgumentException("The flags passed contains reserved bits.");
            }

            _pointer->Flags |= flags;
        }
Beispiel #5
0
        public ByteString FromPtr(byte *valuePtr, int size, ByteStringType type = ByteStringType.Mutable | ByteStringType.External)
        {
            Debug.Assert(valuePtr != null, $"{nameof(valuePtr)} cant be null.");
            Debug.Assert(size >= 0, $"{nameof(size)} cannot be negative.");

            var result = AllocateExternal(valuePtr, size, type | ByteStringType.External); // We are allocating external, so we will force it (even if we are checking for it in debug).

            RegisterForValidation(result);

            return(result);
        }
Beispiel #6
0
        private ByteString AllocateWholeSegment(int length, ByteStringType type)
        {
            // The allocation is big, therefore we will just allocate the segment and move on.
            var segment = AllocateSegment(length + sizeof(ByteStringStorage));

            var byteString = Create(segment.Current, length, segment.Size, type);

            segment.Current += byteString._pointer->Size;
            _wholeSegments.Add(segment);

            return(byteString);
        }
Beispiel #7
0
        public ByteString From(byte *valuePtr, int size, ByteStringType type = ByteStringType.Mutable)
        {
            Debug.Assert(valuePtr != null, $"{nameof(valuePtr)} cant be null.");
            Debug.Assert((type & ByteStringType.External) == 0, $"{nameof(From)} is not expected to be called with the '{nameof(ByteStringType.External)}' requested type, use {nameof(FromPtr)} instead.");

            var result = AllocateInternal(size, type);

            Memory.Copy(result._pointer->Ptr, valuePtr, size);

            RegisterForValidation(result);
            return(result);
        }
Beispiel #8
0
        public static Slice ToSlice(this string str, ByteStringContext context, ByteStringType type = ByteStringType.Mutable)
        {
            var size = Encoding.UTF8.GetByteCount(str);

            Debug.Assert(size <= ushort.MaxValue);

            var sliceWriter = new SliceWriter(size);

            sliceWriter.Write(str);

            return(sliceWriter.CreateSlice(context, type));
        }
Beispiel #9
0
        public ByteString Clone(ByteString value, ByteStringType type = ByteStringType.Mutable)
        {
            Debug.Assert(value._pointer != null, $"{nameof(value)} cant be null.");

            // TODO: If origin and destination are immutable, we can create external references.

            var result = AllocateInternal(value.Length, type);

            Memory.CopyInline(result._pointer->Ptr, value._pointer->Ptr, value._pointer->Length);

            RegisterForValidation(result);
            return(result);
        }
Beispiel #10
0
        public ByteString From(byte[] value, int size, ByteStringType type = ByteStringType.Mutable)
        {
            Debug.Assert(value != null, $"{nameof(value)} cant be null.");

            var result = AllocateInternal(size, type);

            fixed(byte *ptr = value)
            {
                Memory.Copy(result._pointer->Ptr, ptr, size);
            }

            RegisterForValidation(result);
            return(result);
        }
Beispiel #11
0
        public Slice GetNodeKey(LowLevelTransaction tx, int nodeNumber, ByteStringType type = ByteStringType.Mutable | ByteStringType.External)
        {
            var node = GetNode(nodeNumber);

            // This will ensure that we can create a copy or just use the pointer instead.
            if ((type & ByteStringType.External) == 0)
            {
                return(TreeNodeHeader.ToSlice(tx.Allocator, node, type));
            }
            else
            {
                return(TreeNodeHeader.ToSlicePtr(tx.Allocator, node, type));
            }
        }
Beispiel #12
0
        private ByteString Create(void *ptr, int length, int size, ByteStringType type = ByteStringType.Immutable)
        {
            Debug.Assert(length <= size - sizeof(ByteStringStorage));

            var basePtr = (ByteStringStorage *)ptr;

            basePtr->Flags  = type;
            basePtr->Length = length;
            basePtr->Ptr    = (byte *)ptr + sizeof(ByteStringStorage);
            basePtr->Size   = size;

            // We are registering the storage for validation here. Not the ByteString itself
            RegisterForValidation(basePtr);

            return(new ByteString(basePtr));
        }
Beispiel #13
0
        public ByteString From(string value, Encoding encoding, ByteStringType type = ByteStringType.Mutable)
        {
            Debug.Assert(value != null, $"{nameof(value)} cant be null.");

            int maxSize = 4 * value.Length;
            // Important if not working with Unicode.
            // http://stackoverflow.com/questions/9533258/what-is-the-maximum-number-of-bytes-for-a-utf-8-encoded-character
            var result = AllocateInternal(maxSize, type);

            fixed(char *ptr = value)
            {
                int length = encoding.GetBytes(ptr, value.Length, result.Ptr, maxSize);

                // We can do this because it is internal. See if it makes sense to actually give this ability.
                result._pointer->Length = length;
            }

            RegisterForValidation(result);
            return(result);
        }
Beispiel #14
0
        private ByteString AllocateExternal(byte *valuePtr, int size, ByteStringType type)
        {
            Debug.Assert((type & ByteStringType.External) != 0, "This allocation routine is only for use with external storage byte strings.");

            int allocationSize = sizeof(ByteStringStorage);

            ByteStringStorage *storagePtr;

            if (_externalFastPoolCount > 0)
            {
                storagePtr = (ByteStringStorage *)_externalFastPool[--_externalFastPoolCount].ToPointer();
            }
            else if (_externalStringPool.Count != 0)
            {
                storagePtr = (ByteStringStorage *)_externalStringPool.Pop().ToPointer();
            }
            else
            {
                if (_externalCurrentLeft == 0)
                {
                    AllocateExternalSegment(_allocationBlockSize);
                }

                storagePtr = (ByteStringStorage *)_externalCurrent.Current;
                _externalCurrent.Current += _externalAlignedSize;
                _externalCurrentLeft--;
            }

            storagePtr->Flags  = type;
            storagePtr->Length = size;
            storagePtr->Ptr    = valuePtr;

            // We are registering the storage for validation here. Not the ByteString itself
            RegisterForValidation(storagePtr);

            return(new ByteString(storagePtr));
        }
Beispiel #15
0
        public ByteString Skip(ByteString value, int bytesToSkip, ByteStringType type = ByteStringType.Mutable)
        {
            Debug.Assert(value._pointer != null, "ByteString cant be null.");

            if (bytesToSkip < 0)
            {
                throw new ArgumentException($"'{nameof(bytesToSkip)}' cannot be smaller than 0.");
            }

            if (bytesToSkip > value.Length)
            {
                throw new ArgumentException($"'{nameof(bytesToSkip)}' cannot be bigger than '{nameof(value)}.Length' 0.");
            }

            // TODO: If origin and destination are immutable, we can create external references.

            int size   = value.Length - bytesToSkip;
            var result = AllocateInternal(size, type);

            Memory.CopyInline(result._pointer->Ptr, value._pointer->Ptr + bytesToSkip, size);

            RegisterForValidation(result);
            return(result);
        }
Beispiel #16
0
        public static ByteStringContext.InternalScope From(ByteStringContext context, string value, ByteStringType type, out Slice str)
        {
            var scope = context.From(value, type, out ByteString s);

            str = new Slice(s);
            return(scope);
        }
Beispiel #17
0
        public static ByteStringContext.ExternalScope External(ByteStringContext context, byte *value, int size, ByteStringType type, out Slice slice)
        {
            var scope = context.FromPtr(value, size, type | ByteStringType.External, out ByteString str);

            slice = new Slice(str);
            return(scope);
        }
Beispiel #18
0
        public static ByteStringContext.InternalScope From(ByteStringContext context, byte *value, int size, ByteStringType type, out Slice str)
        {
            var scope = context.From(value, size, type, out ByteString byteString);

            str = new Slice(byteString);
            return(scope);
        }
Beispiel #19
0
        public static ByteStringContext.InternalScope From(ByteStringContext context, byte[] value, int offset, int count, ByteStringType type, out Slice str)
        {
            var scope = context.From(value, offset, count, type, out ByteString byteString);

            str = new Slice(byteString);
            return(scope);
        }
Beispiel #20
0
        public static ByteStringContext.InternalScope From(ByteStringContext context, byte[] value, ByteStringType type, out Slice str)
        {
            var scope = context.From(value, 0, value.Length, type, out ByteString byteString);

            str = new Slice(byteString);
            return(scope);
        }
Beispiel #21
0
        public static ByteStringContext.InternalScope ToSlice(ByteStringContext context, TreeNodeHeader *node, ByteStringType type, out Slice str)
        {
            ByteString byteString;
            var        scope = context.From((byte *)node + Constants.Tree.NodeHeaderSize, node->KeySize, type | (ByteStringType)SliceOptions.Key, out byteString);

            str = new Slice(byteString);
            return(scope);
        }
Beispiel #22
0
        public Slice CreateSlice(ByteStringContext context, int size, ByteStringType type = ByteStringType.Mutable)
        {
            var content = context.From(_buffer, size, type);

            return(new Slice(content));
        }
Beispiel #23
0
        private ByteString AllocateInternal(int length, ByteStringType type)
        {
            Debug.Assert((type & ByteStringType.External) == 0, "This allocation routine is only for use with internal storage byte strings.");
            type &= ~ByteStringType.External; // We are allocating internal, so we will force it (even if we are checking for it in debug).

            int allocationSize = length + sizeof(ByteStringStorage);

            // This is even bigger than the configured allocation block size. There is no reason why we shouldn't
            // allocate it directly. When released (if released) this will be reused as a segment, ensuring that the context
            // could handle that.
            if (allocationSize > _allocationBlockSize)
            {
                return(AllocateWholeSegment(length, type)); // We will pass the length because this is a whole allocated segment able to hold a length size ByteString.
            }
            int reusablePoolIndex = GetPoolIndexForReuse(allocationSize);
            int allocationUnit    = Bits.NextPowerOf2(allocationSize);

            // The allocation unit is bigger than MinBlockSize (therefore it wont be 2^n aligned).
            // Then we will 64bits align the allocation.
            if (allocationUnit > MinBlockSizeInBytes)
            {
                allocationUnit += sizeof(long) - allocationUnit % sizeof(long);
            }

            // All allocation units are 32 bits aligned. If not we will have a performance issue.
            Debug.Assert(allocationUnit % sizeof(int) == 0);

            // If we can reuse... we retrieve those.
            if (allocationSize <= MinBlockSizeInBytes && _internalReusableStringPoolCount[reusablePoolIndex] != 0)
            {
                // This is a stack because hotter memory will be on top.
                Stack <IntPtr> pool = _internalReusableStringPool[reusablePoolIndex];

                _internalReusableStringPoolCount[reusablePoolIndex]--;
                void *ptr = pool.Pop().ToPointer();

                return(Create(ptr, length, allocationUnit, type));
            }
            else
            {
                int currentSizeLeft = _internalCurrent.SizeLeft;
                if (allocationUnit > currentSizeLeft) // This shouldn't happen that much, if it does you should increase your default allocation block.
                {
                    SegmentInformation segment = null;

                    // We will try to find a hot segment with enough space if available.
                    // Older (colder) segments are at the front of the list. That's why we would start scanning backwards.
                    for (int i = _internalReadyToUseMemorySegments.Count - 1; i >= 0; i--)
                    {
                        var segmentValue = _internalReadyToUseMemorySegments[i];
                        if (segmentValue.SizeLeft >= allocationUnit)
                        {
                            // Put the last where this one is (if it is the same, this is a no-op) and remove it from the list.
                            _internalReadyToUseMemorySegments[i] = _internalReadyToUseMemorySegments[_internalReadyToUseMemorySegments.Count - 1];
                            _internalReadyToUseMemorySegments.RemoveAt(_internalReadyToUseMemorySegments.Count - 1);

                            segment = segmentValue;
                            break;
                        }
                    }

                    // If the size left is bigger than MinBlockSize, we release current as a reusable segment
                    if (currentSizeLeft > MinBlockSizeInBytes)
                    {
                        byte *start = _internalCurrent.Current;
                        byte *end   = start + currentSizeLeft;

                        _internalReadyToUseMemorySegments.Add(new SegmentInformation {
                            Start = start, Current = start, End = end, CanDispose = false
                        });
                    }
                    else if (currentSizeLeft > sizeof(ByteStringType) + MinReusableBlockSizeInBytes)
                    {
                        // The memory chunk left is big enough to make sense to reuse it.
                        reusablePoolIndex = GetPoolIndexForReservation(currentSizeLeft);

                        Stack <IntPtr> pool = this._internalReusableStringPool[reusablePoolIndex];
                        if (pool == null)
                        {
                            pool = new Stack <IntPtr>();
                            this._internalReusableStringPool[reusablePoolIndex] = pool;
                        }

                        pool.Push(new IntPtr(_internalCurrent.Current));
                        this._internalReusableStringPoolCount[reusablePoolIndex]++;
                    }

                    // Use the segment and if there is no segment available that matches the request, just get a new one.
                    this._internalCurrent = segment ?? AllocateSegment(_allocationBlockSize);
                }

                var byteString = Create(_internalCurrent.Current, length, allocationUnit, type);
                _internalCurrent.Current += byteString._pointer->Size;

                return(byteString);
            }
        }
 public Slice ToSlice(ByteStringContext context, ByteStringType type = ByteStringType.Mutable)
 {
     return(new Slice(context.From(ToBuffer(), type)));
 }
Beispiel #25
0
 public Slice Clone(ByteStringContext context, ByteStringType type = ByteStringType.Mutable)
 {
     return(new Slice(context.Clone(this.Content, type)));
 }
Beispiel #26
0
 public static Slice From(ByteStringContext context, byte *value, int size, ByteStringType type = ByteStringType.Mutable)
 {
     return(new Slice(context.From(value, size, type)));
 }
Beispiel #27
0
 public static Slice External(ByteStringContext context, byte *value, int size, ByteStringType type = ByteStringType.Mutable | ByteStringType.External)
 {
     return(new Slice(context.FromPtr(value, size, type | ByteStringType.External)));
 }
Beispiel #28
0
        public static ByteStringContext.ExternalScope ToSlicePtr(ByteStringContext context, TreeNodeHeader *node, ByteStringType type, out Slice slice)
        {
            ByteString str;
            var        scope = context.FromPtr((byte *)node + Constants.Tree.NodeHeaderSize, node->KeySize, type, out str);

            slice = new Slice(str);
            return(scope);
        }
Beispiel #29
0
 public Slice Skip(ByteStringContext context, int bytesToSkip, ByteStringType type = ByteStringType.Mutable)
 {
     return(new Slice(context.Skip(this.Content, bytesToSkip, type)));
 }
Beispiel #30
0
        public static Slice ToSliceUsingBuffer(this string str, ByteStringContext context, byte[] buffer, ByteStringType type = ByteStringType.Mutable)
        {
            var sliceWriter = new SliceWriter(buffer);

            sliceWriter.Write(str);

            return(sliceWriter.CreateSlice(context, type));
        }