summaryrefslogtreecommitdiffstats
path: root/include/binder/CursorWindow.h
blob: 4fbff2ac9476ebef4da6fe9877adacd40c1ee8c7 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _ANDROID__DATABASE_WINDOW_H
#define _ANDROID__DATABASE_WINDOW_H

#include <cutils/log.h>
#include <stddef.h>
#include <stdint.h>

#include <binder/IMemory.h>
#include <utils/RefBase.h>

#define DEFAULT_WINDOW_SIZE 4096
#define MAX_WINDOW_SIZE (1024 * 1024)
#define WINDOW_ALLOCATION_SIZE 4096

#define ROW_SLOT_CHUNK_NUM_ROWS 16

// Row slots are allocated in chunks of ROW_SLOT_CHUNK_NUM_ROWS,
// with an offset after the rows that points to the next chunk
#define ROW_SLOT_CHUNK_SIZE ((ROW_SLOT_CHUNK_NUM_ROWS * sizeof(row_slot_t)) + sizeof(uint32_t))


#if LOG_NDEBUG

#define IF_LOG_WINDOW() if (false)
#define LOG_WINDOW(...)

#else

#define IF_LOG_WINDOW() IF_LOG(LOG_DEBUG, "CursorWindow")
#define LOG_WINDOW(...) LOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__)

#endif


// When defined to true strings are stored as UTF8, otherwise they're UTF16
#define WINDOW_STORAGE_UTF8 1

// When defined to true numberic values are stored inline in the field_slot_t, otherwise they're allocated in the window
#define WINDOW_STORAGE_INLINE_NUMERICS 1

namespace android {

typedef struct
{
    uint32_t numRows;
    uint32_t numColumns;
} window_header_t;

typedef struct
{
    uint32_t offset;
} row_slot_t;

typedef struct
{
    uint8_t type;
    union {
        double d;
        int64_t l;
        struct {
            uint32_t offset;
            uint32_t size;
        } buffer;
    } data;
} __attribute__((packed)) field_slot_t;

#define FIELD_TYPE_NULL 0
#define FIELD_TYPE_INTEGER 1
#define FIELD_TYPE_FLOAT 2
#define FIELD_TYPE_STRING 3
#define FIELD_TYPE_BLOB 4

/**
 * This class stores a set of rows from a database in a buffer. The begining of the
 * window has first chunk of row_slot_ts, which are offsets to the row directory, followed by
 * an offset to the next chunk in a linked-list of additional chunk of row_slot_ts in case
 * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a
 * field_slot_t per column, which has the size, offset, and type of the data for that field.
 * Note that the data types come from sqlite3.h.
 */
class CursorWindow
{
public:
                        CursorWindow(size_t maxSize);
                        CursorWindow(){}
    bool                setMemory(const sp<IMemory>&);
                        ~CursorWindow();

    bool                initBuffer(bool localOnly);
    sp<IMemory>         getMemory() {return mMemory;}

    size_t              size() {return mSize;}
    uint8_t *           data() {return mData;}
    uint32_t            getNumRows() {return mHeader->numRows;}
    uint32_t            getNumColumns() {return mHeader->numColumns;}
    void                freeLastRow() {
                            if (mHeader->numRows > 0) {
                                mHeader->numRows--;
                            }
                        }
    bool                setNumColumns(uint32_t numColumns)
                            {
                                uint32_t cur = mHeader->numColumns;
                                if (cur > 0 && cur != numColumns) {
                                    LOGE("Trying to go from %d columns to %d", cur, numColumns);
                                    return false;
                                }
                                mHeader->numColumns = numColumns;
                                return true;
                            }

    int32_t             freeSpace();

    void                clear();

                        /**
                         * Allocate a row slot and its directory. The returned
                         * pointer points to the begining of the row's directory
                         * or NULL if there wasn't room. The directory is
                         * initialied with NULL entries for each field.
                         */
    field_slot_t *      allocRow();

                        /**
                         * Allocate a portion of the window. Returns the offset
                         * of the allocation, or 0 if there isn't enough space.
                         * If aligned is true, the allocation gets 4 byte alignment.
                         */
    uint32_t            alloc(size_t size, bool aligned = false);

    uint32_t            read_field_slot(int row, int column, field_slot_t * slot);

                        /**
                         * Copy data into the window at the given offset.
                         */
    void                copyIn(uint32_t offset, uint8_t const * data, size_t size);
    void                copyIn(uint32_t offset, int64_t data);
    void                copyIn(uint32_t offset, double data);

    void                copyOut(uint32_t offset, uint8_t * data, size_t size);
    int64_t             copyOutLong(uint32_t offset);
    double              copyOutDouble(uint32_t offset);

    bool                putLong(unsigned int row, unsigned int col, int64_t value);
    bool                putDouble(unsigned int row, unsigned int col, double value);
    bool                putNull(unsigned int row, unsigned int col);

    bool                getLong(unsigned int row, unsigned int col, int64_t * valueOut);
    bool                getDouble(unsigned int row, unsigned int col, double * valueOut);
    bool                getNull(unsigned int row, unsigned int col, bool * valueOut);

    uint8_t *           offsetToPtr(uint32_t offset) {return mData + offset;}

    row_slot_t *        allocRowSlot();

    row_slot_t *        getRowSlot(int row);

                        /**
                         * return NULL if Failed to find rowSlot or
                         * Invalid rowSlot
                         */
    field_slot_t *      getFieldSlotWithCheck(int row, int column);
    field_slot_t *      getFieldSlot(int row, int column)
                            {
                                int fieldDirOffset = getRowSlot(row)->offset;
                                return ((field_slot_t *)offsetToPtr(fieldDirOffset)) + column;
                            }

private:
    uint8_t * mData;
    size_t mSize;
    size_t mMaxSize;
    window_header_t * mHeader;
    sp<IMemory> mMemory;

    /**
     * Offset of the lowest unused data byte in the array.
     */
    uint32_t mFreeOffset;
};

}; // namespace android

#endif