/*
* 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>
#include <jni.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_INTEGER 1
#define FIELD_TYPE_FLOAT 2
#define FIELD_TYPE_STRING 3
#define FIELD_TYPE_BLOB 4
#define FIELD_TYPE_NULL 5
/**
* 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