Sirikata
libcore/include/sirikata/core/transfer/Range.hpp
Go to the documentation of this file.
00001 /*  Sirikata Transfer -- Content Transfer management system
00002  *  Range.hpp
00003  *
00004  *  Copyright (c) 2008, Patrick Reiter Horn
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions are
00009  *  met:
00010  *  * Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *  * Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *  * Neither the name of Sirikata nor the names of its contributors may
00017  *    be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00021  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00023  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00024  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00026  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 
00033 #ifndef SIRIKATA_Range_HPP__
00034 #define SIRIKATA_Range_HPP__
00035 
00036 namespace Sirikata {
00037 namespace Transfer {
00038 
00039 typedef uint64 cache_usize_type;
00040 typedef int64 cache_ssize_type;
00041 
00042 enum Initializer { LENGTH, BOUNDS };
00043 
00045 class Range {
00046 public:
00047     typedef cache_usize_type base_type;
00048     typedef cache_usize_type length_type;
00049 
00050     typedef length_type size_type;
00051         typedef cache_ssize_type difference_type;
00052 
00053     //static const length_type npos = (cache_usize_type)-1;
00054 private:
00056     base_type mStart;
00058     length_type mLength;
00059 
00060     bool mWholeFile;
00061 
00063     Range(base_type start, base_type end);
00064 public:
00065 
00067     explicit Range(bool wholeFile)
00068         : mStart(0), mLength(0), mWholeFile(wholeFile) {
00069     }
00070 
00072     Range(base_type start, bool wholeFile)
00073         : mStart(start), mLength(0), mWholeFile(wholeFile) {
00074     }
00075 
00081     Range(base_type start, base_type length,
00082             Initializer type, bool wholeFile=false)
00083         : mStart(start), mLength(type==LENGTH?length:length-start), mWholeFile(wholeFile) {
00084     }
00085 
00087     Range(const Range &other)
00088         : mStart(other.mStart), mLength(other.mLength), mWholeFile(other.mWholeFile) {
00089     }
00090 
00095     inline bool goesToEndOfFile() const {
00096         return mWholeFile;
00097     }
00098 
00100     inline base_type startbyte() const {
00101         return mStart;
00102     }
00107     inline length_type length() const {
00108         return mLength;
00109     }
00110     inline length_type size() const {
00111            return length();
00112     }
00113 
00115     inline base_type endbyte() const {
00116         return mStart + mLength - 1;
00117     }
00118 
00120     inline void setLength(length_type l, bool wholeFile) {
00121         mLength = l;
00122         mWholeFile = wholeFile;
00123     }
00125     inline void setBase(base_type s) {
00126         mStart = s;
00127     }
00128 
00130     inline bool operator< (const Range &other) const {
00131         if (mLength == other.mLength) {
00132             if (mStart == other.mStart && (mWholeFile || other.mWholeFile)) {
00133                 return other.mWholeFile && !mWholeFile;
00134             }
00135             return mStart < other.mStart;
00136         }
00137         return mLength < other.mLength;
00138     }
00139 
00146     friend inline std::ostream &operator << (std::ostream &os, const Range &range) {
00147         os << "[" << range.startbyte();
00148         if (range.mLength) {
00149             os << ", " << range.endbyte();
00150         }
00151         if (range.mWholeFile) {
00152             os << " => eof";
00153         }
00154         os << ")";
00155         return os;
00156     }
00157 
00160     template <class ListType>
00161     bool isContainedBy(const ListType &list) const {
00162 
00163         typename ListType::const_iterator iter = list.begin(),
00164             enditer = list.end();
00165 
00166         bool found = false;
00167         base_type lastEnd = 0;
00168 
00169         while (iter != enditer) {
00170             base_type start = (*iter).startbyte();
00171             if (mStart >= start && (*iter).goesToEndOfFile()) {
00172                 return true;
00173             }
00174             base_type end = (*iter).endbyte();
00175 
00176             if (mStart >= start && mStart <= end) {
00177                 found = true;
00178                 lastEnd = end;
00179                 break;
00180             }
00181             ++iter;
00182         }
00183         if (!found) {
00184             return false;
00185         }
00186         found = false;
00187         while (iter != enditer) {
00188             base_type start = (*iter).startbyte();
00189             if (start > lastEnd) {
00190                 found = false; // gap in range.
00191                 break;
00192             }
00193             base_type end = (*iter).endbyte();
00194 
00195             // only an infinite range can include an infinite range.
00196             if ((*iter).goesToEndOfFile()) {
00197                 return true;
00198             }
00199             if (!goesToEndOfFile() && endbyte() <= end) {
00200                 found = true;
00201                 break;
00202             }
00203             lastEnd = end;
00204             ++iter;
00205         }
00206         return found;
00207     }
00208 
00209     inline bool contains(const Range &other) const {
00210         if (this->goesToEndOfFile()) {
00211             // endbyte infinitely long -- can contain anything.
00212             return (other.startbyte() >= this->startbyte());
00213         } else if (!this->goesToEndOfFile() && other.goesToEndOfFile()) {
00214             // endbyte is not infinite.
00215             return false;
00216         } else {
00217             return (other.startbyte() >= this->startbyte()) &&
00218                 (other.endbyte() <= this->endbyte());
00219         }
00220     }
00221 
00222     inline bool isContainedBy(const Range &other) const {
00223         return other.contains(*this);
00224     }
00225 
00227     template <class ListType>
00228     void addToList(const typename ListType::value_type &data, ListType &list) const {
00229         if (length()<=0) {
00230             // Ensure that no dummy data will get added. Shouldn't get here.
00231             return;
00232         }
00233         if (startbyte()==0 && goesToEndOfFile()) {
00234             // favor a single chunk covering the whole file.
00235             list.clear();
00236             list.insert(list.end(), data);
00237             return;
00238         }
00239 
00240         typename ListType::iterator endIter=list.end(), iter=list.begin();
00241         Range::base_type startdata = startbyte();
00242         Range::base_type maxend = startdata;
00243         bool includeseof = false;
00244         while (iter != endIter) {
00245             // maxend is not relevant for ranges strictly above us.
00246             if ((*iter).startbyte() > startdata) {
00247                 break;
00248             }
00249             if ((*iter).endbyte() > maxend) {
00250                 maxend = (*iter).endbyte();
00251             }
00252             if ((*iter).goesToEndOfFile()) {
00253                 includeseof = true;
00254             }
00255             // we do not want to allow for more than one
00256             // range starting at the same start byte--
00257             // If this is the case, one is guaranteed to overlap.
00258             if ((*iter).startbyte() >= startdata) {
00259                 break;
00260             }
00261             ++iter;
00262         }
00263         if (includeseof || (maxend > endbyte() && !goesToEndOfFile())) {
00264             return; // already included by another range.
00265         }
00266         iter = list.insert(iter, data);
00267         ++iter;
00268         while (iter != endIter) {
00269             typename ListType::iterator nextIter = iter;
00270             ++nextIter;
00271 
00272             if (goesToEndOfFile() ||
00273                     (!(*iter).goesToEndOfFile() && (*iter).endbyte() <= endbyte())) {
00274                 list.erase(iter);
00275             }
00276 
00277             iter = nextIter;
00278         }
00279     }
00280 
00281     template <class ListType>
00282     static std::ostream &printRangeList(
00283                 std::ostream &os,
00284                 const ListType &cdata,
00285                 Range checkFor=Range(false),
00286                 bool exact=false) {
00287         bool start = true;
00288         typename ListType::const_iterator iter = cdata.begin(),
00289             enditer = cdata.end();
00290         for (;
00291                 iter != enditer;
00292                 ++iter) {
00293             os << (start?'{':',') << (*iter);
00294             start = false;
00295             if ((Range)(*iter) == checkFor) {
00296                 os << "**";
00297             }
00298             else if (!exact) {
00299                 if ((*iter).isContainedBy(checkFor)) {
00300                     os << "++";
00301                 }
00302             }
00303         }
00304         os << '}';
00305         return os;
00306     }
00307 
00309     inline bool operator== (const Range &other) const {
00310         return mLength == other.mLength &&
00311             mStart == other.mStart &&
00312             mWholeFile == other.mWholeFile;
00313     }
00314 };
00315 
00317 typedef std::list<Range> RangeList;
00318 
00319 }
00320 }
00321 
00322 #endif