void validate(CollectionChangeSet const& info)
    {
        info.insertions.verify();
        info.deletions.verify();
        info.modifications.verify();

        std::vector<size_t> move_sources;
        for (auto const& move : info.moves)
            move_sources.push_back(m_initial[move.from]);

        // Apply the changes from the transaction log to our copy of the
        // initial, using UITableView's batching rules (i.e. delete, then
        // insert, then update)
        auto it = util::make_reverse_iterator(info.deletions.end());
        auto end = util::make_reverse_iterator(info.deletions.begin());
        for (; it != end; ++it) {
            m_initial.erase(m_initial.begin() + it->first, m_initial.begin() + it->second);
        }

        for (auto const& range : info.insertions) {
            for (auto i = range.first; i < range.second; ++i)
                m_initial.insert(m_initial.begin() + i, m_linkview->get(i).get_int(0));
        }

        for (auto const& range : info.modifications) {
            for (auto i = range.first; i < range.second; ++i)
                m_initial[i] = m_linkview->get(i).get_int(0);
        }

        REQUIRE(m_linkview->is_attached());

        // and make sure we end up with the same end result
        REQUIRE(m_initial.size() == m_linkview->size());
        for (size_t i = 0; i < m_initial.size(); ++i)
            CHECK(m_initial[i] == m_linkview->get(i).get_int(0));

        // Verify that everything marked as a move actually is one
        for (size_t i = 0; i < move_sources.size(); ++i) {
            if (!info.modifications.contains(info.moves[i].to)) {
                CHECK(m_linkview->get(info.moves[i].to).get_int(0) == move_sources[i]);
            }
        }
    }
    CaptureHelper(std::string const& path, SharedRealm const& r, LinkViewRef lv)
    : m_history(make_client_history(path))
    , m_sg(*m_history, SharedGroup::durability_MemOnly)
    , m_realm(r)
    , m_group(m_sg.begin_read())
    , m_linkview(lv)
    {
        m_realm->begin_transaction();

        m_initial.reserve(lv->size());
        for (size_t i = 0; i < lv->size(); ++i)
            m_initial.push_back(lv->get(i).get_int(0));
    }
JNIEXPORT jlong JNICALL Java_io_realm_internal_LinkView_nativeGetTargetRowIndex
  (JNIEnv* env, jobject, jlong nativeLinkViewPtr, jlong pos)
{
    TR_ENTER_PTR(nativeLinkViewPtr)
    LinkViewRef *lv = LV(nativeLinkViewPtr);
    if (!ROW_INDEX_VALID(env, *lv, pos)) {
        return -1;
    }
    try {
        LinkViewRef lvr = *lv;
        return lvr->get( S(pos) ).get_index();
    } CATCH_STD()
    return 0;
}