LCOV - code coverage report
Current view: top level - backends/inmemory - inmemory_database.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 7028d852e609 Lines: 423 434 97.5 %
Date: 2019-02-17 14:59:59 Functions: 71 75 94.7 %
Branches: 424 656 64.6 %

           Branch data     Line data    Source code
       1                 :            : /** @file inmemory_database.cc
       2                 :            :  * @brief C++ class definition for inmemory database access
       3                 :            :  */
       4                 :            : /* Copyright 1999,2000,2001 BrightStation PLC
       5                 :            :  * Copyright 2002 Ananova Ltd
       6                 :            :  * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2014,2017 Olly Betts
       7                 :            :  * Copyright 2006,2009 Lemur Consulting Ltd
       8                 :            :  *
       9                 :            :  * This program is free software; you can redistribute it and/or
      10                 :            :  * modify it under the terms of the GNU General Public License as
      11                 :            :  * published by the Free Software Foundation; either version 2 of the
      12                 :            :  * License, or (at your option) any later version.
      13                 :            :  *
      14                 :            :  * This program is distributed in the hope that it will be useful,
      15                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17                 :            :  * GNU General Public License for more details.
      18                 :            :  *
      19                 :            :  * You should have received a copy of the GNU General Public License
      20                 :            :  * along with this program; if not, write to the Free Software
      21                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      22                 :            :  * USA
      23                 :            :  */
      24                 :            : 
      25                 :            : #include <config.h>
      26                 :            : 
      27                 :            : #include "inmemory_database.h"
      28                 :            : 
      29                 :            : #include "debuglog.h"
      30                 :            : 
      31                 :            : #include "expand/expandweight.h"
      32                 :            : #include "inmemory_document.h"
      33                 :            : #include "inmemory_alltermslist.h"
      34                 :            : #include "str.h"
      35                 :            : #include "backends/valuestats.h"
      36                 :            : 
      37                 :            : #include <algorithm>
      38                 :            : #include <string>
      39                 :            : #include <vector>
      40                 :            : #include <map>
      41                 :            : 
      42                 :            : #include <xapian/error.h>
      43                 :            : #include <xapian/valueiterator.h>
      44                 :            : 
      45                 :            : using std::make_pair;
      46                 :            : using Xapian::Internal::intrusive_ptr;
      47                 :            : 
      48                 :            : inline void
      49                 :    1413489 : InMemoryTerm::add_posting(InMemoryPosting&& post)
      50                 :            : {
      51                 :            :     // Add document to right place in list
      52                 :    1413489 :     vector<InMemoryPosting>::iterator p;
      53                 :            :     p = lower_bound(docs.begin(), docs.end(),
      54         [ +  - ]:    1413489 :                     post, InMemoryPostingLessThan());
      55 [ +  + ][ +  + ]:    1413489 :     if (p == docs.end() || InMemoryPostingLessThan()(post, *p)) {
         [ +  + ][ +  - ]
                 [ +  + ]
      56         [ +  - ]:    1041758 :         docs.insert(p, std::move(post));
      57         [ +  + ]:     371731 :     } else if (!p->valid) {
      58         [ +  - ]:        168 :         *p = std::move(post);
      59                 :            :     } else {
      60         [ +  - ]:     371563 :         (*p).merge(post);
      61                 :            :     }
      62                 :    1413489 : }
      63                 :            : 
      64                 :            : inline void
      65                 :    1413489 : InMemoryDoc::add_posting(InMemoryTermEntry&& post)
      66                 :            : {
      67                 :            :     // Add document to right place in list
      68                 :    1413489 :     vector<InMemoryTermEntry>::iterator p;
      69                 :            :     p = lower_bound(terms.begin(), terms.end(),
      70         [ +  - ]:    1413489 :                     post, InMemoryTermEntryLessThan());
      71 [ +  + ][ +  - ]:    1413489 :     if (p == terms.end() || InMemoryTermEntryLessThan()(post, *p)) {
         [ -  + ][ +  + ]
         [ +  - ][ +  +  
             #  #  #  # ]
      72         [ +  - ]:    1041926 :         terms.insert(p, std::move(post));
      73                 :            :     } else {
      74         [ +  - ]:     371563 :         (*p).merge(post);
      75                 :            :     }
      76                 :    1413489 : }
      77                 :            : 
      78                 :            : //////////////
      79                 :            : // Postlist //
      80                 :            : //////////////
      81                 :            : 
      82                 :      51413 : InMemoryPostList::InMemoryPostList(intrusive_ptr<const InMemoryDatabase> db_,
      83                 :            :                                    const InMemoryTerm & imterm,
      84                 :            :                                    const std::string & term_)
      85                 :            :         : LeafPostList(term_),
      86                 :      51413 :           pos(imterm.docs.begin()),
      87                 :      51413 :           end(imterm.docs.end()),
      88                 :            :           termfreq(imterm.term_freq),
      89                 :            :           started(false),
      90         [ +  - ]:      51413 :           db(db_)
      91                 :            : {
      92 [ +  + ][ +  + ]:      51414 :     while (pos != end && !pos->valid) ++pos;
                 [ +  + ]
      93                 :      51413 : }
      94                 :            : 
      95                 :            : Xapian::doccount
      96                 :     200017 : InMemoryPostList::get_termfreq() const
      97                 :            : {
      98                 :     200017 :     return termfreq;
      99                 :            : }
     100                 :            : 
     101                 :            : Xapian::docid
     102                 :   10319807 : InMemoryPostList::get_docid() const
     103                 :            : {
     104         [ +  + ]:   10319807 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     105                 :            :     Assert(started);
     106                 :            :     Assert(!at_end());
     107                 :   10319801 :     return (*pos).did;
     108                 :            : }
     109                 :            : 
     110                 :            : PostList *
     111                 :    9585191 : InMemoryPostList::next(double /*w_min*/)
     112                 :            : {
     113         [ +  + ]:    9585191 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     114         [ +  + ]:    9585189 :     if (started) {
     115                 :            :         Assert(!at_end());
     116                 :    9534469 :         ++pos;
     117 [ +  + ][ +  + ]:    9534475 :         while (pos != end && !pos->valid) ++pos;
                 [ +  + ]
     118                 :            :     } else {
     119                 :      50720 :         started = true;
     120                 :            :     }
     121                 :    9585189 :     return NULL;
     122                 :            : }
     123                 :            : 
     124                 :            : PostList *
     125                 :       1617 : InMemoryPostList::skip_to(Xapian::docid did, double w_min)
     126                 :            : {
     127         [ -  + ]:       1617 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     128                 :            :     // FIXME - see if we can make more efficient, perhaps using better
     129                 :            :     // data structure.  Note, though, that a binary search of
     130                 :            :     // the remaining list may NOT be a good idea (search time is then
     131                 :            :     // O(log {length of list}), as opposed to O(distance we want to skip)
     132                 :            :     // Since we will frequently only be skipping a short distance, this
     133                 :            :     // could well be worse.
     134                 :            : 
     135                 :            :     // If we've not started, it's OK to call skip_to().
     136                 :            :     Assert(!at_end() || !started);
     137                 :       1617 :     started = true;
     138 [ +  + ][ +  + ]:       4870 :     while (!at_end() && (*pos).did < did) {
                 [ +  + ]
     139                 :       3253 :         (void) next(w_min);
     140                 :            :     }
     141                 :       1617 :     return NULL;
     142                 :            : }
     143                 :            : 
     144                 :            : bool
     145                 :    9612448 : InMemoryPostList::at_end() const
     146                 :            : {
     147         [ -  + ]:    9612448 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     148                 :    9612448 :     return (pos == end);
     149                 :            : }
     150                 :            : 
     151                 :            : string
     152                 :          3 : InMemoryPostList::get_description() const
     153                 :            : {
     154 [ +  - ][ +  - ]:          3 :     return term + ":" + str(termfreq);
     155                 :            : }
     156                 :            : 
     157                 :            : PositionList *
     158                 :        669 : InMemoryPostList::read_position_list()
     159                 :            : {
     160         [ -  + ]:        669 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     161 [ +  - ][ +  - ]:        669 :     mypositions.assign(pos->positions.copy());
     162                 :        669 :     return &mypositions;
     163                 :            : }
     164                 :            : 
     165                 :            : PositionList *
     166                 :         55 : InMemoryPostList::open_position_list() const
     167                 :            : {
     168         [ -  + ]:         55 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     169 [ +  - ][ +  - ]:         55 :     return new InMemoryPositionList(pos->positions.copy());
     170                 :            : }
     171                 :            : 
     172                 :            : Xapian::termcount
     173                 :    9532160 : InMemoryPostList::get_wdf() const
     174                 :            : {
     175         [ -  + ]:    9532160 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     176                 :    9532160 :     return (*pos).wdf;
     177                 :            : }
     178                 :            : 
     179                 :            : //////////////
     180                 :            : // Termlist //
     181                 :            : //////////////
     182                 :            : 
     183                 :        519 : InMemoryTermList::InMemoryTermList(intrusive_ptr<const InMemoryDatabase> db_,
     184                 :            :                                    Xapian::docid did_,
     185                 :            :                                    const InMemoryDoc & doc,
     186                 :            :                                    Xapian::termcount len)
     187                 :        519 :         : pos(doc.terms.begin()), end(doc.terms.end()), terms(doc.terms.size()),
     188                 :       1038 :           started(false), db(db_), did(did_), document_length(len)
     189                 :            : {
     190                 :            :     LOGLINE(DB, "InMemoryTermList::InMemoryTermList(): " <<
     191                 :            :                 terms << " terms starting from " << pos->tname);
     192                 :        519 : }
     193                 :            : 
     194                 :            : Xapian::termcount
     195                 :       2162 : InMemoryTermList::get_wdf() const
     196                 :            : {
     197         [ +  + ]:       2162 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     198                 :            :     Assert(started);
     199                 :            :     Assert(!at_end());
     200                 :       2161 :     return (*pos).wdf;
     201                 :            : }
     202                 :            : 
     203                 :            : Xapian::doccount
     204                 :       1511 : InMemoryTermList::get_termfreq() const
     205                 :            : {
     206         [ +  + ]:       1511 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     207                 :            :     Assert(started);
     208                 :            :     Assert(!at_end());
     209                 :            : 
     210                 :            :     Xapian::doccount tf;
     211         [ +  - ]:       1510 :     db->get_freqs((*pos).tname, &tf, NULL);
     212                 :       1510 :     return tf;
     213                 :            : }
     214                 :            : 
     215                 :            : Xapian::termcount
     216                 :         62 : InMemoryTermList::get_approx_size() const
     217                 :            : {
     218         [ -  + ]:         62 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     219                 :         62 :     return terms;
     220                 :            : }
     221                 :            : 
     222                 :            : void
     223                 :       1387 : InMemoryTermList::accumulate_stats(Xapian::Internal::ExpandStats & stats) const
     224                 :            : {
     225         [ -  + ]:       1387 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     226                 :            :     Assert(started);
     227                 :            :     Assert(!at_end());
     228                 :            :     stats.accumulate(InMemoryTermList::get_wdf(), document_length,
     229                 :            :                      InMemoryTermList::get_termfreq(),
     230                 :       1387 :                      db->get_doccount());
     231                 :       1387 : }
     232                 :            : 
     233                 :            : string
     234                 :       3282 : InMemoryTermList::get_termname() const
     235                 :            : {
     236         [ +  + ]:       3282 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     237                 :            :     Assert(started);
     238                 :            :     Assert(!at_end());
     239                 :       3281 :     return (*pos).tname;
     240                 :            : }
     241                 :            : 
     242                 :            : TermList *
     243                 :       3409 : InMemoryTermList::next()
     244                 :            : {
     245         [ +  + ]:       3409 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     246         [ +  + ]:       3408 :     if (started) {
     247                 :            :         Assert(!at_end());
     248                 :       2920 :         ++pos;
     249                 :            :     } else {
     250                 :        488 :         started = true;
     251                 :            :     }
     252                 :       3408 :     return NULL;
     253                 :            : }
     254                 :            : 
     255                 :            : TermList *
     256                 :         74 : InMemoryTermList::skip_to(const string & term)
     257                 :            : {
     258         [ -  + ]:         74 :     if (rare(db->is_closed()))
     259                 :          0 :         InMemoryDatabase::throw_database_closed();
     260                 :            : 
     261 [ +  + ][ +  + ]:        561 :     while (pos != end && pos->tname < term) {
                 [ +  + ]
     262                 :        487 :         ++pos;
     263                 :            :     }
     264                 :            : 
     265                 :         74 :     started = true;
     266                 :         74 :     return NULL;
     267                 :            : }
     268                 :            : 
     269                 :            : bool
     270                 :       3501 : InMemoryTermList::at_end() const
     271                 :            : {
     272         [ -  + ]:       3501 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     273                 :            :     Assert(started);
     274                 :       3501 :     return (pos == end);
     275                 :            : }
     276                 :            : 
     277                 :            : Xapian::termcount
     278                 :         59 : InMemoryTermList::positionlist_count() const
     279                 :            : {
     280         [ -  + ]:         59 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     281                 :         59 :     return db->positionlist_count(did, (*pos).tname);
     282                 :            : }
     283                 :            : 
     284                 :            : PositionList*
     285                 :        246 : InMemoryTermList::positionlist_begin() const
     286                 :            : {
     287         [ -  + ]:        246 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     288                 :        246 :     return db->open_position_list(did, (*pos).tname);
     289                 :            : }
     290                 :            : 
     291                 :            : /////////////////////////////
     292                 :            : // InMemoryAllDocsPostList //
     293                 :            : /////////////////////////////
     294                 :            : 
     295                 :         66 : InMemoryAllDocsPostList::InMemoryAllDocsPostList(intrusive_ptr<const InMemoryDatabase> db_)
     296         [ +  - ]:         66 :         : LeafPostList(std::string()), did(0), db(db_)
     297                 :            : {
     298                 :         66 : }
     299                 :            : 
     300                 :            : Xapian::doccount
     301                 :         95 : InMemoryAllDocsPostList::get_termfreq() const
     302                 :            : {
     303         [ -  + ]:         95 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     304                 :         95 :     return db->totdocs;
     305                 :            : }
     306                 :            : 
     307                 :            : Xapian::docid
     308                 :       6510 : InMemoryAllDocsPostList::get_docid() const
     309                 :            : {
     310         [ -  + ]:       6510 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     311                 :            :     Assert(did > 0);
     312                 :            :     Assert(did <= db->termlists.size());
     313                 :            :     Assert(db->termlists[did - 1].is_valid);
     314                 :       6510 :     return did;
     315                 :            : }
     316                 :            : 
     317                 :            : Xapian::termcount
     318                 :         55 : InMemoryAllDocsPostList::get_wdf() const
     319                 :            : {
     320                 :         55 :     return 1;
     321                 :            : }
     322                 :            : 
     323                 :            : PositionList *
     324                 :          0 : InMemoryAllDocsPostList::read_position_list()
     325                 :            : {
     326 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("Can't open position list for all docs iterator");
                 [ #  # ]
     327                 :            : }
     328                 :            : 
     329                 :            : PositionList *
     330                 :          0 : InMemoryAllDocsPostList::open_position_list() const
     331                 :            : {
     332 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("Can't open position list for all docs iterator");
                 [ #  # ]
     333                 :            : }
     334                 :            : 
     335                 :            : PostList *
     336                 :       3980 : InMemoryAllDocsPostList::next(double /*w_min*/)
     337                 :            : {
     338         [ -  + ]:       3980 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     339                 :            :     Assert(!at_end());
     340         [ +  + ]:      35788 :     do {
     341                 :      35788 :         ++did;
     342 [ +  + ][ +  + ]:      35788 :     } while (did <= db->termlists.size() && !db->termlists[did - 1].is_valid);
     343                 :       3980 :     return NULL;
     344                 :            : }
     345                 :            : 
     346                 :            : PostList *
     347                 :         11 : InMemoryAllDocsPostList::skip_to(Xapian::docid did_, double /*w_min*/)
     348                 :            : {
     349         [ -  + ]:         11 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     350                 :            :     Assert(!at_end());
     351         [ +  - ]:         11 :     if (did <= did_) {
     352                 :         11 :         did = did_;
     353 [ +  - ][ +  + ]:         12 :         while (did <= db->termlists.size() && !db->termlists[did - 1].is_valid) {
                 [ +  + ]
     354                 :          1 :             ++did;
     355                 :            :         }
     356                 :            :     }
     357                 :         11 :     return NULL;
     358                 :            : }
     359                 :            : 
     360                 :            : bool
     361                 :       3995 : InMemoryAllDocsPostList::at_end() const
     362                 :            : {
     363         [ -  + ]:       3995 :     if (db->is_closed()) InMemoryDatabase::throw_database_closed();
     364                 :       3995 :     return (did > db->termlists.size());
     365                 :            : }
     366                 :            : 
     367                 :            : string
     368                 :          0 : InMemoryAllDocsPostList::get_description() const
     369                 :            : {
     370         [ #  # ]:          0 :     return "InMemoryAllDocsPostList " + str(did);
     371                 :            : }
     372                 :            : 
     373                 :            : ///////////////////////////
     374                 :            : // Actual database class //
     375                 :            : ///////////////////////////
     376                 :            : 
     377                 :            : // Updates are applied immediately so we can't support transactions.
     378                 :        368 : InMemoryDatabase::InMemoryDatabase()
     379                 :            :     : Xapian::Database::Internal(TRANSACTION_UNIMPLEMENTED),
     380 [ +  - ][ +  - ]:        368 :       totdocs(0), totlen(0), positions_present(false), closed(false)
                 [ +  - ]
     381                 :            : {
     382                 :            :     // We keep an empty entry in postlists for convenience of implementing
     383                 :            :     // allterms iteration and returning a PostList for an absent term.
     384 [ +  - ][ +  - ]:        368 :     postlists.insert(make_pair(string(), InMemoryTerm()));
     385                 :        368 : }
     386                 :            : 
     387                 :       1104 : InMemoryDatabase::~InMemoryDatabase()
     388                 :            : {
     389                 :        368 :     dtor_called();
     390         [ -  + ]:        736 : }
     391                 :            : 
     392                 :            : bool
     393                 :         20 : InMemoryDatabase::reopen()
     394                 :            : {
     395         [ +  + ]:         20 :     if (closed) InMemoryDatabase::throw_database_closed();
     396                 :         18 :     return false;
     397                 :            : }
     398                 :            : 
     399                 :            : void
     400                 :          5 : InMemoryDatabase::close()
     401                 :            : {
     402                 :            :     // Free all the resources, and mark the db as closed.
     403                 :          5 :     postlists.clear();
     404                 :          5 :     termlists.clear();
     405                 :          5 :     doclists.clear();
     406                 :          5 :     valuelists.clear();
     407                 :          5 :     valuestats.clear();
     408                 :          5 :     doclengths.clear();
     409                 :          5 :     metadata.clear();
     410                 :          5 :     closed = true;
     411                 :          5 : }
     412                 :            : 
     413                 :            : PostList*
     414                 :        477 : InMemoryDatabase::open_post_list(const string& term) const
     415                 :            : {
     416                 :        477 :     return InMemoryDatabase::open_leaf_post_list(term, false);
     417                 :            : }
     418                 :            : 
     419                 :            : LeafPostList*
     420                 :      51482 : InMemoryDatabase::open_leaf_post_list(const string& term, bool need_read_pos) const
     421                 :            : {
     422                 :            :     (void)need_read_pos;
     423         [ +  + ]:      51482 :     if (closed) InMemoryDatabase::throw_database_closed();
     424         [ +  + ]:      51479 :     if (term.empty()) {
     425                 :            :         Assert(!need_read_pos);
     426                 :         66 :         intrusive_ptr<const InMemoryDatabase> ptrtothis(this);
     427 [ +  - ][ +  - ]:         66 :         return new InMemoryAllDocsPostList(ptrtothis);
     428                 :            :     }
     429         [ +  - ]:      51413 :     map<string, InMemoryTerm>::const_iterator i = postlists.find(term);
     430 [ +  + ][ +  + ]:      51413 :     if (i == postlists.end() || i->second.term_freq == 0) {
         [ +  - ][ +  + ]
     431                 :        209 :         i = postlists.begin();
     432                 :            :         // Check that our dummy entry for string() is present.
     433                 :            :         Assert(i->first.empty());
     434                 :            :     }
     435                 :      51413 :     intrusive_ptr<const InMemoryDatabase> ptrtothis(this);
     436 [ +  - ][ +  - ]:      51479 :     return new InMemoryPostList(ptrtothis, i->second, term);
     437                 :            : }
     438                 :            : 
     439                 :            : bool
     440                 :    9541720 : InMemoryDatabase::doc_exists(Xapian::docid did) const
     441                 :            : {
     442         [ -  + ]:    9541720 :     if (closed) InMemoryDatabase::throw_database_closed();
     443 [ +  - ][ +  + ]:    9541720 :     return (did > 0 && did <= termlists.size() && termlists[did - 1].is_valid);
                 [ +  + ]
     444                 :            : }
     445                 :            : 
     446                 :            : void
     447                 :     105976 : InMemoryDatabase::get_freqs(const string & term,
     448                 :            :                             Xapian::doccount * termfreq_ptr,
     449                 :            :                             Xapian::termcount * collfreq_ptr) const
     450                 :            : {
     451         [ +  + ]:     105976 :     if (closed) InMemoryDatabase::throw_database_closed();
     452         [ +  - ]:     105973 :     map<string, InMemoryTerm>::const_iterator i = postlists.find(term);
     453         [ +  + ]:     105973 :     if (i != postlists.end()) {
     454         [ +  + ]:     105413 :         if (termfreq_ptr)
     455                 :      52884 :             *termfreq_ptr = i->second.term_freq;
     456         [ +  + ]:     105413 :         if (collfreq_ptr)
     457                 :     102756 :             *collfreq_ptr = i->second.collection_freq;
     458                 :            :     } else {
     459         [ +  + ]:        560 :         if (termfreq_ptr)
     460                 :        336 :             *termfreq_ptr = 0;
     461         [ +  + ]:        560 :         if (collfreq_ptr)
     462                 :        415 :             *collfreq_ptr = 0;
     463                 :            :     }
     464                 :     105973 : }
     465                 :            : 
     466                 :            : Xapian::doccount
     467                 :       4090 : InMemoryDatabase::get_value_freq(Xapian::valueno slot) const
     468                 :            : {
     469         [ +  + ]:       4090 :     if (closed) InMemoryDatabase::throw_database_closed();
     470         [ +  - ]:       4089 :     map<Xapian::valueno, ValueStats>::const_iterator i = valuestats.find(slot);
     471         [ +  + ]:       4089 :     if (i == valuestats.end()) return 0;
     472                 :       4089 :     return i->second.freq;
     473                 :            : }
     474                 :            : 
     475                 :            : std::string
     476                 :       6047 : InMemoryDatabase::get_value_lower_bound(Xapian::valueno slot) const
     477                 :            : {
     478         [ +  + ]:       6047 :     if (closed) InMemoryDatabase::throw_database_closed();
     479         [ +  - ]:       6046 :     map<Xapian::valueno, ValueStats>::const_iterator i = valuestats.find(slot);
     480 [ +  + ][ +  - ]:       6046 :     if (i == valuestats.end()) return string();
     481         [ +  - ]:       6046 :     return i->second.lower_bound;
     482                 :            : }
     483                 :            : 
     484                 :            : std::string
     485                 :       6075 : InMemoryDatabase::get_value_upper_bound(Xapian::valueno slot) const
     486                 :            : {
     487         [ +  + ]:       6075 :     if (closed) InMemoryDatabase::throw_database_closed();
     488         [ +  - ]:       6074 :     map<Xapian::valueno, ValueStats>::const_iterator i = valuestats.find(slot);
     489 [ +  + ][ +  - ]:       6074 :     if (i == valuestats.end()) return string();
     490         [ +  - ]:       6074 :     return i->second.upper_bound;
     491                 :            : }
     492                 :            : 
     493                 :            : Xapian::termcount
     494                 :      79351 : InMemoryDatabase::get_doclength_lower_bound() const
     495                 :            : {
     496                 :            :     // A zero-length document can't contain any terms, so we ignore such
     497                 :            :     // documents for the purposes of this lower bound.
     498                 :      79351 :     return 1;
     499                 :            : }
     500                 :            : 
     501                 :            : Xapian::termcount
     502                 :        733 : InMemoryDatabase::get_doclength_upper_bound() const
     503                 :            : {
     504                 :            :     // Not a very tight bound in general, but InMemory isn't really built for
     505                 :            :     // performance.
     506         [ +  - ]:        733 :     return min(get_total_length(), Xapian::totallength(Xapian::termcount(-1)));
     507                 :            : }
     508                 :            : 
     509                 :            : Xapian::termcount
     510                 :      50549 : InMemoryDatabase::get_wdf_upper_bound(const string & term) const
     511                 :            : {
     512                 :            :     // Not a very tight bound in general, but InMemory isn't really built for
     513                 :            :     // performance.
     514                 :            :     Xapian::termcount cf;
     515         [ +  + ]:      50549 :     get_freqs(term, NULL, &cf);
     516                 :      50548 :     return cf;
     517                 :            : }
     518                 :            : 
     519                 :            : Xapian::doccount
     520                 :     120184 : InMemoryDatabase::get_doccount() const
     521                 :            : {
     522         [ +  + ]:     120184 :     if (closed) InMemoryDatabase::throw_database_closed();
     523                 :     120181 :     return totdocs;
     524                 :            : }
     525                 :            : 
     526                 :            : Xapian::docid
     527                 :       5187 : InMemoryDatabase::get_lastdocid() const
     528                 :            : {
     529         [ +  + ]:       5187 :     if (closed) InMemoryDatabase::throw_database_closed();
     530                 :       5185 :     return termlists.size();
     531                 :            : }
     532                 :            : 
     533                 :            : Xapian::totallength
     534                 :      58810 : InMemoryDatabase::get_total_length() const
     535                 :            : {
     536                 :      58810 :     return totlen;
     537                 :            : }
     538                 :            : 
     539                 :            : Xapian::termcount
     540                 :    9484415 : InMemoryDatabase::get_doclength(Xapian::docid did) const
     541                 :            : {
     542         [ +  + ]:    9484415 :     if (closed) InMemoryDatabase::throw_database_closed();
     543         [ +  + ]:    9484414 :     if (!doc_exists(did)) {
     544 [ +  - ][ +  - ]:       6014 :         throw Xapian::DocNotFoundError(string("Docid ") + str(did) +
         [ +  - ][ +  - ]
                 [ +  - ]
     545 [ +  - ][ +  - ]:       9021 :                                  string(" not found"));
     546                 :            :     }
     547                 :    9481407 :     return doclengths[did - 1];
     548                 :            : }
     549                 :            : 
     550                 :            : Xapian::termcount
     551                 :       3527 : InMemoryDatabase::get_unique_terms(Xapian::docid did) const
     552                 :            : {
     553         [ +  + ]:       3527 :     if (closed) InMemoryDatabase::throw_database_closed();
     554 [ +  - ][ +  + ]:       3526 :     if (did == 0 || did > termlists.size() || !termlists[did - 1].is_valid)
         [ +  + ][ +  + ]
     555 [ +  - ][ +  - ]:       6012 :         throw Xapian::DocNotFoundError(string("Docid ") + str(did) +
         [ +  - ][ +  - ]
                 [ +  - ]
     556 [ +  - ][ +  - ]:       9018 :                                  string(" not found"));
     557                 :            :     // get_unique_terms() really ought to only count terms with wdf > 0, but
     558                 :            :     // that's expensive to calculate on demand, so for now let's just ensure
     559                 :            :     // unique_terms <= doclen.
     560                 :        520 :     Xapian::termcount terms = termlists[did - 1].terms.size();
     561                 :        520 :     return std::min(terms, Xapian::termcount(doclengths[did - 1]));
     562                 :            : }
     563                 :            : 
     564                 :            : TermList *
     565                 :       3530 : InMemoryDatabase::open_term_list(Xapian::docid did) const
     566                 :            : {
     567         [ +  + ]:       3530 :     if (closed) InMemoryDatabase::throw_database_closed();
     568                 :            :     Assert(did != 0);
     569         [ +  + ]:       3528 :     if (!doc_exists(did)) {
     570                 :            :         // FIXME: the docid in this message will be local, not global
     571 [ +  - ][ +  - ]:       6018 :         throw Xapian::DocNotFoundError(string("Docid ") + str(did) +
         [ +  - ][ +  - ]
                 [ +  - ]
     572 [ +  - ][ +  - ]:       9027 :                                  string(" not found"));
     573                 :            :     }
     574                 :            :     return new InMemoryTermList(intrusive_ptr<const InMemoryDatabase>(this), did,
     575 [ +  - ][ +  - ]:        519 :                                 termlists[did - 1], doclengths[did - 1]);
     576                 :            : }
     577                 :            : 
     578                 :            : TermList *
     579                 :         46 : InMemoryDatabase::open_term_list_direct(Xapian::docid did) const
     580                 :            : {
     581                 :         46 :     return InMemoryDatabase::open_term_list(did);
     582                 :            : }
     583                 :            : 
     584                 :            : Xapian::Document::Internal *
     585                 :     249327 : InMemoryDatabase::open_document(Xapian::docid did, bool lazy) const
     586                 :            : {
     587         [ +  + ]:     249327 :     if (closed) InMemoryDatabase::throw_database_closed();
     588                 :            :     Assert(did != 0);
     589 [ +  + ][ +  + ]:     249325 :     if (!lazy && !doc_exists(did)) {
                 [ +  + ]
     590                 :            :         // FIXME: the docid in this message will be local, not global
     591 [ +  - ][ +  - ]:       6030 :         throw Xapian::DocNotFoundError(string("Docid ") + str(did) +
         [ +  - ][ +  - ]
                 [ +  - ]
     592 [ +  - ][ +  - ]:       9045 :                                  string(" not found"));
     593                 :            :     }
     594         [ +  - ]:     246310 :     return new InMemoryDocument(this, did);
     595                 :            : }
     596                 :            : 
     597                 :            : std::string
     598                 :         13 : InMemoryDatabase::get_metadata(const std::string & key) const
     599                 :            : {
     600         [ +  + ]:         13 :     if (closed) InMemoryDatabase::throw_database_closed();
     601         [ +  - ]:         11 :     map<string, string>::const_iterator i = metadata.find(key);
     602         [ +  + ]:         11 :     if (i == metadata.end())
     603         [ +  - ]:          2 :         return string();
     604         [ +  - ]:         11 :     return i->second;
     605                 :            : }
     606                 :            : 
     607                 :            : TermList *
     608                 :          2 : InMemoryDatabase::open_metadata_keylist(const string &) const
     609                 :            : {
     610         [ +  + ]:          2 :     if (closed) InMemoryDatabase::throw_database_closed();
     611         [ +  - ]:          1 :     if (metadata.empty()) return NULL;
     612                 :            :     // FIXME: nobody implemented this yet...
     613 [ #  # ][ #  # ]:          0 :     throw Xapian::UnimplementedError("InMemory backend doesn't currently implement Database::metadata_keys_begin()");
                 [ #  # ]
     614                 :            : }
     615                 :            : 
     616                 :            : void
     617                 :         11 : InMemoryDatabase::set_metadata(const std::string & key,
     618                 :            :                                const std::string & value)
     619                 :            : {
     620         [ +  + ]:         11 :     if (closed) InMemoryDatabase::throw_database_closed();
     621         [ +  + ]:         10 :     if (!value.empty()) {
     622                 :          9 :         metadata[key] = value;
     623                 :            :     } else {
     624                 :          1 :         metadata.erase(key);
     625                 :            :     }
     626                 :         10 : }
     627                 :            : 
     628                 :            : Xapian::termcount
     629                 :         59 : InMemoryDatabase::positionlist_count(Xapian::docid did,
     630                 :            :                                      const string & tname) const
     631                 :            : {
     632         [ -  + ]:         59 :     if (closed) InMemoryDatabase::throw_database_closed();
     633 [ +  - ][ -  + ]:         59 :     if (!doc_exists(did)) {
     634                 :          0 :         return 0;
     635                 :            :     }
     636                 :         59 :     const InMemoryDoc &doc = termlists[did - 1];
     637                 :            : 
     638         [ +  - ]:         59 :     InMemoryTermEntry temp;
     639         [ +  - ]:         59 :     temp.tname = tname;
     640                 :            :     auto t = lower_bound(doc.terms.begin(), doc.terms.end(),
     641         [ +  - ]:         59 :                          temp, InMemoryTermEntryLessThan());
     642 [ +  - ][ +  - ]:         59 :     if (t != doc.terms.end() && t->tname == tname) {
         [ +  - ][ +  - ]
     643                 :         59 :         return t->positions.size();
     644                 :            :     }
     645                 :         59 :     return 0;
     646                 :            : }
     647                 :            : 
     648                 :            : PositionList *
     649                 :        270 : InMemoryDatabase::open_position_list(Xapian::docid did,
     650                 :            :                                      const string & tname) const
     651                 :            : {
     652         [ +  + ]:        270 :     if (closed) InMemoryDatabase::throw_database_closed();
     653         [ +  + ]:        269 :     if (usual(doc_exists(did))) {
     654                 :        267 :         const InMemoryDoc &doc = termlists[did - 1];
     655                 :            : 
     656         [ +  - ]:        267 :         InMemoryTermEntry temp;
     657         [ +  - ]:        267 :         temp.tname = tname;
     658                 :            :         auto t = lower_bound(doc.terms.begin(), doc.terms.end(),
     659         [ +  - ]:        267 :                              temp, InMemoryTermEntryLessThan());
     660 [ +  + ][ +  + ]:        267 :         if (t != doc.terms.end() && t->tname == tname) {
         [ +  - ][ +  + ]
     661 [ +  - ][ +  - ]:        267 :             return new InMemoryPositionList(t->positions);
                 [ +  + ]
     662                 :        267 :         }
     663                 :            :     }
     664         [ +  - ]:        269 :     return new InMemoryPositionList();
     665                 :            : }
     666                 :            : 
     667                 :            : void
     668                 :      26136 : InMemoryDatabase::add_values(Xapian::docid did,
     669                 :            :                              const map<Xapian::valueno, string> &values_)
     670                 :            : {
     671         [ -  + ]:      26136 :     if (closed) InMemoryDatabase::throw_database_closed();
     672         [ +  + ]:      26136 :     if (did > valuelists.size()) {
     673         [ +  - ]:      23018 :         valuelists.resize(did);
     674                 :            :     }
     675         [ +  - ]:      26136 :     valuelists[did - 1] = values_;
     676                 :            : 
     677                 :            :     // Update the statistics.
     678                 :      26136 :     map<Xapian::valueno, string>::const_iterator j;
     679         [ +  + ]:     275708 :     for (j = values_.begin(); j != values_.end(); ++j) {
     680                 :     249572 :         std::pair<map<Xapian::valueno, ValueStats>::iterator, bool> i;
     681 [ +  - ][ +  - ]:     249572 :         i = valuestats.insert(make_pair(j->first, ValueStats()));
     682                 :            : 
     683                 :            :         // Now, modify the stored statistics.
     684         [ +  + ]:     249572 :         if ((i.first->second.freq)++ == 0) {
     685                 :            :             // If the value count was previously zero, set the upper and lower
     686                 :            :             // bounds to the newly added value.
     687         [ +  - ]:      58759 :             i.first->second.lower_bound = j->second;
     688         [ +  - ]:      58759 :             i.first->second.upper_bound = j->second;
     689                 :            :         } else {
     690                 :            :             // Otherwise, simply make sure they reflect the new value.
     691 [ +  - ][ +  + ]:     190813 :             if (j->second < i.first->second.lower_bound) {
     692         [ +  - ]:       4024 :                 i.first->second.lower_bound = j->second;
     693                 :            :             }
     694 [ +  - ][ +  + ]:     190813 :             if (j->second > i.first->second.upper_bound) {
     695         [ +  - ]:       4310 :                 i.first->second.upper_bound = j->second;
     696                 :            :             }
     697                 :            :         }
     698                 :            :     }
     699                 :      26136 : }
     700                 :            : 
     701                 :            : // We implicitly commit each modification right away, so nothing to do here.
     702                 :            : void
     703                 :       1071 : InMemoryDatabase::commit()
     704                 :            : {
     705                 :       1071 : }
     706                 :            : 
     707                 :            : // We implicitly commit each modification right away, so nothing to do here.
     708                 :            : void
     709                 :          0 : InMemoryDatabase::cancel()
     710                 :            : {
     711                 :          0 : }
     712                 :            : 
     713                 :            : void
     714                 :       3028 : InMemoryDatabase::delete_document(Xapian::docid did)
     715                 :            : {
     716         [ +  + ]:       3028 :     if (closed) InMemoryDatabase::throw_database_closed();
     717 [ +  - ][ +  + ]:       3027 :     if (!doc_exists(did)) {
     718 [ +  - ][ +  - ]:          2 :         throw Xapian::DocNotFoundError(string("Docid ") + str(did) +
         [ +  - ][ +  - ]
                 [ +  - ]
     719 [ +  - ][ +  - ]:          3 :                                  string(" not found"));
     720                 :            :     }
     721                 :       3026 :     termlists[did - 1].is_valid = false;
     722 [ +  - ][ +  - ]:       3026 :     doclists[did - 1] = string();
     723                 :       3026 :     map<Xapian::valueno, string>::const_iterator j;
     724         [ +  + ]:       3128 :     for (j = valuelists[did - 1].begin(); j != valuelists[did - 1].end(); ++j) {
     725                 :        102 :         map<Xapian::valueno, ValueStats>::iterator i;
     726         [ +  - ]:        102 :         i = valuestats.find(j->first);
     727         [ +  + ]:        102 :         if (--(i->second.freq) == 0) {
     728         [ +  - ]:         16 :             i->second.lower_bound.resize(0);
     729         [ +  - ]:         16 :             i->second.upper_bound.resize(0);
     730                 :            :         }
     731                 :            :     }
     732                 :       3026 :     valuelists[did - 1].clear();
     733                 :            : 
     734                 :       3026 :     totlen -= doclengths[did - 1];
     735                 :       3026 :     doclengths[did - 1] = 0;
     736                 :       3026 :     totdocs--;
     737                 :            :     // A crude check, but it's hard to be more precise with the current
     738                 :            :     // InMemory structure without being very inefficient.
     739         [ +  + ]:       3026 :     if (totdocs == 0) positions_present = false;
     740                 :            : 
     741                 :       3026 :     vector<InMemoryTermEntry>::const_iterator i;
     742         [ +  + ]:      18204 :     for (i = termlists[did - 1].terms.begin();
     743                 :       9102 :          i != termlists[did - 1].terms.end();
     744                 :            :          ++i) {
     745         [ +  - ]:       6076 :         map<string, InMemoryTerm>::iterator t = postlists.find(i->tname);
     746                 :            :         Assert(t != postlists.end());
     747                 :       6076 :         t->second.collection_freq -= i->wdf;
     748                 :       6076 :         --t->second.term_freq;
     749                 :            : 
     750                 :            :         // Just invalidate erased doc ids - otherwise we need to erase
     751                 :            :         // in a vector (inefficient) and we break any posting lists
     752                 :            :         // iterating over this posting list.
     753         [ +  - ]:       6076 :         InMemoryPosting temp;
     754                 :       6076 :         temp.did = did;
     755                 :      12152 :         auto p = lower_bound(t->second.docs.begin(), t->second.docs.end(),
     756         [ +  - ]:      12152 :                              temp, InMemoryPostingLessThan());
     757 [ +  - ][ +  - ]:       6076 :         if (p != t->second.docs.end() && p->did == did) {
         [ +  - ][ +  - ]
     758                 :       6076 :             p->valid = false;
     759                 :            :         }
     760                 :       6076 :     }
     761                 :       3026 :     termlists[did - 1].terms.clear();
     762                 :       3026 : }
     763                 :            : 
     764                 :            : void
     765                 :       3120 : InMemoryDatabase::replace_document(Xapian::docid did,
     766                 :            :                                    const Xapian::Document & document)
     767                 :            : {
     768                 :            :     LOGCALL_VOID(DB, "InMemoryDatabase::replace_document", did | document);
     769                 :            : 
     770         [ +  + ]:       3120 :     if (closed) InMemoryDatabase::throw_database_closed();
     771                 :            : 
     772 [ +  - ][ +  + ]:       3118 :     if (doc_exists(did)) {
     773                 :       3084 :         map<Xapian::valueno, string>::const_iterator j;
     774         [ +  + ]:       5697 :         for (j = valuelists[did - 1].begin(); j != valuelists[did - 1].end(); ++j) {
     775                 :       2613 :             map<Xapian::valueno, ValueStats>::iterator i;
     776         [ +  - ]:       2613 :             i = valuestats.find(j->first);
     777         [ +  + ]:       2613 :             if (--(i->second.freq) == 0) {
     778         [ +  - ]:          2 :                 i->second.lower_bound.resize(0);
     779         [ +  - ]:          2 :                 i->second.upper_bound.resize(0);
     780                 :            :             }
     781                 :            :         }
     782                 :            : 
     783                 :       3084 :         totlen -= doclengths[did - 1];
     784                 :       3084 :         totdocs--;
     785         [ +  + ]:         34 :     } else if (did > termlists.size()) {
     786         [ +  - ]:         29 :         termlists.resize(did);
     787                 :         29 :         termlists[did - 1].is_valid = true;
     788         [ +  - ]:         29 :         doclengths.resize(did);
     789         [ +  - ]:         29 :         doclists.resize(did);
     790         [ +  - ]:         29 :         valuelists.resize(did);
     791                 :            :     } else {
     792                 :          5 :         termlists[did - 1].is_valid = true;
     793                 :            :     }
     794                 :            : 
     795                 :       3118 :     vector<InMemoryTermEntry>::const_iterator i;
     796         [ +  + ]:       6602 :     for (i = termlists[did - 1].terms.begin();
     797                 :       3301 :          i != termlists[did - 1].terms.end();
     798                 :            :          ++i) {
     799         [ +  - ]:        183 :         map<string, InMemoryTerm>::iterator t = postlists.find(i->tname);
     800                 :            :         Assert(t != postlists.end());
     801                 :        183 :         t->second.collection_freq -= i->wdf;
     802                 :        183 :         --t->second.term_freq;
     803                 :            : 
     804                 :            :         // Just invalidate erased doc ids - otherwise we need to erase
     805                 :            :         // in a vector (inefficient) and we break any posting lists
     806                 :            :         // iterating over this posting list.
     807         [ +  - ]:        183 :         InMemoryPosting temp;
     808                 :        183 :         temp.did = did;
     809                 :        366 :         auto p = lower_bound(t->second.docs.begin(), t->second.docs.end(),
     810         [ +  - ]:        366 :                              temp, InMemoryPostingLessThan());
     811 [ +  - ][ +  - ]:        183 :         if (p != t->second.docs.end() && p->did == did) {
         [ +  - ][ +  - ]
     812                 :        183 :             p->valid = false;
     813                 :            :         }
     814                 :        183 :     }
     815                 :            : 
     816                 :       3118 :     doclengths[did - 1] = 0;
     817 [ +  - ][ +  - ]:       3118 :     doclists[did - 1] = document.get_data();
     818                 :            : 
     819         [ +  - ]:       3118 :     finish_add_doc(did, document);
     820                 :       3118 : }
     821                 :            : 
     822                 :            : Xapian::docid
     823                 :      23019 : InMemoryDatabase::add_document(const Xapian::Document & document)
     824                 :            : {
     825                 :            :     LOGCALL(DB, Xapian::docid, "InMemoryDatabase::add_document", document);
     826         [ +  + ]:      23019 :     if (closed) InMemoryDatabase::throw_database_closed();
     827                 :            : 
     828         [ +  - ]:      23018 :     Xapian::docid did = make_doc(document.get_data());
     829                 :            : 
     830                 :      23018 :     finish_add_doc(did, document);
     831                 :            : 
     832                 :      23018 :     RETURN(did);
     833                 :            : }
     834                 :            : 
     835                 :            : void
     836                 :      26136 : InMemoryDatabase::finish_add_doc(Xapian::docid did, const Xapian::Document &document)
     837                 :            : {
     838                 :            :     {
     839         [ +  - ]:      26136 :         map<Xapian::valueno, string> values;
     840         [ +  - ]:      52272 :         Xapian::ValueIterator k = document.values_begin();
     841 [ +  - ][ +  + ]:     275708 :         for ( ; k != document.values_end(); ++k) {
     842 [ +  - ][ +  - ]:     249572 :             values.insert(make_pair(k.get_valueno(), *k));
                 [ +  - ]
     843                 :            :             LOGLINE(DB, "InMemoryDatabase::finish_add_doc(): adding value " <<
     844                 :            :                         k.get_valueno() << " -> " << *k);
     845                 :            :         }
     846         [ +  - ]:      52272 :         add_values(did, values);
     847                 :            :     }
     848                 :            : 
     849                 :      26136 :     InMemoryDoc doc(true);
     850         [ +  - ]:      52272 :     Xapian::TermIterator i = document.termlist_begin();
     851 [ +  - ][ +  + ]:    1068062 :     for ( ; i != document.termlist_end(); ++i) {
     852 [ +  - ][ +  - ]:    1041926 :         make_term(*i);
     853                 :            : 
     854                 :            :         LOGLINE(DB, "InMemoryDatabase::finish_add_doc(): adding term " << *i);
     855         [ +  - ]:    1041926 :         Xapian::PositionIterator j = i.positionlist_begin();
     856         [ +  + ]:    1041926 :         if (j == i.positionlist_end()) {
     857                 :            :             /* Make sure the posting exists, even without a position. */
     858 [ +  - ][ +  - ]:      26108 :             make_posting(&doc, *i, did, 0, i.get_wdf(), false);
                 [ +  - ]
     859                 :            :         } else {
     860                 :    1015818 :             positions_present = true;
     861 [ +  - ][ +  + ]:    2403199 :             for ( ; j != i.positionlist_end(); ++j) {
     862 [ +  - ][ +  - ]:    1387381 :                 make_posting(&doc, *i, did, *j, i.get_wdf());
         [ +  - ][ +  - ]
     863                 :            :             }
     864                 :            :         }
     865                 :            : 
     866                 :            :         Assert(did > 0 && did <= doclengths.size());
     867         [ +  - ]:    1041926 :         doclengths[did - 1] += i.get_wdf();
     868         [ +  - ]:    1041926 :         totlen += i.get_wdf();
     869 [ +  - ][ +  - ]:    1041926 :         postlists[*i].collection_freq += i.get_wdf();
                 [ +  - ]
     870 [ +  - ][ +  - ]:    1041926 :         ++postlists[*i].term_freq;
     871                 :    1041926 :     }
     872                 :      26136 :     swap(termlists[did - 1], doc);
     873                 :            : 
     874                 :      26136 :     totdocs++;
     875                 :      26136 : }
     876                 :            : 
     877                 :            : void
     878                 :    1041926 : InMemoryDatabase::make_term(const string & tname)
     879                 :            : {
     880                 :    1041926 :     postlists[tname];  // Initialise, if not already there.
     881                 :    1041926 : }
     882                 :            : 
     883                 :            : Xapian::docid
     884                 :      23018 : InMemoryDatabase::make_doc(const string & docdata)
     885                 :            : {
     886         [ +  - ]:      23018 :     termlists.push_back(InMemoryDoc(true));
     887         [ +  - ]:      23018 :     doclengths.push_back(0);
     888                 :      23018 :     doclists.push_back(docdata);
     889                 :            : 
     890                 :            :     AssertEqParanoid(termlists.size(), doclengths.size());
     891                 :            : 
     892                 :      23018 :     return termlists.size();
     893                 :            : }
     894                 :            : 
     895                 :    1413489 : void InMemoryDatabase::make_posting(InMemoryDoc * doc,
     896                 :            :                                     const string & tname,
     897                 :            :                                     Xapian::docid did,
     898                 :            :                                     Xapian::termpos position,
     899                 :            :                                     Xapian::termcount wdf,
     900                 :            :                                     bool use_position)
     901                 :            : {
     902                 :            :     Assert(doc);
     903                 :            :     Assert(postlists.find(tname) != postlists.end());
     904                 :            :     Assert(did > 0 && did <= termlists.size());
     905                 :            :     Assert(did > 0 && did <= doclengths.size());
     906                 :            :     Assert(doc_exists(did));
     907                 :            : 
     908                 :            :     // Make the posting
     909         [ +  - ]:    1413489 :     InMemoryPosting posting;
     910                 :    1413489 :     posting.did = did;
     911         [ +  + ]:    1413489 :     if (use_position) {
     912         [ +  - ]:    1387381 :         posting.positions.push_back(position);
     913                 :            :     }
     914                 :    1413489 :     posting.wdf = wdf;
     915                 :    1413489 :     posting.valid = true;
     916                 :            : 
     917                 :            :     // Now record the posting
     918 [ +  - ][ +  - ]:    1413489 :     postlists[tname].add_posting(std::move(posting));
     919                 :            : 
     920                 :            :     // Make the termentry
     921         [ +  - ]:    2826978 :     InMemoryTermEntry termentry;
     922         [ +  - ]:    1413489 :     termentry.tname = tname;
     923         [ +  + ]:    1413489 :     if (use_position) {
     924         [ +  - ]:    1387381 :         termentry.positions.push_back(position);
     925                 :            :     }
     926                 :    1413489 :     termentry.wdf = wdf;
     927                 :            : 
     928                 :            :     // Now record the termentry
     929         [ +  - ]:    2826978 :     doc->add_posting(std::move(termentry));
     930                 :    1413489 : }
     931                 :            : 
     932                 :            : bool
     933                 :         79 : InMemoryDatabase::term_exists(const string & tname) const
     934                 :            : {
     935         [ +  + ]:         79 :     if (closed) InMemoryDatabase::throw_database_closed();
     936         [ +  + ]:         78 :     if (tname.empty()) {
     937                 :         10 :         return totdocs != 0;
     938                 :            :     }
     939         [ +  - ]:         68 :     map<string, InMemoryTerm>::const_iterator i = postlists.find(tname);
     940         [ +  + ]:         68 :     if (i == postlists.end()) return false;
     941                 :         78 :     return (i->second.term_freq != 0);
     942                 :            : }
     943                 :            : 
     944                 :            : bool
     945                 :      28819 : InMemoryDatabase::has_positions() const
     946                 :            : {
     947         [ +  + ]:      28819 :     if (closed) InMemoryDatabase::throw_database_closed();
     948                 :      28818 :     return positions_present;
     949                 :            : }
     950                 :            : 
     951                 :            : TermList *
     952                 :        109 : InMemoryDatabase::open_allterms(const string & prefix) const
     953                 :            : {
     954         [ +  + ]:        109 :     if (closed) InMemoryDatabase::throw_database_closed();
     955                 :            :     return new InMemoryAllTermsList(&postlists,
     956                 :            :                                     intrusive_ptr<const InMemoryDatabase>(this),
     957 [ +  - ][ +  - ]:        107 :                                     prefix);
     958                 :            : }
     959                 :            : 
     960                 :            : void
     961                 :         51 : InMemoryDatabase::throw_database_closed()
     962                 :            : {
     963 [ +  - ][ +  - ]:         51 :     throw Xapian::DatabaseClosedError("Database has been closed");
                 [ +  - ]
     964                 :            : }
     965                 :            : 
     966                 :            : string
     967                 :          6 : InMemoryDatabase::get_description() const
     968                 :            : {
     969         [ +  - ]:          6 :     return "InMemory";
     970                 :            : }
     971                 :            : 
     972                 :            : #ifdef DISABLE_GPL_LIBXAPIAN
     973                 :            : # error GPL source we cannot relicense included in libxapian
     974                 :            : #endif

Generated by: LCOV version 1.11