//--------------------------------------------------------------- // ____ _ _ ____ _ //| _ \ ___ _ _ __ _| | |_ _ _/ ___|| |__ __ _ _ __ ___ //| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \ //| _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | | __/ //|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_| \___| // |___/ |___/ // // Copyright (C) 2011 RoyaltyShare, Inc. All Rights Reserved //--------------------------------------------------------------- #ifndef hPackedTable #define hPackedTable #include #include class PackedTable { public: // These error constants will be thrown as exceptions (i.e. we'll throw ints). // Less overhead than throwing objects around. // static const int kErrorProgrammer = 9999; // pretty generic... // !!! In most cases, we'll actually throw errno. PackedTable() {;} virtual ~PackedTable() {;} virtual void createDataFile(const char* outFileBaseName, MYSQL* dbConnection, int loadAfterBuildFlag) = 0; virtual void loadDataFile(const char* inFileBaseName) = 0; virtual long numItems() = 0; // // This returns the number of slots in the data array. // This does NOT tell you how many are 'real' - Just the size of the array. // NOT the number of bytes... protected: static void _ParseLong(const char* inString, long* outLong); static void _ParseString(const char* inString, char* outString, long len); static void _ParseDate(const char* inString, time_t* outString); static void _ParseChar(const char* inString, char* outChar); static void _ParseByte(const char* inString, char* outByte); }; class PackedTableFlat : public PackedTable { protected: void* _data; long _dataSize; virtual long _dataElementSize() = 0; virtual const char* _maxIDQueryString() = 0; virtual const char* _dataQueryString() = 0; virtual void _readDataRow(MYSQL_ROW row, void* dataBlock) = 0; public: PackedTableFlat() : _data(NULL), _dataSize(0) {;} virtual ~PackedTableFlat(); virtual void createDataFile(const char* outFileBaseName, MYSQL* dbConnection, int loadAfterBuildFlag); virtual void loadDataFile(const char* outFileBaseName); void* getIndexedData(const long index) { if (NULL == this->_data) { // Bad programmer!! // fprintf(stderr, "ERROR: getIndexData called before data has been loaded!"); throw PackedTable::kErrorProgrammer; } void* dataPtr = (void*)((this->_dataElementSize() * index) + (unsigned long)this->_data); return dataPtr; // struct _sale *array = (struct _sale *)this->_data; // return &(array[index - 1]); } }; class PackedTableDynamic : public PackedTable { protected: PackedTableFlat* _indexTable; void* _maxValidAddr; void* _dataPtr; // // Here's the strategy - We _contain_ another table Object (a 'uses' relationship), // which is the Index table. We also _are_ a Table (the data payload). // We're probably going to need an iterator class... Or we could be slightly less slick, // and just provide an iterator interface in this class, somehow. // // public: PackedTableDynamic() : _indexTable(NULL), _dataPtr(NULL), _maxValidAddr(0) {;} virtual ~PackedTableDynamic(); virtual void createDataFile(const char* outFileBaseName, MYSQL* dbConnection, int loadAfterBuildFlag); virtual void loadDataFile(const char* inFileBaseName); protected: virtual unsigned long _dataChunkSize() = 0; virtual unsigned long _equalKeys(void* ptrA, void* ptrB) = 0; int _pointerIsValid(void* ptr) { if (NULL == ptr) { return 0; } if (ptr > this->_maxValidAddr) { return 0; } return 1; } public: class Iterator { PackedTableDynamic* _table; void* _ptr; public: Iterator(PackedTableDynamic* table) : _table(table), _ptr(NULL) {;} virtual ~Iterator() {;} void* next() { // Want to not have to keep a count in my data. // But that does make it relatively easy to fuck it up. // I don't want to have segfaults when I try to increment the pointer. // Basically, the Iterator class is going to be making calls into the Table class // to figure out what it needs to know. // After instantiation the Iterator will be pointing to a data chuck. void* returnPtr = this->_ptr; if (this->_ptr != NULL) { // Increment the ptr to the next node. And check to make sure we don't roll off the edge. // unsigned long addr = (unsigned long)this->_ptr; addr += _table->_dataChunkSize(); this->_ptr = (void*)addr; if (! _table->_pointerIsValid(this->_ptr)) { this->_ptr = NULL; } else { if (! _table->_equalKeys(returnPtr, this->_ptr)) { this->_ptr = NULL; } } } return returnPtr; } }; virtual class Interator* getIndexedList(long index) = 0; }; #endif