<commit_before>#include "CPU.h"
#include "Emulator.h"
#include "Types.h"
#include "Log.h"
#include "Random.h"
#include "Font.h"

#include <cassert>

namespace
{
using namespace Chip8;

inline int regX(const opcode_t &opcode)
{
	return ((opcode >> 8) & 0xF);
}
inline int regY(const opcode_t &opcode)
{
	return ((opcode >> 4) & 0xF);
}
}

namespace Chip8
{
CPU::CPU(Emulator *emu) : emu(emu)
{
	assert(emu != nullptr);
	reset();
}
CPU::~CPU()
{
}

void CPU::reset()
{
	pc = Memory::ROM_START;
	sp = 0;

	for (int i = 0; i < STACK_SIZE; ++i)
	{
		stack[i] = 0;
	}

	delayTimer = 0;
	soundTimer = 0;
	timeKeep = 0.f;

	I = 0;
	for (int i = 0; i < 16; ++i)
	{
		V[i] = 0;
	}
}

void CPU::step(float seconds)
{
	parseOpcode();
	tickTimers(seconds);

	emu->getSound().setInput(soundTimer > 0);
}

void CPU::parseOpcode()
{
	Memory &memory = emu->getMemory();

	opcode_t opcode = memory.read(pc);
	opcode <<= sizeof(byte_t)*8;
	opcode |= memory.read(pc+1);

	pc += sizeof(opcode_t);

	switch ((opcode >> 12) & 0xF)
	{
	case 0x0:
		switch (opcode & 0x0FFF)
		{
		case 0x0E0: emu->getDisplay().clear(); break;
		case 0x0EE: pc = pop(); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0x1: pc = (opcode & 0x0FFF); break;
	case 0x2: callSubroutine(opcode & 0x0FFF); break;
	case 0x3: if (V[regX(opcode)] == (opcode & 0x00FF)) skipInstruction(); break;
	case 0x4: if (V[regX(opcode)] != (opcode & 0x00FF)) skipInstruction(); break;
	case 0x5: if (V[regX(opcode)] == V[regY(opcode)]) skipInstruction(); break;
	case 0x6: V[regX(opcode)] = (opcode & 0x00FF); break;
	case 0x7: V[regX(opcode)] += (opcode & 0x00FF); break;
	case 0x8:
		switch (opcode & 0x000F)
		{
		case 0x0: V[regX(opcode)] = V[regY(opcode)]; break;
		case 0x1: V[regX(opcode)] |= V[regY(opcode)]; break;
		case 0x2: V[regX(opcode)] &= V[regY(opcode)]; break;
		case 0x3: V[regX(opcode)] ^= V[regY(opcode)]; break;
		case 0x4: V[regX(opcode)] = addSetCarry(V[regX(opcode)], V[regY(opcode)]); break;
		case 0x5: V[regX(opcode)] = subtractSetCarry(V[regX(opcode)], V[regY(opcode)]); break;
		case 0x6: V[regX(opcode)] = shiftRightSetCarry(V[regX(opcode)], 1); break;
		case 0x7: V[regX(opcode)] = subtractSetCarry(V[regY(opcode)], V[regX(opcode)]); break;
		case 0xE: V[regX(opcode)] = shiftLeftSetCarry(V[regX(opcode)], 1); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0x9: if (V[regX(opcode)] != V[regY(opcode)]) skipInstruction(); break;
	case 0xA: I = (opcode & 0x0FFF); break;
	case 0xB: pc = ((opcode & 0x0FFF) + V[0x0]); break;
	case 0xC: V[regX(opcode)] = Random::get() & (opcode & 0x00FF); break;
	case 0xD: V[0xF] = emu->getDisplay().drawSprite(V[regX(opcode)], V[regY(opcode)], emu->getMemory().get(I), (opcode & 0xF)) ? 1 : 0; break;
	case 0xE:
		switch (opcode & 0x00FF)
		{
		case 0x9E: if (emu->getInput().isPressed(V[regX(opcode)])) skipInstruction(); break;
		case 0xA1: if (!emu->getInput().isPressed(V[regX(opcode)])) skipInstruction(); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0xF:
		switch (opcode & 0x00FF)
		{
		case 0x07: V[regX(opcode)] = delayTimer; break;
		case 0x0A: if (emu->getInput().isAnyPressed()) V[regX(opcode)] = emu->getInput().getFirstPressed(); else repeatInstruction(); break;
		case 0x15: delayTimer = V[regX(opcode)]; break;
		case 0x18: soundTimer = V[regX(opcode)]; break;
		case 0x1E: I = addSetOverflow(I, V[regX(opcode)]); break;
		case 0x29: I = Memory::FONT_START + (V[regX(opcode)] * Font::HEIGHT); break;
		case 0x33: storeDecimal(I, V[regX(opcode)]); break;
		case 0x55: storeRegisters(I, regX(opcode)); break;
		case 0x65: fillRegisters(I, regX(opcode)); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	default: unknownOpcode(opcode); break;
	}
}
void CPU::tickTimers(float seconds)
{
	timeKeep += seconds;

	static const float SECONDS_PER_TICK = (1.f / (float)TIMER_HZ);
	while (timeKeep >= SECONDS_PER_TICK)
	{
		timeKeep -= SECONDS_PER_TICK;
		if (delayTimer > 0)
			--delayTimer;
		if (soundTimer > 0)
			--soundTimer;
	}
}

void CPU::push(address_t address)
{
	if (sp >= STACK_SIZE)
	{
		Log::error() << "Stack overflow" << std::endl;
	}
	else
	{
		stack[sp] = address;
		++sp;
	}
}
address_t CPU::pop()
{
	if (sp <= 0)
	{
		Log::error() << "Stack underflow" << std::endl;
		return 0;
	}
	else
	{
		--sp;
		address_t top = stack[sp];
		return top;
	}
}

void CPU::storeRegisters(address_t address, int maxReg)
{
	Memory &memory = emu->getMemory();
	for (int i = 0x0; i <= maxReg; ++i)
	{
		memory.write(address + i, V[i]);
	}
}
void CPU::fillRegisters(address_t address, int maxReg)
{
	Memory &memory = emu->getMemory();
	for (int i = 0x0; i <= maxReg; ++i)
	{
		V[i] = memory.read(address + i);
	}
}

void CPU::storeDecimal(address_t address, byte_t byte)
{
	Memory &memory = emu->getMemory();
	byte_t hundreds = byte / 100;
	byte -= hundreds * 100;
	byte_t tens = byte / 10;
	byte -= tens * 10;
	byte_t ones = byte;
	memory.write(address + 0, hundreds);
	memory.write(address + 1, tens);
	memory.write(address + 2, ones);
}

void CPU::skipInstruction()
{
	pc += sizeof(opcode_t);
}
void CPU::repeatInstruction()
{
	pc -= sizeof(opcode_t);
}
void CPU::callSubroutine(address_t address)
{
	push(pc + sizeof(opcode_t));
	pc = address;
}

byte_t CPU::addSetCarry(byte_t v1, byte_t v2)
{
	int result = static_cast<int>(v1) + static_cast<int>(v2);
	V[0xF] = (result > 0xFF ? 1 : 0);
	return static_cast<byte_t>(result);
}
byte_t CPU::subtractSetCarry(byte_t v1, byte_t v2)
{
	V[0xF] = (v1 >= v2 ? 1 : 0);
	return v1 - v2;
}

address_t CPU::addSetOverflow(address_t v1, address_t v2)
{
	int result = static_cast<int>(v1) + static_cast<int>(v2);
	V[0xF] = (result > 0xFFF ? 1 : 0);
	return static_cast<address_t>(result);
}

byte_t CPU::shiftRightSetCarry(byte_t v, int steps)
{
	V[0xF] = (v & 0x1);
	return (v >> steps);
}
byte_t CPU::shiftLeftSetCarry(byte_t v, int steps)
{
	V[0xF] = ((v >> 7) & 0x1);
	return (v << steps);
}

void CPU::unknownOpcode(opcode_t opcode)
{
	Log::error() << "Unknown opcode 0x" << std::hex << opcode << std::endl;
}
}
<commit_msg>Slightly changed the look of a for loop<commit_after>#include "CPU.h"
#include "Emulator.h"
#include "Types.h"
#include "Log.h"
#include "Random.h"
#include "Font.h"

#include <cassert>

namespace
{
using namespace Chip8;

inline int regX(const opcode_t &opcode)
{
	return ((opcode >> 8) & 0xF);
}
inline int regY(const opcode_t &opcode)
{
	return ((opcode >> 4) & 0xF);
}
}

namespace Chip8
{
CPU::CPU(Emulator *emu) : emu(emu)
{
	assert(emu != nullptr);
	reset();
}
CPU::~CPU()
{
}

void CPU::reset()
{
	pc = Memory::ROM_START;
	sp = 0;

	for (int i = 0; i < STACK_SIZE; ++i)
	{
		stack[i] = 0;
	}

	delayTimer = 0;
	soundTimer = 0;
	timeKeep = 0.f;

	I = 0;
	for (int i = 0x0; i <= 0xF; ++i)
	{
		V[i] = 0;
	}
}

void CPU::step(float seconds)
{
	parseOpcode();
	tickTimers(seconds);

	emu->getSound().setInput(soundTimer > 0);
}

void CPU::parseOpcode()
{
	Memory &memory = emu->getMemory();

	opcode_t opcode = memory.read(pc);
	opcode <<= sizeof(byte_t)*8;
	opcode |= memory.read(pc+1);

	pc += sizeof(opcode_t);

	switch ((opcode >> 12) & 0xF)
	{
	case 0x0:
		switch (opcode & 0x0FFF)
		{
		case 0x0E0: emu->getDisplay().clear(); break;
		case 0x0EE: pc = pop(); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0x1: pc = (opcode & 0x0FFF); break;
	case 0x2: callSubroutine(opcode & 0x0FFF); break;
	case 0x3: if (V[regX(opcode)] == (opcode & 0x00FF)) skipInstruction(); break;
	case 0x4: if (V[regX(opcode)] != (opcode & 0x00FF)) skipInstruction(); break;
	case 0x5: if (V[regX(opcode)] == V[regY(opcode)]) skipInstruction(); break;
	case 0x6: V[regX(opcode)] = (opcode & 0x00FF); break;
	case 0x7: V[regX(opcode)] += (opcode & 0x00FF); break;
	case 0x8:
		switch (opcode & 0x000F)
		{
		case 0x0: V[regX(opcode)] = V[regY(opcode)]; break;
		case 0x1: V[regX(opcode)] |= V[regY(opcode)]; break;
		case 0x2: V[regX(opcode)] &= V[regY(opcode)]; break;
		case 0x3: V[regX(opcode)] ^= V[regY(opcode)]; break;
		case 0x4: V[regX(opcode)] = addSetCarry(V[regX(opcode)], V[regY(opcode)]); break;
		case 0x5: V[regX(opcode)] = subtractSetCarry(V[regX(opcode)], V[regY(opcode)]); break;
		case 0x6: V[regX(opcode)] = shiftRightSetCarry(V[regX(opcode)], 1); break;
		case 0x7: V[regX(opcode)] = subtractSetCarry(V[regY(opcode)], V[regX(opcode)]); break;
		case 0xE: V[regX(opcode)] = shiftLeftSetCarry(V[regX(opcode)], 1); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0x9: if (V[regX(opcode)] != V[regY(opcode)]) skipInstruction(); break;
	case 0xA: I = (opcode & 0x0FFF); break;
	case 0xB: pc = ((opcode & 0x0FFF) + V[0x0]); break;
	case 0xC: V[regX(opcode)] = Random::get() & (opcode & 0x00FF); break;
	case 0xD: V[0xF] = emu->getDisplay().drawSprite(V[regX(opcode)], V[regY(opcode)], emu->getMemory().get(I), (opcode & 0xF)) ? 1 : 0; break;
	case 0xE:
		switch (opcode & 0x00FF)
		{
		case 0x9E: if (emu->getInput().isPressed(V[regX(opcode)])) skipInstruction(); break;
		case 0xA1: if (!emu->getInput().isPressed(V[regX(opcode)])) skipInstruction(); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0xF:
		switch (opcode & 0x00FF)
		{
		case 0x07: V[regX(opcode)] = delayTimer; break;
		case 0x0A: if (emu->getInput().isAnyPressed()) V[regX(opcode)] = emu->getInput().getFirstPressed(); else repeatInstruction(); break;
		case 0x15: delayTimer = V[regX(opcode)]; break;
		case 0x18: soundTimer = V[regX(opcode)]; break;
		case 0x1E: I = addSetOverflow(I, V[regX(opcode)]); break;
		case 0x29: I = Memory::FONT_START + (V[regX(opcode)] * Font::HEIGHT); break;
		case 0x33: storeDecimal(I, V[regX(opcode)]); break;
		case 0x55: storeRegisters(I, regX(opcode)); break;
		case 0x65: fillRegisters(I, regX(opcode)); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	default: unknownOpcode(opcode); break;
	}
}
void CPU::tickTimers(float seconds)
{
	timeKeep += seconds;

	static const float SECONDS_PER_TICK = (1.f / (float)TIMER_HZ);
	while (timeKeep >= SECONDS_PER_TICK)
	{
		timeKeep -= SECONDS_PER_TICK;
		if (delayTimer > 0)
			--delayTimer;
		if (soundTimer > 0)
			--soundTimer;
	}
}

void CPU::push(address_t address)
{
	if (sp >= STACK_SIZE)
	{
		Log::error() << "Stack overflow" << std::endl;
	}
	else
	{
		stack[sp] = address;
		++sp;
	}
}
address_t CPU::pop()
{
	if (sp <= 0)
	{
		Log::error() << "Stack underflow" << std::endl;
		return 0;
	}
	else
	{
		--sp;
		address_t top = stack[sp];
		return top;
	}
}

void CPU::storeRegisters(address_t address, int maxReg)
{
	Memory &memory = emu->getMemory();
	for (int i = 0x0; i <= maxReg; ++i)
	{
		memory.write(address + i, V[i]);
	}
}
void CPU::fillRegisters(address_t address, int maxReg)
{
	Memory &memory = emu->getMemory();
	for (int i = 0x0; i <= maxReg; ++i)
	{
		V[i] = memory.read(address + i);
	}
}

void CPU::storeDecimal(address_t address, byte_t byte)
{
	Memory &memory = emu->getMemory();
	byte_t hundreds = byte / 100;
	byte -= hundreds * 100;
	byte_t tens = byte / 10;
	byte -= tens * 10;
	byte_t ones = byte;
	memory.write(address + 0, hundreds);
	memory.write(address + 1, tens);
	memory.write(address + 2, ones);
}

void CPU::skipInstruction()
{
	pc += sizeof(opcode_t);
}
void CPU::repeatInstruction()
{
	pc -= sizeof(opcode_t);
}
void CPU::callSubroutine(address_t address)
{
	push(pc + sizeof(opcode_t));
	pc = address;
}

byte_t CPU::addSetCarry(byte_t v1, byte_t v2)
{
	int result = static_cast<int>(v1) + static_cast<int>(v2);
	V[0xF] = (result > 0xFF ? 1 : 0);
	return static_cast<byte_t>(result);
}
byte_t CPU::subtractSetCarry(byte_t v1, byte_t v2)
{
	V[0xF] = (v1 >= v2 ? 1 : 0);
	return v1 - v2;
}

address_t CPU::addSetOverflow(address_t v1, address_t v2)
{
	int result = static_cast<int>(v1) + static_cast<int>(v2);
	V[0xF] = (result > 0xFFF ? 1 : 0);
	return static_cast<address_t>(result);
}

byte_t CPU::shiftRightSetCarry(byte_t v, int steps)
{
	V[0xF] = (v & 0x1);
	return (v >> steps);
}
byte_t CPU::shiftLeftSetCarry(byte_t v, int steps)
{
	V[0xF] = ((v >> 7) & 0x1);
	return (v << steps);
}

void CPU::unknownOpcode(opcode_t opcode)
{
	Log::error() << "Unknown opcode 0x" << std::hex << opcode << std::endl;
}
}
<|endoftext|>


<commit_before>/*
 * Lda.cpp
 *
 * Copyright (c) 2012 Tsukasa OMOTO <henry0312@gmail.com>
 *
 * 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.
*/

/* This file is available under an MIT license. */

#include "Lda.hpp"

/**
 * Constructor
 *
 * @param const unsigned int _K the number of Topics
 * @param const double _alpha hyperparameter, alpha
 * @param const double _beta hyperparameter, beta
 * @param const unsigned int _seed seed value
 * @param const char *train Training set
 * @param const char *test Test set
 * @param const char *vocab Vocabulary
 * @param bool _asymmetry If true, use Asymmetry Dirichlet distribution
 */
Lda::Lda(const unsigned int _K, const double _alpha, const double _beta, const unsigned int _seed,
        const char *train, const char *test, const char *vocab, bool _asymmetry=false)
    :dataset(train, vocab), testset(test), K(_K), alpha_z(_K, _alpha),
    beta(_beta), asymmetry(_asymmetry), gen(_seed)
{
    init();
}

/**
 * Initialization
 */
void Lda::init() {
    // n_mz
    n_m_z.resize(dataset.M);
    for (auto& n_z : n_m_z) {
        n_z.resize(K, 0);
    }

    // n_zt
    n_z_t.resize(K);
    for (auto& n_t : n_z_t) {
        n_t.resize(dataset.V, 0);
    }

    // n_z
    n_z.resize(K, 0);

    /*
     * Topics
     */
    z_m_n.resize(dataset.M);
    std::uniform_int_distribution<> dis(0, K-1);
    for (int m = 0; m < dataset.M; ++m) {
        z_m_n[m].resize(dataset.n_m[m]);
        for (int n = 0; n < dataset.n_m[m]; ++n) {
            auto z = dis(gen);
            z_m_n[m][n] = z;
            ++n_m_z[m][z];
            ++n_z_t[z][dataset.docs[m][n] - 1];
            ++n_z[z];
        }
    }

    // phi
    phi_z_t.resize(K);
    for (auto& phi_t : phi_z_t) {
        phi_t.resize(dataset.V);
    }

    // theta
    theta_m_z.resize(dataset.M);
    for (auto& theta_z : theta_m_z) {
        theta_z.resize(K);
    }
}

/**
 * Inference
 */
void Lda::inference() {
    /*
     * Sampling z_mn
     */
    for (int m = 0; m < dataset.M; ++m) {
        for (int n = 0; n < dataset.n_m[m]; ++n) {
            sampling_z(m, n);
        }
    }
}

/**
 * Sampling z_mn
 *
 * Perform Gibbs sampling once
 *
 * @param const int m the mth doc
 * @param const int n the nth word
 */
void Lda::sampling_z(const int m, const int n) {
    // word
    const int t = dataset.docs[m][n];
    // old topic
    const int old_z = z_m_n[m][n];

    /*
     * Delete old topic
     */
    --n_m_z[m][old_z];
    --n_z_t[old_z][t - 1];
    --n_z[old_z];

    /*
     * Gibbs sampling
     */
    std::vector<double> p_z(K);
    for (int z = 0; z < K; ++z) {
        p_z[z] = (alpha_z[z] + n_m_z[m][z]) * (beta + n_z_t[z][t - 1]) / (n_z[z] + dataset.V * beta);
    }
    std::discrete_distribution<> dis(begin(p_z), end(p_z));
    int new_z = dis(gen);

    /*
     * Update topic
     */
    z_m_n[m][n] = new_z;
    ++n_m_z[m][new_z];
    ++n_z_t[new_z][t - 1];
    ++n_z[new_z];
}

/**
 * Compute Perplexity
 */
double Lda::perplexity() {
    /*
     * phi
     */
    for (int z = 0; z < K; ++z) {
        for (int t = 0; t < dataset.V; ++t) {
            phi_z_t[z][t] = (beta + n_z_t[z][t]) / (n_z[z] + dataset.V * beta);
        }
    }

    /*
     * theta
     */
    for (int m = 0; m < dataset.M; ++m) {
        for (int z = 0; z < K; ++z) {
            theta_m_z[m][z] = (alpha_z[z] + n_m_z[m][z]) / (dataset.n_m[m] + K * alpha_z[z]);
        }
    }

    /*
     * Perplexity
     */
    double log_per = 0.0;
    for (int m = 0; m < testset.M; ++m) {
        for (int n = 0; n < testset.n_m[m]; ++n) {
            const int t = testset.docs[m][n] - 1;
            double sum = 0.0;
            for (int z = 0; z < K; ++z) {
                sum += theta_m_z[m][z] * phi_z_t[z][t];
            }
            log_per -= log(sum);
        }
    }
    return exp( log_per / testset.N );
}

/**
 * Learning
 *
 * Perform Gibbs sampling specified number of times and Calculate perplexity with each cycle
 *
 * @param const unsigned int iteration the number of times of inference
 * @param const unsigned int burn_in burn-in period
 */
void Lda::learn(const unsigned int iteration, const unsigned int burn_in) {
    using namespace std;

    cout.precision(3);
    cout.setf(ios::fixed);

    /*
     * Show Initial parameters
     */
    cout << "K = " << K << endl;
    if (asymmetry) {
        cout << "alpha_z = " << alpha_z[0] << endl;
    } else {
        cout << "alpha = " << alpha_z[0] << endl;
    }
    cout << "beta = " << beta << endl;

    // Start time
    auto start = std::chrono::system_clock::now();

    // Inference
    cout << "iter\tperplexity\n";
    for (unsigned int i = 0; i < iteration; ++i) {
        cout << i << "\t" << perplexity() << endl;

        /*
         * Update hyperparameters
         */
        if (asymmetry) {
            if (i >= burn_in) {
                update_alpha();
            }
        }

        inference();
    }
    cout << iteration << "\t" << perplexity() << endl;

    // End time
    auto end = std::chrono::system_clock::now();

    // Elapsed time
    auto ms = std::chrono::duration_cast< std::chrono::milliseconds >(end - start).count();
    int s = ms * 0.001; ms -= s * 1000;
    int m = s / 60; s %= 60;
    int h = m / 60; m %= 60;
    cout << "Elapsed time: " << h << "h " << m << "m " << s << "." << ms << "s\n" << endl;

    /*
     * Dump
     */
    // topic-word distribution
    dump();
    // alpha_z
    if (asymmetry) {
        for (int z = 0; z < K; ++z) {
            cout << "alpha_z[" << z << "] = " << alpha_z[z] << endl;
        }
    }
}

/**
 * Dump
 *
 * Print topic-word distribution
 */
void Lda::dump() {
    // Insert topic-word distribution to vector
    std::vector<std::vector<std::pair<int, double>>> topic_word;
    topic_word.resize(K);
    for (int z = 0; z < K; ++z) {
        topic_word[z].resize(dataset.V);
        for (int t = 0; t < dataset.V; ++t) {
            topic_word[z][t] = std::make_pair(t, phi_z_t[z][t]);
        }
    }

    // Descending sort
    for (int z = 0; z < K; ++z) {
        std::sort( begin(topic_word[z]), end(topic_word[z]),
                    [](const std::pair<int, double> &a, const std::pair<int, double> &b)
                    -> bool { return a.second > b.second; } );
    }

    // Print
    for (int z = 0; z < K; ++z) {
        printf("Topic: %d (%d words)\n", z, n_z[z]);
        for (int i = 0; i < (n_z[z] > 10 ? 10 : n_z[z]); ++i) {
            auto t = topic_word[z][i].first;
            auto phi = topic_word[z][i].second;
            printf("%s: %f (%d)\n", dataset.vocab[t].c_str(), phi, n_z_t[z][t]);
        }
        std::cout << std::endl;
    }
}

/**
 * Sampling new alpha
 */
void Lda::update_alpha() {
    using namespace boost::math;

    double sum_alpha = 0.0;
    for (auto alpha : alpha_z) {
        sum_alpha += alpha;
    }

    double numer, denom;
    for (int z = 0; z < K; ++z) {
        numer = denom = 0.0;
        for (int m = 0; m < dataset.M; ++m) {
            numer += digamma(n_m_z[m][z] + alpha_z[z]) - digamma(alpha_z[z]);
            denom += digamma(dataset.n_m[m] + sum_alpha) - digamma(sum_alpha);
        }
        alpha_z[z] = alpha_z[z] * numer / denom;
    }
}
<commit_msg>Change the decimal precision to be used by output operations.<commit_after>/*
 * Lda.cpp
 *
 * Copyright (c) 2012 Tsukasa OMOTO <henry0312@gmail.com>
 *
 * 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.
*/

/* This file is available under an MIT license. */

#include "Lda.hpp"

/**
 * Constructor
 *
 * @param const unsigned int _K the number of Topics
 * @param const double _alpha hyperparameter, alpha
 * @param const double _beta hyperparameter, beta
 * @param const unsigned int _seed seed value
 * @param const char *train Training set
 * @param const char *test Test set
 * @param const char *vocab Vocabulary
 * @param bool _asymmetry If true, use Asymmetry Dirichlet distribution
 */
Lda::Lda(const unsigned int _K, const double _alpha, const double _beta, const unsigned int _seed,
        const char *train, const char *test, const char *vocab, bool _asymmetry=false)
    :dataset(train, vocab), testset(test), K(_K), alpha_z(_K, _alpha),
    beta(_beta), asymmetry(_asymmetry), gen(_seed)
{
    init();
}

/**
 * Initialization
 */
void Lda::init() {
    // n_mz
    n_m_z.resize(dataset.M);
    for (auto& n_z : n_m_z) {
        n_z.resize(K, 0);
    }

    // n_zt
    n_z_t.resize(K);
    for (auto& n_t : n_z_t) {
        n_t.resize(dataset.V, 0);
    }

    // n_z
    n_z.resize(K, 0);

    /*
     * Topics
     */
    z_m_n.resize(dataset.M);
    std::uniform_int_distribution<> dis(0, K-1);
    for (int m = 0; m < dataset.M; ++m) {
        z_m_n[m].resize(dataset.n_m[m]);
        for (int n = 0; n < dataset.n_m[m]; ++n) {
            auto z = dis(gen);
            z_m_n[m][n] = z;
            ++n_m_z[m][z];
            ++n_z_t[z][dataset.docs[m][n] - 1];
            ++n_z[z];
        }
    }

    // phi
    phi_z_t.resize(K);
    for (auto& phi_t : phi_z_t) {
        phi_t.resize(dataset.V);
    }

    // theta
    theta_m_z.resize(dataset.M);
    for (auto& theta_z : theta_m_z) {
        theta_z.resize(K);
    }
}

/**
 * Inference
 */
void Lda::inference() {
    /*
     * Sampling z_mn
     */
    for (int m = 0; m < dataset.M; ++m) {
        for (int n = 0; n < dataset.n_m[m]; ++n) {
            sampling_z(m, n);
        }
    }
}

/**
 * Sampling z_mn
 *
 * Perform Gibbs sampling once
 *
 * @param const int m the mth doc
 * @param const int n the nth word
 */
void Lda::sampling_z(const int m, const int n) {
    // word
    const int t = dataset.docs[m][n];
    // old topic
    const int old_z = z_m_n[m][n];

    /*
     * Delete old topic
     */
    --n_m_z[m][old_z];
    --n_z_t[old_z][t - 1];
    --n_z[old_z];

    /*
     * Gibbs sampling
     */
    std::vector<double> p_z(K);
    for (int z = 0; z < K; ++z) {
        p_z[z] = (alpha_z[z] + n_m_z[m][z]) * (beta + n_z_t[z][t - 1]) / (n_z[z] + dataset.V * beta);
    }
    std::discrete_distribution<> dis(begin(p_z), end(p_z));
    int new_z = dis(gen);

    /*
     * Update topic
     */
    z_m_n[m][n] = new_z;
    ++n_m_z[m][new_z];
    ++n_z_t[new_z][t - 1];
    ++n_z[new_z];
}

/**
 * Compute Perplexity
 */
double Lda::perplexity() {
    /*
     * phi
     */
    for (int z = 0; z < K; ++z) {
        for (int t = 0; t < dataset.V; ++t) {
            phi_z_t[z][t] = (beta + n_z_t[z][t]) / (n_z[z] + dataset.V * beta);
        }
    }

    /*
     * theta
     */
    for (int m = 0; m < dataset.M; ++m) {
        for (int z = 0; z < K; ++z) {
            theta_m_z[m][z] = (alpha_z[z] + n_m_z[m][z]) / (dataset.n_m[m] + K * alpha_z[z]);
        }
    }

    /*
     * Perplexity
     */
    double log_per = 0.0;
    for (int m = 0; m < testset.M; ++m) {
        for (int n = 0; n < testset.n_m[m]; ++n) {
            const int t = testset.docs[m][n] - 1;
            double sum = 0.0;
            for (int z = 0; z < K; ++z) {
                sum += theta_m_z[m][z] * phi_z_t[z][t];
            }
            log_per -= log(sum);
        }
    }
    return exp( log_per / testset.N );
}

/**
 * Learning
 *
 * Perform Gibbs sampling specified number of times and Calculate perplexity with each cycle
 *
 * @param const unsigned int iteration the number of times of inference
 * @param const unsigned int burn_in burn-in period
 */
void Lda::learn(const unsigned int iteration, const unsigned int burn_in) {
    using namespace std;
    cout.setf(ios::fixed);

    /*
     * Show Initial parameters
     */
    cout << "K = " << K << endl;
    if (asymmetry) {
        cout << setprecision(6) << "alpha_z = " << alpha_z[0] << endl;
    } else {
        cout << setprecision(6) << "alpha = " << alpha_z[0] << endl;
    }
    cout << setprecision(6) << "beta = " << beta << endl;

    // Start time
    auto start = std::chrono::system_clock::now();

    // Inference
    cout.precision(3);
    cout << "iter\tperplexity\n";
    for (unsigned int i = 0; i < iteration; ++i) {
        cout << i << "\t" << perplexity() << endl;

        /*
         * Update hyperparameters
         */
        if (asymmetry) {
            if (i >= burn_in) {
                update_alpha();
            }
        }

        inference();
    }
    cout << iteration << "\t" << perplexity() << endl;

    // End time
    auto end = std::chrono::system_clock::now();

    // Elapsed time
    auto ms = std::chrono::duration_cast< std::chrono::milliseconds >(end - start).count();
    int s = ms * 0.001; ms -= s * 1000;
    int m = s / 60; s %= 60;
    int h = m / 60; m %= 60;
    cout << "Elapsed time: " << h << "h " << m << "m " << s << "." << ms << "s\n" << endl;

    /*
     * Dump
     */
    // topic-word distribution
    dump();
    // alpha_z
    if (asymmetry) {
        cout.precision(6);
        for (int z = 0; z < K; ++z) {
            cout << "alpha_z[" << z << "] = " << alpha_z[z] << endl;
        }
    }
}

/**
 * Dump
 *
 * Print topic-word distribution
 */
void Lda::dump() {
    // Insert topic-word distribution to vector
    std::vector<std::vector<std::pair<int, double>>> topic_word;
    topic_word.resize(K);
    for (int z = 0; z < K; ++z) {
        topic_word[z].resize(dataset.V);
        for (int t = 0; t < dataset.V; ++t) {
            topic_word[z][t] = std::make_pair(t, phi_z_t[z][t]);
        }
    }

    // Descending sort
    for (int z = 0; z < K; ++z) {
        std::sort( begin(topic_word[z]), end(topic_word[z]),
                    [](const std::pair<int, double> &a, const std::pair<int, double> &b)
                    -> bool { return a.second > b.second; } );
    }

    // Print
    for (int z = 0; z < K; ++z) {
        printf("Topic: %d (%d words)\n", z, n_z[z]);
        for (int i = 0; i < (n_z[z] > 10 ? 10 : n_z[z]); ++i) {
            auto t = topic_word[z][i].first;
            auto phi = topic_word[z][i].second;
            printf("%s: %f (%d)\n", dataset.vocab[t].c_str(), phi, n_z_t[z][t]);
        }
        std::cout << std::endl;
    }
}

/**
 * Sampling new alpha
 */
void Lda::update_alpha() {
    using namespace boost::math;

    double sum_alpha = 0.0;
    for (auto alpha : alpha_z) {
        sum_alpha += alpha;
    }

    double numer, denom;
    for (int z = 0; z < K; ++z) {
        numer = denom = 0.0;
        for (int m = 0; m < dataset.M; ++m) {
            numer += digamma(n_m_z[m][z] + alpha_z[z]) - digamma(alpha_z[z]);
            denom += digamma(dataset.n_m[m] + sum_alpha) - digamma(sum_alpha);
        }
        alpha_z[z] = alpha_z[z] * numer / denom;
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <vector>
#include "prevector.h"
#include "random.h"

#include "serialize.h"
#include "streams.h"

#include "test/test_pivx.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(PrevectorTests, TestingSetup)

template<unsigned int N, typename T>
class prevector_tester {
    typedef std::vector<T> realtype;
    realtype real_vector;

    typedef prevector<N, T> pretype;
    pretype pre_vector;

    typedef typename pretype::size_type Size;

    void test() {
        const pretype& const_pre_vector = pre_vector;
        BOOST_CHECK_EQUAL(real_vector.size(), pre_vector.size());
        BOOST_CHECK_EQUAL(real_vector.empty(), pre_vector.empty());
        for (Size s = 0; s < real_vector.size(); s++) {
             BOOST_CHECK(real_vector[s] == pre_vector[s]);
             BOOST_CHECK(&(pre_vector[s]) == &(pre_vector.begin()[s]));
             BOOST_CHECK(&(pre_vector[s]) == &*(pre_vector.begin() + s));
             BOOST_CHECK(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
        }
        // BOOST_CHECK(realtype(pre_vector) == real_vector);
        BOOST_CHECK(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
        BOOST_CHECK(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
        size_t pos = 0;
        for (const T& v  : pre_vector) {
             BOOST_CHECK(v == real_vector[pos++]);
        }
        pos = 0;
        for (const T& v : const_pre_vector) {
             BOOST_CHECK(v == real_vector[pos++]);
        }

        CDataStream ss1(SER_DISK, 0);
        CDataStream ss2(SER_DISK, 0);
        ss1 << real_vector;
        ss2 << pre_vector;
        BOOST_CHECK_EQUAL(ss1.size(), ss2.size());
        for (Size s = 0; s < ss1.size(); s++) {
            BOOST_CHECK_EQUAL(ss1[s], ss2[s]);
        }
    }

public:
    void resize(Size s) {
        real_vector.resize(s);
        BOOST_CHECK_EQUAL(real_vector.size(), s);
        pre_vector.resize(s);
        BOOST_CHECK_EQUAL(pre_vector.size(), s);
        test();
    }

    void reserve(Size s) {
        real_vector.reserve(s);
        BOOST_CHECK(real_vector.capacity() >= s);
        pre_vector.reserve(s);
        BOOST_CHECK(pre_vector.capacity() >= s);
        test();
    }

    void insert(Size position, const T& value) {
        real_vector.insert(real_vector.begin() + position, value);
        pre_vector.insert(pre_vector.begin() + position, value);
        test();
    }

    void insert(Size position, Size count, const T& value) {
        real_vector.insert(real_vector.begin() + position, count, value);
        pre_vector.insert(pre_vector.begin() + position, count, value);
        test();
    }

    template<typename I>
    void insert_range(Size position, I first, I last) {
        real_vector.insert(real_vector.begin() + position, first, last);
        pre_vector.insert(pre_vector.begin() + position, first, last);
        test();
    }

    void erase(Size position) {
        real_vector.erase(real_vector.begin() + position);
        pre_vector.erase(pre_vector.begin() + position);
        test();
    }

    void erase(Size first, Size last) {
        real_vector.erase(real_vector.begin() + first, real_vector.begin() + last);
        pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last);
        test();
    }

    void update(Size pos, const T& value) {
        real_vector[pos] = value;
        pre_vector[pos] = value;
        test();
    }

    void push_back(const T& value) {
        real_vector.push_back(value);
        pre_vector.push_back(value);
        test();
    }

    void pop_back() {
        real_vector.pop_back();
        pre_vector.pop_back();
        test();
    }

    void clear() {
        real_vector.clear();
        pre_vector.clear();
    }

    void assign(Size n, const T& value) {
        real_vector.assign(n, value);
        pre_vector.assign(n, value);
    }

    Size size() {
        return real_vector.size();
    }

    Size capacity() {
        return pre_vector.capacity();
    }

    void shrink_to_fit() {
        pre_vector.shrink_to_fit();
        test();
    }
};

BOOST_AUTO_TEST_CASE(PrevectorTestInt)
{
    for (int j = 0; j < 64; j++) {
        prevector_tester<8, int> test;
        for (int i = 0; i < 2048; i++) {
            int r = InsecureRand32();
            if ((r % 4) == 0) {
                test.insert(InsecureRand32() % (test.size() + 1), InsecureRand32());
            }
            if (test.size() > 0 && ((r >> 2) % 4) == 1) {
                test.erase(InsecureRand32() % test.size());
            }
            if (((r >> 4) % 8) == 2) {
                int new_size = std::max<int>(0, std::min<int>(30, test.size() + (InsecureRand32() % 5) - 2));
                test.resize(new_size);
            }
            if (((r >> 7) % 8) == 3) {
                test.insert(InsecureRand32() % (test.size() + 1), 1 + (InsecureRand32() % 2), InsecureRand32());
            }
            if (((r >> 10) % 8) == 4) {
                int del = std::min<int>(test.size(), 1 + (InsecureRand32() % 2));
                int beg = InsecureRand32() % (test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            if (((r >> 13) % 16) == 5) {
                test.push_back(InsecureRand32());
            }
            if (test.size() > 0 && ((r >> 17) % 16) == 6) {
                test.pop_back();
            }
            if (((r >> 21) % 32) == 7) {
                int values[4];
                int num = 1 + (InsecureRand32() % 4);
                for (int i = 0; i < num; i++) {
                    values[i] = InsecureRand32();
                }
                test.insert_range(InsecureRand32() % (test.size() + 1), values, values + num);
            }
            if (((r >> 26) % 32) == 8) {
                int del = std::min<int>(test.size(), 1 + (InsecureRand32() % 4));
                int beg = InsecureRand32() % (test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            r = InsecureRand32();
            if (r % 32 == 9) {
                test.reserve(InsecureRand32() % 32);
            }
            if ((r >> 5) % 64 == 10) {
                test.shrink_to_fit();
            }
            if (test.size() > 0) {
                test.update(InsecureRand32() % test.size(), InsecureRand32());
            }
            if (((r >> 11) & 1024) == 11) {
                test.clear();
            }
            if (((r >> 21) & 512) == 12) {
                test.assign(InsecureRand32() % 32, InsecureRand32());
            }
        }
    }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>test prevector::swap<commit_after>// Copyright (c) 2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <vector>
#include "prevector.h"
#include "random.h"

#include "serialize.h"
#include "streams.h"

#include "test/test_pivx.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(PrevectorTests, TestingSetup)

template<unsigned int N, typename T>
class prevector_tester {
    typedef std::vector<T> realtype;
    realtype real_vector;
    realtype real_vector_alt;

    typedef prevector<N, T> pretype;
    pretype pre_vector;
    pretype pre_vector_alt;

    typedef typename pretype::size_type Size;

    void test() {
        const pretype& const_pre_vector = pre_vector;
        BOOST_CHECK_EQUAL(real_vector.size(), pre_vector.size());
        BOOST_CHECK_EQUAL(real_vector.empty(), pre_vector.empty());
        for (Size s = 0; s < real_vector.size(); s++) {
             BOOST_CHECK(real_vector[s] == pre_vector[s]);
             BOOST_CHECK(&(pre_vector[s]) == &(pre_vector.begin()[s]));
             BOOST_CHECK(&(pre_vector[s]) == &*(pre_vector.begin() + s));
             BOOST_CHECK(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
        }
        // BOOST_CHECK(realtype(pre_vector) == real_vector);
        BOOST_CHECK(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
        BOOST_CHECK(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
        size_t pos = 0;
        for (const T& v  : pre_vector) {
             BOOST_CHECK(v == real_vector[pos++]);
        }
        pos = 0;
        for (const T& v : const_pre_vector) {
             BOOST_CHECK(v == real_vector[pos++]);
        }

        CDataStream ss1(SER_DISK, 0);
        CDataStream ss2(SER_DISK, 0);
        ss1 << real_vector;
        ss2 << pre_vector;
        BOOST_CHECK_EQUAL(ss1.size(), ss2.size());
        for (Size s = 0; s < ss1.size(); s++) {
            BOOST_CHECK_EQUAL(ss1[s], ss2[s]);
        }
    }

public:
    void resize(Size s) {
        real_vector.resize(s);
        BOOST_CHECK_EQUAL(real_vector.size(), s);
        pre_vector.resize(s);
        BOOST_CHECK_EQUAL(pre_vector.size(), s);
        test();
    }

    void reserve(Size s) {
        real_vector.reserve(s);
        BOOST_CHECK(real_vector.capacity() >= s);
        pre_vector.reserve(s);
        BOOST_CHECK(pre_vector.capacity() >= s);
        test();
    }

    void insert(Size position, const T& value) {
        real_vector.insert(real_vector.begin() + position, value);
        pre_vector.insert(pre_vector.begin() + position, value);
        test();
    }

    void insert(Size position, Size count, const T& value) {
        real_vector.insert(real_vector.begin() + position, count, value);
        pre_vector.insert(pre_vector.begin() + position, count, value);
        test();
    }

    template<typename I>
    void insert_range(Size position, I first, I last) {
        real_vector.insert(real_vector.begin() + position, first, last);
        pre_vector.insert(pre_vector.begin() + position, first, last);
        test();
    }

    void erase(Size position) {
        real_vector.erase(real_vector.begin() + position);
        pre_vector.erase(pre_vector.begin() + position);
        test();
    }

    void erase(Size first, Size last) {
        real_vector.erase(real_vector.begin() + first, real_vector.begin() + last);
        pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last);
        test();
    }

    void update(Size pos, const T& value) {
        real_vector[pos] = value;
        pre_vector[pos] = value;
        test();
    }

    void push_back(const T& value) {
        real_vector.push_back(value);
        pre_vector.push_back(value);
        test();
    }

    void pop_back() {
        real_vector.pop_back();
        pre_vector.pop_back();
        test();
    }

    void clear() {
        real_vector.clear();
        pre_vector.clear();
    }

    void assign(Size n, const T& value) {
        real_vector.assign(n, value);
        pre_vector.assign(n, value);
    }

    Size size() {
        return real_vector.size();
    }

    Size capacity() {
        return pre_vector.capacity();
    }

    void shrink_to_fit() {
        pre_vector.shrink_to_fit();
        test();
    }

    void swap() {
        real_vector.swap(real_vector_alt);
        pre_vector.swap(pre_vector_alt);
        test();
    }
};

BOOST_AUTO_TEST_CASE(PrevectorTestInt)
{
    for (int j = 0; j < 64; j++) {
        prevector_tester<8, int> test;
        for (int i = 0; i < 2048; i++) {
            int r = InsecureRand32();
            if ((r % 4) == 0) {
                test.insert(InsecureRand32() % (test.size() + 1), InsecureRand32());
            }
            if (test.size() > 0 && ((r >> 2) % 4) == 1) {
                test.erase(InsecureRand32() % test.size());
            }
            if (((r >> 4) % 8) == 2) {
                int new_size = std::max<int>(0, std::min<int>(30, test.size() + (InsecureRand32() % 5) - 2));
                test.resize(new_size);
            }
            if (((r >> 7) % 8) == 3) {
                test.insert(InsecureRand32() % (test.size() + 1), 1 + (InsecureRand32() % 2), InsecureRand32());
            }
            if (((r >> 10) % 8) == 4) {
                int del = std::min<int>(test.size(), 1 + (InsecureRand32() % 2));
                int beg = InsecureRand32() % (test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            if (((r >> 13) % 16) == 5) {
                test.push_back(InsecureRand32());
            }
            if (test.size() > 0 && ((r >> 17) % 16) == 6) {
                test.pop_back();
            }
            if (((r >> 21) % 32) == 7) {
                int values[4];
                int num = 1 + (InsecureRand32() % 4);
                for (int i = 0; i < num; i++) {
                    values[i] = InsecureRand32();
                }
                test.insert_range(InsecureRand32() % (test.size() + 1), values, values + num);
            }
            if (((r >> 26) % 32) == 8) {
                int del = std::min<int>(test.size(), 1 + (InsecureRand32() % 4));
                int beg = InsecureRand32() % (test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            r = InsecureRand32();
            if (r % 32 == 9) {
                test.reserve(InsecureRand32() % 32);
            }
            if ((r >> 5) % 64 == 10) {
                test.shrink_to_fit();
            }
            if (test.size() > 0) {
                test.update(InsecureRand32() % test.size(), InsecureRand32());
            }
            if (((r >> 11) % 1024) == 11) {
                test.clear();
            }
            if (((r >> 21) % 512) == 12) {
                test.assign(InsecureRand32() % 32, InsecureRand32());
            }
            if (((r >> 15) % 64) == 3) {
                test.swap();
            }
        }
    }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*
 * File:   csg_fmatch_main.cc
 * Author: lukyanov
 *
 * Created on June 10, 2009, 5:00 PM
 */

#include <iostream>
#include <fstream>
#include <boost/program_options.hpp>
#include <cgengine.h>
#include <libversion.h>
#include "csg_fmatch.h"
/*
 *
 */
int main(int argc, char** argv)
{
    // we have one observer, this analyzes neamtic order
    CGForceMatching fmatch;
    // The CGEngine does the work
    CGEngine cg_engine;

    // add our observer that it gets called to analyze frames
    cg_engine.AddObserver((CGObserver*)&fmatch);

    // initialize the readers/writers,
    // this will be combined in an initialize function later
    TrajectoryWriter::RegisterPlugins();
    TrajectoryReader::RegisterPlugins();
    TopologyReader::RegisterPlugins();

    // lets read in some program options
    namespace po = boost::program_options;

    // Declare the supported options.
    po::options_description desc("Allowed options");

    desc.add_options()
      ("options", po::value<string>(), "options file for coarse graining");

    // let cg_engine add some program options
    cg_engine.AddProgramOptions(desc);

    // now read in the command line
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    // does the user want help?
    if (vm.count("help")) {
        cout << "csg_fmatch, lib version " << LIB_VERSION_STR << "\n\n";
        cout << desc << endl;
        return 0;
    }
    // or asks for the program version?
    if (vm.count("version")) {
        cout << "csg_fmatch, lib version " << LIB_VERSION_STR  << "\n";
        return 0;
    }

    if(!vm.count("options")) {
        cout << "need to specify options file\n";
        cout << desc << endl;
        return -1;
    }

    fmatch.LoadOptions(vm["options"].as<string>());

    // try to run the cg process, go through the frames, etc...
    try {
        cg_engine.Run(desc, vm);
    }
    // did an error occour?
    catch(string error) {
        cerr << "An error occoured!" << endl << error << endl;
    }
    return 0;
}
<commit_msg>improved error handling from Victor<commit_after>/*
 * File:   csg_fmatch_main.cc
 * Author: lukyanov
 *
 * Created on June 10, 2009, 5:00 PM
 */

#include <iostream>
#include <fstream>
#include <boost/program_options.hpp>
#include <cgengine.h>
#include <libversion.h>
#include "csg_fmatch.h"
/*
 *
 */
int main(int argc, char** argv)
{
    // we have one observer, this analyzes neamtic order
    CGForceMatching fmatch;
    // The CGEngine does the work
    CGEngine cg_engine;

    // add our observer that it gets called to analyze frames
    cg_engine.AddObserver((CGObserver*)&fmatch);

    // initialize the readers/writers,
    // this will be combined in an initialize function later
    TrajectoryWriter::RegisterPlugins();
    TrajectoryReader::RegisterPlugins();
    TopologyReader::RegisterPlugins();

    // lets read in some program options
    namespace po = boost::program_options;

    // Declare the supported options.
    po::options_description desc("Allowed options");

    desc.add_options()
      ("options", po::value<string>(), "options file for coarse graining");

    // let cg_engine add some program options
    cg_engine.AddProgramOptions(desc);

    // now read in the command line
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    // does the user want help?
    if (vm.count("help")) {
        cout << "csg_fmatch, lib version " << LIB_VERSION_STR << "\n\n";
        cout << desc << endl;
        return 0;
    }
    // or asks for the program version?
    if (vm.count("version")) {
        cout << "csg_fmatch, lib version " << LIB_VERSION_STR  << "\n";
        return 0;
    }

    if(!vm.count("options")) {
        cout << "need to specify options file\n";
        cout << desc << endl;
        return -1;
    }

    fmatch.LoadOptions(vm["options"].as<string>());

    // try to run the cg process, go through the frames, etc...
    try {
        cg_engine.Run(desc, vm);
    }

    // did an error occour?
    catch(exception &error) {
        cerr << "An error occoured!" << endl << error.what() << endl;
    }
    return 0;
}
<|endoftext|>


<commit_before>#define AN_BAUD 9600
#define AN_HANDSHAKE_IN "AN:HELLO_ARDUINO"
#define AN_HANDSHAKE_OUT "AN:HELLO_NODE"
#define AN_NL '\n'

void setup() {
  Serial.begin(AN_BAUD);
  _waitForHandShake();
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
}

void loop(){
  while (Serial.available() > 0) {
    int inByte = Serial.read();
    Serial.println(inByte);
    switch (inByte) {
      case '0':
         digitalWrite(13,LOW);
         break;
      case '1':
         digitalWrite(13,HIGH);
         break;
    }
  }
}

void _waitForHandShake(){
  bool handShaked = false;
  while (!handShaked) {
    String str = Serial.readStringUntil(AN_NL);
    if (str == AN_HANDSHAKE_IN) {
      Serial.write(AN_HANDSHAKE_OUT);
      handShaked = true;
    }
  }
}

<commit_msg>Just commenting out...<commit_after>#define AN_BAUD          9600
#define AN_HANDSHAKE_IN  "AN:HELLO_ARDUINO"
#define AN_HANDSHAKE_OUT "AN:HELLO_NODE"
#define AN_NL            '\n'

/**
 * Setup Arnode Stuff
 */
void setup() {
  // Open the serial port
  Serial.begin(AN_BAUD);
  // Wait for the hand-shake, before anything else
  _waitForHandShake();

  // test stuff
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
}

void loop(){

  // Scratch part, will be removed soon, now we need it for tests
  while (Serial.available() > 0) {
    int inByte = Serial.read();
    Serial.println(inByte);
    switch (inByte) {
      case '0':
         digitalWrite(13,LOW);
         break;
      case '1':
         digitalWrite(13,HIGH);
         break;
    }
  }
}

/**
 * Private 'method' to wait until the hand-shake is done :)
 */
void _waitForHandShake(){
  bool handShaked = false;
  while (!handShaked) {
    String str = Serial.readStringUntil(AN_NL);
    if (str == AN_HANDSHAKE_IN) {
      Serial.write(AN_HANDSHAKE_OUT);
      handShaked = true;
    }
  }
}
<|endoftext|>


<commit_before>/*
  PWM.cpp - PWM library v1.0.0 - 10-04-2016
  Copyright (c) 2006-2008 Dani Gonzalez.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.
*/

//******************************************************************************
//* Includes
//******************************************************************************

#include "Arduino.h"
#include "PWM.h"

//******************************************************************************
//* Constructors
//******************************************************************************

PWM::PWM(int pin){
   pinMode(pin, OUTPUT);
   _pin = pin;
}

//******************************************************************************
//* Public Methods
//******************************************************************************

/* handler method that use a timer and a counter to make the cycle */
int PWM::handler(){
	_tempActual = micros();
  if (_tempActual - _tempVell >= _retard) {
    _tempVell = _tempActual;
    _counter++;
    if (_counter == 101) {
      _counter = 0;
    }
    if (_dutyCicle > _counter || _dutyCicle == 100) {
      digitalWrite(_pin, HIGH);
    } else {
      digitalWrite(_pin, LOW);
    }
  }
  return digitalRead(_pin);
}

/* setDuty method to set the time period in which the output is on */
void PWM::setDuty(int dutyCicle){
	_dutyCicle=dutyCicle;
}
/* setRetard method to set the period of the time cycle */
void PWM::setRetard(unsigned long retard){
	_retard=retard;
}

/* getCounter method to get the actual value of the progressive 1-100 counter */
int PWM::getCounter(){
   return _counter;
}

<commit_msg>Delete PWM.cpp<commit_after><|endoftext|>


<commit_before>///
/// @file  S2_easy.cpp
/// @brief Calculate the contribution of the clustered easy leaves
///        and the sparse easy leaves in parallel using OpenMP
///        (Deleglise-Rivat algorithm).
///
/// Copyright (C) 2016 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <PiTable.hpp>
#include <primecount-internal.hpp>
#include <calculator.hpp>
#include <fast_div.hpp>
#include <generate.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <imath.hpp>
#include <S2Status.hpp>
#include <S2.hpp>
#include <json.hpp>

#include <stdint.h>
#include <vector>
#include <fstream>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;
using namespace nlohmann;

namespace {

template <typename T>
void backup(T x,
            int64_t y,
            int64_t z,
            int64_t c,
            int64_t start,
            int64_t pi_x13,
            T s2_easy,
            double percent,
            double time)
{
  ifstream ifs("primecount.backup");
  json j;

  if (ifs.is_open())
  {
    ifs >> j;
    ifs.close();
  }

  if (j.find("S2_easy") != j.end())
    j.erase(j.find("S2_easy"));

  j["S2_easy"]["x"] = to_string(x);
  j["S2_easy"]["y"] = y;
  j["S2_easy"]["z"] = z;
  j["S2_easy"]["c"] = c;
  j["S2_easy"]["start"] = start;
  j["S2_easy"]["pi_x13"] = pi_x13;
  j["S2_easy"]["s2_easy"] = to_string(s2_easy);
  j["S2_easy"]["percent"] = percent;
  j["S2_easy"]["seconds"] = get_wtime() - time;

  ofstream ofs("primecount.backup");
  ofs << setw(4) << j << endl;
}

template <typename T>
bool resume(T x,
            int64_t y,
            int64_t z,
            int64_t c,
            int64_t& start,
            int64_t& pi_x13,
            T& s2_easy,
            double& time)
{
  ifstream ifs("primecount.backup");
  json j;

  if (ifs.is_open())
  {
    ifs >> j;
    ifs.close();
  }

  if (j.find("S2_easy") != j.end() &&
      x == calculator::eval<T>(j["S2_easy"]["x"]) &&
      y == j["S2_easy"]["y"] &&
      z == j["S2_easy"]["z"] &&
      c == j["S2_easy"]["c"])
  {
    start = j["S2_easy"]["start"];
    pi_x13 = j["S2_easy"]["pi_x13"];
    s2_easy = calculator::eval<T>(j["S2_easy"]["s2_easy"]);
    double seconds = j["S2_easy"]["seconds"];
    time = get_wtime() - seconds;

    if (is_print())
    {
      if (!print_variables())
        cout << endl;

      cout << "=== Resuming from primecount.backup ===" << endl;
      cout << "start = " << start << endl;
      cout << "pi_x13 = " << pi_x13 << endl;
      cout << "s2_easy = " << s2_easy << endl;
      cout << "Seconds: " << seconds << endl;
      cout << endl;
    }

    return true;
  }

  return false;
}

/// Calculate the contribution of the clustered easy leaves
/// and the sparse easy leaves.
/// @param T  either int64_t or uint128_t.
///
template <typename T, typename Primes>
T S2_easy_OpenMP(T x,
                 int64_t y,
                 int64_t z,
                 int64_t c,
                 Primes& primes,
                 int threads,
                 double& time)
{
  T s2_easy = 0;
  int64_t start;
  int64_t pi_x13;
  double backup_time = get_wtime();

  if (resume(x, y, z, c, start, pi_x13, s2_easy, time) && start >= pi_x13)
    return s2_easy;

  PiTable pi(y);
  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t x13 = iroot<3>(x);
  int64_t max_dist = 1;
  int64_t thread_threshold = 1000;
  threads = ideal_num_threads(threads, x13, thread_threshold);

  pi_x13 = pi[x13];
  start = max(c, pi_sqrty) + 1;
  S2Status status(x);

  while (start <= pi_x13)
  {
    int64_t stop = min(start + max_dist * threads, pi_x13);

    #pragma omp parallel for schedule(dynamic) num_threads(threads) reduction(+: s2_easy)
    for (int64_t b = start; b <= stop; b++)
    {
      int64_t prime = primes[b];
      T x2 = x / prime;
      int64_t min_trivial = min(x2 / prime, y);
      int64_t min_clustered = (int64_t) isqrt(x2);
      int64_t min_sparse = z / prime;

      min_clustered = in_between(prime, min_clustered, y);
      min_sparse = in_between(prime, min_sparse, y);

      int64_t l = pi[min_trivial];
      int64_t pi_min_clustered = pi[min_clustered];
      int64_t pi_min_sparse = pi[min_sparse];

      // Find all clustered easy leaves:
      // n = primes[b] * primes[l]
      // x / n <= y && phi(x / n, b - 1) == phi(x / m, b - 1)
      // where phi(x / n, b - 1) = pi(x / n) - b + 2
      while (l > pi_min_clustered)
      {
        int64_t xn = (int64_t) fast_div(x2, primes[l]);
        int64_t phi_xn = pi[xn] - b + 2;
        int64_t xm = (int64_t) fast_div(x2, primes[b + phi_xn - 1]);
        int64_t l2 = pi[xm];
        s2_easy += phi_xn * (l - l2);
        l = l2;
      }

      // Find all sparse easy leaves:
      // n = primes[b] * primes[l]
      // x / n <= y && phi(x / n, b - 1) = pi(x / n) - b + 2
      for (; l > pi_min_sparse; l--)
      {
        int64_t xn = (int64_t) fast_div(x2, primes[l]);
        s2_easy += pi[xn] - b + 2;
      }

      if (is_print())
        status.print(b, pi_x13);
    }

    start = stop + 1;

    if (get_wtime() - backup_time < 60)
      max_dist *= 2;
    else
    {
      max_dist = ceil_div(max_dist, 2);
      double percent = status.getPercent(start, pi_x13, start, pi_x13);
      backup(x, y, z, c, start, pi_x13, s2_easy, percent, time);
      backup_time = get_wtime();
    }
  }

  backup(x, y, z, c, pi_x13, pi_x13, s2_easy, 100, time);

  return s2_easy;
}

} // namespace

namespace primecount {

int64_t S2_easy(int64_t x,
                int64_t y,
                int64_t z,
                int64_t c,
                int threads)
{
#ifdef HAVE_MPI
  if (mpi_num_procs() > 1)
    return S2_easy_mpi(x, y, z, c, threads);
#endif

  print("");
  print("=== S2_easy(x, y) ===");
  print("Computation of the easy special leaves");
  print(x, y, c, threads);

  double time = get_wtime();
  auto primes = generate_primes<int32_t>(y);
  int64_t s2_easy = S2_easy_OpenMP((intfast64_t) x, y, z, c, primes, threads, time);

  print("S2_easy", s2_easy, time);
  return s2_easy;
}

#ifdef HAVE_INT128_T

int128_t S2_easy(int128_t x,
                 int64_t y,
                 int64_t z,
                 int64_t c,
                 int threads)
{
#ifdef HAVE_MPI
  if (mpi_num_procs() > 1)
    return S2_easy_mpi(x, y, z, c, threads);
#endif

  print("");
  print("=== S2_easy(x, y) ===");
  print("Computation of the easy special leaves");
  print(x, y, c, threads);

  int128_t s2_easy;
  double time = get_wtime();

  // uses less memory
  if (y <= numeric_limits<uint32_t>::max())
  {
    auto primes = generate_primes<uint32_t>(y);
    s2_easy = S2_easy_OpenMP((intfast128_t) x, y, z, c, primes, threads, time);
  }
  else
  {
    auto primes = generate_primes<int64_t>(y);
    s2_easy = S2_easy_OpenMP((intfast128_t) x, y, z, c, primes, threads, time);
  }

  print("S2_easy", s2_easy, time);
  return s2_easy;
}

#endif

} // namespace
<commit_msg>Refactor<commit_after>///
/// @file  S2_easy.cpp
/// @brief Calculate the contribution of the clustered easy leaves
///        and the sparse easy leaves in parallel using OpenMP
///        (Deleglise-Rivat algorithm).
///
/// Copyright (C) 2016 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <PiTable.hpp>
#include <primecount-internal.hpp>
#include <calculator.hpp>
#include <fast_div.hpp>
#include <generate.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <imath.hpp>
#include <S2Status.hpp>
#include <S2.hpp>
#include <json.hpp>

#include <stdint.h>
#include <vector>
#include <fstream>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;
using namespace nlohmann;

namespace {

template <typename T>
void backup(T x,
            int64_t y,
            int64_t z,
            int64_t c,
            int64_t start,
            int64_t pi_x13,
            T s2_easy,
            double percent,
            double time)
{
  ifstream ifs("primecount.backup");
  json j;

  if (ifs.is_open())
  {
    ifs >> j;
    ifs.close();
  }

  if (j.find("S2_easy") != j.end())
    j.erase(j.find("S2_easy"));

  j["S2_easy"]["x"] = to_string(x);
  j["S2_easy"]["y"] = y;
  j["S2_easy"]["z"] = z;
  j["S2_easy"]["c"] = c;
  j["S2_easy"]["start"] = start;
  j["S2_easy"]["pi_x13"] = pi_x13;
  j["S2_easy"]["s2_easy"] = to_string(s2_easy);
  j["S2_easy"]["percent"] = percent;
  j["S2_easy"]["seconds"] = get_wtime() - time;

  ofstream ofs("primecount.backup");
  ofs << setw(4) << j << endl;
}

template <typename T>
bool resume(T x,
            int64_t y,
            int64_t z,
            int64_t c,
            int64_t& start,
            int64_t& pi_x13,
            T& s2_easy,
            double& time)
{
  ifstream ifs("primecount.backup");
  json j;

  if (ifs.is_open())
  {
    ifs >> j;
    ifs.close();
  }

  if (j.find("S2_easy") != j.end() &&
      x == calculator::eval<T>(j["S2_easy"]["x"]) &&
      y == j["S2_easy"]["y"] &&
      z == j["S2_easy"]["z"] &&
      c == j["S2_easy"]["c"])
  {
    double percent = j["S2_easy"]["percent"];
    double seconds = j["S2_easy"]["seconds"];

    start = j["S2_easy"]["start"];
    pi_x13 = j["S2_easy"]["pi_x13"];
    s2_easy = calculator::eval<T>(j["S2_easy"]["s2_easy"]);
    time = get_wtime() - seconds;

    if (is_print())
    {
      if (!print_variables())
        cout << endl;

      cout << "=== Resuming from primecount.backup ===" << endl;
      cout << "start = " << start << endl;
      cout << "pi_x13 = " << pi_x13 << endl;
      cout << "s2_easy = " << s2_easy << endl;
      cout << "Seconds: " << seconds << endl << endl;
      cout << "Status: " << fixed << setprecision(get_status_precision(x)) << percent << '%' << flush;
    }

    return true;
  }

  return false;
}

/// Calculate the contribution of the clustered easy leaves
/// and the sparse easy leaves.
/// @param T  either int64_t or uint128_t.
///
template <typename T, typename Primes>
T S2_easy_OpenMP(T x,
                 int64_t y,
                 int64_t z,
                 int64_t c,
                 Primes& primes,
                 int threads,
                 double& time)
{
  T s2_easy = 0;
  int64_t start;
  int64_t pi_x13;
  double backup_time = get_wtime();
  bool is_resume = resume(x, y, z, c, start, pi_x13, s2_easy, time);

  if (is_resume && start >= pi_x13)
    return s2_easy;

  PiTable pi(y);
  S2Status status(x);

  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t x13 = iroot<3>(x);
  int64_t max_dist = 1;
  int64_t thread_threshold = 1000;
  threads = ideal_num_threads(threads, x13, thread_threshold);

  if (!is_resume)
  {
    start = max(c, pi_sqrty) + 1;
    pi_x13 = pi[x13];
  }

  while (start <= pi_x13)
  {
    int64_t stop = min(start + max_dist * threads, pi_x13);

    #pragma omp parallel for schedule(dynamic) num_threads(threads) reduction(+: s2_easy)
    for (int64_t b = start; b <= stop; b++)
    {
      int64_t prime = primes[b];
      T x2 = x / prime;
      int64_t min_trivial = min(x2 / prime, y);
      int64_t min_clustered = (int64_t) isqrt(x2);
      int64_t min_sparse = z / prime;

      min_clustered = in_between(prime, min_clustered, y);
      min_sparse = in_between(prime, min_sparse, y);

      int64_t l = pi[min_trivial];
      int64_t pi_min_clustered = pi[min_clustered];
      int64_t pi_min_sparse = pi[min_sparse];

      // Find all clustered easy leaves:
      // n = primes[b] * primes[l]
      // x / n <= y && phi(x / n, b - 1) == phi(x / m, b - 1)
      // where phi(x / n, b - 1) = pi(x / n) - b + 2
      while (l > pi_min_clustered)
      {
        int64_t xn = (int64_t) fast_div(x2, primes[l]);
        int64_t phi_xn = pi[xn] - b + 2;
        int64_t xm = (int64_t) fast_div(x2, primes[b + phi_xn - 1]);
        int64_t l2 = pi[xm];
        s2_easy += phi_xn * (l - l2);
        l = l2;
      }

      // Find all sparse easy leaves:
      // n = primes[b] * primes[l]
      // x / n <= y && phi(x / n, b - 1) = pi(x / n) - b + 2
      for (; l > pi_min_sparse; l--)
      {
        int64_t xn = (int64_t) fast_div(x2, primes[l]);
        s2_easy += pi[xn] - b + 2;
      }

      if (is_print())
        status.print(b, pi_x13);
    }

    start = stop + 1;

    if (get_wtime() - backup_time < 60)
      max_dist *= 2;
    else
    {
      max_dist = ceil_div(max_dist, 2);
      double percent = status.getPercent(start, pi_x13, start, pi_x13);
      backup(x, y, z, c, start, pi_x13, s2_easy, percent, time);
      backup_time = get_wtime();
    }
  }

  backup(x, y, z, c, pi_x13, pi_x13, s2_easy, 100, time);

  return s2_easy;
}

} // namespace

namespace primecount {

int64_t S2_easy(int64_t x,
                int64_t y,
                int64_t z,
                int64_t c,
                int threads)
{
#ifdef HAVE_MPI
  if (mpi_num_procs() > 1)
    return S2_easy_mpi(x, y, z, c, threads);
#endif

  print("");
  print("=== S2_easy(x, y) ===");
  print("Computation of the easy special leaves");
  print(x, y, c, threads);

  double time = get_wtime();
  auto primes = generate_primes<int32_t>(y);
  int64_t s2_easy = S2_easy_OpenMP((intfast64_t) x, y, z, c, primes, threads, time);

  print("S2_easy", s2_easy, time);
  return s2_easy;
}

#ifdef HAVE_INT128_T

int128_t S2_easy(int128_t x,
                 int64_t y,
                 int64_t z,
                 int64_t c,
                 int threads)
{
#ifdef HAVE_MPI
  if (mpi_num_procs() > 1)
    return S2_easy_mpi(x, y, z, c, threads);
#endif

  print("");
  print("=== S2_easy(x, y) ===");
  print("Computation of the easy special leaves");
  print(x, y, c, threads);

  int128_t s2_easy;
  double time = get_wtime();

  // uses less memory
  if (y <= numeric_limits<uint32_t>::max())
  {
    auto primes = generate_primes<uint32_t>(y);
    s2_easy = S2_easy_OpenMP((intfast128_t) x, y, z, c, primes, threads, time);
  }
  else
  {
    auto primes = generate_primes<int64_t>(y);
    s2_easy = S2_easy_OpenMP((intfast128_t) x, y, z, c, primes, threads, time);
  }

  print("S2_easy", s2_easy, time);
  return s2_easy;
}

#endif

} // namespace
<|endoftext|>


<commit_before>/*
Copyright (c) 2011 Steve Revill and Shane Woolcock
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 <windows.h>
#include <string.h>
#include <iostream>

#include <time.h>
#include <Shellapi.h>
extern gxtkAudio *bb_audio_device;
extern gxtkGraphics *bb_graphics_device;

float diddy_mouseWheel = 0.0f;

float diddy_mouseZ() {
	float ret = glfwGetMouseWheel() - diddy_mouseWheel;
	diddy_mouseWheel = glfwGetMouseWheel();
	return ret;
}

class diddy
{
	public:

	// Returns an empty string if dialog is cancelled
	static String openfilename() {
		char *filter = "All Files (*.*)\0*.*\0";
		HWND owner = NULL;
		OPENFILENAME ofn;
		char fileName[MAX_PATH] = "";
		ZeroMemory(&ofn, sizeof(ofn));

		ofn.lStructSize = sizeof(OPENFILENAME);
		ofn.hwndOwner = owner;
		ofn.lpstrFilter = filter;
		ofn.lpstrFile = fileName;
		ofn.nMaxFile = MAX_PATH;
		ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
		ofn.lpstrDefExt = "";

		String fileNameStr;

		if ( GetOpenFileName(&ofn) )
			fileNameStr = fileName;

		return fileNameStr;
	}

	static String savefilename() {
		char *filter = "All Files (*.*)\0*.*\0";
		HWND owner = NULL;
		OPENFILENAME ofn;
		char fileName[MAX_PATH] = "";
		ZeroMemory(&ofn, sizeof(ofn));

		ofn.lStructSize = sizeof(OPENFILENAME);
		ofn.hwndOwner = owner;
		ofn.lpstrFilter = filter;
		ofn.lpstrFile = fileName;
		ofn.nMaxFile = MAX_PATH;
		ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
		ofn.lpstrDefExt = "";

		String fileNameStr;

		if ( GetSaveFileNameA(&ofn) )
			fileNameStr = fileName;

		return fileNameStr;
	}

	static float mouseZ()
	{
		return diddy_mouseZ();
	}

	static void mouseZInit()
	{
		return;
	}

	// only accurate to 1 second
	static int systemMillisecs() {
		time_t seconds;
		seconds = time (NULL);
		return seconds * 1000;
	}

	static void setGraphics(int w, int h)
	{
		glfwSetWindowSize(w, h);
		GLFWvidmode desktopMode;
		glfwGetDesktopMode( &desktopMode );
		glfwSetWindowPos( (desktopMode.Width-w)/2,(desktopMode.Height-h)/2 );
	}

	static void setMouse(int x, int y)
	{
		glfwSetMousePos(x, y);
	}

	static void showKeyboard()
	{
	}
	static void launchBrowser(String address, String windowName)
	{
		LPCSTR addressStr = address.ToCString<char>();
		ShellExecute(HWND_DESKTOP, "open", addressStr, NULL, NULL, SW_SHOWNORMAL);
	}
	static void launchEmail(String email, String subject, String text)
	{
		String tmp = "mailto:";
		tmp+=email;
		tmp+="&subject=";
		tmp+=subject;
		tmp+="&body=";
		tmp+=text;
		LPCSTR addressStr = tmp.ToCString<char>();
		ShellExecute(HWND_DESKTOP, "open", addressStr, NULL, NULL, SW_SHOWNORMAL);
	}

	static void startVibrate(int millisecs)
	{
	}
	static void stopVibrate()
	{
	}

	static int getDayOfMonth()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wDay;
	}

	static int getDayOfWeek()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wDayOfWeek;
	}

	static int getMonth()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wMonth;
	}

	static int getYear()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wYear;
	}

	static int getHours()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wHour;
	}

	static int getMinutes()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wMinute;
	}

	static int getSeconds()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wSecond;
	}

	static int getMilliSeconds()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wMilliseconds;
	}

	static void startGps()
	{
	}
	static String getLatitiude()
	{
		return "";
	}
	static String getLongitude()
	{
		return "";
	}
	static void showAlertDialog(String title, String message)
	{
	}
	static String getInputString()
	{
		return "";
	}

	static int seekMusic(int timeMillis)
	{
		gxtkChannel *chan = &(bb_audio_device->channels[32]);
		if(chan && chan->state==1)
		{
			alSourcef(chan->source, AL_SEC_OFFSET, (float)(timeMillis / 1000.0));
		}
		// TODO: check it worked
		return 1;
	}
};
<commit_msg>Added ifdefs WIN32 to GLFW C++ - hopefully now it will compile with Linux (UNTESTED!)<commit_after>/*
Copyright (c) 2011 Steve Revill and Shane Woolcock
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.
*/

#ifdef _WIN32
#include <windows.h>
#include <Shellapi.h>
#include <iostream>
#endif

#include <string.h>
#include <time.h>

extern gxtkAudio *bb_audio_device;
extern gxtkGraphics *bb_graphics_device;

float diddy_mouseWheel = 0.0f;

float diddy_mouseZ() {
	float ret = glfwGetMouseWheel() - diddy_mouseWheel;
	diddy_mouseWheel = glfwGetMouseWheel();
	return ret;
}

class diddy
{
	public:

	// Returns an empty string if dialog is cancelled
	static String openfilename() {
		#ifdef _WIN32
		char *filter = "All Files (*.*)\0*.*\0";
		HWND owner = NULL;
		OPENFILENAME ofn;
		char fileName[MAX_PATH] = "";
		ZeroMemory(&ofn, sizeof(ofn));

		ofn.lStructSize = sizeof(OPENFILENAME);
		ofn.hwndOwner = owner;
		ofn.lpstrFilter = filter;
		ofn.lpstrFile = fileName;
		ofn.nMaxFile = MAX_PATH;
		ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
		ofn.lpstrDefExt = "";

		String fileNameStr;

		if ( GetOpenFileName(&ofn) )
			fileNameStr = fileName;

		return fileNameStr;
		#endif
		#ifdef linux
		return "";
		#endif
	}

	static String savefilename() {
		#ifdef _WIN32
		char *filter = "All Files (*.*)\0*.*\0";
		HWND owner = NULL;
		OPENFILENAME ofn;
		char fileName[MAX_PATH] = "";
		ZeroMemory(&ofn, sizeof(ofn));

		ofn.lStructSize = sizeof(OPENFILENAME);
		ofn.hwndOwner = owner;
		ofn.lpstrFilter = filter;
		ofn.lpstrFile = fileName;
		ofn.nMaxFile = MAX_PATH;
		ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
		ofn.lpstrDefExt = "";

		String fileNameStr;

		if ( GetSaveFileNameA(&ofn) )
			fileNameStr = fileName;

		return fileNameStr;
		#endif
		#ifdef linux
		return "";
		#endif
	}

	static float mouseZ()
	{
		return diddy_mouseZ();
	}

	static void mouseZInit()
	{
		return;
	}

	// only accurate to 1 second
	static int systemMillisecs() {
		time_t seconds;
		seconds = time (NULL);
		return seconds * 1000;
	}

	static void setGraphics(int w, int h)
	{
		glfwSetWindowSize(w, h);
		GLFWvidmode desktopMode;
		glfwGetDesktopMode( &desktopMode );
		glfwSetWindowPos( (desktopMode.Width-w)/2,(desktopMode.Height-h)/2 );
	}

	static void setMouse(int x, int y)
	{
		glfwSetMousePos(x, y);
	}

	static void showKeyboard()
	{
	}
	static void launchBrowser(String address, String windowName)
	{
		#ifdef _WIN32
		LPCSTR addressStr = address.ToCString<char>();
		ShellExecute(HWND_DESKTOP, "open", addressStr, NULL, NULL, SW_SHOWNORMAL);
		#endif
	}
	static void launchEmail(String email, String subject, String text)
	{
		#ifdef _WIN32
		String tmp = "mailto:";
		tmp+=email;
		tmp+="&subject=";
		tmp+=subject;
		tmp+="&body=";
		tmp+=text;
		LPCSTR addressStr = tmp.ToCString<char>();
		ShellExecute(HWND_DESKTOP, "open", addressStr, NULL, NULL, SW_SHOWNORMAL);
		#endif
	}

	static void startVibrate(int millisecs)
	{
	}
	static void stopVibrate()
	{
	}

	static int getDayOfMonth()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wDay;
	}

	static int getDayOfWeek()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wDayOfWeek;
	}

	static int getMonth()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wMonth;
	}

	static int getYear()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wYear;
	}

	static int getHours()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wHour;
	}

	static int getMinutes()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wMinute;
	}

	static int getSeconds()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wSecond;
	}

	static int getMilliSeconds()
	{
		SYSTEMTIME st;
		GetSystemTime(&st);
		return st.wMilliseconds;
	}

	static void startGps()
	{
	}
	static String getLatitiude()
	{
		return "";
	}
	static String getLongitude()
	{
		return "";
	}
	static void showAlertDialog(String title, String message)
	{
	}
	static String getInputString()
	{
		return "";
	}

	static int seekMusic(int timeMillis)
	{
		gxtkChannel *chan = &(bb_audio_device->channels[32]);
		if(chan && chan->state==1)
		{
			alSourcef(chan->source, AL_SEC_OFFSET, (float)(timeMillis / 1000.0));
		}
		// TODO: check it worked
		return 1;
	}
};
<|endoftext|>


<commit_before>
#include "journal/player.hpp"

#include <chrono>
#include <filesystem>
#include <string>

#include "base/array.hpp"
#include "base/get_line.hpp"
#include "base/hexadecimal.hpp"
#include "journal/profiles.hpp"
#include "glog/logging.h"

namespace principia {

using base::GetLine;
using base::HexadecimalEncoder;
using base::UniqueArray;
using interface::principia__ActivatePlayer;

namespace journal {

Player::Player(std::filesystem::path const& path)
    : stream_(path, std::ios::in) {
  principia__ActivatePlayer();
  CHECK(!stream_.fail());
}

bool Player::Play(int const index) {
  std::unique_ptr<serialization::Method> method_in = Read();
  if (method_in == nullptr) {
    // End of input file.
    return false;
  }
  std::unique_ptr<serialization::Method> method_out_return = Read();
  if (method_out_return == nullptr) {
    LOG(ERROR) << "Unpaired method:\n" << method_in->DebugString();
    return false;
  }

#if 0
  if (index == 3171451) {
    LOG_IF(ERROR, index > 3170000) << "index: " << index << "\n"
                                   << method_in->ShortDebugString() << "\n"
                                   << method_out_return->ShortDebugString();
  }
#endif

  auto const before = std::chrono::system_clock::now();

#include "journal/player.generated.cc"

  auto const after = std::chrono::system_clock::now();
  if (after - before > std::chrono::milliseconds(100)) {
    LOG(ERROR) << "Long method:\n" << method_in->DebugString();
  }

  last_method_in_.swap(method_in);
  last_method_out_return_.swap(method_out_return);

  return true;
}

serialization::Method const& Player::last_method_in() const {
  return *last_method_in_;
}

serialization::Method const& Player::last_method_out_return() const {
  return *last_method_out_return_;
}

std::unique_ptr<serialization::Method> Player::Read() {
  std::string const line = GetLine(stream_);
  if (line.empty()) {
    return nullptr;
  }

  static auto* const encoder = new HexadecimalEncoder</*null_terminated=*/true>;
  auto const bytes = encoder->Decode({line.c_str(), strlen(line.c_str())});
  auto method = std::make_unique<serialization::Method>();
  CHECK(method->ParseFromArray(bytes.data.get(), static_cast<int>(bytes.size)));

  return method;
}

}  // namespace journal
}  // namespace principia
<commit_msg>Cleanup.<commit_after>
#include "journal/player.hpp"

#include <chrono>
#include <filesystem>
#include <string>

#include "base/array.hpp"
#include "base/get_line.hpp"
#include "base/hexadecimal.hpp"
#include "journal/profiles.hpp"
#include "glog/logging.h"

namespace principia {

using base::GetLine;
using base::HexadecimalEncoder;
using base::UniqueArray;
using interface::principia__ActivatePlayer;

namespace journal {

Player::Player(std::filesystem::path const& path)
    : stream_(path, std::ios::in) {
  principia__ActivatePlayer();
  CHECK(!stream_.fail());
}

bool Player::Play(int const index) {
  std::unique_ptr<serialization::Method> method_in = Read();
  if (method_in == nullptr) {
    // End of input file.
    return false;
  }
  std::unique_ptr<serialization::Method> method_out_return = Read();
  if (method_out_return == nullptr) {
    LOG(ERROR) << "Unpaired method:\n" << method_in->DebugString();
    return false;
  }

#if 0
  LOG_IF(ERROR, index > 3170000) << "index: " << index << "\n"
                                 << method_in->ShortDebugString() << "\n"
                                 << method_out_return->ShortDebugString();
#endif

  auto const before = std::chrono::system_clock::now();

#include "journal/player.generated.cc"

  auto const after = std::chrono::system_clock::now();
  if (after - before > std::chrono::milliseconds(100)) {
    LOG(ERROR) << "Long method:\n" << method_in->DebugString();
  }

  last_method_in_.swap(method_in);
  last_method_out_return_.swap(method_out_return);

  return true;
}

serialization::Method const& Player::last_method_in() const {
  return *last_method_in_;
}

serialization::Method const& Player::last_method_out_return() const {
  return *last_method_out_return_;
}

std::unique_ptr<serialization::Method> Player::Read() {
  std::string const line = GetLine(stream_);
  if (line.empty()) {
    return nullptr;
  }

  static auto* const encoder = new HexadecimalEncoder</*null_terminated=*/true>;
  auto const bytes = encoder->Decode({line.c_str(), strlen(line.c_str())});
  auto method = std::make_unique<serialization::Method>();
  CHECK(method->ParseFromArray(bytes.data.get(), static_cast<int>(bytes.size)));

  return method;
}

}  // namespace journal
}  // namespace principia
<|endoftext|>


<commit_before>// TasksView.cpp : implementation of the CTasksView class
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"

#include "TasksView.h"
#include <net/utf8.hpp>
#include <algorithm>
#include <sstream>

class TaskViewModelListener : public CAppModelListener {
	HWND m_hWnd;
public:
	TaskViewModelListener(HWND hWnd) : m_hWnd(hWnd) {}

	void onListChanged(uint32_t addedOrRemoved) override
	{
		// traversing the borders of threads, if needed
		// also, the actual reaction to the vent will
		// not block the emit up there
		if (IsWindow(m_hWnd))
			PostMessage(m_hWnd, UM_LISTCHANGED, addedOrRemoved, 0);
	}
};

class ServerListener : public jira::server_listener {
	HWND m_hWnd;
	uint32_t m_sessionId;
public:
	ServerListener(HWND hWnd, uint32_t sessionId) : m_hWnd(hWnd), m_sessionId(sessionId) {}

	void onRefreshStarted() override
	{
		if (IsWindow(m_hWnd))
			PostMessage(m_hWnd, UM_REFRESHSTART, m_sessionId, 0);
	}

	void onRefreshFinished() override
	{
		if (IsWindow(m_hWnd))
			PostMessage(m_hWnd, UM_REFRESHSTOP, m_sessionId, 0);
	}
};

std::vector<CTasksView::ServerInfo>::iterator CTasksView::find(uint32_t sessionId)
{
	return std::find_if(std::begin(m_servers), std::end(m_servers), [sessionId](const ServerInfo& info) { return info.m_sessionId == sessionId; });
}

std::vector<CTasksView::ServerInfo>::iterator CTasksView::insert(std::vector<ServerInfo>::const_iterator it, const std::shared_ptr<jira::server>& server)
{
	// TODO: create UI element
	// TDOD: attach refresh listener to the server
	auto listener = std::make_shared<ServerListener>(m_hWnd, server->sessionId());
	return m_servers.emplace(it, server, listener);
}

std::vector<CTasksView::ServerInfo>::iterator CTasksView::erase(std::vector<ServerInfo>::const_iterator it)
{
	// TODO: destroy UI element
	// TDOD: detach refresh listener from the server
	return m_servers.erase(it);
}

BOOL CTasksView::PreTranslateMessage(MSG* pMsg)
{
	pMsg;
	return FALSE;
}

LRESULT CTasksView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	m_listener = std::make_shared<TaskViewModelListener>(m_hWnd);
	m_model->registerListener(m_listener);
	return 0;
}

LRESULT CTasksView::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	m_model->unregisterListener(m_listener);
	return 0;
}

LRESULT CTasksView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	CPaintDC dc(m_hWnd);

	//TODO: Add your drawing code here

	return 0;
}

LRESULT CTasksView::OnListChanged(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	OutputDebugString(utf::widen(std::to_string((UINT_PTR) m_hWnd) + ": OnListChanged(" +std::to_string(wParam) + ")\n").c_str());

	// TODO: lock updates
	if (wParam) {
		// a server has been added or removed...
		auto it = find(wParam);
		if (it == m_servers.end()) { // it was added
			synchronize(*m_model, [&] {
				auto& servers = m_model->servers();
				// find the location of the ID; hint: it might be at the end
				auto rit = std::find_if(std::rbegin(servers), std::rend(servers), [&](const std::shared_ptr<jira::server>& server) { return server->sessionId() == wParam; });
				if (rit != std::rend(servers)) {
					auto it = std::begin(m_servers);

					// it += (rit.base() - servers.begin())
					 std::advance(it, std::distance(std::begin(servers), rit.base()));

					 insert(it, *rit);
				}
			});
		} else
			erase(it);
	} else {
		// no specific item has changed, go over entire model
		synchronize(*m_model, [&] {
			auto& servers = m_model->servers();

			auto it = std::begin(m_servers);
			auto end = std::end(m_servers);

			// for each ServerInfo: if not in model - remove
			while (it != end) {
				auto query = std::find_if(std::begin(servers), std::end(servers), [&](const std::shared_ptr<jira::server>& srv) { return srv->sessionId() == it->m_sessionId; });
				if (query == std::end(servers))
				{
					it = erase(it);
					end = std::end(m_servers);
				}
			}

			// for each server in model: if not in ServerInfos - add
			// side note: we have only items from the model, granted maybe not the ALL items
			// if we kept track of additions/deletions, they are in the same order as in the model
			// we just need to fill in the holes...

			it = std::begin(m_servers);
			end = std::end(m_servers);
			auto srv_it = std::begin(servers);
			auto srv_end = std::end(servers);

			for (; srv_it != srv_end; ++srv_it) {
				if (it != end && (*srv_it)->sessionId() == it->m_sessionId) {
					++it;
					continue;
				}

				it = insert(it, *srv_it); // fill in blanks...
				end = std::end(m_servers);
			}
		});
	}
	// TODO: unlock updates

	return 0;
}

LRESULT CTasksView::OnRefreshStart(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	OutputDebugString(utf::widen(std::to_string((UINT_PTR) m_hWnd) + ": OnRefreshStart(" + std::to_string(wParam) + ")\n").c_str());
	return 0;
}

LRESULT CTasksView::OnRefreshStop(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	OutputDebugString(utf::widen(std::to_string((UINT_PTR) m_hWnd) + ": OnRefreshStop(" + std::to_string(wParam) + ")\n").c_str());

	auto it = find(wParam);
	if (it == m_servers.end())
		return 0;

	auto& server = *it->m_server;
	it->m_dataset = server.dataset();
	// TODO: update layout
	// TODO: redraw the report table

	auto& dataset = *it->m_dataset;
	std::ostringstream o;
	o << "-----------------------------------------------\n"
		<< "Answer from: " << server.login() << " @ " << server.displayName() << "\n"
		<< "Query: " << (server.view().jql().empty() ? jira::search_def::standard.jql() : server.view().jql()) << "\n";
	OutputDebugString(utf::widen(o.str()).c_str()); o.str("");
	o << "Issues " << (dataset.startAt + 1)
		<< '-' << (dataset.startAt + dataset.data.size())
		<< " of " << dataset.total << ":\n";
	OutputDebugString(utf::widen(o.str()).c_str()); o.str("");

	{
		o << "\n";
		bool first = true;
		for (auto& col : dataset.schema.cols()) {
			if (first) first = false;
			else o << " | ";
			o << col->titleFull();
		}
		o << "\n-----------------------------------------------------------------------\n";
		OutputDebugString(utf::widen(o.str()).c_str()); o.str("");
	}

	for (auto&& row : dataset.data)
		OutputDebugString(utf::widen(row.text(" | ") + "\n").c_str());

	return 0;
}
<commit_msg>Dummy notification something is happening<commit_after>// TasksView.cpp : implementation of the CTasksView class
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"

#include "TasksView.h"
#include <net/utf8.hpp>
#include <algorithm>
#include <sstream>

class TaskViewModelListener : public CAppModelListener {
	HWND m_hWnd;
public:
	TaskViewModelListener(HWND hWnd) : m_hWnd(hWnd) {}

	void onListChanged(uint32_t addedOrRemoved) override
	{
		// traversing the borders of threads, if needed
		// also, the actual reaction to the vent will
		// not block the emit up there
		if (IsWindow(m_hWnd))
			PostMessage(m_hWnd, UM_LISTCHANGED, addedOrRemoved, 0);
	}
};

class ServerListener : public jira::server_listener {
	HWND m_hWnd;
	uint32_t m_sessionId;
public:
	ServerListener(HWND hWnd, uint32_t sessionId) : m_hWnd(hWnd), m_sessionId(sessionId) {}

	void onRefreshStarted() override
	{
		if (IsWindow(m_hWnd))
			PostMessage(m_hWnd, UM_REFRESHSTART, m_sessionId, 0);
	}

	void onRefreshFinished() override
	{
		if (IsWindow(m_hWnd))
			PostMessage(m_hWnd, UM_REFRESHSTOP, m_sessionId, 0);
	}
};

std::vector<CTasksView::ServerInfo>::iterator CTasksView::find(uint32_t sessionId)
{
	return std::find_if(std::begin(m_servers), std::end(m_servers), [sessionId](const ServerInfo& info) { return info.m_sessionId == sessionId; });
}

std::vector<CTasksView::ServerInfo>::iterator CTasksView::insert(std::vector<ServerInfo>::const_iterator it, const std::shared_ptr<jira::server>& server)
{
	// TODO: create UI element
	// TDOD: attach refresh listener to the server
	auto listener = std::make_shared<ServerListener>(m_hWnd, server->sessionId());
	return m_servers.emplace(it, server, listener);
}

std::vector<CTasksView::ServerInfo>::iterator CTasksView::erase(std::vector<ServerInfo>::const_iterator it)
{
	// TODO: destroy UI element
	// TDOD: detach refresh listener from the server
	return m_servers.erase(it);
}

BOOL CTasksView::PreTranslateMessage(MSG* pMsg)
{
	pMsg;
	return FALSE;
}

LRESULT CTasksView::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	m_listener = std::make_shared<TaskViewModelListener>(m_hWnd);
	m_model->registerListener(m_listener);
	return 0;
}

LRESULT CTasksView::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	m_model->unregisterListener(m_listener);
	return 0;
}

LRESULT CTasksView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	CPaintDC dc(m_hWnd);

	//TODO: Add your drawing code here

	return 0;
}

LRESULT CTasksView::OnListChanged(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	OutputDebugString(utf::widen(std::to_string((UINT_PTR) m_hWnd) + ": OnListChanged(" +std::to_string(wParam) + ")\n").c_str());

	// TODO: lock updates
	if (wParam) {
		// a server has been added or removed...
		auto it = find(wParam);
		if (it == m_servers.end()) { // it was added
			synchronize(*m_model, [&] {
				auto& servers = m_model->servers();
				// find the location of the ID; hint: it might be at the end
				auto rit = std::find_if(std::rbegin(servers), std::rend(servers), [&](const std::shared_ptr<jira::server>& server) { return server->sessionId() == wParam; });
				if (rit != std::rend(servers)) {
					auto it = std::begin(m_servers);

					// it += (rit.base() - servers.begin())
					 std::advance(it, std::distance(std::begin(servers), rit.base()));

					 insert(it, *rit);
				}
			});
		} else
			erase(it);
	} else {
		// no specific item has changed, go over entire model
		synchronize(*m_model, [&] {
			auto& servers = m_model->servers();

			auto it = std::begin(m_servers);
			auto end = std::end(m_servers);

			// for each ServerInfo: if not in model - remove
			while (it != end) {
				auto query = std::find_if(std::begin(servers), std::end(servers), [&](const std::shared_ptr<jira::server>& srv) { return srv->sessionId() == it->m_sessionId; });
				if (query == std::end(servers))
				{
					it = erase(it);
					end = std::end(m_servers);
				}
			}

			// for each server in model: if not in ServerInfos - add
			// side note: we have only items from the model, granted maybe not the ALL items
			// if we kept track of additions/deletions, they are in the same order as in the model
			// we just need to fill in the holes...

			it = std::begin(m_servers);
			end = std::end(m_servers);
			auto srv_it = std::begin(servers);
			auto srv_end = std::end(servers);

			for (; srv_it != srv_end; ++srv_it) {
				if (it != end && (*srv_it)->sessionId() == it->m_sessionId) {
					++it;
					continue;
				}

				it = insert(it, *srv_it); // fill in blanks...
				end = std::end(m_servers);
			}
		});
	}
	// TODO: unlock updates

	return 0;
}

LRESULT CTasksView::OnRefreshStart(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	OutputDebugString(utf::widen(std::to_string((UINT_PTR) m_hWnd) + ": OnRefreshStart(" + std::to_string(wParam) + ")\n").c_str());
	TCHAR szWindowName[260] = { 0 };
	::LoadString(ModuleHelper::GetResourceInstance(), IDR_MAINFRAME, szWindowName, sizeof(szWindowName) / sizeof(szWindowName[0]));

	GetParent().SetWindowText((std::wstring{szWindowName} + L" - Loading...").c_str());
	return 0;
}

LRESULT CTasksView::OnRefreshStop(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	OutputDebugString(utf::widen(std::to_string((UINT_PTR) m_hWnd) + ": OnRefreshStop(" + std::to_string(wParam) + ")\n").c_str());
	TCHAR szWindowName[260] = { 0 };
	::LoadString(ModuleHelper::GetResourceInstance(), IDR_MAINFRAME, szWindowName, sizeof(szWindowName) / sizeof(szWindowName[0]));

	GetParent().SetWindowText(szWindowName);

	auto it = find(wParam);
	if (it == m_servers.end())
		return 0;

	auto& server = *it->m_server;
	it->m_dataset = server.dataset();
	// TODO: update layout
	// TODO: redraw the report table

	auto& dataset = *it->m_dataset;
	std::ostringstream o;
	o << "-----------------------------------------------\n"
		<< "Answer from: " << server.login() << " @ " << server.displayName() << "\n"
		<< "Query: " << (server.view().jql().empty() ? jira::search_def::standard.jql() : server.view().jql()) << "\n";
	OutputDebugString(utf::widen(o.str()).c_str()); o.str("");
	o << "Issues " << (dataset.startAt + 1)
		<< '-' << (dataset.startAt + dataset.data.size())
		<< " of " << dataset.total << ":\n";
	OutputDebugString(utf::widen(o.str()).c_str()); o.str("");

	{
		o << "\n";
		bool first = true;
		for (auto& col : dataset.schema.cols()) {
			if (first) first = false;
			else o << " | ";
			o << col->titleFull();
		}
		o << "\n-----------------------------------------------------------------------\n";
		OutputDebugString(utf::widen(o.str()).c_str()); o.str("");
	}

	for (auto&& row : dataset.data)
		OutputDebugString(utf::widen(row.text(" | ") + "\n").c_str());

	return 0;
}
<|endoftext|>


<commit_before><commit_msg>fix compilation in studio_app.cpp<commit_after><|endoftext|>