⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 timeseries.h

📁 用于嵌入式环境的数据库
💻 H
📖 第 1 页 / 共 2 页
字号:
//-< TIMESERIES.H >--------------------------------------------------*--------*
// FastDB                    Version 1.0         (c) 1999  GARRET    *     ?  *
// (Post Relational Database Management System)                      *   /\|  *
//                                                                   *  /  \  *
//                          Created:     22-Nov-2002  K.A. Knizhnik  * / [] \ *
//                          Last update: 22-Nov-2002  K.A. Knizhnik  * GARRET *
//-------------------------------------------------------------------*--------*
// Container for time serires data
//-------------------------------------------------------------------*--------*

#ifndef __TIMESERIES_H__
#define __TIMESERIES_H__

#include <time.h>
#include "fastdb.h"

#define INFINITE_TIME 0x7fffffff

/**
 * Time series block contaning array of elements. Grouping several elements in one block (record)
 * reduce space overhead and increase processing speed.<BR>
 * <B>Attention!</B> This class is not serialized, so it is can be accessed only by one thread<P>
 * <I>You are defining your own time series class, for example:</I>
 * <PRE>
 * class Stock {
 *   public:
 *     char const* name;
 *     TYPE_DESCRIPTOR((KEY(name, INDEXED)));
 * };
 * 
 * 
 * class Quote {
 *   public:
 *     int4        tickerDate;
 *     real4       bid;
 *     int4        bidSize;
 *     real4       ask;
 *     int4        askSize;
 * 
 *     time_t time() const { return tickerDate; } // this method should be defined 
 * 
 *     TYPE_DESCRIPTOR((FIELD(tickerDate), FIELD(bid), FIELD(bidSize), FIELD(ask), FIELD(askSize)));
 * };
 * typedef dbTimeSeriesBlock<Daily>  DailyBlock;
 * REGISTER(DailyBlock);
 * </PRE>    
 * <I>Now you can work with time series objects in the followin way:</I>
 * <PRE>
 * dbDatabase db;
 * if (db.open("mydatabase.dbs")) {
 *     dbTimeSeriesProcessor&lt;Quote&gt; proc(db, MIN_ELEMENTS_IN_BLOCK,MAX_ELEMENTS_IN_BLOCK);
 *     Quote quote;
 *     // initialize quote
 *     Stock stock;
 *     stock.name = "AAD";
 *     oid_t stockId = insert(oid).getOid();
 *     proc.add(stockId, quote); // add new element in time series
 * 
 *     Quote quoteBuf[MAX_QUOTES];
 *     // select quotes for the specified interval
 *     int n = proc.getInterval(stockId, fromDate, tillDate, quoteBuf, MAX_QUOTES);
 *     for (int i = 0; i < n; i++) {
 *         printf("bid=d ask=%d\n", quoteBuf[i].bid, quoteBuf[i].ask);
 *     }
 * }  
 * </PRE>
 */
template<class T>
class dbTimeSeriesBlock { 
  public:
    db_int8 blockId;
    db_int4 used;
    dbArray<T> elements;
  
    TYPE_DESCRIPTOR((KEY(blockId, INDEXED), FIELD(used), FIELD(elements)));
};


/**
 * Time series processor.<BR>
 * Element of time series can be arbitrary type with declared TYPE_DESCRIPTOR and defined
 * <code>time_t time()</code> method
 */
template<class T>
class dbTimeSeriesProcessor { 
    struct Interval { 
        db_int8 from;
        db_int8 till;
    };

  public:
    /**
     * Virtual method for processing elements, Should be redefinedin derived class.
     * @param data reference to the processed data element
     */
    virtual void process(T const&) {}
    
    /**
     * Add new element
     * @param oid time series identifer (OID of the object associated with this time series)
     * @param data reference to the inserted element
     */
    void add(oid_t oid, T const& data) 
    { 
        Interval interval;
        interval.from = generateBlockId(oid, data.time() - maxBlockTimeInterval);
        interval.till = generateBlockId(oid, data.time());
        dbCursor< dbTimeSeriesBlock<T> > blocks;
        blocks.select(selectBlock, dbCursorForUpdate, &interval);
        if (blocks.last()) { 
            insertInBlock(oid, blocks, data);
        } else { 
            addNewBlock(oid, data);
        }
    }

    /**
     * Process elements in the block belonging to the specified range
     * @param oid time series identifer (OID of the object associated with this time series)
     * @param from inclusive low bound for element timestamp (set 0 to disable this criteria)
     * @param till inclusive high bound for element timestamp (set INFINITE_TIME to disable this criteria)
     */
    void select(oid_t oid, time_t from, time_t till) 
    { 
        Interval interval;
        interval.from = generateBlockId(oid, from - maxBlockTimeInterval);
        interval.till = generateBlockId(oid, till);
        dbCursor< dbTimeSeriesBlock<T> > blocks;
        if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) { 
            do { 
                int n = blocks->used;
                T const* e =  blocks->elements.get();
                int l = 0, r = n;
                while (l < r)  {
                    int i = (l+r) >> 1;
                    if (from > e[i].time()) { 
                        l = i+1;
                    } else { 
                        r = i;
                    }
                }
                assert(l == r && (l == n || e[l].time() >= from)); 
                while (l < n && e[l].time() <= till) {
                    process(e[l++]);
                }
            } while (blocks.next());
        }
    }
    
    /**
     * Get the time of the first element in time series
     * @param oid time series identifer (OID of the object associated with this time series)
     * @return earliest time in times series or -1 if there are no elements in time series
     */
    time_t getFirstTime(oid_t oid) 
    {
        Interval interval;
        interval.from = generateBlockId(oid, 0);
        interval.till = generateBlockId(oid, INFINITE_TIME);
        dbCursor< dbTimeSeriesBlock<T> > blocks;
        blocks.setSelectionLimit(1);
        if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) { 
            return blocks->elements[0].time();
        }
        return (time_t)-1;
    }
    
    /**
     * Get the time of the last element in time series
     * @param oid time series identifer (OID of the object associated with this time series)
     * @return latest time in times series or -1 if there are no elements in time series
     */
    time_t getLastTime(oid_t oid) 
    {
        Interval interval;
        interval.from = generateBlockId(oid, 0);
        interval.till = generateBlockId(oid, INFINITE_TIME);
        dbCursor< dbTimeSeriesBlock<T> > blocks;
        blocks.setSelectionLimit(1);
        if (blocks.select(selectBlockReverse, dbCursorViewOnly, &interval)) { 
            return blocks->elements[blocks->used-1].time();
        }
        return (time_t)-1;
    }
    
    /**
     * Get number of elements in time series.
     * @param oid time series identifer (OID of the object associated with this time series)
     * @return number of elements in time series.
     */
    size_t getNumberOfElements(oid_t oid) 
    {
        Interval interval;
        interval.from = generateBlockId(oid, 0);
        interval.till = generateBlockId(oid, INFINITE_TIME);
        dbCursor< dbTimeSeriesBlock<T> > blocks;
        int n = 0;
        if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) {
            do { 
                n += blocks->used;
            } while (blocks.next());
        }
        return n;
    }
        
    /**
     * Select elements belonging to the specified interval
     * @param oid time series identifer (OID of the object associated with this time series)
     * @param from inclusive low bound for element timestamp (set 0 to disable this criteria)
     * @param till inclusive high bound for element timestamp (set INFINITE_TIME to disable this criteria)
     * @param buf destination buffer for selected elements
     * @param bufSize size of buffer: up to bufSize elements will be placed in buffer
     * @return number of elements belonging to the specified interval (can be greater than bufSize)
     */
    size_t getInterval(oid_t oid, time_t from, time_t till, T* buf, size_t bufSize) 
    { 
        Interval interval;
        interval.from = generateBlockId(oid, from == 0 ? 0 : from - maxBlockTimeInterval);
        interval.till = generateBlockId(oid, till);
        dbCursor< dbTimeSeriesBlock<T> > blocks;
        size_t nSelected = 0;
        if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) { 
            do { 
                int n = blocks->used;
                T const* e =  blocks->elements.get();
                int l = 0, r = n;
                while (l < r)  {
                    int i = (l+r) >> 1;
                    if (from > e[i].time()) { 
                        l = i+1;
                    } else { 
                        r = i;
                    }
                }
                assert(l == r && (l == n || e[l].time() >= from)); 
                while (l < n && e[l].time() <= till) {
                    if (nSelected < bufSize) { 
                        buf[nSelected] = e[l];
                    }
                    l += 1;
                    nSelected += 1;
                }
            } while (blocks.next());
        }
        return nSelected;
    }        
        
    /**
     * Get time series element with specified time
     * @param oid time series identifer (OID of the object associated with this time series)
     * @param elem reference to the extracted element 
     * @param t timestamp of extracted element
     * @return <code>true</code> if element with specifed times exists in time series
     */
    bool getElement(oid_t oid, T& elem, time_t t) 
    { 
        return getInterval(oid, t, t, &elem, 1) == 1;
    }        
        
    /**
     * Select first N elements of times series with timestamp less than or equal to specified
     * @param oid time series identifer (OID of the object associated with this time series)
     * @param till inclusive high bound for element timestamp (set INFINITE_TIME to disable this criteria) 
     * @param buf destination buffer for selected elements
     * @param bufSize size of buffer: up to bufSize elements will be placed in buffer
     * @return number of selected elements (can be less than bufSize if there are less elements in time series
     * with timestamp less or equal than specified, but can not be greater than bufSize)
     */
    size_t getFirstInterval(oid_t oid, time_t till, T* buf, size_t bufSize) 
    {
        if (bufSize == 0) { 
            return 0;
        }
        Interval interval;
        interval.from = generateBlockId(oid, 0);
        interval.till = generateBlockId(oid, till);
        dbCursor< dbTimeSeriesBlock<T> > blocks;
        size_t nSelected = 0;
        if (blocks.select(selectBlock, dbCursorViewOnly, &interval)) { 
            do { 
                int n = blocks->used;
                T const* e =  blocks->elements.get();
                for (int i = 0; i < n && e[i].time() <= till; i++) { 
                    buf[nSelected++] = e[i];
                    if (nSelected == bufSize) { 
                        return nSelected;
                    }
                }
            } while (blocks.next());
        }
        return nSelected;
    }        


    /**
     * Select last N elements of times series with timestamp greater than or equal to specified
     * @param oid time series identifer (OID of the object associated with this time series)
     * @param from inclusive low bound for element timestamp (set 0 to disable this criteria)
     * @param buf destination buffer for selected elements
     * @param bufSize size of buffer: up to bufSize elements will be placed in buffer
     * @return number of selected elements (can be less than bufSize if there are less elements in time series
     * with timestamp greater or equal than specified, but can not be greater than bufSize)
     */
    size_t getLastInterval(oid_t oid, time_t from, T* buf, size_t bufSize) 
    {
        if (bufSize == 0) { 
            return 0;
        }
        Interval interval;
        interval.from = generateBlockId(oid, from == 0 ? 0 : from - maxBlockTimeInterval);
        interval.till = generateBlockId(oid, INFINITE_TIME);
        dbCursor< dbTimeSeriesBlock<T> > blocks;

        size_t nSelected = 0;
        blocks.select(selectBlock, dbCursorViewOnly, &interval);
        if (blocks.last()) { 
            do { 
                int n = blocks->used;
                T const* e =  blocks->elements.get();
                for (int i = n; --i >= 0 && e[i].time() >= from;) { 
                    buf[nSelected++] = e[i];
                    if (nSelected == bufSize) { 
                        return nSelected;
                    }
                }
            } while (blocks.prev());
        }
        return nSelected;
    }        



    /**
     * Check if there is element for specified data in time series
     * @param oid time series identifer (OID of the object associated with this time series)
     * @param t timestamp of checked element
     * @return <code>true</code> if element with specifed times exists in time series
     */
    bool hasElement(oid_t oid, time_t t) 
    { 
        T dummy;
        return getElement(oid, dummy, t);
    }        

    /**
     * TimeSeries processor constructor
     * @param database reference to the database
     * @param minElementsInBlock preallocated number of the elements in the block: 
     * array with specified number of elements will be allocated for new block
     * @param maxElementsInBlock maximal number of the elements in the block: block will be splitten if it has maxElementsInBlock
     * elements and new is added to the block
     * @param maxBlockTimeInterval maximal interval between first and last element in the block, new block will be created if 
     * adding new element to the block cause violation of this assumption. If maxBlockTimeInterval is 0, then it is assigned

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -