From: Peter Duniho on
On Fri, 18 Sep 2009 22:27:43 -0700, Michelle <michelle(a)notvalid.nomail>
wrote:

> [...]
> It works without error (so far we've verified) and that's most important.
> But efficiency is the second most important.
> I do not have enough knowledge and experience with C # to construct your
> explanation into code.
> If you have time and opportunity to spare, you might want to send an
> example. I would at least grateful.

Here's a short snippet illustrating what I mean. Assume a structure like
this:

struct PatternSubset
{
public readonly int ib;
public readonly byte[] rgb;

public PatternSubset(int ib, byte[] rgb)
{
this.ib = ib;
this.rgb = rgb;
}
}


then, rather than just calling FRangesEqual() for a given pattern, call it
in a loop like this:

// This is probably passed into the search method, but I'll just show
a regular
// local variable initialization here
PatternSubset[] rgps = new
{
new PatternSubset(0, new byte[] { 0x07, 0x00 }),
new PatternSubset(3, new byte[] { 0x00, 0x00, 0x00, 0x07, 0x00 }),
new PatternSubset(9, new byte[] { 0x00, 0x00, 0x00, 0x08, 0x00 })
};



// Instead of a single call to FRangesEqual(), you'll have something
like this:
bool fMatches = true;
foreach (PatternSubset ps in lps)
{
if (!FRangesEqual(rgbBlockCur, ibOffset + ps.ib, ps.rgb.Length,
ps.rgb))
{
fMatches = false;
break;
}
}

if (fMatches)
{
// do whatever
}

That's the basic idea. The above doesn't do anything to deal with the
cross-block boundary, so you'll have to adapt the idea shown in the
example to the code you're actually using. It won't work as it is shown
exactly above. But if you take the time to understand both the original
example, and the example above, you should be able to combine them
correctly.

One suggestion for doing that combination: you'll note that in the above,
the call to FRangesEqual() is logically equivalent to the call to
FRangesEqual() in the original example. So, the calculated value
"ibOffset + ps.ib" is logically equivalent to the "ibOffset" value in the
original example. It may make the code more readable if you abstract out
the logic that handles dealing with one or two blocks, like this:

In the original example, instead of the section of code that looks like
this:

if (ibOffset + rgbPattern.Length <= cbBlockCur)
{
if (FRangesEqual(rgbBlockCur, ibOffset, rgbPattern.Length,
rgbPattern))
{
return ibBaseOffset + ibOffset;
}
}
else if (ibOffset + rgbPattern.Length <= cbBlockCur + cbBlockNext)
{
if (FRangesEqual(rgbBlockCur, ibOffset, cbBlockCur - ibOffset,
rgbPattern) &&
FRangesEqual(rgbBlockNext, 0, ibOffset + rgbPattern.Length -
cbBlockCur, rgbPattern))
{
return ibBaseOffset + ibOffset;
}
}
else
{
return -1;
}

You'd replace it with a section of code that looks like this:

if (ibOffset + rgbPattern.Length <= cbBlockCur + cbBlockNext)
{
if (FRangesEqualInBlocks(rgbBlockCur, cbBlockCur, rgbBlockNext,
ibOffset, rgbPattern))
{
return ibBaseOffset + ibOffset;
}
}
else
{
return -1;
}

The FRangesEqualInBlocks() method then looks like this (yes, I know that's
a lot of method arguments...and that's not even allowing for the one more
argument required if you want error checking):

bool FRangesEqualInBlocks(byte[] rgbBlockCur, int cbBlockCur, byte[]
rgbBlockNext, long ibOffset, byte[] rgbPattern)
{
if (ibOffset + rgbPattern.Length <= cbBlockCur)
{
return FRangesEqual(rgbBlockCur, ibOffset, rgbPattern.Length,
rgbPattern);
}

return FRangesEqual(rgbBlockCur, ibOffset, cbBlockCur - ibOffset,
rgbPattern) &&
FRangesEqual(rgbBlockNext, 0, ibOffset + rgbPattern.Length -
cbBlockCur, rgbPattern);
}

Finally, applying that to the example I started out with in this post,
instead of the code I wrote where you'd just call FRangesEqual(), instead
you'd call this new FRangesEqualInBlocks() method:

foreach (PatternSubset ps in lps)
{
if (!FRangesEqualInBlocks(rgbBlockCur, cbBlockCur, rgbBlockNext,
ibOffset + ps.ib, ps.rgb))
{
fMatches = false;
break;
}
}

Oh, one other thing. The original code example was able to detect the
termination condition based solely on "ibOffset" as compared to the
remaining data available. You can do basically the same thing even with
the list of segments to compare; just apply that logic to the last segment
in the list (you may want to validate the list of segments by ensuring
that they are in order of the offset, and that they don't overlap...that
is, the offset plus the length of the byte[] for one segment is less than
the offset for the next segment).

Validation might look something like this:

int cbPattern = -1;

foreach (PatternSubset ps in rgps)
{
if (ps.ib <= cbPattern)
{
// report error

// note that technically, "ps.ib < cbPattern" would
// be okay, but you may want to consider the "equals"
// condition an error anyway, because if it happens,
// it means someone passed in multiple pattern subsets
// that could have been merged. It just depends on how
// strict you want to be with callers.
}

cbPattern = ps.ib + ps.rgb.Length;
}

And then the termination condition becomes this:

if (ibOffset + cbPattern <= cbBlockCur + cbBlockNext)
{
// code to loop through PatternSubset[]
}
else
{
return -1;
}

Hope that helps, and that walking you through the different variations
leading to the eventual solution is okay. Hopefully that allows you to
understand the evolution of the design better, without confusing you too
much, and leaving some actual work for _you_ to do. :)

Pete
From: Michelle on
Peter,

Thanks for the code and explanation.
This week i'm going to work with the code and I'll let you know if it
succeeded.

Regards,

Michelle


From: Michelle on
Peter,

I'm stuck.
I have your code and explanations read several times teh last days, but I do
not manage it.
I give up. I'm lost with the different variants. It's confusing me to much.
You've inserted so much time and ernergie already, that's all I can ask of
you.
Very sincere thanks for all the work and patience.

Regards,

Michelle.