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_LOG(LOG_DEBUG, "CursorWindow") 35 #define LOG_WINDOW(...) LOG(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, bool localOnly, 84 CursorWindow** outCursorWindow); 85 static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow); 86 87 status_t writeToParcel(Parcel* parcel); 88 89 inline String8 name() { return mName; } 90 inline size_t size() { return mSize; } 91 inline size_t freeSpace() { return mSize - mHeader->freeOffset; } 92 inline uint32_t getNumRows() { return mHeader->numRows; } 93 inline uint32_t getNumColumns() { return mHeader->numColumns; } 94 95 status_t clear(); 96 status_t setNumColumns(uint32_t numColumns); 97 98 /** 99 * Allocate a row slot and its directory. 100 * The row is initialized will null entries for each field. 101 */ 102 status_t allocRow(); 103 status_t freeLastRow(); 104 105 status_t putBlob(uint32_t row, uint32_t column, const void* value, size_t size); 106 status_t putString(uint32_t row, uint32_t column, const char* value, size_t sizeIncludingNull); 107 status_t putLong(uint32_t row, uint32_t column, int64_t value); 108 status_t putDouble(uint32_t row, uint32_t column, double value); 109 status_t putNull(uint32_t row, uint32_t column); 110 111 /** 112 * Gets the field slot at the specified row and column. 113 * Returns null if the requested row or column is not in the window. 114 */ 115 FieldSlot* getFieldSlot(uint32_t row, uint32_t column); 116 117 inline int32_t getFieldSlotType(FieldSlot* fieldSlot) { 118 return fieldSlot->type; 119 } 120 121 inline int64_t getFieldSlotValueLong(FieldSlot* fieldSlot) { 122 return fieldSlot->data.l; 123 } 124 125 inline double getFieldSlotValueDouble(FieldSlot* fieldSlot) { 126 return fieldSlot->data.d; 127 } 128 129 inline const char* getFieldSlotValueString(FieldSlot* fieldSlot, 130 size_t* outSizeIncludingNull) { 131 *outSizeIncludingNull = fieldSlot->data.buffer.size; 132 return static_cast<char*>(offsetToPtr(fieldSlot->data.buffer.offset)); 133 } 134 135 inline const void* getFieldSlotValueBlob(FieldSlot* fieldSlot, size_t* outSize) { 136 *outSize = fieldSlot->data.buffer.size; 137 return offsetToPtr(fieldSlot->data.buffer.offset); 138 } 139 140 private: 141 static const size_t ROW_SLOT_CHUNK_NUM_ROWS = 100; 142 143 struct Header { 144 // Offset of the lowest unused byte in the window. 145 uint32_t freeOffset; 146 147 // Offset of the first row slot chunk. 148 uint32_t firstChunkOffset; 149 150 uint32_t numRows; 151 uint32_t numColumns; 152 }; 153 154 struct RowSlot { 155 uint32_t offset; 156 }; 157 158 struct RowSlotChunk { 159 RowSlot slots[ROW_SLOT_CHUNK_NUM_ROWS]; 160 uint32_t nextChunkOffset; 161 }; 162 163 String8 mName; 164 int mAshmemFd; 165 void* mData; 166 size_t mSize; 167 bool mReadOnly; 168 Header* mHeader; 169 170 inline void* offsetToPtr(uint32_t offset) { 171 return static_cast<uint8_t*>(mData) + offset; 172 } 173 174 inline uint32_t offsetFromPtr(void* ptr) { 175 return static_cast<uint8_t*>(ptr) - static_cast<uint8_t*>(mData); 176 } 177 178 /** 179 * Allocate a portion of the window. Returns the offset 180 * of the allocation, or 0 if there isn't enough space. 181 * If aligned is true, the allocation gets 4 byte alignment. 182 */ 183 uint32_t alloc(size_t size, bool aligned = false); 184 185 RowSlot* getRowSlot(uint32_t row); 186 RowSlot* allocRowSlot(); 187 188 status_t putBlobOrString(uint32_t row, uint32_t column, 189 const void* value, size_t size, int32_t type); 190 }; 191 192 }; // namespace android 193 194 #endif 195