예제 #1
0
	const_iterator begin() const
	{
		const_iterator::iterator_type start = _ranges.begin(), end = _ranges.begin();
		if(end != _ranges.end())
			++end;
		return const_iterator(_ranges.end(), start, end);
	}
예제 #2
0
RangeMap MetadataManager::_getCopyOfRangesToClean_inlock() {
    RangeMap ranges = SimpleBSONObjComparator::kInstance.makeBSONObjIndexedMap<BSONObj>();
    for (auto it = _rangesToClean.begin(); it != _rangesToClean.end(); ++it) {
        ranges.insert(std::make_pair(it->first, it->second.getMax()));
    }
    return ranges;
}
예제 #3
0
    void RepositoryXL::dump(std::ostream& out) {
        Repository::dump(out);

        out << endl << "calling ranges:";
        if (callingRanges_.empty()) {
            out << " none." << endl;
        } else {
            out << endl << endl;
            for (RangeMap::const_iterator i = callingRanges_.begin();
                i != callingRanges_.end(); ++i) {
                    out << i->second;
            }
        }

        out << endl << "Error messages:";
        if (errorMessageMap_.empty()) {
            out << " none." << endl;
        } else {
            out << endl << endl;
            for (ErrorMessageMap::const_iterator i = errorMessageMap_.begin();
                i != errorMessageMap_.end(); ++i) {
                    out << std::left << std::setw(50) << i->first << i->second->errorMessage() << endl;
            }
        }

        out << endl << endl << "VBA error message: " << vbaError_ << endl;
    }
예제 #4
0
 shared_ptr<CallingRange> RepositoryXL::getCallingRange() {
     string callerName = FunctionCall::instance().callerName();
     if (callerName == "VBA") {
         // Called from VBA - check whether the corresponding calling range
         // object exists and create it if not.
         RangeMap::const_iterator i = callingRanges_.find(callerName);
         if (i == callingRanges_.end()) {
             shared_ptr<CallingRange> callingRange(new CallingRange);
             callingRanges_[callingRange->key()] = callingRange;
             return callingRange;
         } else {
             return i->second;
         }
         // Called from a worksheet formula
     } else if (callerName.empty()) {
         // Calling range not yet named - create a new CallingRange object
         shared_ptr<CallingRange> callingRange(new CallingRange);
         callingRanges_[callingRange->key()] = callingRange;
         return callingRange;
     } else {
         // Calling range already named - return associated CallingRange object
         RangeMap::const_iterator i = callingRanges_.find(callerName);
         OH_REQUIRE(i != callingRanges_.end(), "No calling range named " << callerName);
         return i->second;
     }
 }
예제 #5
0
bool rangeBasedShouldSuppress(int beginLine, clang::ASTContext &context, oclint::RuleBase *rule)
{
    std::string filePath = getMainFilePath(context);
    auto commentRangesIt = rangeMapping.find(filePath);
    RangeSet commentRanges;
    if (commentRangesIt == rangeMapping.end())
    {
        DeclAnnotationRangeCollector annotationCollector;
        commentRanges = annotationCollector.collect(context, rule);
        rangeMapping[filePath] = commentRanges;
    }
    else
    {
        commentRanges = commentRangesIt->second;
    }

    for (const auto& range : commentRanges)
    {
        if (beginLine >= range.first && beginLine <= range.second)
        {
            return true;
        }
    }

    return false;
}
예제 #6
0
TEST(RangeMapTest, inner_ranges) {
	RangeMap rangemap;
	rangemap.addRange(5, 20, 1);
	rangemap.addRange(10, 15, 6);
	ASSERT_EQ(rangemap.numRanges(), 1u);
	CHECK_RANGE("A", rangemap, 5, 20, 1);

	rangemap.addRange(10, 15, 100);
	ASSERT_EQ(rangemap.numRanges(), 3u);
	CHECK_RANGE("B", rangemap, 5, 9, 1);
	CHECK_RANGE("C", rangemap, 10, 15, 100);
	CHECK_RANGE("D", rangemap, 16, 20, 12);

	rangemap.addRange(15, 15, 50);
	ASSERT_EQ(rangemap.numRanges(), 4u);
	CHECK_RANGE("E", rangemap, 5, 9, 1);
	CHECK_RANGE("F", rangemap, 10, 14, 100);
	CHECK_RANGE("G", rangemap, 15, 15, 50);
	CHECK_RANGE("H", rangemap, 16, 20, 12);

	rangemap.addRange(6, 19, 1);
	ASSERT_EQ(rangemap.numRanges(), 3u);
	CHECK_RANGE("I", rangemap, 5, 5, 1);
	CHECK_RANGE("J", rangemap, 6, 19, 1);
	CHECK_RANGE("K", rangemap, 20, 20, 16);
}
예제 #7
0
RangeMap MetadataManager::_getCopyOfRangesToClean_inlock() {
    RangeMap ranges;
    for (auto it = _rangesToClean.begin(); it != _rangesToClean.end(); ++it) {
        ranges.insert(std::make_pair(it->first, it->second.getMax()));
    }
    return ranges;
}
예제 #8
0
TEST(RangeMapTest, iterators) {
	RangeMap rangemap;
	rangemap.addRange(5, 10, 1);
	rangemap.addRange(20, 25, 60);
	ASSERT_EQ(rangemap.numRanges(), 2u);
	using Pair32 = pair<uint32_t,uint32_t>;
	vector<Pair32> pairs = {
		Pair32(5, 1), Pair32(6, 2), Pair32(7, 3), Pair32(8, 4), Pair32(9, 5), Pair32(10, 6),
		Pair32(20, 60), Pair32(21, 61), Pair32(22, 62), Pair32(23, 63), Pair32(24, 64), Pair32(25, 65)
	};
	int count=0;
	for (auto p : rangemap)
		ASSERT_EQ(p, pairs[count++]);
}
예제 #9
0
    void RepositoryXL::collectGarbage(const bool &deletePermanent) {

        RangeMap::iterator i = callingRanges_.begin();
        while (i != callingRanges_.end()) {
            shared_ptr<CallingRange> callingRange = i->second;
            if (callingRange->valid()) {
                ++i;
            } else {
                callingRange->clearResidentObjects(deletePermanent);
                if (callingRange->empty())
                    callingRanges_.erase(i++);
                else
                    ++i;
            }
        }
    }
예제 #10
0
TEST(RangeMapTest, touching_ranges2) {
	RangeMap rangemap;
	rangemap.addRange(7, 8, 10);
	ASSERT_EQ(rangemap.numRanges(), 1u);
	CHECK_RANGE("A", rangemap, 7, 8, 10);

	rangemap.addRange(2, 3, 1);
	ASSERT_EQ(rangemap.numRanges(), 2u);
	CHECK_RANGE("B", rangemap, 2, 3, 1);
	CHECK_RANGE("C", rangemap, 7, 8, 10);

	rangemap.addRange(4, 4, 3);
	ASSERT_EQ(rangemap.numRanges(), 2u);
	CHECK_RANGE("D", rangemap, 2, 4, 1);
	CHECK_RANGE("E", rangemap, 7, 8, 10);
}
예제 #11
0
	void add(value_type start, value_type end)
	{
		if(end <= start)
			return;
		// dirty list represents ranges with alternate elements: start,end,start,end 
		// to insert a new range:
		// find insert point of start. find element before, if it is a start element then it is the start of the new range
		// otherwise the new insertion is
		// find insert point of end. find element after, if it is an end element then it is the end of the new range
		// otherwise the new insertion is
		std::pair<RangeMap::iterator, bool> sloc = _ranges.insert(RangeRec(start, true));

		if(sloc.first != _ranges.begin())
		{
			RangeMap::iterator prev = sloc.first; prev--;
			if(prev->start)
			{
				sloc.first--;
			}
		}
		std::pair<RangeMap::iterator, bool> eloc = _ranges.insert(RangeRec(end, false));
		RangeMap::iterator next = eloc.first; next++;

		if(next != _ranges.end() && !next->start)
		{
			eloc.first++;
		}

		// erase the interior of the range
		++sloc.first;
		if(sloc.first != eloc.first && sloc.first != _ranges.end())
		{
			//eloc.first;
			if(sloc.first != eloc.first)
				_ranges.erase(sloc.first, eloc.first);
			else
				_ranges.erase(sloc.first);
		}
		assert((_ranges.size() - 1) % 2 != 0);
	}
예제 #12
0
TEST(RangeMapTest, overlapping_ranges) {
	RangeMap rangemap;
	rangemap.addRange(5, 8, 10);
	rangemap.addRange(7, 15, 12);
	ASSERT_EQ(rangemap.numRanges(), 1u);
	CHECK_RANGE("A", rangemap, 5, 15, 10);

	rangemap.addRange(10, 20, 1);
	ASSERT_EQ(rangemap.numRanges(), 2u);
	CHECK_RANGE("B", rangemap, 5, 9, 10);
	CHECK_RANGE("C", rangemap, 10, 20, 1);

	rangemap.addRange(2, 7, 7);
	ASSERT_EQ(rangemap.numRanges(), 2u);
	CHECK_RANGE("D", rangemap, 2, 9, 7);
	CHECK_RANGE("E", rangemap, 10, 20, 1);

	rangemap.addRange(1, 12, 100);
	ASSERT_EQ(rangemap.numRanges(), 2u);
	CHECK_RANGE("F", rangemap, 1, 12, 100);
	CHECK_RANGE("G", rangemap, 13, 20, 4);

	rangemap.addRange(0, 30, 1);
	ASSERT_EQ(rangemap.numRanges(), 1u);
	CHECK_RANGE("H", rangemap, 0, 30, 1);
}
예제 #13
0
	iterator end()
	{
		return iterator(_ranges.end(), _ranges.end(), _ranges.end());
	}
예제 #14
0
	const_iterator end() const
	{
		return const_iterator(_ranges.end(), _ranges.end(), _ranges.end());
	}
예제 #15
0
namespace ObjectHandler {

    // Below are three structures which must be declared as static variables rather than
    // class members because std::map cannot be exported across DLL boundaries.

    // The object map declared in the cpp file for the base Repository class.
    extern Repository::ObjectMap objectMap_;

    // A map to associate error messages with Excel range addresses.
    typedef std::map<string, shared_ptr<RangeReference> > ErrorMessageMap;
    ErrorMessageMap errorMessageMap_;

    // Excel cell ranges in which objects have been constructed,
    // keyed by a unique ID which is assigned to each range.
    typedef std::map<string, shared_ptr<CallingRange> > RangeMap;
    RangeMap callingRanges_;

    RepositoryXL &RepositoryXL::instance() {
        if (instance_) {
            RepositoryXL *ret = dynamic_cast<RepositoryXL*>(instance_);
            if (ret) return *ret;
        }
        OH_FAIL("Attempt to reference uninitialized RepositoryXL object");
    }

    void RepositoryXL::clear() {
        objectMap_.clear();
        errorMessageMap_.clear();
        callingRanges_.clear();
    }

    string RepositoryXL::storeObject(
        const string &objectIDRaw,
        const shared_ptr<Object> &object,
        bool overwrite,
        boost::shared_ptr<ValueObject> valueObject) {

            shared_ptr<CallingRange> callingRange = getCallingRange();
            string objectID = callingRange->initializeID(objectIDRaw);
            if (objectIDRaw.empty() && valueObject)
                valueObject->setProperty("OBJECTID", objectID);

            shared_ptr<ObjectWrapperXL> objectWrapperXL;
            ObjectMap::const_iterator result = objectMap_.find(objectID);
            if (result == objectMap_.end()) {
                objectWrapperXL = shared_ptr<ObjectWrapperXL> (
                    new ObjectWrapperXL(objectID, object, callingRange));
                objectMap_[objectID] = objectWrapperXL;
                callingRange->registerObject(objectID, objectWrapperXL);
            } else {
                objectWrapperXL = boost::static_pointer_cast<ObjectWrapperXL>(result->second);
                if (objectWrapperXL->callerKey() != callingRange->key()) {
                    OH_REQUIRE(overwrite, "Cannot create object with ID '" << objectID <<
                        "' in cell " << callingRange->addressString() <<
                        " because an object with that ID already resides in cell " <<
                        objectWrapperXL->callerAddress());
                    objectWrapperXL->resetCaller(callingRange);
                    callingRange->registerObject(objectID, objectWrapperXL);
                }
                objectWrapperXL->reset(object);
            }

            registerObserver(objectWrapperXL);
            return objectWrapperXL->idFull();
    }

    void RepositoryXL::setError(
        const string &message,
        const shared_ptr<FunctionCall> &functionCall) {

            std::ostringstream logMessage, cellMessage;
            cellMessage << functionCall->functionName() << " - " << message;

            string refStr = functionCall->refStr();
            string refStrUpper = boost::algorithm::to_upper_copy(refStr);
            ErrorMessageMap::const_iterator i = errorMessageMap_.find(refStrUpper);
            if (i == errorMessageMap_.end()) {
                shared_ptr<RangeReference> rangeReference(new RangeReference(refStrUpper));
                rangeReference->setErrorMessage(cellMessage.str());
                errorMessageMap_[refStrUpper] = rangeReference;
            } else {
                i->second->setErrorMessage(cellMessage.str());
            }
    }

    void RepositoryXL::logError(
        const string &message,
        const shared_ptr<FunctionCall> &functionCall) {

            // This function is called during error handling and must not throw.

            try {

                if (functionCall) {

                    functionCall->setError();
                    std::ostringstream fullMessage;
                    if (functionCall->callerType() == CallerType::Cell) {
                        setError(message, functionCall);
                        fullMessage << functionCall->addressString() << " - ";
                    } else if (functionCall->callerType() == CallerType::VBA || functionCall->callerType() == CallerType::Menu) {
                        vbaError_ = message;
                        fullMessage << "VBA - ";
                    }

                    fullMessage << functionCall->functionName() << " - " << message;
                    logWriteMessage(fullMessage.str(), 2);

                } else {
                    logWriteMessage(message, 2);
                }

            } catch(...) {}
    }

    string RepositoryXL::retrieveError(const XLOPER *xRangeRef) {

        OH_REQUIRE(xRangeRef->xltype == xltypeRef || xRangeRef->xltype == xltypeSRef,
            "Input parameter is not a range reference.");
        Xloper xRangeText;
        Excel(xlfReftext, &xRangeText, 1, xRangeRef);
        string refStr = ConvertOper(xRangeText());
        string refStrUpper = boost::algorithm::to_upper_copy(refStr);

        ErrorMessageMap::const_iterator i = errorMessageMap_.find(refStrUpper);
        if (i != errorMessageMap_.end())
            return i->second->errorMessage();

        RangeReference selectionReference(refStrUpper);
        for (i = errorMessageMap_.begin(); i != errorMessageMap_.end(); ++i) {
            if (i->second->contains(selectionReference))
                return i->second->errorMessage();
        }

        return "";
    }

    void RepositoryXL::clearError() {
        string refStr = FunctionCall::instance().refStr();
        errorMessageMap_.erase(boost::algorithm::to_upper_copy(refStr));
    }

    void RepositoryXL::collectGarbage(const bool &deletePermanent) {

        RangeMap::iterator i = callingRanges_.begin();
        while (i != callingRanges_.end()) {
            shared_ptr<CallingRange> callingRange = i->second;
            if (callingRange->valid()) {
                ++i;
            } else {
                callingRange->clearResidentObjects(deletePermanent);
                if (callingRange->empty())
                    callingRanges_.erase(i++);
                else
                    ++i;
            }
        }
    }

    shared_ptr<CallingRange> RepositoryXL::getCallingRange() {
        string callerName = FunctionCall::instance().callerName();
        if (callerName == "VBA") {
            // Called from VBA - check whether the corresponding calling range
            // object exists and create it if not.
            RangeMap::const_iterator i = callingRanges_.find(callerName);
            if (i == callingRanges_.end()) {
                shared_ptr<CallingRange> callingRange(new CallingRange);
                callingRanges_[callingRange->key()] = callingRange;
                return callingRange;
            } else {
                return i->second;
            }
            // Called from a worksheet formula
        } else if (callerName.empty()) {
            // Calling range not yet named - create a new CallingRange object
            shared_ptr<CallingRange> callingRange(new CallingRange);
            callingRanges_[callingRange->key()] = callingRange;
            return callingRange;
        } else {
            // Calling range already named - return associated CallingRange object
            RangeMap::const_iterator i = callingRanges_.find(callerName);
            OH_REQUIRE(i != callingRanges_.end(), "No calling range named " << callerName);
            return i->second;
        }
    }

    void RepositoryXL::dump(std::ostream& out) {
        Repository::dump(out);

        out << endl << "calling ranges:";
        if (callingRanges_.empty()) {
            out << " none." << endl;
        } else {
            out << endl << endl;
            for (RangeMap::const_iterator i = callingRanges_.begin();
                i != callingRanges_.end(); ++i) {
                    out << i->second;
            }
        }

        out << endl << "Error messages:";
        if (errorMessageMap_.empty()) {
            out << " none." << endl;
        } else {
            out << endl << endl;
            for (ErrorMessageMap::const_iterator i = errorMessageMap_.begin();
                i != errorMessageMap_.end(); ++i) {
                    out << std::left << std::setw(50) << i->first << i->second->errorMessage() << endl;
            }
        }

        out << endl << endl << "VBA error message: " << vbaError_ << endl;
    }

    std::vector<string> RepositoryXL::callerAddress(const std::vector<string> &objectList) {

        std::vector<string> ret;

        for (std::vector<string>::const_iterator i = objectList.begin();
            i != objectList.end(); ++i) {
                string idStrip = CallingRange::getStub(*i);
                const shared_ptr<ObjectWrapperXL>& objectWrapperXL = boost::static_pointer_cast<ObjectWrapperXL>(
                    getObjectWrapper(idStrip));
                ret.push_back(objectWrapperXL->callerAddress());
        }

        return ret;
    }

    std::vector<string> RepositoryXL::callerKey(const std::vector<string> &objectList) {

        std::vector<string> ret;

        for (std::vector<string>::const_iterator i = objectList.begin();
            i != objectList.end(); ++i) {
                string idStrip = CallingRange::getStub(*i);
                const shared_ptr<ObjectWrapperXL>& objectWrapperXL = boost::static_pointer_cast<ObjectWrapperXL>(
                    getObjectWrapper(idStrip));
                ret.push_back(objectWrapperXL->callerKey());
        }

        return ret;
    }

    std::vector<bool> RepositoryXL::isOrphan(const std::vector<string> &objectList){
        std::vector<bool> ret;

        for (std::vector<string>::const_iterator i = objectList.begin();
            i != objectList.end(); ++i) {
                shared_ptr<ObjectWrapperXL> objectWrapperXL;
                ObjectMap::const_iterator result = objectMap_.find(CallingRange::getStub(*i));
                if (result != objectMap_.end()) {

                    objectWrapperXL = boost::static_pointer_cast<ObjectWrapperXL>(result->second);

                    ret.push_back(!objectWrapperXL->getCallingRange()->valid());
                }
                else {
                    OH_FAIL( "Unable to retrieve object with ID " << *i);
                }
        }
        return ret;

    }

    std::vector<string>
    RepositoryXL::updateCounter(const std::vector<string> &objectList) {
        std::vector<string> ret;

        for (std::vector<string>::const_iterator i = objectList.begin();
            i != objectList.end(); ++i) {

                shared_ptr<ObjectWrapperXL> objectWrapperXL;
                ObjectMap::const_iterator result = objectMap_.find(CallingRange::getStub(*i));
                if (result != objectMap_.end()) {

                    objectWrapperXL = boost::static_pointer_cast<ObjectWrapperXL>(result->second);

                    ret.push_back(objectWrapperXL->getCallingRange()->getUpdateCount());
                }
                else {
                    OH_FAIL( "Unable to retrieve object with ID " << *i);
                }
        }

        return ret;

    }

    string RepositoryXL::formatID(const string &objectID){

        return CallingRange::getStub(objectID);
    }

}
예제 #16
0
TEST(RangeMapTest, disjoint_ranges) {
	RangeMap rangemap;
	rangemap.addRange(5, 8, 1);
	ASSERT_EQ(rangemap.numRanges(), 1u);
	EXPECT_EQ(rangemap.numValues(), 4u);
	CHECK_RANGE("A", rangemap, 5, 8, 1);
	CHECK_ZERO("B", rangemap, 0, 4);
	CHECK_ZERO("C", rangemap, 9, 20);

	rangemap.addRange(10, 15, 5);
	ASSERT_EQ(rangemap.numRanges(), 2u);
	EXPECT_EQ(rangemap.numValues(), 10u);
	CHECK_RANGE("D", rangemap, 5, 8, 1);
	CHECK_RANGE("E", rangemap, 10, 15, 5);
	CHECK_ZERO("F", rangemap, 0, 4);
	CHECK_ZERO("G", rangemap, 9, 9);
	CHECK_ZERO("H", rangemap, 16, 20);

	rangemap.addRange(0, 3, 50);
	ASSERT_EQ(rangemap.numRanges(), 3u);
	EXPECT_EQ(rangemap.numValues(), 14u);
	CHECK_RANGE("I", rangemap, 0, 3, 50);
	CHECK_RANGE("J", rangemap, 5, 8, 1);
	CHECK_RANGE("K", rangemap, 10, 15, 5);
	CHECK_ZERO("L", rangemap, 4, 4);
	CHECK_ZERO("M", rangemap, 9, 9);
	CHECK_ZERO("N", rangemap, 16, 20);

	rangemap.addRange(16, 20, 1);
	ASSERT_EQ(rangemap.numRanges(), 4u);
	EXPECT_EQ(rangemap.numValues(), 19u);
	CHECK_RANGE("O", rangemap, 5, 8, 1);
	CHECK_RANGE("P", rangemap, 10, 15, 5);
	CHECK_RANGE("Q", rangemap, 0, 3, 50);
	CHECK_RANGE("R", rangemap, 16, 20, 1);
}
예제 #17
0
static void check_range (const RangeMap &rangemap, int min, int max, int minval) {
	for (int i=min; i <= max; i++)
		ASSERT_EQ((int)rangemap.valueAt(i), minval+(i-min));
}
예제 #18
0
	void clear() 
	{
		_ranges.clear();
	}
예제 #19
0
 void RepositoryXL::clear() {
     objectMap_.clear();
     errorMessageMap_.clear();
     callingRanges_.clear();
 }
예제 #20
0
static void check_zero (const RangeMap &rangemap, int min, int max) {
	for (int i=min; i <= max; i++)
		ASSERT_EQ(rangemap.valueAt(i), 0u);
}
예제 #21
0
	bool empty() const
	{
		return _ranges.size() == 0;
	}
예제 #22
0
TEST(RangeMapTest, touching_ranges1) {
	RangeMap rangemap;
	rangemap.addRange(5, 8, 10);
	ASSERT_EQ(rangemap.numRanges(), 1u);
	EXPECT_EQ(rangemap.numValues(), 4u);
	CHECK_RANGE("A", rangemap, 5, 8, 10);

	rangemap.addRange(9, 15, 14);
	ASSERT_EQ(rangemap.numRanges(), 1u);
	EXPECT_EQ(rangemap.numValues(), 11u);
	CHECK_RANGE("B", rangemap, 5, 15, 10);

	rangemap.addRange(1, 4, 5);
	ASSERT_EQ(rangemap.numRanges(), 2u);
	EXPECT_EQ(rangemap.numValues(), 15u);
	CHECK_RANGE("C", rangemap, 1, 4, 5);
	CHECK_RANGE("D", rangemap, 5, 15, 10);

	rangemap.addRange(1, 4, 6);
	ASSERT_EQ(rangemap.numRanges(), 1u);
	EXPECT_EQ(rangemap.numValues(), 15u);
	CHECK_RANGE("E", rangemap, 1, 15, 6);
}
예제 #23
0
파일: sharding.cpp 프로젝트: waitman/mongo
        void run() {

            int numShards = 10;
            int numInitialChunks = 5;
            int maxChunks = 100000; // Needed to not overflow the BSONArray's max bytes
            int keySize = 2;

            BSONArrayBuilder chunksB;

            BSONObj lastSplitPt;
            ShardChunkVersion version( 1, 0, OID() );

            //
            // Generate numChunks with a given key size over numShards
            // All chunks have double key values, so we can split them a bunch
            //

            for( int i = -1; i < numInitialChunks; i++ ){

                BSONObjBuilder splitPtB;
                for( int k = 0; k < keySize; k++ ){
                    string field = string( "k" ) + string( 1, (char)('0' + k) );
                    if( i < 0 )
                        splitPtB.appendMinKey( field );
                    else if( i < numInitialChunks - 1 )
                        splitPtB.append( field, (double)i );
                    else
                        splitPtB.appendMaxKey( field );
                }
                BSONObj splitPt = splitPtB.obj();

                if( i >= 0 ){
                    BSONObjBuilder chunkB;

                    chunkB.append( "min", lastSplitPt );
                    chunkB.append( "max", splitPt );

                    int shardNum = rand( numShards );
                    chunkB.append( "shard", "shard" + string( 1, (char)('A' + shardNum) ) );

                    rand( 2 ) ? version.incMajor() : version.incMinor();
                    version.addToBSON( chunkB, "lastmod" );

                    chunksB.append( chunkB.obj() );
                }

                lastSplitPt = splitPt;
            }

            BSONArray chunks = chunksB.arr();

            // log() << "Chunks generated : " << chunks << endl;

            DBClientMockCursor chunksCursor( chunks );

            // Setup the empty ranges and versions first
            RangeMap ranges;
            ShardChunkVersion maxVersion = ShardChunkVersion( 0, 0, OID() );
            VersionMap maxShardVersions;

            // Create a differ which will track our progress
            boost::shared_ptr< DefaultDiffAdapter > differ( _inverse ? new InverseDiffAdapter() : new DefaultDiffAdapter() );
            differ->attach( "test", ranges, maxVersion, maxShardVersions );

            // Validate initial load
            differ->calculateConfigDiff( chunksCursor );
            validate( chunks, ranges, maxVersion, maxShardVersions );

            // Generate a lot of diffs, and keep validating that updating from the diffs always
            // gives us the right ranges and versions

            int numDiffs = 135; // Makes about 100000 chunks overall
            int numChunks = numInitialChunks;
            for( int i = 0; i < numDiffs; i++ ){

                // log() << "Generating new diff... " << i << endl;

                BSONArrayBuilder diffsB;
                BSONArrayBuilder newChunksB;
                BSONObjIterator chunksIt( chunks );

                while( chunksIt.more() ){

                    BSONObj chunk = chunksIt.next().Obj();

                    int randChoice = rand( 10 );

                    if( randChoice < 2 && numChunks < maxChunks ){
                        // Simulate a split

                        // log() << " ...starting a split with chunk " << chunk << endl;

                        BSONObjBuilder leftB;
                        BSONObjBuilder rightB;
                        BSONObjBuilder midB;

                        for( int k = 0; k < keySize; k++ ){
                            string field = string( "k" ) + string( 1, (char)('0' + k) );

                            BSONType maxType = chunk["max"].Obj()[field].type();
                            double max = maxType == NumberDouble ? chunk["max"].Obj()[field].Number() : 0.0;
                            BSONType minType = chunk["min"].Obj()[field].type();
                            double min = minType == NumberDouble ? chunk["min"].Obj()[field].Number() : 0.0;

                            if( minType == MinKey ){
                                midB.append( field, max - 1.0 );
                            }
                            else if( maxType == MaxKey ){
                                midB.append( field, min + 1.0 );
                            }
                            else {
                                midB.append( field, ( max + min ) / 2.0 );
                            }
                        }

                        BSONObj midPt = midB.obj();
                        // Only happens if we can't split the min chunk
                        if( midPt.isEmpty() ) continue;

                        leftB.append( chunk["min"] );
                        leftB.append( "max", midPt );
                        rightB.append( "min", midPt );
                        rightB.append( chunk["max"] );

                        leftB.append( chunk["shard"] );
                        rightB.append( chunk["shard"] );

                        version.incMajor();
                        version._minor = 0;
                        version.addToBSON( leftB, "lastmod" );
                        version.incMinor();
                        version.addToBSON( rightB, "lastmod" );

                        BSONObj left = leftB.obj();
                        BSONObj right = rightB.obj();

                        // log() << " ... split into " << left << " and " << right << endl;

                        newChunksB.append( left );
                        newChunksB.append( right );

                        diffsB.append( right );
                        diffsB.append( left );

                        numChunks++;
                    }
                    else if( randChoice < 4 && chunksIt.more() ){
                        // Simulate a migrate

                        // log() << " ...starting a migrate with chunk " << chunk << endl;

                        BSONObj prevShardChunk;
                        while( chunksIt.more() ){
                            prevShardChunk = chunksIt.next().Obj();
                            if( prevShardChunk["shard"].String() == chunk["shard"].String() ) break;

                            // log() << "... appending chunk from diff shard: " << prevShardChunk << endl;
                            newChunksB.append( prevShardChunk );

                            prevShardChunk = BSONObj();
                        }

                        // We need to move between different shards, hence the weirdness in logic here
                        if( ! prevShardChunk.isEmpty() ){

                            BSONObjBuilder newShardB;
                            BSONObjBuilder prevShardB;

                            newShardB.append( chunk["min"] );
                            newShardB.append( chunk["max"] );
                            prevShardB.append( prevShardChunk["min"] );
                            prevShardB.append( prevShardChunk["max"] );

                            int shardNum = rand( numShards );
                            newShardB.append( "shard", "shard" + string( 1, (char)('A' + shardNum) ) );
                            prevShardB.append( prevShardChunk["shard"] );

                            version.incMajor();
                            version._minor = 0;
                            version.addToBSON( newShardB, "lastmod" );
                            version.incMinor();
                            version.addToBSON( prevShardB, "lastmod" );

                            BSONObj newShard = newShardB.obj();
                            BSONObj prevShard = prevShardB.obj();

                            // log() << " ... migrated to " << newShard << " and updated " << prevShard << endl;

                            newChunksB.append( newShard );
                            newChunksB.append( prevShard );

                            diffsB.append( newShard );
                            diffsB.append( prevShard );

                        }
                        else{
                            // log() << "... appending chunk, no more left: " << chunk << endl;
                            newChunksB.append( chunk );
                        }
                    }
                    else{
                        // log() << "Appending chunk : " << chunk << endl;
                        newChunksB.append( chunk );
                    }

                }

                BSONArray diffs = diffsB.arr();
                chunks = newChunksB.arr();

                // log() << "Diffs generated : " << diffs << endl;
                // log() << "All chunks : " << chunks << endl;

                // Rarely entirely clear out our data
                if( rand( 10 ) < 1 ){
                    diffs = chunks;
                    ranges.clear();
                    maxVersion = ShardChunkVersion( 0, 0, OID() );
                    maxShardVersions.clear();
                }

                // log() << "Total number of chunks : " << numChunks << " iteration " << i << endl;

                DBClientMockCursor diffCursor( diffs );

                differ->calculateConfigDiff( diffCursor );

                validate( chunks, ranges, maxVersion, maxShardVersions );

            }

        }