#pragma once

#ifndef UPCA_ARCH_H
#error "Don't include this file directly. Use #include <upca/upca.h>."
#endif

#include <iostream>
#include <memory>
#include <sstream>
#include <string>

#include <gsl/gsl>

#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef JEVENTS_FOUND

#include <inttypes.h>
#include <unistd.h>

#ifdef __cplusplus
extern "C" {
#endif
#include <jevents.h>
#include <rdpmc.h>
#ifdef __cplusplus
}
#endif

#include <linux/perf_event.h>
#include <sys/ioctl.h>

#endif

namespace upca {

std::ostream &operator<<(std::ostream &os, const struct perf_event_attr &c);

namespace arch {
namespace x86_64 {

class x86_64_base_pmu {
public:
  uint64_t timestamp_begin() {
    unsigned high, low;
    __asm__ volatile("CPUID\n\t"
                     "RDTSC\n\t"
                     "mov %%edx, %0\n\t"
                     "mov %%eax, %1\n\t"
                     : "=r"(high), "=r"(low)::"%rax", "%rbx", "%rcx", "%rdx");

    return static_cast<uint64_t>(high) << 32 | low;
  }

  uint64_t timestamp_end() {
    unsigned high, low;
    __asm__ volatile("RDTSCP\n\t"
                     "mov %%edx,%0\n\t"
                     "mov %%eax,%1\n\t"
                     "CPUID\n\t"
                     : "=r"(high), "=r"(low)::"%rax", "%rbx", "%rcx", "%rdx");
    return static_cast<uint64_t>(high) << 32 | low;
  }
};

#ifdef JEVENTS_FOUND

#ifndef __APPLE__

/*
 * SYSCALL_HANDLED(601, pmc_init) int counter, int type, int mode
 * SYSCALL_HANDLED(602, pmc_start)
 * SYSCALL_HANDLED(603, pmc_stop)
 * SYSCALL_HANDLED(604, pmc_reset)
 *
 * Yes, the interface is that fucked up. counter is either int or unsigned long,
 * depending on the syscall …
 */

static inline long mck_pmc_init(int counter, int type, unsigned mode) {
  return syscall(601, counter, type, mode);
}

static inline long mck_pmc_start(unsigned long counter) {
  return syscall(602, counter);
}
static inline long mck_pmc_stop(unsigned long counter) { return syscall(603, counter); }
static inline long mck_pmc_reset(int counter) { return syscall(604, counter); }

static inline int mck_is_mckernel() { return syscall(732) == 0; }

#else

static inline int mck_is_mckernel() { return 0; }

#endif

class resolver {
public:
  resolver();

  struct perf_event_attr resolve(const std::string &name) const;
};

class fd {
  int fd_;

public:
  explicit fd(int fd) : fd_(fd) {}
  fd(std::nullptr_t = nullptr) : fd_(-1) {}
  ~fd() {
    if (fd_ != -1) {
      close(fd_);
    }
  }
  fd(fd &&l) {
    fd_ = l.fd_;
    l.fd_ = -1;
  }
  explicit operator bool() { return fd_ != -1; }
  explicit operator int() { return fd_; }
  friend bool operator==(const fd &l, const fd &r) { return l.fd_ == r.fd_; }
  friend bool operator!=(const fd &l, const fd &r) { return !(l == r); }
};

static inline std::unique_ptr<fd> make_perf_fd(struct perf_event_attr &attr) {
  const int fd = perf_event_open(&attr, 0, -1, -1, 0);

  if (fd < 0) {
    std::ostringstream os;
    os << "perf_event_open() failed: " << errno << strerror(errno) << std::endl;
    throw std::runtime_error(os.str());
  }
  return std::make_unique<class fd>(fd);
}

static uint64_t rdpmc(const uint32_t counter) {
  uint32_t low, high;
  __asm__ volatile("rdpmc" : "=a"(low), "=d"(high) : "c"(counter));
  return static_cast<uint64_t>(high) << 32 | low;
}

enum msrs {
  IA32_PMC_BASE = 0x0c1,
  IA32_PERFEVTSEL_BASE = 0x186,
  IA32_FIXED_CTR_CTRL = 0x38d,
  IA32_PERF_GLOBAL_STATUS = 0x38e,
  IA32_PERF_GLOBAL_CTRL = 0x38f,
  IA32_PERF_GLOBAL_OVF_CTRL = 0x390,
  IA32_PERF_CAPABILITIES = 0x345,
  IA32_DEBUGCTL = 0x1d9,
};

static inline void cpuid(const int code, uint32_t *a, uint32_t *b, uint32_t *c,
                         uint32_t *d) {
  asm volatile("cpuid" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) : "a"(code));
}

#define MASK(v, high, low) ((v >> low) & ((1 << (high - low + 1)) - 1))

template <typename POLICY> static void pmu_info(const POLICY &msr) {
  uint32_t eax, ebx, ecx, edx;

  cpuid(0x1, &eax, &ebx, &ecx, &edx);

  std::cout << std::hex;

  std::cout << "EAX: " << eax << std::endl;
  std::cout << "EBX: " << ebx << std::endl;
  std::cout << "ECX: " << ecx << std::endl;
  std::cout << "EDX: " << edx << std::endl;

  if (ecx & (1 << 15)) {
    const uint64_t caps = msr.rdmsr(IA32_PERF_CAPABILITIES);
    const int vmm_freeze = MASK(caps, 12, 12);
    std::cout << "Caps: " << caps << std::endl;
    std::cout << "VMM Freeze: " << std::boolalpha
              << static_cast<bool>(vmm_freeze) << std::noboolalpha << std::endl;
    if (vmm_freeze) {
      const uint64_t debugctl = msr.rdmsr(IA32_DEBUGCTL);
      msr.wrmsr(IA32_DEBUGCTL, debugctl & ~(1 << 14));
    }
  }

  cpuid(0xa, &eax, &ebx, &ecx, &edx);

  const unsigned version = MASK(eax, 7, 0);
  const unsigned counters = MASK(eax, 15, 8);
  const unsigned width = MASK(eax, 23, 16);

  const unsigned ffpc = MASK(edx, 4, 0);
  const unsigned ff_width = MASK(edx, 12, 5);

  std::cout << "EAX: " << eax << std::endl;
  std::cout << "EBX: " << ebx << std::endl;
  std::cout << "ECX: " << ecx << std::endl;
  std::cout << "EDX: " << edx << std::endl;

  std::cout << std::dec;

  std::cout << "PMC version " << version << std::endl;
  std::cout << "PMC counters: " << counters << std::endl;
  std::cout << "PMC width: " << width << std::endl;

  std::cout << "FFPCs: " << ffpc << ", width: " << ff_width << std::endl;
}

struct x86_pmc_base {
  virtual ~x86_pmc_base();
  virtual gsl::span<uint64_t>::index_type start(gsl::span<uint64_t>) = 0;
  virtual gsl::span<uint64_t>::index_type stop(gsl::span<uint64_t>) = 0;
};

struct mck_mck_policy {
  static long init(const int active, const uint64_t config) {
    return mck_pmc_init(active, gsl::narrow<int>(config), 0x4);
  }

  /* writes MSR_IA32_PMC0 + i to 0 */
  static void reset(const int i) { mck_pmc_reset(i); }
  /* sets and clears bits in MSR_PERF_GLOBAL_CTRL */
  static void start(const unsigned long mask) {
    const auto err = mck_pmc_start(mask);
    if (err) {
      std::cerr << "Error starting PMCs" << std::endl;
    }
  }
  static void stop(const unsigned long mask) {
    const auto err = mck_pmc_stop(mask);
    if (err) {
      std::cerr << "Error stopping PMCs" << std::endl;
    }
  }
  static uint64_t read(const unsigned i) { return rdpmc(i); }
};

class msr_mck {
public:
  msr_mck() {}
  uint64_t rdmsr(const uint32_t reg) const {
    return static_cast<unsigned long>(syscall(850, reg));
  }
  auto wrmsr(const uint32_t reg, const uint64_t val) const {
    /* always returns 0 */
    return syscall(851, reg, val);
  }
};

class msr_linux {
  std::unique_ptr<fd> fd_;

  static unsigned cpu() {
    int cpu = sched_getcpu();
    if (cpu < 0) {
      using namespace std::string_literals;
      throw std::runtime_error("Error getting CPU number: "s + strerror(errno) +
                               " (" + std::to_string(errno) + ")\n");
    }
    /* TODO: check thread affinity mask
     * - has a single CPU
     * - this single CPU is this CPU
     */
    return static_cast<unsigned>(cpu);
  }

public:
  msr_linux()
      : fd_(std::make_unique<fd>(open(
            ("/dev/cpu/" + std::to_string(cpu()) + "/msr").c_str(), O_RDWR))) {}

  uint64_t rdmsr(const uint32_t reg) const {
    uint64_t v;
    const ssize_t ret = pread(static_cast<int>(*fd_), &v, sizeof(v), reg);
    if (ret != sizeof(v)) {
      std::cerr << "Reading MSR " << std::hex << reg << std::dec << " failed."
                << std::endl;
    }
    return v;
  }

  auto wrmsr(const uint32_t reg, const uint64_t val) const {
    const ssize_t ret = pwrite(static_cast<int>(*fd_), &val, sizeof(val), reg);
    if (ret != sizeof(val)) {
      std::cerr << "Writing MSR " << std::hex << reg << std::dec << " failed."
                << std::endl;
    }
    return ret;
  }
};

template <typename MSR> class rawmsr_policy : MSR {
  uint64_t global_ctrl_;

public:
  rawmsr_policy() : global_ctrl_(this->rdmsr(IA32_PERF_GLOBAL_CTRL)) {
    // pmu_info(static_cast<MSR&>(*this));
  }
  ~rawmsr_policy() { this->wrmsr(IA32_PERF_GLOBAL_CTRL, global_ctrl_); }
  int init(const int i, const uint64_t config) {
    const uint64_t v = (1 << 22) | (1 << 16) | config;
    this->wrmsr(IA32_PERFEVTSEL_BASE + static_cast<uint32_t>(i), v);
    return 0;
  }

  void reset(const int i) {
    this->wrmsr(IA32_PMC_BASE + static_cast<uint32_t>(i), 0);
  }
  void start(const unsigned long mask) {
    this->wrmsr(IA32_PERF_GLOBAL_OVF_CTRL, 0);
    this->wrmsr(IA32_PERF_GLOBAL_CTRL, mask);
  }
  void stop(const unsigned long /* mask */) {
    this->wrmsr(IA32_PERF_GLOBAL_CTRL, 0);
    const uint64_t ovf = this->rdmsr(IA32_PERF_GLOBAL_STATUS);
    if (ovf) {
      std::cout << "Overflow: " << std::hex << ovf << std::dec << std::endl;
      this->wrmsr(IA32_PERF_GLOBAL_OVF_CTRL, 0);
    }
  }
  /* Should be equivalent to rdpmc instruction */
  uint64_t read(const unsigned i) { return this->rdmsr(IA32_PMC_BASE + i); }
};

template <typename ACCESS> class msr_pmc final : ACCESS, public x86_pmc_base {
  unsigned long active_mask_ = 0;
  int active = 0;

public:
  using resolver_type = resolver;

  template <typename T> msr_pmc(const T &pmcs) {
    for (const auto &pmc : pmcs) {
      const auto err = ACCESS::init(active, pmc.data().config);
      if (err) {
        std::cerr << "Error configuring PMU " << pmc.name() << " with "
                  << std::hex << pmc.data().config << std::dec << std::endl;
        continue;
      }
      ++active;
    }

    active_mask_ = static_cast<unsigned long>((1 << active) - 1);
  }

  gsl::span<uint64_t>::index_type start(gsl::span<uint64_t>) override {
    for (int i = 0; i < active; ++i) {
      ACCESS::reset(i);
    }
    ACCESS::start(active_mask_);

    return active;
  }

  gsl::span<uint64_t>::index_type stop(gsl::span<uint64_t> buf) override {
    ACCESS::stop(active_mask_);
    for (int i = 0; i < active; ++i) {
      buf[i] = ACCESS::read(static_cast<uint32_t>(i));
    }
    return active;
  }
};

using mck_rawmsr = msr_pmc<rawmsr_policy<msr_mck>>;
using mck_mckmsr = msr_pmc<mck_mck_policy>;
using linux_rawmsr = msr_pmc<rawmsr_policy<msr_linux>>;

class linux_jevents final : public x86_pmc_base {
  struct rdpmc_t {
    struct rdpmc_ctx ctx;
    int close = 0;

    rdpmc_t(struct perf_event_attr attr) {
      const int err = rdpmc_open_attr(&attr, &ctx, nullptr);
      if (err) {
        throw std::runtime_error(std::to_string(errno) + ' ' + strerror(errno));
      }

      close = 1;
    }
    ~rdpmc_t() {
      if (close) {
        rdpmc_close(&ctx);
      }
    }
    rdpmc_t(const rdpmc_t &) = delete;
    rdpmc_t(rdpmc_t &&rhs) {
      this->ctx = rhs.ctx;
      this->close = rhs.close;
      rhs.close = 0;
    }

    uint64_t read() { return rdpmc_read(&ctx); }
  };

  std::vector<rdpmc_t> rdpmc_ctxs;

public:
  using resolver_type = resolver;

  template <typename T> linux_jevents(const T &pmcs) {
    for (const auto &pmc : pmcs) {
      rdpmc_ctxs.emplace_back(pmc.data());
    }
  }

  gsl::span<uint64_t>::index_type start(gsl::span<uint64_t> buf) override {
    int idx = 0;
    for (auto &&pmc : rdpmc_ctxs) {
      buf[idx] = pmc.read();
      ++idx;
    }
    return idx;
  }

  gsl::span<uint64_t>::index_type stop(gsl::span<uint64_t> buf) override {
    int idx = 0;
    for (auto &&pmc : rdpmc_ctxs) {
      buf[idx] = pmc.read() - buf[idx];
      ++idx;
    }
    return idx;
  }
};

class linux_perf final : public x86_pmc_base {
  std::vector<std::unique_ptr<fd>> perf_fds;

public:
  using resolver_type = resolver;

  template <typename T> linux_perf(const T &pmcs) {
    for (const auto &pmc : pmcs) {
      struct perf_event_attr pe;
      memset(&pe, 0, sizeof(pe));
      const auto &attr = pmc.data();
      pe.config = attr.config;
      pe.config1 = attr.config1;
      pe.config2 = attr.config2;
      pe.type = attr.type;
      pe.size = attr.size;
      // attr.disabled = 1;
      pe.exclude_kernel = 1;
      pe.exclude_hv = 1;
      try {
        perf_fds.push_back(make_perf_fd(pe));
      } catch (const std::exception &e) {
        std::cerr << pmc.name() << ": " << e.what() << std::endl;
      }
    }
  }

  gsl::span<uint64_t>::index_type start(gsl::span<uint64_t>) override {
    for (const auto &perf_fd : perf_fds) {
      if (ioctl(static_cast<int>(*perf_fd), PERF_EVENT_IOC_RESET, 0)) {
        std::cerr << "Error in ioctl\n";
      }
    }

    return static_cast<gsl::span<uint64_t>::index_type>(perf_fds.size());
  }

  gsl::span<uint64_t>::index_type stop(gsl::span<uint64_t> buf) override {
    uint64_t v;
    int idx = 0;
    for (const auto &perf_fd : perf_fds) {
      const auto ret = read(static_cast<int>(*perf_fd), &v, sizeof(v));
      if (ret < 0) {
        std::cerr << "perf: Error reading performance counter: " << errno
                  << ": " << strerror(errno) << std::endl;
      } else if (ret != sizeof(v)) {
        std::cerr << "perf: Error reading " << sizeof(v) << " bytes."
                  << std::endl;
      }
      buf[idx] = v;
      ++idx;
    }
    return idx;
  }
};

template <typename MCK, typename LINUX>
class x86_linux_mckernel : public x86_64_base_pmu {
  std::unique_ptr<x86_pmc_base> backend_;

public:
  using resolver_type = resolver;

  template <typename T>
  x86_linux_mckernel(const T &pmcs)
      : backend_(mck_is_mckernel() ? static_cast<std::unique_ptr<x86_pmc_base>>(
                                         std::make_unique<MCK>(pmcs))
                                   : static_cast<std::unique_ptr<x86_pmc_base>>(
                                         std::make_unique<LINUX>(pmcs))) {}

  auto start(gsl::span<uint64_t> o) { return backend_->start(o); }
  auto stop(gsl::span<uint64_t> o) { return backend_->stop(o); }
};

#else

struct Reason {
  static constexpr const char reason[] =
      "PMC support not compiled in; libjevents missing";
};

class x86_64_pmu : public x86_64_base_pmu {
public:
  using resolver_type = upca::arch::detail::null_resolver<Reason>;
  template <typename T> x86_64_pmu(const T &) {}

  gsl::span<uint64_t>::index_type start(gsl::span<uint64_t>) { return 0; }
  gsl::span<uint64_t>::index_type stop(gsl::span<uint64_t>) { return 0; }
};

#endif /* JEVENTS_FOUND */

} // namespace x86_64
} // namespace arch
} // namespace upca


#pragma once
#include <gsl/span>
#include "halley/data_structures/vector.h"
#include "component_schema.h"
#include "custom_type_schema.h"
#include "halley/data_structures/hash_map.h"
#include "halley/text/halleystring.h"
#include "message_schema.h"
#include "system_message_schema.h"
#include "system_schema.h"

namespace YAML
{
	class Node;
}

namespace Halley {
	struct CodegenSourceInfo {
		String filename;
		gsl::span<const gsl::byte> data;
		bool generate = false;
	};

	class Codegen;

    class ECSData {
    public:
		void loadSources(Vector<CodegenSourceInfo> files);

		const HashMap<String, ComponentSchema>& getComponents() const;
		const HashMap<String, SystemSchema>& getSystems() const;
		const HashMap<String, MessageSchema>& getMessages() const;
		const HashMap<String, SystemMessageSchema>& getSystemMessages() const;
		const HashMap<String, CustomTypeSchema>& getCustomTypes() const;

    	void clear();
		int getRevision() const;

	private:
    	void addSource(CodegenSourceInfo sourceInfo);
		void addComponent(YAML::Node rootNode, bool generate);
		void addSystem(YAML::Node rootNode, bool generate);
		void addMessage(YAML::Node rootNode, bool generate);
    	void addSystemMessage(YAML::Node rootNode, bool generate);
		void addType(YAML::Node rootNode);
		String getInclude(String typeName) const;

    	void validate();
		void process();

    	HashMap<String, ComponentSchema> components;
		HashMap<String, SystemSchema> systems;
		HashMap<String, MessageSchema> messages;
    	HashMap<String, SystemMessageSchema> systemMessages;
		HashMap<String, CustomTypeSchema> types;
		int revision = 0;
    };
}


#pragma once

#include <string_view>
#include <gsl/span>
#include <spirv_cross.hpp>

namespace glslang
{
    class TShader;
}

namespace Babylon
{
    class ShaderCompiler
    {
    public:
        ShaderCompiler();
        ~ShaderCompiler();

        struct ShaderInfo
        {
            std::unique_ptr<const spirv_cross::Compiler> Compiler;
            gsl::span<uint8_t> Bytes;
        };

        void Compile(std::string_view vertexSource, std::string_view fragmentSource, std::function<void(ShaderInfo, ShaderInfo)> onCompiled);

    protected:
        // Invert dFdy operands similar to bgfx_shader.sh
        // https://github.com/bkaradzic/bgfx/blob/7be225bf490bb1cd231cfb4abf7e617bf35b59cb/src/bgfx_shader.sh#L44-L45
        // https://github.com/bkaradzic/bgfx/blob/7be225bf490bb1cd231cfb4abf7e617bf35b59cb/src/bgfx_shader.sh#L62-L65
        static void InvertYDerivativeOperands(glslang::TShader& shader);
    };
}


//
//  Engine.hpp
//  PretendToWork
//
//  Created by tqtifnypmb on 14/12/2017.
//  Copyright © 2017 tqtifnypmb. All rights reserved.
//

#pragma once

#include "../rope/Rope.h"
#include "../types.h"
#include "Revision.h"

#include <gsl/gsl>
#include <vector>
#include <map>

namespace brick
{

class Engine {
public:
    using DeltaList = std::vector<Revision>;

    Engine(size_t authorId, gsl::not_null<Rope*> rope);

    template <class Converter>
    void insert(gsl::span<const char> bytes, size_t pos);
    void insert(const detail::CodePointList& cplist, size_t pos);

    void erase(const Range& range);

    std::pair<DeltaList, DeltaList> sync(Engine& other);

    void fastForward(const std::vector<Revision>& revs);

    const std::vector<Revision>& revisions() const {
        return revisions_;
    }

    std::vector<Revision>& revisions() {
        return revisions_;
    }

    size_t authorId() const {
        return authorId_;
    }

    size_t nextRevId() {
        return revId_++;
    }

private:
    Revision delta(const Revision& history, Revision& rev);
    std::vector<Revision> delta(Revision& rev);

    void appendRevision(Revision rev);
    bool appendRevision(Revision rev, bool pendingRev, std::vector<Revision>* deltas);
    std::pair<DeltaList, DeltaList> sync(Engine& other, bool symetric);

    gsl::not_null<Rope*> rope_;
    std::vector<Revision> revisions_;
    std::vector<Revision> pendingRevs_;
    std::map<size_t, std::pair<size_t, size_t>> sync_state_;

    size_t authorId_;
    size_t revId_;
};

template <class Converter>
void Engine::insert(gsl::span<const char> bytes, size_t pos) {
    return insert(Converter::encode(bytes), pos);
}

}   // namespace brick


/* matrix/gsl_matrix_uchar.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_MATRIX_UCHAR_H__
#define __GSL_MATRIX_UCHAR_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_inline.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_vector_uchar.h>
#include <gsl/gsl_blas_types.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

typedef struct
{
  size_t size1;
  size_t size2;
  size_t tda;
  unsigned char * data;
  gsl_block_uchar * block;
  int owner;
} gsl_matrix_uchar;

typedef struct
{
  gsl_matrix_uchar matrix;
} _gsl_matrix_uchar_view;

typedef _gsl_matrix_uchar_view gsl_matrix_uchar_view;

typedef struct
{
  gsl_matrix_uchar matrix;
} _gsl_matrix_uchar_const_view;

typedef const _gsl_matrix_uchar_const_view gsl_matrix_uchar_const_view;

/* Allocation */

GSL_FUN gsl_matrix_uchar *
gsl_matrix_uchar_alloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_uchar *
gsl_matrix_uchar_calloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_uchar *
gsl_matrix_uchar_alloc_from_block (gsl_block_uchar * b,
                                   const size_t offset,
                                   const size_t n1,
                                   const size_t n2,
                                   const size_t d2);

GSL_FUN gsl_matrix_uchar *
gsl_matrix_uchar_alloc_from_matrix (gsl_matrix_uchar * m,
                                    const size_t k1,
                                    const size_t k2,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN gsl_vector_uchar *
gsl_vector_uchar_alloc_row_from_matrix (gsl_matrix_uchar * m,
                                        const size_t i);

GSL_FUN gsl_vector_uchar *
gsl_vector_uchar_alloc_col_from_matrix (gsl_matrix_uchar * m,
                                        const size_t j);

GSL_FUN void gsl_matrix_uchar_free (gsl_matrix_uchar * m);

/* Views */

GSL_FUN _gsl_matrix_uchar_view
gsl_matrix_uchar_submatrix (gsl_matrix_uchar * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_uchar_view
gsl_matrix_uchar_row (gsl_matrix_uchar * m, const size_t i);

GSL_FUN _gsl_vector_uchar_view
gsl_matrix_uchar_column (gsl_matrix_uchar * m, const size_t j);

GSL_FUN _gsl_vector_uchar_view
gsl_matrix_uchar_diagonal (gsl_matrix_uchar * m);

GSL_FUN _gsl_vector_uchar_view
gsl_matrix_uchar_subdiagonal (gsl_matrix_uchar * m, const size_t k);

GSL_FUN _gsl_vector_uchar_view
gsl_matrix_uchar_superdiagonal (gsl_matrix_uchar * m, const size_t k);

GSL_FUN _gsl_vector_uchar_view
gsl_matrix_uchar_subrow (gsl_matrix_uchar * m, const size_t i,
                         const size_t offset, const size_t n);

GSL_FUN _gsl_vector_uchar_view
gsl_matrix_uchar_subcolumn (gsl_matrix_uchar * m, const size_t j,
                            const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_uchar_view
gsl_matrix_uchar_view_array (unsigned char * base,
                             const size_t n1,
                             const size_t n2);

GSL_FUN _gsl_matrix_uchar_view
gsl_matrix_uchar_view_array_with_tda (unsigned char * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

GSL_FUN _gsl_matrix_uchar_view
gsl_matrix_uchar_view_vector (gsl_vector_uchar * v,
                              const size_t n1,
                              const size_t n2);

GSL_FUN _gsl_matrix_uchar_view
gsl_matrix_uchar_view_vector_with_tda (gsl_vector_uchar * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

GSL_FUN _gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_submatrix (const gsl_matrix_uchar * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_uchar_const_view
gsl_matrix_uchar_const_row (const gsl_matrix_uchar * m,
                            const size_t i);

GSL_FUN _gsl_vector_uchar_const_view
gsl_matrix_uchar_const_column (const gsl_matrix_uchar * m,
                               const size_t j);

GSL_FUN _gsl_vector_uchar_const_view
gsl_matrix_uchar_const_diagonal (const gsl_matrix_uchar * m);

GSL_FUN _gsl_vector_uchar_const_view
gsl_matrix_uchar_const_subdiagonal (const gsl_matrix_uchar * m,
                                    const size_t k);

GSL_FUN _gsl_vector_uchar_const_view
gsl_matrix_uchar_const_superdiagonal (const gsl_matrix_uchar * m,
                                      const size_t k);

GSL_FUN _gsl_vector_uchar_const_view
gsl_matrix_uchar_const_subrow (const gsl_matrix_uchar * m, const size_t i,
                               const size_t offset, const size_t n);

GSL_FUN _gsl_vector_uchar_const_view
gsl_matrix_uchar_const_subcolumn (const gsl_matrix_uchar * m, const size_t j,
                                  const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_view_array (const unsigned char * base,
                                   const size_t n1,
                                   const size_t n2);

GSL_FUN _gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_view_array_with_tda (const unsigned char * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

GSL_FUN _gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_view_vector (const gsl_vector_uchar * v,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN _gsl_matrix_uchar_const_view
gsl_matrix_uchar_const_view_vector_with_tda (const gsl_vector_uchar * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

GSL_FUN void gsl_matrix_uchar_set_zero (gsl_matrix_uchar * m);
GSL_FUN void gsl_matrix_uchar_set_identity (gsl_matrix_uchar * m);
GSL_FUN void gsl_matrix_uchar_set_all (gsl_matrix_uchar * m, unsigned char x);

GSL_FUN int gsl_matrix_uchar_fread (FILE * stream, gsl_matrix_uchar * m) ;
GSL_FUN int gsl_matrix_uchar_fwrite (FILE * stream, const gsl_matrix_uchar * m) ;
GSL_FUN int gsl_matrix_uchar_fscanf (FILE * stream, gsl_matrix_uchar * m);
GSL_FUN int gsl_matrix_uchar_fprintf (FILE * stream, const gsl_matrix_uchar * m, const char * format);

GSL_FUN int gsl_matrix_uchar_memcpy(gsl_matrix_uchar * dest, const gsl_matrix_uchar * src);
GSL_FUN int gsl_matrix_uchar_swap(gsl_matrix_uchar * m1, gsl_matrix_uchar * m2);
GSL_FUN int gsl_matrix_uchar_tricpy(CBLAS_UPLO_t Uplo, CBLAS_DIAG_t Diag, gsl_matrix_uchar * dest, const gsl_matrix_uchar * src);

GSL_FUN int gsl_matrix_uchar_swap_rows(gsl_matrix_uchar * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_uchar_swap_columns(gsl_matrix_uchar * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_uchar_swap_rowcol(gsl_matrix_uchar * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_uchar_transpose (gsl_matrix_uchar * m);
GSL_FUN int gsl_matrix_uchar_transpose_memcpy (gsl_matrix_uchar * dest, const gsl_matrix_uchar * src);
GSL_FUN int gsl_matrix_uchar_transpose_tricpy (CBLAS_UPLO_t Uplo_src, CBLAS_DIAG_t Diag, gsl_matrix_uchar * dest, const gsl_matrix_uchar * src);

GSL_FUN unsigned char gsl_matrix_uchar_max (const gsl_matrix_uchar * m);
GSL_FUN unsigned char gsl_matrix_uchar_min (const gsl_matrix_uchar * m);
GSL_FUN void gsl_matrix_uchar_minmax (const gsl_matrix_uchar * m, unsigned char * min_out, unsigned char * max_out);

GSL_FUN void gsl_matrix_uchar_max_index (const gsl_matrix_uchar * m, size_t * imax, size_t *jmax);
GSL_FUN void gsl_matrix_uchar_min_index (const gsl_matrix_uchar * m, size_t * imin, size_t *jmin);
GSL_FUN void gsl_matrix_uchar_minmax_index (const gsl_matrix_uchar * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);

GSL_FUN int gsl_matrix_uchar_equal (const gsl_matrix_uchar * a, const gsl_matrix_uchar * b);

GSL_FUN int gsl_matrix_uchar_isnull (const gsl_matrix_uchar * m);
GSL_FUN int gsl_matrix_uchar_ispos (const gsl_matrix_uchar * m);
GSL_FUN int gsl_matrix_uchar_isneg (const gsl_matrix_uchar * m);
GSL_FUN int gsl_matrix_uchar_isnonneg (const gsl_matrix_uchar * m);

GSL_FUN unsigned char gsl_matrix_uchar_norm1 (const gsl_matrix_uchar * m);

GSL_FUN int gsl_matrix_uchar_add (gsl_matrix_uchar * a, const gsl_matrix_uchar * b);
GSL_FUN int gsl_matrix_uchar_sub (gsl_matrix_uchar * a, const gsl_matrix_uchar * b);
GSL_FUN int gsl_matrix_uchar_mul_elements (gsl_matrix_uchar * a, const gsl_matrix_uchar * b);
GSL_FUN int gsl_matrix_uchar_div_elements (gsl_matrix_uchar * a, const gsl_matrix_uchar * b);
GSL_FUN int gsl_matrix_uchar_scale (gsl_matrix_uchar * a, const double x);
GSL_FUN int gsl_matrix_uchar_scale_rows (gsl_matrix_uchar * a, const gsl_vector_uchar * x);
GSL_FUN int gsl_matrix_uchar_scale_columns (gsl_matrix_uchar * a, const gsl_vector_uchar * x);
GSL_FUN int gsl_matrix_uchar_add_constant (gsl_matrix_uchar * a, const double x);
GSL_FUN int gsl_matrix_uchar_add_diagonal (gsl_matrix_uchar * a, const double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
GSL_FUN int gsl_matrix_uchar_get_row(gsl_vector_uchar * v, const gsl_matrix_uchar * m, const size_t i);
GSL_FUN int gsl_matrix_uchar_get_col(gsl_vector_uchar * v, const gsl_matrix_uchar * m, const size_t j);
GSL_FUN int gsl_matrix_uchar_set_row(gsl_matrix_uchar * m, const size_t i, const gsl_vector_uchar * v);
GSL_FUN int gsl_matrix_uchar_set_col(gsl_matrix_uchar * m, const size_t j, const gsl_vector_uchar * v);
/***********************************************************************/

/* inline functions if you are using GCC */

GSL_FUN INLINE_DECL unsigned char   gsl_matrix_uchar_get(const gsl_matrix_uchar * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL void    gsl_matrix_uchar_set(gsl_matrix_uchar * m, const size_t i, const size_t j, const unsigned char x);
GSL_FUN INLINE_DECL unsigned char * gsl_matrix_uchar_ptr(gsl_matrix_uchar * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL const unsigned char * gsl_matrix_uchar_const_ptr(const gsl_matrix_uchar * m, const size_t i, const size_t j);

#ifdef HAVE_INLINE
INLINE_FUN
unsigned char
gsl_matrix_uchar_get(const gsl_matrix_uchar * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_VAL("first index out of range", GSL_EINVAL, 0) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_VAL("second index out of range", GSL_EINVAL, 0) ;
        }
    }
#endif
  return m->data[i * m->tda + j] ;
}

INLINE_FUN
void
gsl_matrix_uchar_set(gsl_matrix_uchar * m, const size_t i, const size_t j, const unsigned char x)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_VOID("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_VOID("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  m->data[i * m->tda + j] = x ;
}

INLINE_FUN
unsigned char *
gsl_matrix_uchar_ptr(gsl_matrix_uchar * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  return (unsigned char *) (m->data + (i * m->tda + j)) ;
}

INLINE_FUN
const unsigned char *
gsl_matrix_uchar_const_ptr(const gsl_matrix_uchar * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  return (const unsigned char *) (m->data + (i * m->tda + j)) ;
}

#endif

__END_DECLS

#endif /* __GSL_MATRIX_UCHAR_H__ */


#pragma once

#include <gsl/span>

namespace CesiumUtility {
/**
 * @brief This function converts between span types. This function
 * has the same rules with C++ reintepret_cast
 * https://en.cppreference.com/w/cpp/language/reinterpret_cast. So please use it
 * carefully
 */
template <typename To, typename From>
gsl::span<To> reintepretCastSpan(const gsl::span<From>& from) noexcept {
  return gsl::span<To>(
      reinterpret_cast<To*>(from.data()),
      from.size() * sizeof(From) / sizeof(To));
}
} // namespace CesiumUtility


#ifndef IOSLICEMUT_H
#define IOSLICEMUT_H

#include <WinSock2.h>

#include <variant>
#include <gsl/span>

namespace laio {

    template<typename T>
    using Result = std::variant<T, std::exception>;

    namespace net {

        class IoSpanMut {
            WSABUF _raw_wsa_buffer;
        public:
            explicit constexpr IoSpanMut(const WSABUF& wsaBuffer) noexcept
                : _raw_wsa_buffer{wsaBuffer} {}

            explicit constexpr IoSpanMut(WSABUF&& wsaBuffer) noexcept
                : _raw_wsa_buffer{std::move(wsaBuffer)} {}  // NOLINT(hicpp-move-const-arg,performance-move-const-arg)

            static inline IoSpanMut create(unsigned char buf[]) noexcept {
                static_assert(sizeof(*buf) <= (std::numeric_limits<ULONG>::max)());

                // Seriously? Casting an unsigned char to a signed char?
                // Well behaved for all 128 ASCII characters - Blows up for any value lesser than 0 or greater than 127
                return IoSpanMut{std::move(WSABUF{  // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
                    sizeof(*buf),
                    reinterpret_cast<CHAR*>(buf),
                })};
            }

            inline Result<std::monostate> advance(std::size_t n) noexcept {
                if (static_cast<std::size_t>(sizeof(_raw_wsa_buffer.len)) < n) {
                    return std::out_of_range("Advancing out of range");
                }
                _raw_wsa_buffer.len -= static_cast<ULONG>(n);
                _raw_wsa_buffer.buf += n;
                return std::monostate{};
            }

            inline gsl::span<const unsigned char> as_span() noexcept {
                return gsl::span<const unsigned char>{
                    reinterpret_cast<const unsigned char*>(_raw_wsa_buffer.buf),
                    static_cast<int>(_raw_wsa_buffer.len)
                };
            }

            inline gsl::span<unsigned char> as_mut_span() noexcept {
                return gsl::span<unsigned char>{
                    reinterpret_cast<unsigned char*>(_raw_wsa_buffer.buf),
                    static_cast<int>(_raw_wsa_buffer.len)
                };
            }
        };

    } // namespace net

} // namespace laio

#endif // IOSLICEMUT_H


#pragma once
#include "common/to_do.h"
#include "open_file.h"
#include "trees/regular_file.h"
#include <gsl/span>

namespace dogbox::tree
{
    enum class read_caching
    {
        none,
        one_piece
    };

    inline std::ostream &operator<<(std::ostream &out, read_caching const printed)
    {
        switch (printed)
        {
        case read_caching::none:
            return out << "none";
        case read_caching::one_piece:
            return out << "one_piece";
        }
        TO_DO();
    }

    constexpr dogbox::tree::read_caching all_read_caching_modes[] = {
        dogbox::tree::read_caching::none, dogbox::tree::read_caching::one_piece};

    size_t read_file(open_file &file, sqlite3 &database, regular_file::length_type const offset,
                     gsl::span<std::byte> const into, read_caching const caching);
}


#pragma once

#include "text_parser.h"
#include "width_cache.h"

#include <string>
#include <vector>

#include <gsl/span>

namespace terminal_editor {

enum class GraphemeKind {
    NORMAL,      ///< Normal, displayable characters.
    INVALID,     ///< Invalid characters for given encoding.
    REPLACEMENT, ///< Replacement representation of valid (possibly control) characters (such as 4 spaces for tabs, or [NUL] for 0x00).
};

/// Each grapheme represents one logical 'image' on the screen.
/// It can consist of many actual characters (either because we have combining characters, or because we replaced bytes with some special string, like "[CR]").
/// It is produced from one or more bytes in the underlying byte data.
/// It can have a width of 0 or more (either because actual characters take two columns, or because replacement string is longer, like "[x66]" or "[TAB]").
struct Grapheme {
    GraphemeKind kind;    ///< Kind of grapheme: normal grapheme, invalid bytes or replacement.
    std::string rendered; ///< Valid UTF-8 string to display on the screen.
    std::string info;     ///< Valid UTF-8 string. Can contain arbitrary informational text about the grapheme. Will contain error description in case of invalid graphemes.
    int width;            ///< Width (in terminal cells) of the 'rendered' string, once it will be displayed on the terminal.
    gsl::span<const char> consumedInput; ///< Span of input data that was rendered into this grapheme.
};

/// Converts given span of CodePoinInfos into a Grapheme, by concatenating their representations.
/// @param codePoinInfos    A span of CodePoinInfos.
///                         @note If codePoinInfos is empty a NORMAL, but zero width grapheme is returned.
Grapheme renderGrapheme(gsl::span<const CodePointInfo> codePointInfos);

/// CodePointWidthCache used by renderLine().
/// @todo This should not be a gloabl variable.
extern CodePointWidthCache textRendererWidthCache;

/// Renders data into Graphemes.
/// Each byte of invalid CodePointInfos are rendered as separate graphemes.
/// Valid CodePointInfos are grouped into maximal chunks where only first CodePointInfo can have non-zero wcwidth() (after processing replacements). One grapheme is created for
/// each such group.
/// @note Some resulting graphemes can have zero-width.
/// @note Result can be empty.
/// @note Width of characters is computed using global CodePointWidthCache.
/// @param data     Input string to render. It is assumed to be in UTF-8, but can contain invalid characters (which will be rendered as special Graphemes).
///                 @note Any control characters (including new line characters) will be rendered as a replacement string (i.e. [LF]).
std::vector<Grapheme> renderLine(gsl::span<CodePointInfo> codePointInfos);

/// Returns concatenation of rendered property of all graphemes.
/// @param graphemes    Span of graphemes to concatenate.
/// @param useBrackets  If true all invalid and replacement sequences will be enclosed with brackets.
std::string renderGraphemes(gsl::span<const Grapheme> graphemes, bool useBrackets);

/// Returns width of given text after rendering on screen.
/// @note This functions takes into consideration replacement strings, and thus differs from wcswidth().
/// @note This function is very slow, as it needs to convert text to graphemes first.
/// @param text     UTF-8 string, can be invalid.
int getRenderedWidth(gsl::span<const char> text);

/// Returns width of given line of graphemes after rendering on screen.
/// @param graphemes    A span of graphemes.
int getRenderedWidth(gsl::span<const Grapheme> graphemes);

} // namespace terminal_editor


#ifndef TTT_UTIL_UTILITIES_H
#define TTT_UTIL_UTILITIES_H

#include <SDL_keyboard.h>

#include <gsl/util>

namespace ttt::util
{
	// Used to avoid having to cast std::size_t to gsl::index.
	template<typename Container>
	[[nodiscard]] inline gsl::index getSize(const Container &container) noexcept
	{
		return gsl::narrow_cast<gsl::index>(container.size());
	}
}

#endif


/* Copyright (c) 2020 Felix Kutzner (github.com/fkutzner)

 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.

 Except as contained in this notice, the name(s) of the above copyright holders
 shall not be used in advertising or otherwise to promote the sale, use or
 other dealings in this Software without prior written authorization.

*/

#pragma once

#include <libincmonk/verifier/Clause.h>

#include <cassert>
#include <cstdint>
#include <functional>
#include <gsl/span>
#include <iterator>
#include <limits>
#include <optional>
#include <ostream>

//
// Implementation of inline function declared in Clause.h
//

namespace incmonk::verifier {

constexpr Var::Var(uint32_t id) : m_rawValue(id) {}

constexpr Var::Var() : m_rawValue{0} {}

constexpr auto Var::getRawValue() const -> uint32_t
{
  return m_rawValue;
}

constexpr auto Var::operator==(Var rhs) const -> bool
{
  return m_rawValue == rhs.m_rawValue;
}

constexpr auto Var::operator!=(Var rhs) const -> bool
{
  return m_rawValue != rhs.m_rawValue;
}

constexpr auto Var::operator<(Var rhs) const -> bool
{
  return m_rawValue < rhs.m_rawValue;
}

constexpr auto Var::operator<=(Var rhs) const -> bool
{
  return m_rawValue <= rhs.m_rawValue;
}

constexpr auto Var::operator>(Var rhs) const -> bool
{
  return m_rawValue > rhs.m_rawValue;
}

constexpr auto Var::operator>=(Var rhs) const -> bool
{
  return m_rawValue >= rhs.m_rawValue;
}

inline auto operator""_Var(unsigned long long cnfValue) -> Var
{
  return Var{static_cast<uint32_t>(cnfValue)};
}

constexpr auto Key<Var>::get(Var const& item) -> std::size_t
{
  return item.getRawValue();
}

constexpr Lit::Lit(Var v, bool positive) : m_rawValue{(v.getRawValue() << 1) + (positive ? 1 : 0)}
{
}

constexpr Lit::Lit() : m_rawValue{0} {}

constexpr auto Lit::getRawValue() const -> uint32_t
{
  return m_rawValue;
}

constexpr auto Lit::getVar() const -> Var
{
  return Var{m_rawValue >> 1};
}

constexpr auto Lit::isPositive() const -> bool
{
  return (m_rawValue & 1) == 1;
}

constexpr auto Lit::operator-() const -> Lit
{
  return Lit{getVar(), !isPositive()};
}

constexpr auto Lit::operator==(Lit rhs) const -> bool
{
  return m_rawValue == rhs.m_rawValue;
}

constexpr auto Lit::operator!=(Lit rhs) const -> bool
{
  return m_rawValue != rhs.m_rawValue;
}

constexpr auto Lit::operator<(Lit rhs) const -> bool
{
  return m_rawValue < rhs.m_rawValue;
}

constexpr auto Lit::operator<=(Lit rhs) const -> bool
{
  return m_rawValue <= rhs.m_rawValue;
}

constexpr auto Lit::operator>(Lit rhs) const -> bool
{
  return m_rawValue > rhs.m_rawValue;
}

constexpr auto Lit::operator>=(Lit rhs) const -> bool
{
  return m_rawValue >= rhs.m_rawValue;
}

inline auto operator""_Lit(unsigned long long cnfValue) -> Lit
{
  Var var{static_cast<uint32_t>(cnfValue)};
  return Lit{var, cnfValue > 0};
}

constexpr auto Key<Lit>::get(Lit const& item) -> std::size_t
{
  return item.getRawValue();
}

inline auto Clause::operator[](size_type idx) noexcept -> Lit&
{
  return *((&m_firstLit) + idx);
}

inline auto Clause::operator[](size_type idx) const noexcept -> Lit const&
{
  return *((&m_firstLit) + idx);
}

inline auto Clause::getLiterals() noexcept -> gsl::span<Lit>
{
  return gsl::span<Lit>{&m_firstLit, (&m_firstLit) + m_size};
}

inline auto Clause::getLiterals() const noexcept -> gsl::span<Lit const>
{
  return gsl::span<Lit const>{&m_firstLit, (&m_firstLit) + m_size};
}

inline auto Clause::size() const noexcept -> size_type
{
  return m_size;
}

inline auto Clause::empty() const noexcept -> bool
{
  return m_size == 0;
}

inline void Clause::setState(ClauseVerificationState state) noexcept
{
  uint8_t rawState = static_cast<uint8_t>(state);
  m_flags = (m_flags & 0xFFFFFFFC) | rawState;
}

inline auto Clause::getState() const noexcept -> ClauseVerificationState
{
  return static_cast<ClauseVerificationState>(m_flags & 3);
}

inline auto Clause::getAddIdx() const noexcept -> ProofSequenceIdx
{
  return m_pointOfAdd;
}

inline Clause::Clause(size_type size,
                      ClauseVerificationState initialState,
                      ProofSequenceIdx addIdx) noexcept
  : m_size{size}, m_pointOfAdd{addIdx}, m_firstLit{Var{0}, false}
{
  setState(initialState);
}

inline auto ClauseCollection::Ref::operator==(Ref rhs) const noexcept -> bool
{
  return m_offset == rhs.m_offset;
}

inline auto ClauseCollection::Ref::operator!=(Ref rhs) const noexcept -> bool
{
  return !(*this == rhs);
}

inline ClauseCollection::RefIterator::RefIterator(char const* m_allocatorMemory,
                                                  std::size_t highWaterMark) noexcept
  : m_clausePtr{m_allocatorMemory}, m_distanceToEnd{highWaterMark}, m_currentRef{}
{
  if (m_distanceToEnd == 0) {
    m_clausePtr = nullptr;
  }
  // Otherwise, the iterator is valid and currentRef is 0, referring to the first clause
}

inline ClauseCollection::RefIterator::RefIterator() noexcept
  : m_clausePtr{nullptr}, m_distanceToEnd{0}, m_currentRef{}
{
}

inline auto ClauseCollection::RefIterator::operator*() const noexcept -> Ref const&
{
  assert(m_clausePtr != nullptr && "Dereferencing a non-dereferencaable RefIterator");
  return m_currentRef;
}

inline auto ClauseCollection::RefIterator::operator->() const noexcept -> Ref const*
{
  assert(m_clausePtr != nullptr && "Dereferencing a non-dereferencaable RefIterator");
  return &m_currentRef;
}

inline auto ClauseCollection::RefIterator::operator++(int) noexcept -> RefIterator
{
  RefIterator old = *this;
  ++(*this);
  return old;
}

inline auto ClauseCollection::RefIterator::operator==(RefIterator const& rhs) const noexcept -> bool
{
  return (this == &rhs) || (m_clausePtr == nullptr && rhs.m_clausePtr == nullptr) ||
         (m_clausePtr == rhs.m_clausePtr && m_distanceToEnd == rhs.m_distanceToEnd &&
          m_currentRef == rhs.m_currentRef);
}

inline auto ClauseCollection::RefIterator::operator!=(RefIterator const& rhs) const noexcept -> bool
{
  return !(*this == rhs);
}

}

namespace std {
template <>
struct hash<incmonk::verifier::Lit> {
  auto operator()(incmonk::verifier::Lit lit) const noexcept -> std::size_t
  {
    return std::hash<uint32_t>{}(lit.getRawValue());
  }
};

template <>
struct hash<incmonk::verifier::Var> {
  auto operator()(incmonk::verifier::Var var) const noexcept -> std::size_t
  {
    return std::hash<uint32_t>{}(var.getRawValue());
  }
};

template <>
struct hash<incmonk::verifier::ClauseCollection::Ref> {
  auto operator()(incmonk::verifier::ClauseCollection::Ref ref) const noexcept -> std::size_t
  {
    return std::hash<std::size_t>{}(ref.m_offset);
  }
};
}


/*
   Copyright [2021] [IBM Corporation]
   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 _MCAS_COMMON_BYTE_
#define _MCAS_COMMON_BYTE_

#include <cstddef>
#include <gsl/gsl_byte>

#ifndef MCAS_BYTE_USES_STD
/* For compilation with C++14 use gsl::byte, not C++17 std::byte */
#define MCAS_BYTE_USES_STD 0
#endif

namespace common
{
#if MCAS_BYTE_USES_STD
	using byte = std::byte;
#else
	using byte = gsl::byte; /* can be std::byte in C++17 */
#endif
}

#endif


// SPDX-License-Identifier: MIT
// The MIT License (MIT)
//
// Copyright (c) 2014-2018, Institute for Software & Systems Engineering
// Copyright (c) 2018-2019, Johannes Leupolz
//
// 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.

#ifndef PEMC_EXECUTABLE_MODEL_MODEL_EXECUTOR_H_
#define PEMC_EXECUTABLE_MODEL_MODEL_EXECUTOR_H_

#include <vector>
#include <gsl/span>
#include <cstdint>
#include <atomic>
#include <stack>
#include <limits>
#include <functional>

#include "pemc/basic/tsc_index.h"
#include "pemc/basic/configuration.h"
#include "pemc/basic/label.h"
#include "pemc/basic/model_capacity.h"
#include "pemc/basic/raw_memory.h"
#include "pemc/formula/formula.h"
#include "pemc/generic_traverser/i_transitions_calculator.h"
#include "pemc/generic_traverser/i_pre_state_storage_modifier.h"
#include "pemc/generic_traverser/i_post_state_storage_modifier.h"
#include "pemc/executable_model/temporary_state_storage.h"
#include "pemc/executable_model/i_choice_resolver.h"
#include "pemc/executable_model/abstract_model.h"

namespace pemc {

  class ModelExecutor : public ITransitionsCalculator {
  protected:
      std::unique_ptr<IChoiceResolver> choiceResolver;
      std::unique_ptr<AbstractModel> model;

      // Create a storage for different state vectors and a vector of transitions
      // that can be reused for different calculations. This should prevent garbage.
      TemporaryStateStorage temporaryStateStorage;
      std::vector<TraversalTransition> transitions;

      int32_t preStateStorageModifierStateVectorSize = 0;

      void addTransition();
  public:
      ModelExecutor(const Configuration& conf);

      void setModel(std::unique_ptr<AbstractModel> _model);

      void setChoiceResolver(std::unique_ptr<IChoiceResolver> _choiceResolver);

      virtual int32_t getStateVectorSize();

      virtual void setPreStateStorageModifierStateVectorSize(int32_t _preStateStorageModifierStateVectorSize);

      virtual gsl::span<TraversalTransition> calculateInitialTransitions();

      virtual gsl::span<TraversalTransition> calculateTransitionsOfState(gsl::span<gsl::byte> state);

      virtual void* getCustomPayloadOfLastCalculation();

  };

}

#endif  // PEMC_EXECUTABLE_MODEL_MODEL_EXECUTOR_H_


/*	$Id$ */
/*
 * Copyright (c) 2014, 2015 Kristaps Dzonsons <kristaps@kcons.eu>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#ifdef MAC_INTEGRATION
#include <gtkosxapplication.h>
#endif
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_multifit.h>
#include <gsl/gsl_histogram.h>
#include <kplot.h>

#include "extern.h"

static	const char *const inputs[INPUT__MAX] = {
	"uniform",
	"variable",
	"mapped",
};

static	const char *const views[VIEW__MAX] = {
	"times-cdf", /* VIEW_TIMEESCDF */
	"times-pdf", /* VIEW_TIMEESPDF */
	"raw-mean-stddev", /* VIEW_DEV */
	"extinct-incumbent", /* VIEW_EXTI */
	"extinct-incumbent-min-cdf", /* VIEW_EXTIMINCDF */
	"extinct-incumbent-min-pdf", /* VIEW_EXTIMINPDF */
	"extinct-incumbent-min-mean", /* VIEW_EXTIMINS */
	"extinct-mutant", /* VIEW_EXTM */
	"extinct-mutant-max-cdf", /* VIEW_EXTMMAXCDF */
	"extinct-mutant-max-pdf", /* VIEW_EXTMMAXPDF */
	"extinct-mutant-max-mean", /* VIEW_EXTMMAXS */
	"island-mean", /* VIEW_ISLANDMEAN */
	"islander-mean", /* VIEW_ISLANDERMEAN */
	"raw-mean", /* VIEW_MEAN */
	"raw-mean-min-cdf", /* VIEW_MEANMINCDF */
	"raw-mean-min-pdf", /* VIEW_MEANMINPDF */
	"raw-mean-min-history", /* VIEW_MEANMINQ */
	"raw-mean-min-mean", /* VIEW_MEANMINS */
	"fitted-mean", /* VIEW_POLY */
	"fitted-mean-min-cdf", /* VIEW_POLYMINCDF */
	"fitted-mean-min-pdf", /* VIEW_POLYMINPDF */
	"fitted-mean-min-history", /* VIEW_POLYMINQ */
	"fitted-mean-min-mean", /* VIEW_POLYMINS */
	"extinct-mutant-smooth", /* VIEW_SEXTM */
	"extinct-incunmbent-smooth", /* VIEW_SEXTI */
	"raw-mean-smooth", /* VIEW_SMEAN */
};

static void
hwin_init(struct hwin *c, GtkBuilder *b)
{
	GObject		*w;
	gchar		 buf[1024];
	gchar		*bufp;
	GTimeVal	 gt;
	size_t		 nprocs;

	c->maptop[MAPTOP_RECORD] = win_init_toggle(b, "radiobutton10");
	c->maptop[MAPTOP_RAND] = win_init_toggle(b, "radiobutton11");
	c->maptop[MAPTOP_TORUS] = win_init_toggle(b, "radiobutton13");
	c->rangeminlambda = win_init_label(b, "label55");
	c->rangemaxlambda = win_init_label(b, "label52");
	c->rangemeanlambda = win_init_label(b, "label58");
	c->rangeerrorbox = win_init_box(b, "box39");
	c->rangeerror = win_init_label(b, "label74");
	c->rangemin = win_init_label(b, "label43");
	c->rangemax = win_init_label(b, "label41");
	c->rangemean = win_init_label(b, "label45");
	c->rangestatus = win_init_label(b, "label47");
	c->rangefunc = win_init_label(b, "label50");
	c->rangeparms = win_init_label(b, "label72");
	c->buttonrange = win_init_button(b, "button4");
	c->mapindices[MAPINDEX_STRIPED] = win_init_toggle(b, "radiobutton15");
	c->mapindices[MAPINDEX_FIXED] = win_init_toggle(b, "radiobutton16");
	c->mapindexfix = win_init_adjustment(b, "adjustment11");
	c->namefill[NAMEFILL_DATE] = win_init_toggle(b, "radiobutton3");
	c->namefill[NAMEFILL_M] = win_init_toggle(b, "radiobutton4");
	c->namefill[NAMEFILL_T] = win_init_toggle(b, "radiobutton7");
	c->namefill[NAMEFILL_MUTANTS] = win_init_toggle(b, "radiobutton8");
	c->namefill[NAMEFILL_NONE] = win_init_toggle(b, "radiobutton9");
	c->mapbox = win_init_box(b, "box31");
	c->config = win_init_window(b, "window1");
	c->rangefind = win_init_window(b, "window2");
	c->status = win_init_status(b, "statusbar1");
	c->menu = win_init_menubar(b, "menubar1");
	c->mutants[MUTANTS_DISCRETE] = win_init_radio(b, "radiobutton1");
	c->mutants[MUTANTS_GAUSSIAN] = win_init_radio(b, "radiobutton2");
	c->weighted = win_init_toggle(b, "checkbutton1");
	c->menuquit = win_init_menuitem(b, "menuitem5");
	c->input = win_init_label(b, "label19");
	c->mutantsigma = win_init_entry(b, "entry17");
	c->name = win_init_entry(b, "entry16");
	c->stop = win_init_entry(b, "entry9");
	c->xmin = win_init_entry(b, "entry8");
	c->xmax = win_init_entry(b, "entry10");
	c->ymin = win_init_entry(b, "entry18");
	c->ymax = win_init_entry(b, "entry19");
	c->inputs = win_init_notebook(b, "notebook1");
	c->error = win_init_label(b, "label8");
	c->func = win_init_entry(b, "entry2");
	c->smoothing = win_init_adjustment(b, "adjustment10");
	c->nthreads = win_init_adjustment(b, "adjustment3");
	c->fitpoly = win_init_adjustment(b, "adjustment4");
	c->pop = win_init_adjustment(b, "adjustment1");
	c->totalpop = win_init_label(b, "label68");
	c->islands = win_init_adjustment(b, "adjustment2");
	c->ideathmean = win_init_adjustment(b, "adjustment12");
	c->ideathcoef = win_init_entry(b, "entry3");
	c->resprocs = win_init_label(b, "label3");
	c->onprocs = win_init_label(b, "label36");
	c->alpha = win_init_entry(b, "entry13");
	c->delta = win_init_entry(b, "entry14");
	c->migrate[INPUT_UNIFORM] = win_init_entry(b, "entry1");
	c->migrate[INPUT_VARIABLE] = win_init_entry(b, "entry20");
	c->migrate[INPUT_MAPPED] = win_init_entry(b, "entry4");
	c->incumbents = win_init_entry(b, "entry15");
	c->mapfile = win_init_filechoose(b, "filechooserbutton1");
	c->mapmigrants[MAPMIGRANT_UNIFORM] = win_init_toggle(b, "radiobutton5");
	c->mapmigrants[MAPMIGRANT_DISTANCE] = win_init_toggle(b, "radiobutton6");
	c->mapmigrants[MAPMIGRANT_NEAREST] = win_init_toggle(b, "radiobutton12");
	c->mapmigrants[MAPMIGRANT_TWONEAREST] = win_init_toggle(b, "radiobutton14");
	c->maprandislands = win_init_adjustment(b, "adjustment6");
	c->maprandislanders = win_init_adjustment(b, "adjustment7");
	c->maptorusislands = win_init_adjustment(b, "adjustment8");
	c->maptorusislanders = win_init_adjustment(b, "adjustment9");

	gtk_widget_show_all(GTK_WIDGET(c->config));

	/* Hide our error message. */
	gtk_widget_hide(GTK_WIDGET(c->error));

	/* Set the initially-selected notebooks. */
	gtk_label_set_text(c->input, inputs
		[gtk_notebook_get_current_page(c->inputs)]);

	/* XXX: builder doesn't do this. */
	w = gtk_builder_get_object(b, "comboboxtext1");
	gtk_combo_box_set_active(GTK_COMBO_BOX(w), 0);

#if GLIB_CHECK_VERSION(2, 36, 0)
	nprocs = g_get_num_processors();
#else
	nprocs = sysconf(_SC_NPROCESSORS_ONLN);
#endif

	/* Maximum number of processors. */
	gtk_adjustment_set_upper(c->nthreads, nprocs);
	w = gtk_builder_get_object(b, "label12");
	(void)g_snprintf(buf, sizeof(buf), "%zu", nprocs);
	gtk_label_set_text(GTK_LABEL(w), buf);

	/* Compute initial total population. */
	(void)g_snprintf(buf, sizeof(buf),
		"%g", gtk_adjustment_get_value(c->pop) *
		gtk_adjustment_get_value(c->islands));
	gtk_label_set_text(c->totalpop, buf);

	g_get_current_time(&gt);
	bufp = g_time_val_to_iso8601(&gt);
	gtk_entry_set_text(c->name, bufp);
	g_free(bufp);

	/* Hide the rangefinder when we start up. */
	gtk_widget_set_visible(GTK_WIDGET(c->rangefind), FALSE);

#ifdef MAC_INTEGRATION
	gtk_widget_hide(GTK_WIDGET(c->menu));
	gtk_widget_hide(GTK_WIDGET(c->menuquit));
	gtkosx_application_set_menu_bar
		(gtkosx_application_get(),
		 GTK_MENU_SHELL(c->menu));
	gtkosx_application_sync_menubar
		(gtkosx_application_get());
#endif
}

/*
 * Free a given simulation, possibly waiting for the simulation threads
 * to exit.
 * The simulation is presumed to have been set as terminating before
 * running this.
 * Yes, we can wait if the simulation takes a long time between updates.
 */
static void
sim_free(gpointer arg)
{
	struct sim	*p = arg;
	size_t		 i;

	if (NULL == p)
		return;

	g_debug("%p: Freeing simulation", p);

	/*
	 * Join all of our running threads.
	 * They were stopped in the sim_stop function, which was called
	 * before this one.
	 */
	for (i = 0; i < p->nprocs; i++)
		if (NULL != p->threads[i].thread) {
			g_debug("%p: Freeing joining thread "
				"(simulation %p)",
				p->threads[i].thread, p);
			g_thread_join(p->threads[i].thread);
		}
	p->nprocs = 0;

	simbuf_free(p->bufs.means);
	simbuf_free(p->bufs.stddevs);
	simbuf_free(p->bufs.imeans);
	simbuf_free(p->bufs.times);
	simbuf_free(p->bufs.istddevs);
	simbuf_free(p->bufs.islandmeans);
	simbuf_free(p->bufs.islandstddevs);
	simbuf_free(p->bufs.mextinct);
	simbuf_free(p->bufs.iextinct);
	kdata_destroy(p->bufs.fractions);
	kdata_destroy(p->bufs.ifractions);
	kdata_destroy(p->bufs.mutants);
	kdata_destroy(p->bufs.incumbents);
	kdata_destroy(p->bufs.islands);
	kdata_destroy(p->bufs.meanmins);
	kdata_destroy(p->bufs.mextinctmaxs);
	kdata_destroy(p->bufs.iextinctmins);
	kdata_destroy(p->bufs.fitpoly);
	kdata_destroy(p->bufs.fitpolybuf);
	kdata_destroy(p->bufs.fitpolymins);
	kdata_destroy(p->bufs.meanminqbuf);
	kdata_destroy(p->bufs.fitminqbuf);

	hnode_free(p->exp);
	g_mutex_clear(&p->hot.mux);
	g_cond_clear(&p->hot.cond);
	g_free(p->name);
	g_free(p->func);
	if (NULL != p->ms)
		for (i = 0; i < p->islands; i++)
			g_free(p->ms[i]);
	g_free(p->ms);
	g_free(p->pops);
	kml_free(p->kml);
	if (p->fitpoly) {
		g_free(p->work.coeffs);
		gsl_matrix_free(p->work.X);
		gsl_vector_free(p->work.y);
		gsl_vector_free(p->work.w);
		gsl_vector_free(p->work.c);
		gsl_matrix_free(p->work.cov);
		gsl_multifit_linear_free(p->work.work);
		p->fitpoly = 0;
	}
	g_free(p->threads);
	g_free(p);
	g_debug("%p: Simulation freed", p);
}

/*
 * Set a given simulation to stop running.
 * This must be invoked before sim_free() or simulation threads will
 * still be running.
 */
void
sim_stop(gpointer arg, gpointer unused)
{
	struct sim	*p = arg;
	int		 pause;

	if (p->terminate)
		return;
	g_debug("%p: Simulation stopping", p);
	p->terminate = 1;
	g_mutex_lock(&p->hot.mux);
	if (0 != (pause = p->hot.pause)) {
		p->hot.pause = 0;
		g_cond_broadcast(&p->hot.cond);
	}
	g_mutex_unlock(&p->hot.mux);
	if (pause)
		g_debug("%p: Simulation unpausing to stop", p);
}

/*
 * Free up all memory.
 * This can be reentrant (due to gtk-osx's funny handling of
 * termination), so be careful to nullify things so that if recalled it
 * doesn't puke.
 */
static void
bmigrate_free(struct bmigrate *p)
{

	g_debug("%p: Freeing main", p);
	g_list_foreach(p->sims, sim_stop, NULL);
	g_list_free_full(p->sims, sim_free);
	p->sims = NULL;
	hnode_free(p->range.exp);
	p->range.exp = NULL;
	if (NULL != p->status_elapsed)
		g_timer_destroy(p->status_elapsed);
	p->status_elapsed = NULL;
	p->clrsz = 0;
	free(p->clrs);
	p->clrs = NULL;
}

/*
 * Pause or unpause (unset pause and broadcast to condition) a given
 * simulation depending on its current pause status.
 */
static void
on_sim_pause(struct sim *sim, int dopause)
{
	int		 pause = -1;

	g_mutex_lock(&sim->hot.mux);
	if (0 == dopause && sim->hot.pause) {
		sim->hot.pause = pause = 0;
		g_cond_broadcast(&sim->hot.cond);
	} else if (dopause && 0 == sim->hot.pause)
		sim->hot.pause = pause = 1;
	g_mutex_unlock(&sim->hot.mux);

	if (0 == pause && 0 == dopause)
		g_debug("Unpausing simulation %p", sim);
	else if (pause && dopause)
		g_debug("Pausing simulation %p", sim);
}

static void
cqueue_fill(size_t pos, struct kpair *kp, void *arg)
{
	struct cqueue	*q = arg;

	kp->x = -(double)(CQUEUESZ - pos);
	kp->y = q->vals[(q->pos + pos + 1) % CQUEUESZ];
}

static void
cqueue_push(struct cqueue *q, double val)
{

	q->vals[q->pos] = val;
	if (val > q->vals[q->maxpos])
		q->maxpos = q->pos;
	q->pos = (q->pos + 1) % CQUEUESZ;
}

/*
 * This copies data from the threads into local ("cold") storage.
 * It does so by checking whether the threads have copied out of "hot"
 * storage (locking their mutex in the process) and, if so, indicates
 * that we're about to read it (and thus to do so again), then after
 * reading, reset that the data is stale.
 */
static gboolean
on_sim_copyout(gpointer dat)
{
	struct bmigrate	*b = dat;
	GList		*list, *w, *sims;
	ssize_t		 pos;
	struct kpair	 kp;
	struct sim	*sim;
	struct curwin	*cur;
	int		 copy, rc;

	for (list = b->sims; NULL != list; list = g_list_next(list)) {
		sim = list->data;
		if (0 == sim->nprocs)
			continue;
		/*
		 * Instruct the simulation to copy out its data into warm
		 * storage.
		 * If it hasn't already done so, then don't copy into
		 * cold storage, as nothing has changed.
		 */
		g_mutex_lock(&sim->hot.mux);
		copy = 0 == sim->hot.copyout;
		g_mutex_unlock(&sim->hot.mux);

		if ( ! copy)
			continue;

		/*
		 * Don't copy stale data.
		 * Trigger the simulation to copy-out when it gets a
		 * chance.
		 */
		if (sim->cold.truns == sim->warm.truns) {
			assert(sim->cold.tgens == sim->warm.tgens);
			g_mutex_lock(&sim->hot.mux);
			g_assert(0 == sim->hot.copyout);
			sim->hot.copyout = 1;
			g_mutex_unlock(&sim->hot.mux);
			continue;
		}

		/*
		 * Since we're updating this particular simulation, make
		 * sure that all windows tied to this simulation are
		 * also going to be redrawn when the redrawer is called.
		 */
		for (w = b->windows ; w != NULL; w = w->next) {
			cur = w->data;
			sims = cur->sims;
			g_assert(NULL != sims);
			for ( ; NULL != sims; sims = sims->next)
				if (sim == sims->data) {
					cur->redraw = 1;
					break;
				}
		}

		/* Most strutures we simply copy over. */
		simbuf_copy_cold(sim->bufs.times);
		simbuf_copy_cold(sim->bufs.imeans);
		simbuf_copy_cold(sim->bufs.istddevs);
		simbuf_copy_cold(sim->bufs.islandmeans);
		simbuf_copy_cold(sim->bufs.islandstddevs);
		simbuf_copy_cold(sim->bufs.means);
		simbuf_copy_cold(sim->bufs.stddevs);
		simbuf_copy_cold(sim->bufs.mextinct);
		simbuf_copy_cold(sim->bufs.iextinct);
		rc = kdata_buffer_copy
			(sim->bufs.fitpolybuf,
			 sim->bufs.fitpoly);
		g_assert(0 != rc);

		sim->cold.truns = sim->warm.truns;
		sim->cold.tgens = sim->warm.tgens;

		pos = kdata_ymin(sim->bufs.means->cold, &kp);
		g_assert(pos >= 0);
		kdata_array_add(sim->bufs.meanmins, pos, 1.0);
		cqueue_push(&sim->bufs.meanminq, kp.x);
		kdata_array_fill(sim->bufs.meanminqbuf,
			&sim->bufs.meanminq, cqueue_fill);

		kdata_array_add(sim->bufs.mextinctmaxs,
			kdata_ymax(sim->bufs.mextinct->cold, NULL), 1.0);

		kdata_array_add(sim->bufs.iextinctmins,
			kdata_ymin(sim->bufs.iextinct->cold, NULL), 1.0);

		pos = kdata_ymin(sim->bufs.fitpolybuf, &kp);
		g_assert(pos >= 0);
		kdata_array_add(sim->bufs.fitpolymins, pos, 1.0);
		cqueue_push(&sim->bufs.fitminq, kp.x);
		kdata_array_fill(sim->bufs.fitminqbuf,
			&sim->bufs.fitminq, cqueue_fill);

		/* Copy-out when convenient. */
		g_mutex_lock(&sim->hot.mux);
		g_assert(0 == sim->hot.copyout);
		sim->hot.copyout = 1;
		g_mutex_unlock(&sim->hot.mux);
	}

	return(TRUE);
}

static gboolean
on_sim_autosave(gpointer dat)
{
	struct bmigrate	*b = dat;
	struct curwin	*cur;
	GList		*l;
	GtkWidget	*dialog;
	enum view	 sv, view;
	gchar		*file;
	int		 rc;

	for (l = b->windows; l != NULL; l = l->next) {
		cur = l->data;
		if (NULL == cur->autosave)
			continue;
		sv = cur->view;
		for (view = 0; view < VIEW__MAX; view++) {
			file = g_strdup_printf
				("%s" G_DIR_SEPARATOR_S "%s.pdf",
				 cur->autosave, views[view]);
			cur->view = view;
			rc = save(file, cur);
			g_free(file);
			if (0 == rc)
				break;
		}
		cur->view = sv;
		if (view != VIEW__MAX)
			break;
		file = g_strdup_printf("%s"
			G_DIR_SEPARATOR_S "README.txt",
			cur->autosave);
		rc = saveconfig(file, cur);
		g_free(file);
		if (0 == rc)
			break;
	}
	if (NULL == l)
		return(TRUE);

	dialog = gtk_message_dialog_new
		(GTK_WINDOW(cur->wins.window),
		 GTK_DIALOG_DESTROY_WITH_PARENT,
		 GTK_MESSAGE_ERROR,
		 GTK_BUTTONS_CLOSE,
		 "Error auto-saving: %s",
		 strerror(errno));
	gtk_dialog_run(GTK_DIALOG(dialog));
	gtk_widget_destroy(dialog);
	g_free(cur->autosave);
	cur->autosave = NULL;
	gtk_widget_hide(GTK_WIDGET
		(cur->wins.menuunautoexport));
	gtk_widget_show(GTK_WIDGET
		(cur->wins.menuautoexport));
	return(TRUE);
}

static void
on_win_redraw(struct curwin *cur)
{
	GList		*l;
	struct sim	*sim;
	size_t		 i;
	int		 rc;

	for (i = 0, l = cur->sims; NULL != l; l = g_list_next(l), i++) {
		sim = l->data;
		rc = kdata_vector_set(cur->winmean, i, i,
			kdata_pmfmean(sim->bufs.meanmins));
		g_assert(0 != rc);
		rc = kdata_vector_set(cur->winstddev, i, i,
			kdata_pmfstddev(sim->bufs.meanmins));
		g_assert(0 != rc);
		rc = kdata_vector_set(cur->winfitmean, i, i,
			kdata_pmfmean(sim->bufs.fitpolymins));
		g_assert(0 != rc);
		rc = kdata_vector_set(cur->winfitstddev, i, i,
			kdata_pmfstddev(sim->bufs.fitpolymins));
		g_assert(0 != rc);
		rc = kdata_vector_set(cur->winmextinctmean, i, i,
			kdata_pmfmean(sim->bufs.mextinctmaxs));
		g_assert(0 != rc);
		rc = kdata_vector_set(cur->winmextinctstddev, i, i,
			kdata_pmfstddev(sim->bufs.mextinctmaxs));
		g_assert(0 != rc);
		rc = kdata_vector_set(cur->winiextinctmean, i, i,
			kdata_pmfmean(sim->bufs.iextinctmins));
		g_assert(0 != rc);
		rc = kdata_vector_set(cur->winiextinctstddev, i, i,
			kdata_pmfstddev(sim->bufs.iextinctmins));
		g_assert(0 != rc);
	}

	gtk_widget_queue_draw(GTK_WIDGET(cur->wins.window));
}

/*
 * Run this fairly often to see if we need to join any worker threads.
 * Worker threads are joined when they have zero references are in the
 * terminating state.
 */
static gboolean
on_sim_timer(gpointer dat)
{
	struct bmigrate	*b = dat;
	struct sim	*sim;
	gchar		 buf[1024];
	GList		*list;
	uint64_t	 runs;
	size_t		 i, onprocs, resprocs;
	double		 elapsed;

	onprocs = resprocs = runs = 0;
	for (list = b->sims; NULL != list; list = g_list_next(list)) {
		sim = (struct sim *)list->data;
		runs += sim->cold.tgens;
		/*
		 * If "terminate" is set, then the thread is (or already
		 * did finish) exiting, so wait for it.
		 * If we wait, it should take only a very small while.
		 */
		if (sim->terminate && sim->nprocs > 0) {
			for (i = 0; i < sim->nprocs; i++)  {
				if (NULL == sim->threads[i].thread)
					continue;
				g_debug("%p: Timeout handler joining "
					"thread (simulation %p)",
					sim->threads[i].thread, sim);
				g_thread_join(sim->threads[i].thread);
				sim->threads[i].thread = NULL;
			}
			sim->nprocs = 0;
			assert(0 == sim->refs);
		} else if ( ! sim->terminate && ! sim->hot.pause) {
			onprocs += sim->nprocs;
			resprocs += sim->nprocs;
		} else if ( ! sim->terminate)
			resprocs += sim->nprocs;
	}

	/*
	 * Remind us of how many threads we're running.
	 * FIXME: this shows the number of allocated threads, not
	 * necessarily the number of running threads.
	 */
	(void)g_snprintf(buf, sizeof(buf), "%zu", resprocs);
	gtk_label_set_text(b->wins.resprocs, buf);

	(void)g_snprintf(buf, sizeof(buf), "%zu", onprocs);
	gtk_label_set_text(b->wins.onprocs, buf);

	/*
	 * Tell us how many generations have transpired (if no time has
	 * elapsed, then make sure we don't divide by zero).
	 * Then update the status bar.
	 * This will in turn redraw that window portion.
	 */
	elapsed = g_timer_elapsed(b->status_elapsed, NULL);
	if (0.0 == elapsed)
		elapsed = DBL_MIN;
	(void)g_snprintf(buf, sizeof(buf),
		"Running %.0f generations/second.",
		(runs - b->lastmatches) / elapsed);
	gtk_statusbar_pop(b->wins.status, 0);
	gtk_statusbar_push(b->wins.status, 0, buf);
	g_timer_start(b->status_elapsed);
	b->lastmatches = runs;

	/*
	 * Conditionally update our windows.
	 * We do this by iterating through all simulation windows and
	 * seeing if they have the "update" flag set to true.
	 */
	for (list = b->windows; list != NULL; list = list->next)
		if (((struct curwin *)list->data)->redraw)
			on_win_redraw(list->data);

	return(TRUE);
}

gboolean
onfocussim(GtkWidget *w, GdkEvent *event, gpointer dat)
{
#ifdef MAC_INTEGRATION
	struct curwin	  *c = dat;

	gtkosx_application_set_menu_bar
		(gtkosx_application_get(),
		 GTK_MENU_SHELL(c->wins.menu));
	gtkosx_application_sync_menubar
		(gtkosx_application_get());
#endif
	return(TRUE);
}

gboolean
onfocusmain(GtkWidget *w, GdkEvent *event, gpointer dat)
{
#ifdef MAC_INTEGRATION
	struct bmigrate	  *b = dat;

	gtkosx_application_set_menu_bar
		(gtkosx_application_get(),
		 GTK_MENU_SHELL(b->wins.menu));
	gtkosx_application_sync_menubar
		(gtkosx_application_get());
#endif
	return(TRUE);
}

gboolean
ondraw(GtkWidget *w, cairo_t *cr, gpointer dat)
{

	draw(w, cr, dat);
	return(TRUE);
}

void
onunautoexport(GtkMenuItem *menuitem, gpointer dat)
{
	struct curwin	*cur = dat;

	g_assert(NULL != cur->autosave);
	g_debug("Disabling auto-exporting: %s", cur->autosave);
	g_free(cur->autosave);
	cur->autosave = NULL;
	gtk_widget_show(GTK_WIDGET(cur->wins.menuautoexport));
	gtk_widget_hide(GTK_WIDGET(cur->wins.menuunautoexport));
}

void
onautoexport(GtkMenuItem *menuitem, gpointer dat)
{
	GtkWidget	*dialog;
	gint		 res;
	struct curwin	*cur = dat;
	GtkFileChooser	*chooser;

	g_assert(NULL == cur->autosave);
	dialog = gtk_file_chooser_dialog_new
		("Create Data Folder", cur->wins.window,
		 GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER,
		 "_Cancel", GTK_RESPONSE_CANCEL,
		 "_Create", GTK_RESPONSE_ACCEPT, NULL);
	chooser = GTK_FILE_CHOOSER(dialog);
	gtk_file_chooser_set_current_name(chooser, "bmigrate");
	res = gtk_dialog_run(GTK_DIALOG(dialog));
	if (res != GTK_RESPONSE_ACCEPT) {
		gtk_widget_destroy(dialog);
		return;
	}
	cur->autosave = gtk_file_chooser_get_filename(chooser);
	gtk_widget_destroy(dialog);
	gtk_widget_hide(GTK_WIDGET(cur->wins.menuautoexport));
	gtk_widget_show(GTK_WIDGET(cur->wins.menuunautoexport));
	g_debug("Auto-exporting: %s", cur->autosave);
	g_mkdir_with_parents(cur->autosave, 0755);
}

/*
 * Toggle a different view of the current window.
 */
void
onviewtoggle(GtkMenuItem *menuitem, gpointer dat)
{
	struct curwin	*cur = dat;

	/*
	 * First, set the "view" indicator to be the current view as
	 * found in the drop-down menu.
	 */
	for (cur->view = 0; cur->view < VIEW__MAX; cur->view++)
		if (gtk_check_menu_item_get_active
			(cur->wins.views[cur->view]))
			break;
	/*
	 * Next, set the window name to be the label associated with the
	 * respective menu check item.
	 */
	g_assert(cur->view < VIEW__MAX);
	gtk_window_set_title(GTK_WINDOW(cur->wins.window),
		gtk_menu_item_get_label
		(GTK_MENU_ITEM(cur->wins.views[cur->view])));

	/* Redraw the window. */
	gtk_widget_queue_draw(GTK_WIDGET(cur->wins.window));
}

/*
 * Pause all simulations connect to a view.
 */
void
onpause(GtkMenuItem *menuitem, gpointer dat)
{
	GList		*l;
	struct curwin	*cur = dat;

	for (l = cur->sims; NULL != l; l = l->next)
		on_sim_pause(l->data, 1);
}

/*
 * Unpause all simulations connect to a view.
 */
void
onunpause(GtkMenuItem *menuitem, gpointer dat)
{
	struct curwin	*cur = dat;
	GList		*l;

	for (l = cur->sims ; NULL != l; l = l->next)
		on_sim_pause(l->data, 0);
}

gboolean
onrangedelete(GtkWidget *widget, GdkEvent *event, gpointer dat)
{
	struct bmigrate	*b = dat;

	gtk_widget_set_visible
		(GTK_WIDGET(b->wins.rangefind), FALSE);

	if (b->rangeid > 0) {
		g_debug("Disabling rangefinder (user request)");
		g_source_remove(b->rangeid);
		b->rangeid = 0;
	} else
		g_debug("Rangefinder already disabled (user request)");

	return(TRUE);
}

void
onrangeclose(GtkButton *button, gpointer dat)
{
	struct bmigrate	*b = dat;

	gtk_widget_set_visible
		(GTK_WIDGET(b->wins.rangefind), FALSE);

	if (b->rangeid > 0) {
		g_debug("Disabling rangefinder (user request)");
		g_source_remove(b->rangeid);
		b->rangeid = 0;
	} else
		g_debug("Rangefinder already disabled (user request)");
}

/*
 * One of the preset continuum functions for our continuum game
 * possibility.
 */
void
onpreset(GtkComboBox *widget, gpointer dat)
{
	struct bmigrate	*b = dat;

	switch (gtk_combo_box_get_active(widget)) {
	case (1):
		/* Tullock */
		gtk_entry_set_text(b->wins.func,
			"x * (1 / X) - x");
		break;
	case (2):
		/* Cournot */
		gtk_entry_set_text(b->wins.func, "(1 - X) * x");
		break;
	case (3):
		/* Exponential Public Goods */
		gtk_entry_set_text(b->wins.func,
			"(1 - exp(-X)) - x");
		break;
	case (4):
		/* Quadratic Public Goods */
		gtk_entry_set_text(b->wins.func,
			"sqrt(1 / n * X) - 0.5 * x^2");
		break;
	default:
		gtk_entry_set_text(b->wins.func, "");
		break;
	}
}

static void
on_totalpop(struct bmigrate *b, gint pnum)
{
	GList		*l, *cl, *sv;
	gchar	 	 buf[32];
	double		 v = 0.0;
	enum maptop	 maptop;
	struct kml	*kml;
	struct kmlplace	*kmlp;
	gchar		*file;

	switch (pnum) {
	case (INPUT_UNIFORM):
		gtk_label_set_text(b->wins.input, "uniform");
		v = gtk_adjustment_get_value(b->wins.pop) *
			gtk_adjustment_get_value(b->wins.islands);
		break;
	case (INPUT_VARIABLE):
		gtk_label_set_text(b->wins.input, "variable");
		l = sv = gtk_container_get_children
			(GTK_CONTAINER(b->wins.mapbox));
		for (; NULL != l; l = g_list_next(l)) {
			cl = gtk_container_get_children
				(GTK_CONTAINER(l->data));
			v += gtk_spin_button_get_value_as_int
				(GTK_SPIN_BUTTON(g_list_next(cl)->data));
			g_list_free(cl);
		}
		g_list_free(sv);
		break;
	case (INPUT_MAPPED):
		for (maptop = 0; maptop < MAPTOP__MAX; maptop++)
			if (gtk_toggle_button_get_active
				 (b->wins.maptop[maptop]))
				break;
		switch (maptop) {
		case (MAPTOP_RECORD):
			gtk_label_set_text(b->wins.input,
				"KML islands");
			file = gtk_file_chooser_get_filename
				(b->wins.mapfile);
			if (NULL == file)
				break;
			kml = kml_parse(file, NULL);
			if (NULL == kml)
				break;
			l = kml->kmls;
			for ( ; NULL != l; l = g_list_next(l)) {
				kmlp = l->data;
				v += kmlp->pop;
			}
			kml_free(kml);
			break;
		case (MAPTOP_RAND):
			gtk_label_set_text(b->wins.input,
				"random islands");
			v = gtk_adjustment_get_value
				(b->wins.maprandislands) *
				gtk_adjustment_get_value
				(b->wins.maprandislanders);
			break;
		case (MAPTOP_TORUS):
			gtk_label_set_text(b->wins.input,
				"toroidal islands");
			v = gtk_adjustment_get_value
				(b->wins.maptorusislands) *
				gtk_adjustment_get_value
				(b->wins.maptorusislanders);
			break;
		default:
			abort();
		}
		break;
	default:
		abort();
	}

	g_snprintf(buf, sizeof(buf), "%g", v);
	gtk_label_set_text(b->wins.totalpop, buf);
}

void
on_change_input(GtkNotebook *notebook,
	GtkWidget *page, gint pnum, gpointer dat)
{

	on_totalpop(dat, pnum);
}

void
on_change_mapfile(GtkFileChooserButton *widget, gpointer dat)
{
	struct bmigrate	*b = dat;

	on_totalpop(b, gtk_notebook_get_current_page(b->wins.inputs));
}

void
on_change_maptype(GtkToggleButton *togglebutton, gpointer dat)
{
	struct bmigrate	*b = dat;

	on_totalpop(b, gtk_notebook_get_current_page(b->wins.inputs));
}

void
on_change_totalpop(GtkSpinButton *spinbutton, gpointer dat)
{
	struct bmigrate	*b = dat;

	on_totalpop(b, gtk_notebook_get_current_page(b->wins.inputs));
}

void
onsaveall(GtkMenuItem *menuitem, gpointer dat)
{
	struct curwin	*cur = dat;
	GtkWidget	*dialog;
	gint		 res;
	GtkFileChooser	*chooser;
	char 		*dir, *file;
	enum view	 view, sv;
	int		 rc;

	dialog = gtk_file_chooser_dialog_new
		("Create View Data Folder", cur->wins.window,
		 GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER,
		 "_Cancel", GTK_RESPONSE_CANCEL,
		 "_Create", GTK_RESPONSE_ACCEPT, NULL);

	chooser = GTK_FILE_CHOOSER(dialog);
	gtk_file_chooser_set_current_name(chooser, "bmigrate");
	res = gtk_dialog_run(GTK_DIALOG(dialog));
	if (res != GTK_RESPONSE_ACCEPT) {
		gtk_widget_destroy(dialog);
		return;
	}
	dir = gtk_file_chooser_get_filename(chooser);
	gtk_widget_destroy(dialog);
	g_assert(NULL != dir);
	g_assert('\0' != *dir);

	sv = cur->view;
	for (view = 0; view < VIEW__MAX; view++) {
		file = g_strdup_printf
			("%s" G_DIR_SEPARATOR_S "%s.pdf",
			 dir, views[view]);
		cur->view = view;
		rc = save(file, cur);
		g_free(file);
		if (0 == rc)
			break;
	}
	cur->view = sv;
	if (view == VIEW__MAX) {
		file = g_strdup_printf("%s"
			G_DIR_SEPARATOR_S "README.txt", dir);
		if (0 == (rc = saveconfig(file, cur)))
			view = 0;
		g_free(file);
	}
	g_free(dir);
	if (view == VIEW__MAX)
		return;
	dialog = gtk_message_dialog_new
		(GTK_WINDOW(cur->wins.window),
		 GTK_DIALOG_DESTROY_WITH_PARENT,
		 GTK_MESSAGE_ERROR,
		 GTK_BUTTONS_CLOSE,
		 "Error saving: %s",
		 strerror(errno));
	gtk_dialog_run(GTK_DIALOG(dialog));
	gtk_widget_destroy(dialog);
}

void
onsave(GtkMenuItem *menuitem, gpointer dat)
{
	struct curwin	*cur = dat;
	GtkWidget	*dialog;
	gint		 res;
	GtkFileChooser	*chooser;
	int		 rc;
	char 		*file;

	dialog = gtk_file_chooser_dialog_new
		("Save View Data", cur->wins.window,
		 GTK_FILE_CHOOSER_ACTION_SAVE,
		 "_Cancel", GTK_RESPONSE_CANCEL,
		 "_Save", GTK_RESPONSE_ACCEPT, NULL);
	chooser = GTK_FILE_CHOOSER(dialog);
	gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
	gtk_file_chooser_set_current_name(chooser, "bmigrate.pdf");
	res = gtk_dialog_run(GTK_DIALOG(dialog));
	if (res != GTK_RESPONSE_ACCEPT) {
		gtk_widget_destroy(dialog);
		return;
	}
	file = gtk_file_chooser_get_filename(chooser);
	gtk_widget_destroy(dialog);
	g_assert(NULL != file);
	g_assert('\0' != *file);
	rc = save(file, cur);
	g_free(file);
	if (0 != rc)
		return;
	dialog = gtk_message_dialog_new
		(GTK_WINDOW(cur->wins.window),
		 GTK_DIALOG_DESTROY_WITH_PARENT,
		 GTK_MESSAGE_ERROR,
		 GTK_BUTTONS_CLOSE,
		 "Error saving: %s",
		 strerror(errno));
	gtk_dialog_run(GTK_DIALOG(dialog));
	gtk_widget_destroy(dialog);
}

#ifdef MAC_INTEGRATION
gboolean
onterminate(GtkosxApplication *action, gpointer dat)
{

	bmigrate_free(dat);
	gtk_main_quit();
	return(FALSE);
}
#endif

/*
 * Run when we quit from a simulation window.
 */
void
onclose(GtkMenuItem *menuitem, gpointer dat)
{
	struct curwin	*cur = dat;

	g_debug("Simulation window closing");
	gtk_widget_destroy(GTK_WIDGET(cur->wins.window));
}

/*
 * Run when we quit from a simulation window.
 */
void
onquitsim(GtkMenuItem *menuitem, gpointer dat)
{
	struct curwin	*cur = dat;

	bmigrate_free(cur->b);
	gtk_main_quit();
}

/*
 * Run when we quit from a simulation window.
 */
void
onquitmain(GtkMenuItem *menuitem, gpointer dat)
{

	bmigrate_free(dat);
	gtk_main_quit();
}

/*
 * Run when we destroy the config screen.
 */
void
ondestroy(GtkWidget *object, gpointer dat)
{

	bmigrate_free(dat);
	gtk_main_quit();
}

/*
 * Run when we press "Quit" on the config screen.
 */
void
on_deactivate(GtkButton *button, gpointer dat)
{

	bmigrate_free(dat);
	gtk_main_quit();
}

/*
 * Add an island configuration.
 * For the time being, we only allow the population size of the island
 * to be specified.
 * (Inter-island migration probabilities may not yet be assigned.)
 */
static void
mapbox_add(struct bmigrate *b, size_t sz)
{
	GtkWidget	*box, *label, *btn;
	GtkAdjustment	*adj;
	gchar		 buf[64];

	box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);

	g_snprintf(buf, sizeof(buf), "Population %zu:", sz);
	label = gtk_label_new(buf);
	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
	gtk_label_set_width_chars(GTK_LABEL(label), 20);
	gtk_container_add(GTK_CONTAINER(box), label);

	adj = gtk_adjustment_new(2.0, 2.0, 1000.0, 1.0, 10.0, 0.0);
	btn = gtk_spin_button_new(adj, 1.0, 0);
	g_signal_connect(btn, "value-changed",
		G_CALLBACK(on_change_totalpop), b);
	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(btn), TRUE);
	gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(btn), TRUE);
	gtk_container_add(GTK_CONTAINER(box), btn);
	gtk_container_add(GTK_CONTAINER(b->wins.mapbox), box);
	gtk_widget_show_all(box);
}

/*
 * Remove the last island configuration.
 */
static void
mapbox_rem(struct bmigrate *b)
{
	GList		*list, *last;

	list = gtk_container_get_children(GTK_CONTAINER(b->wins.mapbox));
	last = g_list_last(list);
	gtk_widget_destroy(GTK_WIDGET(last->data));
	g_list_free(list);
}

/*
 * We've requested more or fewer islands for the mapped scenario.
 */
void
onislandspin(GtkSpinButton *spinbutton, gpointer dat)
{
	struct bmigrate	*b = dat;
	guint		 oldsz, newsz;
	GList		*list;

	list = gtk_container_get_children(GTK_CONTAINER(b->wins.mapbox));
	oldsz = g_list_length(list);
	g_list_free(list);
	newsz = (guint)gtk_spin_button_get_value(spinbutton);

	if (newsz > oldsz) {
		while (oldsz++ < newsz)
			mapbox_add(b, oldsz);
	} else if (oldsz > newsz) {
		while (oldsz-- > newsz)
			mapbox_rem(b);
	}

	on_totalpop(b, gtk_notebook_get_current_page(b->wins.inputs));
}

int
main(int argc, char *argv[])
{
	GtkBuilder	*builder;
	struct bmigrate	 b;
	int		 rc;

	memset(&b, 0, sizeof(struct bmigrate));
	gtk_init(&argc, &argv);

	rc = kplotcfg_default_palette(&b.clrs, &b.clrsz);
	g_assert(0 != rc);

	/*
	 * Sanity-check to make sure that the hnode expression evaluator
	 * is working properly.
	 * You'll need to actually look at the debugging output to see
	 * if that's the case, of course.
	 */
	hnode_test();

	builder = builder_get("bmigrate.glade");
	if (NULL == builder)
		return(EXIT_FAILURE);

	hwin_init(&b.wins, builder);
	gtk_builder_connect_signals(builder, &b);
	g_object_unref(G_OBJECT(builder));

	/*
	 * Have two running timers: once per second, forcing a refresh of
	 * the window system; then another at four times per second
	 * updating our cold statistics.
	 */
	b.status_elapsed = g_timer_new();
	g_timeout_add_seconds(1, (GSourceFunc)on_sim_timer, &b);
	g_timeout_add_seconds(60, (GSourceFunc)on_sim_autosave, &b);
	g_timeout_add(250, (GSourceFunc)on_sim_copyout, &b);
	gtk_statusbar_push(b.wins.status, 0, "No simulations.");

#ifdef MAC_INTEGRATION
	g_signal_connect(gtkosx_application_get(),
		"NSApplicationWillTerminate",
		G_CALLBACK(onterminate), &b);
	gtkosx_application_ready(gtkosx_application_get());
#endif

	gtk_main();
	bmigrate_free(&b);
	return(EXIT_SUCCESS);
}


#pragma once

#include <memory>
#include <string>

#include <gsl/gsl>
#include <nonstd/optional.hpp>

#include "chainerx/backend.h"
#include "chainerx/context.h"
#include "chainerx/device.h"
#include "chainerx/kernel_registry.h"

namespace chainerx {
namespace cuda {

class CudaDevice;
class CudaBackend;

namespace cuda_internal {

// Creates a device instance.
// This function is meant to be used from the backend class. Never use it for other purpose.
// This is defined in cuda_internal namespace in order to make it a friend of CudaDevice
// class.
gsl::owner<CudaDevice*> CreateDevice(CudaBackend& backend, int index);

}  // namespace cuda_internal

class CudaBackend : public Backend {
public:
    static constexpr const char* kDefaultName = "cuda";
    static constexpr const size_t kCudnnDefaultMaxWorkspaceSize = 8 * 1024 * 1024;
    static constexpr const char* kCudnnMaxWorkspaceSizeEnvVarName = "CHAINERX_CUDNN_MAX_WORKSPACE_SIZE";

    using Backend::Backend;

    std::string GetName() const override;

    int GetDeviceCount() const override;

    bool SupportsTransfer(Device& src_device, Device& dst_device) override;

    // TODO(hvy): Move to CudaDevice.
    // Sets maximum cuDNN workspace size.
    // This value is shared across threads.
    void SetCudnnMaxWorkspaceSize(size_t max_workspace_size);

    // TODO(hvy): Move to CudaDevice.
    // Gets maximum cuDNN workspace size.
    size_t GetCudnnMaxWorkspaceSize();

    static KernelRegistry& GetGlobalKernelRegistry() {
        static gsl::owner<KernelRegistry*> global_kernel_registry = new KernelRegistry{};
        return *global_kernel_registry;
    }

protected:
    KernelRegistry& GetParentKernelRegistry() override { return GetGlobalKernelRegistry(); }

private:
    std::unique_ptr<Device> CreateDevice(int index) override;

    // TODO(hvy): Move to CudaDevice.
    nonstd::optional<size_t> cudnn_max_workspace_size_{};

    std::mutex mutex_;
};

}  // namespace cuda
}  // namespace chainerx