private unsafe List<TextRange> FindWorker(
      TextFragment textFragment,
      Func<TextRange, TextRange?> postProcess, 
      IOperationProgressTracker progressTracker,
      int maxResultSize) {
      List<TextRange> result = null;

      // Note: From C# spec: If E is zero, then no allocation is made, and
      // the pointer returned is implementation-defined.
      byte* searchBuffer = stackalloc byte[this.SearchBufferSize];
      var searchParams = new NativeMethods.SearchParams {
        TextStart = textFragment.StartPtr,
        TextLength = textFragment.Length,
        SearchBuffer = new IntPtr(searchBuffer),
      };

      while (true) {
        // Perform next search
        Search(ref searchParams);
        if (searchParams.MatchStart == IntPtr.Zero)
          break;

        // Convert match from *byte* pointers to a *text* range
        var matchFragment = textFragment.Sub(searchParams.MatchStart, searchParams.MatchLength);
        var matchRange = new TextRange(matchFragment.Position, matchFragment.Length);

        // Post process match, maybe skipping it
        var postMatchRange = postProcess(matchRange);
        if (postMatchRange == null)
          continue;
        matchRange = postMatchRange.Value;

        // Add to result collection
        if (result == null)
          result = new List<TextRange>();
        result.Add(matchRange);

        // Check it is time to end processing early.
        maxResultSize--;
        progressTracker.AddResults(1);
        if (maxResultSize <= 0 || progressTracker.ShouldEndProcessing) {
          CancelSearch(ref searchParams);
          break;
        }
      }

      return result ?? NoResult;
    }
 public TextRange? FindFirst(TextFragment textFragment, IOperationProgressTracker progressTracker) {
   return null;
 }
 public IList<TextRange> FindAll(
   TextFragment textFragment,
   Func<TextRange, TextRange?> postProcess,
   IOperationProgressTracker progressTracker) {
   return NoResult;
 }
 public TextRange? FindFirst(TextFragment textFragment, IOperationProgressTracker progressTracker) {
   var result = FindWorker(textFragment, x => x, progressTracker, 1);
   if (result.Count == 0)
     return null;
   return result.First();
 }
 public IList<TextRange> FindAll(TextFragment textFragment, Func<TextRange, TextRange?> postProcess, IOperationProgressTracker progressTracker) {
   if (progressTracker.ShouldEndProcessing)
     return NoResult;
   return FindWorker(textFragment, postProcess, progressTracker, int.MaxValue);
 }