private String8Set SplitRows(String8 block, PartialArray <int> rowPositionArray)
        {
            // Split the block into lines (and save the split for use splitting columns)
            _blockLines = block.Split(UTF8.Newline, _lineArray);

            // Reset where which line the next row begins with
            _nextLineIndex = 0;

            rowPositionArray.Clear();
            rowPositionArray.Add(0);

            for (int i = 0; i < _blockLines.Count - 1; ++i)
            {
                String8 line = _blockLines[i];

                // An empty line (or \n\r\n) indicates a new logical row
                if (line.Length == 0 || (line.Length == 1 && line[0] == UTF8.CR))
                {
                    rowPositionArray.Add(_lineArray[i + 1]);
                }
            }

            rowPositionArray.Add(block.Length + 1);

            return(new String8Set(block, 1, rowPositionArray));
        }
        /// <summary>
        ///  Split a string into alphanumeric words without allocation by using
        ///  the same PartialArray&lt;int&gt; in a loop. When traversing over the
        ///  returned String8Set, check if each first letter IsAlphaNumeric to
        ///  decide whether to include it.
        /// </summary>
        /// <param name="value">String8 to split</param>
        /// <param name="buffer">PartialArray to contain split positions [allows reuse without allocations]</param>
        /// <returns>String8Set containing value split at alpha-to-non-alpha boundaries</returns>
        public static String8Set Split(String8 value, ref PartialArray <int> buffer)
        {
            // Reset the buffer for our use
            buffer.Clear();

            if (!value.IsEmpty())
            {
                // Add the beginning as a part
                buffer.Add(0);

                bool inWord = IsAlphaNumeric(value[0]);

                for (int i = 1; i < value.Length; ++i)
                {
                    bool charIsAlpha = IsAlphaNumeric(value[i]);

                    if (inWord != charIsAlpha)
                    {
                        // Add a boundary at each alpha to non-alpha transition
                        buffer.Add(i);
                        inWord = charIsAlpha;
                    }
                }

                // Add the remaining part of the string
                buffer.Add(value.Length);
            }

            return(new String8Set(value, 0, buffer));
        }
        /// <summary>
        ///  Split a string on a given delimiter only outside matching double quotes.
        ///  Used to split CSV content where the delimiters are ignored within quotes.
        /// </summary>
        /// <param name="value">String8 value to split</param>
        /// <param name="delimiter">Delimiter to split on</param>
        /// <param name="positions">PartialArray&lt;int&gt; to contain split positions</param>
        /// <returns>String8Set containing split value</returns>
        public static String8Set SplitOutsideQuotes(String8 value, byte delimiter, PartialArray <int> positions)
        {
            if (value.IsEmpty())
            {
                return(String8Set.Empty);
            }

            // Clear any previous values in the array
            positions.Clear();

            // The first part always begins at the start of the string
            positions.Add(0);

            byte[] array = value._buffer;
            int    i     = value._index;
            int    end   = i + value._length;

            // Walk the string. Find and mark delimiters outside of quotes only
            while (i < end)
            {
                // Outside Quotes
                for (; i < end; ++i)
                {
                    // If a quote is found, we're now inside quotes
                    if (array[i] == UTF8.Quote)
                    {
                        i++;
                        break;
                    }

                    // If a delimiter is found, add another split position
                    if (array[i] == delimiter)
                    {
                        positions.Add(i - value._index + 1);
                    }
                }

                // Inside Quotes
                for (; i < end; ++i)
                {
                    // If a quote was found, we're now outside quotes
                    if (array[i] == UTF8.Quote)
                    {
                        i++;
                        break;
                    }
                }
            }

            // The last part always ends at the end of the string
            positions.Add(value.Length + 1);

            return(new String8Set(value, 1, positions));
        }
Exemple #4
0
        private void Sort(int parentNodeIndex, IComparer <int> nodeIndexComparer, ref PartialArray <int> buffer)
        {
            int currentChild = _firstChildIndex[parentNodeIndex];

            // If no children, return
            if (currentChild <= 0)
            {
                return;
            }

            // Add all children of the current element to the buffer
            buffer.Clear();
            while (currentChild > 0)
            {
                buffer.Add(currentChild);
                currentChild = _nextSiblingIndex[currentChild];
            }

            // Sort the children by the compare function
            buffer.Sort(nodeIndexComparer);

            // Modify the FirstChild and NextSibling pointers to be in sorted order
            currentChild = buffer[0];
            _firstChildIndex[parentNodeIndex] = currentChild;

            for (int i = 1; i < buffer.Count; ++i)
            {
                int nextChild = buffer[i];
                _nextSiblingIndex[currentChild] = nextChild;
                currentChild = nextChild;
            }

            _nextSiblingIndex[currentChild] = -1;

            // Recurse on the children
            currentChild = _firstChildIndex[parentNodeIndex];
            while (currentChild > 0)
            {
                Sort(currentChild, nodeIndexComparer, ref buffer);
                currentChild = _nextSiblingIndex[currentChild];
            }
        }
        /// <summary>
        ///  Split a string on a given delimiter into a provided byte[]. Used
        ///  to split strings without allocation when a large byte[] is created
        ///  and reused for many strings.
        /// </summary>
        /// <param name="value">String8 value to split</param>
        /// <param name="delimiter">Delimiter to split on</param>
        /// <param name="positions">PartialArray&lt;int&gt; to contain split positions</param>
        /// <returns>String8Set containing split value</returns>
        public static String8Set Split(String8 value, byte delimiter, PartialArray <int> positions)
        {
            // Ensure the delimiter is single byte
            if (delimiter >= 128)
            {
                throw new ArgumentException(String.Format(Resources.UnableToSupportMultibyteCharacter, delimiter));
            }

            if (value.IsEmpty())
            {
                return(String8Set.Empty);
            }

            // Clear any previous values in the array
            positions.Clear();

            // Record each delimiter position
            positions.Add(0);

            // Get the String8 array directly and loop from index to (index + length)
            // 3x faster than String8[index].
            byte[] array = value._buffer;
            int    end   = value._index + value._length;

            for (int i = value._index; i < end; ++i)
            {
                if (array[i] == delimiter)
                {
                    // Next start position is after this delimiter
                    positions.Add(i - value._index + 1);
                }
            }

            positions.Add(value.Length + 1);

            return(new String8Set(value, 1, positions));
        }
        /// <summary>
        ///  Split a CSV row into cells. This method splits and unencodes quoted values together.
        ///  It changes the underlying buffer in the process.
        /// </summary>
        /// <param name="row">String8 containing a CSV row</param>
        /// <param name="positions">PartialArray&lt;int&gt; to contain split positions</param>
        /// <returns>String8Set containing unencoded cell values</returns>
        public static String8Set SplitAndDecodeCsvCells(String8 row, PartialArray <int> positions)
        {
            // If row is empty, return empty set
            if (row.IsEmpty())
            {
                return(String8Set.Empty);
            }

            // Clear any previous values in the array
            positions.Clear();

            // The first part always begins at the start of the (shifted) string
            positions.Add(0);

            byte[] array = row._buffer;
            int    i     = row._index;
            int    end   = i + row._length;

            // We're shifting values in the string to overwrite quotes around cells
            // and doubled quotes. copyTo is where we've written to in the unescaped
            // string.
            int copyTo = i;

            // Walk each cell, handling quoted and unquoted cells.
            while (i < end)
            {
                bool inQuote = (array[i] == UTF8.Quote);

                if (!inQuote)
                {
                    // Unquoted cell. Copy until next comma.
                    for (; i < end; ++i, ++copyTo)
                    {
                        // Copy everything as-is (no unescaping)
                        array[copyTo] = array[i];

                        // If a delimiter is found, add another split position
                        if (array[i] == UTF8.Comma)
                        {
                            positions.Add(copyTo - row._index + 1);
                            i++; copyTo++;
                            break;
                        }
                    }
                }
                else
                {
                    // Quoted cell.

                    // Overwrite opening quote
                    i++;

                    // Look for end quote (undoubled quote)
                    for (; i < end; ++i, ++copyTo)
                    {
                        if (array[i] != UTF8.Quote)
                        {
                            // Copy everything that wasn't an escaped quote
                            array[copyTo] = array[i];
                        }
                        else
                        {
                            // Quote found. End of cell, escaped quote, or unescaped quote (error)?
                            i++;

                            // End of cell [end of line]
                            if (i == end)
                            {
                                break;
                            }

                            if (array[i] == UTF8.Comma)
                            {
                                // End of cell [comma]. Copy comma, end of cell.
                                positions.Add(copyTo - row._index + 1);
                                array[copyTo] = array[i];
                                i++; copyTo++;
                                break;
                            }
                            else if (array[i] == UTF8.Quote)
                            {
                                // Escaped quote. Copy the second quote, continue cell.
                                array[copyTo] = array[i];
                            }
                            else
                            {
                                // Unescaped quote. Abort; caller will see incomplete row and can throw
                                return(new String8Set(row, 1, positions));
                            }
                        }
                    }
                }
            }

            // The last part always ends at the end of the (shifted) string
            positions.Add(copyTo - row._index + 1);

            // Overwrite duplicate values left from shifting to make bugs clearer
            for (; copyTo < end; ++copyTo)
            {
                array[copyTo] = UTF8.Null;
            }

            return(new String8Set(row, 1, positions));
        }
 public void Clear()
 {
     _identifiers.Clear();
 }
 public void Clear()
 {
     _ticksValues.Clear();
 }
        public void PartialArray_Basics()
        {
            // Default Constructor - no fixed size
            PartialArray <int> a = new PartialArray <int>();

            // Verify empty to start
            Assert.AreEqual(0, a.Count);
            Assert.AreEqual(0, a.Capacity);
            Assert.IsFalse(a.IsStaticSize);
            Assert.IsFalse(a.IsFull);

            // Verify Add doesn't throw
            for (int i = 0; i < 100; ++i)
            {
                a.Add(i);
            }

            // Verify count and capacity are right, IsFull is still false
            Assert.AreEqual(100, a.Count);
            Assert.IsTrue(a.Capacity >= 100);
            Assert.IsFalse(a.IsFull);

            // Verify we can get values back
            for (int i = 0; i < 100; ++i)
            {
                Assert.AreEqual(i, a[i]);
            }

            // Verify changing a value works
            a[0] = 50;
            Assert.AreEqual(50, a[0]);
            a[0] = 0;

            // Verify round trip works [Primitives only]
            PartialArray <int> readArray = new PartialArray <int>();

            Verify.RoundTrip <PartialArray <int> >(a, readArray);
            a = readArray;

            // Verify count and capacity are right, IsFull is still false
            Assert.AreEqual(100, a.Count);
            Assert.IsTrue(a.Capacity >= 100);
            Assert.IsFalse(a.IsFull);

            // Verify we can get values back
            for (int i = 0; i < 100; ++i)
            {
                Assert.AreEqual(i, a[i]);
            }

            // Verify clear works
            a.Clear();
            Assert.AreEqual(0, a.Count);
            Assert.IsTrue(a.Capacity >= 100);
            Assert.IsFalse(a.IsFull);

            // Verify Add after Clear works
            a.Add(10);
            Assert.AreEqual(1, a.Count);
            Assert.AreEqual(10, a[0]);
        }
Exemple #10
0
        /// <summary>
        ///  Search the given IMemberDatabase for matches to this query and put
        ///  results into the results array provided. The capacity of the results
        ///  array determines how many results are returned.
        /// </summary>
        /// <param name="db">Database to search</param>
        /// <param name="results">PartialArray to contain results, sized for the count desired.</param>
        /// <returns>True if results were added, False otherwise</returns>
        public bool TryFindMembers(IMemberDatabase db, ref PartialArray <Symbol> results)
        {
            // Ensure strings must be found again so that benchmarks are realistic
            ForceReresolve();

            // Clear results from a previous query
            results.Clear();

            // If there was no query, return with no results
            if (String.IsNullOrEmpty(SymbolName))
            {
                return(false);
            }

            // Get required members from database
            StringStore strings         = db.StringStore;
            ItemTree    declaredMembers = db.DeclaredMembers;
            MemberIndex index           = db.Index;

            // Map strings to the local StringStore. Stop immediately if any values aren't found.
            if (!ResolveStringsTo(strings))
            {
                return(false);
            }

            // Cache whether this query needs details to match
            bool usesDetails = !this.Parameters8.IsEmpty() || this.Type != SymbolType.Any || this.Modifiers != SymbolModifier.None;

            int[] matches;
            int   matchesIndex, matchesCount;

            if (SplitSymbolName8.Count == 1)
            {
                // Find the set of symbols with names in range. If no symbols in index, return nothing
                if (!index.TryGetMatchesInRange(SymbolNameSuffixIdentifiers, out matches, out matchesIndex, out matchesCount))
                {
                    return(false);
                }

                // If there was just one name part searched for, all matches count
                for (int i = matchesIndex; i < matchesIndex + matchesCount; ++i)
                {
                    if ((usesDetails ? MatchesDetailed(declaredMembers, strings, db, matches[i]) : Matches(declaredMembers, strings, matches[i])))
                    {
                        results.Add(new Symbol(db, matches[i]));
                        if (results.IsFull)
                        {
                            return(true);
                        }
                    }
                }
            }
            else
            {
                // Find all entries with exactly the second-to-last name
                if (!index.TryGetMatchesInRange(SymbolNamePrefixIdentifiers[SymbolNamePrefixIdentifiers.Length - 1], out matches, out matchesIndex, out matchesCount))
                {
                    return(false);
                }

                for (int i = matchesIndex; i < matchesIndex + matchesCount; ++i)
                {
                    int currentMatchIndex = matches[i];

                    // First, do all previous name parts in the query match?
                    int currentAncestorIndex = currentMatchIndex;
                    int namePartIndex        = SymbolNamePrefixIdentifiers.Length - 2;
                    for (; namePartIndex >= 0; --namePartIndex)
                    {
                        currentAncestorIndex = declaredMembers.GetParent(currentAncestorIndex);
                        int currentAncestorNameIdentifier = declaredMembers.GetNameIdentifier(currentAncestorIndex);
                        if (!SymbolNamePrefixIdentifiers[namePartIndex].Contains(currentAncestorNameIdentifier))
                        {
                            break;
                        }
                    }

                    if (namePartIndex != -1)
                    {
                        continue;
                    }

                    // If this was a full match, are we out of namespaces?
                    if (IsFullNamespace)
                    {
                        currentAncestorIndex = declaredMembers.GetParent(currentAncestorIndex);
                        SymbolType symbolAboveFullNameType = db.GetMemberType(currentAncestorIndex);
                        if (!symbolAboveFullNameType.IsAboveNamespace())
                        {
                            return(false);
                        }
                    }

                    // Next, find children of this item which match the last part typed
                    int leafId = declaredMembers.GetFirstChild(currentMatchIndex);
                    while (leafId > 0)
                    {
                        if ((usesDetails ? MatchesDetailed(declaredMembers, strings, db, leafId) : Matches(declaredMembers, strings, leafId)))
                        {
                            results.Add(new Symbol(db, leafId));
                            if (results.IsFull)
                            {
                                return(true);
                            }
                        }

                        leafId = declaredMembers.GetNextSibling(leafId);
                    }
                }
            }

            return(results.Count > 0);
        }