<commit_before>/*  Sirikata Utilities -- Sirikata Synchronization Utilities
 *  LockFreeQueue.hpp
 *
 *  Copyright (c) 2008, Daniel Reiter Horn
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _SIRIKATA_LOCK_FREE_QUEUE_HPP_
#define _SIRIKATA_LOCK_FREE_QUEUE_HPP_
#ifdef __APPLE__
#include <libkern/OSAtomic.h>
#endif
/// LockFreeQueue.hpp
namespace Sirikata {

/// A queue of any type that has thread-safe push() and pop() functions.
template <typename T> class LockFreeQueue {
private:
    struct Node {
        volatile Node * mNext;
        T mContent;
        Node() :mNext(NULL), mContent() {
        }
    };
    static bool compare_and_swap(volatile Node*volatile *target, volatile Node *comperand, volatile Node * exchange){
#ifdef _WIN32
        return InterlockedCompareExchangePointer(target, exchange, comperand)==comperand;
#else
#ifdef __APPLE__
        if (sizeof(exchange)==4) {
            return OSAtomicCompareAndSwap32((int32_t)comperand, (int32_t)exchange, (int32_t*)target);
        }else {
            return OSAtomicCompareAndSwap64((int64_t)comperand, (int64_t)exchange, (int64_t*)target);
        }
#else
        return __sync_bool_compare_and_swap (target, comperand, exchange);
#endif
#endif
    }
    class FreeNodePool {

        volatile Node *mHead;
    public:
        FreeNodePool() {
            mHead = new Node();
        }

        Node* allocate() {
            volatile Node* node=NULL;
            do {
                node = mHead->mNext;
                if (node == NULL)
                    return new Node();//FIXME should probably be aligned to size(Node) bytes
            } while (!compare_and_swap(&mHead->mNext, node, node->mNext));
            Node * return_node=(Node*)node;//FIXME volatile cast only allowed if mContent is primitive type of pointer size or less
            return_node->mNext = NULL;
            return_node->mContent=T();
            return return_node;
        }

        void release(Node *node) {
            node->mContent = T();
            do {
                node->mNext = mHead->mNext;
            } while (!compare_and_swap(&mHead->mNext, node->mNext, node));
        }
    } mFreeNodePool;
    volatile Node *mHead;
    volatile Node *mTail;
public:
    LockFreeQueue() {
        mHead = mFreeNodePool.allocate();
        mTail = mHead;
    }

    class NodeIterator {
    private:
    	// Noncopyable
    	NodeIterator(const NodeIterator &other);
    	void operator=(const NodeIterator &other);

    	Node *mLastReturned;
    	Node *mCurrent;

    	FreeNodePool *mFreePool;

    public:
    	NodeIterator(LockFreeQueue<T> &queue)
    		: mLastReturned(queue.fork()),
    		  mCurrent(const_cast<Node*>(mLastReturned->mNext)),
    		  mFreePool(&queue.mFreeNodePool) {
    	}

    	~NodeIterator() {
    		if (mLastReturned) {
    			mFreePool->release(mLastReturned);
    		}
    		while (mCurrent) {
    			mFreePool->release(mCurrent);
    			mCurrent = const_cast<Node*>(mCurrent->mNext);
    		}
    	}

    	T *next() {
    		if (mLastReturned) {
    			mFreePool->release(mLastReturned);
    		}
    		mLastReturned = mCurrent;
    		if (mCurrent) {
    			mCurrent = const_cast<Node*>(mCurrent->mNext);
        		return &mLastReturned->mContent;
    		} else {
    			return NULL;
    		}
    	}
    };

private:
    friend class NodeIterator;

    Node *fork() {
    	volatile Node *newHead = mFreeNodePool.allocate();
		volatile Node *oldHead = mHead;

    	// Acquire "lock" on head, for multiple people fork()ing at once.
    	{
    		while (oldHead == NULL ||
						!compare_and_swap(&mHead, oldHead, NULL)) {
    			oldHead = mHead;
    		}
    	}

    	{
			volatile Node *oldTail = mTail;
			while (!compare_and_swap(&mTail, oldTail, newHead)) {
				oldTail = mTail;
			}
    	}

    	mHead = newHead;
    	return const_cast<Node*>(oldHead);
    }
public:

    /**
     * Pushes value onto the queue
     *
     * @param value  Will be copied and placed onto the end of the queue.
     */
    void push(const T &value) {
        volatile Node* formerTail = NULL;
        volatile Node* formerTailNext=NULL;

        Node* newerNode = mFreeNodePool.allocate();
        newerNode->mContent = value;
        volatile Node*newNode=newerNode;
        bool successfulAddNode = false;
        while (!successfulAddNode) {
            formerTail = mTail;
            formerTailNext = formerTail->mNext;

            if (mTail == formerTail) {
                if (formerTailNext == NULL)
                    successfulAddNode = compare_and_swap(&mTail->mNext, NULL, newNode);
                else
                    compare_and_swap(&mTail, formerTail, formerTailNext);
            }
        }

        compare_and_swap(&mTail, formerTail, newNode);
    }

    /**
     * Pops the front value from the queue and places it in value.
     *
     * @param value  Will have the T at the front of the queue copied into it.
     * @returns      whether value was changed (if the queue had at least one item).
     */
    bool pop(T &value) {
        volatile Node* formerHead = NULL;

        bool headAlreadyAdvanced = false;
        while (!headAlreadyAdvanced) {

            formerHead = mHead;
            if (formerHead == NULL) {
            	// fork() function is operating on mTail.
            	continue;
            }
            volatile Node* formerHeadNext = formerHead->mNext;
            volatile Node*formerTail = mTail;

            if (formerHead == mHead) {
                if (formerHead == formerTail) {
                    if (formerHeadNext == NULL) {
                        value=T();
                        return false;
                    }
                    compare_and_swap(&mTail, formerTail, formerHeadNext);
                }

                else {
                    value = ((Node*)formerHeadNext)->mContent;//FIXME volatile cast only allowed if mContent is primitive type of pointer size or less
                    headAlreadyAdvanced = compare_and_swap(&mHead, formerHead, formerHeadNext);
                }
            }
        }
        mFreeNodePool.release((Node*)formerHead);//FIXME volatile cast only allowed if mContent is primitive type of pointer size or less
        return true;
    }

    bool probablyEmpty() {
        volatile Node* formerHead = mHead;
        if (formerHead) {
            if (formerHead->mNext) {
                // fork() function is operating on mTail.
                return false;
            }
        }
        return true;
    }
};
}

#endif //_SIRIKATA_LOCK_FREE_QUEUE_HPP_
<commit_msg>corrected types of arguments to the ExchangeCompare instruction<commit_after>/*  Sirikata Utilities -- Sirikata Synchronization Utilities
 *  LockFreeQueue.hpp
 *
 *  Copyright (c) 2008, Daniel Reiter Horn
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of Sirikata nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _SIRIKATA_LOCK_FREE_QUEUE_HPP_
#define _SIRIKATA_LOCK_FREE_QUEUE_HPP_
#ifdef __APPLE__
#include <libkern/OSAtomic.h>
#endif
/// LockFreeQueue.hpp
namespace Sirikata {

/// A queue of any type that has thread-safe push() and pop() functions.
template <typename T> class LockFreeQueue {
private:
    struct Node {
        volatile Node * mNext;
        T mContent;
        Node() :mNext(NULL), mContent() {
        }
    };
    static bool compare_and_swap(volatile Node*volatile *target, volatile Node *comperand, volatile Node * exchange){
#ifdef _WIN32
        return InterlockedCompareExchangePointer((volatile PVOID*)target, (volatile PVOID)exchange, (volatile PVOID)comperand)==comperand;
#else
#ifdef __APPLE__
        if (sizeof(exchange)==4) {
            return OSAtomicCompareAndSwap32((int32_t)comperand, (int32_t)exchange, (int32_t*)target);
        }else {
            return OSAtomicCompareAndSwap64((int64_t)comperand, (int64_t)exchange, (int64_t*)target);
        }
#else
        return __sync_bool_compare_and_swap (target, comperand, exchange);
#endif
#endif
    }
    class FreeNodePool {

        volatile Node *mHead;
    public:
        FreeNodePool() {
            mHead = new Node();
        }

        Node* allocate() {
            volatile Node* node=NULL;
            do {
                node = mHead->mNext;
                if (node == NULL)
                    return new Node();//FIXME should probably be aligned to size(Node) bytes
            } while (!compare_and_swap(&mHead->mNext, node, node->mNext));
            Node * return_node=(Node*)node;//FIXME volatile cast only allowed if mContent is primitive type of pointer size or less
            return_node->mNext = NULL;
            return_node->mContent=T();
            return return_node;
        }

        void release(Node *node) {
            node->mContent = T();
            do {
                node->mNext = mHead->mNext;
            } while (!compare_and_swap(&mHead->mNext, node->mNext, node));
        }
    } mFreeNodePool;
    volatile Node *mHead;
    volatile Node *mTail;
public:
    LockFreeQueue() {
        mHead = mFreeNodePool.allocate();
        mTail = mHead;
    }

    class NodeIterator {
    private:
    	// Noncopyable
    	NodeIterator(const NodeIterator &other);
    	void operator=(const NodeIterator &other);

    	Node *mLastReturned;
    	Node *mCurrent;

    	FreeNodePool *mFreePool;

    public:
    	NodeIterator(LockFreeQueue<T> &queue)
    		: mLastReturned(queue.fork()),
    		  mCurrent(const_cast<Node*>(mLastReturned->mNext)),
    		  mFreePool(&queue.mFreeNodePool) {
    	}

    	~NodeIterator() {
    		if (mLastReturned) {
    			mFreePool->release(mLastReturned);
    		}
    		while (mCurrent) {
    			mFreePool->release(mCurrent);
    			mCurrent = const_cast<Node*>(mCurrent->mNext);
    		}
    	}

    	T *next() {
    		if (mLastReturned) {
    			mFreePool->release(mLastReturned);
    		}
    		mLastReturned = mCurrent;
    		if (mCurrent) {
    			mCurrent = const_cast<Node*>(mCurrent->mNext);
        		return &mLastReturned->mContent;
    		} else {
    			return NULL;
    		}
    	}
    };

private:
    friend class NodeIterator;

    Node *fork() {
    	volatile Node *newHead = mFreeNodePool.allocate();
		volatile Node *oldHead = mHead;

    	// Acquire "lock" on head, for multiple people fork()ing at once.
    	{
    		while (oldHead == NULL ||
						!compare_and_swap(&mHead, oldHead, NULL)) {
    			oldHead = mHead;
    		}
    	}

    	{
			volatile Node *oldTail = mTail;
			while (!compare_and_swap(&mTail, oldTail, newHead)) {
				oldTail = mTail;
			}
    	}

    	mHead = newHead;
    	return const_cast<Node*>(oldHead);
    }
public:

    /**
     * Pushes value onto the queue
     *
     * @param value  Will be copied and placed onto the end of the queue.
     */
    void push(const T &value) {
        volatile Node* formerTail = NULL;
        volatile Node* formerTailNext=NULL;

        Node* newerNode = mFreeNodePool.allocate();
        newerNode->mContent = value;
        volatile Node*newNode=newerNode;
        bool successfulAddNode = false;
        while (!successfulAddNode) {
            formerTail = mTail;
            formerTailNext = formerTail->mNext;

            if (mTail == formerTail) {
                if (formerTailNext == NULL)
                    successfulAddNode = compare_and_swap(&mTail->mNext, NULL, newNode);
                else
                    compare_and_swap(&mTail, formerTail, formerTailNext);
            }
        }

        compare_and_swap(&mTail, formerTail, newNode);
    }

    /**
     * Pops the front value from the queue and places it in value.
     *
     * @param value  Will have the T at the front of the queue copied into it.
     * @returns      whether value was changed (if the queue had at least one item).
     */
    bool pop(T &value) {
        volatile Node* formerHead = NULL;

        bool headAlreadyAdvanced = false;
        while (!headAlreadyAdvanced) {

            formerHead = mHead;
            if (formerHead == NULL) {
            	// fork() function is operating on mTail.
            	continue;
            }
            volatile Node* formerHeadNext = formerHead->mNext;
            volatile Node*formerTail = mTail;

            if (formerHead == mHead) {
                if (formerHead == formerTail) {
                    if (formerHeadNext == NULL) {
                        value=T();
                        return false;
                    }
                    compare_and_swap(&mTail, formerTail, formerHeadNext);
                }

                else {
                    value = ((Node*)formerHeadNext)->mContent;//FIXME volatile cast only allowed if mContent is primitive type of pointer size or less
                    headAlreadyAdvanced = compare_and_swap(&mHead, formerHead, formerHeadNext);
                }
            }
        }
        mFreeNodePool.release((Node*)formerHead);//FIXME volatile cast only allowed if mContent is primitive type of pointer size or less
        return true;
    }

    bool probablyEmpty() {
        volatile Node* formerHead = mHead;
        if (formerHead) {
            if (formerHead->mNext) {
                // fork() function is operating on mTail.
                return false;
            }
        }
        return true;
    }
};
}

#endif //_SIRIKATA_LOCK_FREE_QUEUE_HPP_
<|endoftext|>


<commit_before>/*
Copyright (C) 2010, Oleg Efimov <efimovov@gmail.com>

See license text in LICENSE file
*/

#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <getopt.h>

#include <mysql.h>

#include <map>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <ctime>

MYSQL *conn;

std::map<std::string, std::string> cfg;

//
// Utility void
//

void do_benchmark(void (*f)(int), const char *title, int count = 0) {
    clock_t start = 0, finish = 0;
    double delta = 0;

    start = clock();
    f(count);
    finish = clock();

    delta = static_cast<double>(finish-start)/CLOCKS_PER_SEC;

    if (count > 0) {
        printf("%s %.2lfs (%ld/s)\n", title, delta,
               static_cast<long int>(static_cast<double>(count)/delta));
    } else {
        printf("%s %.2lfs\n", title, delta);
    }
}

//
// Benchmarking functions
//

/*void do_benchmark_select() {
    rows = array();

    r = mysql_query(conn, "SELECT * FROM ".cfg["test_table"].";");

    while(row = mysql_fetch_array(r))
    {
        rows[] = row;
    }
}*/

void do_benchmark_inserts(int count) {
    int i = 0;

    for (i = 0; i < count; i++) {
        mysql_query(conn, cfg["insert_query"].c_str());
    }
}

void do_benchmark_reconnect(int count) {
    int i = 0;

    for (i = 0; i < count; i++) {
        mysql_close(conn);

        conn = mysql_init(NULL);
        if (!conn) {
            exit(1);
        }

        if (!mysql_real_connect(conn,
                                cfg["host"].c_str(),
                                cfg["user"].c_str(),
                                cfg["password"].length() ? cfg["password"].c_str() : NULL,
                                cfg["database"].c_str(),
                                0, NULL, 0)) {
            printf("Error %d: %s\n", mysql_errno(conn), mysql_error(conn));
            mysql_close(conn);
            exit(1);
        }
    }
}

void do_benchmark_escape_string(int count) {
    int i = 0;
    char *escaped_string;

    for (i = 0; i < count; i++) {
        escaped_string = new char[2*cfg["string_to_escape"].length() + 1];
        mysql_real_escape_string(conn, escaped_string, cfg["string_to_escape"].c_str(), cfg["string_to_escape"].length());
        delete[] escaped_string;
    }
}

void do_benchmark_initialization(int count) {
    conn = mysql_init(NULL);

    if (!conn) {
        exit(1);
    }

    if (!mysql_real_connect(conn,
                            cfg["host"].c_str(),
                            cfg["user"].c_str(),
                            cfg["password"].length() ? cfg["password"].c_str() : NULL,
                            cfg["database"].c_str(),
                            0, NULL, 0)) {
        printf("Error %d: %s\n", mysql_errno(conn), mysql_error(conn));
        mysql_close(conn);
        exit(1);
    }

    char drop_query[1024];
    sprintf(drop_query, "DROP TABLE IF EXISTS %s;", cfg["test_table"].c_str());
    mysql_query(conn, drop_query);
    mysql_query(conn, cfg["create_table_query"].c_str());
}

int main(int argc, char *argv[]) {
    int c = 0;
    opterr = 0;

    static struct option long_options[] = {
        {"host", required_argument, NULL, 0},
        {"user", required_argument, NULL, 0},
        {"password", optional_argument, NULL, 0},
        {"database", required_argument, NULL, 0},
        {"test_table", required_argument, NULL, 0},
        {"create_table_query", required_argument, NULL, 0},
        {"escape_count", required_argument, NULL, 0},
        {"string_to_escape", required_argument, NULL, 0},
        {"reconnect_count", required_argument, NULL, 0},
        {"insert_rows_count", required_argument, NULL, 0},
        {"insert_query", required_argument, NULL, 0},
        {"delay_before_select", required_argument, NULL, 0}
    };
    int option_index = 0;

    while ( (c = getopt_long(argc, argv, "", long_options, &option_index)) != -1 ) {
        switch (c) {
            case 0:
                if (optarg) {
                    cfg[long_options[option_index].name] = optarg;
                } else {
                    cfg[long_options[option_index].name] = "";
                }
                break;
            default:
                break;
        }
    }

    char title[128];
    int count = 0;

    // Initialize connection and database
    sprintf(title, "**** Benchmark initialization time is");
    count = 0;
    do_benchmark(do_benchmark_initialization, title, count);

    // Benchmark 1: Escapes
    sprintf(title, "**** %s escapes in", cfg["escape_count"].c_str());
    count = atoi(cfg["escape_count"].c_str());
    do_benchmark(do_benchmark_escape_string, title, count);

    // Benchmark 2: Reconnects
    sprintf(title, "**** %s sync reconnects in", cfg["reconnect_count"].c_str());
    count = atoi(cfg["reconnect_count"].c_str());
    do_benchmark(do_benchmark_reconnect, title, count);

    // Benchmark 3: inserts
    sprintf(title, "**** %s sync insertions in", cfg["insert_rows_count"].c_str());
    count = atoi(cfg["insert_rows_count"].c_str());
    do_benchmark(do_benchmark_inserts, title, count);

    sleep(atoi(cfg["delay_before_select"].c_str())/1000); // _micro_seconds

    // Benchmark 3: selects
    /*sprintf(title, "**** %s rows sync selected in", cfg["insert_rows_count"].c_str());
    count = atoi(cfg["insert_rows_count"].c_str());
    do_benchmark(do_benchmark_select, title, count);*/

    mysql_close(conn);
}
<commit_msg>Make C++ benchmark faster and more similar to V8 structure<commit_after>/*
Copyright (C) 2010, Oleg Efimov <efimovov@gmail.com>

See license text in LICENSE file
*/

#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <getopt.h>

#include <mysql.h>

#include <map>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <ctime>

MYSQL *conn;

std::map<std::string, std::string> cfg;

//
// Utility void
//

void do_benchmark(void (*f)(int), const char *title, int count = 0) {
    clock_t start = 0, finish = 0;
    double delta = 0;

    start = clock();
    f(count);
    finish = clock();

    delta = static_cast<double>(finish-start)/CLOCKS_PER_SEC;

    if (count > 0) {
        printf("%s %.2lfs (%ld/s)\n", title, delta,
               static_cast<long int>(static_cast<double>(count)/delta));
    } else {
        printf("%s %.2lfs\n", title, delta);
    }
}

//
// Benchmarking functions
//

/*void do_benchmark_select() {
    rows = array();

    r = mysql_query(conn, "SELECT * FROM ".cfg["test_table"].";");

    while(row = mysql_fetch_array(r))
    {
        rows[] = row;
    }
}*/

void do_benchmark_inserts(int count) {
    int i = 0;

    for (i = 0; i < count; i++) {
        mysql_query(conn, cfg["insert_query"].c_str());
    }
}

void do_benchmark_reconnect(int count) {
    int i = 0;

    for (i = 0; i < count; i++) {
        mysql_close(conn);

        conn = mysql_init(NULL);
        if (!conn) {
            exit(1);
        }

        if (!mysql_real_connect(conn,
                                cfg["host"].c_str(),
                                cfg["user"].c_str(),
                                cfg["password"].length() ? cfg["password"].c_str() : NULL,
                                cfg["database"].c_str(),
                                0, NULL, 0)) {
            printf("Error %d: %s\n", mysql_errno(conn), mysql_error(conn));
            mysql_close(conn);
            exit(1);
        }
    }
}

void do_benchmark_escape_string(int count) {
    int i = 0;
    char *escaped_string;
    const char *string_to_escape = cfg["string_to_escape"].c_str();
    const int string_to_escape_len = cfg["string_to_escape"].length();

    for (i = 0; i < count; i++) {
        escaped_string = new char[2*string_to_escape_len + 1];
        mysql_real_escape_string(conn, escaped_string, string_to_escape, string_to_escape_len);
        delete[] escaped_string;
    }
}

void do_benchmark_initialization(int count) {
    conn = mysql_init(NULL);

    if (!conn) {
        exit(1);
    }

    if (!mysql_real_connect(conn,
                            cfg["host"].c_str(),
                            cfg["user"].c_str(),
                            cfg["password"].length() ? cfg["password"].c_str() : NULL,
                            cfg["database"].c_str(),
                            0, NULL, 0)) {
        printf("Error %d: %s\n", mysql_errno(conn), mysql_error(conn));
        mysql_close(conn);
        exit(1);
    }

    char drop_query[1024];
    sprintf(drop_query, "DROP TABLE IF EXISTS %s;", cfg["test_table"].c_str());
    mysql_query(conn, drop_query);
    mysql_query(conn, cfg["create_table_query"].c_str());
}

int main(int argc, char *argv[]) {
    int c = 0;
    opterr = 0;

    static struct option long_options[] = {
        {"host", required_argument, NULL, 0},
        {"user", required_argument, NULL, 0},
        {"password", optional_argument, NULL, 0},
        {"database", required_argument, NULL, 0},
        {"test_table", required_argument, NULL, 0},
        {"create_table_query", required_argument, NULL, 0},
        {"escape_count", required_argument, NULL, 0},
        {"string_to_escape", required_argument, NULL, 0},
        {"reconnect_count", required_argument, NULL, 0},
        {"insert_rows_count", required_argument, NULL, 0},
        {"insert_query", required_argument, NULL, 0},
        {"delay_before_select", required_argument, NULL, 0}
    };
    int option_index = 0;

    while ( (c = getopt_long(argc, argv, "", long_options, &option_index)) != -1 ) {
        switch (c) {
            case 0:
                if (optarg) {
                    cfg[long_options[option_index].name] = optarg;
                } else {
                    cfg[long_options[option_index].name] = "";
                }
                break;
            default:
                break;
        }
    }

    char title[128];
    int count = 0;

    // Initialize connection and database
    sprintf(title, "**** Benchmark initialization time is");
    count = 0;
    do_benchmark(do_benchmark_initialization, title, count);

    // Benchmark 1: Escapes
    sprintf(title, "**** %s escapes in", cfg["escape_count"].c_str());
    count = atoi(cfg["escape_count"].c_str());
    do_benchmark(do_benchmark_escape_string, title, count);

    // Benchmark 2: Reconnects
    sprintf(title, "**** %s sync reconnects in", cfg["reconnect_count"].c_str());
    count = atoi(cfg["reconnect_count"].c_str());
    do_benchmark(do_benchmark_reconnect, title, count);

    // Benchmark 3: inserts
    sprintf(title, "**** %s sync insertions in", cfg["insert_rows_count"].c_str());
    count = atoi(cfg["insert_rows_count"].c_str());
    do_benchmark(do_benchmark_inserts, title, count);

    sleep(atoi(cfg["delay_before_select"].c_str())/1000); // _micro_seconds

    // Benchmark 3: selects
    /*sprintf(title, "**** %s rows sync selected in", cfg["insert_rows_count"].c_str());
    count = atoi(cfg["insert_rows_count"].c_str());
    do_benchmark(do_benchmark_select, title, count);*/

    mysql_close(conn);
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <atomic>
#include <iostream>
#include <limits>
#include <utility>
#include <vector>

#include <getopt.h>
#include <signal.h>
#include <unistd.h>

#include <zcm/zcm-cpp.hpp>

using namespace std;

static atomic_int done {0};

static void sighandler(int signal)
{
    done++;
    if (done == 3) exit(1);
}

struct Args
{
    string infile    = "";
    string outfile   = "";
    bool   verifyOnly = false;

    bool init(int argc, char *argv[])
    {
        struct option long_opts[] = {
            { "help",                no_argument, 0, 'h' },
            { "output",        required_argument, 0, 'o' },
            { "verify-only",         no_argument, 0, 'v' },
            { 0, 0, 0, 0 }
        };

        int c;
        while ((c = getopt_long(argc, argv, "ho:v", long_opts, 0)) >= 0) {
            switch (c) {
                case 'o': outfile    = string(optarg); break;
                case 'v': verifyOnly = true;           break;
                case 'h': default: usage(); return false;
            };
        }

        if (optind != argc - 1) {
            cerr << "Please specify a logfile" << endl;
            usage();
            return false;
        }

        infile = string(argv[optind]);

        if (outfile.empty()) {
            cerr << "Must specify output file" << endl;
            return false;
        }

        return true;
    }

    void usage()
    {
        cerr << "usage: zcm-log-repair [options] [FILE]" << endl
             << "" << endl
             << "    Reads packets from an ZCM log file and re-writes that log file" << endl
             << "    ensuring that all events are stored in recv_utime order." << endl
             << "    This is generally only required if the original log was captured" << endl
             << "    using multiple zcm shards and the user requires a strict ordering" << endl
             << "    of events in the log." << endl
             << "" << endl
             << "Options:" << endl
             << "" << endl
             << "  -o, --output=filename  specify output file" << endl
             << "  -v, --verify-only      Skip writing output file, only verify that" << endl
             << "                         an already existing output file is the repaired" << endl
             << "                         version of the input." << endl
             << "  -h, --help             Shows some help text and exits." << endl
             << endl;
    }
};

struct LogRepair
{
    Args args;
    zcm::LogFile* logIn  = nullptr;
    zcm::LogFile* logOut = nullptr;
    zcm::LogFile* logVer = nullptr;

    const zcm::LogEvent*         event;
    off_t                        length;
    off_t                        offset;
    vector<pair<int64_t, off_t>> timestamps;
    size_t                       progress;

    LogRepair() { }

    ~LogRepair()
    {
        if (logIn)  {
            if (logIn->good()) logIn->close();
            delete  logIn;
        }
        if (logOut) {
            if (logOut->good()) logOut->close();
            delete logOut;
        }
        if (logVer) {
            if (logVer->good()) logVer->close();
            delete logVer;
        }
    }

    bool init(int argc, char *argv[])
    {
        if (!args.init(argc, argv))
            return false;

        logIn = new zcm::LogFile(args.infile, "r");
        if (!logIn->good()) {
            cerr << "Error: Failed to open '" << args.infile << "'" << endl;
            return false;
        }

        if (!args.verifyOnly) {
            logOut = new zcm::LogFile(args.outfile, "w");
            if (!logOut->good()) {
                cerr << "Error: Failed to create output log" << endl;
                return false;
            }
        }

        fseeko(logIn->getFilePtr(), 0, SEEK_END);
        length = ftello(logIn->getFilePtr());
        fseeko(logIn->getFilePtr(), 0, SEEK_SET);

        timestamps.reserve(1e6);

        return true;
    }

    int run()
    {
        cout << "Reading log" << endl;
        progress = 0;
        cout << progress << "%" << flush;
        while (true) {
            if (done) return 1;

            offset = ftello(logIn->getFilePtr());
            event  = logIn->readNextEvent();
            if (!event) break;

            timestamps.emplace_back(event->timestamp, offset);

            size_t p = (size_t)((100 * offset) / length);
            if (p != progress) {
                progress = p;
                cout << "\r" << progress << "%" << flush;
            }
        }
        cout << endl << "Read " << timestamps.size() << " events" << endl;

        cout << "Repairing log data" << endl;
        sort(timestamps.begin(), timestamps.end());

        if (!args.verifyOnly) {
            cout << "Writing new log" << endl;
            progress = 0;
            cout << progress << "%" << flush;
            for (size_t i = 0; i < timestamps.size(); ++i) {
                if (done) return 1;

                logOut->writeEvent(logIn->readEventAtOffset(timestamps[i].second));

                size_t p = (100 * i) / timestamps.size();
                if (p != progress) {
                    progress = p;
                    cout << "\r" << progress << "%" << flush;
                }
            }

            cout << endl << "Flushing to disk" << endl;
            logOut->close();
        }

        cout << "Verifying output" << endl;
        logVer = new zcm::LogFile(args.outfile, "r");
        if (!logVer->good()) {
            cerr << "Error: Failed to open output log for verification" << endl;
            return 1;
        }

        size_t i = 0;
        progress = 0;
        cout << progress << "%" << flush;
        while (true) {
            if (done) return 1;

            event = logVer->readNextEvent();
            if (!event) break;
            if (event->timestamp != timestamps[i++].first) {
                cerr << endl << "Error: output log timestamp mismatch" << endl;
                cerr << "Expected " << timestamps[i].first << " got "
                     << event->timestamp << " (idx " << i << ")" << endl;
                return 1;
            }

            size_t p = (100 * i) / timestamps.size();
            if (p != progress) {
                progress = p;
                cout << "\r" << progress << "%" << flush;
            }
        }
        if (i < timestamps.size()) {
            cerr << endl << "Error: output log was missing "
                 << timestamps.size() - i << " events" << endl;
        }

        return 0;
    }
};

int main(int argc, char* argv[])
{
    LogRepair lr;
    if (!lr.init(argc, argv)) return 1;

    // Register signal handlers
    signal(SIGINT, sighandler);
    signal(SIGQUIT, sighandler);
    signal(SIGTERM, sighandler);

    int ret = lr.run();

    if (ret == 0) {
        cout << endl << "Success" << endl;
    } else {
        cerr << endl << "Failure" << endl;
    }

    return ret;
}
<commit_msg>better cli<commit_after>#include <algorithm>
#include <atomic>
#include <iostream>
#include <limits>
#include <utility>
#include <vector>

#include <getopt.h>
#include <signal.h>
#include <unistd.h>

#include <zcm/zcm-cpp.hpp>

using namespace std;

static atomic_int done {0};

static void sighandler(int signal)
{
    done++;
    if (done == 3) exit(1);
}

struct Args
{
    string infile  = "";
    string outfile = "";
    bool   verify  = false;

    bool init(int argc, char *argv[])
    {
        struct option long_opts[] = {
            { "help",         no_argument, 0, 'h' },
            { "output", required_argument, 0, 'o' },
            { "verify",       no_argument, 0, 'v' },
            { 0, 0, 0, 0 }
        };

        int c;
        while ((c = getopt_long(argc, argv, "ho:v", long_opts, 0)) >= 0) {
            switch (c) {
                case 'o': outfile    = string(optarg); break;
                case 'v': verify = true;           break;
                case 'h': default: usage(); return false;
            };
        }

        if (optind != argc - 1) {
            cerr << "Please specify a logfile" << endl;
            usage();
            return false;
        }

        infile = string(argv[optind]);

        if (outfile.empty() && !verify) {
            cerr << "Must specify output file" << endl;
            return false;
        }

        return true;
    }

    void usage()
    {
        cerr << "usage: zcm-log-repair [options] [FILE]" << endl
             << "" << endl
             << "    Reads packets from an ZCM log file and re-writes that log file" << endl
             << "    ensuring that all events are stored in recv_utime order." << endl
             << "    This is generally only required if the original log was captured" << endl
             << "    using multiple zcm shards and the user requires a strict ordering" << endl
             << "    of events in the log." << endl
             << "" << endl
             << "Options:" << endl
             << "" << endl
             << "  -o, --output=filename  specify output file" << endl
             << "  -v, --verify           verify input log is monotonic in timestamp" << endl
             << "  -h, --help             Shows some help text and exits." << endl
             << endl;
    }
};

struct LogRepair
{
    Args args;
    zcm::LogFile* logIn  = nullptr;
    zcm::LogFile* logOut = nullptr;
    zcm::LogFile* logVer = nullptr;

    const zcm::LogEvent*         event;
    off_t                        length;
    off_t                        offset;
    vector<pair<int64_t, off_t>> timestamps;
    size_t                       progress;

    LogRepair() { }

    ~LogRepair()
    {
        if (logIn)  {
            if (logIn->good()) logIn->close();
            delete  logIn;
        }
        if (logOut) {
            if (logOut->good()) logOut->close();
            delete logOut;
        }
        if (logVer) {
            if (logVer->good()) logVer->close();
            delete logVer;
        }
    }

    bool init(int argc, char *argv[])
    {
        if (!args.init(argc, argv))
            return false;

        logIn = new zcm::LogFile(args.infile, "r");
        if (!logIn->good()) {
            cerr << "Error: Failed to open '" << args.infile << "'" << endl;
            return false;
        }

        if (!args.verify) {
            logOut = new zcm::LogFile(args.outfile, "w");
            if (!logOut->good()) {
                cerr << "Error: Failed to create output log" << endl;
                return false;
            }
        }

        fseeko(logIn->getFilePtr(), 0, SEEK_END);
        length = ftello(logIn->getFilePtr());
        fseeko(logIn->getFilePtr(), 0, SEEK_SET);

        timestamps.reserve(1e6);

        return true;
    }

    int run()
    {
        cout << "Reading log" << endl;
        progress = 0;
        cout << progress << "%" << flush;
        while (true) {
            if (done) return 1;

            offset = ftello(logIn->getFilePtr());
            event  = logIn->readNextEvent();
            if (!event) break;

            if (args.verify && !timestamps.empty() &&
                event->timestamp < timestamps.back().first) {
                cerr << endl << "Detected nonmonotonic timestamp at event "
                     << timestamps.size() << endl;
                return 1;
            }

            timestamps.emplace_back(event->timestamp, offset);

            size_t p = (size_t)((100 * offset) / length);
            if (p != progress) {
                progress = p;
                cout << "\r" << progress << "%" << flush;
            }
        }
        cout << endl << "Read " << timestamps.size() << " events" << endl;
        logIn->close();

        if (args.verify) return 0;

        sort(timestamps.begin(), timestamps.end());

        cout << "Writing new log" << endl;
        progress = 0;
        cout << progress << "%" << flush;
        for (size_t i = 0; i < timestamps.size(); ++i) {
            if (done) return 1;

            logOut->writeEvent(logIn->readEventAtOffset(timestamps[i].second));

            size_t p = (100 * i) / timestamps.size();
            if (p != progress) {
                progress = p;
                cout << "\r" << progress << "%" << flush;
            }
        }

        cout << endl << "Flushing to disk" << endl;
        logOut->close();

        cout << "Verifying output" << endl;
        logVer = new zcm::LogFile(args.verify ? args.infile : args.outfile, "r");
        if (!logVer->good()) {
            cerr << "Error: Failed to open log for verification" << endl;
            return 1;
        }

        size_t i = 0;
        progress = 0;
        cout << progress << "%" << flush;
        while (true) {
            if (done) return 1;

            event = logVer->readNextEvent();
            if (!event) break;
            if (event->timestamp != timestamps[i++].first) {
                cerr << endl << "Error: output log timestamp mismatch" << endl;
                cerr << "Expected " << timestamps[i].first << " got "
                     << event->timestamp << " (idx " << i << ")" << endl;
                return 1;
            }

            size_t p = (100 * i) / timestamps.size();
            if (p != progress) {
                progress = p;
                cout << "\r" << progress << "%" << flush;
            }
        }
        if (i < timestamps.size()) {
            cerr << endl << "Error: output log was missing "
                 << timestamps.size() - i << " events" << endl;
        }
        logVer->close();

        return 0;
    }
};

int main(int argc, char* argv[])
{
    LogRepair lr;
    if (!lr.init(argc, argv)) return 1;

    // Register signal handlers
    signal(SIGINT, sighandler);
    signal(SIGQUIT, sighandler);
    signal(SIGTERM, sighandler);

    int ret = lr.run();

    if (ret == 0) {
        cout << endl << "Success" << endl;
    } else {
        cerr << endl << "Failure" << endl;
    }

    return ret;
}
<|endoftext|>


<commit_before>/*************************************************
* BigInt Assignment Operators Source File        *
* (C) 1999-2007 Jack Lloyd                       *
*************************************************/

#include <botan/bigint.h>
#include <botan/mp_core.h>
#include <botan/bit_ops.h>
#include <algorithm>

namespace Botan {

/*************************************************
* Addition Operator                              *
*************************************************/
BigInt& BigInt::operator+=(const BigInt& y)
   {
   const u32bit x_sw = sig_words(), y_sw = y.sig_words();

   const u32bit reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if((sign() == y.sign()))
      bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw);
   else
      {
      s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

      if(relative_size < 0)
         {
         SecureVector<word> z(reg_size - 1);
         bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw);
         copy_mem(reg.begin(), z.begin(), z.size());
         set_sign(y.sign());
         }
      else if(relative_size == 0)
         {
         reg.clear();
         set_sign(Positive);
         }
      else if(relative_size > 0)
         bigint_sub2(get_reg(), x_sw, y.data(), y_sw);
      }

   return (*this);
   }

/*************************************************
* Subtraction Operator                           *
*************************************************/
BigInt& BigInt::operator-=(const BigInt& y)
   {
   const u32bit x_sw = sig_words(), y_sw = y.sig_words();

   s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

   const u32bit reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if(relative_size < 0)
      {
      if(sign() == y.sign())
         {
         SecureVector<word> z(reg_size - 1);
         bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw);
         copy_mem(reg.begin(), z.begin(), z.size());
         }
      else
         bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw);

      set_sign(y.reverse_sign());
      }
   else if(relative_size == 0)
      {
      if(sign() == y.sign())
         {
         reg.clear();
         set_sign(Positive);
         }
      else
         bigint_shl1(get_reg(), x_sw, 0, 1);
      }
   else if(relative_size > 0)
      {
      if(sign() == y.sign())
         bigint_sub2(get_reg(), x_sw, y.data(), y_sw);
      else
         bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw);
      }

   return (*this);
   }

/*************************************************
* Multiplication Operator                        *
*************************************************/
BigInt& BigInt::operator*=(const BigInt& y)
   {
   const u32bit x_sw = sig_words(), y_sw = y.sig_words();
   set_sign((sign() == y.sign()) ? Positive : Negative);

   if(x_sw == 0 || y_sw == 0)
      {
      reg.clear();
      set_sign(Positive);
      }
   else if(x_sw == 1 && y_sw)
      {
      grow_to(y_sw + 2);
      bigint_linmul3(get_reg(), y.data(), y_sw, word_at(0));
      }
   else if(y_sw == 1 && x_sw)
      {
      grow_to(x_sw + 2);
      bigint_linmul2(get_reg(), x_sw, y.word_at(0));
      }
   else
      {
      grow_to(size() + y.size());

      SecureVector<word> z(data(), x_sw);
      SecureVector<word> workspace(size());

      bigint_mul(get_reg(), size(), workspace,
                 z, z.size(), x_sw,
                 y.data(), y.size(), y_sw);
      }

   return (*this);
   }

/*************************************************
* Division Operator                              *
*************************************************/
BigInt& BigInt::operator/=(const BigInt& y)
   {
   if(y.sig_words() == 1 && power_of_2(y.word_at(0)))
      (*this) >>= (y.bits() - 1);
   else
      (*this) = (*this) / y;
   return (*this);
   }

/*************************************************
* Modulo Operator                                *
*************************************************/
BigInt& BigInt::operator%=(const BigInt& mod)
   {
   return (*this = (*this) % mod);
   }

/*************************************************
* Modulo Operator                                *
*************************************************/
word BigInt::operator%=(word mod)
   {
   if(mod == 0)
      throw BigInt::DivideByZero();
   if(power_of_2(mod))
       {
       word result = (word_at(0) & (mod - 1));
       clear();
       grow_to(2);
       reg[0] = result;
       return result;
       }

   word remainder = 0;

   for(u32bit j = sig_words(); j > 0; --j)
      remainder = bigint_modop(remainder, word_at(j-1), mod);
   clear();
   grow_to(2);

   if(remainder && sign() == BigInt::Negative)
      reg[0] = mod - remainder;
   else
      reg[0] = remainder;

   set_sign(BigInt::Positive);

   return word_at(0);
   }

/*************************************************
* Left Shift Operator                            *
*************************************************/
BigInt& BigInt::operator<<=(u32bit shift)
   {
   if(shift)
      {
      const u32bit shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS,
                   words = sig_words();

      grow_to(words + shift_words + (shift_bits ? 1 : 0));
      bigint_shl1(get_reg(), words, shift_words, shift_bits);
      }

   return (*this);
   }

/*************************************************
* Right Shift Operator                           *
*************************************************/
BigInt& BigInt::operator>>=(u32bit shift)
   {
   if(shift)
      {
      const u32bit shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS;

      bigint_shr1(get_reg(), sig_words(), shift_words, shift_bits);

      if(is_zero())
         set_sign(Positive);
      }

   return (*this);
   }

}
<commit_msg>Remove unneeded parens<commit_after>/*************************************************
* BigInt Assignment Operators Source File        *
* (C) 1999-2007 Jack Lloyd                       *
*************************************************/

#include <botan/bigint.h>
#include <botan/mp_core.h>
#include <botan/bit_ops.h>
#include <algorithm>

namespace Botan {

/*************************************************
* Addition Operator                              *
*************************************************/
BigInt& BigInt::operator+=(const BigInt& y)
   {
   const u32bit x_sw = sig_words(), y_sw = y.sig_words();

   const u32bit reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if(sign() == y.sign())
      bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw);
   else
      {
      s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

      if(relative_size < 0)
         {
         SecureVector<word> z(reg_size - 1);
         bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw);
         copy_mem(reg.begin(), z.begin(), z.size());
         set_sign(y.sign());
         }
      else if(relative_size == 0)
         {
         reg.clear();
         set_sign(Positive);
         }
      else if(relative_size > 0)
         bigint_sub2(get_reg(), x_sw, y.data(), y_sw);
      }

   return (*this);
   }

/*************************************************
* Subtraction Operator                           *
*************************************************/
BigInt& BigInt::operator-=(const BigInt& y)
   {
   const u32bit x_sw = sig_words(), y_sw = y.sig_words();

   s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw);

   const u32bit reg_size = std::max(x_sw, y_sw) + 1;
   grow_to(reg_size);

   if(relative_size < 0)
      {
      if(sign() == y.sign())
         {
         SecureVector<word> z(reg_size - 1);
         bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw);
         copy_mem(reg.begin(), z.begin(), z.size());
         }
      else
         bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw);

      set_sign(y.reverse_sign());
      }
   else if(relative_size == 0)
      {
      if(sign() == y.sign())
         {
         reg.clear();
         set_sign(Positive);
         }
      else
         bigint_shl1(get_reg(), x_sw, 0, 1);
      }
   else if(relative_size > 0)
      {
      if(sign() == y.sign())
         bigint_sub2(get_reg(), x_sw, y.data(), y_sw);
      else
         bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw);
      }

   return (*this);
   }

/*************************************************
* Multiplication Operator                        *
*************************************************/
BigInt& BigInt::operator*=(const BigInt& y)
   {
   const u32bit x_sw = sig_words(), y_sw = y.sig_words();
   set_sign((sign() == y.sign()) ? Positive : Negative);

   if(x_sw == 0 || y_sw == 0)
      {
      reg.clear();
      set_sign(Positive);
      }
   else if(x_sw == 1 && y_sw)
      {
      grow_to(y_sw + 2);
      bigint_linmul3(get_reg(), y.data(), y_sw, word_at(0));
      }
   else if(y_sw == 1 && x_sw)
      {
      grow_to(x_sw + 2);
      bigint_linmul2(get_reg(), x_sw, y.word_at(0));
      }
   else
      {
      grow_to(size() + y.size());

      SecureVector<word> z(data(), x_sw);
      SecureVector<word> workspace(size());

      bigint_mul(get_reg(), size(), workspace,
                 z, z.size(), x_sw,
                 y.data(), y.size(), y_sw);
      }

   return (*this);
   }

/*************************************************
* Division Operator                              *
*************************************************/
BigInt& BigInt::operator/=(const BigInt& y)
   {
   if(y.sig_words() == 1 && power_of_2(y.word_at(0)))
      (*this) >>= (y.bits() - 1);
   else
      (*this) = (*this) / y;
   return (*this);
   }

/*************************************************
* Modulo Operator                                *
*************************************************/
BigInt& BigInt::operator%=(const BigInt& mod)
   {
   return (*this = (*this) % mod);
   }

/*************************************************
* Modulo Operator                                *
*************************************************/
word BigInt::operator%=(word mod)
   {
   if(mod == 0)
      throw BigInt::DivideByZero();
   if(power_of_2(mod))
       {
       word result = (word_at(0) & (mod - 1));
       clear();
       grow_to(2);
       reg[0] = result;
       return result;
       }

   word remainder = 0;

   for(u32bit j = sig_words(); j > 0; --j)
      remainder = bigint_modop(remainder, word_at(j-1), mod);
   clear();
   grow_to(2);

   if(remainder && sign() == BigInt::Negative)
      reg[0] = mod - remainder;
   else
      reg[0] = remainder;

   set_sign(BigInt::Positive);

   return word_at(0);
   }

/*************************************************
* Left Shift Operator                            *
*************************************************/
BigInt& BigInt::operator<<=(u32bit shift)
   {
   if(shift)
      {
      const u32bit shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS,
                   words = sig_words();

      grow_to(words + shift_words + (shift_bits ? 1 : 0));
      bigint_shl1(get_reg(), words, shift_words, shift_bits);
      }

   return (*this);
   }

/*************************************************
* Right Shift Operator                           *
*************************************************/
BigInt& BigInt::operator>>=(u32bit shift)
   {
   if(shift)
      {
      const u32bit shift_words = shift / MP_WORD_BITS,
                   shift_bits  = shift % MP_WORD_BITS;

      bigint_shr1(get_reg(), sig_words(), shift_words, shift_bits);

      if(is_zero())
         set_sign(Positive);
      }

   return (*this);
   }

}
<|endoftext|>


<commit_before>/*Copyright 2010 George Karagoulis

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.*/

#include <QString>

template <typename T> GUtil::DataObjects::Collection<T>::Collection()
    :CollectionBase<T>(){}

template <typename T> GUtil::DataObjects::Collection<T>::Collection(
        const DataObjects::Collection<T> &o)
            :CollectionBase<T>(o){}

template <typename T> GUtil::DataObjects::Collection<T>::Collection(const QList<T> &o)
    :CollectionBase<T>(o){}

template <typename T> GUtil::DataObjects::Collection<T>::~Collection(){}

template <typename T> T &GUtil::DataObjects::Collection<T>::Add(const T &value)
{
    return CollectionBase<T>::add_protected(value);
}

template <typename T> T &GUtil::DataObjects::Collection<T>::Insert(const T &value, int index)
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::insert_protected(value, index);
}

template <typename T> const T &GUtil::DataObjects::Collection<T>::At(int index) const
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::at_protected(index);
}

template <typename T> T &GUtil::DataObjects::Collection<T>::At(int index)
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::at_protected(index);
}

template <typename T> T &GUtil::DataObjects::Collection<T>::operator [](int index)
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::at_protected(index);
}

template <typename T> const T &GUtil::DataObjects::Collection<T>::operator [](int index) const
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::at_protected(index);
}

template <typename T> void GUtil::DataObjects::Collection<T>::Remove(int index)
        throw(Core::IndexOutOfRangeException)
{
    CollectionBase<T>::remove_protected(index);
}

template <typename T> void GUtil::DataObjects::Collection<T>::RemoveOne(const T &i)
{
    CollectionBase<T>::removeOne_protected(i);
}

template <typename T> void GUtil::DataObjects::Collection<T>::RemoveAll(const T &i)
{
    CollectionBase<T>::removeAll_protected(i);
}

template <typename T> void GUtil::DataObjects::Collection<T>::Clear()
{
    CollectionBase<T>::clear_protected();
}

template <typename T> bool GUtil::DataObjects::Collection<T>::Contains(const T &o) const
{
    return CollectionBase<T>::contains_protected(o);
}

template <typename T> int GUtil::DataObjects::Collection<T>::IndexOf(const T &o, int from) const
{
    return CollectionBase<T>::indexOf_protected(o, from);
}

template <typename T> bool GUtil::DataObjects::Collection<T>::Equals(
        const DataObjects::Collection<T> &rhs) const
{
    return CollectionBase<T>::Equals(rhs);
}

template <typename T> int GUtil::DataObjects::Collection<T>::Count() const
{
    return CollectionBase<T>::count_protected();
}

template <typename T> int GUtil::DataObjects::Collection<T>::Size() const
{
   return CollectionBase<T>::size_protected();
}

template <typename T> GUtil::DataObjects::Collection<T> &GUtil::DataObjects::Collection<T>::CloneTo(
        DataObjects::Collection<T> &o) const
{
    return (GUtil::DataObjects::Collection<T> &)CollectionBase<T>::CloneTo(o);
}

template <typename T> GUtil::DataObjects::CollectionBase<T>::CollectionBase(
        const DataObjects::CollectionBase<T> &o)
            :IReadOnlyObject(o)
{
    o.CloneTo(*this);
}

template <typename T> GUtil::DataObjects::CollectionBase<T>::CollectionBase(const QList<T> &o)
    :_collection(o)
{}

template <typename T> T &GUtil::DataObjects::CollectionBase<T>::add_protected(const T &value)
{
    FailIfReadOnly();

    validate_new_item(value);

    int index = _collection.size();
    _collection.append(value);

    on_add(index);

    return _collection[index];
}

template <typename T> T &GUtil::DataObjects::CollectionBase<T>::insert_protected(const T &value, int index)
        throw(Core::IndexOutOfRangeException)
{
    FailIfReadOnly();
    _validate_index(index);

    validate_new_item(value);

    _collection.insert(index, value);

    on_add(index);

    return _collection[index];
}

template <typename T> const T &GUtil::DataObjects::CollectionBase<T>::at_protected(int index) const
        throw(Core::IndexOutOfRangeException)
{
    _validate_index(index);

    return _collection[index];
}

template <typename T> T &GUtil::DataObjects::CollectionBase<T>::at_protected(int index)
        throw(Core::IndexOutOfRangeException)
{
    _validate_index(index);

    return _collection[index];
}

template <typename T> void GUtil::DataObjects::CollectionBase<T>::remove_protected(int index)
        throw(Core::IndexOutOfRangeException)
{
    FailIfReadOnly();

    on_remove(index);

    _collection.removeAt(index);
}

template <typename T> void GUtil::DataObjects::CollectionBase<T>::removeOne_protected(const T &i)
{
    int ind = indexOf_protected(i);
    if(ind >= 0)
        remove_protected(ind);
}

template <typename T> void GUtil::DataObjects::CollectionBase<T>::removeAll_protected(const T &i)
{
    int ind = 0;
    while((ind = indexOf_protected(i, ind)) >= 0)
        remove_protected(ind);
}

template <typename T> void GUtil::DataObjects::CollectionBase<T>::clear_protected()
{
    while(count_protected() > 0)
        remove_protected(0);
}

template <typename T> bool GUtil::DataObjects::CollectionBase<T>::contains_protected(const T &o) const
{
    return indexOf_protected(o) != -1;
}

template <typename T> int GUtil::DataObjects::CollectionBase<T>::indexOf_protected(const T &o, int from) const
{
    int ret = -1;

    for(int i = from; i < size_protected(); i++)
    {
        if(compare_equality(at_protected(i), o))
        {
            ret = i;
            break;
        }
    }

    return ret;
}

template<typename T> void GUtil::DataObjects::CollectionBase<T>::_validate_index(int index) const
{
    if(index < 0 || index >= count_protected())
        THROW_NEW_GUTIL_EXCEPTION2(Core::IndexOutOfRangeException,
                                  QString("Collection only has %1 items in it, and you tried to "
                                          "index the item at %2")
                                  .arg(count_protected()).arg(index).toStdString());
}

template <typename T> bool GUtil::DataObjects::CollectionBase<T>::Equals(
        const GUtil::DataObjects::CollectionBase<T> &rhs) const
{
    bool ret = _collection == rhs._collection;

    for(int i = 0; ret && i < count_protected(); i++)
        if(!compare_equality(at_protected(i), rhs.at_protected(i)))
            ret = false;

    return ret;
}

template <typename T> int GUtil::DataObjects::CollectionBase<T>::count_protected() const
{
    return _collection.length();
}

template <typename T> int GUtil::DataObjects::CollectionBase<T>::size_protected() const
{
   return _collection.length();
}

template <typename T> GUtil::DataObjects::CollectionBase<T> &
GUtil::DataObjects::CollectionBase<T>::CloneTo(
    GUtil::DataObjects::CollectionBase<T> &o) const
{
    o.FailIfReadOnly();

    o._collection = _collection;
    return o;
}
<commit_msg>Inserting should have different index validation, which should include the index at the end of the array<commit_after>/*Copyright 2010 George Karagoulis

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.*/

#include <QString>

template <typename T> GUtil::DataObjects::Collection<T>::Collection()
    :CollectionBase<T>(){}

template <typename T> GUtil::DataObjects::Collection<T>::Collection(
        const DataObjects::Collection<T> &o)
            :CollectionBase<T>(o){}

template <typename T> GUtil::DataObjects::Collection<T>::Collection(const QList<T> &o)
    :CollectionBase<T>(o){}

template <typename T> GUtil::DataObjects::Collection<T>::~Collection(){}

template <typename T> T &GUtil::DataObjects::Collection<T>::Add(const T &value)
{
    return CollectionBase<T>::add_protected(value);
}

template <typename T> T &GUtil::DataObjects::Collection<T>::Insert(const T &value, int index)
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::insert_protected(value, index);
}

template <typename T> const T &GUtil::DataObjects::Collection<T>::At(int index) const
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::at_protected(index);
}

template <typename T> T &GUtil::DataObjects::Collection<T>::At(int index)
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::at_protected(index);
}

template <typename T> T &GUtil::DataObjects::Collection<T>::operator [](int index)
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::at_protected(index);
}

template <typename T> const T &GUtil::DataObjects::Collection<T>::operator [](int index) const
        throw(Core::IndexOutOfRangeException)
{
    return CollectionBase<T>::at_protected(index);
}

template <typename T> void GUtil::DataObjects::Collection<T>::Remove(int index)
        throw(Core::IndexOutOfRangeException)
{
    CollectionBase<T>::remove_protected(index);
}

template <typename T> void GUtil::DataObjects::Collection<T>::RemoveOne(const T &i)
{
    CollectionBase<T>::removeOne_protected(i);
}

template <typename T> void GUtil::DataObjects::Collection<T>::RemoveAll(const T &i)
{
    CollectionBase<T>::removeAll_protected(i);
}

template <typename T> void GUtil::DataObjects::Collection<T>::Clear()
{
    CollectionBase<T>::clear_protected();
}

template <typename T> bool GUtil::DataObjects::Collection<T>::Contains(const T &o) const
{
    return CollectionBase<T>::contains_protected(o);
}

template <typename T> int GUtil::DataObjects::Collection<T>::IndexOf(const T &o, int from) const
{
    return CollectionBase<T>::indexOf_protected(o, from);
}

template <typename T> bool GUtil::DataObjects::Collection<T>::Equals(
        const DataObjects::Collection<T> &rhs) const
{
    return CollectionBase<T>::Equals(rhs);
}

template <typename T> int GUtil::DataObjects::Collection<T>::Count() const
{
    return CollectionBase<T>::count_protected();
}

template <typename T> int GUtil::DataObjects::Collection<T>::Size() const
{
   return CollectionBase<T>::size_protected();
}

template <typename T> GUtil::DataObjects::Collection<T> &GUtil::DataObjects::Collection<T>::CloneTo(
        DataObjects::Collection<T> &o) const
{
    return (GUtil::DataObjects::Collection<T> &)CollectionBase<T>::CloneTo(o);
}

template <typename T> GUtil::DataObjects::CollectionBase<T>::CollectionBase(
        const DataObjects::CollectionBase<T> &o)
            :IReadOnlyObject(o)
{
    o.CloneTo(*this);
}

template <typename T> GUtil::DataObjects::CollectionBase<T>::CollectionBase(const QList<T> &o)
    :_collection(o)
{}

template <typename T> T &GUtil::DataObjects::CollectionBase<T>::add_protected(const T &value)
{
    FailIfReadOnly();

    validate_new_item(value);

    int index = _collection.size();
    _collection.append(value);

    on_add(index);

    return _collection[index];
}

template <typename T> T &GUtil::DataObjects::CollectionBase<T>::insert_protected(const T &value, int index)
        throw(Core::IndexOutOfRangeException)
{
    FailIfReadOnly();
    if(index < 0 || index > this->count_protected())
        throw Core::IndexOutOfRangeException(QString("Cannot insert at index %1")
                                             .arg(index).toStdString());

    validate_new_item(value);

    _collection.insert(index, value);

    on_add(index);

    return _collection[index];
}

template <typename T> const T &GUtil::DataObjects::CollectionBase<T>::at_protected(int index) const
        throw(Core::IndexOutOfRangeException)
{
    _validate_index(index);

    return _collection[index];
}

template <typename T> T &GUtil::DataObjects::CollectionBase<T>::at_protected(int index)
        throw(Core::IndexOutOfRangeException)
{
    _validate_index(index);

    return _collection[index];
}

template <typename T> void GUtil::DataObjects::CollectionBase<T>::remove_protected(int index)
        throw(Core::IndexOutOfRangeException)
{
    FailIfReadOnly();

    on_remove(index);

    _collection.removeAt(index);
}

template <typename T> void GUtil::DataObjects::CollectionBase<T>::removeOne_protected(const T &i)
{
    int ind = indexOf_protected(i);
    if(ind >= 0)
        remove_protected(ind);
}

template <typename T> void GUtil::DataObjects::CollectionBase<T>::removeAll_protected(const T &i)
{
    int ind = 0;
    while((ind = indexOf_protected(i, ind)) >= 0)
        remove_protected(ind);
}

template <typename T> void GUtil::DataObjects::CollectionBase<T>::clear_protected()
{
    while(count_protected() > 0)
        remove_protected(0);
}

template <typename T> bool GUtil::DataObjects::CollectionBase<T>::contains_protected(const T &o) const
{
    return indexOf_protected(o) != -1;
}

template <typename T> int GUtil::DataObjects::CollectionBase<T>::indexOf_protected(const T &o, int from) const
{
    int ret = -1;

    for(int i = from; i < size_protected(); i++)
    {
        if(compare_equality(at_protected(i), o))
        {
            ret = i;
            break;
        }
    }

    return ret;
}

template<typename T> void GUtil::DataObjects::CollectionBase<T>::_validate_index(int index) const
{
    if(index < 0 || index >= count_protected())
        THROW_NEW_GUTIL_EXCEPTION2(Core::IndexOutOfRangeException,
                                  QString("Collection only has %1 items in it, and you tried to "
                                          "index the item at %2")
                                  .arg(count_protected()).arg(index).toStdString());
}

template <typename T> bool GUtil::DataObjects::CollectionBase<T>::Equals(
        const GUtil::DataObjects::CollectionBase<T> &rhs) const
{
    bool ret = _collection == rhs._collection;

    for(int i = 0; ret && i < count_protected(); i++)
        if(!compare_equality(at_protected(i), rhs.at_protected(i)))
            ret = false;

    return ret;
}

template <typename T> int GUtil::DataObjects::CollectionBase<T>::count_protected() const
{
    return _collection.length();
}

template <typename T> int GUtil::DataObjects::CollectionBase<T>::size_protected() const
{
   return _collection.length();
}

template <typename T> GUtil::DataObjects::CollectionBase<T> &
GUtil::DataObjects::CollectionBase<T>::CloneTo(
    GUtil::DataObjects::CollectionBase<T> &o) const
{
    o.FailIfReadOnly();

    o._collection = _collection;
    return o;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "bytes.hh"
#include "timestamp.hh"
#include "gc_clock.hh"
#include <cstdint>

template<typename T>
static inline
void set_field(bytes& v, unsigned offset, T val) {
    reinterpret_cast<net::packed<T>*>(v.begin() + offset)->raw = net::hton(val);
}

template<typename T>
static inline
T get_field(const bytes_view& v, unsigned offset) {
    return net::ntoh(*reinterpret_cast<const net::packed<T>*>(v.begin() + offset));
}

class atomic_cell_or_collection;

/*
 * Represents atomic cell layout. Works on serialized form.
 *
 * Layout:
 *
 *  <live>  := <int8_t:flags><int64_t:timestamp><int32_t:ttl>?<value>
 *  <dead>  := <int8_t:    0><int64_t:timestamp><int32_t:ttl>
 */
class atomic_cell final {
private:
    static constexpr int8_t DEAD_FLAGS = 0;
    static constexpr int8_t LIVE_FLAG = 0x01;
    static constexpr int8_t TTL_FLAG  = 0x02; // When present, TTL field is present. Set only for live cells
    static constexpr unsigned flags_size = 1;
    static constexpr unsigned timestamp_offset = flags_size;
    static constexpr unsigned timestamp_size = 8;
    static constexpr unsigned ttl_offset = timestamp_offset + timestamp_size;
    static constexpr unsigned ttl_size = 4;
public:
    class view;
    class one;
private:
    static bool is_live(const bytes_view& cell) {
        return cell[0] != DEAD_FLAGS;
    }
    static bool is_live_and_has_ttl(const bytes_view& cell) {
        return cell[0] & TTL_FLAG;
    }
    static bool is_dead(const bytes_view& cell) {
        return cell[0] == DEAD_FLAGS;
    }
    // Can be called on live and dead cells
    static api::timestamp_type timestamp(const bytes_view& cell) {
        return get_field<api::timestamp_type>(cell, timestamp_offset);
    }
    // Can be called on live cells only
    static bytes_view value(bytes_view cell) {
        auto ttl_field_size = bool(cell[0] & TTL_FLAG) * ttl_size;
        auto value_offset = flags_size + timestamp_size + ttl_field_size;
        cell.remove_prefix(value_offset);
        return cell;
    }
    // Can be called on live and dead cells. For dead cells, the result is never empty.
    static ttl_opt ttl(const bytes_view& cell) {
        auto flags = cell[0];
        if (flags == DEAD_FLAGS || (flags & TTL_FLAG)) {
            auto ttl = get_field<int32_t>(cell, ttl_offset);
            return {gc_clock::time_point(gc_clock::duration(ttl))};
        }
        return {};
    }
    static bytes make_dead(api::timestamp_type timestamp, gc_clock::time_point ttl) {
        bytes b(bytes::initialized_later(), flags_size + timestamp_size + ttl_size);
        b[0] = DEAD_FLAGS;
        set_field(b, timestamp_offset, timestamp);
        set_field(b, ttl_offset, ttl.time_since_epoch().count());
        return b;
    }
    static bytes make_live(api::timestamp_type timestamp, ttl_opt ttl, bytes_view value) {
        auto value_offset = flags_size + timestamp_size + bool(ttl) * ttl_size;
        bytes b(bytes::initialized_later(), value_offset + value.size());
        b[0] = (ttl ? TTL_FLAG : 0) | LIVE_FLAG;
        set_field(b, timestamp_offset, timestamp);
        if (ttl) {
            set_field(b, ttl_offset, ttl->time_since_epoch().count());
        }
        std::copy_n(value.begin(), value.size(), b.begin() + value_offset);
        return b;
    }
    friend class one;
    friend class view;
};

class atomic_cell::view final {
    bytes_view _data;
private:
    view(bytes_view data) : _data(data) {}
public:
    static view from_bytes(bytes_view data) { return view(data); }
    bool is_live() const {
        return atomic_cell::is_live(_data);
    }
    bool is_live_and_has_ttl() const {
        return atomic_cell::is_live_and_has_ttl(_data);
    }
    bool is_dead(const bytes_view& cell) const {
        return atomic_cell::is_dead(_data);
    }
    // Can be called on live and dead cells
    api::timestamp_type timestamp() const {
        return atomic_cell::timestamp(_data);
    }
    // Can be called on live cells only
    bytes_view value() const {
        return atomic_cell::value(_data);
    }
    // Can be called on live and dead cells. For dead cells, the result is never empty.
    ttl_opt ttl() const {
        return atomic_cell::ttl(_data);
    }
    bytes_view serialize() const {
        return _data;
    }
    friend class atomic_cell::one;
};

class atomic_cell::one final {
    bytes _data;
private:
    one(bytes b) : _data(std::move(b)) {}
public:
    one(const one&) = default;
    one(one&&) = default;
    one& operator=(const one&) = default;
    one& operator=(one&&) = default;
    static one from_bytes(bytes b) {
        return one(std::move(b));
    }
    one(atomic_cell::view other) : _data(other._data.begin(), other._data.end()) {}
    bool is_live() const {
        return atomic_cell::is_live(_data);
    }
    bool is_live_and_has_ttl() const {
        return atomic_cell::is_live_and_has_ttl(_data);
    }
    bool is_dead(const bytes_view& cell) const {
        return atomic_cell::is_dead(_data);
    }
    // Can be called on live and dead cells
    api::timestamp_type timestamp() const {
        return atomic_cell::timestamp(_data);
    }
    // Can be called on live cells only
    bytes_view value() const {
        return atomic_cell::value(_data);
    }
    // Can be called on live and dead cells. For dead cells, the result is never empty.
    ttl_opt ttl() const {
        return atomic_cell::ttl(_data);
    }
    operator atomic_cell::view() const {
        return atomic_cell::view(_data);
    }
    static one make_dead(api::timestamp_type timestamp, gc_clock::time_point ttl) {
        return atomic_cell::make_dead(timestamp, ttl);
    }
    static one make_live(api::timestamp_type timestamp, ttl_opt ttl, bytes_view value) {
        return atomic_cell::make_live(timestamp, ttl, value);
    }
    friend class atomic_cell_or_collection;
};

// A variant type that can hold either an atomic_cell, or a serialized collection.
// Which type is stored is determinied by the schema.
class atomic_cell_or_collection final {
    bytes _data;
private:
    atomic_cell_or_collection(bytes&& data) : _data(std::move(data)) {}
public:
    atomic_cell_or_collection(atomic_cell::one ac) : _data(std::move(ac._data)) {}
    static atomic_cell_or_collection from_atomic_cell(atomic_cell::one data) { return { std::move(data._data) }; }
    atomic_cell::view as_atomic_cell() const { return atomic_cell::view::from_bytes(_data); }
    // FIXME: insert collection variant here
};

<commit_msg>atomic_cell: add collection support<commit_after>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "bytes.hh"
#include "timestamp.hh"
#include "gc_clock.hh"
#include <cstdint>

template<typename T>
static inline
void set_field(bytes& v, unsigned offset, T val) {
    reinterpret_cast<net::packed<T>*>(v.begin() + offset)->raw = net::hton(val);
}

template<typename T>
static inline
T get_field(const bytes_view& v, unsigned offset) {
    return net::ntoh(*reinterpret_cast<const net::packed<T>*>(v.begin() + offset));
}

class atomic_cell_or_collection;

/*
 * Represents atomic cell layout. Works on serialized form.
 *
 * Layout:
 *
 *  <live>  := <int8_t:flags><int64_t:timestamp><int32_t:ttl>?<value>
 *  <dead>  := <int8_t:    0><int64_t:timestamp><int32_t:ttl>
 */
class atomic_cell final {
private:
    static constexpr int8_t DEAD_FLAGS = 0;
    static constexpr int8_t LIVE_FLAG = 0x01;
    static constexpr int8_t TTL_FLAG  = 0x02; // When present, TTL field is present. Set only for live cells
    static constexpr unsigned flags_size = 1;
    static constexpr unsigned timestamp_offset = flags_size;
    static constexpr unsigned timestamp_size = 8;
    static constexpr unsigned ttl_offset = timestamp_offset + timestamp_size;
    static constexpr unsigned ttl_size = 4;
public:
    class view;
    class one;
private:
    static bool is_live(const bytes_view& cell) {
        return cell[0] != DEAD_FLAGS;
    }
    static bool is_live_and_has_ttl(const bytes_view& cell) {
        return cell[0] & TTL_FLAG;
    }
    static bool is_dead(const bytes_view& cell) {
        return cell[0] == DEAD_FLAGS;
    }
    // Can be called on live and dead cells
    static api::timestamp_type timestamp(const bytes_view& cell) {
        return get_field<api::timestamp_type>(cell, timestamp_offset);
    }
    // Can be called on live cells only
    static bytes_view value(bytes_view cell) {
        auto ttl_field_size = bool(cell[0] & TTL_FLAG) * ttl_size;
        auto value_offset = flags_size + timestamp_size + ttl_field_size;
        cell.remove_prefix(value_offset);
        return cell;
    }
    // Can be called on live and dead cells. For dead cells, the result is never empty.
    static ttl_opt ttl(const bytes_view& cell) {
        auto flags = cell[0];
        if (flags == DEAD_FLAGS || (flags & TTL_FLAG)) {
            auto ttl = get_field<int32_t>(cell, ttl_offset);
            return {gc_clock::time_point(gc_clock::duration(ttl))};
        }
        return {};
    }
    static bytes make_dead(api::timestamp_type timestamp, gc_clock::time_point ttl) {
        bytes b(bytes::initialized_later(), flags_size + timestamp_size + ttl_size);
        b[0] = DEAD_FLAGS;
        set_field(b, timestamp_offset, timestamp);
        set_field(b, ttl_offset, ttl.time_since_epoch().count());
        return b;
    }
    static bytes make_live(api::timestamp_type timestamp, ttl_opt ttl, bytes_view value) {
        auto value_offset = flags_size + timestamp_size + bool(ttl) * ttl_size;
        bytes b(bytes::initialized_later(), value_offset + value.size());
        b[0] = (ttl ? TTL_FLAG : 0) | LIVE_FLAG;
        set_field(b, timestamp_offset, timestamp);
        if (ttl) {
            set_field(b, ttl_offset, ttl->time_since_epoch().count());
        }
        std::copy_n(value.begin(), value.size(), b.begin() + value_offset);
        return b;
    }
    friend class one;
    friend class view;
};

class atomic_cell::view final {
    bytes_view _data;
private:
    view(bytes_view data) : _data(data) {}
public:
    static view from_bytes(bytes_view data) { return view(data); }
    bool is_live() const {
        return atomic_cell::is_live(_data);
    }
    bool is_live_and_has_ttl() const {
        return atomic_cell::is_live_and_has_ttl(_data);
    }
    bool is_dead(const bytes_view& cell) const {
        return atomic_cell::is_dead(_data);
    }
    // Can be called on live and dead cells
    api::timestamp_type timestamp() const {
        return atomic_cell::timestamp(_data);
    }
    // Can be called on live cells only
    bytes_view value() const {
        return atomic_cell::value(_data);
    }
    // Can be called on live and dead cells. For dead cells, the result is never empty.
    ttl_opt ttl() const {
        return atomic_cell::ttl(_data);
    }
    bytes_view serialize() const {
        return _data;
    }
    friend class atomic_cell::one;
};

class atomic_cell::one final {
    bytes _data;
private:
    one(bytes b) : _data(std::move(b)) {}
public:
    one(const one&) = default;
    one(one&&) = default;
    one& operator=(const one&) = default;
    one& operator=(one&&) = default;
    static one from_bytes(bytes b) {
        return one(std::move(b));
    }
    one(atomic_cell::view other) : _data(other._data.begin(), other._data.end()) {}
    bool is_live() const {
        return atomic_cell::is_live(_data);
    }
    bool is_live_and_has_ttl() const {
        return atomic_cell::is_live_and_has_ttl(_data);
    }
    bool is_dead(const bytes_view& cell) const {
        return atomic_cell::is_dead(_data);
    }
    // Can be called on live and dead cells
    api::timestamp_type timestamp() const {
        return atomic_cell::timestamp(_data);
    }
    // Can be called on live cells only
    bytes_view value() const {
        return atomic_cell::value(_data);
    }
    // Can be called on live and dead cells. For dead cells, the result is never empty.
    ttl_opt ttl() const {
        return atomic_cell::ttl(_data);
    }
    operator atomic_cell::view() const {
        return atomic_cell::view(_data);
    }
    static one make_dead(api::timestamp_type timestamp, gc_clock::time_point ttl) {
        return atomic_cell::make_dead(timestamp, ttl);
    }
    static one make_live(api::timestamp_type timestamp, ttl_opt ttl, bytes_view value) {
        return atomic_cell::make_live(timestamp, ttl, value);
    }
    friend class atomic_cell_or_collection;
};

// Represents a mutation of a collection.  Actual format is determined by collection type,
// and is:
//   set:  list of atomic_cell
//   map:  list of pair<atomic_cell, bytes> (for key/value)
//   list: tbd, probably ugly
class collection_mutation {
public:
    struct view {
        bytes_view data;
    };
    struct one {
        bytes data;
        operator view() const { return { data }; }
    };
};

// A variant type that can hold either an atomic_cell, or a serialized collection.
// Which type is stored is determinied by the schema.
class atomic_cell_or_collection final {
    bytes _data;
private:
    atomic_cell_or_collection(bytes&& data) : _data(std::move(data)) {}
public:
    atomic_cell_or_collection(atomic_cell::one ac) : _data(std::move(ac._data)) {}
    static atomic_cell_or_collection from_atomic_cell(atomic_cell::one data) { return { std::move(data._data) }; }
    atomic_cell::view as_atomic_cell() const { return atomic_cell::view::from_bytes(_data); }
    atomic_cell_or_collection(collection_mutation::one cm) : _data(std::move(cm.data)) {}
    static atomic_cell_or_collection from_collection_mutation(collection_mutation::one data) {
        return std::move(data.data);
    }
    collection_mutation::view as_collection_mutation() const {
        return collection_mutation::view{_data};
    }
};

<|endoftext|>