コード例 #1
0
ファイル: SetComparer.cs プロジェクト: lulzzz/elfie-arriba
        /// <summary>
        ///  ConvertToEnumIndexComparer takes a comparer on the values of the enum and translates it to a comparer
        ///  which can operate on the byte[] indices instead.
        /// </summary>
        /// <param name="leftColumn">EnumColumn being compared</param>
        /// <param name="currentComparer">Current Comparison function requested by TermExpression</param>
        /// <param name="rightColumn">Constant being compared against</param>
        /// <param name="source">IXTable containing comparison</param>
        /// <returns>Comparer to compare the (updated) right Constant to the EnumColumn.Indices (rather than Values)</returns>
        public static ComparerExtensions.Comparer ConvertToEnumIndexComparer(IXColumn leftColumn, ComparerExtensions.Comparer currentComparer, ref IXColumn rightColumn, IXTable source)
        {
            Func <XArray> valuesGetter = leftColumn.ValuesGetter();

            if (valuesGetter == null)
            {
                throw new ArgumentException("ConvertToEnumIndexComparer is only valid for columns implementing Values.");
            }

            // Get all distinct values from the left side and find matches
            XArray    left  = leftColumn.ValuesGetter()();
            XArray    right = rightColumn.ValuesGetter()();
            BitVector set   = new BitVector(left.Count);

            currentComparer(left, right, set);

            // NOTE: When EnumColumn values are sorted, can convert comparisons to non-equality native accelerated compare.

            if (set.Count == 0)
            {
                // If there were no matches, always return none
                return(None);
            }
            else if (set.Count == left.Count)
            {
                // If everything matched, always return everything
                return(All);
            }
            else if (set.Count == 1)
            {
                // Convert the constant to the one matching index and make the comparison for index equals that
                rightColumn = new ConstantColumn(source, (byte)set.GetSingle(), typeof(byte));

                return(TypeProviderFactory.Get(typeof(byte)).TryGetComparer(CompareOperator.Equal));
            }
            else if (set.Count == left.Count - 1)
            {
                set.Not(set.Count);

                // Convert the constant to the one non-matching index and make the comparison for index doesn't equal that
                rightColumn = new ConstantColumn(source, (byte)set.GetSingle(), typeof(byte));

                return(TypeProviderFactory.Get(typeof(byte)).TryGetComparer(CompareOperator.NotEqual));
            }
            else
            {
                // Otherwise, build a matcher for values in the set
                return(new SetComparer(set).Evaluate);
            }
        }
コード例 #2
0
        public static bool IsNullConstant(this IXColumn column)
        {
            if (!column.IsConstantColumn())
            {
                return(false);
            }

            XArray value = column.ValuesGetter()();

            return(value.HasNulls && value.NullRows[value.Index(0)]);
        }
コード例 #3
0
ファイル: IsNull.cs プロジェクト: sharwell/elfie-arriba
        public Func <XArray> ValuesGetter()
        {
            Func <XArray> innerGetter = _column.ValuesGetter();

            if (innerGetter == null)
            {
                return(null);
            }

            return(() => Convert(innerGetter()));
        }
コード例 #4
0
        public Func <XArray> ValuesGetter()
        {
            if (_convertedValues.Array == null)
            {
                Func <XArray> innerGetter = _column.ValuesGetter();
                if (innerGetter == null)
                {
                    return(null);
                }

                _convertedValues = _converter(innerGetter());
            }

            return(() => _convertedValues);
        }
コード例 #5
0
        public Func <XArray> ValuesGetter()
        {
            if (_convertedValues.Array == null)
            {
                Func <XArray> innerGetter = _column.ValuesGetter();
                if (innerGetter == null)
                {
                    return(null);
                }

                _beforeBatch?.Invoke();
                _convertedValues = Convert(innerGetter());
            }

            return(() => _convertedValues);
        }
コード例 #6
0
        public static IXColumn Build(IXTable source, IXColumn column, Type targetType, ValueKinds errorOnKinds = ValueKindsDefaults.ErrorOn, object defaultValue = null, ValueKinds changeToDefaultKinds = ValueKindsDefaults.ChangeToDefault)
        {
            // If the column is already the right type, just return it
            if (column.ColumnDetails.Type == targetType)
            {
                return(column);
            }

            // Convert constants individually
            if (column.IsConstantColumn())
            {
                XArray array = column.ValuesGetter()();
                return(new ConstantColumn(source, TypeConverterFactory.ConvertSingle(array.Array.GetValue(0), targetType), targetType));
            }

            // Otherwise, wrap in a CastedColumn [Enums are automatically converted just once]
            return(new CastedColumn(column, targetType, errorOnKinds, defaultValue, changeToDefaultKinds));
        }
コード例 #7
0
        private void BuildSingleEnumColumnDictionary(CancellationToken cancellationToken)
        {
            // Build a CountAggregator for the enum GroupBy
            CountAggregator counts = new CountAggregator();

            XArray        values        = _column.ValuesGetter()();
            Func <XArray> indicesGetter = _column.IndicesCurrentGetter();

            int count;

            while ((count = _source.Next(XTableExtensions.DefaultBatchSize, cancellationToken)) != 0)
            {
                // Aggregate each row directly on the row index (already a small zero-based value)
                XArray indices = indicesGetter();
                counts.Add(indices, values.Count);
            }

            // Once the loop is done, get the distinct values and aggregation results
            PostSortAndFilter(values, counts.Values, counts.TotalRowCount, true);
        }
コード例 #8
0
 public Func <XArray> ValuesGetter()
 {
     return(_column.ValuesGetter());
 }
コード例 #9
0
        public TermExpression(IXTable source, IXColumn left, CompareOperator op, IXColumn right)
        {
            _evaluate = EvaluateNormal;

            // Save arguments as-is for ToString()
            _left  = left;
            _cOp   = op;
            _right = right;

            // Disallow constant <op> constant [likely error not wrapping column name]
            if (_left is ConstantColumn && _right is ConstantColumn)
            {
                throw new ArgumentException($"({left} {op.ToQueryForm()} {right}) is comparing two constants. Wrap [ColumnNames] in braces.");
            }

            // If the left side is a constant and the operator can be swapped, move it to the right side.
            // Comparers can check if the right side is constant and run a faster loop when that's the case.
            if (_left.IsConstantColumn() && !(_right.IsConstantColumn()))
            {
                if (op.TryInvertCompareOperator(out op))
                {
                    _left  = right;
                    _right = left;
                }
            }

            // Disallow unquoted constants used as strings
            if (_right.IsConstantColumn() && _left.ColumnDetails.Type == typeof(String8) && _right.ColumnDetails.Type == typeof(String8))
            {
                ConstantColumn cRight = _right as ConstantColumn;
                if (cRight != null && !cRight.IsNull && cRight.WasUnwrappedLiteral)
                {
                    throw new ArgumentException($"{right} is compared to a string, but is unquoted. Strings must be quoted.");
                }
            }

            // Convert the right side to the left side type if required
            // This means constants will always be casted to the other side type.
            if (_left.ColumnDetails.Type != _right.ColumnDetails.Type)
            {
                _right = CastedColumn.Build(source, _right, _left.ColumnDetails.Type, ValueKinds.Invalid);
            }

            // Get the left and right getters
            _leftGetter  = _left.CurrentGetter();
            _rightGetter = _right.CurrentGetter();

            // Null comparison is generic
            if (_right.IsNullConstant())
            {
                if (op == CompareOperator.Equal)
                {
                    _comparer = WhereIsNull;
                }
                else if (op == CompareOperator.NotEqual)
                {
                    _comparer = WhereIsNotNull;
                }
                else
                {
                    throw new ArgumentException($"Only equals and not equals operators are supported against null.");
                }
            }
            else if (_left.IsNullConstant())
            {
                _left = _right;
                if (op == CompareOperator.Equal)
                {
                    _comparer = WhereIsNull;
                }
                else if (op == CompareOperator.NotEqual)
                {
                    _comparer = WhereIsNotNull;
                }
                else
                {
                    throw new ArgumentException($"Only equals and not equals operators are supported against null.");
                }
            }
            else
            {
                // Get a comparer which can compare the values
                _comparer = TypeProviderFactory.Get(left.ColumnDetails.Type).TryGetComparer(op);
                if (_comparer == null)
                {
                    throw new ArgumentException($"No comparer found for type {left.ColumnDetails.Type.Name}.");
                }
            }

            // Optimize Enum to Constant comparisons to use the underlying indices
            if (_left.IsEnumColumn() && _right.IsConstantColumn())
            {
                // Get an optimized comparer against the indices rather than values
                IXColumn replacedRight = _right;
                _comparer = SetComparer.ConvertToEnumIndexComparer(_left, _comparer, ref replacedRight, source);

                // Get the indices on the left side
                _leftGetter = _left.IndicesCurrentGetter();

                // Use the updated value for the right side
                _rightGetter = replacedRight.CurrentGetter();
            }

            // Allow String8 to constant Contains queries to compare on the raw byte[] and int[]
            if (op == CompareOperator.Contains && _right.IsConstantColumn() && _left.ColumnDetails.Type == typeof(String8) && !_left.IsEnumColumn())
            {
                Func <object> rawGetter = _left.ComponentGetter(ColumnComponent.String8Raw);

                if (rawGetter != null)
                {
                    String8         rightValue      = (String8)_right.ValuesGetter()().Array.GetValue(0);
                    String8Comparer string8Comparer = new String8Comparer();

                    _evaluate = (vector) =>
                    {
                        String8Raw raw = (String8Raw)rawGetter();
                        string8Comparer.WhereContains(raw, rightValue, vector);
                    };
                }
            }
        }
コード例 #10
0
 public static bool IsConstantColumn(this IXColumn column)
 {
     return(column.IndicesType == null && column.ValuesGetter() != null);
 }