private bool ForEachMemoryBlockRecursive(MemoryReader mreader,
                                                     MemoryReader.Converter <double> elementConverter,
                                                     MemoryBlockPredicate memoryBlockPredicate,
                                                     MemoryReader.ValueConverter <byte, byte> boolConverter,
                                                     MemoryReader.ValueConverter <ulong> ptrConverter,
                                                     ulong nodeAddr,
                                                     long leftDiff, long rightDiff,
                                                     long isNilDiff, long valDiff)
            {
                byte[] isNil = new byte[1];
                if (!mreader.Read(nodeAddr + (ulong)isNilDiff, isNil, boolConverter))
                {
                    return(false);
                }
                if (isNil[0] == 0) // _Isnil == false
                {
                    ulong[]  leftAddr  = new ulong[1];
                    ulong[]  rightAddr = new ulong[1];
                    double[] values    = new double[elementConverter.ValueCount()];

                    return(mreader.Read(nodeAddr + (ulong)leftDiff, leftAddr, ptrConverter) &&
                           mreader.Read(nodeAddr + (ulong)rightDiff, rightAddr, ptrConverter) &&
                           mreader.Read(nodeAddr + (ulong)valDiff, values, elementConverter) &&
                           ForEachMemoryBlockRecursive(mreader, elementConverter, memoryBlockPredicate,
                                                       boolConverter, ptrConverter,
                                                       leftAddr[0], leftDiff, rightDiff, isNilDiff, valDiff) &&
                           memoryBlockPredicate(values) &&
                           ForEachMemoryBlockRecursive(mreader, elementConverter, memoryBlockPredicate,
                                                       boolConverter, ptrConverter,
                                                       rightAddr[0], leftDiff, rightDiff, isNilDiff, valDiff));
                }

                return(true);
            }
            public override bool ForEachMemoryBlock(MemoryReader mreader, Debugger debugger,
                                                    string name, string type,
                                                    MemoryReader.Converter <double> elementConverter,
                                                    MemoryBlockPredicate memoryBlockPredicate)
            {
                int size = LoadSize(debugger, name);

                if (size <= 0)
                {
                    return(true);
                }

                string nextName     = HeadStr(name) + "->_Next";
                string nextNextName = HeadStr(name) + "->_Next->_Next";
                string nextValName  = HeadStr(name) + "->_Next->_Myval";

                TypeInfo nextInfo = new TypeInfo(debugger, nextName);

                if (!nextInfo.IsValid)
                {
                    return(false);
                }

                MemoryReader.ValueConverter <ulong> nextConverter = mreader.GetPointerConverter(nextInfo.Type, nextInfo.Size);
                if (nextConverter == null)
                {
                    return(false);
                }

                long nextDiff = ExpressionParser.GetAddressDifference(debugger, "(*" + nextName + ")", nextNextName);
                long valDiff  = ExpressionParser.GetAddressDifference(debugger, "(*" + nextName + ")", nextValName);

                if (ExpressionParser.IsInvalidAddressDifference(nextDiff) ||
                    ExpressionParser.IsInvalidAddressDifference(valDiff) ||
                    nextDiff < 0 || valDiff < 0)
                {
                    return(false);
                }

                ulong[] nextTmp = new ulong[1];
                ulong   next    = 0;

                for (int i = 0; i < size; ++i)
                {
                    ulong address = 0;
                    if (next == 0)
                    {
                        address = ExpressionParser.GetValueAddress(debugger, nextName);
                        if (address == 0)
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        address = next + (ulong)nextDiff;
                    }

                    if (!mreader.Read(address, nextTmp, nextConverter))
                    {
                        return(false);
                    }
                    next = nextTmp[0];

                    double[] values = new double[elementConverter.ValueCount()];
                    if (!mreader.Read(next + (ulong)valDiff, values, elementConverter))
                    {
                        return(false);
                    }

                    if (!memoryBlockPredicate(values))
                    {
                        return(false);
                    }
                }

                return(true);
            }
            public override bool ForEachMemoryBlock(MemoryReader mreader, Debugger debugger,
                                                    string name, string type,
                                                    MemoryReader.Converter <double> elementConverter,
                                                    MemoryBlockPredicate memoryBlockPredicate)
            {
                int size = LoadSize(debugger, name);

                if (size <= 0)
                {
                    return(true);
                }

                string headName  = HeadStr(name);
                string leftName  = headName + "->_Left";
                string rightName = headName + "->_Right";
                string isNilName = headName + "->_Isnil";
                string valName   = headName + "->_Myval";

                TypeInfo headInfo = new TypeInfo(debugger, headName);

                if (!headInfo.IsValid)
                {
                    return(false);
                }

                MemoryReader.ValueConverter <byte, byte> boolConverter = new MemoryReader.ValueConverter <byte, byte>();
                MemoryReader.ValueConverter <ulong>      ptrConverter  = mreader.GetPointerConverter(headInfo.Type, headInfo.Size);
                if (ptrConverter == null)
                {
                    return(false);
                }

                long leftDiff  = ExpressionParser.GetAddressDifference(debugger, "(*" + headName + ")", leftName);
                long rightDiff = ExpressionParser.GetAddressDifference(debugger, "(*" + headName + ")", rightName);
                long isNilDiff = ExpressionParser.GetAddressDifference(debugger, "(*" + headName + ")", isNilName);
                long valDiff   = ExpressionParser.GetAddressDifference(debugger, "(*" + headName + ")", valName);

                if (ExpressionParser.IsInvalidAddressDifference(leftDiff) ||
                    ExpressionParser.IsInvalidAddressDifference(rightDiff) ||
                    ExpressionParser.IsInvalidAddressDifference(isNilDiff) ||
                    ExpressionParser.IsInvalidAddressDifference(valDiff) ||
                    leftDiff < 0 || rightDiff < 0 || isNilDiff < 0 || valDiff < 0)
                {
                    return(false);
                }

                ulong address = ExpressionParser.GetValueAddress(debugger, headName);

                if (address == 0)
                {
                    return(false);
                }

                ulong[] headAddr = new ulong[1];
                if (!mreader.Read(address, headAddr, ptrConverter))
                {
                    return(false);
                }

                return(ForEachMemoryBlockRecursive(mreader, elementConverter, memoryBlockPredicate,
                                                   boolConverter, ptrConverter,
                                                   headAddr[0], leftDiff, rightDiff, isNilDiff, valDiff));
            }
            public override bool ForEachMemoryBlock(MemoryReader mreader, Debugger debugger,
                                                    string name, string type,
                                                    MemoryReader.Converter <double> elementConverter,
                                                    MemoryBlockPredicate memoryBlockPredicate)
            {
                int size = LoadSize(debugger, name);

                if (size <= 0)
                {
                    return(true);
                }

                // TODO: All of the debugger-related things should be done
                //   in Initialize().

                // TODO: Handle non-value types,
                //   It is not clear for now where the distinction should be made
                //   in the container or outside. When non-value types are stored
                //   the container effectively stores pointers to objects.
                //   So whether or not it's a pointer-container is defined by the
                //   element type in C# and by the container in C++.
                string     elementType     = debugger.GetExpression(name + ".head.item").Type;
                Expression isValueTypeExpr = debugger.GetExpression("typeof(" + elementType + ").IsValueType");

                if (!isValueTypeExpr.IsValidValue || isValueTypeExpr.Value != "true")
                {
                    return(false);
                }

                //string headPointerPointerName = "(void*)&(" + name + ".head)"; //(void*)IntPtr*
                string headPointerName        = "(void*)*(&(" + name + ".head))";      // (void*)IntPtr
                string nextPointerPointerName = "(void*)&(" + name + ".head.next)";    //(void*)IntPtr*
                string nextPointerName        = "(void*)*(&(" + name + ".head.next))"; // (void*)IntPtr
                string valPointerName         = "(void*)&(" + name + ".head.item)";    // (void*)IntPtr* or (void*)ValueType*

                TypeInfo nextPointerInfo = new TypeInfo(debugger, nextPointerPointerName);
                TypeInfo nextInfo        = new TypeInfo(debugger, nextPointerName);

                if (!nextPointerInfo.IsValid || !nextInfo.IsValid)
                {
                    return(false);
                }

                MemoryReader.ValueConverter <ulong> pointerConverter = mreader.GetPointerConverter(nextPointerInfo.Type, nextPointerInfo.Size);
                if (pointerConverter == null)
                {
                    return(false);
                }

                long nextDiff = ExpressionParser.GetPointerDifference(debugger, headPointerName, nextPointerPointerName);
                long valDiff  = ExpressionParser.GetPointerDifference(debugger, headPointerName, valPointerName);

                if (ExpressionParser.IsInvalidAddressDifference(nextDiff) ||
                    ExpressionParser.IsInvalidAddressDifference(valDiff) ||
                    nextDiff < 0 || valDiff < 0)
                {
                    return(false);
                }

                ulong address = ExpressionParser.GetPointer(debugger, headPointerName);

                if (address == 0)
                {
                    return(false);
                }

                for (int i = 0; i < size; ++i)
                {
                    double[] values = new double[elementConverter.ValueCount()];
                    if (!mreader.Read(address + (ulong)valDiff, values, elementConverter))
                    {
                        return(false);
                    }

                    if (!memoryBlockPredicate(values))
                    {
                        return(false);
                    }

                    ulong[] nextTmp = new ulong[1];
                    if (!mreader.Read(address + (ulong)nextDiff, nextTmp, pointerConverter))
                    {
                        return(false);
                    }
                    address = nextTmp[0];
                }
                return(true);
            }