<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <algorithm>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/Language.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-base/util/SimpleRateLimit.h"
#include "fnord-base/InternMap.h"
#include "fnord-json/json.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "fnord-sstable/sstablereader.h"
#include "fnord-sstable/sstablewriter.h"
#include "fnord-sstable/SSTableColumnSchema.h"
#include "fnord-sstable/SSTableColumnReader.h"
#include "fnord-sstable/SSTableColumnWriter.h"
#include <fnord-fts/fts.h>
#include <fnord-fts/fts_common.h>
#include "common.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "CTRCounter.h"
#include "IndexReader.h"
#include "reports/ReportBuilder.h"
#include "reports/JoinedQueryTableSource.h"
#include "reports/CTRByPositionMapper.h"
#include "reports/CTRByPageMapper.h"
#include "reports/CTRBySearchQueryMapper.h"
#include "reports/CTRByQueryAttributeMapper.h"
#include "reports/CTRBySearchTermCrossCategoryMapper.h"
#include "reports/CTRStatsMapper.h"
#include "reports/CTRCounterMergeReducer.h"
#include "reports/CTRCounterTableSink.h"
#include "reports/CTRCounterTableSource.h"
#include "reports/RelatedTermsMapper.h"
#include "reports/TopCategoriesByTermMapper.h"
#include "reports/TermInfoMergeReducer.h"

using namespace fnord;
using namespace cm;

Set<uint64_t> mkGenerations(
    uint64_t window_secs,
    uint64_t range_secs,
    uint64_t now_secs = 0) {
  Set<uint64_t> generations;
  auto now = now_secs == 0 ? WallClock::unixMicros() : now_secs * kMicrosPerSecond;
  auto gen_window = kMicrosPerSecond * window_secs;
  for (uint64_t i = 1; i < kMicrosPerSecond * range_secs; i += gen_window) {
    generations.emplace((now - i) / gen_window);
  }

  return generations;
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "conf",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      "./conf",
      "conf directory",
      "<path>");

  flags.defineFlag(
      "index",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "index directory",
      "<path>");

  flags.defineFlag(
      "artifacts",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "artifact directory",
      "<path>");

  flags.defineFlag(
      "loop",
      fnord::cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "loop",
      "<switch>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  auto index_path = flags.getString("index");
  auto conf_path = flags.getString("conf");
  auto dir = flags.getString("artifacts");

  /* open index */
  auto index_reader = cm::IndexReader::openIndex(index_path);
  auto analyzer = RefPtr<fts::Analyzer>(new fts::Analyzer(conf_path));

  /* set up reportbuilder */
  cm::ReportBuilder report_builder;

  /* 4 hourly reports */
  for (const auto& g : mkGenerations(
        4 * kSecondsPerHour,
        60 * kSecondsPerDay)) {
    /* dawanda: map joined queries */
    auto jq_source = new JoinedQueryTableSource(
        StringUtil::format("$0/dawanda_joined_queries.$1.sstable", dir, g));

    report_builder.addReport(
        new CTRByPositionMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_position.$1.sstable",
                    dir,
                    g)),
            ItemEligibility::ALL));

    report_builder.addReport(
        new CTRByPageMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_page.$1.sstable",
                    dir,
                    g)),
            ItemEligibility::ALL));

    report_builder.addReport(
        new CTRStatsMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_stats.$1.sstable",
                    dir,
                    g)),
            ItemEligibility::ALL));

    report_builder.addReport(
        new CTRByQueryAttributeMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_catalog_e1.$1.sstable",
                    dir,
                    g)),
            "q_cat1",
            ItemEligibility::ALL));

    report_builder.addReport(
        new CTRByQueryAttributeMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_catalog_e2.$1.sstable",
                    dir,
                    g)),
            "q_cat2",
            ItemEligibility::ALL));

    report_builder.addReport(
        new CTRByQueryAttributeMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_catalog_e3.$1.sstable",
                    dir,
                    g)),
            "q_cat3",
            ItemEligibility::ALL));

    report_builder.addReport(
        new CTRBySearchQueryMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_searchquery.$1.sstable",
                    dir,
                    g)),
            ItemEligibility::ALL,
            analyzer));

    report_builder.addReport(
        new CTRBySearchTermCrossCategoryMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_searchterm_cross_e1.$1.sstable",
                    dir,
                    g)),
            "category1",
            ItemEligibility::ALL,
            analyzer,
            index_reader));

    report_builder.addReport(
        new CTRBySearchTermCrossCategoryMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_searchterm_cross_e2.$1.sstable",
                    dir,
                    g)),
            "category2",
            ItemEligibility::ALL,
            analyzer,
            index_reader));

    report_builder.addReport(
        new CTRBySearchTermCrossCategoryMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_searchterm_cross_e3.$1.sstable",
                    dir,
                    g)),
            "category3",
            ItemEligibility::ALL,
            analyzer,
            index_reader));
  }

  /* daily reports */
  for (const auto& og : mkGenerations(
        1 * kSecondsPerDay,
        60 * kSecondsPerDay)) {
    auto day_gens = mkGenerations(
        4 * kSecondsPerHour,
        1 * kSecondsPerDay,
        og * kSecondsPerDay);

    auto month_gens = mkGenerations(
        1 * kSecondsPerDay,
        30 * kSecondsPerDay,
        og * kSecondsPerDay);

    /* dawanda: roll up ctr stats */
    Set<String> ctr_stats_sources;
    for (const auto& ig : day_gens) {
      ctr_stats_sources.emplace(
          StringUtil::format("$0/dawanda_ctr_stats.$1.sstable", dir, ig));
    }

    report_builder.addReport(
        new CTRCounterMergeReducer(
            new CTRCounterTableSource(ctr_stats_sources),
            new CTRCounterTableSink(
                (og) * kMicrosPerDay,
                (og + 1) * kMicrosPerDay,
                StringUtil::format(
                    "$0/dawanda_ctr_stats_daily.$1.sstable",
                    dir,
                    og))));

    /* dawanda: roll up ctr positions */
    Set<String> ctr_posi_sources;
    for (const auto& ig : day_gens) {
      ctr_posi_sources.emplace(
          StringUtil::format("$0/dawanda_ctr_by_position.$1.sstable", dir, ig));
    }

    report_builder.addReport(
        new CTRCounterMergeReducer(
            new CTRCounterTableSource(ctr_posi_sources),
            new CTRCounterTableSink(
                (og) * kMicrosPerDay,
                (og + 1) * kMicrosPerDay,
                StringUtil::format(
                    "$0/dawanda_ctr_by_position_daily.$1.sstable",
                    dir,
                    og))));

    /* dawanda: roll up ctr by page */
    Set<String> ctr_by_page_sources;
    for (const auto& ig : day_gens) {
      ctr_by_page_sources.emplace(
          StringUtil::format("$0/dawanda_ctr_by_page.$1.sstable", dir, ig));
    }

    report_builder.addReport(
        new CTRCounterMergeReducer(
            new CTRCounterTableSource(ctr_by_page_sources),
            new CTRCounterTableSink(
                (og) * kMicrosPerDay,
                (og + 1) * kMicrosPerDay,
                StringUtil::format(
                    "$0/dawanda_ctr_by_page_daily.$1.sstable",
                    dir,
                    og))));

    /* dawanda: roll up related search terms */
    Set<String> related_terms_sources;
    for (const auto& ig : day_gens) {
      related_terms_sources.emplace(StringUtil::format(
          "$0/dawanda_ctr_by_searchquery.$1.sstable",
          dir,
          ig));
    }

    report_builder.addReport(
        new RelatedTermsMapper(
            new CTRCounterTableSource(related_terms_sources),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_related_terms.$1.sstable",
                    dir,
                    og))));

    Set<String> related_terms_rollup_sources;
    for (const auto& ig : month_gens) {
      related_terms_rollup_sources.emplace(StringUtil::format(
          "$0/dawanda_related_terms.$1.sstable",
          dir,
          ig));
    }

    report_builder.addReport(
        new TermInfoMergeReducer(
            new TermInfoTableSource(related_terms_rollup_sources),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_related_terms_30d.$1.sstable",
                    dir,
                    og))));

    /* dawanda: roll up search term x e1 id */
    Set<String> term_cross_e1_sources;
    for (const auto& ig : day_gens) {
      term_cross_e1_sources.emplace(StringUtil::format(
          "$0/dawanda_ctr_by_searchterm_cross_e1.$1.sstable",
          dir,
          ig));
    }

    report_builder.addReport(
        new TopCategoriesByTermMapper(
            new CTRCounterTableSource(term_cross_e1_sources),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_top_cats_by_searchterm_e1.$1.sstable",
                    dir,
                    og)),
            "e1-"));

    Set<String> term_cross_e1_rollup_sources;
    for (const auto& ig : month_gens) {
      term_cross_e1_rollup_sources.emplace(StringUtil::format(
          "$0/dawanda_top_cats_by_searchterm_e1.$1.sstable",
          dir,
          ig));
    }

    report_builder.addReport(
        new TermInfoMergeReducer(
            new TermInfoTableSource(term_cross_e1_rollup_sources),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_top_cats_by_searchterm_e1_30d.$1.sstable",
                    dir,
                    og))));

    /* merge all term info 30d reports */
    report_builder.addReport(
        new TermInfoMergeReducer(
            new TermInfoTableSource(Set<String> {
              StringUtil::format(
                    "$0/dawanda_related_terms_30d.$1.sstable",
                    dir,
                    og),
              StringUtil::format(
                    "$0/dawanda_top_cats_by_searchterm_e1_30d.$1.sstable",
                    dir,
                    og)
            }),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_termstats_30d.$1.sstable",
                    dir,
                    og))));
  }

  if (flags.isSet("loop")) {
    report_builder.buildLoop();
  } else {
    report_builder.buildAll();
  }
  return 0;
}

<commit_msg>delete obsolete reports<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <algorithm>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/Language.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-base/util/SimpleRateLimit.h"
#include "fnord-base/InternMap.h"
#include "fnord-json/json.h"
#include "fnord-mdb/MDB.h"
#include "fnord-mdb/MDBUtil.h"
#include "fnord-sstable/sstablereader.h"
#include "fnord-sstable/sstablewriter.h"
#include "fnord-sstable/SSTableColumnSchema.h"
#include "fnord-sstable/SSTableColumnReader.h"
#include "fnord-sstable/SSTableColumnWriter.h"
#include <fnord-fts/fts.h>
#include <fnord-fts/fts_common.h>
#include "common.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "JoinedQuery.h"
#include "CTRCounter.h"
#include "IndexReader.h"
#include "reports/ReportBuilder.h"
#include "reports/JoinedQueryTableSource.h"
#include "reports/CTRByPositionMapper.h"
#include "reports/CTRByPageMapper.h"
#include "reports/CTRBySearchQueryMapper.h"
#include "reports/CTRByQueryAttributeMapper.h"
#include "reports/CTRBySearchTermCrossCategoryMapper.h"
#include "reports/CTRStatsMapper.h"
#include "reports/CTRCounterMergeReducer.h"
#include "reports/CTRCounterTableSink.h"
#include "reports/CTRCounterTableSource.h"
#include "reports/RelatedTermsMapper.h"
#include "reports/TopCategoriesByTermMapper.h"
#include "reports/TermInfoMergeReducer.h"

using namespace fnord;
using namespace cm;

Set<uint64_t> mkGenerations(
    uint64_t window_secs,
    uint64_t range_secs,
    uint64_t now_secs = 0) {
  Set<uint64_t> generations;
  auto now = now_secs == 0 ? WallClock::unixMicros() : now_secs * kMicrosPerSecond;
  auto gen_window = kMicrosPerSecond * window_secs;
  for (uint64_t i = 1; i < kMicrosPerSecond * range_secs; i += gen_window) {
    generations.emplace((now - i) / gen_window);
  }

  return generations;
}

int main(int argc, const char** argv) {
  fnord::Application::init();
  fnord::Application::logToStderr();

  fnord::cli::FlagParser flags;

  flags.defineFlag(
      "conf",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      "./conf",
      "conf directory",
      "<path>");

  flags.defineFlag(
      "index",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "index directory",
      "<path>");

  flags.defineFlag(
      "artifacts",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "artifact directory",
      "<path>");

  flags.defineFlag(
      "loop",
      fnord::cli::FlagParser::T_SWITCH,
      false,
      NULL,
      NULL,
      "loop",
      "<switch>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  auto index_path = flags.getString("index");
  auto conf_path = flags.getString("conf");
  auto dir = flags.getString("artifacts");

  /* open index */
  auto index_reader = cm::IndexReader::openIndex(index_path);
  auto analyzer = RefPtr<fts::Analyzer>(new fts::Analyzer(conf_path));

  /* set up reportbuilder */
  cm::ReportBuilder report_builder;

  /* 4 hourly reports */
  for (const auto& g : mkGenerations(
        4 * kSecondsPerHour,
        60 * kSecondsPerDay)) {
    /* dawanda: map joined queries */
    auto jq_source = new JoinedQueryTableSource(
        StringUtil::format("$0/dawanda_joined_queries.$1.sstable", dir, g));

    report_builder.addReport(
        new CTRByPositionMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_position.$1.sstable",
                    dir,
                    g)),
            ItemEligibility::ALL));

    report_builder.addReport(
        new CTRBySearchQueryMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_searchquery.$1.sstable",
                    dir,
                    g)),
            ItemEligibility::ALL,
            analyzer));

    report_builder.addReport(
        new CTRBySearchTermCrossCategoryMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_searchterm_cross_e1.$1.sstable",
                    dir,
                    g)),
            "category1",
            ItemEligibility::ALL,
            analyzer,
            index_reader));

    report_builder.addReport(
        new CTRBySearchTermCrossCategoryMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_searchterm_cross_e2.$1.sstable",
                    dir,
                    g)),
            "category2",
            ItemEligibility::ALL,
            analyzer,
            index_reader));

    report_builder.addReport(
        new CTRBySearchTermCrossCategoryMapper(
            jq_source,
            new CTRCounterTableSink(
                g * kMicrosPerHour * 4,
                (g + 1) * kMicrosPerHour * 4,
                StringUtil::format(
                    "$0/dawanda_ctr_by_searchterm_cross_e3.$1.sstable",
                    dir,
                    g)),
            "category3",
            ItemEligibility::ALL,
            analyzer,
            index_reader));
  }

  /* daily reports */
  for (const auto& og : mkGenerations(
        1 * kSecondsPerDay,
        60 * kSecondsPerDay)) {
    auto day_gens = mkGenerations(
        4 * kSecondsPerHour,
        1 * kSecondsPerDay,
        og * kSecondsPerDay);

    auto month_gens = mkGenerations(
        1 * kSecondsPerDay,
        30 * kSecondsPerDay,
        og * kSecondsPerDay);

    /* dawanda: roll up related search terms */
    Set<String> related_terms_sources;
    for (const auto& ig : day_gens) {
      related_terms_sources.emplace(StringUtil::format(
          "$0/dawanda_ctr_by_searchquery.$1.sstable",
          dir,
          ig));
    }

    report_builder.addReport(
        new RelatedTermsMapper(
            new CTRCounterTableSource(related_terms_sources),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_related_terms.$1.sstable",
                    dir,
                    og))));

    Set<String> related_terms_rollup_sources;
    for (const auto& ig : month_gens) {
      related_terms_rollup_sources.emplace(StringUtil::format(
          "$0/dawanda_related_terms.$1.sstable",
          dir,
          ig));
    }

    report_builder.addReport(
        new TermInfoMergeReducer(
            new TermInfoTableSource(related_terms_rollup_sources),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_related_terms_30d.$1.sstable",
                    dir,
                    og))));

    /* dawanda: roll up search term x e1 id */
    Set<String> term_cross_e1_sources;
    for (const auto& ig : day_gens) {
      term_cross_e1_sources.emplace(StringUtil::format(
          "$0/dawanda_ctr_by_searchterm_cross_e1.$1.sstable",
          dir,
          ig));
    }

    report_builder.addReport(
        new TopCategoriesByTermMapper(
            new CTRCounterTableSource(term_cross_e1_sources),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_top_cats_by_searchterm_e1.$1.sstable",
                    dir,
                    og)),
            "e1-"));

    Set<String> term_cross_e1_rollup_sources;
    for (const auto& ig : month_gens) {
      term_cross_e1_rollup_sources.emplace(StringUtil::format(
          "$0/dawanda_top_cats_by_searchterm_e1.$1.sstable",
          dir,
          ig));
    }

    report_builder.addReport(
        new TermInfoMergeReducer(
            new TermInfoTableSource(term_cross_e1_rollup_sources),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_top_cats_by_searchterm_e1_30d.$1.sstable",
                    dir,
                    og))));

    /* merge all term info 30d reports */
    report_builder.addReport(
        new TermInfoMergeReducer(
            new TermInfoTableSource(Set<String> {
              StringUtil::format(
                    "$0/dawanda_related_terms_30d.$1.sstable",
                    dir,
                    og),
              StringUtil::format(
                    "$0/dawanda_top_cats_by_searchterm_e1_30d.$1.sstable",
                    dir,
                    og)
            }),
            new TermInfoTableSink(
                StringUtil::format(
                    "$0/dawanda_termstats_30d.$1.sstable",
                    dir,
                    og))));
  }

  if (flags.isSet("loop")) {
    report_builder.buildLoop();
  } else {
    report_builder.buildAll();
  }
  return 0;
}

<|endoftext|>


<commit_before>#include <ncurses.h>

#include <string>

using namespace std;

void menuShow(WINDOW *wnd, string title);

int main(int argc, char **argv) {

    WINDOW *wmenu, *wmain, *winfo;
    char menuItems[2][10] = {
        "start",
        "quit"
    };
    char menuItem[7];
    int ch, i = 0, width = 7;

    initscr();

    /*
     * init main window
     */

    wmain = newwin(40, 80, 1, 1);
    box(wmain, 0, 0);

    /*
     * init info window
     */

    winfo = newwin(10, 80, 40 + 1, 1);
    box(winfo, 0, 0);

    /*
     * init menu window
     */

    wmenu = newwin(10, 12, 10, 10);
    wborder(wmenu,
            ACS_BULLET, ACS_BULLET, ACS_BULLET, ACS_BULLET,     /* ls, rs, ts, bs */
            '+', '+', '+', '+');                                /* tl, tr, bl, br */

    for (i = 0; i < 2; i++) {
        if (i == 0) wattron(wmenu, A_STANDOUT);
        else wattroff(wmenu, A_STANDOUT);

        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
    }

    /*
     * init title, menu
     */

    wrefresh(wmain);
    wrefresh(wmenu);
    wrefresh(winfo);
    menuShow(wmain, "TERMINAL QUEST");
    i = 0;
    noecho();
    keypad(wmenu, true);
    curs_set(0);

    while (( ch = wgetch(wmenu)) != 'q') {
        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
        switch (ch) {
            case KEY_UP:
            case 'k':
                i--;
                i = (i < 0) ? 1 : i;
                break;
            case KEY_DOWN:
            case 'j':
                i++;
                i = (i > 1) ? 0: i;
                break;
            default: // XXX only displays on second input
                string msg = "ch:" + to_string(ch) + ", i:" +to_string(i);
                wmove(winfo, 1, 1);
                wrefresh(winfo);
                wprintw(winfo, msg.c_str());
                break;
        }

        wattron(wmenu, A_STANDOUT);
        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
        wattroff(wmenu, A_STANDOUT);
    }

    /*
     * exit
     */

    delwin(wmenu);
    delwin(wmain);
    delwin(winfo);
    endwin();
    return 0;
}

void menuShow(WINDOW *wnd, string title) {

    wmove(wnd, 5, 5);

    for (size_t i = 0; i < title.size(); i++) {
        waddch(wnd, title[i]);
        waddch(wnd, ' ');
    }

    wrefresh(wnd);
}

<commit_msg>Refactor info panel printing<commit_after>#include <ncurses.h>

#include <string>

using namespace std;

void menuShow(WINDOW *wnd, string title);

int main(int argc, char **argv) {

    WINDOW *wmenu, *wmain, *winfo;
    char menuItems[2][10] = {
        "start",
        "quit"
    };
    char menuItem[7];
    int ch, i = 0, width = 7;

    initscr();

    /*
     * init main window
     */

    wmain = newwin(40, 80, 1, 1);
    box(wmain, 0, 0);

    /*
     * init info window
     * TODO
     *  [_] allow multiple info lines
     *  [_] delete oldest line when full
     *  [_] don't clear borders
     */

    winfo = newwin(10, 80, 40 + 1, 1);
    box(winfo, 0, 0);

    /*
     * init menu window
     */

    wmenu = newwin(10, 12, 10, 10);
    wborder(wmenu,
            ACS_BULLET, ACS_BULLET, ACS_BULLET, ACS_BULLET,     /* ls, rs, ts, bs */
            '+', '+', '+', '+');                                /* tl, tr, bl, br */

    for (i = 0; i < 2; i++) {
        if (i == 0) wattron(wmenu, A_STANDOUT);
        else wattroff(wmenu, A_STANDOUT);

        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
    }

    /*
     * init title, menu
     */

    wrefresh(wmain);
    wrefresh(wmenu);
    wrefresh(winfo);
    menuShow(wmain, "TERMINAL QUEST");
    i = 0;
    noecho();
    keypad(wmenu, true);
    curs_set(0);

    string infoPos, infoKey, infoMsg;
    while (( ch = wgetch(wmenu)) != 'q') {
        infoPos = to_string(ch);
        infoKey = to_string(i);
        infoMsg = to_string(KEY_ENTER);

        box(winfo, 0, 0);
        wmove(winfo, 1, 1);
        wprintw(winfo, (infoPos + ' ' + infoKey + ' ' + infoMsg).c_str());

        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
        switch (ch) {
            case KEY_UP:
            case 'k':
                i--;
                i = (i < 0) ? 1 : i;
                break;
            case KEY_DOWN:
            case 'j':
                i++;
                i = (i > 1) ? 0: i;
                break;
            case KEY_ENTER: /* numpad enter */
            case '\n':      /* keyboard return */
                /*
                 * TODO
                 *  check i and handle according to value
                 */
                break;

        }
        wmove(winfo, 1, 1);
        wrefresh(winfo);
        werase(winfo);

        wattron(wmenu, A_STANDOUT);
        sprintf(menuItem, "%-7s", menuItems[i]);
        mvwprintw(wmenu, i + 1, 2, "%s", menuItem);
        wattroff(wmenu, A_STANDOUT);
    }

    /*
     * exit
     */

    delwin(wmenu);
    delwin(wmain);
    delwin(winfo);
    endwin();
    return 0;
}

void menuShow(WINDOW *wnd, string title) {

    wmove(wnd, 5, 5);

    for (size_t i = 0; i < title.size(); i++) {
        waddch(wnd, title[i]);
        waddch(wnd, ' ');
    }

    wrefresh(wnd);
}

<|endoftext|>


<commit_before>/*
 *
 * Copyright (C) 2000 Frans Kaashoek (kaashoek@lcs.mit.edu)
 *                    Frank Dabek (fdabek@mit.edu)
 *
 *  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 "chord.h"
#include "dhash.h"
#include "parseopt.h"

EXITFN (cleanup);

#define MAX_VNODES 1024
#define STORE_SIZE 10000 //size of block store per vnode (in blocks)

ptr<chord> chordnode;
static str p2psocket;
int do_cache;
int cache_size;
dhash *dh[MAX_VNODES + 1];
int ndhash = 0;
int myport;

void stats ();
void stop ();
void halt ();

void
client_accept (int fd)
{
  if (fd < 0)
    fatal ("EOF\n");

  ref<axprt_stream> x = axprt_stream::alloc (fd);

  // XXX these dhashgateway objects are leaked
  //
  dhashgateway *c = New dhashgateway (x, chordnode);
  c->set_caching (do_cache ? 1 : 0);
}

static void
client_accept_socket (int lfd)
{
  sockaddr_un sun;
  bzero (&sun, sizeof (sun));
  socklen_t sunlen = sizeof (sun);
  int fd = accept (lfd, reinterpret_cast<sockaddr *> (&sun), &sunlen);
  if (fd >= 0)
    client_accept (fd);
}

static void
client_listening_cb (int fd, int status)
{
  if (status)
    close (fd);
  else if (listen (fd, 5) < 0) {
    fatal ("Error from listen: %m\n");
    close (fd);
  } else {
    fdcb (fd, selread, wrap (client_accept_socket, fd));
  }
}

static void
cleanup ()
{
   unlink (p2psocket);
}

static void
startclntd()
{

  unlink (p2psocket);
  int clntfd = unixsocket (p2psocket);
  if (clntfd < 0)
    fatal << "Error creating client socket (UNIX)" << strerror (errno) << "\n";
  client_listening_cb (clntfd, 0);

  int tcp_clntfd = inetsocket (SOCK_STREAM, myport);
  if (tcp_clntfd < 0)
    fatal << "Error creating client socket (TCP)\n";
  client_listening_cb (tcp_clntfd, 0);

}

static void
newvnode_cb (int nreplica, str db_name, int ss_mode, int n, vnode *my,
	     chordstat stat)
{
  if (stat != CHORD_OK) {
    warnx << "newvnode_cb: status " << stat << "\n";
    fatal ("unable to join\n");
  }
  str db_name_prime = strbuf () << db_name << "-" << n;
  if (ndhash >= MAX_VNODES) fatal << "Too many virtual nodes (1024)\n";
  dh[ndhash++] = New dhash (db_name_prime, my, nreplica,
			    STORE_SIZE,
			    cache_size,
			    ss_mode);
  if (n > 0) chordnode->newvnode (wrap (newvnode_cb, nreplica, db_name,
					ss_mode, n-1));
}

void
halt ()
{
  exit (0);
}

void
stats ()
{
  chordnode->stats ();
  for (int i = 0 ; i < ndhash; i++)
    dh[i]->print_stats ();
  chordnode->print ();
}

void
stop ()
{
  chordnode->stop ();
  for (int i = 0 ; i < ndhash; i++)
    dh[i]->stop ();
}

static void
usage ()
{
  warnx << "Usage: " << progname
	<< " -d <dbfile> -j hostname:port -p port "
    "[-S <sock>] [-v <nvnode>] [-c <cache?>] "
    "-B <cache size> "
    "[-s <server select mode>]\n";
  exit (1);
}

int
main (int argc, char **argv)
{
  int vnode = 1;
  setprogname (argv[0]);
  sfsconst_init ();
  random_init ();

  int ch;

  do_cache = 0;
  int ss_mode = 0;

  myport = 0;
  cache_size = 2000;
  int max_loccache = 100;
  str wellknownhost;
  int wellknownport = 0;
  int nreplica = 0;
  str db_name = "/var/tmp/db";
  p2psocket = "/tmp/chord-sock";
  str myname = my_addr ();

  while ((ch = getopt (argc, argv, "S:cd:s:v:j:p:B:n:l:")) != -1)
    switch (ch) {
    case 'l':
      if (inet_addr (optarg) == INADDR_NONE) {
	warn << "must specify bind address in dotted decimal form\n";
	exit (1);
      }
      myname = optarg;
    case 'n':
      nreplica = atoi (optarg);
      break;
    case 'p':
      myport = atoi (optarg);
      break;
    case 'j':
      {
	char *bs_port = strchr(optarg, ':');
	if (!bs_port) usage ();
	*bs_port = 0;
	bs_port++;
	if (inet_addr (optarg) == INADDR_NONE) {
	  //yep, this blocks
	  struct hostent *h = gethostbyname (optarg);
	  if (!h) {
	    warn << "Invalid address or hostname: " << optarg << "\n";
	    usage ();
	  }
	  struct in_addr *ptr = (struct in_addr *)h->h_addr;
	  wellknownhost = inet_ntoa (*ptr);
	} else
	  wellknownhost = optarg;

	wellknownport = atoi (bs_port);

	break;
      }
    case 'B':
      cache_size = atoi (optarg);
      break;
    case 'S':
      p2psocket = optarg;
      break;
    case 'c':
      do_cache = 1;
      break;
    case 'd':
      db_name = optarg;
      break;
    case 's':
      ss_mode = atoi(optarg);
      break;
    case 'v':
      vnode = atoi (optarg);
      break;
    default:
      usage ();
      break;
    }

  if (wellknownport == 0) usage ();

  max_loccache = max_loccache * (vnode + 1);
  chordnode = New refcounted<chord> (wellknownhost, wellknownport,
				     myname,
				     myport,
				     max_loccache,
				     ss_mode);
  chordnode->newvnode (wrap (newvnode_cb, nreplica, db_name, ss_mode,
			     vnode-1));

  sigcb(SIGUSR1, wrap (&stats));
  sigcb(SIGUSR2, wrap (&stop));
  sigcb(SIGHUP, wrap (&halt));

  if (p2psocket)
    startclntd();
  amain ();
}

<commit_msg>hack to allow DHASHTCP to continue working<commit_after>/*
 *
 * Copyright (C) 2000 Frans Kaashoek (kaashoek@lcs.mit.edu)
 *                    Frank Dabek (fdabek@mit.edu)
 *
 *  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 "chord.h"
#include "dhash.h"
#include "parseopt.h"

EXITFN (cleanup);

#define MAX_VNODES 1024
#define STORE_SIZE 10000 //size of block store per vnode (in blocks)

ptr<chord> chordnode;
static str p2psocket;
int do_cache;
int cache_size;
dhash *dh[MAX_VNODES + 1];
int ndhash = 0;
int myport;

void stats ();
void stop ();
void halt ();

void
client_accept (int fd)
{
  if (fd < 0)
    fatal ("EOF\n");

  ref<axprt_stream> x = axprt_stream::alloc (fd);

  // XXX these dhashgateway objects are leaked
  //
  dhashgateway *c = New dhashgateway (x, chordnode);
  c->set_caching (do_cache ? 1 : 0);
}

static void
client_accept_socket (int lfd)
{
  sockaddr_un sun;
  bzero (&sun, sizeof (sun));
  socklen_t sunlen = sizeof (sun);
  int fd = accept (lfd, reinterpret_cast<sockaddr *> (&sun), &sunlen);
  if (fd >= 0)
    client_accept (fd);
}

static void
client_listening_cb (int fd, int status)
{
  if (status)
    close (fd);
  else if (listen (fd, 5) < 0) {
    fatal ("Error from listen: %m\n");
    close (fd);
  } else {
    fdcb (fd, selread, wrap (client_accept_socket, fd));
  }
}

static void
cleanup ()
{
   unlink (p2psocket);
}

static void
startclntd()
{

  unlink (p2psocket);
  int clntfd = unixsocket (p2psocket);
  if (clntfd < 0)
    fatal << "Error creating client socket (UNIX)" << strerror (errno) << "\n";
  client_listening_cb (clntfd, 0);

  int port = (myport == 0) ? 0 : myport + 1;
  int tcp_clntfd = inetsocket (SOCK_STREAM, port);
  if (tcp_clntfd < 0)
    fatal << "Error creating client socket (TCP) " << strerror(errno) << "\n";
  client_listening_cb (tcp_clntfd, 0);

}

static void
newvnode_cb (int nreplica, str db_name, int ss_mode, int n, vnode *my,
	     chordstat stat)
{
  if (stat != CHORD_OK) {
    warnx << "newvnode_cb: status " << stat << "\n";
    fatal ("unable to join\n");
  }
  str db_name_prime = strbuf () << db_name << "-" << n;
  if (ndhash >= MAX_VNODES) fatal << "Too many virtual nodes (1024)\n";
  dh[ndhash++] = New dhash (db_name_prime, my, nreplica,
			    STORE_SIZE,
			    cache_size,
			    ss_mode);
  if (n > 0) chordnode->newvnode (wrap (newvnode_cb, nreplica, db_name,
					ss_mode, n-1));
}

void
halt ()
{
  exit (0);
}

void
stats ()
{
  chordnode->stats ();
  for (int i = 0 ; i < ndhash; i++)
    dh[i]->print_stats ();
  chordnode->print ();
}

void
stop ()
{
  chordnode->stop ();
  for (int i = 0 ; i < ndhash; i++)
    dh[i]->stop ();
}

static void
usage ()
{
  warnx << "Usage: " << progname
	<< " -d <dbfile> -j hostname:port -p port "
    "[-S <sock>] [-v <nvnode>] [-c <cache?>] "
    "-B <cache size> "
    "[-s <server select mode>]\n";
  exit (1);
}

int
main (int argc, char **argv)
{
  int vnode = 1;
  setprogname (argv[0]);
  sfsconst_init ();
  random_init ();

  int ch;

  do_cache = 0;
  int ss_mode = 0;

  myport = 0;
  cache_size = 2000;
  int max_loccache = 100;
  str wellknownhost;
  int wellknownport = 0;
  int nreplica = 0;
  str db_name = "/var/tmp/db";
  p2psocket = "/tmp/chord-sock";
  str myname = my_addr ();

  while ((ch = getopt (argc, argv, "S:cd:s:v:j:p:B:n:l:")) != -1)
    switch (ch) {
    case 'l':
      if (inet_addr (optarg) == INADDR_NONE) {
	warn << "must specify bind address in dotted decimal form\n";
	exit (1);
      }
      myname = optarg;
    case 'n':
      nreplica = atoi (optarg);
      break;
    case 'p':
      myport = atoi (optarg);
      break;
    case 'j':
      {
	char *bs_port = strchr(optarg, ':');
	if (!bs_port) usage ();
	*bs_port = 0;
	bs_port++;
	if (inet_addr (optarg) == INADDR_NONE) {
	  //yep, this blocks
	  struct hostent *h = gethostbyname (optarg);
	  if (!h) {
	    warn << "Invalid address or hostname: " << optarg << "\n";
	    usage ();
	  }
	  struct in_addr *ptr = (struct in_addr *)h->h_addr;
	  wellknownhost = inet_ntoa (*ptr);
	} else
	  wellknownhost = optarg;

	wellknownport = atoi (bs_port);

	break;
      }
    case 'B':
      cache_size = atoi (optarg);
      break;
    case 'S':
      p2psocket = optarg;
      break;
    case 'c':
      do_cache = 1;
      break;
    case 'd':
      db_name = optarg;
      break;
    case 's':
      ss_mode = atoi(optarg);
      break;
    case 'v':
      vnode = atoi (optarg);
      break;
    default:
      usage ();
      break;
    }

  if (wellknownport == 0) usage ();

  max_loccache = max_loccache * (vnode + 1);
  chordnode = New refcounted<chord> (wellknownhost, wellknownport,
				     myname,
				     myport,
				     max_loccache,
				     ss_mode);
  chordnode->newvnode (wrap (newvnode_cb, nreplica, db_name, ss_mode,
			     vnode-1));

  sigcb(SIGUSR1, wrap (&stats));
  sigcb(SIGUSR2, wrap (&stop));
  sigcb(SIGHUP, wrap (&halt));

  if (p2psocket)
    startclntd();
  amain ();
}

<|endoftext|>


<commit_before>/**
 * \file main.cpp
 * \brief Provides command line interface.
 */

#include <ios>
#include <iostream>
#include <sstream>
#include <exception>
#include <stdexcept>

#include "vigenere_square.hpp"
#include "stringutils.hpp"

/**
 * \brief Main function for user I/O and error handling.
 * \return 0 if no errors.
 */
int main()
{
    std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
    std::cout << "Vigenère cipher demo using the Vigenère table." << std::endl;
    std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;

    std::string alphabet;
    std::string cipher;
    std::string key;
    std::stringstream ss;

    std::cout << "Input alphabet and press ENTER. Input '_DEFAULT_' " <<
                 "to use default English alphabet." << std::endl;
    std::cin >> std::skipws >> alphabet;z

    if(alphabet == "_DEFAULT_")
    {
        alphabet = "ABCDEFGHIJKLMNOPQRSTUWXYZ";
    }

    try
    {
        vigenere_square vsq{stringutils::uppercase(alphabet)};
    }
    catch(std::invalid_argument e)
    {
        std::cout << e.what() << std::endl;
        return 1;
    }

    std::cout << "Input cipher and press ENTER." << std::endl;
    std::cin >> cipher;

    std::cout << "Input key and press ENTER." << std::endl;
    std::cin >> key;

    return 0;
}
<commit_msg>command line interface<commit_after>/**
 * \file main.cpp
 * \brief Provides command line interface.
 */

#include <ios>
#include <iostream>
#include <sstream>
#include <exception>
#include <stdexcept>

#include "vigenere_square.hpp"
#include "stringutils.hpp"

/**
 * \brief Main function for user I/O and error handling.
 * \return 0 if no errors.
 */
int main()
{
    std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
    std::cout << "Vigenère cipher demo using the Vigenère table." << std::endl;
    std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;

    vigenere_square vsq;
    std::string alphabet;
    std::string text;
    std::string key;
    std::stringstream ss;

    std::cout << "Input alphabet and press ENTER. Input '_DEFAULT_' " <<
                 "to use default English alphabet." << std::endl;
    std::cin >> std::skipws >> alphabet;

    if(alphabet == "_DEFAULT_")
    {
        alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    }

    try
    {
        vsq = vigenere_square{stringutils::uppercase(alphabet)};
    }
    catch(std::invalid_argument e)
    {
        std::cout << e.what() << std::endl;
        return 1;
    }

    std::string prompt;
    bool encrypt;
    while(true)
    {
        std::cout << "Please choose 'encrypt' or 'decrypt' and press ENTER." << std::endl;
        std::cin >> std::skipws >> text;
        text = stringutils::uppercase(text);
        if(text == "ENCRYPT")
        {
            prompt =  "Input plain text and press ENTER.";
            encrypt = true;
            break;
        }
        else if(text == "DECRYPT")
        {
            prompt =  "Input cipher text and press ENTER.";
            encrypt = false;
            break;
        }
    }

    std::cout << prompt << std::endl;
    std::cin >> std::skipws >> text;

    std::cout << "Input key and press ENTER." << std::endl;
    std::cin >> std::skipws >> key;

    if(encrypt)
    {
        std::cout << vsq.encrypt(text, key) << std::endl;
    }
    else
    {
        std::cout << vsq.decrypt(text, key) << std::endl;
    }

    return 0;
}
<|endoftext|>


<commit_before>#pragma once
#include <vector>
#include <type_traits>
#include <algorithm>
#define BOOST_PP_VARIADICS 1
#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include "type.hpp"
#include "optional.hpp"

namespace spn {
	//! 順序なし配列
	/*! 基本的にはstd::vectorそのまま
		要素を削除した時に順序を保証しない点だけが異なる */
	template <class T, class AL=std::allocator<T>>
	class noseq_vec : public std::vector<T, AL> {
		using vector = std::vector<T,AL>;
		public:
			using vector::vector;
			using vector::erase;
			void erase(typename vector::iterator itr) {
				if(vector::size() > 1 && itr != --vector::end()) {
					assert(itr < vector::end());
					// 削除対象が最後尾でなければ最後尾の要素と取り替える
					std::swap(*itr, vector::back());
				}
				assert(itr != vector::end());
				vector::pop_back();
			}
	};

	//! 同じ型を(Nを変えて)違う型として扱う為のラップクラス
	template <class T, int N>
	struct TypeWrap {
		T value;

		explicit TypeWrap(const T& id): value(id) {}
		explicit TypeWrap(T&& id): value(std::forward<T>(id)) {}
		operator T& () { return value; }
		operator const T& () const { return value; }
		TypeWrap& operator = (const T& id) {
			value = id;
			return *this;
		}
		TypeWrap& operator = (T&& id) {
			value = std::forward<T>(id);
			return *this;
		}
	};
	// TODO: 間に合わせの名前なので後でちゃんとした名前にする
	template <class T>
	struct TheType {
		using T2 = typename std::remove_reference<T>::type;
		using ctype = const typename std::remove_const<T2>::type&;
		using type = T2&;
		using pointer = T2*;
	};
	template <class T>
	struct TheType<T*> {
		using ctype = const typename std::remove_const<T>::type*;
		using type = T*&;
		using pointer = T**;
	};
	template <class DT, class REV>
	class AdaptItrBase : public REV {
		using Itr = REV;
		public:
			using Itr::Itr;
			using value_type = DT;
			using pointer = typename TheType<DT>::pointer;
			using reference = typename TheType<DT>::type;

			AdaptItrBase() = default;
			AdaptItrBase(const Itr& itr): Itr(itr) {}
			reference operator *() const {
				return (reference)Itr::operator*();
			}
	};

	//! 順序なしのID付きリスト
	/*! 全走査を速く、要素の追加削除を速く(走査中はNG)、要素の順序はどうでもいい、あまり余計なメモリは食わないように・・というクラス */
	template <class T, template <class> class Allocator=std::allocator, class IDType=unsigned int, unsigned int MaxID=std::numeric_limits<IDType>::max()>
	class noseq_list {
		using ID = typename std::make_unsigned<IDType>::type;
		constexpr static bool Validation(ID id) {
			return id < MaxID;
		}
		using RT = typename std::remove_reference<T>::type;
		//! ユーザーの要素を格納
		struct UData {
			using OPValue = Optional<T>;
			OPValue		value;
			ID			uid;		//!< ユニークID。要素の配列内移動をする際に使用

			UData(UData&& rp): value(std::forward<OPValue>(rp.value)), uid(rp.uid) {}
			template <class T2>
			UData(T2&& t, ID id): value(std::forward<T2>(t)), uid(id) {}

			UData& operator = (UData&& r) {
				std::swap(value, r.value);
				std::swap(uid, r.uid);
				return *this;
			}
		};
		struct FreeID : TypeWrap<ID,0> {using TypeWrap<ID,0>::TypeWrap;};
		struct ObjID : TypeWrap<ID,1> {using TypeWrap<ID,1>::TypeWrap;};
		/*! ObjID = UserDataの格納先インデックス
			FreeID = 次の空きインデックス */
		using IDS = boost::variant<boost::blank, ObjID, FreeID>;

		struct Entry {
			UData	udata;
			IDS		ids;

			template <class T2>
			Entry(T2&& t, ID idx): udata(std::forward<T2>(t),idx), ids(ObjID(idx)) {}
			operator typename TheType<T>::type () { return *udata.value; }
			operator typename TheType<T>::ctype () const { return *udata.value; }
		};
		using Array = std::vector<Entry, Allocator<Entry>>;
		Array		_array;
		ID			_nFree = 0,		//!< 空きブロック数
					_firstFree;		//!< 最初の空きブロックインデックス
		//! 現在削除処理中かのフラグ
		bool		_bRemoving = false;
		using RemList = std::vector<ID>;
		RemList		_remList;

		public:
			using iterator = AdaptItrBase<T, typename Array::iterator>;
			using const_iterator = AdaptItrBase<const T, typename Array::const_iterator>;
			using reverse_iterator = AdaptItrBase<T, std::reverse_iterator<typename Array::iterator>>;
			using const_reverse_iterator = AdaptItrBase<const T, std::reverse_iterator<typename Array::const_iterator>>;

			using id_type = ID;
			noseq_list() {
				static_assert(std::is_integral<IDType>::value, "typename ID should be Integral type");
			}
			noseq_list(noseq_list&& sl): _array(std::forward<noseq_vec<T>>(sl._array)), _nFree(sl._nFree), _firstFree(sl._firstFree) {}

			template <class... Ts>
			ID emplace(Ts&&... ts) {
				return add(T(std::forward<Ts>(ts)...));
			}
			template <class T2>
			ID add(T2&& t) {
				if(_nFree == 0) {
					// 空きが無いので配列の拡張
					ID sz = _array.size();
					_array.emplace_back(std::forward<T2>(t), sz);
					return sz;
				}
				ID ret = _firstFree;					// IDPairを書き込む場所
				ID objI = _array.size() - _nFree;		// ユーザーデータを書き込む場所
				--_nFree;
				auto& objE = _array[objI].udata;
				objE.value = std::forward<T2>(t);		// ユーザーデータの書き込み
				objE.uid = ret;

				auto& idE = _array[ret].ids;
				_firstFree = boost::get<FreeID>(idE);	// フリーリストの先頭を書き換え
				idE = ObjID(objI);						// IDPairの初期化
				return ret;
			}
			void rem(ID uindex) {
				AssertP(Trap, Validation(uindex), "invalid resource number %1%", uindex)
				if(!_bRemoving) {
					_bRemoving = true;

					auto& ids = _array[uindex].ids;
					auto& objI = boost::get<ObjID>(ids);	// 削除対象のnoseqインデックスを受け取る
					ID backI = _array.size()-_nFree-1;
					if(objI != backI) {
						// 最後尾と削除予定の要素を交換
						std::swap(_array[backI].udata, _array[objI].udata);
						// UIDとindex対応の書き換え
						_array[_array[objI].udata.uid].ids = ObjID(objI);
					}
					// 要素を解放
					_array[backI].udata.value = none;
					// フリーリストをつなぎ替える
					ids = FreeID(_firstFree);
					_firstFree = uindex;
					++_nFree;

					_bRemoving = false;
					while(!_remList.empty()) {
						ID tmp = _remList[0];
						_remList.erase(_remList.begin());
						rem(tmp);
					}
				} else
					_remList.push_back(uindex);
			}
			using Ref = decltype(*_array[0].udata.value);
			//! 要素の領域を先に取得
			std::pair<ID,Ref> alloc() {
				ID id = add(UData::OPValue::AsInitialized);
				return std::pair<ID,Ref>(id, get(id));
			}
			Ref get(ID uindex) {
				AssertP(Trap, Validation(uindex), "invalid resource number %1%", uindex)
				ID idx = boost::get<ObjID>(_array[uindex].ids);
				return *_array[idx].udata.value;
			}
			const Ref get(ID uindex) const {
				AssertP(Trap, Validation(uindex), "invalid resource number %1%", uindex)
				return const_cast<noseq_list*>(this)->get(uindex);
			}

			// イテレータの範囲はフリー要素を勘定に入れる
			iterator begin() { return _array.begin(); }
			iterator end() { return _array.end()-_nFree; }
			reverse_iterator rbegin() { return _array.rbegin()+_nFree; }
			reverse_iterator rend() { return _array.rend(); }
			const_iterator cbegin() const { return _array.cbegin(); }
			const_iterator cend() const { return _array.cend()-_nFree; }
			const_iterator begin() const { return _array.begin(); }
			const_iterator end() const { return _array.end()-_nFree; }
			const_reverse_iterator crbegin() const { return const_cast<noseq_list*>(this)->rbegin(); }
			const_reverse_iterator crend() const { return const_cast<noseq_list*>(this)->rend(); }

			//! 主にResMgrから開放時の処理をする為に使用
			template <class CB>
			void iterate(CB cb) {
				int n = _array.size();
				for(int i=0 ; i<n ; i++) {
					auto& ent = _array[i];
					// エントリが有効な場合のみコールバックを呼ぶ
					if(ent.ids.which() == 1) {
						ID id = boost::get<ObjID>(ent.ids);
						cb(_array[id].udata.value);
					}
				}
			}

			size_t size() const {
				return _array.size() - _nFree;
			}
			void clear() {
				_array.clear();
				_nFree = 0;
			}
			bool empty() const {
				return size() == 0;
			}
	};
}
<commit_msg>noseq_list: シリアライズ対応<commit_after>#pragma once
#include <vector>
#include <type_traits>
#include <algorithm>
#define BOOST_PP_VARIADICS 1
#include <boost/variant.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/variant.hpp>
#include <boost/serialization/traits.hpp>
#include <boost/serialization/tracking_enum.hpp>
#include "type.hpp"
#include "optional.hpp"

namespace boost {
	namespace serialization {
		template <class Archive>
		void serialize(Archive& ar, boost::blank& blk, const unsigned int) {
			// 何も出力しない
		}
	}
}
namespace spn {
	//! 順序なし配列
	/*! 基本的にはstd::vectorそのまま
		要素を削除した時に順序を保証しない点だけが異なる */
	template <class T, class AL=std::allocator<T>>
	class noseq_vec : public std::vector<T, AL> {
		using vector = std::vector<T,AL>;
		public:
			using vector::vector;
			using vector::erase;
			void erase(typename vector::iterator itr) {
				if(vector::size() > 1 && itr != --vector::end()) {
					assert(itr < vector::end());
					// 削除対象が最後尾でなければ最後尾の要素と取り替える
					std::swap(*itr, vector::back());
				}
				assert(itr != vector::end());
				vector::pop_back();
			}
	};

	//! 同じ型を(Nを変えて)違う型として扱う為のラップクラス
	template <class T, int N>
	struct TypeWrap : boost::serialization::traits<TypeWrap<T,N>, boost::serialization::object_serializable, boost::serialization::track_never, 0> {
		T value;

		template <class Archive>
		void serialize(Archive& ar, const unsigned int) {
			ar & value;
		}

		TypeWrap() = default;
		explicit TypeWrap(const T& id): value(id) {}
		explicit TypeWrap(T&& id): value(std::forward<T>(id)) {}
		operator T& () { return value; }
		operator const T& () const { return value; }
		TypeWrap& operator = (const T& id) {
			value = id;
			return *this;
		}
		TypeWrap& operator = (T&& id) {
			value = std::forward<T>(id);
			return *this;
		}
	};
	// TODO: 間に合わせの名前なので後でちゃんとした名前にする
	template <class T>
	struct TheType {
		using T2 = typename std::remove_reference<T>::type;
		using ctype = const typename std::remove_const<T2>::type&;
		using type = T2&;
		using pointer = T2*;
	};
	template <class T>
	struct TheType<T*> {
		using ctype = const typename std::remove_const<T>::type*;
		using type = T*&;
		using pointer = T**;
	};
	template <class DT, class REV>
	class AdaptItrBase : public REV {
		using Itr = REV;
		public:
			using Itr::Itr;
			using value_type = DT;
			using pointer = typename TheType<DT>::pointer;
			using reference = typename TheType<DT>::type;

			AdaptItrBase() = default;
			AdaptItrBase(const Itr& itr): Itr(itr) {}
			reference operator *() const {
				return (reference)Itr::operator*();
			}
	};

	//! 順序なしのID付きリスト
	/*! 全走査を速く、要素の追加削除を速く(走査中はNG)、要素の順序はどうでもいい、あまり余計なメモリは食わないように・・というクラス */
	template <class T, template <class> class Allocator=std::allocator, class IDType=unsigned int, unsigned int MaxID=std::numeric_limits<IDType>::max()>
	class noseq_list {
		using ID = typename std::make_unsigned<IDType>::type;
		constexpr static bool Validation(ID id) {
			return id < MaxID;
		}
		using RT = typename std::remove_reference<T>::type;
		//! ユーザーの要素を格納
		struct UData {
			using OPValue = Optional<T>;
			OPValue		value;
			ID			uid;		//!< ユニークID。要素の配列内移動をする際に使用

			UData(UData&& rp): value(std::forward<OPValue>(rp.value)), uid(rp.uid) {}
			template <class T2>
			UData(T2&& t, ID id): value(std::forward<T2>(t)), uid(id) {}

			UData& operator = (UData&& r) {
				std::swap(value, r.value);
				std::swap(uid, r.uid);
				return *this;
			}
			bool operator == (const UData& ud) const {
				return value == ud.value &&
						uid == ud.uid;
			}
		};
		struct FreeID : TypeWrap<ID,0> {using TypeWrap<ID,0>::TypeWrap;};
		struct ObjID : TypeWrap<ID,1> {using TypeWrap<ID,1>::TypeWrap;};
		/*! ObjID = UserDataの格納先インデックス
			FreeID = 次の空きインデックス */
		using IDS = boost::variant<boost::blank, ObjID, FreeID>;

		struct Entry {
			UData	udata;
			IDS		ids;

			template <class T2>
			Entry(T2&& t, ID idx): udata(std::forward<T2>(t),idx), ids(ObjID(idx)) {}
			//! deserialize用
			Entry(typename UData::OPValue&& value, ID uid, IDS ids): udata(std::move(value), uid), ids(ids) {}
			operator typename TheType<T>::type () { return *udata.value; }
			operator typename TheType<T>::ctype () const { return *udata.value; }

			bool operator == (const Entry& e) const {
				return udata == e.udata &&
						ids == e.ids;
			}
		};
		using Array = std::vector<Entry, Allocator<Entry>>;
		Array		_array;
		ID			_nFree = 0,		//!< 空きブロック数
					_firstFree;		//!< 最初の空きブロックインデックス
		//! 現在削除処理中かのフラグ
		bool		_bRemoving = false;
		using RemList = std::vector<ID>;
		RemList		_remList;

		friend class boost::serialization::access;
		BOOST_SERIALIZATION_SPLIT_MEMBER();
		template <class Archive>
		void load(Archive& ar, const unsigned int ver) {
			AssertP(Trap, !_bRemoving)
			int nEnt;
			ar & nEnt & _nFree & _firstFree & _remList;
			_array.clear();
			_array.reserve(nEnt);

			typename UData::OPValue value;
			ID uid;
			IDS ids;
			for(int i=0 ; i<nEnt ; i++) {
				// Entryの復元
				ar & value & uid & ids;
				_array.emplace_back(std::move(value), uid, ids);
			}
		}
		template <class Archive>
		void save(Archive& ar, const unsigned int ver) const {
			AssertP(Trap, !_bRemoving)
			ar & static_cast<const int&>(_array.size()) & _nFree & _firstFree & _remList;
			for(auto& p : _array)
				ar & p.udata.value & p.udata.uid & p.ids;
		}

		public:
			using entry_type = Entry;
			using iterator = AdaptItrBase<T, typename Array::iterator>;
			using const_iterator = AdaptItrBase<const T, typename Array::const_iterator>;
			using reverse_iterator = AdaptItrBase<T, std::reverse_iterator<typename Array::iterator>>;
			using const_reverse_iterator = AdaptItrBase<const T, std::reverse_iterator<typename Array::const_iterator>>;

			using id_type = ID;
			noseq_list() {
				static_assert(std::is_integral<IDType>::value, "typename ID should be Integral type");
			}
			noseq_list(noseq_list&& sl): _array(std::forward<noseq_vec<T>>(sl._array)), _nFree(sl._nFree), _firstFree(sl._firstFree) {}

			template <class... Ts>
			ID emplace(Ts&&... ts) {
				return add(T(std::forward<Ts>(ts)...));
			}
			template <class T2>
			ID add(T2&& t) {
				if(_nFree == 0) {
					// 空きが無いので配列の拡張
					ID sz = _array.size();
					_array.emplace_back(std::forward<T2>(t), sz);
					return sz;
				}
				ID ret = _firstFree;					// IDPairを書き込む場所
				ID objI = _array.size() - _nFree;		// ユーザーデータを書き込む場所
				--_nFree;
				auto& objE = _array[objI].udata;
				objE.value = std::forward<T2>(t);		// ユーザーデータの書き込み
				objE.uid = ret;

				auto& idE = _array[ret].ids;
				_firstFree = boost::get<FreeID>(idE);	// フリーリストの先頭を書き換え
				idE = ObjID(objI);						// IDPairの初期化
				return ret;
			}
			void rem(ID uindex) {
				AssertP(Trap, Validation(uindex), "invalid resource number %1%", uindex)
				if(!_bRemoving) {
					_bRemoving = true;

					auto& ids = _array[uindex].ids;
					auto& objI = boost::get<ObjID>(ids);	// 削除対象のnoseqインデックスを受け取る
					ID backI = _array.size()-_nFree-1;
					if(objI != backI) {
						// 最後尾と削除予定の要素を交換
						std::swap(_array[backI].udata, _array[objI].udata);
						// UIDとindex対応の書き換え
						_array[_array[objI].udata.uid].ids = ObjID(objI);
					}
					// 要素を解放
					_array[backI].udata.value = none;
					// フリーリストをつなぎ替える
					ids = FreeID(_firstFree);
					_firstFree = uindex;
					++_nFree;

					_bRemoving = false;
					while(!_remList.empty()) {
						ID tmp = _remList[0];
						_remList.erase(_remList.begin());
						rem(tmp);
					}
				} else
					_remList.push_back(uindex);
			}
			using Ref = decltype(*_array[0].udata.value);
			//! 要素の領域を先に取得
			std::pair<ID,Ref> alloc() {
				ID id = add(UData::OPValue::AsInitialized);
				return std::pair<ID,Ref>(id, get(id));
			}
			Ref get(ID uindex) {
				AssertP(Trap, Validation(uindex), "invalid resource number %1%", uindex)
				ID idx = boost::get<ObjID>(_array[uindex].ids);
				return *_array[idx].udata.value;
			}
			const Ref get(ID uindex) const {
				AssertP(Trap, Validation(uindex), "invalid resource number %1%", uindex)
				return const_cast<noseq_list*>(this)->get(uindex);
			}

			// イテレータの範囲はフリー要素を勘定に入れる
			iterator begin() { return _array.begin(); }
			iterator end() { return _array.end()-_nFree; }
			reverse_iterator rbegin() { return _array.rbegin()+_nFree; }
			reverse_iterator rend() { return _array.rend(); }
			const_iterator cbegin() const { return _array.cbegin(); }
			const_iterator cend() const { return _array.cend()-_nFree; }
			const_iterator begin() const { return _array.begin(); }
			const_iterator end() const { return _array.end()-_nFree; }
			const_reverse_iterator crbegin() const { return const_cast<noseq_list*>(this)->rbegin(); }
			const_reverse_iterator crend() const { return const_cast<noseq_list*>(this)->rend(); }

			//! 主にResMgrから開放時の処理をする為に使用
			template <class CB>
			void iterate(CB cb) {
				int n = _array.size();
				for(int i=0 ; i<n ; i++) {
					auto& ent = _array[i];
					// エントリが有効な場合のみコールバックを呼ぶ
					if(ent.ids.which() == 1) {
						ID id = boost::get<ObjID>(ent.ids);
						cb(_array[id].udata.value);
					}
				}
			}

			size_t size() const {
				return _array.size() - _nFree;
			}
			void clear() {
				_array.clear();
				_nFree = 0;
			}
			bool empty() const {
				return size() == 0;
			}
			//! 主にデバッグ用。内部状態も含めて比較
			bool operator == (const noseq_list& lst) const {
				AssertP(Trap, !_bRemoving)
				return _nFree == lst._nFree &&
						_firstFree == lst._firstFree &&
						_remList == lst._remList &&
						_array == lst._array;
			}
	};
}
namespace boost {
	namespace serialization {
		template <class T, template <class> class Allocator, class IDType, unsigned int MaxID>
		struct version<spn::noseq_list<T, Allocator, IDType, MaxID>> {
			typedef mpl::int_<0> type;
			typedef mpl::integral_c_tag tag;
			BOOST_STATIC_CONSTANT(int, value = version::type::value);
		};
	}
}
<|endoftext|>


<commit_before>#include "MemoryPool.h"
#include "Point2.h"
#include "Vector2.h"
#include "VoronoiDiagramGenerator.h"
#include "RBTree.h"
#include <vector>
#include <ctime>
#include <iostream>
#include "Epsilon.h"

/*************************************************************************************************************/
#define DRAW_TO_WINDOW 0
#if DRAW_TO_WINDOW
	// GLEW
	#define GLEW_STATIC
	#include <GLEW/glew.h>
	// GLFW
	#include <GLFW/glfw3.h>
	// Function prototypes
	void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
	// Window dimensions
	const GLuint WINDOW_WIDTH = 900, WINDOW_HEIGHT = 900;
	// Shaders
	const GLchar* vertexShaderSource =
		"#version 330 core\n"
		"layout (location = 0) in vec3 position;\n"
		"void main()\n"
		"{\n"
		"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
		"}\0";
	const GLchar* fragmentShaderSource =
		"#version 330 core\n"
		"out vec4 color;\n"
		"void main()\n"
		"{\n"
		"color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
		"}\n\0";
	double normalize(double in, int dimension) {
		return in / (float)dimension*1.8 - 0.9;
	}
	//globals for use in giving relaxation commands
	int relax = 0;
	bool startOver = true;
	bool relaxHold = false;
	bool relaxForever = false;
	// Is called whenever a key is pressed/released via GLFW
	void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
		if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
			glfwSetWindowShouldClose(window, GL_TRUE);
		if (key == GLFW_KEY_R && action == GLFW_PRESS)
			++relax;
		if (key == GLFW_KEY_T && action == GLFW_PRESS)
			relax += 10;
		if (key == GLFW_KEY_X && action == GLFW_PRESS)
			startOver = true;
		if (key == GLFW_KEY_H) {
			if (action == GLFW_PRESS)
				relaxHold = true;
			else if (action == GLFW_RELEASE)
				relaxHold = false;
		}
		if (key == GLFW_KEY_J && action == GLFW_PRESS) {
			if (relaxForever) relaxForever = false;
			else relaxForever = true;
		}
	}
#endif
/*************************************************************************************************************/

bool sitesOrdered(const Point2& s1, const Point2& s2) {
	if (s1.y < s2.y)
		return true;
	if (s1.y == s2.y && s1.x < s2.x)
		return true;

	return false;
}

void randomSites(std::vector<Point2>& sites, BoundingBox& bbox, unsigned int dimension, unsigned int numSites) {
	bbox = BoundingBox(0, dimension, dimension, 0);

	Point2 s;

	srand(std::clock());
	for (unsigned int i = 0; i < numSites; ++i) {
		s.x = 1 + (rand() / (double)RAND_MAX)*(dimension - 2);
		s.y = 1 + (rand() / (double)RAND_MAX)*(dimension - 2);
		sites.push_back(s);
	}
}

int main() {
	unsigned int nPoints;
	unsigned int dimension = 20000;
	VoronoiDiagramGenerator vdg = VoronoiDiagramGenerator();
	Diagram* diagram = nullptr;

	std::vector<Point2>* sites;
	std::vector<Point2>* safeSites;
	BoundingBox bbox;

#if !DRAW_TO_WINDOW
	nPoints = 8;
	sites = new std::vector<Point2>();
	safeSites = new std::vector<Point2>();
	randomSites(*sites, bbox, dimension, nPoints);
	std::sort(sites->begin(), sites->end(), sitesOrdered);
	safeSites->push_back((*sites)[0]);
	for (Point2& s : *sites) {
		if (s != safeSites->back())
			safeSites->push_back(s);
	}
	diagram = vdg.compute(*safeSites, bbox);

	while (true) {
		diagram = vdg.relax();
	}
#else
	// Init GLFW
	glfwInit();
	// Set all the required options for GLFW
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
	// Create a GLFWwindow object that we can use for GLFW's functions
	GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Voronoi Diagram Generator", nullptr, nullptr);
	glfwMakeContextCurrent(window);
	// Set the required callback functions
	glfwSetKeyCallback(window, key_callback);
	// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
	glewExperimental = GL_TRUE;
	// Initialize GLEW to setup the OpenGL Function pointers
	glewInit();
	// Define the viewport dimensions
	glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
	// Uncommenting this call will result in wireframe polygons.
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	while (!glfwWindowShouldClose(window)) {
		// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
		glfwPollEvents();

		if (startOver) {
			startOver = false;
			relaxHold = false;
			relaxForever = false;
			relax = 0;
			sites = new std::vector<Point2>();
			safeSites = new std::vector<Point2>();
			std::cin >> nPoints;
			randomSites(*sites, bbox, dimension, nPoints);
			std::sort(sites->begin(), sites->end(), sitesOrdered);
			safeSites->push_back((*sites)[0]);
			int duplicates = -1;
			for (Point2& s : *sites) {
				if (s != safeSites->back()) {
					safeSites->push_back(s);
				}
				else {
					++duplicates;
				}
			}
			diagram = vdg.compute(*safeSites, bbox);
			delete sites;
			delete safeSites;
		}

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glBegin(GL_POINTS);
		for (Cell* c : diagram->cells) {
			Point2& p = c->site.p;
			glVertex3d(normalize(p.x, dimension), -normalize(p.y, dimension), 0.0);
		}
		glEnd();

		for (Edge* e : diagram->edges) {
			if (e->vertA && e->vertB) {
				glBegin(GL_LINES);
				Point2& p1 = *e->vertA;
				Point2& p2 = *e->vertB;

				glVertex3d(normalize(p1[0], dimension), -normalize(p1[1], dimension), 0.0);
				glVertex3d(normalize(p2[0], dimension), -normalize(p2[1], dimension), 0.0);
				glEnd();
			}
		}

		if (relax || relaxHold || relaxForever) {
			diagram = vdg.relax();
			if (diagram->cells.size() != 4) {
				int x = 0;
			}
			--relax;
			if (relax < 0) relax = 0;
		}

		// Swap the screen buffers
		glfwSwapBuffers(window);
	}

	// Terminate GLFW, clearing any resources allocated by GLFW.
	glfwTerminate();
#endif

	delete diagram;
	return 0;
}
<commit_msg>showing andy some stuff<commit_after>#include "MemoryPool.h"
#include "Point2.h"
#include "Vector2.h"
#include "VoronoiDiagramGenerator.h"
#include "RBTree.h"
#include <vector>
#include <ctime>
#include <iostream>
#include "Epsilon.h"

a;sldfij a;sldkfj a;sldfkj a;lskdfkj as;ldfkj as;lkdfkj as;lkdkfj as;lkdk fjdsa

/*************************************************************************************************************/
#define DRAW_TO_WINDOW 0
#if DRAW_TO_WINDOW
	// GLEW
	#define GLEW_STATIC
	#include <GLEW/glew.h>
	// GLFW
	#include <GLFW/glfw3.h>
	// Function prototypes
	void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
	// Window dimensions
	const GLuint WINDOW_WIDTH = 900, WINDOW_HEIGHT = 900;
	// Shaders
	const GLchar* vertexShaderSource =
		"#version 330 core\n"
		"layout (location = 0) in vec3 position;\n"
		"void main()\n"
		"{\n"
		"gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
		"}\0";
	const GLchar* fragmentShaderSource =
		"#version 330 core\n"
		"out vec4 color;\n"
		"void main()\n"
		"{\n"
		"color = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
		"}\n\0";
	double normalize(double in, int dimension) {
		return in / (float)dimension*1.8 - 0.9;
	}
	//globals for use in giving relaxation commands
	int relax = 0;
	bool startOver = true;
	bool relaxHold = false;
	bool relaxForever = false;
	// Is called whenever a key is pressed/released via GLFW
	void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
		if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
			glfwSetWindowShouldClose(window, GL_TRUE);
		if (key == GLFW_KEY_R && action == GLFW_PRESS)
			++relax;
		if (key == GLFW_KEY_T && action == GLFW_PRESS)
			relax += 10;
		if (key == GLFW_KEY_X && action == GLFW_PRESS)
			startOver = true;
		if (key == GLFW_KEY_H) {
			if (action == GLFW_PRESS)
				relaxHold = true;
			else if (action == GLFW_RELEASE)
				relaxHold = false;
		}
		if (key == GLFW_KEY_J && action == GLFW_PRESS) {
			if (relaxForever) relaxForever = false;
			else relaxForever = true;
		}
	}
#endif
/*************************************************************************************************************/

bool sitesOrdered(const Point2& s1, const Point2& s2) {
	if (s1.y < s2.y)
		return true;
	if (s1.y == s2.y && s1.x < s2.x)
		return true;

	return false;
}

void randomSites(std::vector<Point2>& sites, BoundingBox& bbox, unsigned int dimension, unsigned int numSites) {
	bbox = BoundingBox(0, dimension, dimension, 0);

	Point2 s;

	srand(std::clock());
	for (unsigned int i = 0; i < numSites; ++i) {
		s.x = 1 + (rand() / (double)RAND_MAX)*(dimension - 2);
		s.y = 1 + (rand() / (double)RAND_MAX)*(dimension - 2);
		sites.push_back(s);
	}
}

int main() {
	unsigned int nPoints;
	unsigned int dimension = 20000;
	VoronoiDiagramGenerator vdg = VoronoiDiagramGenerator();
	Diagram* diagram = nullptr;

	std::vector<Point2>* sites;
	std::vector<Point2>* safeSites;
	BoundingBox bbox;

#if !DRAW_TO_WINDOW
	nPoints = 8;
	sites = new std::vector<Point2>();
	safeSites = new std::vector<Point2>();
	randomSites(*sites, bbox, dimension, nPoints);
	std::sort(sites->begin(), sites->end(), sitesOrdered);
	safeSites->push_back((*sites)[0]);
	for (Point2& s : *sites) {
		if (s != safeSites->back())
			safeSites->push_back(s);
	}
	diagram = vdg.compute(*safeSites, bbox);

	while (true) {
		diagram = vdg.relax();
	}
#else
	// Init GLFW
	glfwInit();
	// Set all the required options for GLFW
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
	// Create a GLFWwindow object that we can use for GLFW's functions
	GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Voronoi Diagram Generator", nullptr, nullptr);
	glfwMakeContextCurrent(window);
	// Set the required callback functions
	glfwSetKeyCallback(window, key_callback);
	// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
	glewExperimental = GL_TRUE;
	// Initialize GLEW to setup the OpenGL Function pointers
	glewInit();
	// Define the viewport dimensions
	glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
	// Uncommenting this call will result in wireframe polygons.
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	while (!glfwWindowShouldClose(window)) {
		// Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
		glfwPollEvents();

		if (startOver) {
			startOver = false;
			relaxHold = false;
			relaxForever = false;
			relax = 0;
			sites = new std::vector<Point2>();
			safeSites = new std::vector<Point2>();
			std::cin >> nPoints;
			randomSites(*sites, bbox, dimension, nPoints);
			std::sort(sites->begin(), sites->end(), sitesOrdered);
			safeSites->push_back((*sites)[0]);
			int duplicates = -1;
			for (Point2& s : *sites) {
				if (s != safeSites->back()) {
					safeSites->push_back(s);
				}
				else {
					++duplicates;
				}
			}
			diagram = vdg.compute(*safeSites, bbox);
			delete sites;
			delete safeSites;
		}

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glBegin(GL_POINTS);
		for (Cell* c : diagram->cells) {
			Point2& p = c->site.p;
			glVertex3d(normalize(p.x, dimension), -normalize(p.y, dimension), 0.0);
		}
		glEnd();

		for (Edge* e : diagram->edges) {
			if (e->vertA && e->vertB) {
				glBegin(GL_LINES);
				Point2& p1 = *e->vertA;
				Point2& p2 = *e->vertB;

				glVertex3d(normalize(p1[0], dimension), -normalize(p1[1], dimension), 0.0);
				glVertex3d(normalize(p2[0], dimension), -normalize(p2[1], dimension), 0.0);
				glEnd();
			}
		}

		if (relax || relaxHold || relaxForever) {
			diagram = vdg.relax();
			if (diagram->cells.size() != 4) {
				int x = 0;
			}
			--relax;
			if (relax < 0) relax = 0;
		}

		// Swap the screen buffers
		glfwSwapBuffers(window);
	}

	// Terminate GLFW, clearing any resources allocated by GLFW.
	glfwTerminate();
#endif

	delete diagram;
	return 0;
}
<|endoftext|>


<commit_before>/**
 * @file    main.cpp
 * @ingroup sorted-vector
 * @brief   Comparing various implementations of sorted STL containers.
 *
 * Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */

#include <cstdio>
#include <vector>
#include <algorithm>
#include <numeric>

#include "utils/measure.h"
#include "utils/random.h"

/**
 * @brief Store all benchmarks results
 */
struct Results {
    std::vector<time_t> fillingUs;
    std::vector<time_t> copyingUs;
    std::vector<time_t> findingUs;
    std::vector<time_t> insertingUs;
    std::vector<time_t> removingUs;
};

/**
 * @brief Orders in which containers are filled
*/
enum Order {
    eOrderRandom,   ///< Filled with random integers
    eOrderForward,  ///< Filled with ordered random integers
    eOrderReverse   ///< Filled with reverse ordered random integers
};

/**
 * @brief Convert an Order value to its textual description
 */
const char* OrderToString(const Order aOrder) {
    const char* pOrderString = NULL;

    switch (aOrder) {
        case eOrderRandom:  pOrderString = "random";    break;
        case eOrderForward: pOrderString = "forward";   break;
        case eOrderReverse: pOrderString = "reverse";   break;
        default:            pOrderString = "?";         break;
    }

    return pOrderString;
}

/**
 * @brief Generate values in the order specified for the test
 */
template<typename TVal>
void generateValues(const size_t aSize, const Order aOrder, std::vector<TVal>& aValues) {
    TVal value = (TVal)-1;

    aValues.reserve(aSize);
    if (eOrderReverse != aOrder) {
        for (size_t elt = 0;
                    elt < aSize;
                    ++elt) {
            if (eOrderRandom == aOrder) {
                value = (TVal)Utils::Random::gen(5 * aSize);
            } else { // eOrderForward
                value += (TVal)(Utils::Random::gen(1, 10));
            }
            aValues[elt] = value;
        }
    } else { // eOrderReverse
        for (size_t elt = aSize;
                    elt > 0;
                    --elt) {
            value += (TVal)(Utils::Random::gen(1, 10));
            aValues[elt - 1] = value;
        }
    }

    /** TODO(SRombauts)
    for (size_t elt = 0; elt < aSize; ++elt) {
        printf("%u, ", aValues[elt]);
    }
    printf("\n");
    */
}

/**
 * @brief Run each test thousands times
 */
template<typename T>
void runTest(const size_t aSize, const Order aOrder, Results& aResults) {
    using Utils::Measure;

    for (size_t idxTest = 0;
                idxTest < 10000;
                ++idxTest) {
        // Pre-generate random values for the following tests
        std::vector<typename T::value_type> values(aSize);
        generateValues<typename T::value_type>(aSize, aOrder, values);

        T   container;
        ////////////////////////////////////////////////////////////////////////
        // Filling the container with the pre-generated values:
        {
            Measure measure;
            for (size_t idxValue = 0;
                        idxValue < aSize;
                        ++idxValue) {
                container.push_back(values[idxValue]);
            }
            time_t  deltaUs = measure.diff();
            aResults.fillingUs.push_back(deltaUs);
        }

        ////////////////////////////////////////////////////////////////////////
        // Copying the filled container:
        {
            Measure measure;
            T       container2;
            container2 = container;
            time_t  deltaUs = measure.diff();
            aResults.copyingUs.push_back(deltaUs);
        }

        ////////////////////////////////////////////////////////////////////////
        // Finding the pre-generated values in the container:
        {
            Measure measure;
            for (size_t nbFind = 0;
                        nbFind < 1000;
                        ++nbFind) {
                typename T::iterator iValue = std::find(container.begin(),
                                                        container.end(),
                                                        container[nbFind%aSize]);
            }
            time_t  deltaUs = measure.diff();
            aResults.findingUs.push_back(deltaUs);
        }
    }
}

/**
 * @brief Run various benchmarks on different containers
 *
 * (C++11, Boost) * (sizes: 25, 100, 250) * (random, forward, reverse) * (10000 run) :
 * - filling
 * - full copy
 * - 1000 random find
 * - (future) 10 random insertion
 * - (future) 10 random removal
*/
int main() {
    Order tabOrder[] = {eOrderRandom, eOrderForward, eOrderReverse};
    size_t tabSizes[] = {25, 100, 250};

    for (size_t idxSize = 0;
                idxSize < sizeof(tabSizes)/sizeof(tabSizes[0]);
                ++idxSize) {
        size_t size = tabSizes[idxSize];
        for (size_t idxOrder = 0;
                    idxOrder < sizeof(tabOrder)/sizeof(tabOrder[0]);
                    ++idxOrder) {
            Order order = tabOrder[idxOrder];
            printf("%i %s; ", size, OrderToString(order));

            Results results;
            runTest<std::vector<size_t> >(size, order, results);
            time_t  fillingMs   = std::accumulate(results.fillingUs.begin(), results.fillingUs.end(), 0)/1000;
            time_t  copyingMs   = std::accumulate(results.copyingUs.begin(), results.copyingUs.end(), 0)/1000;
            time_t  findingMs   = std::accumulate(results.findingUs.begin(), results.findingUs.end(), 0)/1000;
            time_t  insertingMs = std::accumulate(results.insertingUs.begin(), results.insertingUs.end(), 0)/1000;
            time_t  removingMs  = std::accumulate(results.removingUs.begin(), results.removingUs.end(), 0)/1000;
            printf("%lu;%lu;%lu;%lu;%lu;\n", fillingMs, copyingMs, findingMs, insertingMs, removingMs);
        }
    }

    return 0;
}
<commit_msg>Using a Vector template derived from std::vector<commit_after>/**
 * @file    main.cpp
 * @ingroup sorted-vector
 * @brief   Comparing various implementations of sorted STL containers.
 *
 * Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */

#include <cstdio>
#include <vector>
#include <algorithm>
#include <numeric>

#include "utils/measure.h"
#include "utils/random.h"

/**
 * @brief Store all benchmarks results
 */
struct Results {
    std::vector<time_t> fillingUs;
    std::vector<time_t> copyingUs;
    std::vector<time_t> findingUs;
    std::vector<time_t> insertingUs;
    std::vector<time_t> removingUs;
};

/**
 * @brief Orders in which containers are filled
*/
enum Order {
    eOrderRandom,   ///< Filled with random integers
    eOrderForward,  ///< Filled with ordered random integers
    eOrderReverse   ///< Filled with reverse ordered random integers
};

/**
 * @brief Convert an Order value to its textual description
 */
const char* OrderToString(const Order aOrder) {
    const char* pOrderString = NULL;

    switch (aOrder) {
        case eOrderRandom:  pOrderString = "random";    break;
        case eOrderForward: pOrderString = "forward";   break;
        case eOrderReverse: pOrderString = "reverse";   break;
        default:            pOrderString = "?";         break;
    }

    return pOrderString;
}

/**
 * @brief Generate values in the order specified for the test
 */
void generateValues(const size_t aSize, const Order aOrder, std::vector<size_t>& aValues) {
    size_t value = (size_t)-1;

    aValues.reserve(aSize);
    if (eOrderReverse != aOrder) {
        for (size_t elt = 0;
                    elt < aSize;
                    ++elt) {
            if (eOrderRandom == aOrder) {
                value = (size_t)Utils::Random::gen(5 * aSize);
            } else { // eOrderForward
                value += (size_t)(Utils::Random::gen(1, 10));
            }
            aValues[elt] = value;
        }
    } else { // eOrderReverse
        for (size_t elt = aSize;
                    elt > 0;
                    --elt) {
            value += (size_t)(Utils::Random::gen(1, 10));
            aValues[elt - 1] = value;
        }
    }

    /** TODO(SRombauts)
    for (size_t elt = 0; elt < aSize; ++elt) {
        printf("%u, ", aValues[elt]);
    }
    printf("\n");
    */
}

/**
 * @brief Data index by Id
 */
class Data {
public:
    Data() :
        mId(0) {
    }
    explicit Data(const size_t aId) :
        mId(aId) {
    }
    inline size_t getId() const {
        return mId;
    }
    bool operator==(const Data& aData) const {
        return (aData.getId() == mId);
    }
private:
    size_t  mId;
};

/**
 * @brief Run each test thousands times
 */
template<typename T>
void runTest(const size_t aSize, const Order aOrder, Results& aResults) {
    using Utils::Measure;

    for (size_t idxTest = 0;
                idxTest < 10000;
                ++idxTest) {
        // Pre-generate random values for the following tests
        std::vector<size_t> values(aSize);
        generateValues(aSize, aOrder, values);

        T   container;
        ////////////////////////////////////////////////////////////////////////
        // Filling the container with the pre-generated values:
        {
            Measure measure;
            for (size_t idxValue = 0;
                        idxValue < aSize;
                        ++idxValue) {
                container.push_back(Data(values[idxValue]));
            }
            time_t  deltaUs = measure.diff();
            aResults.fillingUs.push_back(deltaUs);
        }

        ////////////////////////////////////////////////////////////////////////
        // Copying the filled container:
        {
            Measure measure;
            T       container2;
            container2 = container;
            time_t  deltaUs = measure.diff();
            aResults.copyingUs.push_back(deltaUs);
        }

        ////////////////////////////////////////////////////////////////////////
        // Finding the pre-generated values in the container:
        {
            Measure measure;
            for (size_t nbFind = 0;
                        nbFind < 1000;
                        ++nbFind) {
                typename T::iterator iValue = std::find(container.begin(),
                                                        container.end(),
                                                        container[nbFind%aSize]);
            }
            time_t  deltaUs = measure.diff();
            aResults.findingUs.push_back(deltaUs);
        }
    }
}

template<typename T>
class Vector : public std::vector<T> {
};

/*
template<typename T>
class Vector {
public:
//  typedef std::vector<typename T>::iterator  iterator;
    typedef std::vector<T>::iterator  iterator;

    typename std::vector<T>::iterator begin() {
        return mVector.begin();
    }
    typename std::vector<T>::iterator& end() {
        return mVector.end();
    }
    void push_back(const T& aVal) {
        return mVector.push_back(aVal);
    }
private:
    std::vector<T>  mVector;
};
*/

/**
 * @brief Run various benchmarks on different containers
 *
 * (C++11, Boost) * (sizes: 25, 100, 250) * (random, forward, reverse) * (10000 run) :
 * - filling
 * - full copy
 * - 1000 random find
 * - (future) 10 random insertion
 * - (future) 10 random removal
*/
int main() {
    Order tabOrder[] = {eOrderRandom, eOrderForward, eOrderReverse};
    size_t tabSizes[] = {25, 100, 250};

    for (size_t idxSize = 0;
                idxSize < sizeof(tabSizes)/sizeof(tabSizes[0]);
                ++idxSize) {
        size_t size = tabSizes[idxSize];
        for (size_t idxOrder = 0;
                    idxOrder < sizeof(tabOrder)/sizeof(tabOrder[0]);
                    ++idxOrder) {
            Order order = tabOrder[idxOrder];
            printf("%i %s; ", size, OrderToString(order));

            Results results;
            runTest<Vector<Data> >(size, order, results);
            time_t  fillingMs   = std::accumulate(results.fillingUs.begin(), results.fillingUs.end(), 0)/1000;
            time_t  copyingMs   = std::accumulate(results.copyingUs.begin(), results.copyingUs.end(), 0)/1000;
            time_t  findingMs   = std::accumulate(results.findingUs.begin(), results.findingUs.end(), 0)/1000;
            time_t  insertingMs = std::accumulate(results.insertingUs.begin(), results.insertingUs.end(), 0)/1000;
            time_t  removingMs  = std::accumulate(results.removingUs.begin(), results.removingUs.end(), 0)/1000;
            printf("%lu;%lu;%lu;%lu;%lu;\n", fillingMs, copyingMs, findingMs, insertingMs, removingMs);
        }
    }

    return 0;
}
<|endoftext|>