LCOV - code coverage report
Current view: top level - toolkit/components/url-classifier - ChunkSet.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 99 124 79.8 %
Date: 2017-07-14 16:53:18 Functions: 13 13 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "ChunkSet.h"
       7             : 
       8             : namespace mozilla {
       9             : namespace safebrowsing {
      10             : 
      11             : const size_t ChunkSet::IO_BUFFER_SIZE;
      12             : 
      13             : nsresult
      14          12 : ChunkSet::Serialize(nsACString& aChunkStr)
      15             : {
      16          12 :   aChunkStr.Truncate();
      17          24 :   for (const Range& range : mRanges) {
      18          12 :     if (&range != &mRanges[0]) {
      19           0 :       aChunkStr.Append(',');
      20             :     }
      21             : 
      22          12 :     aChunkStr.AppendInt((int32_t)range.Begin());
      23          12 :     if (range.Begin() != range.End()) {
      24           2 :       aChunkStr.Append('-');
      25           2 :       aChunkStr.AppendInt((int32_t)range.End());
      26             :     }
      27             :   }
      28             : 
      29          12 :   return NS_OK;
      30             : }
      31             : 
      32             : nsresult
      33          48 : ChunkSet::Set(uint32_t aChunk)
      34             : {
      35          48 :   if (!Has(aChunk)) {
      36          48 :     Range chunkRange(aChunk, aChunk);
      37             : 
      38          48 :     if (mRanges.Length() == 0) {
      39          42 :       if (!mRanges.AppendElement(chunkRange, fallible)) {
      40          42 :         return NS_ERROR_OUT_OF_MEMORY;
      41             :       }
      42          42 :       return NS_OK;
      43             :     }
      44             : 
      45           6 :     if (mRanges.LastElement().Precedes(chunkRange)) {
      46           6 :       mRanges.LastElement().End(aChunk);
      47           0 :     } else if (chunkRange.Precedes(mRanges[0])) {
      48           0 :       mRanges[0].Begin(aChunk);
      49             :     } else {
      50           0 :       ChunkSet tmp;
      51           0 :       if (!tmp.mRanges.AppendElement(chunkRange, fallible)) {
      52           0 :         return NS_ERROR_OUT_OF_MEMORY;
      53             :       }
      54             : 
      55           0 :       return Merge(tmp);
      56             :     }
      57             :   }
      58             : 
      59           6 :   return NS_OK;
      60             : }
      61             : 
      62             : bool
      63          62 : ChunkSet::Has(uint32_t aChunk) const
      64             : {
      65             :   size_t idx;
      66          62 :   return BinarySearchIf(mRanges, 0, mRanges.Length(),
      67         124 :                         Range::IntersectionComparator(Range(aChunk, aChunk)),
      68         124 :                         &idx);
      69             :                         // IntersectionComparator works because we create a
      70             :                         // single-chunk range.
      71             : }
      72             : 
      73             : nsresult
      74          36 : ChunkSet::Merge(const ChunkSet& aOther)
      75             : {
      76          36 :   size_t oldLen = mRanges.Length();
      77             : 
      78          54 :   for (const Range& mergeRange : aOther.mRanges) {
      79          18 :     if (!HasSubrange(mergeRange)) {
      80          12 :       if (!mRanges.InsertElementSorted(mergeRange, fallible)) {
      81           0 :         return NS_ERROR_OUT_OF_MEMORY;
      82             :       }
      83             :     }
      84             :   }
      85             : 
      86          36 :   if (oldLen < mRanges.Length()) {
      87          12 :     for (size_t i = 1; i < mRanges.Length(); i++) {
      88           1 :       while (mRanges[i - 1].FoldLeft(mRanges[i])) {
      89           1 :         mRanges.RemoveElementAt(i);
      90             : 
      91           1 :         if (i == mRanges.Length()) {
      92           1 :           return NS_OK;
      93             :         }
      94             :       }
      95             :     }
      96             :   }
      97             : 
      98          35 :   return NS_OK;
      99             : }
     100             : 
     101             : uint32_t
     102         182 : ChunkSet::Length() const
     103             : {
     104         182 :   uint32_t len = 0;
     105         284 :   for (const Range& range : mRanges) {
     106         102 :     len += range.Length();
     107             :   }
     108             : 
     109         182 :   return len;
     110             : }
     111             : 
     112             : nsresult
     113          12 : ChunkSet::Remove(const ChunkSet& aOther)
     114             : {
     115          18 :   for (const Range& removalRange : aOther.mRanges) {
     116             : 
     117           6 :     if (mRanges.Length() == 0) {
     118           0 :       return NS_OK;
     119             :     }
     120             : 
     121          12 :     if (mRanges.LastElement().End() < removalRange.Begin() ||
     122           6 :         aOther.mRanges.LastElement().End() < mRanges[0].Begin()) {
     123           0 :       return NS_OK;
     124             :     }
     125             : 
     126             :     size_t intersectionIdx;
     127          30 :     while (BinarySearchIf(mRanges, 0, mRanges.Length(),
     128          24 :            Range::IntersectionComparator(removalRange), &intersectionIdx)) {
     129             : 
     130          12 :       ChunkSet remains;
     131           6 :       nsresult rv = mRanges[intersectionIdx].Remove(removalRange, remains);
     132             : 
     133           6 :       if (NS_FAILED(rv)) {
     134           0 :         return rv;
     135             :       }
     136             : 
     137           6 :       mRanges.RemoveElementAt(intersectionIdx);
     138           6 :       if (!mRanges.InsertElementsAt(intersectionIdx, remains.mRanges,
     139             :                                     fallible)) {
     140           0 :         return NS_ERROR_OUT_OF_MEMORY;
     141             :       }
     142             :     }
     143             :   }
     144             : 
     145          12 :   return NS_OK;
     146             : }
     147             : 
     148             : void
     149          12 : ChunkSet::Clear()
     150             : {
     151          12 :   mRanges.Clear();
     152          12 : }
     153             : 
     154             : nsresult
     155          12 : ChunkSet::Write(nsIOutputStream* aOut)
     156             : {
     157          24 :   nsTArray<uint32_t> chunks(IO_BUFFER_SIZE);
     158             : 
     159          18 :   for (const Range& range : mRanges) {
     160          13 :     for (uint32_t chunk = range.Begin(); chunk <= range.End(); chunk++) {
     161           7 :       chunks.AppendElement(chunk);
     162             : 
     163           7 :       if (chunks.Length() == chunks.Capacity()) {
     164           0 :         nsresult rv = WriteTArray(aOut, chunks);
     165             : 
     166           0 :         if (NS_FAILED(rv)) {
     167           0 :           return rv;
     168             :         }
     169             : 
     170           0 :         chunks.Clear();
     171             :       }
     172             :     }
     173             :   }
     174             : 
     175          12 :   nsresult rv = WriteTArray(aOut, chunks);
     176             : 
     177          12 :   if (NS_FAILED(rv)) {
     178           0 :     return rv;
     179             :   }
     180             : 
     181          12 :   return NS_OK;
     182             : }
     183             : 
     184             : nsresult
     185          60 : ChunkSet::Read(nsIInputStream* aIn, uint32_t aNumElements)
     186             : {
     187         120 :   nsTArray<uint32_t> chunks(IO_BUFFER_SIZE);
     188             : 
     189         120 :   while (aNumElements != 0) {
     190          30 :     chunks.Clear();
     191             : 
     192          30 :     uint32_t numToRead = aNumElements > IO_BUFFER_SIZE ? IO_BUFFER_SIZE : aNumElements;
     193             : 
     194          30 :     nsresult rv = ReadTArray(aIn, &chunks, numToRead);
     195             : 
     196          30 :     if (NS_FAILED(rv)) {
     197           0 :       return rv;
     198             :     }
     199             : 
     200          30 :     aNumElements -= numToRead;
     201             : 
     202          65 :     for (uint32_t c : chunks) {
     203          35 :       rv = Set(c);
     204             : 
     205          35 :       if (NS_FAILED(rv)) {
     206           0 :         return rv;
     207             :       }
     208             :     }
     209             :   }
     210             : 
     211          60 :   return NS_OK;
     212             : }
     213             : 
     214             : bool
     215          18 : ChunkSet::HasSubrange(const Range& aSubrange) const
     216             : {
     217          18 :   for (const Range& range : mRanges) {
     218           7 :     if (range.Contains(aSubrange)) {
     219          13 :       return true;
     220           2 :     } else if (!(aSubrange.Begin() > range.End() ||
     221           1 :                  range.Begin() > aSubrange.End())) {
     222             :       // In this case, aSubrange overlaps this range but is not a subrange.
     223             :       // because the ChunkSet implementation ensures that there are no
     224             :       // overlapping ranges, this means that aSubrange cannot be a subrange of
     225             :       // any of the following ranges
     226           1 :       return false;
     227             :     }
     228             :   }
     229             : 
     230          11 :   return false;
     231             : }
     232             : 
     233             : uint32_t
     234         102 : ChunkSet::Range::Length() const
     235             : {
     236         102 :   return mEnd - mBegin + 1;
     237             : }
     238             : 
     239             : nsresult
     240           6 : ChunkSet::Range::Remove(const Range& aRange, ChunkSet& aRemainderSet) const
     241             : {
     242           6 :   if (mBegin < aRange.mBegin && aRange.mBegin <= mEnd) {
     243             :     // aRange overlaps & follows this range
     244           1 :     Range range(mBegin, aRange.mBegin - 1);
     245           1 :     if (!aRemainderSet.mRanges.AppendElement(range, fallible)) {
     246           0 :       return NS_ERROR_OUT_OF_MEMORY;
     247             :     }
     248             :   }
     249             : 
     250           6 :   if (mBegin <= aRange.mEnd && aRange.mEnd < mEnd) {
     251             :     // aRange overlaps & precedes this range
     252           0 :     Range range(aRange.mEnd + 1, mEnd);
     253           0 :     if (!aRemainderSet.mRanges.AppendElement(range, fallible)) {
     254           0 :       return NS_ERROR_OUT_OF_MEMORY;
     255             :     }
     256             :   }
     257             : 
     258           6 :   return NS_OK;
     259             : }
     260             : 
     261             : bool
     262           1 : ChunkSet::Range::FoldLeft(const Range& aRange)
     263             : {
     264           1 :   if (Contains(aRange)) {
     265           0 :     return true;
     266           3 :   } else if (Precedes(aRange) ||
     267           2 :              (mBegin <= aRange.mBegin && aRange.mBegin <= mEnd)) {
     268           1 :     mEnd = aRange.mEnd;
     269           1 :     return true;
     270             :   }
     271             : 
     272           0 :   return false;
     273             : }
     274             : 
     275             : } // namespace safebrowsing
     276             : } // namespace mozilla

Generated by: LCOV version 1.13