summaryrefslogtreecommitdiffstats
path: root/include/util/Cursor.h
blob: 3f5f20fce1085b390d45b5c95194a0f947fd6e89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 * include/util/Cursor.h
 *
 * Copyright (C) 2023 Douglas Rumbaugh <drumbaugh@psu.edu> 
 *                    Dong Xie <dongx@psu.edu>
 *
 * All rights reserved. Published under the Modified BSD License.
 *
 */
#pragma once

#include "util/base.h"
#include "util/record.h"
#include "io/PagedFile.h"

namespace de {
struct Cursor {
    record_t *ptr;
    const record_t *end;
    size_t cur_rec_idx;
    size_t rec_cnt;

    friend bool operator==(const Cursor &a, const Cursor &b) {
        return a.ptr == b.ptr && a.end == b.end;
    }
};

static Cursor g_empty_cursor = {0};

/*
 * Advance the cursor to the next record. If the cursor is backed by an
 * iterator, will attempt to advance the iterator once the cursor reaches its
 * end and reset the cursor to the beginning of the read page.
 *
 * If the advance succeeds, ptr will be updated to point to the new record
 * and true will be returned. If the advance reaches the end, then ptr will
 * be updated to be equal to end, and false will be returned. Iterators will
 * not be closed.
 */
inline static bool advance_cursor(Cursor *cur, PagedFileIterator *iter = nullptr) {
    cur->ptr++;
    cur->cur_rec_idx++;

    if (cur->cur_rec_idx >= cur->rec_cnt) return false;

    if (cur->ptr >= cur->end) {
        if (iter && iter->next()) {
            cur->ptr = (record_t*)iter->get_item();
            cur->end = cur->ptr + (PAGE_SIZE / sizeof(record_t));
            return true;
        }

        return false;
    }
    return true;
}

/*
 *   Process the list of cursors to return the cursor containing the next
 *   largest element. Does not advance any of the cursors. If current is
 *   specified, then skip the current head of that cursor during checking. 
 *   This allows for "peaking" at the next largest element after the current 
 *   largest is processed.
 */
inline static Cursor *get_next(std::vector<Cursor> &cursors, Cursor *current=&g_empty_cursor) {
    const record_t *min_rec = nullptr;
    Cursor *result = &g_empty_cursor;
    for (size_t i=0; i< cursors.size(); i++) {
        if (cursors[i] == g_empty_cursor) continue;

        const record_t *rec = (&cursors[i] == current) ? cursors[i].ptr + 1 : cursors[i].ptr;
        if (rec >= cursors[i].end) continue;

        if (min_rec == nullptr) {
            result = &cursors[i];
            min_rec = rec;
            continue;
        }

        if (*rec < *min_rec) {
            result = &cursors[i];
            min_rec = rec;
        }
    }

    return result;
} 

}