text:
/*
 * Copyright (c) 2016-2018, Intel Corporation
 *
 * 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 Intel Corporation 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 "common.h"
#include "data_corpus.h"
#include "engine_hyperscan.h"
#if defined(HS_HYBRID)
#include "engine_chimera.h"
#include "engine_pcre.h"
#endif
#include "expressions.h"
#include "sqldb.h"
#include "thread_barrier.h"
#include "timer.h"
#include "util/expression_path.h"
#include "util/string_util.h"

#include "grey.h"
#include "hs.h"
#include "ue2common.h"
#include "util/make_unique.h"

#include <algorithm>
#include <clocale>
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <map>
#include <numeric>
#include <sstream>
#include <set>
#include <thread>

#ifndef _WIN32
#include <getopt.h>
#else
#include "win_getopt.h"
#endif
#ifndef _WIN32
#include <pthread.h>
#if defined(HAVE_PTHREAD_NP_H)
#include <pthread_np.h>
#endif
#include <unistd.h>
#endif

#include <boost/core/noncopyable.hpp>
#include <boost/range/adaptor/map.hpp>

using namespace std;
using namespace ue2;
using boost::adaptors::map_keys;

// Globals common to all files.
bool echo_matches = false;
bool saveDatabases = false;
bool loadDatabases = false;
string serializePath("");
unsigned int somPrecisionMode = HS_MODE_SOM_HORIZON_LARGE;
bool forceEditDistance = false;
unsigned editDistance = 0;
bool printCompressSize = false;

// Globals local to this file.
static bool compressStream = false;

namespace /* anonymous */ {

bool display_per_scan = false;
ScanMode scan_mode = ScanMode::STREAMING;
bool useHybrid = false;
bool usePcre = false;
unsigned repeats = 20;
string exprPath("");
string corpusFile("");
string sqloutFile("");
string sigName(""); // info only
vector<unsigned int> threadCores;
Timer totalTimer;
double totalSecs = 0;

SqlDB out_db;

typedef void (*thread_func_t)(void *context);

class ThreadContext : boost::noncopyable {
public:
    ThreadContext(unsigned num_in, const Engine &db_in,
                  thread_barrier &tb_in, thread_func_t function_in,
                  vector<DataBlock> corpus_data_in)
        : num(num_in), results(repeats), engine(db_in),
          enginectx(db_in.makeContext()), corpus_data(move(corpus_data_in)),
          tb(tb_in), function(function_in) {}

    // Start the thread.
    bool start(int cpu) {
        thr = thread(function, this);

        // affine if it's asked for
        if (cpu >= 0) {
            return affine(cpu);
        }
        return true;
    }

    // Wait for the thread to exit.
    void join() {
        thr.join();
    }

    // Serialise all threads on a global barrier.
    void barrier() {
        tb.wait();
    }

    // Apply processor affinity (if available) to this thread.
    bool affine(UNUSED int cpu) {

#if defined(_WIN32)
        SYSTEM_INFO system_info;
        GetSystemInfo(&system_info);
        assert(cpu >= 0 && (DWORD)cpu < system_info.dwNumberOfProcessors);
        DWORD_PTR mask = 1 << cpu;
        DWORD_PTR rv = SetThreadAffinityMask(thr.native_handle(), mask);
        return rv != 0;
#endif

#ifdef HAVE_DECL_PTHREAD_SETAFFINITY_NP
#if defined(__FreeBSD__)
        cpuset_t cpuset;
#else
        cpu_set_t cpuset;
#endif
        CPU_ZERO(&cpuset);
        assert(cpu >= 0 && cpu < CPU_SETSIZE);

        // The 'clang' compiler complains about an unused result here, so we
        // silence it.
        (void)CPU_SET(cpu, &cpuset);

        int rv = pthread_setaffinity_np(thr.native_handle(), sizeof(cpuset),
                                        &cpuset);
        return (rv == 0);
#endif
        return false;  // not available
    }

    unsigned num;
    Timer timer;
    vector<ResultEntry> results;
    const Engine &engine;
    unique_ptr<EngineContext> enginectx;
    vector<DataBlock> corpus_data;

protected:
    thread_barrier &tb; // shared barrier for time sync
    thread_func_t function;
    thread thr;
};

/** Display usage information, with an optional error. */
static
void usage(const char *error) {
    printf("Usage: hsbench [OPTIONS...]\n\n");
    printf("Options:\n\n");
    printf("  -h              Display help and exit.\n");
    printf("  -G OVERRIDES    Overrides for the grey box.\n");
    printf("  -e PATH         Path to expression directory.\n");
    printf("  -s FILE         Signature file to use.\n");
    printf("  -z NUM          Signature ID to use.\n");
    printf("  -c FILE         File to use as corpus.\n");
    printf("  -n NUMBER       Repeat scan NUMBER times (default 20).\n");
    printf("  -N              Benchmark in block mode"
           " (default: streaming).\n");
    printf("  -V              Benchmark in vectored mode"
           " (default: streaming).\n");
#if defined(HS_HYBRID)
    printf("  -H              Benchmark using Chimera (if supported).\n");
    printf("  -P              Benchmark using PCRE (if supported).\n");
#endif
#if defined(HAVE_DECL_PTHREAD_SETAFFINITY_NP) || defined(_WIN32)
    printf("  -T CPU,CPU,...  Benchmark with threads on these CPUs.\n");
#endif
    printf("  -i DIR          Don't compile, load from files in DIR"
           " instead.\n");
    printf("  -w DIR          After compiling, save to files in DIR.\n");
    printf("  -d NUMBER       Set SOM precision mode (default: 8 (large)).\n");
    printf("  -E DISTANCE     Match all patterns within edit distance"
           " DISTANCE.\n");
    printf("\n");
    printf("  --per-scan      Display per-scan Mbit/sec results.\n");
    printf("  --echo-matches  Display all matches that occur during scan.\n");
    printf("  --sql-out FILE  Output sqlite db.\n");
    printf("  -S NAME         Signature set name (for sqlite db).\n");
    printf("\n\n");

    if (error) {
        printf("Error: %s\n", error);
    }
}

/** Wraps up a name and the set of signature IDs it refers to. */
struct BenchmarkSigs {
    BenchmarkSigs(string name_in, SignatureSet sigs_in)
        : name(move(name_in)), sigs(move(sigs_in)) {}
    string name;
    SignatureSet sigs;
};

/** Process command-line arguments. Prints usage and exits on error. */
static
void processArgs(int argc, char *argv[], vector<BenchmarkSigs> &sigSets,
                 UNUSED unique_ptr<Grey> &grey) {
    const char options[] = "-b:c:Cd:e:E:G:hHi:n:No:p:PsS:Vw:z:"
#if defined(HAVE_DECL_PTHREAD_SETAFFINITY_NP) || defined(_WIN32)
        "T:" // add the thread flag
#endif
        ;
    int in_sigfile = 0;
    int do_per_scan = 0;
    int do_compress = 0;
    int do_compress_size = 0;
    int do_echo_matches = 0;
    int do_sql_output = 0;
    int option_index = 0;
    vector<string> sigFiles;

    static struct option longopts[] = {
        {"per-scan", no_argument, &do_per_scan, 1},
        {"echo-matches", no_argument, &do_echo_matches, 1},
        {"compress-stream", no_argument, &do_compress, 1},
        {"sql-out", required_argument, &do_sql_output, 1},
        {nullptr, 0, nullptr, 0}
    };

    for (;;) {
        int c = getopt_long(argc, argv, options, longopts, &option_index);
        if (c < 0) {
            break;
        }
        switch (c) {
        case 'c':
            corpusFile.assign(optarg);
            break;
        case 'd': {
            unsigned dist;
            if (!fromString(optarg, dist)) {
                usage("Must provide an integer argument to '-d' flag");
                exit(1);
            }
            switch (dist) {
            case 2:
                somPrecisionMode = HS_MODE_SOM_HORIZON_SMALL;
                break;
            case 4:
                somPrecisionMode = HS_MODE_SOM_HORIZON_MEDIUM;
                break;
            case 8:
                somPrecisionMode = HS_MODE_SOM_HORIZON_LARGE;
                break;
            default:
                usage("SOM precision must be 2, 4 or 8");
                exit(1);
            }
            break;
        }
        case 'e':
            exprPath.assign(optarg);
            break;
        case 'E':
            if (!fromString(optarg, editDistance)) {
                usage("Couldn't parse argument to -E flag, should be"
                      " a non-negative integer.");
                exit(1);
            }
            forceEditDistance = true;
            break;
#ifndef RELEASE_BUILD
        case 'G':
            applyGreyOverrides(grey.get(), string(optarg));
            break;
#endif
        case 'h':
            usage(nullptr);
            exit(0);
            break;
        case 'H':
#if defined(HS_HYBRID)
            useHybrid = true;
#else
            usage("Hybrid matcher not enabled in this build");
            exit(1);
#endif
            break;
        case 'n':
            if (!fromString(optarg, repeats) || repeats == 0) {
                usage("Couldn't parse argument to -n flag, should be"
                      " a positive integer.");
                exit(1);
            }
            break;
        case 'P':
#if defined(HS_HYBRID)
            usePcre = true;
#else
            usage("PCRE matcher not enabled in this build");
            exit(1);
#endif
            break;
        case 's':
            in_sigfile = 2;
            break;
        case 'N':
            scan_mode = ScanMode::BLOCK;
            break;
        case 'V':
            scan_mode = ScanMode::VECTORED;
            break;
        case 'S':
            sigName.assign(optarg);
            break;
#if defined(HAVE_DECL_PTHREAD_SETAFFINITY_NP) || defined(_WIN32)
        case 'T':
            if (!strToList(optarg, threadCores)) {
                usage("Couldn't parse argument to -T flag, should be"
                      " a list of positive integers.");
                exit(1);
            }
            break;
#endif
        case 'z': {
            unsigned int sinumber;
            if (!fromString(optarg, sinumber)) {
                usage("Argument to '-z' flag must be an integer");
                exit(1);
            }
            SignatureSet sigs = {sinumber};
            sigSets.emplace_back(string("-z ") + optarg, sigs);
            break;
        }
        case 'i':
            loadDatabases = true;
            serializePath = optarg;
            break;
        case 'w':
            saveDatabases = true;
            serializePath = optarg;
            break;
        case 0:
            if (do_sql_output) {
                sqloutFile.assign(optarg);
                do_sql_output = 0;
            }
            break;
        case 1:
            if (in_sigfile) {
                sigFiles.push_back(optarg);
                in_sigfile = 2;
                break;
            }
            /* fallthrough */
        default:
            usage("Unrecognised command line argument.");
            exit(1);
        }

        if (in_sigfile) {
            in_sigfile--;
        }
    }

    if (do_echo_matches) {
        echo_matches = true;
    }
    if (do_per_scan) {
        display_per_scan = true;
    }
    if (do_compress) {
        compressStream = true;
    }
    if (do_compress_size) {
        printCompressSize = true;
    }

    if (exprPath.empty() && !sigFiles.empty()) {
        /* attempt to infer an expression directory */
        auto si = sigFiles.begin();
        exprPath = inferExpressionPath(*si);
        for (++si; si != sigFiles.end(); ++si) {
            if (exprPath != inferExpressionPath(*si)) {
                usage("Unable to infer consistent expression directory");
                exit(1);
            }
        }
    }

    // Must have a valid expression path
    if (exprPath.empty()) {
        usage("Must specify an expression path with the -e option.");
        exit(1);
    }

    // Must have valid database to scan
    if (corpusFile.empty()) {
        usage("Must specify a corpus file with the -c option.");
        exit(1);
    }

    // Cannot ask for both loading and saving
    if (loadDatabases && saveDatabases) {
        usage("You cannot both load and save databases.");
        exit(1);
    }

    // Constraints on Chimera and PCRE engines
    if (useHybrid || usePcre) {
        if (useHybrid && usePcre) {
            usage("Can't run both Chimera and PCRE.");
            exit(1);
        }
        if (scan_mode != ScanMode::BLOCK) {
            usage("Must specify block mode in Chimera or PCRE with "
                  "the -N option.");
            exit(1);
        }

        if (forceEditDistance || loadDatabases || saveDatabases) {
            usage("No extended options are supported in Chimera or PCRE.");
            exit(1);
        }
    }

    // Read in any -s signature sets.
    for (const auto &file : sigFiles) {
        SignatureSet sigs;
        loadSignatureList(file, sigs);
        sigSets.emplace_back(file, move(sigs));
    }
}

/** Start the global timer. */
static
void startTotalTimer(ThreadContext *ctx) {
    if (ctx->num != 0) {
        return; // only runs in the first thread
    }
    totalTimer.start();
}

/** Stop the global timer and calculate totals. */
static
void stopTotalTimer(ThreadContext *ctx) {
    if (ctx->num != 0) {
        return; // only runs in the first thread
    }
    totalTimer.complete();
    totalSecs = totalTimer.seconds();
}

/** Run a benchmark over a given engine and corpus in block mode. */
static
void benchBlock(void *context) {
    ThreadContext *ctx = (ThreadContext *)context;

    // Synchronization point
    ctx->barrier();

    startTotalTimer(ctx);

    for (ResultEntry &r : ctx->results) {
        ctx->timer.start();

        for (const DataBlock &block : ctx->corpus_data) {
            ctx->engine.scan(block.payload.c_str(), block.payload.size(),
                             block.id, r, *ctx->enginectx);
        }

        ctx->timer.complete();
        r.seconds = ctx->timer.seconds();
    }

    // Synchronization point
    ctx->barrier();

    // Now that all threads are finished, we can stop the clock.
    stopTotalTimer(ctx);
}

/** Structure used to represent a stream. */
struct StreamInfo {
    unsigned int stream_id = ~0U;
    unsigned int first_block_id = ~0U;
    unsigned int last_block_id = 0;
    unique_ptr<EngineStream> eng_handle;
};

static
u64a count_streams(const vector<DataBlock> &corpus_blocks) {
    set<unsigned int> streams;
    for (const DataBlock &block : corpus_blocks) {
        streams.insert(block.stream_id);
    }

    return (u64a)streams.size();
}

/**
 * Take a ThreadContext and prepare a vector<StreamDataBlock> for streaming mode
 * scanning from it.
 */
static
vector<StreamInfo> prepStreamingData(const ThreadContext *ctx) {
    vector<StreamInfo> info(count_streams(ctx->corpus_data));
    for (const DataBlock &block : ctx->corpus_data) {
        assert(block.internal_stream_index < info.size());
        StreamInfo &si = info[block.internal_stream_index];

        /* check if this is the first time we have encountered this stream */
        if (si.first_block_id > si.last_block_id) {
            si.stream_id = block.stream_id;
            si.first_block_id = block.id;
            si.last_block_id = block.id;
        } else {
            assert(block.stream_id == si.stream_id);
            assert(block.id > si.last_block_id);
            assert(block.id > si.first_block_id);
            si.last_block_id = block.id;
        }
    }
    return info;
}

static
void benchStreamingInternal(ThreadContext *ctx, vector<StreamInfo> &streams,
                            bool do_compress) {
    assert(ctx);
    const Engine &e = ctx->engine;
    const vector<DataBlock> &blocks = ctx->corpus_data;
    vector<char> compress_buf(do_compress ? 1000 : 0);

    for (ResultEntry &r : ctx->results) {
        ctx->timer.start();

        for (const auto &b : blocks) {
            StreamInfo &stream = streams[b.internal_stream_index];
            assert(stream.stream_id == b.stream_id);

            // If this is the first block in the stream, open the stream
            // handle.
            if (b.id == stream.first_block_id) {
                assert(!stream.eng_handle);
                stream.eng_handle = e.streamOpen(*ctx->enginectx, b.stream_id);
                if (!stream.eng_handle) {
                    printf("Fatal error: stream open failed!\n");
                    exit(1);
                }
            } else if (do_compress) {
                e.streamCompressExpand(*stream.eng_handle, compress_buf);
            }

            assert(stream.eng_handle);

            e.streamScan(*stream.eng_handle, b.payload.c_str(),
                         b.payload.size(), b.id, r);

            // if this was the last block in the stream, close the stream handle
            if (b.id == stream.last_block_id) {
                e.streamClose(move(stream.eng_handle), r);
                stream.eng_handle = nullptr;
            }
        }

        ctx->timer.complete();
        r.seconds = ctx->timer.seconds();
    }
}

/** Run a benchmark over a given engine and corpus in streaming mode. */
static
void benchStreaming(void *context) {
    ThreadContext *ctx = (ThreadContext *)context;
    vector<StreamInfo> streams = prepStreamingData(ctx);

    // Synchronization point
    ctx->barrier();

    startTotalTimer(ctx);

    benchStreamingInternal(ctx, streams, false);

    // Synchronization point
    ctx->barrier();

    // Now that all threads are finished, we can stop the clock.
    stopTotalTimer(ctx);
}

static
void benchStreamingCompress(void *context) {
    ThreadContext *ctx = (ThreadContext *)context;
    vector<StreamInfo> streams = prepStreamingData(ctx);

    // Synchronization point
    ctx->barrier();

    startTotalTimer(ctx);

    benchStreamingInternal(ctx, streams, true);

    // Synchronization point
    ctx->barrier();

    // Now that all threads are finished, we can stop the clock.
    stopTotalTimer(ctx);
}

/** In-memory structure for a data block to be scanned in vectored mode. */
struct VectoredInfo {
    vector<const char *> data;
    vector<unsigned int> len;
    unsigned int stream_id;
};

/**
 * Take a ThreadContext and prepare a vector<VectoredInfo> for vectored mode
 * scanning from it.
 */
static
vector<VectoredInfo> prepVectorData(const ThreadContext *ctx) {
    vector<VectoredInfo> out(count_streams(ctx->corpus_data));
    for (const DataBlock &block : ctx->corpus_data) {
        VectoredInfo &vi = out[block.internal_stream_index];
        if (vi.data.empty()) {
            vi.stream_id = block.stream_id;
        } else {
            assert(vi.stream_id == block.stream_id);
        }
        vi.data.push_back(block.payload.c_str());
        vi.len.push_back(block.payload.size());
    }

    return out;
}

/** Run a benchmark over a given engine and corpus in vectored mode. */
static
void benchVectored(void *context) {
    ThreadContext *ctx = (ThreadContext *)context;

    vector<VectoredInfo> v_plans = prepVectorData(ctx);

    // Synchronization point
    ctx->barrier();

    startTotalTimer(ctx);

    for (ResultEntry &r : ctx->results) {
        ctx->timer.start();

        for (const VectoredInfo &v_plan : v_plans) {
            ctx->engine.scan_vectored(&v_plan.data[0], &v_plan.len[0],
                                      v_plan.data.size(), v_plan.stream_id, r,
                                      *ctx->enginectx);
        }

        ctx->timer.complete();
        r.seconds = ctx->timer.seconds();
    }

    // Synchronization point
    ctx->barrier();

    // Now that all threads are finished, we can stop the clock.
    stopTotalTimer(ctx);
}

/** Given a time and a size, compute the throughput in megabits/sec. */
static
long double calc_mbps(double seconds, u64a bytes) {
    assert(seconds > 0);
    return (long double)bytes / ((long double)seconds * 125000);
}

/** Dump per-scan throughput data to screen. */
static
void displayPerScanResults(const vector<unique_ptr<ThreadContext>> &threads,
                           u64a bytesPerRun) {
    for (const auto &t : threads) {
        const auto &results = t->results;
        for (size_t j = 0; j != results.size(); j++) {
            const auto &r = results[j];
            double mbps = calc_mbps(r.seconds, bytesPerRun);
#ifndef _WIN32
            printf("T %2u Scan %2zu: %'0.2f Mbit/sec\n", t->num, j, mbps);
#else
            printf("T %2u Scan %2zu: %0.2f Mbit/sec\n", t->num, j, mbps);
#endif
        }
    }
    printf("\n");
}

static
double fastestResult(const vector<unique_ptr<ThreadContext>> &threads) {
    double best = threads[0]->results[0].seconds;
    for (const auto &t : threads) {
        for (const auto &r : t->results) {
            best = min(best, r.seconds);
        }
    }
    return best;
}

static
u64a byte_size(const vector<DataBlock> &corpus_blocks) {
    u64a total = 0;
    for (const DataBlock &block : corpus_blocks) {
        total += block.payload.size();
    }

    return total;
}

/** Dump benchmark results to screen. */
static
void displayResults(const vector<unique_ptr<ThreadContext>> &threads,
                    const vector<DataBlock> &corpus_blocks) {
    u64a bytesPerRun = byte_size(corpus_blocks);
    u64a matchesPerRun = threads[0]->results[0].matches;

    // Sanity check: all of our results should have the same match count.
    for (const auto &t : threads) {
        if (!all_of(begin(t->results), end(t->results),
                    [&matchesPerRun](const ResultEntry &e) {
                        return e.matches == matchesPerRun;
                    })) {
            printf("\nWARNING: PER-SCAN MATCH COUNTS ARE INCONSISTENT!\n\n");
            break;
        }
    }

#ifndef _WIN32
    printf("Time spent scanning:       %'0.3f seconds\n", totalSecs);
    printf("Corpus size:               %'llu bytes ", bytesPerRun);
    switch (scan_mode) {
    case ScanMode::STREAMING:
        printf("(%'zu blocks in %'llu streams)\n", corpus_blocks.size(),
               count_streams(corpus_blocks));
        break;
    case ScanMode::VECTORED:
        printf("(%'zu blocks in %'llu vectors)\n", corpus_blocks.size(),
               count_streams(corpus_blocks));
        break;
    case ScanMode::BLOCK:
        printf("(%'zu blocks)\n", corpus_blocks.size());
        break;
    }
#else
    printf("Time spent scanning:       %0.3f seconds\n", totalSecs);
    printf("Corpus size:               %llu bytes ", bytesPerRun);
    switch (scan_mode) {
    case ScanMode::STREAMING:
        printf("(%zu blocks in %llu streams)\n", corpus_blocks.size(),
               count_streams(corpus_blocks));
        break;
    case ScanMode::VECTORED:
        printf("(%zu blocks in %llu vectors)\n", corpus_blocks.size(),
               count_streams(corpus_blocks));
        break;
    case ScanMode::BLOCK:
        printf("(%zu blocks)\n", corpus_blocks.size());
        break;
    }
#endif

    u64a totalBytes = bytesPerRun * repeats * threads.size();
    u64a totalBlocks = corpus_blocks.size() * repeats * threads.size();

    double matchRate = ((double)matchesPerRun * 1024) / bytesPerRun;
#ifndef _WIN32
    printf("Matches per iteration:     %'llu (%'0.3f matches/kilobyte)\n",
           matchesPerRun, matchRate);
#else
    printf("Matches per iteration:     %llu (%0.3f matches/kilobyte)\n",
           matchesPerRun, matchRate);
#endif

    double blockRate = (double)totalBlocks / (double)totalSecs;
#ifndef _WIN32
    printf("Overall block rate:        %'0.2f blocks/sec\n", blockRate);
    printf("Mean throughput (overall): %'0.2Lf Mbit/sec\n",
           calc_mbps(totalSecs, totalBytes));

#else
    printf("Overall block rate:        %0.2f blocks/sec\n", blockRate);
    printf("Mean throughput (overall): %0.2Lf Mbit/sec\n",
           calc_mbps(totalSecs, totalBytes));

#endif
    double lowestScanTime = fastestResult(threads);
#ifndef _WIN32
    printf("Max throughput (per core): %'0.2Lf Mbit/sec\n",
           calc_mbps(lowestScanTime, bytesPerRun));
#else
    printf("Max throughput (per core): %0.2Lf Mbit/sec\n",
           calc_mbps(lowestScanTime, bytesPerRun));
#endif
    printf("\n");

    if (display_per_scan) {
        displayPerScanResults(threads, bytesPerRun);
    }
}

/** Dump per-scan throughput data to sql. */
static
void sqlPerScanResults(const vector<unique_ptr<ThreadContext>> &threads,
                       u64a bytesPerRun, u64a scan_id) {
    static const std::string Q =
        "INSERT INTO ScanResults (scan_id, thread, scan, throughput) "
        "VALUES (?1, ?2, ?3, ?4)";

    for (const auto &t : threads) {
        const auto &results = t->results;
        for (size_t j = 0; j != results.size(); j++) {
            const auto &r = results[j];
            double mbps = calc_mbps(r.seconds, bytesPerRun);
            out_db.insert_all(Q, scan_id, t->num, j, mbps);
        }
    }
}

/** Dump benchmark results to sql. */
static
void sqlResults(const vector<unique_ptr<ThreadContext>> &threads,
                const vector<DataBlock> &corpus_blocks) {
    u64a bytesPerRun = byte_size(corpus_blocks);
    u64a matchesPerRun = threads[0]->results[0].matches;

    u64a scan_id = out_db.lastRowId();

    // Sanity check: all of our results should have the same match count.
    for (const auto &t : threads) {
        if (!all_of(begin(t->results), end(t->results),
                    [&matchesPerRun](const ResultEntry &e) {
                        return e.matches == matchesPerRun;
                    })) {
            printf("\nWARNING: PER-SCAN MATCH COUNTS ARE INCONSISTENT!\n\n");
            break;
        }
    }

    u64a totalBytes = bytesPerRun * repeats * threads.size();
    double matchRate = ((double)matchesPerRun * 1024) / bytesPerRun;

    const auto pos = corpusFile.find_last_of('/');
    const auto corpus = corpusFile.substr(pos + 1);

    static const std::string Q =
        "INSERT INTO Scan (scan_id, corpusFile, totalSecs, "
            "bytesPerRun, blockSize, blockCount, totalBytes, "
            "totalBlocks, matchesPerRun, matchRate, overallTput) "
        "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)";

    out_db.insert_all(
        Q, scan_id, corpus, totalSecs, bytesPerRun, corpus_blocks.size(),
        scan_mode == ScanMode::BLOCK ? 1 : count_streams(corpus_blocks),
        totalBytes, corpus_blocks.size() * repeats * threads.size(),
        matchesPerRun, matchRate, calc_mbps(totalSecs, totalBytes));

    if (display_per_scan) {
        sqlPerScanResults(threads, bytesPerRun, scan_id);
    }
}

/**
 * Construct a thread context for this scanning mode.
 *
 * Note: does not take blocks by reference. This is to give every thread their
 * own copy of the data. It would be unrealistic for every thread to be scanning
 * the same copy of the data.
 */
static
unique_ptr<ThreadContext> makeThreadContext(const Engine &db,
                                            const vector<DataBlock> &blocks,
                                            unsigned id,
                                            thread_barrier &sync_barrier) {
    thread_func_t fn = nullptr;
    switch (scan_mode) {
    case ScanMode::STREAMING:
        if (compressStream) {
            fn = benchStreamingCompress;
        } else {
            fn = benchStreaming;
        }
        break;
    case ScanMode::VECTORED:
        fn = benchVectored;
        break;
    case ScanMode::BLOCK:
        fn = benchBlock;
        break;
    }
    assert(fn);

    return ue2::make_unique<ThreadContext>(id, db, sync_barrier, fn, blocks);
}

/** Run the given benchmark. */
static
void runBenchmark(const Engine &db,
                  const vector<DataBlock> &corpus_blocks) {
    size_t numThreads;
    bool useAffinity = false;

    if (threadCores.empty()) {
        numThreads = 1;
    } else {
        numThreads = threadCores.size();
#if defined(HAVE_DECL_PTHREAD_SETAFFINITY_NP) || defined(_WIN32)
        useAffinity = true;
#else
        useAffinity = false;
#endif
    }

    // Initialise a barrier that will let us sync threads before/after scanning
    // for timer measurements.
    thread_barrier sync_barrier(numThreads);

    vector<unique_ptr<ThreadContext>> threads;

    for (unsigned i = 0; i < numThreads; i++) {
        auto t = makeThreadContext(db, corpus_blocks, i, sync_barrier);
        int core = useAffinity ? (int)threadCores[i] : -1;
        if (!t->start(core)) {
            printf("Unable to start processing thread %u\n", i);
            exit(1);
        }
        threads.push_back(move(t));
    }

    // Reap threads.
    for (auto &t : threads) {
        t->join();
    }

    if (sqloutFile.empty()) {
        // Display global results.
        displayResults(threads, corpus_blocks);
    } else {
        // write to sqlite file
        sqlResults(threads, corpus_blocks);
        out_db.exec("END");
    }
}
} // namespace

/** Main driver. */
int HS_CDECL main(int argc, char *argv[]) {
    unique_ptr<Grey> grey;
#if !defined(RELEASE_BUILD)
    grey = make_unique<Grey>();
#endif
    setlocale(LC_ALL, ""); // use the user's locale

#ifndef NDEBUG
    printf("\nWARNING: DO NOT BENCHMARK A HYPERSCAN BUILD WITH ASSERTIONS\n\n");
#endif

    vector<BenchmarkSigs> sigSets;
    processArgs(argc, argv, sigSets, grey);

    // read in and process our expressions
    ExpressionMap exprMapTemplate;
    loadExpressions(exprPath, exprMapTemplate);

    // If we have no signature sets, the user wants us to benchmark all the
    // known expressions together.
    if (sigSets.empty()) {
        SignatureSet sigs;
        sigs.reserve(exprMapTemplate.size());
        for (auto i : exprMapTemplate | map_keys) {
            sigs.push_back(i);
        }
        sigSets.emplace_back(exprPath, move(sigs));
    }

    // read in and process our corpus
    vector<DataBlock> corpus_blocks;
    try {
        corpus_blocks = readCorpus(corpusFile);
    } catch (const DataCorpusError &e) {
        printf("Corpus data error: %s\n", e.msg.c_str());
        return 1;
    }
    try {
        if (!sqloutFile.empty()) {
            out_db.open(sqloutFile);
        }

        for (const auto &s : sigSets) {
            auto exprMap = limitToSignatures(exprMapTemplate, s.sigs);
            if (exprMap.empty()) {
                continue;
            }

            unique_ptr<Engine> engine;
            if (useHybrid) {
#if defined(HS_HYBRID)
                engine = buildEngineChimera(exprMap, s.name, sigName);
            } else if (usePcre) {
                engine = buildEnginePcre(exprMap, s.name, sigName);
#endif
            } else {
                engine = buildEngineHyperscan(exprMap, scan_mode, s.name,
                                              sigName, *grey);
            }

            if (!engine) {
                printf("Error: expressions failed to compile.\n");
                exit(1);
            }

            if (sqloutFile.empty()) {
                // Display global results.
                engine->printStats();
                printf("\n");

            } else {
                out_db.exec("BEGIN");
                engine->sqlStats(out_db);
            }

            runBenchmark(*engine, corpus_blocks);
        }
    } catch (const SqlFailure &f) {
        cerr << f.message << '\n';
        return -1;
    }

    return 0;
}

ext: cpp

max_stars_repo_name: jtravee/neuvector

max_issues_repo_name: jtravee/neuvector

max_forks_repo_name: jtravee/neuvector


text:
/*
 * Copyright (C) 2012 Open Source Robotics Foundation
 *
 * 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.
 *
*/

#ifndef GAZEBO_PHYSICS_SIMBODY_SIMBODYPHYSICS_HH
#define GAZEBO_PHYSICS_SIMBODY_SIMBODYPHYSICS_HH
#include <string>

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>

#include "gazebo/physics/PhysicsEngine.hh"
#include "gazebo/physics/Collision.hh"
#include "gazebo/physics/Shape.hh"
#include "gazebo/physics/simbody/SimbodyTypes.hh"

#include "gazebo/physics/simbody/simbody_inc.h"
#include "gazebo/util/system.hh"

namespace gazebo
{
  namespace physics
  {
    /// \ingroup gazebo_physics
    /// \addtogroup gazebo_physics_simbody Simbody Physics
    /// \{

    /// \brief Simbody physics engine
    class GZ_PHYSICS_VISIBLE SimbodyPhysics : public PhysicsEngine
    {
      /// \brief Constructor
      public: SimbodyPhysics(WorldPtr _world);

      /// \brief Destructor
      public: virtual ~SimbodyPhysics();

      // Documentation inherited
      public: virtual void Load(sdf::ElementPtr _sdf);

      // Documentation inherited
      public: virtual void Init();

      // Documentation inherited
      public: virtual void Reset();

      /// \brief Add a Model to the Simbody system.
      /// \param[in] _model Pointer to the model to add into Simbody.
      public: void InitModel(const physics::ModelPtr _model);

      // Documentation inherited
      public: virtual void InitForThread();

      // Documentation inherited
      public: virtual void UpdateCollision();

      // Documentation inherited
      public: virtual void UpdatePhysics();

      // Documentation inherited
      public: virtual void Fini();

      // Documentation inherited
      public: virtual std::string GetType() const;

      // Documentation inherited
      public: virtual LinkPtr CreateLink(ModelPtr _parent);

      // Documentation inherited
      public: virtual CollisionPtr CreateCollision(const std::string &_type,
                                                   LinkPtr _body);

      // Documentation inherited
      public: virtual JointPtr CreateJoint(const std::string &_type,
                                           ModelPtr _parent);

      // Documentation inherited
      public: virtual ShapePtr CreateShape(const std::string &_shapeType,
                                           CollisionPtr _collision);

      /// \brief Register a joint with the dynamics world
      public: SimTK::MultibodySystem *GetDynamicsWorld() const;

      // Documentation inherited
      public: virtual void SetGravity(const ignition::math::Vector3d &_gravity);

      // Documentation inherited
      public: virtual void DebugPrint() const;

      // Documentation inherited
      public: virtual void SetSeed(uint32_t _seed);

      // Documentation inherited
      public: virtual ModelPtr CreateModel(BasePtr _parent);

      /// \brief Convert gazebo::math::Quaternion to SimTK::Quaternion
      /// \param[in] _q Gazeb's math::Quaternion object
      /// \return Simbody's SimTK::Quaternion object
      /// \deprecated See function which accepts an ignition math object.
      public: static SimTK::Quaternion QuadToQuad(const math::Quaternion &_q)
          GAZEBO_DEPRECATED(8.0);

      /// \brief Convert ignition::math::Quaterniond to SimTK::Quaternion
      /// \param[in] _q Ignition::math::Quaterniond object
      /// \return Simbody's SimTK::Quaternion object
      public: static SimTK::Quaternion QuadToQuad(
          const ignition::math::Quaterniond &_q);

      /// \brief Convert SimTK::Quaternion to gazebo::math::Quaternion
      /// \param[in] _q Simbody's SimTK::Quaternion object
      /// \return Gazeb's math::Quaternion object
      /// \deprecated See QuadToQuadIgn
      public: static math::Quaternion QuadToQuad(const SimTK::Quaternion &_q)
          GAZEBO_DEPRECATED(8.0);

      /// \brief Convert SimTK::Quaternion to ignition::math::Quaterniond
      /// \param[in] _q Simbody's SimTK::Quaternion object
      /// \return Ignition::math::Quaterniond object
      public: static ignition::math::Quaterniond QuadToQuadIgn(
          const SimTK::Quaternion &_q);

      /// \brief Convert gazebo::math::Vector3 to SimTK::Vec3
      /// \param[in] _v Gazebo's math::Vector3 object
      /// \return Simbody's SimTK::Vec3 object
      /// \deprecated See function which accepts an ignition math object.
      public: static SimTK::Vec3 Vector3ToVec3(const math::Vector3 &_v)
          GAZEBO_DEPRECATED(8.0);

      /// \brief Convert ignition::math::Vector3d to SimTK::Vec3
      /// \param[in] _v Ignition math Vector3d object
      /// \return Simbody's SimTK::Vec3 object
      public: static SimTK::Vec3 Vector3ToVec3(
          const ignition::math::Vector3d &_v);

      /// \brief Convert SimTK::Vec3 to gazebo::math::Vector3
      /// \param[in] _v Simbody's SimTK::Vec3 object
      /// \return Gazebo's math::Vector3 object
      /// \deprecated See Vec3ToVector3Ign
      public: static math::Vector3 Vec3ToVector3(const SimTK::Vec3 &_v)
          GAZEBO_DEPRECATED(8.0);

      /// \brief Convert SimTK::Vec3 to ignition::math::Vector3d
      /// \param[in] _v Simbody's SimTK::Vec3 object
      /// \return ignition::math::Vector3d object
      public: static ignition::math::Vector3d Vec3ToVector3Ign(
                  const SimTK::Vec3 &_v);

      /// \brief Convert the given pose in x,y,z,thetax,thetay,thetaz format to
      /// a Simbody Transform. The rotation angles are interpreted as a
      /// body-fixed sequence, meaning we rotation about x, then about
      /// the new y, then about the now twice-rotated z.
      /// \param[in] _pose Gazebo's math::Pose object
      /// \return Simbody's SimTK::Transform object
      /// \deprecated See function which accepts an ignition math object.
      public: static SimTK::Transform Pose2Transform(const math::Pose &_pose)
          GAZEBO_DEPRECATED(8.0);

      /// \brief Convert the given pose in x,y,z,thetax,thetay,thetaz format to
      /// a Simbody Transform. The rotation angles are interpreted as a
      /// body-fixed sequence, meaning we rotation about x, then about
      /// the new y, then about the now twice-rotated z.
      /// \param[in] _pose Ignition math Pose3d object
      /// \return Simbody's SimTK::Transform object
      public: static SimTK::Transform Pose2Transform(
                  const ignition::math::Pose3d &_pose);

      /// \brief Convert a Simbody transform to a pose in x,y,z,
      /// thetax,thetay,thetaz format.
      /// \param[in] _xAB Simbody's SimTK::Transform object
      /// \return Gazebo's math::Pose object
      /// \deprecated See Transform2PoseIgn
      public: static math::Pose Transform2Pose(const SimTK::Transform &_xAB)
          GAZEBO_DEPRECATED(8.0);

      /// \brief Convert a Simbody transform to a pose in x,y,z,
      /// thetax,thetay,thetaz format.
      /// \param[in] _xAB Simbody's SimTK::Transform object
      /// \return ignition::math::Pose3d object
      public: static ignition::math::Pose3d Transform2PoseIgn(
          const SimTK::Transform &_xAB);

      /// \brief If the given element contains a <pose> element, return it as a
      /// Transform. Otherwise return the identity Transform. If there
      /// is more than one <pose> element, only the first one is processed.
      public: static SimTK::Transform GetPose(sdf::ElementPtr _element);

      /// \brief Convert Base::GetType() to string,
      /// this is needed by the MultibodyGraphMaker.
      /// \param[in] _type Joint type returned by Joint::GetType().
      /// \return a hard-coded string needed by the MultibodyGraphMaker.
      public: static std::string GetTypeString(unsigned int _type);

      /// \brief Convert Base::GetType() to string,
      /// this is needed by the MultibodyGraphMaker.
      /// \param[in] _type Joint type returned by Joint::GetType().
      /// \return a hard-coded string needed by the MultibodyGraphMaker.
      public: static std::string GetTypeString(physics::Base::EntityType _type);

      // Documentation inherited
      protected: virtual void OnRequest(ConstRequestPtr &_msg);

      // Documentation inherited
      protected: virtual void OnPhysicsMsg(ConstPhysicsPtr &_msg);

      /// \brief CREATE MULTIBODY GRAPH
      /// Define Gazebo joint types, then use links and joints in the
      /// given model to construct a reasonable spanning-tree-plus-constraints
      /// multibody graph to represent that model. An exception will be
      /// thrown if this fails.  Note that this step is not Simbody dependent.
      /// \param[in] _mbgraph Create a MultibodyGraphMaker that is equivalent
      /// of incoming physics::Model.
      /// \param[in] _model Model loaded by Gazebo parsing SDF.
      private: void CreateMultibodyGraph(
        SimTK::MultibodyGraphMaker& _mbgraph, const physics::ModelPtr _model);

      /// \brief BUILD SIMBODY SYSTEM
      /// Given a desired multibody graph, gravity, and the Gazebo model
      /// that was used to generate the graph, create a Simbody System
      /// for it. There are many limitations here, especially in the
      /// handling of contact. Any Gazebo features that we haven't
      /// modeled are just ignored.  The GazeboModel is updated so that
      /// its links and joints have references to their corresponding
      /// Simbody elements.  We set up some visualization here so we
      /// can see what's happening but this would not be needed in Gazebo
      /// since it does its own visualization.
      private: void InitSimbodySystem();

      /// \brief Add a static Model to simbody system, and reinitialize state
      /// \param[in] _model the incoming static Gazebo physics::Model.
      private: void AddStaticModelToSimbodySystem(
                   const physics::ModelPtr _model);

      /// \brief Read from MultibodydGraphMaker and construct a physics::Model.
      /// \param[in] _mbgraph Contain MultibodyGraphMaker object.
      /// \param[in] _model Pointer to gazebo model, not used at this time.
      private: void AddDynamicModelToSimbodySystem(
        const SimTK::MultibodyGraphMaker &_mbgraph,
        const physics::ModelPtr _model);

      /// \brief helper function for building SimbodySystem
      private: void AddCollisionsToLink(const physics::SimbodyLink *_link,
        SimTK::MobilizedBody &_mobod, SimTK::ContactCliqueId _modelClique);

      public: SimTK::MultibodySystem system;
      public: SimTK::SimbodyMatterSubsystem matter;
      public: SimTK::GeneralForceSubsystem forces;
      public: SimTK::Force::Gravity gravity;
      public: SimTK::Force::DiscreteForces discreteForces;
      public: SimTK::ContactTrackerSubsystem tracker;
      public: SimTK::CompliantContactSubsystem contact;
      public: SimTK:: Integrator *integ;

      /// \brief true if initialized
      public: bool simbodyPhysicsInitialized;

      public: bool simbodyPhysicsStepped;

      // Documentation inherited
      public: virtual boost::any GetParam(const std::string &_key) const;

      // Documentation inherited
      public: virtual bool GetParam(const std::string &_key,
                  boost::any &_value) const;

      // Documentation inherited
      public: virtual bool SetParam(const std::string &_key,
                  const boost::any &_value);

      /// \brief contact material stiffness.  See sdf description for details.
      private: double contactMaterialStiffness;

      /// \brief contact material dissipation.  See sdf description for details.
      private: double contactMaterialDissipation;

      /// \brief contact material plastic coefficient of restitution.
      /// See sdf description for details.
      private: double contactMaterialPlasticCoefRestitution;

      /// \brief contact material plastic impact velocity.
      /// See sdf description for details.
      private: double contactMaterialPlasticImpactVelocity;

      /// \brief contact material static friction.
      /// See sdf description for details.
      private: double contactMaterialStaticFriction;

      /// \brief contact material dynamic friction.
      /// See sdf description for details.
      private: double contactMaterialDynamicFriction;

      /// \brief contact material viscous friction.
      /// See sdf description for details.
      private: double contactMaterialViscousFriction;

      /// \brief contact impact capture velocity.
      /// See sdf description for details.
      private: double contactImpactCaptureVelocity;

      /// \brief contact stiction transition velocity
      /// See sdf description for details.
      private: double contactStictionTransitionVelocity;

      private: SimTK::MultibodySystem *dynamicsWorld;

      private: common::Time lastUpdateTime;

      private: double stepTimeDouble;

      /// \brief The type of the solver.
      /// Not used, just getting ready for optional pgs rigid contacts.
      private: std::string solverType;

      /// \brief The type of integrator:
      ///   SimTK::RungeKuttaMersonIntegrator(system)
      ///   SimTK::RungeKutta3Integrator(system)
      ///   SimTK::RungeKutta2Integrator(system)
      ///   SimTK::SemiExplicitEuler2Integrator(system)
      private: std::string integratorType;
    };
  /// \}
  }
}
#endif

ext: hh

max_forks_repo_name: mingfeisun/gazebo


text:
#include "Day14-ExtendedPolymerization.h"

#include "PolymerizationEquipment.h"

#include <AdventOfCodeCommon/DisableLibraryWarningsMacros.h>

__BEGIN_LIBRARIES_DISABLE_WARNINGS
#include <boost/algorithm/string.hpp>
__END_LIBRARIES_DISABLE_WARNINGS

namespace
{

size_t NUM_PAIR_INSERTIONS_PART_ONE = 10;
size_t NUM_PAIR_INSERTIONS_PART_TWO = 40;

}

namespace AdventOfCode
{
namespace Year2021
{
namespace Day14
{

using TextSection = std::vector<std::string>;

PolymerPairToInsertedElement parsePairInsertionRulesTextSection(const TextSection& pairInsertionRulesTextSection)
{
    PolymerPairToInsertedElement polymerPairToInsertedElement;

    for (const auto& line : pairInsertionRulesTextSection)
    {
        std::vector<std::string> tokens;
        boost::split(tokens, line, boost::is_any_of(" ->"), boost::token_compress_on);
        polymerPairToInsertedElement[tokens.at(0)] = tokens.at(1).front();
    }

    return polymerPairToInsertedElement;
}

PolymerizationEquipment parsePolymerFormulaLines(const std::vector<std::string>& polymerFormulaLines)
{
    std::vector<TextSection> textSections;
    boost::split(textSections, polymerFormulaLines, [](const auto& elem) { return elem.empty(); });

    std::string polymerTemplate = textSections.at(0).at(0);
    PolymerPairToInsertedElement polymerPairToInsertedElement = parsePairInsertionRulesTextSection(textSections.at(1));

    return PolymerizationEquipment{std::move(polymerTemplate), std::move(polymerPairToInsertedElement)};
}

int64_t mostAndLeastCommonElementQuantityDifference(const std::vector<std::string>& polymerFormulaLines)
{
    PolymerizationEquipment polymerizationEquipment = parsePolymerFormulaLines(polymerFormulaLines);
    polymerizationEquipment.growPolymer(NUM_PAIR_INSERTIONS_PART_ONE);
    return polymerizationEquipment.getMostAndLeastCommonElementQuantityDifference();
}

int64_t mostAndLeastCommonElementQuantityDifferenceReinforced(const std::vector<std::string>& polymerFormulaLines)
{
    PolymerizationEquipment polymerizationEquipment = parsePolymerFormulaLines(polymerFormulaLines);
    polymerizationEquipment.growPolymer(NUM_PAIR_INSERTIONS_PART_TWO);
    return polymerizationEquipment.getMostAndLeastCommonElementQuantityDifference();
}

}
}
}

max_stars_repo_name: dbartok/advent-of-code-cpp

max_issues_repo_name: dbartok/advent-of-code-cpp

max_forks_repo_name: dbartok/advent-of-code-cpp


text:
/* This file was generated by fulmar version 0.9.2. */

/*
 * Copyright (c) 2014-2017 The University of Utah
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <spatialops/SpatialOpsTools.h>
#include <spatialops/structured/FVStaggeredFieldTypes.h>
#include <spatialops/OperatorDatabase.h>
#include <spatialops/structured/stencil/FVStaggeredOperatorTypes.h>
#include <spatialops/structured/stencil/StencilBuilder.h>
#include <test/TestHelper.h>
#include <spatialops/structured/FieldHelper.h>
#include <spatialops/Nebo.h>
#include <boost/program_options.hpp>
#include <string>
#include <stdexcept>
#include "ReferenceStencil.h"
using namespace SpatialOps;
using std::cout;
using std::endl;
using std::string;
namespace po = boost::program_options;
template<typename FirstOpType,
         typename SecondOpType,
         typename SrcType,
         typename ItmdType,
         typename DestType>
 inline bool test_stencil_chain(OperatorDatabase & opdb,
                                IntVec npts,
                                IntVec const bc) {
    /* basic definitions: */
    const GhostData ghosts = GhostData(1);
    const BoundaryCellInfo srcbc = BoundaryCellInfo::build<SrcType>(bc, bc);
    const BoundaryCellInfo itmbc = BoundaryCellInfo::build<ItmdType>(bc, bc);
    const BoundaryCellInfo destbc = BoundaryCellInfo::build<DestType>(bc, bc);
    const MemoryWindow mwSrc = get_window_with_ghost(npts, ghosts, srcbc);
    const MemoryWindow mwItmd = get_window_with_ghost(npts, ghosts, itmbc);
    const MemoryWindow mwDest = get_window_with_ghost(npts, ghosts, destbc);
    SrcType src(mwSrc, srcbc, ghosts, NULL);
    ItmdType itmd(mwItmd, itmbc, ghosts, NULL);
    DestType ref(mwDest, destbc, ghosts, NULL);
    DestType test(mwDest, destbc, ghosts, NULL);

    /* initialize source field / zero out result fields: */
    initialize_field(src);
    itmd <<= 0.0;
    ref <<= 0.0;
    test <<= 0.0;

    /* get first operator */
    typename OperatorTypeBuilder<FirstOpType, SrcType, ItmdType>::type typedef
    FirstOp;
    const FirstOp * const firstOp = opdb.retrieve_operator<FirstOp>();

    /* get second operator: */
    typename OperatorTypeBuilder<SecondOpType, ItmdType, DestType>::type typedef
    SecondOp;
    const SecondOp * const secondOp = opdb.retrieve_operator<SecondOp>();

    /* run reference: */
    itmd <<= (*firstOp)(src);
    ref <<= (*secondOp)(itmd);

    /* run operator: */
    test <<= (*secondOp)((*firstOp)(src));

    return interior_display_fields_compare(ref, test, false, false);
 }
template<typename FirstOpType,
         typename SecondOpType,
         typename SrcType,
         typename ItmdType,
         typename DestType>
 inline void test_stencil_chain_with_status(TestHelper & status,
                                            OperatorDatabase & opdb,
                                            IntVec npts,
                                            IntVec const bc,
                                            string const & str) {
    status(test_stencil_chain<FirstOpType,
                              SecondOpType,
                              SrcType,
                              ItmdType,
                              DestType>(opdb, npts, bc),
           str);
 }
int main(int iarg, char * carg[]) {
   int nx;

   int ny;

   int nz;

   IntVec bc(false, false, false);

   po::options_description desc("Supported Options");

   desc.add_options()
   ("help", "print help message\n")
   ("nx", po::value<int>(&nx)->default_value(11), "number of points in x-dir for base mesh")
   ("ny", po::value<int>(&ny)->default_value(11), "number of points in y-dir for base mesh")
   ("nz", po::value<int>(&nz)->default_value(11), "number of points in z-dir for base mesh")
   ("bcx", "physical boundary on +x side?")
   ("bcy", "physical boundary on +y side?")
   ("bcz", "physical boundary on +z side?");

   po::variables_map args;

   po::store(po::parse_command_line(iarg, carg, desc), args);

   po::notify(args);

   if(args.count("bcx")) { bc[0] = true; };

   if(args.count("bcy")) { bc[1] = true; };

   if(args.count("bcz")) { bc[2] = true; };

   if(args.count("help")) {
      cout << desc << endl << "Examples:" << endl
       << " test_stencil --nx 5 --ny 10 --nz 3 --bcx" << endl
       << " test_stencil --bcx --bcy --bcz" << endl
       << " test_stencil --nx 50 --bcz" << endl
       << endl;

      return -1;
   };

   TestHelper status(true);

   const IntVec npts(nx, ny, nz);

   cout << "Run information:" << endl
    << "  bcx    : " << (bc[0] ? "ON" : "OFF") << endl
    << "  bcy    : " << (bc[1] ? "ON" : "OFF") << endl
    << "  bcz    : " << (bc[2] ? "ON" : "OFF") << endl
    << "  domain : " << npts << endl
    << endl;

   const double length = 10.0;

   OperatorDatabase opdb;

   build_stencils(npts[0], npts[1], npts[2], length, length, length, opdb);

   try{
      /* Test for chains starting with "Interpolant (SVolField->SSurfXField)" */
      if(npts[0]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Divergence,
                                      SVolField,
                                      SSurfXField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->SSurfXField) -> Divergence (SSurfXField->SVolField)");

      /* Test for chains starting with "Interpolant (SVolField->SSurfYField)" */
      if(npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Divergence,
                                      SVolField,
                                      SSurfYField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->SSurfYField) -> Divergence (SSurfYField->SVolField)");

      /* Test for chains starting with "Interpolant (SVolField->SSurfZField)" */
      if(npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Divergence,
                                      SVolField,
                                      SSurfZField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->SSurfZField) -> Divergence (SSurfZField->SVolField)");

      /* Test for chains starting with "Divergence (SSurfXField->SVolField)" */
      if(npts[0]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfXField,
                                      SVolField,
                                      SSurfXField>(status, opdb, npts, bc, "Divergence (SSurfXField->SVolField) -> Interpolant (SVolField->SSurfXField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfXField,
                                      SVolField,
                                      SSurfYField>(status, opdb, npts, bc, "Divergence (SSurfXField->SVolField) -> Interpolant (SVolField->SSurfYField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfXField,
                                      SVolField,
                                      SSurfZField>(status, opdb, npts, bc, "Divergence (SSurfXField->SVolField) -> Interpolant (SVolField->SSurfZField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfXField,
                                      SVolField,
                                      XSurfYField>(status, opdb, npts, bc, "Divergence (SSurfXField->SVolField) -> Interpolant (SVolField->XSurfYField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfXField,
                                      SVolField,
                                      XSurfZField>(status, opdb, npts, bc, "Divergence (SSurfXField->SVolField) -> Interpolant (SVolField->XSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfXField,
                                      SVolField,
                                      YSurfZField>(status, opdb, npts, bc, "Divergence (SSurfXField->SVolField) -> Interpolant (SVolField->YSurfZField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Divergence,
                                      InterpolantY,
                                      SSurfXField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Divergence (SSurfXField->SVolField) -> InterpolantY (SVolField->SVolField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      InterpolantZ,
                                      SSurfXField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Divergence (SSurfXField->SVolField) -> InterpolantZ (SVolField->SVolField)");
      if(npts[0]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfXField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Divergence (SSurfXField->SVolField) -> Interpolant (SVolField->SVolField)");

      /* Test for chains starting with "Divergence (SSurfYField->SVolField)" */
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfYField,
                                      SVolField,
                                      SSurfXField>(status, opdb, npts, bc, "Divergence (SSurfYField->SVolField) -> Interpolant (SVolField->SSurfXField)");
      if(npts[1]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfYField,
                                      SVolField,
                                      SSurfYField>(status, opdb, npts, bc, "Divergence (SSurfYField->SVolField) -> Interpolant (SVolField->SSurfYField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfYField,
                                      SVolField,
                                      SSurfZField>(status, opdb, npts, bc, "Divergence (SSurfYField->SVolField) -> Interpolant (SVolField->SSurfZField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfYField,
                                      SVolField,
                                      XSurfYField>(status, opdb, npts, bc, "Divergence (SSurfYField->SVolField) -> Interpolant (SVolField->XSurfYField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfYField,
                                      SVolField,
                                      XSurfZField>(status, opdb, npts, bc, "Divergence (SSurfYField->SVolField) -> Interpolant (SVolField->XSurfZField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfYField,
                                      SVolField,
                                      YSurfZField>(status, opdb, npts, bc, "Divergence (SSurfYField->SVolField) -> Interpolant (SVolField->YSurfZField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Divergence,
                                      InterpolantX,
                                      SSurfYField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Divergence (SSurfYField->SVolField) -> InterpolantX (SVolField->SVolField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      InterpolantZ,
                                      SSurfYField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Divergence (SSurfYField->SVolField) -> InterpolantZ (SVolField->SVolField)");
      if(npts[1]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfYField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Divergence (SSurfYField->SVolField) -> Interpolant (SVolField->SVolField)");

      /* Test for chains starting with "Divergence (SSurfZField->SVolField)" */
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfZField,
                                      SVolField,
                                      SSurfXField>(status, opdb, npts, bc, "Divergence (SSurfZField->SVolField) -> Interpolant (SVolField->SSurfXField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfZField,
                                      SVolField,
                                      SSurfYField>(status, opdb, npts, bc, "Divergence (SSurfZField->SVolField) -> Interpolant (SVolField->SSurfYField)");
      if(npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfZField,
                                      SVolField,
                                      SSurfZField>(status, opdb, npts, bc, "Divergence (SSurfZField->SVolField) -> Interpolant (SVolField->SSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfZField,
                                      SVolField,
                                      XSurfYField>(status, opdb, npts, bc, "Divergence (SSurfZField->SVolField) -> Interpolant (SVolField->XSurfYField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfZField,
                                      SVolField,
                                      XSurfZField>(status, opdb, npts, bc, "Divergence (SSurfZField->SVolField) -> Interpolant (SVolField->XSurfZField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfZField,
                                      SVolField,
                                      YSurfZField>(status, opdb, npts, bc, "Divergence (SSurfZField->SVolField) -> Interpolant (SVolField->YSurfZField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      InterpolantX,
                                      SSurfZField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Divergence (SSurfZField->SVolField) -> InterpolantX (SVolField->SVolField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      InterpolantY,
                                      SSurfZField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Divergence (SSurfZField->SVolField) -> InterpolantY (SVolField->SVolField)");
      if(npts[2]>1)
       test_stencil_chain_with_status<Divergence,
                                      Interpolant,
                                      SSurfZField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Divergence (SSurfZField->SVolField) -> Interpolant (SVolField->SVolField)");

      /* Test for chains starting with "Interpolant (SVolField->XSurfYField)" */
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      SVolField,
                                      XSurfYField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->XSurfYField) -> Interpolant (XSurfYField->SVolField)");

      /* Test for chains starting with "Interpolant (SVolField->XSurfZField)" */
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      SVolField,
                                      XSurfZField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->XSurfZField) -> Interpolant (XSurfZField->SVolField)");

      /* Test for chains starting with "Interpolant (SVolField->YSurfZField)" */
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      SVolField,
                                      YSurfZField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->YSurfZField) -> Interpolant (YSurfZField->SVolField)");

      /* Test for chains starting with "Interpolant (XSurfYField->SVolField)" */
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfYField,
                                      SVolField,
                                      SSurfYField>(status, opdb, npts, bc, "Interpolant (XSurfYField->SVolField) -> Interpolant (SVolField->SSurfYField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfYField,
                                      SVolField,
                                      SSurfZField>(status, opdb, npts, bc, "Interpolant (XSurfYField->SVolField) -> Interpolant (SVolField->SSurfZField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfYField,
                                      SVolField,
                                      XSurfYField>(status, opdb, npts, bc, "Interpolant (XSurfYField->SVolField) -> Interpolant (SVolField->XSurfYField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfYField,
                                      SVolField,
                                      XSurfZField>(status, opdb, npts, bc, "Interpolant (XSurfYField->SVolField) -> Interpolant (SVolField->XSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfYField,
                                      SVolField,
                                      YSurfZField>(status, opdb, npts, bc, "Interpolant (XSurfYField->SVolField) -> Interpolant (SVolField->YSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      InterpolantZ,
                                      XSurfYField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (XSurfYField->SVolField) -> InterpolantZ (SVolField->SVolField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfYField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (XSurfYField->SVolField) -> Interpolant (SVolField->SVolField)");

      /* Test for chains starting with "Interpolant (XSurfZField->SVolField)" */
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfZField,
                                      SVolField,
                                      SSurfYField>(status, opdb, npts, bc, "Interpolant (XSurfZField->SVolField) -> Interpolant (SVolField->SSurfYField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfZField,
                                      SVolField,
                                      SSurfZField>(status, opdb, npts, bc, "Interpolant (XSurfZField->SVolField) -> Interpolant (SVolField->SSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfZField,
                                      SVolField,
                                      XSurfYField>(status, opdb, npts, bc, "Interpolant (XSurfZField->SVolField) -> Interpolant (SVolField->XSurfYField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfZField,
                                      SVolField,
                                      XSurfZField>(status, opdb, npts, bc, "Interpolant (XSurfZField->SVolField) -> Interpolant (SVolField->XSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfZField,
                                      SVolField,
                                      YSurfZField>(status, opdb, npts, bc, "Interpolant (XSurfZField->SVolField) -> Interpolant (SVolField->YSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      InterpolantY,
                                      XSurfZField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (XSurfZField->SVolField) -> InterpolantY (SVolField->SVolField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XSurfZField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (XSurfZField->SVolField) -> Interpolant (SVolField->SVolField)");

      /* Test for chains starting with "Interpolant (YSurfZField->SVolField)" */
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      YSurfZField,
                                      SVolField,
                                      SSurfXField>(status, opdb, npts, bc, "Interpolant (YSurfZField->SVolField) -> Interpolant (SVolField->SSurfXField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      YSurfZField,
                                      SVolField,
                                      SSurfZField>(status, opdb, npts, bc, "Interpolant (YSurfZField->SVolField) -> Interpolant (SVolField->SSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      YSurfZField,
                                      SVolField,
                                      XSurfZField>(status, opdb, npts, bc, "Interpolant (YSurfZField->SVolField) -> Interpolant (SVolField->XSurfZField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      YSurfZField,
                                      SVolField,
                                      YSurfZField>(status, opdb, npts, bc, "Interpolant (YSurfZField->SVolField) -> Interpolant (SVolField->YSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      InterpolantX,
                                      YSurfZField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (YSurfZField->SVolField) -> InterpolantX (SVolField->SVolField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      YSurfZField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (YSurfZField->SVolField) -> Interpolant (SVolField->SVolField)");

      /* Test for chains starting with "Interpolant (XVolField->YVolField)" */
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XVolField,
                                      YVolField,
                                      XVolField>(status, opdb, npts, bc, "Interpolant (XVolField->YVolField) -> Interpolant (YVolField->XVolField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XVolField,
                                      YVolField,
                                      ZVolField>(status, opdb, npts, bc, "Interpolant (XVolField->YVolField) -> Interpolant (YVolField->ZVolField)");

      /* Test for chains starting with "Interpolant (XVolField->ZVolField)" */
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XVolField,
                                      ZVolField,
                                      XVolField>(status, opdb, npts, bc, "Interpolant (XVolField->ZVolField) -> Interpolant (ZVolField->XVolField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      XVolField,
                                      ZVolField,
                                      YVolField>(status, opdb, npts, bc, "Interpolant (XVolField->ZVolField) -> Interpolant (ZVolField->YVolField)");

      /* Test for chains starting with "Interpolant (YVolField->XVolField)" */
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      YVolField,
                                      XVolField,
                                      YVolField>(status, opdb, npts, bc, "Interpolant (YVolField->XVolField) -> Interpolant (XVolField->YVolField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      YVolField,
                                      XVolField,
                                      ZVolField>(status, opdb, npts, bc, "Interpolant (YVolField->XVolField) -> Interpolant (XVolField->ZVolField)");

      /* Test for chains starting with "Interpolant (YVolField->ZVolField)" */
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      YVolField,
                                      ZVolField,
                                      XVolField>(status, opdb, npts, bc, "Interpolant (YVolField->ZVolField) -> Interpolant (ZVolField->XVolField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      YVolField,
                                      ZVolField,
                                      YVolField>(status, opdb, npts, bc, "Interpolant (YVolField->ZVolField) -> Interpolant (ZVolField->YVolField)");

      /* Test for chains starting with "Interpolant (ZVolField->XVolField)" */
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      ZVolField,
                                      XVolField,
                                      YVolField>(status, opdb, npts, bc, "Interpolant (ZVolField->XVolField) -> Interpolant (XVolField->YVolField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      ZVolField,
                                      XVolField,
                                      ZVolField>(status, opdb, npts, bc, "Interpolant (ZVolField->XVolField) -> Interpolant (XVolField->ZVolField)");

      /* Test for chains starting with "Interpolant (ZVolField->YVolField)" */
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      ZVolField,
                                      YVolField,
                                      XVolField>(status, opdb, npts, bc, "Interpolant (ZVolField->YVolField) -> Interpolant (YVolField->XVolField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      ZVolField,
                                      YVolField,
                                      ZVolField>(status, opdb, npts, bc, "Interpolant (ZVolField->YVolField) -> Interpolant (YVolField->ZVolField)");

      /* Test for chains starting with "InterpolantX (SVolField->SVolField)" */
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<InterpolantX,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SSurfYField>(status, opdb, npts, bc, "InterpolantX (SVolField->SVolField) -> Interpolant (SVolField->SSurfYField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantX,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SSurfZField>(status, opdb, npts, bc, "InterpolantX (SVolField->SVolField) -> Interpolant (SVolField->SSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantX,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      YSurfZField>(status, opdb, npts, bc, "InterpolantX (SVolField->SVolField) -> Interpolant (SVolField->YSurfZField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<InterpolantX,
                                      InterpolantY,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "InterpolantX (SVolField->SVolField) -> InterpolantY (SVolField->SVolField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantX,
                                      InterpolantZ,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "InterpolantX (SVolField->SVolField) -> InterpolantZ (SVolField->SVolField)");
      if(npts[0]>1)
       test_stencil_chain_with_status<InterpolantX,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "InterpolantX (SVolField->SVolField) -> Interpolant (SVolField->SVolField)");

      /* Test for chains starting with "InterpolantY (SVolField->SVolField)" */
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<InterpolantY,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SSurfXField>(status, opdb, npts, bc, "InterpolantY (SVolField->SVolField) -> Interpolant (SVolField->SSurfXField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantY,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SSurfZField>(status, opdb, npts, bc, "InterpolantY (SVolField->SVolField) -> Interpolant (SVolField->SSurfZField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantY,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      XSurfZField>(status, opdb, npts, bc, "InterpolantY (SVolField->SVolField) -> Interpolant (SVolField->XSurfZField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<InterpolantY,
                                      InterpolantX,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "InterpolantY (SVolField->SVolField) -> InterpolantX (SVolField->SVolField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantY,
                                      InterpolantZ,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "InterpolantY (SVolField->SVolField) -> InterpolantZ (SVolField->SVolField)");
      if(npts[1]>1)
       test_stencil_chain_with_status<InterpolantY,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "InterpolantY (SVolField->SVolField) -> Interpolant (SVolField->SVolField)");

      /* Test for chains starting with "InterpolantZ (SVolField->SVolField)" */
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantZ,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SSurfXField>(status, opdb, npts, bc, "InterpolantZ (SVolField->SVolField) -> Interpolant (SVolField->SSurfXField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantZ,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SSurfYField>(status, opdb, npts, bc, "InterpolantZ (SVolField->SVolField) -> Interpolant (SVolField->SSurfYField)");
      if(npts[0]>1 & npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantZ,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      XSurfYField>(status, opdb, npts, bc, "InterpolantZ (SVolField->SVolField) -> Interpolant (SVolField->XSurfYField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantZ,
                                      InterpolantX,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "InterpolantZ (SVolField->SVolField) -> InterpolantX (SVolField->SVolField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<InterpolantZ,
                                      InterpolantY,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "InterpolantZ (SVolField->SVolField) -> InterpolantY (SVolField->SVolField)");
      if(npts[2]>1)
       test_stencil_chain_with_status<InterpolantZ,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "InterpolantZ (SVolField->SVolField) -> Interpolant (SVolField->SVolField)");

      /* Test for chains starting with "Interpolant (SVolField->SVolField)" */
      if(npts[0]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SSurfXField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> Interpolant (SVolField->SSurfXField)");
      if(npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SSurfYField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> Interpolant (SVolField->SSurfYField)");
      if(npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      SSurfZField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> Interpolant (SVolField->SSurfZField)");
      if(npts[0]>1 & npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      XSurfYField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> Interpolant (SVolField->XSurfYField)");
      if(npts[0]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      XSurfZField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> Interpolant (SVolField->XSurfZField)");
      if(npts[1]>1 & npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      Interpolant,
                                      SVolField,
                                      SVolField,
                                      YSurfZField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> Interpolant (SVolField->YSurfZField)");
      if(npts[0]>1)
       test_stencil_chain_with_status<Interpolant,
                                      InterpolantX,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> InterpolantX (SVolField->SVolField)");
      if(npts[1]>1)
       test_stencil_chain_with_status<Interpolant,
                                      InterpolantY,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> InterpolantY (SVolField->SVolField)");
      if(npts[2]>1)
       test_stencil_chain_with_status<Interpolant,
                                      InterpolantZ,
                                      SVolField,
                                      SVolField,
                                      SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> InterpolantZ (SVolField->SVolField)");
      test_stencil_chain_with_status<Interpolant,
                                     Interpolant,
                                     SVolField,
                                     SVolField,
                                     SVolField>(status, opdb, npts, bc, "Interpolant (SVolField->SVolField) -> Interpolant (SVolField->SVolField)");

      if(status.ok()) { cout << "ALL TESTS PASSED :)" << endl; return 0; };
   }
   catch(std::runtime_error & e){ cout << e.what() << endl; };

   cout << "******************************" << endl
    << " At least one test FAILED :(" << endl
    << "******************************" << endl;

   return -1;
}

max_stars_repo_name: MaxZZG/SpatialOps

max_issues_repo_name: MaxZZG/SpatialOps

max_forks_repo_name: MaxZZG/SpatialOps


text:
//Copyright (c) 2013 Singapore-MIT Alliance for Research and Technology
//Licensed under the terms of the MIT License, as described in the file:
//   license.txt   (http://opensource.org/licenses/MIT)

/*
 * BoundaryProcessor.cpp
 *
 */

#include "BoundaryProcessor.hpp"

#include "conf/settings/DisableMPI.h"

#ifndef SIMMOB_DISABLE_MPI
#include "mpi.h"
#include <boost/mpi.hpp>

#include <limits>
#include "BoundaryProcessor.hpp"

#include "util/GeomHelpers.hpp"
#include "entities/AuraManager.hpp"
#include "logging/Log.hpp"
#include "workers/WorkGroup.hpp"

#include "partitions/PartitionManager.hpp"

namespace mpi = boost::mpi;

using std::string;
using std::vector;
using namespace sim_mob;

sim_mob::BoundaryProcessor::BoundaryProcessor(): BOUNDARY_PROCOSS_TAG(2)
{
    std::cout << "Do nothing" << std::endl;
//      downstream_ips.clear();
}

string sim_mob::BoundaryProcessor::boundaryProcessing(int time_step)
{
    std::cout << "Do nothing" << std::endl;
    return "";
}

void sim_mob::BoundaryProcessor::initBoundaryTrafficItems()
{
    std::cout << "Do nothing" << std::endl;
}

string sim_mob::BoundaryProcessor::releaseResources()
{
    std::cout << "Do nothing" << std::endl;
    return "";
}

void sim_mob::BoundaryProcessor::setEntityWorkGroup(WorkGroup* entity_group, WorkGroup* singal_group)
{
    std::cout << "Do nothing" << std::endl;
}

void sim_mob::BoundaryProcessor::loadInBoundarySegment(string id, BoundarySegment* boundary)
{
    std::cout << "Do nothing" << std::endl;
}

void sim_mob::BoundaryProcessor::setConfigure(PartitionConfigure* partition_config, SimulationScenario* scenario)
{
    std::cout << "Do nothing" << std::endl;
}

#endif


text:
#include <boost/regex.hpp>
#include <iostream>
#include <string>

using namespace std;

int main() {
  string s = "Boost Libraries";
  boost::regex expr{"\\w+"};
  boost::regex_token_iterator<string::iterator> it{s.begin(), s.end(), expr};
  boost::regex_token_iterator<string::iterator> end;
  while (it != end)
    cout << *it++ << endl;
}