/* * Copyright (C) 2016 Charybdis Development Team * Copyright (C) 2016 Jason Volk * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice is present in all copies. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once #define HAVE_IRCD_M_VM_CURSOR_H namespace ircd::m::vm { struct cursor; } struct ircd::m::vm::cursor { template struct const_iterator_base; struct const_reverse_iterator; struct const_iterator; template using query_type = vm::query; using iterator_type = const_iterator; db::index index; const query_type<> *query{nullptr}; const_iterator end(const string_view &key = {}); const_iterator begin(const string_view &key = {}); const_reverse_iterator rend(const string_view &key = {}); const_reverse_iterator rbegin(const string_view &key = {}); cursor(const string_view &index, const query_type<> *const &query = nullptr) :index{*event::events, index} ,query{query} {} }; template struct ircd::m::vm::cursor::const_iterator_base { using value_type = const event; using pointer = value_type *; using reference = value_type &; using difference_type = size_t; using iterator_category = std::bidirectional_iterator_tag; template using query_type = cursor::query_type; const query_type<> *query{nullptr}; index_iterator idx; std::array cell; db::row row; mutable event v; mutable bool stale{true}; bool invalid{true}; operator bool() const; bool operator!() const; bool operator==(const const_iterator_base &o) const; bool operator!=(const const_iterator_base &o) const; value_type &operator*() const { if(!stale) return v; assign(v, row, row_key()); stale = false; return v; } value_type *operator->() const { return &this->operator*(); } string_view row_key() const; bool row_valid() const; protected: bool seek_row(); public: const_iterator_base &operator++(); const_iterator_base &operator--(); const_iterator_base(); const_iterator_base(const cursor &, index_iterator, const db::gopts & = {}); }; struct ircd::m::vm::cursor::const_iterator :const_iterator_base { using const_iterator_base::const_iterator_base; }; struct ircd::m::vm::cursor::const_reverse_iterator :const_iterator_base { using const_iterator_base::const_iterator_base; }; // // cursor // inline ircd::m::vm::cursor::const_reverse_iterator ircd::m::vm::cursor::rbegin(const string_view &key) { return const_reverse_iterator { *this, index.rbegin(key), {} }; } inline ircd::m::vm::cursor::const_reverse_iterator ircd::m::vm::cursor::rend(const string_view &key) { return const_reverse_iterator { *this, index.rend(key), {} }; } inline ircd::m::vm::cursor::const_iterator ircd::m::vm::cursor::begin(const string_view &key) { return const_iterator { *this, index.begin(key), {} }; } inline ircd::m::vm::cursor::const_iterator ircd::m::vm::cursor::end(const string_view &key) { return const_iterator { *this, index.end(key), {} }; } // // const iterator // template ircd::m::vm::cursor::const_iterator_base::const_iterator_base(const cursor &c, index_iterator idx, const db::gopts &opts) :query{c.query} ,idx{std::move(idx)} ,cell{} ,row { *event::events, bool(this->idx) && this->idx->second? this->idx->second: bool(this->idx)? this->idx->first: string_view{}, event{}, cell, opts } ,stale { true } ,invalid { !this->idx || !row_valid() } { if(invalid) return; if(!this->query) return; if(!(*this->query)(this->operator*())) this->operator++(); } template ircd::m::vm::cursor::const_iterator_base & ircd::m::vm::cursor::const_iterator_base::operator++() { while(!(invalid = !bool(++idx))) if(seek_row()) break; return *this; } template ircd::m::vm::cursor::const_iterator_base & ircd::m::vm::cursor::const_iterator_base::operator--() { while(!(invalid = !bool(--idx))) if(seek_row()) break; return *this; } template bool ircd::m::vm::cursor::const_iterator_base::seek_row() { if(!db::seek(row, row_key())) return false; stale = true; if(this->query && !(*this->query)(this->operator*())) return false; return true; } template bool ircd::m::vm::cursor::const_iterator_base::row_valid() const { return row.valid(row_key()); } template ircd::string_view ircd::m::vm::cursor::const_iterator_base::row_key() const { if(!idx) return {}; if(idx->second) return idx->second; assert(bool(idx->first)); return idx->first; } template bool ircd::m::vm::cursor::const_iterator_base::operator!() const { return !static_cast(*this); } template ircd::m::vm::cursor::const_iterator_base::operator bool() const { if(invalid) return false; if(!idx) return false; return row_valid(); } template bool ircd::m::vm::cursor::const_iterator_base::operator!=(const const_iterator_base &o) const { return !(*this == o); } template bool ircd::m::vm::cursor::const_iterator_base::operator==(const const_iterator_base &o) const { if(row_key() != o.row_key()) return false; if(!row_valid() && !o.row_valid()) return true; if(!row_valid() || !o.row_valid()) return false; return true; }