1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef _ANDROID__DATABASE_WINDOW_H 18 #define _ANDROID__DATABASE_WINDOW_H 19 20 #include <cutils/log.h> 21 #include <stddef.h> 22 #include <stdint.h> 23 24 #include <binder/Parcel.h> 25 #include <utils/String8.h> 26 27 #if LOG_NDEBUG 28 29 #define IF_LOG_WINDOW() if (false) 30 #define LOG_WINDOW(...) 31 32 #else 33 34 #define IF_LOG_WINDOW() IF_ALOG(LOG_DEBUG, "CursorWindow") 35 #define LOG_WINDOW(...) ALOG(LOG_DEBUG, "CursorWindow", __VA_ARGS__) 36 37 #endif 38 39 namespace android { 40 41 /** 42 * This class stores a set of rows from a database in a buffer. The begining of the 43 * window has first chunk of RowSlots, which are offsets to the row directory, followed by 44 * an offset to the next chunk in a linked-list of additional chunk of RowSlots in case 45 * the pre-allocated chunk isn't big enough to refer to all rows. Each row directory has a 46 * FieldSlot per column, which has the size, offset, and type of the data for that field. 47 * Note that the data types come from sqlite3.h. 48 * 49 * Strings are stored in UTF-8. 50 */ 51 class CursorWindow { 52 CursorWindow(const String8& name, int ashmemFd, 53 void* data, size_t size, bool readOnly); 54 55 public: 56 /* Field types. */ 57 enum { 58 FIELD_TYPE_NULL = 0, 59 FIELD_TYPE_INTEGER = 1, 60 FIELD_TYPE_FLOAT = 2, 61 FIELD_TYPE_STRING = 3, 62 FIELD_TYPE_BLOB = 4, 63 }; 64 65 /* Opaque type that describes a field slot. */ 66 struct FieldSlot { 67 private: 68 int32_t type; 69 union { 70 double d; 71 int64_t l; 72 struct { 73 uint32_t offset; 74 uint32_t size; 75 } buffer; 76 } data; 77 78 friend class CursorWindow; 79 } __attribute((packed)); 80 81 ~CursorWindow(); 82 83 static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow); 84 static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow); 85 86 status_t writeToParcel(Parcel* parcel); 87 88 inline String8 name() { return mName; } 89 inline size_t size() { return mSize; } 90 inline size_t freeSpace() { return mSize - mHeader->freeOffset; } 91 inline uint32_t getNumRows() { return mHeader->numRows; } 92 inline uint32_t getNumColumns() { return mHeader->numColumns; } 93 94 status_t clear(); 95 status_t setNumColumns(uint32_t numColumns); 96 97 /** 98 * Allocate a row slot and its directory. 99 * The row is initialized will null entries for each field. 100 */ 101 status_t allocRow(); 102 status_t freeLastRow(); 103 104 status_t putBlob(uint32_t row, uint32_t column, const void* value, size_t size); 105 status_t putString(uint32_t row, uint32_t column, const char* value, size_t sizeIncludingNull); 106 status_t putLong(uint32_t row, uint32_t column, int64_t value); 107 status_t putDouble(uint32_t row, uint32_t column, double value); 108 status_t putNull(uint32_t row, uint32_t column); 109 110 /** 111 * Gets the field slot at the specified row and column. 112 * Returns null if the requested row or column is not in the window. 113 */ 114 FieldSlot* getFieldSlot(uint32_t row, uint32_t column); 115 116 inline int32_t getFieldSlotType(FieldSlot* fieldSlot) { 117 return fieldSlot->type; 118 } 119 120 inline int64_t getFieldSlotValueLong(FieldSlot* fieldSlot) { 121 return fieldSlot->data.l; 122 } 123 124 inline double getFieldSlotValueDouble(FieldSlot* fieldSlot) { 125 return fieldSlot->data.d; 126 } 127 128 inline const char* getFieldSlotValueString(FieldSlot* fieldSlot, 129 size_t* outSizeIncludingNull) { 130 *outSizeIncludingNull = fieldSlot->data.buffer.size; 131 return static_cast<char*>(offsetToPtr(fieldSlot->data.buffer.offset)); 132 } 133 134 inline const void* getFieldSlotValueBlob(FieldSlot* fieldSlot, size_t* outSize) { 135 *outSize = fieldSlot->data.buffer.size; 136 return offsetToPtr(fieldSlot->data.buffer.offset); 137 } 138 139 private: 140 static const size_t ROW_SLOT_CHUNK_NUM_ROWS = 100; 141 142 struct Header { 143 // Offset of the lowest unused byte in the window. 144 uint32_t freeOffset; 145 146 // Offset of the first row slot chunk. 147 uint32_t firstChunkOffset; 148 149 uint32_t numRows; 150 uint32_t numColumns; 151 }; 152 153 struct RowSlot { 154 uint32_t offset; 155 }; 156 157 struct RowSlotChunk { 158 RowSlot slots[ROW_SLOT_CHUNK_NUM_ROWS]; 159 uint32_t nextChunkOffset; 160 }; 161 162 String8 mName; 163 int mAshmemFd; 164 void* mData; 165 size_t mSize; 166 bool mReadOnly; 167 Header* mHeader; 168 169 inline void* offsetToPtr(uint32_t offset) { 170 return static_cast<uint8_t*>(mData) + offset; 171 } 172 173 inline uint32_t offsetFromPtr(void* ptr) { 174 return static_cast<uint8_t*>(ptr) - static_cast<uint8_t*>(mData); 175 } 176 177 /** 178 * Allocate a portion of the window. Returns the offset 179 * of the allocation, or 0 if there isn't enough space. 180 * If aligned is true, the allocation gets 4 byte alignment. 181 */ 182 uint32_t alloc(size_t size, bool aligned = false); 183 184 RowSlot* getRowSlot(uint32_t row); 185 RowSlot* allocRowSlot(); 186 187 status_t putBlobOrString(uint32_t row, uint32_t column, 188 const void* value, size_t size, int32_t type); 189 }; 190 191 }; // namespace android 192 193 #endif 194