diff --git a/fp-includes/core/core.bplustree.class.php b/fp-includes/core/core.bplustree.class.php index f62421a..1c67643 100755 --- a/fp-includes/core/core.bplustree.class.php +++ b/fp-includes/core/core.bplustree.class.php @@ -978,13 +978,19 @@ class BPlusTree_Node { * @returns int|false corresponding integer or false if key is missing * */ - function getvalue($key) { + function getvalue(&$key, $loose=false) { #d(implode(",",$this->keys)); - $place = array_search($key, $this->keys); - if ($place!==false) { + #$place = array_search($key, $this->keys); + $place = BPT_bisect($this->keys, $key, 0); + if (@$this->keys[$place-1] == $key) { return $this->indices[$place]; } else { + if ($loose) { + if ($place>1) $place--; + $key = $this->keys[$place]; + return $this->indices[$place]; + } trigger_error("key '$key' not found", E_USER_WARNING); return false; } @@ -1522,12 +1528,17 @@ class BPlusTree { /** * returns an iterator for the tree * @param string $keylower key lower limit of the iterator - * @param bool $includelower if true $keylower is included in the iterator + * @param bool|int $includelower if true $keylower is included in the iterator; + * if $includelower > 1 then 'loose' search is assumed: + * the tree will be walked starting from + * the key $k in the tree such as $k <= $keylower + * and such as there are NO other keys $k' + * such as $k < $k' <= $keylower * @param string $keyupper key upper bound of the iterator * @param bool $includeupper if true $keyupper is included in the iterator */ function walker( - $keylower =null, + &$keylower =null, $includelower =null, $keyupper =null, $includeupper =null @@ -1694,14 +1705,16 @@ class BPlusTree { } /** - * @param string $key key to find + * @param string &$key key to find. + * @param bool $loose if true searches the tree for the "nearest" key to $key; + * * @returns int associated value * */ - function getitem($key) { + function getitem(&$key, $loose=false) { if (is_null($this->root)) trigger_error("not open!", E_USER_ERROR); - return $this->find($key, $this->root); + return $this->find($key, $this->root, $loose); } /** @@ -1712,7 +1725,7 @@ class BPlusTree { * @returns int|bool value at the leaf node containing key or false if key is missing * */ - function find($key, &$node) { + function find(&$key, &$node, $loose=false) { while (($node->flag & BPT_FLAG_INTERIOR) == BPT_FLAG_INTERIOR) { @@ -1736,7 +1749,7 @@ class BPlusTree { $node =& $node->getnode($nodekey); } - return $node->getvalue($key); + return $node->getvalue($key, $loose); } /** @@ -1744,7 +1757,7 @@ class BPlusTree { * @returns bool false if key does not exists, true otherwise */ function has_key($key) { - if ($this->getitem($key)!==false) { + if (@$this->getitem($key)!==false) { return true; } else { return false; @@ -2331,7 +2344,7 @@ class BPlusWalker { function BPlusWalker( &$tree, - $keylower=null, + &$keylower=null, $includelower=null, $keyupper=null, $includeupper=null){ @@ -2371,6 +2384,7 @@ class BPlusWalker { $this->node_index = null; $this->valid = 0; $this->first(); + $keylower = $this->keylower; } function first() { @@ -2395,7 +2409,11 @@ class BPlusWalker { if (!$this->valid) { $place = BPT_bisect($keys, $keylower, 0, $validkeys); if ($place < $validkeys) { - $index = $this->node_index = $place; + if ($place > 0) + $index = $place - 1; + else $index = $place; + + $this->node_index = $index; $testk = $keys[$index]; /* if ($testk>$keylower || @@ -2406,7 +2424,11 @@ class BPlusWalker { } */ $this->valid = BPT_keycmp($testk,$keylower)<0||#$testk>$keylower || - ($this->includelower && $testk==$keylower); + ($this->includelower && ($this->includelower>1 || $testk==$keylower) ); + + + $this->keylower = $testk; + } else { $next =& $node->nextneighbour(); if (!is_null($next)) { @@ -2482,10 +2504,10 @@ class caching_BPT extends BPlusTree { var $cache = array(); - function getitem($key) { + function getitem(&$key, $loose=false) { if (isset($cache[$key])) return $cache[$key]; - else return ($cache[$key] = parent::getitem($key)); + else return ($cache[$key] = parent::getitem($key, $loose)); } function resetcache() { @@ -2529,9 +2551,9 @@ class SBPlusTree extends BPlusTree { return $seek; } - function getitem($key) { - $seek = parent::getitem($key); - return $this->getstring($seek); + function getitem(&$key, $loose=false) { + $seek = parent::getitem($key, $loose); + return $seek!==false? $this->getstring($seek) : false; } function setitem($key, $val) { @@ -2541,7 +2563,7 @@ class SBPlusTree extends BPlusTree { } function walker( - $keylower =null, + &$keylower =null, $includelower =null, $keyupper =null, $includeupper =null @@ -2564,10 +2586,10 @@ class caching_SBPT extends SBPlusTree { var $cache = array(); - function getitem($key) { + function getitem(&$key, $loose=false) { if (isset($cache[$key])) return $cache[$key]; - else return ($cache[$key] = parent::getitem($key)); + else return ($cache[$key] = parent::getitem($key, $loose)); } function resetcache() { diff --git a/fp-includes/core/core.entry.php b/fp-includes/core/core.entry.php index bc05b0f..4a4b34e 100755 --- a/fp-includes/core/core.entry.php +++ b/fp-includes/core/core.entry.php @@ -386,6 +386,19 @@ return date('ymdHis', $time); } + function entry_keytotime($key) { + $arr[ 'y' ] = substr($key, 0, 2); + $arr[ 'm' ] = substr($key, 2, 2); + $arr[ 'd' ] = substr($key, 4, 2); + + $arr[ 'H' ] = substr($key, 6, 2); + $arr[ 'M' ] = substr($key, 8, 2); + $arr[ 'S' ] = substr($key, 10, 2); + + return mktime($arr['H'], $arr['M'], $arr['S'], + $arr['m'], $arr['d'], $arr['y']); + } + function entry_idtotime($id) { $date = date_from_id($id); return $date['time']; @@ -408,7 +421,7 @@ function entry_exists($id) { $f = entry_dir($id).EXT; - return $f;file_exists($f)? $f : false; + return file_exists($f)? $f : false; } function entry_dir($id) { diff --git a/fp-includes/core/core.fpdb.class.php b/fp-includes/core/core.fpdb.class.php index 871c69a..9525b5a 100644 --- a/fp-includes/core/core.fpdb.class.php +++ b/fp-includes/core/core.fpdb.class.php @@ -45,7 +45,10 @@ if (entry_exists($params['id'])) { $this->id = $params['id']; - + } else { + // let it fail + $this->count = 0; + return; } } @@ -78,7 +81,7 @@ } - if (isset($params['random'])) { + if (isset($params['random']) && !$this->id) { $this->random = intval($params['random']); $this->count = $this->random; } @@ -148,7 +151,7 @@ $this->params =& new FPDB_QueryParams($params); $this->ID = $ID; - if ($this->params->id) { + if ($this->params->id || $this->params->random) { $this->single = true; } @@ -174,13 +177,13 @@ return; } - if ($this->single) { + if ($this->single || $this->params->random) { + if ($this->params->random>0) { + $this->_get_random_id($entry_index); + } $this->_prepare_single($entry_index); } else { $this->_prepare_list($entry_index); - if ($this->params->random>0) { - $this->_randomize_list(); - } } @@ -197,34 +200,41 @@ $qp =& $this->params; + $time = entry_idtotime($qp->id); + + // let's get a preceding key in the order relation. + // please notice this is hardcoded to $time+1, since + // order of the indices is not configurable by the user + $prevkey = entry_timetokey($time+1); + $key = entry_idtokey($qp->id); + #print_r($key); + + #$key = entry_idtokey($qp->id); if (!($entry_index->has_key($key))){ - trigger_error("FPDB: no entry found for {$qp->id}", E_USER_WARNING); + #trigger_error("FPDB: no entry found for {$qp->id}", E_USER_WARNING); + $qp->count = 0; return; } - $this->walker =& $entry_index->walker($key, true); - - /* - if ($this->counter < 0) { - - $idlist = array_keys($entry_index); - $fliplist = array_flip($idlist); - - $this->local_index =& $entry_index; - $this->local_list =& $idlist; - - $qp->start = $fliplist[$qp->id]; - $qp->count = 1; + // if $includelower = 2 (second parameter) then assumes 'loose' inclusion + // i.e. includes the first key $newkey such as $newkey <= $prevkey + // also, if $prevkey != $newkey then $prevkey := $newkey - } - - $this->pointer = $qp->start; - */ + $this->walker =& $entry_index->walker($prevkey, 2, null, null); + + // since we're searching for $prevkey, i.e. a key preceding the target $id + // in the sequence, if $prevkey becomes equal to $key then it means + // $key is the first post (the last in time) + + if ($prevkey == $key) + $qp->start = 0; + else + $qp->start = 1; - $qp->start = 0; $qp->count = 1; + $this->pointer = 0; } @@ -291,34 +301,26 @@ */ } - - function _randomize_list() { + + // not so great implementation... doesn't work well + function _get_random_id(&$entry_index) { $qp =& $this->params; - - $i = $qp->random - 1; - $nums = array_keys($this->local_list); - - - if ($qp->random == 1) { - $i = mt_rand(0, end($nums)); - $this->single = true; - $qp->id = $this->local_list[ $i ]; - $this->_prepare_single($this->local_index); - return; - } - - shuffle($nums); - - $newlocal = array(); - do { - $newlocal[ $i ] = $this->local_list[ $nums[$i] ]; - } while($i--); - - $this->local_list = $newlocal; - - if ($qp->count > $qp->random) { - $qp->count = $qp->random; - } + $now = time(); + + $first = '999999999999'; + $last = '000000000000'; + $entry_index->getitem($first, true); + $entry_index->getitem($last, true); + + $t1 = entry_keytotime($first); + $t2 = entry_keytotime($last); + + $t = mt_rand($t2, $t1); + + $random_key = entry_timetokey($t); + $entry_index->getitem($random_key, true); + + $qp->id = entry_keytoid($random_key); } /* reading functions */ @@ -361,14 +363,19 @@ $this->previd = $this->currentid; $id = $this->currentid = entry_keytoid($this->walker->current_key()); + if ($this->single) $this->preventry = array('subject' => $this->walker->current_value()); + + $this->walker->next(); $this->pointer++; } // pointer == start - $this->previd = $this->currentid; + $prevcurr = $this->currentid; $id = $this->currentid = entry_keytoid($this->walker->current_key()); + if ($id != $prevcurr) $this->previd = $prevcurr; + if ($qp->fullparse && $this->counter <= 0) { @@ -465,14 +472,16 @@ function getNextPage() { if ($this->single){ - return false; - $id = $this->_getOffsetId(1, $this->params->start); + #return false; + #$id = $this->_getOffsetId(1, $this->params->start); + $id = $this->walker->valid ? entry_keytoid($this->walker->current_key()) : false; - if ($id) - $label = $this->local_index[$id]['subject']; - else + if ($id) { + $label = $this->walker->current_value(); + } else { return false; - + } + return array($label, $id); } @@ -490,14 +499,9 @@ function getPrevPage() { if ($this->single) { - return false; - $id = $this->_getOffsetId(-1, $this->params->start); - - if ($id) - $label = $this->local_index[$id]['subject']; - else - return false; + $id = $this->previd; + $label = $this->preventry['subject']; return array($label, $id); diff --git a/fp-plugins/prettyurls/plugin.prettyurls.php b/fp-plugins/prettyurls/plugin.prettyurls.php index 766a5d6..b2a39fc 100644 --- a/fp-plugins/prettyurls/plugin.prettyurls.php +++ b/fp-plugins/prettyurls/plugin.prettyurls.php @@ -205,7 +205,7 @@ class Plugin_PrettyURLs { } else { // a bit hackish: we make up a fake url when there is no match, // so that at the higher level the system will 404... - $this->fp_params['entry'] = 'entry000000-000000'; + $this->fp_params['entry'] = 'a'; } } else { $this->fp_params['entry'] = $matches[1];