public RowCursor(IChannelProvider provider, int poolRows, IRowCursor input, IRandom rand)
                : base(provider)
            {
                Ch.AssertValue(input);
                Ch.AssertValue(rand);

                Ch.Assert(_blockSize > 0);
                Ch.Assert(_bufferDepth > 0);
                Ch.Assert(poolRows > 0);

                _poolRows = poolRows;
                _input    = input;
                _rand     = rand;

                _pipeIndices = Utils.GetIdentityPermutation(_poolRows - 1 + _bufferDepth * _blockSize);

                int colLim    = Schema.ColumnCount;
                int numActive = 0;

                _colToActivesIndex = new int[colLim];
                for (int c = 0; c < colLim; ++c)
                {
                    _colToActivesIndex[c] = _input.IsColumnActive(c) ? numActive++ : -1;
                }
                _pipes   = new ShufflePipe[numActive + (int)ExtraIndex.Lim];
                _getters = new Delegate[numActive];
                for (int c = 0; c < colLim; ++c)
                {
                    int ia = _colToActivesIndex[c];
                    if (ia < 0)
                    {
                        continue;
                    }
                    _pipes[ia] = ShufflePipe.Create(_pipeIndices.Length,
                                                    input.Schema.GetColumnType(c), RowCursorUtils.GetGetterAsDelegate(input, c));
                    _getters[ia] = CreateGetterDelegate(c);
                }
                var idPipe = _pipes[numActive + (int)ExtraIndex.Id] = ShufflePipe.Create(_pipeIndices.Length, NumberType.UG, input.GetIdGetter());

                _idGetter = CreateGetterDelegate <UInt128>(idPipe);
                // Initially, after the preamble to MoveNextCore, we want:
                // liveCount=0, deadCount=0, circularIndex=0. So we set these
                // funky values accordingly.
                _pipeIndex = _circularIndex = _pipeIndices.Length - 1;
                _deadCount = -1;
                _liveCount = 1;

                // Set up the producer worker.
                _toConsume = new BufferBlock <int>();
                _toProduce = new BufferBlock <int>();
                // First request the pool - 1 + block size rows, to get us going.
                PostAssert(_toProduce, _poolRows - 1 + _blockSize);
                // Queue up the remaining capacity.
                for (int i = 1; i < _bufferDepth; ++i)
                {
                    PostAssert(_toProduce, _blockSize);
                }

                _producerTask = LoopProducerWorker();
            }
            private ValueGetter <TValue> CreateGetterDelegate <TValue>(ShufflePipe pipe)
            {
                Ch.AssertValue(pipe);
                Ch.Assert(pipe is ShufflePipe <TValue>);
                var pipe2 = (ShufflePipe <TValue>)pipe;
                ValueGetter <TValue> getter =
                    (ref TValue value) =>
                {
                    Ch.Assert(_pipeIndex == _pipeIndices[_circularIndex]);
                    pipe2.Fetch(_pipeIndex, ref value);
                };

                return(getter);
            }