<commit_before>/*
 * Copyright (C) 2009 Google Inc. All rights reserved.
 * Copyright (C) 2013 Apple Inc. 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 Google Inc. 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.
 */

#include "config.h"
#include "modules/webdatabase/SQLTransactionCoordinator.h"

#include "modules/webdatabase/DatabaseBackend.h"
#include "modules/webdatabase/SQLTransactionBackend.h"
#include "weborigin/DatabaseIdentifier.h"
#include "weborigin/SecurityOrigin.h"
#include "wtf/Deque.h"
#include "wtf/HashMap.h"
#include "wtf/HashSet.h"
#include "wtf/RefPtr.h"

namespace WebCore {

static String getDatabaseIdentifier(SQLTransactionBackend* transaction)
{
    DatabaseBackend* database = transaction->database();
    ASSERT(database);
    return createDatabaseIdentifierFromSecurityOrigin(database->securityOrigin());
}

SQLTransactionCoordinator::SQLTransactionCoordinator()
    : m_isShuttingDown(false)
{
}

void SQLTransactionCoordinator::processPendingTransactions(CoordinationInfo& info)
{
    if (info.activeWriteTransaction || info.pendingTransactions.isEmpty())
        return;

    RefPtr<SQLTransactionBackend> firstPendingTransaction = info.pendingTransactions.first();
    if (firstPendingTransaction->isReadOnly()) {
        do {
            firstPendingTransaction = info.pendingTransactions.takeFirst();
            info.activeReadTransactions.add(firstPendingTransaction);
            firstPendingTransaction->lockAcquired();
        } while (!info.pendingTransactions.isEmpty() && info.pendingTransactions.first()->isReadOnly());
    } else if (info.activeReadTransactions.isEmpty()) {
        info.pendingTransactions.removeFirst();
        info.activeWriteTransaction = firstPendingTransaction;
        firstPendingTransaction->lockAcquired();
    }
}

void SQLTransactionCoordinator::acquireLock(SQLTransactionBackend* transaction)
{
    ASSERT(!m_isShuttingDown);

    String dbIdentifier = getDatabaseIdentifier(transaction);

    CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier);
    if (coordinationInfoIterator == m_coordinationInfoMap.end()) {
        // No pending transactions for this DB
        coordinationInfoIterator = m_coordinationInfoMap.add(dbIdentifier, CoordinationInfo()).iterator;
    }

    CoordinationInfo& info = coordinationInfoIterator->value;
    info.pendingTransactions.append(transaction);
    processPendingTransactions(info);
}

void SQLTransactionCoordinator::releaseLock(SQLTransactionBackend* transaction)
{
    if (m_isShuttingDown)
        return;

    String dbIdentifier = getDatabaseIdentifier(transaction);

    CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier);
    ASSERT(coordinationInfoIterator != m_coordinationInfoMap.end());
    CoordinationInfo& info = coordinationInfoIterator->value;

    if (transaction->isReadOnly()) {
        ASSERT(info.activeReadTransactions.contains(transaction));
        info.activeReadTransactions.remove(transaction);
    } else {
        ASSERT(info.activeWriteTransaction == transaction);
        info.activeWriteTransaction = 0;
    }

    processPendingTransactions(info);
}

void SQLTransactionCoordinator::shutdown()
{
    // Prevent releaseLock() from accessing / changing the coordinationInfo
    // while we're shutting down.
    m_isShuttingDown = true;

    // Notify all transactions in progress that the database thread is shutting down
    for (CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.begin();
         coordinationInfoIterator != m_coordinationInfoMap.end(); ++coordinationInfoIterator) {
        CoordinationInfo& info = coordinationInfoIterator->value;

        // Clean up transactions that have reached "lockAcquired":
        // Transaction phase 4 cleanup. See comment on "What happens if a
        // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
        if (info.activeWriteTransaction)
            info.activeWriteTransaction->notifyDatabaseThreadIsShuttingDown();
        for (HashSet<RefPtr<SQLTransactionBackend> >::iterator activeReadTransactionsIterator =
                     info.activeReadTransactions.begin();
             activeReadTransactionsIterator != info.activeReadTransactions.end();
             ++activeReadTransactionsIterator) {
            (*activeReadTransactionsIterator)->notifyDatabaseThreadIsShuttingDown();
        }

        // Clean up transactions that have NOT reached "lockAcquired":
        // Transaction phase 3 cleanup. See comment on "What happens if a
        // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
        while (!info.pendingTransactions.isEmpty()) {
            RefPtr<SQLTransactionBackend> transaction = info.pendingTransactions.first();
            transaction->notifyDatabaseThreadIsShuttingDown();
        }
    }

    // Clean up all pending transactions for all databases
    m_coordinationInfoMap.clear();
}

} // namespace WebCore
<commit_msg>Revert one line of of r144760 to undo the following part of it...<commit_after>/*
 * Copyright (C) 2009 Google Inc. All rights reserved.
 * Copyright (C) 2013 Apple Inc. 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 Google Inc. 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.
 */

#include "config.h"
#include "modules/webdatabase/SQLTransactionCoordinator.h"

#include "modules/webdatabase/DatabaseBackend.h"
#include "modules/webdatabase/SQLTransactionBackend.h"
#include "wtf/Deque.h"
#include "wtf/HashMap.h"
#include "wtf/HashSet.h"
#include "wtf/RefPtr.h"

namespace WebCore {

static String getDatabaseIdentifier(SQLTransactionBackend* transaction)
{
    DatabaseBackend* database = transaction->database();
    ASSERT(database);
    return database->stringIdentifier();
}

SQLTransactionCoordinator::SQLTransactionCoordinator()
    : m_isShuttingDown(false)
{
}

void SQLTransactionCoordinator::processPendingTransactions(CoordinationInfo& info)
{
    if (info.activeWriteTransaction || info.pendingTransactions.isEmpty())
        return;

    RefPtr<SQLTransactionBackend> firstPendingTransaction = info.pendingTransactions.first();
    if (firstPendingTransaction->isReadOnly()) {
        do {
            firstPendingTransaction = info.pendingTransactions.takeFirst();
            info.activeReadTransactions.add(firstPendingTransaction);
            firstPendingTransaction->lockAcquired();
        } while (!info.pendingTransactions.isEmpty() && info.pendingTransactions.first()->isReadOnly());
    } else if (info.activeReadTransactions.isEmpty()) {
        info.pendingTransactions.removeFirst();
        info.activeWriteTransaction = firstPendingTransaction;
        firstPendingTransaction->lockAcquired();
    }
}

void SQLTransactionCoordinator::acquireLock(SQLTransactionBackend* transaction)
{
    ASSERT(!m_isShuttingDown);

    String dbIdentifier = getDatabaseIdentifier(transaction);

    CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier);
    if (coordinationInfoIterator == m_coordinationInfoMap.end()) {
        // No pending transactions for this DB
        coordinationInfoIterator = m_coordinationInfoMap.add(dbIdentifier, CoordinationInfo()).iterator;
    }

    CoordinationInfo& info = coordinationInfoIterator->value;
    info.pendingTransactions.append(transaction);
    processPendingTransactions(info);
}

void SQLTransactionCoordinator::releaseLock(SQLTransactionBackend* transaction)
{
    if (m_isShuttingDown)
        return;

    String dbIdentifier = getDatabaseIdentifier(transaction);

    CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier);
    ASSERT(coordinationInfoIterator != m_coordinationInfoMap.end());
    CoordinationInfo& info = coordinationInfoIterator->value;

    if (transaction->isReadOnly()) {
        ASSERT(info.activeReadTransactions.contains(transaction));
        info.activeReadTransactions.remove(transaction);
    } else {
        ASSERT(info.activeWriteTransaction == transaction);
        info.activeWriteTransaction = 0;
    }

    processPendingTransactions(info);
}

void SQLTransactionCoordinator::shutdown()
{
    // Prevent releaseLock() from accessing / changing the coordinationInfo
    // while we're shutting down.
    m_isShuttingDown = true;

    // Notify all transactions in progress that the database thread is shutting down
    for (CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.begin();
         coordinationInfoIterator != m_coordinationInfoMap.end(); ++coordinationInfoIterator) {
        CoordinationInfo& info = coordinationInfoIterator->value;

        // Clean up transactions that have reached "lockAcquired":
        // Transaction phase 4 cleanup. See comment on "What happens if a
        // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
        if (info.activeWriteTransaction)
            info.activeWriteTransaction->notifyDatabaseThreadIsShuttingDown();
        for (HashSet<RefPtr<SQLTransactionBackend> >::iterator activeReadTransactionsIterator =
                     info.activeReadTransactions.begin();
             activeReadTransactionsIterator != info.activeReadTransactions.end();
             ++activeReadTransactionsIterator) {
            (*activeReadTransactionsIterator)->notifyDatabaseThreadIsShuttingDown();
        }

        // Clean up transactions that have NOT reached "lockAcquired":
        // Transaction phase 3 cleanup. See comment on "What happens if a
        // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
        while (!info.pendingTransactions.isEmpty()) {
            RefPtr<SQLTransactionBackend> transaction = info.pendingTransactions.first();
            transaction->notifyDatabaseThreadIsShuttingDown();
        }
    }

    // Clean up all pending transactions for all databases
    m_coordinationInfoMap.clear();
}

} // namespace WebCore
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/
#ifndef __TIGHTDB_QUERY_HPP
#define __TIGHTDB_QUERY_HPP

#include <string>
#include <algorithm>
#include <vector>
#include <stdio.h>
#include <limits.h>
#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
    #include "win32/pthread/pthread.h"
#else
    #include <pthread.h>
#endif

namespace tightdb {

// Pre-declarations
class ParentNode;
class Table;
class TableView;

const size_t MAX_THREADS = 128;

class Query {
public:
    Query();
    Query(const Query& copy); // FIXME: Try to remove this
    ~Query();

    // Conditions: int and bool
    Query& equal(size_t column_ndx, int64_t value);
    Query& equal(size_t column_ndx, bool value);
    Query& not_equal(size_t column_ndx, int64_t value);
    Query& greater(size_t column_ndx, int64_t value);
    Query& greater_equal(size_t column_ndx, int64_t value);
    Query& less(size_t column_ndx, int64_t value);
    Query& less_equal(size_t column_ndx, int64_t value);
    Query& between(size_t column_ndx, int64_t from, int64_t to);

    // Conditions: strings
    Query& equal(size_t column_ndx, const char* value, bool caseSensitive=true);
    Query& begins_with(size_t column_ndx, const char* value, bool caseSensitive=true);
    Query& ends_with(size_t column_ndx, const char* value, bool caseSensitive=true);
    Query& contains(size_t column_ndx, const char* value, bool caseSensitive=true);
    Query& not_equal(size_t column_ndx, const char* value, bool caseSensitive=true);

    // Grouping
    void group();
    void end_group();
    void subtable(size_t column);
    void parent();
    void Or();

    // Searching
    size_t find_next(Table& table, size_t lastmatch=-1);
    TableView find_all(Table& table, size_t start=0, size_t end=size_t(-1), size_t limit=size_t(-1));
    void find_all(Table& table, TableView& tv, size_t start=0, size_t end=size_t(-1), size_t limit=size_t(-1));

    // Aggregates
    int64_t sum(const Table& table, size_t column, size_t* resultcount = NULL, size_t start = 0, size_t end = size_t(-1), size_t limit = size_t(-1)) const;
    int64_t maximum(const Table& table, size_t column, size_t* resultcount=NULL, size_t start = 0, size_t end = size_t(-1), size_t limit = size_t(-1)) const;
    int64_t minimum(const Table& table, size_t column, size_t* resultcount=NULL, size_t start = 0, size_t end = size_t(-1), size_t limit = size_t(-1)) const;
    double average(const Table& table, size_t column_ndx, size_t* resultcount = NULL, size_t start = 0, size_t end = size_t(-1), size_t limit = size_t(-1)) const;
    size_t count(const Table& table, size_t start = 0, size_t end = size_t(-1), size_t limit = size_t(-1)) const;

    // Deletion
    size_t remove(Table& table, size_t start = 0, size_t end = size_t(-1), size_t limit = size_t(-1)) const;

    // Multi-threading
    void FindAllMulti(Table& table, TableView& tv, size_t start = 0, size_t end = size_t(-1));
    int SetThreads(unsigned int threadcount);

    std::string Verify();

    std::string error_code;

protected:
    friend class XQueryAccessorInt;
    friend class XQueryAccessorString;

    void Init(const Table& table) const;
    size_t FindInternal(const Table& table, size_t start = 0, size_t end = size_t(-1)) const;
    void UpdatePointers(ParentNode* p, ParentNode** newnode);
    static bool comp(const std::pair<size_t, size_t>& a, const std::pair<size_t, size_t>& b);
    static void* query_thread(void* arg);

    struct thread_state {
        pthread_mutex_t result_mutex;
        pthread_cond_t completed_cond;
        pthread_mutex_t completed_mutex;
        pthread_mutex_t jobs_mutex;
        pthread_cond_t jobs_cond;
        size_t next_job;
        size_t end_job;
        size_t done_job;
        size_t count;
        ParentNode *node;
        Table *table;
        std::vector<size_t> results;
        std::vector<std::pair<size_t, size_t> > chunks;
    } ts;
    pthread_t threads[MAX_THREADS];

    mutable std::vector<ParentNode*> first;
    std::vector<ParentNode**> update;
    std::vector<ParentNode**> update_override;
    std::vector<ParentNode**> subtables;

private:
    size_t m_threadcount;
};

}

#endif // __TIGHTDB_QUERY_HPP
<commit_msg>Minor style fixes in query.hpp<commit_after>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/
#ifndef __TIGHTDB_QUERY_HPP
#define __TIGHTDB_QUERY_HPP

#include <string>
#include <algorithm>
#include <vector>
#include <stdio.h>
#include <limits.h>
#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
    #include "win32/pthread/pthread.h"
#else
    #include <pthread.h>
#endif

namespace tightdb {

// Pre-declarations
class ParentNode;
class Table;
class TableView;

const size_t MAX_THREADS = 128;

class Query {
public:
    Query();
    Query(const Query& copy); // FIXME: Try to remove this
    ~Query();

    // Conditions: int and bool
    Query& equal(size_t column_ndx, int64_t value);
    Query& equal(size_t column_ndx, bool value);
    Query& not_equal(size_t column_ndx, int64_t value);
    Query& greater(size_t column_ndx, int64_t value);
    Query& greater_equal(size_t column_ndx, int64_t value);
    Query& less(size_t column_ndx, int64_t value);
    Query& less_equal(size_t column_ndx, int64_t value);
    Query& between(size_t column_ndx, int64_t from, int64_t to);

    // Conditions: strings
    Query& equal(size_t column_ndx, const char* value, bool caseSensitive=true);
    Query& begins_with(size_t column_ndx, const char* value, bool caseSensitive=true);
    Query& ends_with(size_t column_ndx, const char* value, bool caseSensitive=true);
    Query& contains(size_t column_ndx, const char* value, bool caseSensitive=true);
    Query& not_equal(size_t column_ndx, const char* value, bool caseSensitive=true);

    // Grouping
    void group();
    void end_group();
    void subtable(size_t column);
    void parent();
    void Or();

    // Searching
    size_t    find_next(Table& table, size_t lastmatch=-1);
    TableView find_all(Table& table, size_t start=0, size_t end=size_t(-1), size_t limit=size_t(-1));
    void      find_all(Table& table, TableView& tv, size_t start=0, size_t end=size_t(-1), size_t limit=size_t(-1));

    // Aggregates
    int64_t sum(const Table& table, size_t column, size_t* resultcount=NULL, size_t start=0, size_t end = size_t(-1), size_t limit=size_t(-1)) const;
    int64_t maximum(const Table& table, size_t column, size_t* resultcount=NULL, size_t start=0, size_t end = size_t(-1), size_t limit=size_t(-1)) const;
    int64_t minimum(const Table& table, size_t column, size_t* resultcount=NULL, size_t start=0, size_t end = size_t(-1), size_t limit=size_t(-1)) const;
    double  average(const Table& table, size_t column_ndx, size_t* resultcount=NULL, size_t start=0, size_t end=size_t(-1), size_t limit=size_t(-1)) const;
    size_t  count(const Table& table, size_t start=0, size_t end=size_t(-1), size_t limit=size_t(-1)) const;

    // Deletion
    size_t  remove(Table& table, size_t start=0, size_t end=size_t(-1), size_t limit=size_t(-1)) const;

    // Multi-threading
    void FindAllMulti(Table& table, TableView& tv, size_t start=0, size_t end=size_t(-1));
    int  SetThreads(unsigned int threadcount);

    std::string Verify();

    std::string error_code;

protected:
    friend class XQueryAccessorInt;
    friend class XQueryAccessorString;

    void   Init(const Table& table) const;
    size_t FindInternal(const Table& table, size_t start=0, size_t end=size_t(-1)) const;
    void   UpdatePointers(ParentNode* p, ParentNode** newnode);

    static bool  comp(const std::pair<size_t, size_t>& a, const std::pair<size_t, size_t>& b);
    static void* query_thread(void* arg);

    struct thread_state {
        pthread_mutex_t result_mutex;
        pthread_cond_t  completed_cond;
        pthread_mutex_t completed_mutex;
        pthread_mutex_t jobs_mutex;
        pthread_cond_t  jobs_cond;
        size_t next_job;
        size_t end_job;
        size_t done_job;
        size_t count;
        ParentNode* node;
        Table* table;
        std::vector<size_t> results;
        std::vector<std::pair<size_t, size_t> > chunks;
    } ts;
    pthread_t threads[MAX_THREADS];

    mutable std::vector<ParentNode*> first;
    std::vector<ParentNode**> update;
    std::vector<ParentNode**> update_override;
    std::vector<ParentNode**> subtables;

private:
    size_t m_threadcount;
};

}

#endif // __TIGHTDB_QUERY_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008, 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QtTest/QtTest>
#include <QtCore>
#include "contextpropertyinfo.h"
#include "infobackend.h"

QMap <QString, ContextProviderInfo> providerMap;
QMap <QString, QString> typeMap;
QMap <QString, QString> docMap;

/* Mocked infobackend */

InfoBackend* currentBackend = NULL;

InfoBackend* InfoBackend::instance(const QString &backendName)
{
    if (currentBackend)
        return currentBackend;
    else {
        currentBackend = new InfoBackend();
        return currentBackend;
    }
}

QString InfoBackend::typeForKey(QString key) const
{
     if (typeMap.contains(key))
        return typeMap.value(key);
    else
        return QString();
}

QString InfoBackend::docForKey(QString key) const
{
    if (docMap.contains(key))
        return docMap.value(key);
    else
        return QString();
}

bool InfoBackend::keyDeclared(QString key) const
{
    if (typeMap.contains(key))
        return true;
    else
        return false;
}

const QList<ContextProviderInfo> InfoBackend::listProviders(QString key)
{
    QList<ContextProviderInfo> lst;
    if (providerMap.contains(key))
        lst << providerMap.value(key, ContextProviderInfo("", ""));

    return lst;
}

void InfoBackend::connectNotify(const char *signal)
{
}

void InfoBackend::disconnectNotify(const char *signal)
{
}

void InfoBackend::fireKeysChanged(const QStringList& keys)
{
    emit keysChanged(keys);
}

void InfoBackend::fireKeysAdded(const QStringList& keys)
{
    emit keysAdded(keys);
}

void InfoBackend::fireKeysRemoved(const QStringList& keys)
{
    emit keysRemoved(keys);
}

void InfoBackend::fireKeyChanged(const QString& key)
{
    emit keyChanged(key);
}

/* ContextRegistryInfoUnitTest */

class ContextPropertyInfoUnitTest : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void key();
    void doc();
    void type();
    void exists();
    void declared();
    void provided();
    void providerDBusName();
    void providerDBusType();
    void plugin();
    void constructionString();
    void typeChanged();
    void providerChanged();
    void providedChanged();
    void pluginChanged();
    void dbusTypeChanged();
};

void ContextPropertyInfoUnitTest::initTestCase()
{
    providerMap.clear();

    ContextProviderInfo info1("contextkit-dbus", "system:org.freedesktop.ContextKit.contextd");
    providerMap.insert("Battery.Charging", info1);

    ContextProviderInfo info2("contextkit-dbus", "session:com.nokia.musicplayer");
    providerMap.insert("Media.NowPlaying", info2);

    typeMap.clear();
    typeMap.insert("Battery.Charging", "TRUTH");
    typeMap.insert("Media.NowPlaying", "STRING");

    docMap.clear();
    docMap.insert("Battery.Charging", "Battery.Charging doc");
    docMap.insert("Media.NowPlaying", "Media.NowPlaying doc");
}

void ContextPropertyInfoUnitTest::key()
{
    ContextPropertyInfo p("Battery.Charging");
    QCOMPARE(p.key(), QString("Battery.Charging"));
}

void ContextPropertyInfoUnitTest::doc()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.doc(), QString("Battery.Charging doc"));
    QCOMPARE(p2.doc(), QString("Media.NowPlaying doc"));
    QCOMPARE(p3.doc(), QString());
}

void ContextPropertyInfoUnitTest::type()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.type(), QString("TRUTH"));
    QCOMPARE(p2.type(), QString("STRING"));
    QCOMPARE(p3.type(), QString());
}

void ContextPropertyInfoUnitTest::exists()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.exists(), true);
    QCOMPARE(p2.exists(), true);
    QCOMPARE(p3.exists(), false);
}

void ContextPropertyInfoUnitTest::declared()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.declared(), true);
    QCOMPARE(p2.declared(), true);
    QCOMPARE(p3.declared(), false);
}

void ContextPropertyInfoUnitTest::provided()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.provided(), true);
    QCOMPARE(p2.provided(), true);
    QCOMPARE(p3.provided(), false);
}

void ContextPropertyInfoUnitTest::providerDBusName()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.providerDBusName(), QString("org.freedesktop.ContextKit.contextd"));
    QCOMPARE(p2.providerDBusName(), QString("com.nokia.musicplayer"));
    QCOMPARE(p3.providerDBusName(), QString());
}

void ContextPropertyInfoUnitTest::providerDBusType()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.providerDBusType(), QDBusConnection::SystemBus);
    QCOMPARE(p2.providerDBusType(), QDBusConnection::SessionBus);
    QCOMPARE(p3.providerDBusType(), QDBusConnection::SessionBus);
}

void ContextPropertyInfoUnitTest::plugin()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.plugin(), QString("contextkit-dbus"));
    QCOMPARE(p2.plugin(), QString("contextkit-dbus"));
    QCOMPARE(p3.plugin(), QString());
}

void ContextPropertyInfoUnitTest::constructionString()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.constructionString(), QString("system:org.freedesktop.ContextKit.contextd"));
    QCOMPARE(p2.constructionString(), QString("session:com.nokia.musicplayer"));
    QCOMPARE(p3.constructionString(), QString());
}

void ContextPropertyInfoUnitTest::typeChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(typeChanged(QString)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    spy.takeFirst();

    typeMap.insert("Battery.Charging", "INT");
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    QList<QVariant> args = spy.takeFirst();
    QCOMPARE(args.at(0).toString(), QString("INT"));
}

void ContextPropertyInfoUnitTest::providerChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(providerChanged(QString)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    spy.takeFirst();

    ContextProviderInfo info("contextkit-dbus", "system:org.freedesktop.ContextKit.robot");
    providerMap.insert("Battery.Charging", info);
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    QList<QVariant> args = spy.takeFirst();
    QCOMPARE(args.at(0).toString(), QString("org.freedesktop.ContextKit.robot"));
}

void ContextPropertyInfoUnitTest::providedChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(providedChanged(bool)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    spy.takeFirst();

    providerMap.remove("Battery.Charging");
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    QList<QVariant> args = spy.takeFirst();
    QCOMPARE(args.at(0).toBool(), false);
}

void ContextPropertyInfoUnitTest::pluginChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy1(&p, SIGNAL(pluginChanged(QString, QString)));
    QSignalSpy spy2(&p, SIGNAL(providerChanged(QString)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy1.count(), 1);
    spy1.takeFirst();
    QCOMPARE(spy2.count(), 1);
    spy2.takeFirst();

    ContextProviderInfo info("test.so", "secret:something");
    providerMap.insert("Battery.Charging", info);
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy1.count(), 1);
    QList<QVariant> args1 = spy1.takeFirst();
    QCOMPARE(args1.at(0).toString(), QString("test.so"));
    QCOMPARE(args1.at(1).toString(), QString("secret:something"));

    QCOMPARE(spy2.count(), 1);
    QList<QVariant> args2 = spy2.takeFirst();
    QCOMPARE(args2.at(0).toString(), QString(""));
}

void ContextPropertyInfoUnitTest::dbusTypeChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(providerDBusTypeChanged(QDBusConnection::BusType)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));
    QCOMPARE(spy.count(), 1);
    spy.takeFirst();

    ContextProviderInfo info("contextkit-dbus", "session:org.freedesktop.ContextKit.contextd");
    providerMap.insert("Battery.Charging", info);
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
}

#include "contextpropertyinfounittest.moc"
QTEST_MAIN(ContextPropertyInfoUnitTest);
<commit_msg>Text ::providers() in ContextPropertyInfo.<commit_after>/*
 * Copyright (C) 2008, 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include <QtTest/QtTest>
#include <QtCore>
#include "contextpropertyinfo.h"
#include "infobackend.h"

QMap <QString, ContextProviderInfo> providerMap;
QMap <QString, QString> typeMap;
QMap <QString, QString> docMap;

/* Mocked infobackend */

InfoBackend* currentBackend = NULL;

InfoBackend* InfoBackend::instance(const QString &backendName)
{
    if (currentBackend)
        return currentBackend;
    else {
        currentBackend = new InfoBackend();
        return currentBackend;
    }
}

QString InfoBackend::typeForKey(QString key) const
{
     if (typeMap.contains(key))
        return typeMap.value(key);
    else
        return QString();
}

QString InfoBackend::docForKey(QString key) const
{
    if (docMap.contains(key))
        return docMap.value(key);
    else
        return QString();
}

bool InfoBackend::keyDeclared(QString key) const
{
    if (typeMap.contains(key))
        return true;
    else
        return false;
}

const QList<ContextProviderInfo> InfoBackend::listProviders(QString key)
{
    QList<ContextProviderInfo> lst;
    if (providerMap.contains(key))
        lst << providerMap.value(key, ContextProviderInfo("", ""));

    return lst;
}

void InfoBackend::connectNotify(const char *signal)
{
}

void InfoBackend::disconnectNotify(const char *signal)
{
}

void InfoBackend::fireKeysChanged(const QStringList& keys)
{
    emit keysChanged(keys);
}

void InfoBackend::fireKeysAdded(const QStringList& keys)
{
    emit keysAdded(keys);
}

void InfoBackend::fireKeysRemoved(const QStringList& keys)
{
    emit keysRemoved(keys);
}

void InfoBackend::fireKeyChanged(const QString& key)
{
    emit keyChanged(key);
}

/* ContextRegistryInfoUnitTest */

class ContextPropertyInfoUnitTest : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void key();
    void doc();
    void type();
    void exists();
    void declared();
    void provided();
    void providers();
    void providerDBusName();
    void providerDBusType();
    void plugin();
    void constructionString();
    void typeChanged();
    void providerChanged();
    void providedChanged();
    void pluginChanged();
    void dbusTypeChanged();
};

void ContextPropertyInfoUnitTest::initTestCase()
{
    providerMap.clear();

    ContextProviderInfo info1("contextkit-dbus", "system:org.freedesktop.ContextKit.contextd");
    providerMap.insert("Battery.Charging", info1);

    ContextProviderInfo info2("contextkit-dbus", "session:com.nokia.musicplayer");
    providerMap.insert("Media.NowPlaying", info2);

    typeMap.clear();
    typeMap.insert("Battery.Charging", "TRUTH");
    typeMap.insert("Media.NowPlaying", "STRING");

    docMap.clear();
    docMap.insert("Battery.Charging", "Battery.Charging doc");
    docMap.insert("Media.NowPlaying", "Media.NowPlaying doc");
}

void ContextPropertyInfoUnitTest::key()
{
    ContextPropertyInfo p("Battery.Charging");
    QCOMPARE(p.key(), QString("Battery.Charging"));
}

void ContextPropertyInfoUnitTest::doc()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.doc(), QString("Battery.Charging doc"));
    QCOMPARE(p2.doc(), QString("Media.NowPlaying doc"));
    QCOMPARE(p3.doc(), QString());
}

void ContextPropertyInfoUnitTest::type()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.type(), QString("TRUTH"));
    QCOMPARE(p2.type(), QString("STRING"));
    QCOMPARE(p3.type(), QString());
}

void ContextPropertyInfoUnitTest::exists()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.exists(), true);
    QCOMPARE(p2.exists(), true);
    QCOMPARE(p3.exists(), false);
}

void ContextPropertyInfoUnitTest::declared()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.declared(), true);
    QCOMPARE(p2.declared(), true);
    QCOMPARE(p3.declared(), false);
}

void ContextPropertyInfoUnitTest::provided()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.provided(), true);
    QCOMPARE(p2.provided(), true);
    QCOMPARE(p3.provided(), false);
}

void ContextPropertyInfoUnitTest::providerDBusName()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.providerDBusName(), QString("org.freedesktop.ContextKit.contextd"));
    QCOMPARE(p2.providerDBusName(), QString("com.nokia.musicplayer"));
    QCOMPARE(p3.providerDBusName(), QString());
}

void ContextPropertyInfoUnitTest::providers()
{
    ContextPropertyInfo p("Battery.Charging");
    QList<ContextProviderInfo> providers = p.providers();
    QCOMPARE(providers.size(), 1);
    QCOMPARE(providers.at(0).plugin, QString("contextkit-dbus"));
    QCOMPARE(providers.at(0).constructionString, QString("system:org.freedesktop.ContextKit.contextd"));
}

void ContextPropertyInfoUnitTest::providerDBusType()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.providerDBusType(), QDBusConnection::SystemBus);
    QCOMPARE(p2.providerDBusType(), QDBusConnection::SessionBus);
    QCOMPARE(p3.providerDBusType(), QDBusConnection::SessionBus);
}

void ContextPropertyInfoUnitTest::plugin()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.plugin(), QString("contextkit-dbus"));
    QCOMPARE(p2.plugin(), QString("contextkit-dbus"));
    QCOMPARE(p3.plugin(), QString());
}

void ContextPropertyInfoUnitTest::constructionString()
{
    ContextPropertyInfo p1("Battery.Charging");
    ContextPropertyInfo p2("Media.NowPlaying");
    ContextPropertyInfo p3("Does.Not.Exist");
    QCOMPARE(p1.constructionString(), QString("system:org.freedesktop.ContextKit.contextd"));
    QCOMPARE(p2.constructionString(), QString("session:com.nokia.musicplayer"));
    QCOMPARE(p3.constructionString(), QString());
}

void ContextPropertyInfoUnitTest::typeChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(typeChanged(QString)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    spy.takeFirst();

    typeMap.insert("Battery.Charging", "INT");
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    QList<QVariant> args = spy.takeFirst();
    QCOMPARE(args.at(0).toString(), QString("INT"));
}

void ContextPropertyInfoUnitTest::providerChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(providerChanged(QString)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    spy.takeFirst();

    ContextProviderInfo info("contextkit-dbus", "system:org.freedesktop.ContextKit.robot");
    providerMap.insert("Battery.Charging", info);
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    QList<QVariant> args = spy.takeFirst();
    QCOMPARE(args.at(0).toString(), QString("org.freedesktop.ContextKit.robot"));
}

void ContextPropertyInfoUnitTest::providedChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(providedChanged(bool)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    spy.takeFirst();

    providerMap.remove("Battery.Charging");
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
    QList<QVariant> args = spy.takeFirst();
    QCOMPARE(args.at(0).toBool(), false);
}

void ContextPropertyInfoUnitTest::pluginChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy1(&p, SIGNAL(pluginChanged(QString, QString)));
    QSignalSpy spy2(&p, SIGNAL(providerChanged(QString)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy1.count(), 1);
    spy1.takeFirst();
    QCOMPARE(spy2.count(), 1);
    spy2.takeFirst();

    ContextProviderInfo info("test.so", "secret:something");
    providerMap.insert("Battery.Charging", info);
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy1.count(), 1);
    QList<QVariant> args1 = spy1.takeFirst();
    QCOMPARE(args1.at(0).toString(), QString("test.so"));
    QCOMPARE(args1.at(1).toString(), QString("secret:something"));

    QCOMPARE(spy2.count(), 1);
    QList<QVariant> args2 = spy2.takeFirst();
    QCOMPARE(args2.at(0).toString(), QString(""));
}

void ContextPropertyInfoUnitTest::dbusTypeChanged()
{
    ContextPropertyInfo p("Battery.Charging");
    QSignalSpy spy(&p, SIGNAL(providerDBusTypeChanged(QDBusConnection::BusType)));

    currentBackend->fireKeyChanged(QString("Battery.Charging"));
    QCOMPARE(spy.count(), 1);
    spy.takeFirst();

    ContextProviderInfo info("contextkit-dbus", "session:org.freedesktop.ContextKit.contextd");
    providerMap.insert("Battery.Charging", info);
    currentBackend->fireKeyChanged(QString("Battery.Charging"));

    QCOMPARE(spy.count(), 1);
}

#include "contextpropertyinfounittest.moc"
QTEST_MAIN(ContextPropertyInfoUnitTest);
<|endoftext|>


<commit_before><commit_msg>Replace `#include` line with a forward declaration.<commit_after><|endoftext|>


<commit_before>/**
 * @file raw_time.cpp
 *
 */

#include "raw_time.h"
#include <mutex>

static std::mutex formatMutex;

using namespace himan;

raw_time::raw_time(const boost::posix_time::ptime& ptime)
{
	itsDateTime = ptime;
}
raw_time::raw_time(const std::string& theDateTime, const std::string& theTimeMask)
{
	if (theTimeMask == "%Y-%m-%d %H:%M:%S")
	{
		FromSQLTime(theDateTime);
	}
	else if (theTimeMask == "%Y%m%d%H%M")
	{
		FromDatabaseTime(theDateTime);
	}
	else
	{
		std::stringstream s(theDateTime);

		{
			std::lock_guard<std::mutex> lock(formatMutex);
			s.imbue(std::locale(s.getloc(), new boost::posix_time::time_input_facet(theTimeMask.c_str())));
		}

		s >> itsDateTime;
	}

	if (Empty())
	{
		throw std::runtime_error(ClassName() + ": Unable to create time from '" + theDateTime + "' with mask '" +
		                         theTimeMask + "'");
	}
}

raw_time::raw_time(const raw_time& other) : itsDateTime(other.itsDateTime)
{
}
raw_time& raw_time::operator=(const raw_time& other)
{
	itsDateTime = other.itsDateTime;

	return *this;
}

bool raw_time::operator==(const raw_time& other) const
{
	if (this == &other)
	{
		return true;
	}

	return (itsDateTime == other.itsDateTime);
}

bool raw_time::operator!=(const raw_time& other) const
{
	return !(*this == other);
}
bool raw_time::operator<(const raw_time& other) const
{
	return itsDateTime < other.itsDateTime;
}
bool raw_time::operator>(const raw_time& other) const
{
	return itsDateTime > other.itsDateTime;
}
bool raw_time::operator>=(const raw_time& other) const
{
	return itsDateTime >= other.itsDateTime;
}
bool raw_time::operator<=(const raw_time& other) const
{
	return itsDateTime <= other.itsDateTime;
}
raw_time::operator std::string() const
{
	return ToDatabaseTime();
}
raw_time raw_time::operator+(const time_duration& adjustment) const
{
	return raw_time(itsDateTime + boost::posix_time::minutes(adjustment.Minutes()));
}
raw_time raw_time::operator-(const time_duration& adjustment) const
{
	return raw_time(itsDateTime - boost::posix_time::minutes(adjustment.Minutes()));
}
raw_time& raw_time::operator+=(const time_duration& adjustment)
{
	itsDateTime += boost::posix_time::minutes(adjustment.Minutes());
	return *this;
}
raw_time& raw_time::operator-=(const time_duration& adjustment)
{
	itsDateTime -= boost::posix_time::minutes(adjustment.Minutes());
	return *this;
}
time_duration raw_time::operator-(const raw_time& other) const
{
	return time_duration(itsDateTime - other.itsDateTime);
}

std::string raw_time::String(const std::string& theTimeMask) const
{
	if (Empty())
	{
		return "not_a_date_time";
	}

	if (theTimeMask == "%Y-%m-%d %H:%M:%S")
	{
		return ToSQLTime();
	}
	else if (theTimeMask == "%Y%m%d%H%M")
	{
		return ToDatabaseTime();
	}

	return FormatTime(theTimeMask);
}

std::string raw_time::FormatTime(const std::string& theTimeMask) const
{
	std::stringstream s;

	// https://stackoverflow.com/questions/11121454/c-why-is-my-date-parsing-not-threadsafe

	{
		std::lock_guard<std::mutex> lock(formatMutex);
		s.imbue(std::locale(s.getloc(), new boost::posix_time::time_facet(theTimeMask.c_str())));
	}

	s << itsDateTime;

	s.flush();

	return s.str();
}

void raw_time::Adjust(HPTimeResolution timeResolution, int theValue)
{
	using namespace boost;

	if (timeResolution == kHourResolution)
	{
		posix_time::hours adjustment(theValue);

		itsDateTime = itsDateTime + adjustment;
	}
	else if (timeResolution == kMinuteResolution)
	{
		posix_time::minutes adjustment(theValue);

		itsDateTime = itsDateTime + adjustment;
	}
	else if (timeResolution == kYearResolution)
	{
		boost::gregorian::years adjustment(theValue);

		itsDateTime += adjustment;

		if (String("%m%d") == "0229")
		{
			itsDateTime += gregorian::date_duration(-1);
		}
	}
	else if (timeResolution == kDayResolution)
	{
		gregorian::days adjustment(theValue);

		itsDateTime = itsDateTime + adjustment;
	}
	else
	{
		throw std::runtime_error(
		    ClassName() + ": Invalid time adjustment unit: " + std::to_string(static_cast<int>(timeResolution)) + "'");
	}
}

bool raw_time::Empty() const
{
	return (itsDateTime == boost::posix_time::not_a_date_time);
}
bool raw_time::IsLeapYear() const
{
	return boost::gregorian::gregorian_calendar::is_leap_year(itsDateTime.date().year());
}

std::ostream& raw_time::Write(std::ostream& file) const
{
	file << "<" << ClassName() << ">" << std::endl;
	file << "__itsDateTime__ " << FormatTime("%Y-%m-%d %H:%M:%S") << std::endl;

	return file;
}

std::string raw_time::ToDatabaseTime() const
{
	const auto& date = itsDateTime.date();
	const auto& time = itsDateTime.time_of_day();

	char fmt[13];
	if (snprintf(fmt, 13, "%04d%02u%02u%02u%02u", static_cast<int>(date.year()), static_cast<int>(date.month()),
	             static_cast<int>(date.day()), static_cast<int>(time.hours()), static_cast<int>(time.minutes())) < 0)
	{
		himan::Abort();
	}

	return std::string(fmt);
}

void raw_time::FromDatabaseTime(const std::string& databaseTime)
{
	const auto year = static_cast<unsigned short>(stoi(databaseTime.substr(0, 4)));
	const auto month = static_cast<unsigned short>(stoi(databaseTime.substr(4, 2)));
	const auto day = static_cast<unsigned short>(stoi(databaseTime.substr(6, 2)));
	const auto hour = static_cast<unsigned short>(stoi(databaseTime.substr(8, 2)));
	const auto minute = static_cast<unsigned short>(stoi(databaseTime.substr(10, 2)));

	using namespace boost;

	itsDateTime = posix_time::ptime(gregorian::date(year, month, day), posix_time::time_duration(hour, minute, 0, 0));
}

std::string raw_time::ToSQLTime() const
{
	const auto& date = itsDateTime.date();
	const auto& time = itsDateTime.time_of_day();

	char fmt[20];
	if (snprintf(fmt, 20, "%04d-%02u-%02u %02u:%02u:%02u", static_cast<int>(date.year()),
	             static_cast<int>(date.month()), static_cast<int>(date.day()), static_cast<int>(time.hours()),
	             static_cast<int>(time.minutes()), static_cast<int>(time.seconds())) < 0)
	{
		himan::Abort();
	}

	return std::string(fmt);
}

void raw_time::FromSQLTime(const std::string& SQLTime)
{
	itsDateTime = boost::posix_time::time_from_string(SQLTime);
}
<commit_msg>Produce stack trace on erroneus datetime formatting<commit_after>/**
 * @file raw_time.cpp
 *
 */

#include "raw_time.h"
#include <mutex>

static std::mutex formatMutex;

using namespace himan;

raw_time::raw_time(const boost::posix_time::ptime& ptime)
{
	itsDateTime = ptime;
}
raw_time::raw_time(const std::string& theDateTime, const std::string& theTimeMask)
{
	if (theTimeMask == "%Y-%m-%d %H:%M:%S")
	{
		FromSQLTime(theDateTime);
	}
	else if (theTimeMask == "%Y%m%d%H%M")
	{
		FromDatabaseTime(theDateTime);
	}
	else
	{
		std::stringstream s(theDateTime);

		{
			std::lock_guard<std::mutex> lock(formatMutex);
			s.imbue(std::locale(s.getloc(), new boost::posix_time::time_input_facet(theTimeMask.c_str())));
		}

		s >> itsDateTime;
	}

	if (Empty())
	{
		throw std::runtime_error(ClassName() + ": Unable to create time from '" + theDateTime + "' with mask '" +
		                         theTimeMask + "'");
	}
}

raw_time::raw_time(const raw_time& other) : itsDateTime(other.itsDateTime)
{
}
raw_time& raw_time::operator=(const raw_time& other)
{
	itsDateTime = other.itsDateTime;

	return *this;
}

bool raw_time::operator==(const raw_time& other) const
{
	if (this == &other)
	{
		return true;
	}

	return (itsDateTime == other.itsDateTime);
}

bool raw_time::operator!=(const raw_time& other) const
{
	return !(*this == other);
}
bool raw_time::operator<(const raw_time& other) const
{
	return itsDateTime < other.itsDateTime;
}
bool raw_time::operator>(const raw_time& other) const
{
	return itsDateTime > other.itsDateTime;
}
bool raw_time::operator>=(const raw_time& other) const
{
	return itsDateTime >= other.itsDateTime;
}
bool raw_time::operator<=(const raw_time& other) const
{
	return itsDateTime <= other.itsDateTime;
}
raw_time::operator std::string() const
{
	return ToDatabaseTime();
}
raw_time raw_time::operator+(const time_duration& adjustment) const
{
	return raw_time(itsDateTime + boost::posix_time::minutes(adjustment.Minutes()));
}
raw_time raw_time::operator-(const time_duration& adjustment) const
{
	return raw_time(itsDateTime - boost::posix_time::minutes(adjustment.Minutes()));
}
raw_time& raw_time::operator+=(const time_duration& adjustment)
{
	itsDateTime += boost::posix_time::minutes(adjustment.Minutes());
	return *this;
}
raw_time& raw_time::operator-=(const time_duration& adjustment)
{
	itsDateTime -= boost::posix_time::minutes(adjustment.Minutes());
	return *this;
}
time_duration raw_time::operator-(const raw_time& other) const
{
	return time_duration(itsDateTime - other.itsDateTime);
}

std::string raw_time::String(const std::string& theTimeMask) const
{
	if (Empty())
	{
		return "not_a_date_time";
	}

	if (theTimeMask == "%Y-%m-%d %H:%M:%S")
	{
		return ToSQLTime();
	}
	else if (theTimeMask == "%Y%m%d%H%M")
	{
		return ToDatabaseTime();
	}

	return FormatTime(theTimeMask);
}

std::string raw_time::FormatTime(const std::string& theTimeMask) const
{
	std::stringstream s;

	// https://stackoverflow.com/questions/11121454/c-why-is-my-date-parsing-not-threadsafe

	{
		std::lock_guard<std::mutex> lock(formatMutex);
		s.imbue(std::locale(s.getloc(), new boost::posix_time::time_facet(theTimeMask.c_str())));
	}

	try
	{
		s << itsDateTime;
	}
	catch (const std::out_of_range& e)
	{
		std::cerr << e.what();
		himan::Abort();
	}

	s.flush();

	return s.str();
}

void raw_time::Adjust(HPTimeResolution timeResolution, int theValue)
{
	using namespace boost;

	if (timeResolution == kHourResolution)
	{
		posix_time::hours adjustment(theValue);

		itsDateTime = itsDateTime + adjustment;
	}
	else if (timeResolution == kMinuteResolution)
	{
		posix_time::minutes adjustment(theValue);

		itsDateTime = itsDateTime + adjustment;
	}
	else if (timeResolution == kYearResolution)
	{
		boost::gregorian::years adjustment(theValue);

		itsDateTime += adjustment;

		if (String("%m%d") == "0229")
		{
			itsDateTime += gregorian::date_duration(-1);
		}
	}
	else if (timeResolution == kDayResolution)
	{
		gregorian::days adjustment(theValue);

		itsDateTime = itsDateTime + adjustment;
	}
	else
	{
		throw std::runtime_error(
		    ClassName() + ": Invalid time adjustment unit: " + std::to_string(static_cast<int>(timeResolution)) + "'");
	}
}

bool raw_time::Empty() const
{
	return (itsDateTime == boost::posix_time::not_a_date_time);
}
bool raw_time::IsLeapYear() const
{
	return boost::gregorian::gregorian_calendar::is_leap_year(itsDateTime.date().year());
}

std::ostream& raw_time::Write(std::ostream& file) const
{
	file << "<" << ClassName() << ">" << std::endl;
	file << "__itsDateTime__ " << FormatTime("%Y-%m-%d %H:%M:%S") << std::endl;

	return file;
}

std::string raw_time::ToDatabaseTime() const
{
	const auto& date = itsDateTime.date();
	const auto& time = itsDateTime.time_of_day();

	char fmt[13];
	if (snprintf(fmt, 13, "%04d%02u%02u%02u%02u", static_cast<int>(date.year()), static_cast<int>(date.month()),
	             static_cast<int>(date.day()), static_cast<int>(time.hours()), static_cast<int>(time.minutes())) < 0)
	{
		himan::Abort();
	}

	return std::string(fmt);
}

void raw_time::FromDatabaseTime(const std::string& databaseTime)
{
	const auto year = static_cast<unsigned short>(stoi(databaseTime.substr(0, 4)));
	const auto month = static_cast<unsigned short>(stoi(databaseTime.substr(4, 2)));
	const auto day = static_cast<unsigned short>(stoi(databaseTime.substr(6, 2)));
	const auto hour = static_cast<unsigned short>(stoi(databaseTime.substr(8, 2)));
	const auto minute = static_cast<unsigned short>(stoi(databaseTime.substr(10, 2)));

	using namespace boost;

	itsDateTime = posix_time::ptime(gregorian::date(year, month, day), posix_time::time_duration(hour, minute, 0, 0));
}

std::string raw_time::ToSQLTime() const
{
	const auto& date = itsDateTime.date();
	const auto& time = itsDateTime.time_of_day();

	char fmt[20];
	if (snprintf(fmt, 20, "%04d-%02u-%02u %02u:%02u:%02u", static_cast<int>(date.year()),
	             static_cast<int>(date.month()), static_cast<int>(date.day()), static_cast<int>(time.hours()),
	             static_cast<int>(time.minutes()), static_cast<int>(time.seconds())) < 0)
	{
		himan::Abort();
	}

	return std::string(fmt);
}

void raw_time::FromSQLTime(const std::string& SQLTime)
{
	itsDateTime = boost::posix_time::time_from_string(SQLTime);
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// 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 <algorithm>
#include <vector>

#include "hwy/aligned_allocator.h"
#include "hwy/base.h"
#include "hwy/print.h"

// clang-format off
#undef HWY_TARGET_INCLUDE
#define HWY_TARGET_INCLUDE "hwy/contrib/algo/find_test.cc"
#include "hwy/foreach_target.h"

#include "hwy/contrib/algo/find-inl.h"
#include "hwy/tests/test_util-inl.h"
// clang-format on

// If your project requires C++14 or later, you can ignore this and pass lambdas
// directly to FindIf, without requiring an lvalue as we do here for C++11.
#if __cplusplus < 201402L
#define HWY_GENERIC_LAMBDA 0
#else
#define HWY_GENERIC_LAMBDA 1
#endif

HWY_BEFORE_NAMESPACE();
namespace hwy {
namespace HWY_NAMESPACE {

// Returns random number in [-8, 8) - we use knowledge of the range to Find()
// values we know are not present.
template <typename T>
T Random(RandomState& rng) {
  const int32_t bits = static_cast<int32_t>(Random32(&rng)) & 1023;
  const double val = (bits - 512) / 64.0;
  // Clamp negative to zero for unsigned types.
  return static_cast<T>(HWY_MAX(hwy::LowestValue<T>(), val));
}

// In C++14, we can instead define these as generic lambdas next to where they
// are invoked.
#if !HWY_GENERIC_LAMBDA

class GreaterThan {
 public:
  GreaterThan(float val) : val_(val) {}
  template <class D, class V>
  Mask<D> operator()(D d, V v) const {
    return Gt(v, Set(d, static_cast<TFromD<D>>(val_)));
  }

 private:
  float val_;
};

#endif  // !HWY_GENERIC_LAMBDA

// Invokes Test (e.g. TestFind) with all arg combinations.
template <class Test>
struct ForeachCountAndMisalign {
  template <typename T, class D>
  HWY_NOINLINE void operator()(T /*unused*/, D d) const {
    RandomState rng;
    const size_t N = Lanes(d);
    const size_t misalignments[3] = {0, N / 4, 3 * N / 5};

    // Find() checks 8 vectors at a time, so we want to cover a fairly large
    // range without oversampling (checking every possible count).
    std::vector<size_t> counts(AdjustedReps(512));
    for (size_t& count : counts) {
      count = rng() % (16 * N + 1);
    }
    counts[0] = 0;  // ensure we test count=0.

    for (size_t count : counts) {
      for (size_t m : misalignments) {
        Test()(d, count, m, rng);
      }
    }
  }
};

struct TestFind {
  template <class D>
  void operator()(D d, size_t count, size_t misalign, RandomState& rng) {
    using T = TFromD<D>;
    // Must allocate at least one even if count is zero.
    AlignedFreeUniquePtr<T[]> storage =
        AllocateAligned<T>(HWY_MAX(1, misalign + count));
    T* in = storage.get() + misalign;
    for (size_t i = 0; i < count; ++i) {
      in[i] = Random<T>(rng);
    }

    // For each position, search for that element (which we know is there)
    for (size_t pos = 0; pos < count; ++pos) {
      const size_t actual = Find(d, in[pos], in, count);

      // We may have found an earlier occurrence of the same value; ensure the
      // value is the same, and that it is the first.
      if (!IsEqual(in[pos], in[actual])) {
        fprintf(stderr, "%s count %d, found %.15f at %d but wanted %.15f\n",
                hwy::TypeName(T(), Lanes(d)).c_str(), static_cast<int>(count),
                static_cast<double>(in[actual]), static_cast<int>(actual),
                static_cast<double>(in[pos]));
        HWY_ASSERT(false);
      }
      for (size_t i = 0; i < actual; ++i) {
        if (IsEqual(in[i], in[pos])) {
          fprintf(stderr, "%s count %d, found %f at %d but Find returned %d\n",
                  hwy::TypeName(T(), Lanes(d)).c_str(), static_cast<int>(count),
                  static_cast<double>(in[i]), static_cast<int>(i),
                  static_cast<int>(actual));
          HWY_ASSERT(false);
        }
      }
    }

    // Also search for values we know not to be present (out of range)
    HWY_ASSERT_EQ(count, Find(d, T{9}, in, count));
    HWY_ASSERT_EQ(count, Find(d, static_cast<T>(-9), in, count));
  }
};

void TestAllFind() {
  ForAllTypes(ForPartialVectors<ForeachCountAndMisalign<TestFind>>());
}

struct TestFindIf {
  template <class D>
  void operator()(D d, size_t count, size_t misalign, RandomState& rng) {
    using T = TFromD<D>;
    // Must allocate at least one even if count is zero.
    AlignedFreeUniquePtr<T[]> storage =
        AllocateAligned<T>(HWY_MAX(1, misalign + count));
    T* in = storage.get() + misalign;
    for (size_t i = 0; i < count; ++i) {
      in[i] = Random<T>(rng);
      HWY_ASSERT(in[i] < 8 && (!hwy::IsSigned<T>() || in[i] >= -8));
    }

    bool found_any = false;
    bool not_found_any = false;

    // unsigned T would be promoted to signed and compare greater than any
    // negative val, whereas Set() would just cast to an unsigned value and the
    // comparison remains unsigned, so avoid negative numbers there.
    const int min_val = IsSigned<T>() ? -9 : 0;
    // Includes out-of-range value 9 to test the not-found path.
    for (int val = min_val; val <= 9; ++val) {
#if HWY_GENERIC_LAMBDA
      const auto greater = [val](const auto d, const auto v) HWY_ATTR {
        return Gt(v, Set(d, static_cast<T>(val)));
      };
#else
      const GreaterThan greater(val);
#endif
      const size_t actual = FindIf(d, in, count, greater);
      found_any |= actual < count;
      not_found_any |= actual == count;

      // Convert returned iterator to index.
      const size_t expected = static_cast<size_t>(
          std::find_if(in, in + count, [val](T x) { return x > val; }) - in);
      if (expected != actual) {
        fprintf(stderr, "%s count %d val %d, expected %d actual %d\n",
                hwy::TypeName(T(), Lanes(d)).c_str(), static_cast<int>(count),
                val, static_cast<int>(expected), static_cast<int>(actual));
        hwy::detail::PrintArray(hwy::detail::MakeTypeInfo<T>(), "in", in, count,
                                0, count);
        HWY_ASSERT(false);
      }
    }

    // We will always not-find something due to val=9.
    HWY_ASSERT(not_found_any);
    // We'll find something unless the input is empty or {0} - because 0 > i
    // is false for all i=[0,9].
    if (count != 0 && in[0] != 0) {
      HWY_ASSERT(found_any);
    }
  }
};

void TestAllFindIf() {
  ForAllTypes(ForPartialVectors<ForeachCountAndMisalign<TestFindIf>>());
}

// NOLINTNEXTLINE(google-readability-namespace-comments)
}  // namespace HWY_NAMESPACE
}  // namespace hwy
HWY_AFTER_NAMESPACE();

#if HWY_ONCE

namespace hwy {
HWY_BEFORE_TEST(FindTest);
HWY_EXPORT_AND_TEST_P(FindTest, TestAllFind);
HWY_EXPORT_AND_TEST_P(FindTest, TestAllFindIf);
}  // namespace hwy

#endif
<commit_msg>fix warning (cast)<commit_after>// Copyright 2022 Google LLC
// SPDX-License-Identifier: Apache-2.0
//
// 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 <algorithm>
#include <vector>

#include "hwy/aligned_allocator.h"
#include "hwy/base.h"
#include "hwy/print.h"

// clang-format off
#undef HWY_TARGET_INCLUDE
#define HWY_TARGET_INCLUDE "hwy/contrib/algo/find_test.cc"
#include "hwy/foreach_target.h"

#include "hwy/contrib/algo/find-inl.h"
#include "hwy/tests/test_util-inl.h"
// clang-format on

// If your project requires C++14 or later, you can ignore this and pass lambdas
// directly to FindIf, without requiring an lvalue as we do here for C++11.
#if __cplusplus < 201402L
#define HWY_GENERIC_LAMBDA 0
#else
#define HWY_GENERIC_LAMBDA 1
#endif

HWY_BEFORE_NAMESPACE();
namespace hwy {
namespace HWY_NAMESPACE {

// Returns random number in [-8, 8) - we use knowledge of the range to Find()
// values we know are not present.
template <typename T>
T Random(RandomState& rng) {
  const int32_t bits = static_cast<int32_t>(Random32(&rng)) & 1023;
  const double val = (bits - 512) / 64.0;
  // Clamp negative to zero for unsigned types.
  return static_cast<T>(HWY_MAX(hwy::LowestValue<T>(), val));
}

// In C++14, we can instead define these as generic lambdas next to where they
// are invoked.
#if !HWY_GENERIC_LAMBDA

class GreaterThan {
 public:
  GreaterThan(float val) : val_(val) {}
  template <class D, class V>
  Mask<D> operator()(D d, V v) const {
    return Gt(v, Set(d, static_cast<TFromD<D>>(val_)));
  }

 private:
  float val_;
};

#endif  // !HWY_GENERIC_LAMBDA

// Invokes Test (e.g. TestFind) with all arg combinations.
template <class Test>
struct ForeachCountAndMisalign {
  template <typename T, class D>
  HWY_NOINLINE void operator()(T /*unused*/, D d) const {
    RandomState rng;
    const size_t N = Lanes(d);
    const size_t misalignments[3] = {0, N / 4, 3 * N / 5};

    // Find() checks 8 vectors at a time, so we want to cover a fairly large
    // range without oversampling (checking every possible count).
    std::vector<size_t> counts(AdjustedReps(512));
    for (size_t& count : counts) {
      count = rng() % (16 * N + 1);
    }
    counts[0] = 0;  // ensure we test count=0.

    for (size_t count : counts) {
      for (size_t m : misalignments) {
        Test()(d, count, m, rng);
      }
    }
  }
};

struct TestFind {
  template <class D>
  void operator()(D d, size_t count, size_t misalign, RandomState& rng) {
    using T = TFromD<D>;
    // Must allocate at least one even if count is zero.
    AlignedFreeUniquePtr<T[]> storage =
        AllocateAligned<T>(HWY_MAX(1, misalign + count));
    T* in = storage.get() + misalign;
    for (size_t i = 0; i < count; ++i) {
      in[i] = Random<T>(rng);
    }

    // For each position, search for that element (which we know is there)
    for (size_t pos = 0; pos < count; ++pos) {
      const size_t actual = Find(d, in[pos], in, count);

      // We may have found an earlier occurrence of the same value; ensure the
      // value is the same, and that it is the first.
      if (!IsEqual(in[pos], in[actual])) {
        fprintf(stderr, "%s count %d, found %.15f at %d but wanted %.15f\n",
                hwy::TypeName(T(), Lanes(d)).c_str(), static_cast<int>(count),
                static_cast<double>(in[actual]), static_cast<int>(actual),
                static_cast<double>(in[pos]));
        HWY_ASSERT(false);
      }
      for (size_t i = 0; i < actual; ++i) {
        if (IsEqual(in[i], in[pos])) {
          fprintf(stderr, "%s count %d, found %f at %d but Find returned %d\n",
                  hwy::TypeName(T(), Lanes(d)).c_str(), static_cast<int>(count),
                  static_cast<double>(in[i]), static_cast<int>(i),
                  static_cast<int>(actual));
          HWY_ASSERT(false);
        }
      }
    }

    // Also search for values we know not to be present (out of range)
    HWY_ASSERT_EQ(count, Find(d, T{9}, in, count));
    HWY_ASSERT_EQ(count, Find(d, static_cast<T>(-9), in, count));
  }
};

void TestAllFind() {
  ForAllTypes(ForPartialVectors<ForeachCountAndMisalign<TestFind>>());
}

struct TestFindIf {
  template <class D>
  void operator()(D d, size_t count, size_t misalign, RandomState& rng) {
    using T = TFromD<D>;
    // Must allocate at least one even if count is zero.
    AlignedFreeUniquePtr<T[]> storage =
        AllocateAligned<T>(HWY_MAX(1, misalign + count));
    T* in = storage.get() + misalign;
    for (size_t i = 0; i < count; ++i) {
      in[i] = Random<T>(rng);
      HWY_ASSERT(in[i] < 8 && (!hwy::IsSigned<T>() || in[i] >= -8));
    }

    bool found_any = false;
    bool not_found_any = false;

    // unsigned T would be promoted to signed and compare greater than any
    // negative val, whereas Set() would just cast to an unsigned value and the
    // comparison remains unsigned, so avoid negative numbers there.
    const int min_val = IsSigned<T>() ? -9 : 0;
    // Includes out-of-range value 9 to test the not-found path.
    for (int val = min_val; val <= 9; ++val) {
#if HWY_GENERIC_LAMBDA
      const auto greater = [val](const auto d, const auto v) HWY_ATTR {
        return Gt(v, Set(d, static_cast<T>(val)));
      };
#else
      const GreaterThan greater(val);
#endif
      const size_t actual = FindIf(d, in, count, greater);
      found_any |= actual < count;
      not_found_any |= actual == count;

      const auto pos = std::find_if(
          in, in + count, [val](T x) { return x > static_cast<T>(val); });
      // Convert returned iterator to index.
      const size_t expected = static_cast<size_t>(pos - in);
      if (expected != actual) {
        fprintf(stderr, "%s count %d val %d, expected %d actual %d\n",
                hwy::TypeName(T(), Lanes(d)).c_str(), static_cast<int>(count),
                val, static_cast<int>(expected), static_cast<int>(actual));
        hwy::detail::PrintArray(hwy::detail::MakeTypeInfo<T>(), "in", in, count,
                                0, count);
        HWY_ASSERT(false);
      }
    }

    // We will always not-find something due to val=9.
    HWY_ASSERT(not_found_any);
    // We'll find something unless the input is empty or {0} - because 0 > i
    // is false for all i=[0,9].
    if (count != 0 && in[0] != 0) {
      HWY_ASSERT(found_any);
    }
  }
};

void TestAllFindIf() {
  ForAllTypes(ForPartialVectors<ForeachCountAndMisalign<TestFindIf>>());
}

// NOLINTNEXTLINE(google-readability-namespace-comments)
}  // namespace HWY_NAMESPACE
}  // namespace hwy
HWY_AFTER_NAMESPACE();

#if HWY_ONCE

namespace hwy {
HWY_BEFORE_TEST(FindTest);
HWY_EXPORT_AND_TEST_P(FindTest, TestAllFind);
HWY_EXPORT_AND_TEST_P(FindTest, TestAllFindIf);
}  // namespace hwy

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2011, Cornell University
// 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 HyperDex 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.

// POSIX
#include <netinet/in.h>
#include <signal.h>
#include <sys/socket.h>

// Google Log
#include <glog/logging.h>

// po6
#include <po6/net/location.h>

// HyperDex
#include <hyperdex/network_constants.h>

// HyperDaemon
#include "datalayer.h"
#include "logical.h"
#include "network_worker.h"
#include "replication_manager.h"
#include "searches.h"

using hyperdex::entityid;
using hyperdex::network_msgtype;
using hyperdex::network_returncode;

hyperdaemon :: network_worker :: network_worker(datalayer* data,
                                                logical* comm,
                                                searches* ssss,
                                                replication_manager* repl)
    : m_continue(true)
    , m_data(data)
    , m_comm(comm)
    , m_ssss(ssss)
    , m_repl(repl)
{
}

hyperdaemon :: network_worker :: ~network_worker()
{
    if (m_continue)
    {
        m_continue = false;
        LOG(INFO) << "Network worker object not cleanly shutdown.";
    }
}

void
hyperdaemon :: network_worker :: run()
{
    sigset_t ss;

    if (sigfillset(&ss) < 0)
    {
        PLOG(ERROR) << "sigfillset";
        return;
    }

    if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0)
    {
        PLOG(ERROR) << "pthread_sigmask";
        return;
    }

    entityid from;
    entityid to;
    network_msgtype type;
    e::buffer msg;
    uint32_t nonce;

    while (m_continue && m_comm->recv(&from, &to, &type, &msg))
    {
        try
        {
            if (type == hyperdex::REQ_GET)
            {
                e::buffer key;
                std::vector<e::buffer> value;
                uint64_t version;
                e::unpacker up(msg.unpack());
                up >> nonce;
                up.leftovers(&key);
                network_returncode result;

                switch (m_data->get(to.get_region(), key, &value, &version))
                {
                    case hyperdisk::SUCCESS:
                        result = hyperdex::NET_SUCCESS;
                        break;
                    case hyperdisk::NOTFOUND:
                        result = hyperdex::NET_NOTFOUND;
                        break;
                    case hyperdisk::WRONGARITY:
                        result = hyperdex::NET_WRONGARITY;
                        break;
                    case hyperdisk::MISSINGDISK:
                        LOG(ERROR) << "GET caused a MISSINGDISK at the data layer.";
                        result = hyperdex::NET_SERVERERROR;
                        break;
                    case hyperdisk::HASHFULL:
                    case hyperdisk::DATAFULL:
                    case hyperdisk::SEARCHFULL:
                    case hyperdisk::SYNCFAILED:
                    case hyperdisk::DROPFAILED:
                    default:
                        LOG(ERROR) << "GET returned unacceptable error code.";
                        result = hyperdex::NET_SERVERERROR;
                        break;
                }

                msg.clear();
                msg.pack() << nonce << static_cast<uint16_t>(result) << value;
                m_comm->send(to, from, hyperdex::RESP_GET, msg);
            }
            else if (type == hyperdex::REQ_PUT)
            {
                e::buffer key;
                std::vector<e::buffer> value;
                msg.unpack() >> nonce >> key >> value;
                m_repl->client_put(from, to.get_region(), nonce, key, value);
            }
            else if (type == hyperdex::REQ_DEL)
            {
                e::buffer key;
                e::unpacker up(msg.unpack());
                up >> nonce;
                up.leftovers(&key);
                m_repl->client_del(from, to.get_region(), nonce, key);
            }
            else if (type == hyperdex::REQ_UPDATE)
            {
                e::buffer key;
                e::bitfield value_mask(0); // This will resize on unpack
                std::vector<e::buffer> value;
                msg.unpack() >> nonce >> key >> value_mask >> value;
                m_repl->client_update(from, to.get_region(), nonce, key, value_mask, value);
            }
            else if (type == hyperdex::REQ_SEARCH_START)
            {
                hyperdex::search s;
                msg.unpack() >> nonce >> s;
                m_ssss->start(from, nonce, to.get_region(), s);
            }
            else if (type == hyperdex::REQ_SEARCH_NEXT)
            {
                msg.unpack() >> nonce;
                m_ssss->next(from, nonce);
            }
            else if (type == hyperdex::REQ_SEARCH_STOP)
            {
                msg.unpack() >> nonce;
                m_ssss->stop(from, nonce);
            }
            else if (type == hyperdex::CHAIN_PUT)
            {
                e::buffer key;
                std::vector<e::buffer> value;
                uint64_t version;
                uint8_t fresh;
                msg.unpack() >> version >> fresh >> key >> value;
                m_repl->chain_put(from, to, version, fresh == 1, key, value);
            }
            else if (type == hyperdex::CHAIN_DEL)
            {
                e::buffer key;
                uint64_t version;
                msg.unpack() >> version >> key;
                m_repl->chain_del(from, to, version, key);
            }
            else if (type == hyperdex::CHAIN_PENDING)
            {
                e::buffer key;
                uint64_t version;
                msg.unpack() >> version >> key;
                m_repl->chain_pending(from, to, version, key);
            }
            else if (type == hyperdex::CHAIN_SUBSPACE)
            {
                uint64_t version;
                e::buffer key;
                std::vector<e::buffer> value;
                uint64_t nextpoint;
                msg.unpack() >> version >> key >> value >> nextpoint;
                m_repl->chain_subspace(from, to, version, key, value, nextpoint);
            }
            else if (type == hyperdex::CHAIN_ACK)
            {
                e::buffer key;
                uint64_t version;
                msg.unpack() >> version >> key;
                m_repl->chain_ack(from, to, version, key);
            }
            else if (type == hyperdex::XFER_MORE)
            {
                m_repl->region_transfer(from, to);
            }
            else if (type == hyperdex::XFER_DONE)
            {
                m_repl->region_transfer_done(from, to);
            }
            else if (type == hyperdex::XFER_DATA)
            {
                uint64_t xfer_num;
                uint8_t op;
                uint64_t version;
                e::buffer key;
                std::vector<e::buffer> value;
                msg.unpack() >> xfer_num >> op >> version >> key >> value;
                m_repl->region_transfer(from, to.subspace, xfer_num,
                                        op == 1, version, key, value);
            }
            else
            {
                LOG(INFO) << "Message of unknown type received.";
            }
        }
        catch (std::out_of_range& e)
        {
            // Unpack error
        }
    }
}

void
hyperdaemon :: network_worker :: shutdown()
{
    // TODO:  This is not the proper shutdown method.  Proper shutdown is a
    // two-stage process, and requires global coordination.
    m_continue = false;
}
<commit_msg>Trickle data when handling network messages.<commit_after>// Copyright (c) 2011, Cornell University
// 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 HyperDex 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.

// POSIX
#include <netinet/in.h>
#include <signal.h>
#include <sys/socket.h>

// Google Log
#include <glog/logging.h>

// po6
#include <po6/net/location.h>

// HyperDex
#include <hyperdex/network_constants.h>

// HyperDaemon
#include "datalayer.h"
#include "logical.h"
#include "network_worker.h"
#include "replication_manager.h"
#include "searches.h"

using hyperdex::entityid;
using hyperdex::network_msgtype;
using hyperdex::network_returncode;

hyperdaemon :: network_worker :: network_worker(datalayer* data,
                                                logical* comm,
                                                searches* ssss,
                                                replication_manager* repl)
    : m_continue(true)
    , m_data(data)
    , m_comm(comm)
    , m_ssss(ssss)
    , m_repl(repl)
{
}

hyperdaemon :: network_worker :: ~network_worker()
{
    if (m_continue)
    {
        m_continue = false;
        LOG(INFO) << "Network worker object not cleanly shutdown.";
    }
}

void
hyperdaemon :: network_worker :: run()
{
    sigset_t ss;

    if (sigfillset(&ss) < 0)
    {
        PLOG(ERROR) << "sigfillset";
        return;
    }

    if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0)
    {
        PLOG(ERROR) << "pthread_sigmask";
        return;
    }

    entityid from;
    entityid to;
    network_msgtype type;
    e::buffer msg;
    uint32_t nonce;

    while (m_continue && m_comm->recv(&from, &to, &type, &msg))
    {
        try
        {
            if (type == hyperdex::REQ_GET)
            {
                e::buffer key;
                std::vector<e::buffer> value;
                uint64_t version;
                e::unpacker up(msg.unpack());
                up >> nonce;
                up.leftovers(&key);
                network_returncode result;

                switch (m_data->get(to.get_region(), key, &value, &version))
                {
                    case hyperdisk::SUCCESS:
                        result = hyperdex::NET_SUCCESS;
                        break;
                    case hyperdisk::NOTFOUND:
                        result = hyperdex::NET_NOTFOUND;
                        break;
                    case hyperdisk::WRONGARITY:
                        result = hyperdex::NET_WRONGARITY;
                        break;
                    case hyperdisk::MISSINGDISK:
                        LOG(ERROR) << "GET caused a MISSINGDISK at the data layer.";
                        result = hyperdex::NET_SERVERERROR;
                        break;
                    case hyperdisk::HASHFULL:
                    case hyperdisk::DATAFULL:
                    case hyperdisk::SEARCHFULL:
                    case hyperdisk::SYNCFAILED:
                    case hyperdisk::DROPFAILED:
                    default:
                        LOG(ERROR) << "GET returned unacceptable error code.";
                        result = hyperdex::NET_SERVERERROR;
                        break;
                }

                msg.clear();
                msg.pack() << nonce << static_cast<uint16_t>(result) << value;
                m_comm->send(to, from, hyperdex::RESP_GET, msg);
            }
            else if (type == hyperdex::REQ_PUT)
            {
                e::buffer key;
                std::vector<e::buffer> value;
                msg.unpack() >> nonce >> key >> value;
                m_repl->client_put(from, to.get_region(), nonce, key, value);
            }
            else if (type == hyperdex::REQ_DEL)
            {
                e::buffer key;
                e::unpacker up(msg.unpack());
                up >> nonce;
                up.leftovers(&key);
                m_repl->client_del(from, to.get_region(), nonce, key);
            }
            else if (type == hyperdex::REQ_UPDATE)
            {
                e::buffer key;
                e::bitfield value_mask(0); // This will resize on unpack
                std::vector<e::buffer> value;
                msg.unpack() >> nonce >> key >> value_mask >> value;
                m_repl->client_update(from, to.get_region(), nonce, key, value_mask, value);
            }
            else if (type == hyperdex::REQ_SEARCH_START)
            {
                hyperdex::search s;
                msg.unpack() >> nonce >> s;
                m_ssss->start(from, nonce, to.get_region(), s);
            }
            else if (type == hyperdex::REQ_SEARCH_NEXT)
            {
                msg.unpack() >> nonce;
                m_ssss->next(from, nonce);
            }
            else if (type == hyperdex::REQ_SEARCH_STOP)
            {
                msg.unpack() >> nonce;
                m_ssss->stop(from, nonce);
            }
            else if (type == hyperdex::CHAIN_PUT)
            {
                e::buffer key;
                std::vector<e::buffer> value;
                uint64_t version;
                uint8_t fresh;
                msg.unpack() >> version >> fresh >> key >> value;
                m_repl->chain_put(from, to, version, fresh == 1, key, value);
            }
            else if (type == hyperdex::CHAIN_DEL)
            {
                e::buffer key;
                uint64_t version;
                msg.unpack() >> version >> key;
                m_repl->chain_del(from, to, version, key);
            }
            else if (type == hyperdex::CHAIN_PENDING)
            {
                e::buffer key;
                uint64_t version;
                msg.unpack() >> version >> key;
                m_repl->chain_pending(from, to, version, key);
            }
            else if (type == hyperdex::CHAIN_SUBSPACE)
            {
                uint64_t version;
                e::buffer key;
                std::vector<e::buffer> value;
                uint64_t nextpoint;
                msg.unpack() >> version >> key >> value >> nextpoint;
                m_repl->chain_subspace(from, to, version, key, value, nextpoint);
            }
            else if (type == hyperdex::CHAIN_ACK)
            {
                e::buffer key;
                uint64_t version;
                msg.unpack() >> version >> key;
                m_repl->chain_ack(from, to, version, key);
            }
            else if (type == hyperdex::XFER_MORE)
            {
                m_repl->region_transfer(from, to);
            }
            else if (type == hyperdex::XFER_DONE)
            {
                m_repl->region_transfer_done(from, to);
            }
            else if (type == hyperdex::XFER_DATA)
            {
                uint64_t xfer_num;
                uint8_t op;
                uint64_t version;
                e::buffer key;
                std::vector<e::buffer> value;
                msg.unpack() >> xfer_num >> op >> version >> key >> value;
                m_repl->region_transfer(from, to.subspace, xfer_num,
                                        op == 1, version, key, value);
            }
            else
            {
                LOG(INFO) << "Message of unknown type received.";
            }

            m_data->trickle(to.get_region());
        }
        catch (std::out_of_range& e)
        {
            // Unpack error
        }
    }
}

void
hyperdaemon :: network_worker :: shutdown()
{
    // TODO:  This is not the proper shutdown method.  Proper shutdown is a
    // two-stage process, and requires global coordination.
    m_continue = false;
}
<|endoftext|>