public int FilterLandRegistryRecordsArrowVectorized2()
        {
            var recordCount = recordBatch.Length;

            //var selectMask = new byte[recordCount]; // new int[0];
            int[]      selectMask         = new int[recordCount];
            const long MillisecondsPerDay = 86400000;
            var        dateFilter         = (int)(DateTimeOffset.Parse("2019-01-01").ToUnixTimeMilliseconds() / MillisecondsPerDay);
            var        dateValues         = (recordBatch.Column(0) as Date32Array).Values;

            VectorizedFiltering.ApplyFilterMask <int, int>(
                dateValues, Vector.GreaterThanOrEqual, (v, f) => v >= f, dateFilter,
                selectMask, Vector.BitwiseOr, (f1, f2) => (byte)(f1 | f2));

            var priceValues = (recordBatch.Column(1) as FloatArray).Values;

            VectorizedFiltering.ApplyFilterMask <float, int>(
                priceValues, Vector.GreaterThan, (v, f) => v > f, 5000000,
                selectMask, Vector.BitwiseAnd, (f1, f2) => f1 & f2);

            byte[] byteSelectMask = VectorizedFiltering.NarrowFilterMask(selectMask);
            var    stringEncoding = Encoding.ASCII;
            var    propertyTypeFilter = new string[] { "D", "S", "T" }.Select(x => stringEncoding.GetBytes(x)[0]).ToArray();
            var    propertyTypeValues = (recordBatch.Column(2) as StringArray).Values;

            byte[] byteSelectMask2 = VectorizedFiltering.GetFilterMask <byte>(
                propertyTypeValues, Vector.Equals, (v, f) => v == f, propertyTypeFilter);
            byteSelectMask = VectorizedFiltering.CombineFilterMask(
                byteSelectMask, byteSelectMask2, Vector.BitwiseAnd, (f1, f2) => (byte)(f1 & f2));

            var tenureFilter = stringEncoding.GetBytes("F")[0];
            var tenureValues = (recordBatch.Column(3) as StringArray).Values;

            VectorizedFiltering.ApplyFilterMask <byte, byte>(
                tenureValues, Vector.Equals, (v, f) => v == f, tenureFilter,
                byteSelectMask, Vector.BitwiseAnd, (f1, f2) => (byte)(f1 & f2));

            var count = VectorizedFiltering.CountFilterMask(byteSelectMask);

#if LOG
            Console.WriteLine("Found {0} records", count);
#endif
            return(count);
        }
        public unsafe int FilterLandRegistryRecordsArrowVectorizedAvx()
        {
            var recordCount = recordBatch.Length;
            var selectMask  = new int[recordCount]; // new int[0];

            const long MillisecondsPerDay = 86400000;

            var dateFilter            = (int)(DateTimeOffset.Parse("2019-01-01").ToUnixTimeMilliseconds() / MillisecondsPerDay);
            var dateFilterVector      = Vector256.Create(dateFilter);
            var dateFilterVectorLimit = recordCount - (recordCount % Vector256 <int> .Count);
            var dateValues            = (recordBatch.Column(0) as Date32Array).Values;

            fixed(int *pDateValues = dateValues, pSelectMask = selectMask)
            {
                for (var i = 0; i < dateFilterVectorLimit; i += Vector256 <int> .Count)
                {
                    var resultVector = Avx2.CompareGreaterThan(
                        Avx2.LoadVector256(pDateValues + i),
                        dateFilterVector
                        );
                    Avx2.Store(pSelectMask + i, resultVector);
                }
            }

            for (var i = dateFilterVectorLimit; i < recordCount; i++)
            {
                var predicateResult = dateValues[i] >= dateFilter;
                selectMask[i] = Unsafe.As <bool, int>(ref predicateResult);
                //selectMask[i] = dateValues[i] >= dateFilter ? -1 : 0;
            }

            var priceFilterVector      = Vector256.Create(5000000f).AsInt32();
            var priceFilterVectorLimit = recordCount - (recordCount % Vector256 <float> .Count);
            var priceValues            = (recordBatch.Column(1) as FloatArray).Values;

            fixed(float *pPriceValues = priceValues)
            fixed(int *pSelectMask = selectMask)
            {
                for (var i = 0; i < priceFilterVectorLimit; i += Vector256 <float> .Count)
                {
                    var resultVector = Avx2.And(
                        Avx2.LoadVector256(pSelectMask + i),
                        Avx2.CompareGreaterThan(
                            Avx2.LoadVector256(pPriceValues + i).AsInt32(),
                            priceFilterVector
                            )
                        );
                    Avx2.Store(pSelectMask + i, resultVector);
                }
            }
            for (var i = priceFilterVectorLimit; i < recordCount; i++)
            {
                var predicateResult = priceValues[i] > 5000000;
                selectMask[i] &= Unsafe.As <bool, int>(ref predicateResult);
                //selectMask[i] = selectMask[i] && priceValues[i] > 5000000 ? -1 : 0;
            }

            byte[] byteSelectMask = VectorizedFiltering.NarrowFilterMask(selectMask);

            var stringEncoding = Encoding.ASCII;
            var propertyTypeSelectMask = new byte[byteSelectMask.Length];
            var propertyTypeFilterList = new string[] { "D", "S", "T" }.Select(x => stringEncoding.GetBytes(x)[0]).ToArray();
            var propertyTypeFilterVectorLimit = recordCount - (recordCount % Vector256 <byte> .Count);

            for (var j = 0; j < propertyTypeFilterList.Length; j++)
            {
                var propertyTypeFilter       = propertyTypeFilterList[j];
                var propertyTypeFilterVector = Vector256.Create(propertyTypeFilter).AsSByte();
                var propertyTypeValues       = (recordBatch.Column(2) as StringArray).Values;
                fixed(byte *pPropertyTypeValues = propertyTypeValues, pPropertyTypeSelectMask = propertyTypeSelectMask)
                {
                    for (var i = 0; i < propertyTypeFilterVectorLimit; i += Vector256 <byte> .Count)
                    {
                        var resultVector = Avx2.And(
                            Avx2.LoadVector256(pPropertyTypeSelectMask + i),
                            Avx2.CompareGreaterThan(
                                Avx2.LoadVector256(pPropertyTypeValues + i).AsSByte(),
                                propertyTypeFilterVector
                                ).AsByte()
                            );
                        Avx2.Store(pPropertyTypeSelectMask + i, resultVector);
                    }
                }

                for (var i = propertyTypeFilterVectorLimit; i < recordCount; i++)
                {
                    var predicateResult = propertyTypeValues[i] == propertyTypeFilter;
                    propertyTypeSelectMask[i] |= Unsafe.As <bool, byte>(ref predicateResult);
                    //byteSelectMask[i] = tenureValues[i] == tenureFilter ? -1 : 0;
                }
                //for (var i = 0; i < recordCount; i++)
                //{
                //    selectMask[i] = selectMask[i] && propertyTypeFilter.Contains(propertyTypeValues[i]);
                //}
            }

            fixed(byte *pByteSelectMask = byteSelectMask, pPropertyTypeSelectMask = propertyTypeSelectMask)
            {
                for (var i = 0; i < propertyTypeFilterVectorLimit; i += Vector256 <byte> .Count)
                {
                    var resultVector = Avx2.And(
                        Avx2.LoadVector256(pByteSelectMask + i),
                        Avx2.LoadVector256(pPropertyTypeSelectMask + i)
                        );
                    Avx2.Store(pByteSelectMask + i, resultVector);
                }
            }

            for (var i = propertyTypeFilterVectorLimit; i < recordCount; i++)
            {
                byteSelectMask[i] &= propertyTypeSelectMask[i];
            }

            var tenureFilter            = stringEncoding.GetBytes("F")[0];
            var tenureFilterVector      = Vector256.Create(tenureFilter).AsSByte();
            var tenureFilterVectorLimit = recordCount - (recordCount % Vector256 <byte> .Count);
            var tenureValues            = (recordBatch.Column(3) as StringArray).Values;

            fixed(byte *pByteSelectMask = byteSelectMask, pTenureValues = tenureValues)
            {
                for (var i = 0; i < tenureFilterVectorLimit; i += Vector256 <byte> .Count)
                {
                    var resultVector = Avx2.And(
                        Avx2.LoadVector256(pByteSelectMask + i),
                        Avx2.CompareGreaterThan(
                            Avx2.LoadVector256(pTenureValues + i).AsSByte(),
                            tenureFilterVector
                            ).AsByte()
                        );
                    Avx2.Store(pByteSelectMask + i, resultVector);
                }
            }

            for (var i = tenureFilterVectorLimit; i < recordCount; i++)
            {
                var predicateResult = tenureValues[i] == tenureFilter;
                byteSelectMask[i] &= Unsafe.As <bool, byte>(ref predicateResult);
                //byteSelectMask[i] = byteSelectMask[i] && tenureValues[i] == tenureFilter ? -1 : 0;
            }

            var countVector = Vector256 <byte> .Zero;
            var oneVector   = Vector256.Create((byte)1);

            fixed(byte *pByteSelectMask = byteSelectMask, pTenureValues = tenureValues)
            {
                for (var i = 0; i < tenureFilterVectorLimit; i += Vector256 <byte> .Count)
                {
                    countVector = Avx2.Add(
                        countVector,
                        Avx2.And(Avx2.LoadVector256(pByteSelectMask + i), oneVector)
                        );
                }
            }

            var count = 0;

            for (var i = 0; i < Vector256 <byte> .Count; i++)
            {
                count += countVector.GetElement(i);
            }
            for (var i = tenureFilterVectorLimit; i < recordCount; i++)
            {
                count += byteSelectMask[i] & 1;
            }
#if LOG
            Console.WriteLine("Found {0} records", count);
#endif
            return(count);
            //return selectMask.Count(v => v == -1);
        }
        public int FilterLandRegistryRecordsArrowVectorized()
        {
            var recordCount = recordBatch.Length;
            var selectMask  = new int[recordCount]; // new int[0];

            const long MillisecondsPerDay = 86400000;

            var dateFilter            = (int)(DateTimeOffset.Parse("2019-01-01").ToUnixTimeMilliseconds() / MillisecondsPerDay);
            var dateFilterVector      = new Vector <int>(dateFilter);
            var dateFilterVectorLimit = recordCount - (recordCount % Vector <int> .Count);
            var dateValues            = (recordBatch.Column(0) as Date32Array).Values;

            for (var i = 0; i < dateFilterVectorLimit; i += Vector <int> .Count)
            {
                var resultVector = Vector.GreaterThanOrEqual(
                    new Vector <int>(dateValues.Slice(i)),
                    dateFilterVector
                    );
                resultVector.CopyTo(selectMask, i);
            }
            for (var i = dateFilterVectorLimit; i < recordCount; i++)
            {
                var predicateResult = dateValues[i] >= dateFilter;
                selectMask[i] = Unsafe.As <bool, int>(ref predicateResult);
                //selectMask[i] = dateValues[i] >= dateFilter ? -1 : 0;
            }

            //selectMask = GetFilterMask<int>(dateValues, Vector.GreaterThanOrEqual, (v, f) => v >= f, dateFilter);

            var priceFilterVector      = new Vector <float>(5000000);
            var priceFilterVectorLimit = recordCount - (recordCount % Vector <float> .Count);
            var priceValues            = (recordBatch.Column(1) as FloatArray).Values;

            for (var i = 0; i < priceFilterVectorLimit; i += Vector <float> .Count)
            {
                Vector.BitwiseAnd(
                    new Vector <int>(selectMask, i),
                    Vector.GreaterThan(
                        new Vector <float>(priceValues.Slice(i)),
                        priceFilterVector
                        )
                    ).CopyTo(selectMask, i);
            }
            for (var i = priceFilterVectorLimit; i < recordCount; i++)
            {
                var predicateResult = priceValues[i] > 5000000;
                selectMask[i] &= Unsafe.As <bool, int>(ref predicateResult);
                //selectMask[i] = selectMask[i] && priceValues[i] > 5000000 ? -1 : 0;
            }

            byte[] byteSelectMask = VectorizedFiltering.NarrowFilterMask(selectMask);

            var stringEncoding = Encoding.ASCII;
            var propertyTypeSelectMask = new byte[byteSelectMask.Length];
            var propertyTypeFilterList = new string[] { "D", "S", "T" }.Select(x => stringEncoding.GetBytes(x)[0]).ToArray();
            var propertyTypeFilterVectorLimit = recordCount - (recordCount % Vector <byte> .Count);

            for (var j = 0; j < propertyTypeFilterList.Length; j++)
            {
                var propertyTypeFilter       = propertyTypeFilterList[j];
                var propertyTypeFilterVector = new Vector <byte>(propertyTypeFilter);
                var propertyTypeValues       = (recordBatch.Column(2) as StringArray).Values;
                for (var i = 0; i < propertyTypeFilterVectorLimit; i += Vector <byte> .Count)
                {
                    Vector.BitwiseOr(
                        new Vector <byte>(propertyTypeSelectMask, i),
                        Vector.GreaterThan(
                            new Vector <byte>(propertyTypeValues.Slice(i)),
                            propertyTypeFilterVector
                            )
                        ).CopyTo(propertyTypeSelectMask, i);
                }
                for (var i = propertyTypeFilterVectorLimit; i < recordCount; i++)
                {
                    var predicateResult = propertyTypeValues[i] == propertyTypeFilter;
                    propertyTypeSelectMask[i] |= Unsafe.As <bool, byte>(ref predicateResult);
                    //byteSelectMask[i] = tenureValues[i] == tenureFilter ? -1 : 0;
                }
                //for (var i = 0; i < recordCount; i++)
                //{
                //    selectMask[i] = selectMask[i] && propertyTypeFilter.Contains(propertyTypeValues[i]);
                //}
            }

            for (var i = 0; i < propertyTypeFilterVectorLimit; i += Vector <byte> .Count)
            {
                Vector.BitwiseAnd(
                    new Vector <byte>(byteSelectMask, i),
                    new Vector <byte>(propertyTypeSelectMask, i)
                    ).CopyTo(byteSelectMask, i);
            }
            for (var i = propertyTypeFilterVectorLimit; i < recordCount; i++)
            {
                byteSelectMask[i] &= propertyTypeSelectMask[i];
            }

            var tenureFilter            = stringEncoding.GetBytes("F")[0];
            var tenureFilterVector      = new Vector <byte>(tenureFilter);
            var tenureFilterVectorLimit = recordCount - (recordCount % Vector <byte> .Count);
            var tenureValues            = (recordBatch.Column(3) as StringArray).Values;

            for (var i = 0; i < tenureFilterVectorLimit; i += Vector <byte> .Count)
            {
                Vector.BitwiseAnd(
                    new Vector <byte>(byteSelectMask, i),
                    Vector.GreaterThan(
                        new Vector <byte>(tenureValues.Slice(i)),
                        tenureFilterVector
                        )
                    ).CopyTo(byteSelectMask, i);
            }
            for (var i = tenureFilterVectorLimit; i < recordCount; i++)
            {
                var predicateResult = tenureValues[i] == tenureFilter;
                byteSelectMask[i] &= Unsafe.As <bool, byte>(ref predicateResult);
                //byteSelectMask[i] = byteSelectMask[i] && tenureValues[i] == tenureFilter ? -1 : 0;
            }

            var countVector = Vector <byte> .Zero;

            for (var i = 0; i < tenureFilterVectorLimit; i += Vector <byte> .Count)
            {
                countVector += new Vector <byte>(byteSelectMask, i) & Vector <byte> .One;
            }
            var count = 0;

            for (var i = 0; i < Vector <byte> .Count; i++)
            {
                count += countVector[i];
            }
            for (var i = tenureFilterVectorLimit; i < recordCount; i++)
            {
                count += byteSelectMask[i] & 1;
            }
#if LOG
            Console.WriteLine("Found {0} records", count);
#endif
            return(count);
            //return selectMask.Count(v => v == -1);
        }