<commit_before>#define BX_IN_CPU_METHOD 1
#include "bochs.h"
#include <assert.h>

bx_apic_c::bx_apic_c(void)
{
  static int apic_ids_used = 1;
  // default address for a local APIC, can be moved
  apic_base_msr = 0xfee00000;
  id = apic_ids_used++;
  err_status = 0;
}

bx_apic_c::~bx_apic_c(void)
{
  // nothing for now
}

  void
bx_apic_c::init()
{
}

Bit32u bx_apic_c::get_base (void)
{
  return apic_base_msr;
}

void bx_apic_c::set_base (Bit32u newbase)
{
  bx_printf ("relocate APIC to %8x\n", newbase);
  apic_base_msr = newbase;
}

void bx_apic_c::write_handler (Bit32u addr, Bit32u *data, unsigned len)
{
  assert (len == 4);
  bx_printf ("write %08x to APIC address %08x\n", *data, addr);
  //assert (!(addr & 0xf));
  switch (addr & 0xff0) {
  case 0x20: // local APIC id
    id = ((*data)>>24) & 0xf;
    break;
  case 0x30: // local APIC version
    bx_printf ("warning: write to read-only APIC register\n");
    break;
  case 0x80: // task priority
  case 0x90: // arbitration priority
  case 0xa0: // processor priority
  case 0xb0: // EOI
  case 0xd0: // logical destination
  case 0xe0: // destination format
  case 0xf0: // spurious interrupt vector
    break;
  case 0x280: // error status reg
    // Here's what the IA-devguide-3 says on p.7-45:
    // The ESR is a read/write register and is reset after being written to by
    // the processor. A write to the ESR must be done just prior to reading the
    // ESR to allow the register to be updated.
    // This doesn't seem clear.  If the write clears the register, then
    // wouldn't you always read zero?  Otherwise, what does the write do?
    // In my model, the write will do nothing.
    break;
  case 0x300: // interrupt command reg 0-31
    {
    icr_low = *data & ~(1<<12);  // force delivery status bit = 0 (idle)
    // and trigger an interrupt to be sent
    int dest_shorthand = (icr_low >> 18) & 3;
    char *dests[4] = {NULL, "self", "all including self", "all except self" };
    char buf[32];
    sprintf (buf, "APIC 0x%02x\n", icr_high >> 24);
    bx_printf ("APIC 0x%02x sending interrupt to destination %s",
       id,
       (dest_shorthand==0) ? buf : dests[dest_shorthand]);
    bx_printf ("low word of APIC 0x%02x ICR = 0x%04x\n", id, icr_low & 0xffff);
    }
    break;
  case 0x310: // interrupt command reg 31-63
    icr_high = *data & 0xff000000;
    break;
  case 0x320: // LVT Timer Reg
  case 0x330: // LVT Thermal Monitor
  case 0x340: // LVT Performance Counter
  case 0x350: // LVT LINT0 Reg
  case 0x360: // LVT Lint1 Reg
  case 0x370: // LVT Error Reg
  case 0x380: // initial count for timer
  case 0x390: // current count for timer
  case 0x3e0: // timer divide configuration
  default:
    bx_printf ("APIC register %08x not implemented\n", addr);
  }
}

void bx_apic_c::read_handler (Bit32u addr, Bit32u *data, unsigned len)
{
  assert (len == 4);
  *data = 0;  // default value for unimplemented registers
  switch (addr & 0xff0) {
  case 0x20: // local APIC id
    *data = (id) << 24;
    break;
  case 0x30: // local APIC version
    *data = 0x00170011;
    break;
  case 0x80: // task priority
  case 0x90: // arbitration priority
  case 0xa0: // processor priority
  case 0xb0: // EOI
  case 0xd0: // logical destination
  case 0xe0: // destination format
  case 0xf0: // spurious interrupt vector
    break;
  case 0x280: // error status reg
    *data = err_status;
    break;
  case 0x300: // interrupt command reg 0-31
    *data = icr_low;
    break;
  case 0x310: // interrupt command reg 31-63
    *data = icr_high;
    break;
  case 0x320: // LVT Timer Reg
  case 0x330: // LVT Thermal Monitor
  case 0x340: // LVT Performance Counter
  case 0x350: // LVT LINT0 Reg
  case 0x360: // LVT Lint1 Reg
  case 0x370: // LVT Error Reg
  case 0x380: // initial count for timer
  case 0x390: // current count for timer
  case 0x3e0: // timer divide configuration
  default:
    bx_printf ("APIC register %08x not implemented\n", addr);
  }
  bx_printf ("read from APIC address %08x = %08x\n", addr, *data);
}
<commit_msg>- added apic_index, a table of BX_CPU_C pointers, indexed by APIC ID<commit_after>#define BX_IN_CPU_METHOD 1
#include "bochs.h"
#include <assert.h>

BX_CPU_C *apic_index[APIC_MAX_ID];

bx_apic_c::bx_apic_c(BX_CPU_C *mycpu)
{
  id = APIC_UNKNOWN_ID;
  cpu = mycpu;
  // default address for a local APIC, can be moved
  apic_base_msr = 0xfee00000;
  err_status = 0;
}

bx_apic_c::~bx_apic_c(void)
{
  // nothing for now
}

Bit32u bx_apic_c::get_base (void)
{
  return apic_base_msr;
}

void bx_apic_c::set_id (Bit8u newid) {
  // update apic_index
  if (id != APIC_UNKNOWN_ID) {
    bx_assert (id < APIC_MAX_ID);
    if (apic_index[id] != cpu)
      bx_panic ("inconsistent APIC id table");
    apic_index[id] = NULL;
  }
  id = newid;
  if (apic_index[id] != NULL)
    bx_panic ("duplicate APIC id assigned");
  apic_index[id] = cpu;
  sprintf (cpu->name, "CPU apicid=%02x", (Bit32u)id);
}

void bx_apic_c::set_base (Bit32u newbase)
{
  bx_printf ("relocate APIC to %8x\n", newbase);
  apic_base_msr = newbase;
}

void bx_apic_c::write_handler (Bit32u addr, Bit32u *data, unsigned len)
{
  assert (len == 4);
  bx_printf ("write %08x to APIC address %08x\n", *data, addr);
  //assert (!(addr & 0xf));
  switch (addr & 0xff0) {
  case 0x20: // local APIC id
    id = ((*data)>>24) & 0xf;
    break;
  case 0x30: // local APIC version
    bx_printf ("warning: write to read-only APIC register\n");
    break;
  case 0x80: // task priority
  case 0x90: // arbitration priority
  case 0xa0: // processor priority
  case 0xb0: // EOI
  case 0xd0: // logical destination
  case 0xe0: // destination format
  case 0xf0: // spurious interrupt vector
    break;
  case 0x280: // error status reg
    // Here's what the IA-devguide-3 says on p.7-45:
    // The ESR is a read/write register and is reset after being written to by
    // the processor. A write to the ESR must be done just prior to reading the
    // ESR to allow the register to be updated.
    // This doesn't seem clear.  If the write clears the register, then
    // wouldn't you always read zero?  Otherwise, what does the write do?
    // In my model, the write will do nothing.
    break;
  case 0x300: // interrupt command reg 0-31
    {
    icr_low = *data & ~(1<<12);  // force delivery status bit = 0 (idle)
    // and trigger an interrupt to be sent
    int dest_shorthand = (icr_low >> 18) & 3;
    char *dests[4] = {NULL, "self", "all including self", "all except self" };
    char buf[32];
    sprintf (buf, "APIC 0x%02x\n", icr_high >> 24);
    bx_printf ("APIC 0x%02x sending interrupt to destination %s",
       id,
       (dest_shorthand==0) ? buf : dests[dest_shorthand]);
    bx_printf ("low word of APIC 0x%02x ICR = 0x%04x\n", id, icr_low & 0xffff);
    }
    break;
  case 0x310: // interrupt command reg 31-63
    icr_high = *data & 0xff000000;
    break;
  case 0x320: // LVT Timer Reg
  case 0x330: // LVT Thermal Monitor
  case 0x340: // LVT Performance Counter
  case 0x350: // LVT LINT0 Reg
  case 0x360: // LVT Lint1 Reg
  case 0x370: // LVT Error Reg
  case 0x380: // initial count for timer
  case 0x390: // current count for timer
  case 0x3e0: // timer divide configuration
  default:
    bx_printf ("APIC register %08x not implemented\n", addr);
  }
}

void bx_apic_c::read_handler (Bit32u addr, Bit32u *data, unsigned len)
{
  assert (len == 4);
  *data = 0;  // default value for unimplemented registers
  switch (addr & 0xff0) {
  case 0x20: // local APIC id
    *data = (id) << 24;
    break;
  case 0x30: // local APIC version
    *data = 0x00170011;
    break;
  case 0x80: // task priority
  case 0x90: // arbitration priority
  case 0xa0: // processor priority
  case 0xb0: // EOI
  case 0xd0: // logical destination
  case 0xe0: // destination format
  case 0xf0: // spurious interrupt vector
    break;
  case 0x280: // error status reg
    *data = err_status;
    break;
  case 0x300: // interrupt command reg 0-31
    *data = icr_low;
    break;
  case 0x310: // interrupt command reg 31-63
    *data = icr_high;
    break;
  case 0x320: // LVT Timer Reg
  case 0x330: // LVT Thermal Monitor
  case 0x340: // LVT Performance Counter
  case 0x350: // LVT LINT0 Reg
  case 0x360: // LVT Lint1 Reg
  case 0x370: // LVT Error Reg
  case 0x380: // initial count for timer
  case 0x390: // current count for timer
  case 0x3e0: // timer divide configuration
  default:
    bx_printf ("APIC register %08x not implemented\n", addr);
  }
  bx_printf ("read from APIC address %08x = %08x\n", addr, *data);
}

BX_CPU_C
bx_apic_c::*get_cpu (Bit8u id)
{
  bx_assert (id >= 0 && id < APIC_MAX_ID);
}
<|endoftext|>


<commit_before>#include "GameManager.hpp"
#include "GameSlave.hpp"

#include <random>
#include <iostream>
#include <time.h>
#ifndef DONTUSEMPI
#include <mpi.h>
#endif

// yep... it's a global variable.  But it makes sense here.
std::default_random_engine rng;

int main(int argc, char** argv)
{
    //Get Inputs
    std::string outputFileString = "output.txt";
    int timesToRepeatEachGame = 3;
    int numberOfPlayers = 2;
    if (argc >= 2)
        outputFileString = std::string(argv[1]);
    if (argc >= 3)
        timesToRepeatEachGame = atoi(argv[2]);
    if (argc >= 4)
        numberOfPlayers = atoi(argv[3]);

    std::cout << "**********************************" << std::endl;
    std::cout << "Configurations" << std::endl;
    std::cout << "OutputFile: " << outputFileString << std::endl;
    std::cout << "TimesToRepeatEachGame: " << timesToRepeatEachGame << std::endl;
    std::cout << "NumberOfPlayers: " << numberOfPlayers << std::endl;
    std::cout << "**********************************" << std::endl;

    //set up MPI , and then init the randomizer
    int myMpiRank, totalProcCount;
#ifndef DONTUSEMPI
    MPI_Init(NULL, NULL);
    MPI_Comm_rank(MPI_COMM_WORLD, &myMpiRank);
    MPI_Comm_size(MPI_COMM_WORLD, &totalProcCount);
#else
    myMpiRank = 0,
            totalProcCount = 1;
#endif
    srand((unsigned int) time(NULL) + 10 * myMpiRank); //We must seed the random number generator.  This one is only used for initializing; rng is used more

    //Spawn the appropriate object
    if (myMpiRank == 0)
    {
        std::cout << "Starting Master: " << myMpiRank << std::endl;

        //prepare tasks to run
        std::vector<StrategyEnum::StrategyEnum> strategies;
        strategies.push_back(StrategyEnum::HumanControlledStrategy);
        ////strategies.push_back(StrategyEnum::BadStrategy1);
        ////strategies.push_back(StrategyEnum::ObtainSmallestContinentsFirstStrategy);

        std::cout << "Strategies being used: ";
        for (StrategyEnum::StrategyEnum e : strategies)
        {
            std::cout << e << " ";
        }
        std::cout << std::endl;

        std::vector<MapEnum::MapEnum> maps;
        ////maps.push_back(MapEnum::ThreeContinent);
        ////maps.push_back(MapEnum::Earth);
        ////maps.push_back(MapEnum::Island);
        maps.push_back(MapEnum::ThreeContinent);

        std::cout << "Maps being used: ";
        for (MapEnum::MapEnum e : maps)
        {
            std::cout << e << " ";
        }
        std::cout << std::endl;

        std::vector<GameTask> tasksToRun = GameManager::getRunsFor(strategies, maps, numberOfPlayers, timesToRepeatEachGame);
        //start the manager
        GameManager manager(totalProcCount - 1);
        manager.setGamesToRun(tasksToRun);
        ////manager.readInExistingReport("reportLocation");
        manager.runIt(outputFileString);
    }
    else
    {
        std::cout << "Starting Slave: " << myMpiRank << std::endl;

        GameSlave slave;
        slave.runIt();
    }

    //clean up MPI stuff
#ifndef DONTUSEMPI
    MPI_Finalize();
#endif
}
<commit_msg>Merging...<commit_after>#include "GameManager.hpp"
#include "GameSlave.hpp"

#include <random>
#include <iostream>
#include <time.h>
#ifndef DONTUSEMPI
#include <mpi.h>
#endif

// yep... it's a global variable.  But it makes sense here.
std::default_random_engine rng;

int main(int argc, char** argv)
{
    //Get Inputs
    std::string outputFileString = "output.txt";
    int timesToRepeatEachGame = 3;
    int numberOfPlayers = 2;
    if (argc >= 2)
        outputFileString = std::string(argv[1]);
    if (argc >= 3)
        timesToRepeatEachGame = atoi(argv[2]);
    if (argc >= 4)
        numberOfPlayers = atoi(argv[3]);

    std::cout << "**********************************" << std::endl;
    std::cout << "Configurations" << std::endl;
    std::cout << "OutputFile: " << outputFileString << std::endl;
    std::cout << "TimesToRepeatEachGame: " << timesToRepeatEachGame << std::endl;
    std::cout << "NumberOfPlayers: " << numberOfPlayers << std::endl;
    std::cout << "**********************************" << std::endl;

    //set up MPI , and then init the randomizer
    int myMpiRank, totalProcCount;
#ifndef DONTUSEMPI
    MPI_Init(NULL, NULL);
    MPI_Comm_rank(MPI_COMM_WORLD, &myMpiRank);
    MPI_Comm_size(MPI_COMM_WORLD, &totalProcCount);
#else
    myMpiRank = 0,
            totalProcCount = 1;
#endif
    srand((unsigned int) time(NULL) + 10 * myMpiRank); //We must seed the random number generator.  This one is only used for initializing; rng is used more

    //Spawn the appropriate object
    if (myMpiRank == 0)
    {
        std::cout << "Starting Master: " << myMpiRank << std::endl;

        //prepare tasks to run
        std::vector<StrategyEnum::StrategyEnum> strategies;
        ////strategies.push_back(StrategyEnum::HumanControlledStrategy);
        ////strategies.push_back(StrategyEnum::BadStrategy1);
        strategies.push_back(StrategyEnum::ObtainSmallestContinentsFirstStrategy);
        strategies.push_back(StrategyEnum::ObtainSmallestContinentsFirstStrategy);

        std::cout << "Strategies being used: ";
        for (StrategyEnum::StrategyEnum e : strategies)
        {
            std::cout << e << " ";
        }
        std::cout << std::endl;

        std::vector<MapEnum::MapEnum> maps;
        ////maps.push_back(MapEnum::ThreeContinent);
        ////maps.push_back(MapEnum::Earth);
        ////maps.push_back(MapEnum::Island);
        maps.push_back(MapEnum::ThreeContinent);

        std::cout << "Maps being used: ";
        for (MapEnum::MapEnum e : maps)
        {
            std::cout << e << " ";
        }
        std::cout << std::endl;

        std::vector<GameTask> tasksToRun = GameManager::getRunsFor(strategies, maps, numberOfPlayers, timesToRepeatEachGame);
        //start the manager
        GameManager manager(totalProcCount - 1);
        manager.setGamesToRun(tasksToRun);
        ////manager.readInExistingReport("reportLocation");
        manager.runIt(outputFileString);
    }
    else
    {
        std::cout << "Starting Slave: " << myMpiRank << std::endl;

        GameSlave slave;
        slave.runIt();
    }

    //clean up MPI stuff
#ifndef DONTUSEMPI
    MPI_Finalize();
#endif
}
<|endoftext|>


<commit_before>#include "ModularSynth.h"
#include "ModuleFactory.h"
#include "Sample.h"
#include "FileSection.h"
#include "ModuleFactory.h"
#include "TrackState.h"
#include "SDL.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

#ifndef TUNING
#define TUNING 440.0
#endif

ModularSynth::ModularSynth()
	:mNumConnections(0), mFrequency(0), mVolume(0), mNoteTrigger(false)
{
	for (int i = 0 ; i < maxModules ; ++i)
		mModules[i] = NULL;
}

ModularSynth::~ModularSynth()
{
	clear();
}

bool ModularSynth::addModule(int index, int moduleId)
{
	ModuleFactory moduleFactory;

	if (mModules[index] != NULL)
		return false;

	mModules[index] = moduleFactory.createModule(moduleId, *this);
	mModules[index]->setSampleRate(mSampleRate);
	mModules[index]->onLoaded();

	return true;
}

bool ModularSynth::connectModules(int fromModule, int toModule, int fromOutput, int toInput)
{
	if (mNumConnections >= maxConnections)
		return false;

	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];

		if (connection.toModule == toModule && connection.toInput == toInput)
			return false;

		if (connection.fromModule == fromModule && connection.fromOutput == fromOutput)
			return false;
	}

	SynthConnection& connection = mConnections[mNumConnections];
	connection.fromModule = fromModule;
	connection.toModule = toModule;
	connection.fromOutput = fromOutput;
	connection.toInput = toInput;

	mNumConnections++;

	return true;
}

void ModularSynth::detachConnection(int moduleIndex, int type, int connectionIndex)
{
	int i;

	for (i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];
		if (type == 1)
		{
			if (connection.fromModule == moduleIndex && connection.fromOutput == connectionIndex)
				break;
		}
		else
		{
			if (connection.toModule == moduleIndex && connection.toInput == connectionIndex)
				break;
		}
	}

	if (i < mNumConnections)
	{
		removeConnection(i);
	}
}

void ModularSynth::removeConnection(int index)
{
	if (index < mNumConnections)
	{
		SynthConnection& connection = mConnections[index];
		if (mModules[connection.toModule] != NULL)
			mModules[connection.toModule]->setInput(connection.toInput, 0.0f);

		mNumConnections--;
		memmove(&mConnections[index], &mConnections[index + 1], sizeof(mConnections[index]) * (mNumConnections - index));
	}
}

void ModularSynth::cycle()
{
	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];
		mModules[connection.toModule]->setInput(connection.toInput, mModules[connection.fromModule]->getOutput(connection.fromOutput));
	}

	for (int i = 0 ; i < maxModules ; ++i)
		if (mModules[i] != NULL)
			mModules[i]->cycle();

	// After all modules have had their change to see if note was triggered,
	// reset the status
	mNoteTrigger = false;
}

void ModularSynth::triggerNote()
{
	mNoteTrigger = true;
}

void ModularSynth::setFrequency(float frequency)
{
	mFrequency = frequency * mSampleRate / static_cast<float>(TUNING);
}

void ModularSynth::setVolume(int volume)
{
	mVolume = static_cast<float>(volume) / ITrackState::maxVolume;
}

void ModularSynth::update(int numSamples)
{
}

void ModularSynth::render(Sample16 *buffer, int numSamples, int offset)
{
	// No update or output if volume is zero, meaning the channel is muted
	if (mVolume > 0.0f)
	{
		for (int i = offset ; i < numSamples ; ++i)
		{
			cycle();

			// Only mono output for now
			buffer[i].left += mOutput[0] * outputResolution;
			buffer[i].right += mOutput[0] * outputResolution;
		}
	}
}

const SynthModule* ModularSynth::getModule(int index) const
{
	return mModules[index];
}

SynthModule* ModularSynth::getModule(int index)
{
	return mModules[index];
}

const SynthConnection& ModularSynth::getConnection(int index) const
{
	return mConnections[index];
}

int ModularSynth::getNumConnections() const
{
	return mNumConnections;
}

void ModularSynth::swapModules(int fromModule, int toModule)
{
	SynthModule* temp = mModules[fromModule];
	mModules[fromModule] = mModules[toModule];
	mModules[toModule] = temp;

	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];

		if (connection.fromModule == toModule)
			connection.fromModule = fromModule;
		else if (connection.fromModule == fromModule)
			connection.fromModule = toModule;

		if (connection.toModule == toModule)
			connection.toModule = fromModule;
		else if (connection.toModule == fromModule)
			connection.toModule = toModule;
	}
}

void ModularSynth::removeModule(int index)
{
	if (mModules[index] != NULL)
	{
		delete mModules[index];
		mModules[index] = NULL;

		// Remove any connections from/to this module

		for (int i = 0 ; i < mNumConnections ; )
		{
			SynthConnection& connection = mConnections[i];

			if (connection.fromModule == index || connection.toModule == index)
				removeConnection(i);
			else
				++i;
		}
	}
}

/* SynthModule parameters are scaled so that -1.0 .. 1.0 equals 0x3fff000 0x4001000
 * which should be accurate and deep enough for any normal purposes (values mostly between
 * 0-255).
 */

static const int paramScale =  0x0001000;
static const int paramCenter = 0x4000000;

bool ModularSynth::readSynth(const FileSection& section, int& offset)
{
	int countModules = section.readByte(offset);

	if (countModules == FileSection::invalidRead || countModules > maxModules)
		return false;

	ModuleFactory moduleFactory;

	clear();

	for (int i = 0 ; i < countModules ; ++i)
	{
		int synthId = section.readByte(offset);

		if (synthId != 0)
		{
			SynthModule *module = moduleFactory.createModule(synthId, *this);

			if (!module)
				return false;

			for (int p = 0 ; p < module->getNumParams() ; ++p)
			{
				int param = section.readDword(offset);
				module->setParam(p, static_cast<float>(param - paramCenter) / paramScale);
			}

			mModules[i] = module;
			module->onLoaded();
			module->setSampleRate(mSampleRate);
		}
	}

	int countConnections = section.readByte(offset);

	if (countConnections == FileSection::invalidRead || countConnections > maxConnections)
		return false;

	mNumConnections = countConnections;

	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];

		int temp = section.readByte(offset);

		if (temp == FileSection::invalidRead || temp > maxModules)
			return false;

		connection.fromModule = temp;

		temp = section.readByte(offset);

		if (temp == FileSection::invalidRead || temp > maxModules)
			return false;
		connection.toModule = temp;

		temp = section.readByte(offset);

		if (temp == FileSection::invalidRead || temp > maxModules)
			return false;

		connection.fromOutput = temp;

		temp = section.readByte(offset);

		if (temp == FileSection::invalidRead || temp > maxModules)
			return false;

		connection.toInput = temp;
	}

	return true;
}

void ModularSynth::writeSynth(FileSection& section)
{
	// Write modules

	section.writeByte(maxModules);

	for (int i = 0 ; i < maxModules ; ++i)
	{
		if (mModules[i] != NULL)
		{
			section.writeByte(mModules[i]->getSynthId());

			for (int p = 0 ; p < mModules[i]->getNumParams() ; ++p)
			{
				section.writeDword(mModules[i]->getParam(p) * paramScale + paramCenter);
			}
		}
		else
		{
			section.writeByte(0);
		}
	}

	// Write connections

	section.writeByte(mNumConnections);

	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];
		section.writeByte(connection.fromModule);
		section.writeByte(connection.toModule);
		section.writeByte(connection.fromOutput);
		section.writeByte(connection.toInput);
	}
}

void ModularSynth::clear()
{
	for (int i = 0 ; i < maxModules ; ++i)
	{
		if (mModules[i] != NULL)
		{
			delete mModules[i];
			mModules[i] = NULL;
		}
	}

	mNumConnections = 0;
}

float ModularSynth::getFrequency() const
{
	return mFrequency;
}

void ModularSynth::setMasterOutput(int channel, float output)
{
	mOutput[channel] = output;
}

bool ModularSynth::getNoteTrigger() const
{
	if (mNoteTrigger)
		return 1.0f;
	else
		return 0.0f;
}

void ModularSynth::setSampleRate(int rate)
{
	mSampleRate = rate;
	for (int index = 0 ; index < maxModules ; ++index)
	{
		if (mModules[index] != NULL)
			mModules[index]->setSampleRate(mSampleRate);
	}
}

void ModularSynth::copy(const ModularSynth& source)
{
	for (int i = 0 ; i < maxModules ; ++i)
	{
		if (source.getModule(i) != NULL)
		{
			addModule(i, source.getModule(i)->getSynthId());
			SynthModule *newModule = getModule(i);

			for (int p = 0 ; mModules[i]->getNumParams() ; ++p)
			{
				newModule->setParam(p, source.getModule(i)->getParam(p));
			}
		}
		else
		{
			if (getModule(i) != NULL)
				removeModule(i);
		}
	}

	mNumConnections = 0;

	for (int i = 0 ; i < source.getNumConnections() ; ++i)
	{
		const SynthConnection& connection = source.getConnection(i);
		connectModules(connection.fromModule, connection.toModule, connection.fromOutput, connection.toInput);
	}
}

ModularSynth* ModularSynth::clone() const
{
	ModularSynth *newSynth = new ModularSynth();

	newSynth->copy(*this);

	return newSynth;
}

void ModularSynth::handleTrackState(ITrackState& _trackState)
{
	TrackState& trackState = static_cast<TrackState&>(_trackState);
	SDL_memcpy(mEffectValues, trackState.effectValues, sizeof(mEffectValues));
}

int ModularSynth::getEffectValue(int effect) const
{
	return mEffectValues[effect];
}
<commit_msg>Fixed ModularSynth::clone()<commit_after>#include "ModularSynth.h"
#include "ModuleFactory.h"
#include "Sample.h"
#include "FileSection.h"
#include "ModuleFactory.h"
#include "TrackState.h"
#include "SDL.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

#ifndef TUNING
#define TUNING 440.0
#endif

ModularSynth::ModularSynth()
	:mNumConnections(0), mFrequency(0), mVolume(0), mNoteTrigger(false)
{
	for (int i = 0 ; i < maxModules ; ++i)
		mModules[i] = NULL;
}

ModularSynth::~ModularSynth()
{
	clear();
}

bool ModularSynth::addModule(int index, int moduleId)
{
	ModuleFactory moduleFactory;

	if (mModules[index] != NULL)
		return false;

	mModules[index] = moduleFactory.createModule(moduleId, *this);
	mModules[index]->setSampleRate(mSampleRate);
	mModules[index]->onLoaded();

	return true;
}

bool ModularSynth::connectModules(int fromModule, int toModule, int fromOutput, int toInput)
{
	if (mNumConnections >= maxConnections)
		return false;

	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];

		if (connection.toModule == toModule && connection.toInput == toInput)
			return false;

		if (connection.fromModule == fromModule && connection.fromOutput == fromOutput)
			return false;
	}

	SynthConnection& connection = mConnections[mNumConnections];
	connection.fromModule = fromModule;
	connection.toModule = toModule;
	connection.fromOutput = fromOutput;
	connection.toInput = toInput;

	mNumConnections++;

	return true;
}

void ModularSynth::detachConnection(int moduleIndex, int type, int connectionIndex)
{
	int i;

	for (i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];
		if (type == 1)
		{
			if (connection.fromModule == moduleIndex && connection.fromOutput == connectionIndex)
				break;
		}
		else
		{
			if (connection.toModule == moduleIndex && connection.toInput == connectionIndex)
				break;
		}
	}

	if (i < mNumConnections)
	{
		removeConnection(i);
	}
}

void ModularSynth::removeConnection(int index)
{
	if (index < mNumConnections)
	{
		SynthConnection& connection = mConnections[index];
		if (mModules[connection.toModule] != NULL)
			mModules[connection.toModule]->setInput(connection.toInput, 0.0f);

		mNumConnections--;
		memmove(&mConnections[index], &mConnections[index + 1], sizeof(mConnections[index]) * (mNumConnections - index));
	}
}

void ModularSynth::cycle()
{
	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];
		mModules[connection.toModule]->setInput(connection.toInput, mModules[connection.fromModule]->getOutput(connection.fromOutput));
	}

	for (int i = 0 ; i < maxModules ; ++i)
		if (mModules[i] != NULL)
			mModules[i]->cycle();

	// After all modules have had their change to see if note was triggered,
	// reset the status
	mNoteTrigger = false;
}

void ModularSynth::triggerNote()
{
	mNoteTrigger = true;
}

void ModularSynth::setFrequency(float frequency)
{
	mFrequency = frequency * mSampleRate / static_cast<float>(TUNING);
}

void ModularSynth::setVolume(int volume)
{
	mVolume = static_cast<float>(volume) / ITrackState::maxVolume;
}

void ModularSynth::update(int numSamples)
{
}

void ModularSynth::render(Sample16 *buffer, int numSamples, int offset)
{
	// No update or output if volume is zero, meaning the channel is muted
	if (mVolume > 0.0f)
	{
		for (int i = offset ; i < numSamples ; ++i)
		{
			cycle();

			// Only mono output for now
			buffer[i].left += mOutput[0] * outputResolution;
			buffer[i].right += mOutput[0] * outputResolution;
		}
	}
}

const SynthModule* ModularSynth::getModule(int index) const
{
	return mModules[index];
}

SynthModule* ModularSynth::getModule(int index)
{
	return mModules[index];
}

const SynthConnection& ModularSynth::getConnection(int index) const
{
	return mConnections[index];
}

int ModularSynth::getNumConnections() const
{
	return mNumConnections;
}

void ModularSynth::swapModules(int fromModule, int toModule)
{
	SynthModule* temp = mModules[fromModule];
	mModules[fromModule] = mModules[toModule];
	mModules[toModule] = temp;

	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];

		if (connection.fromModule == toModule)
			connection.fromModule = fromModule;
		else if (connection.fromModule == fromModule)
			connection.fromModule = toModule;

		if (connection.toModule == toModule)
			connection.toModule = fromModule;
		else if (connection.toModule == fromModule)
			connection.toModule = toModule;
	}
}

void ModularSynth::removeModule(int index)
{
	if (mModules[index] != NULL)
	{
		delete mModules[index];
		mModules[index] = NULL;

		// Remove any connections from/to this module

		for (int i = 0 ; i < mNumConnections ; )
		{
			SynthConnection& connection = mConnections[i];

			if (connection.fromModule == index || connection.toModule == index)
				removeConnection(i);
			else
				++i;
		}
	}
}

/* SynthModule parameters are scaled so that -1.0 .. 1.0 equals 0x3fff000 0x4001000
 * which should be accurate and deep enough for any normal purposes (values mostly between
 * 0-255).
 */

static const int paramScale =  0x0001000;
static const int paramCenter = 0x4000000;

bool ModularSynth::readSynth(const FileSection& section, int& offset)
{
	int countModules = section.readByte(offset);

	if (countModules == FileSection::invalidRead || countModules > maxModules)
		return false;

	ModuleFactory moduleFactory;

	clear();

	for (int i = 0 ; i < countModules ; ++i)
	{
		int synthId = section.readByte(offset);

		if (synthId != 0)
		{
			SynthModule *module = moduleFactory.createModule(synthId, *this);

			if (!module)
				return false;

			for (int p = 0 ; p < module->getNumParams() ; ++p)
			{
				int param = section.readDword(offset);
				module->setParam(p, static_cast<float>(param - paramCenter) / paramScale);
			}

			mModules[i] = module;
			module->onLoaded();
			module->setSampleRate(mSampleRate);
		}
	}

	int countConnections = section.readByte(offset);

	if (countConnections == FileSection::invalidRead || countConnections > maxConnections)
		return false;

	mNumConnections = countConnections;

	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];

		int temp = section.readByte(offset);

		if (temp == FileSection::invalidRead || temp > maxModules)
			return false;

		connection.fromModule = temp;

		temp = section.readByte(offset);

		if (temp == FileSection::invalidRead || temp > maxModules)
			return false;
		connection.toModule = temp;

		temp = section.readByte(offset);

		if (temp == FileSection::invalidRead || temp > maxModules)
			return false;

		connection.fromOutput = temp;

		temp = section.readByte(offset);

		if (temp == FileSection::invalidRead || temp > maxModules)
			return false;

		connection.toInput = temp;
	}

	return true;
}

void ModularSynth::writeSynth(FileSection& section)
{
	// Write modules

	section.writeByte(maxModules);

	for (int i = 0 ; i < maxModules ; ++i)
	{
		if (mModules[i] != NULL)
		{
			section.writeByte(mModules[i]->getSynthId());

			for (int p = 0 ; p < mModules[i]->getNumParams() ; ++p)
			{
				section.writeDword(mModules[i]->getParam(p) * paramScale + paramCenter);
			}
		}
		else
		{
			section.writeByte(0);
		}
	}

	// Write connections

	section.writeByte(mNumConnections);

	for (int i = 0 ; i < mNumConnections ; ++i)
	{
		SynthConnection& connection = mConnections[i];
		section.writeByte(connection.fromModule);
		section.writeByte(connection.toModule);
		section.writeByte(connection.fromOutput);
		section.writeByte(connection.toInput);
	}
}

void ModularSynth::clear()
{
	for (int i = 0 ; i < maxModules ; ++i)
	{
		if (mModules[i] != NULL)
		{
			delete mModules[i];
			mModules[i] = NULL;
		}
	}

	mNumConnections = 0;
}

float ModularSynth::getFrequency() const
{
	return mFrequency;
}

void ModularSynth::setMasterOutput(int channel, float output)
{
	mOutput[channel] = output;
}

bool ModularSynth::getNoteTrigger() const
{
	if (mNoteTrigger)
		return 1.0f;
	else
		return 0.0f;
}

void ModularSynth::setSampleRate(int rate)
{
	mSampleRate = rate;
	for (int index = 0 ; index < maxModules ; ++index)
	{
		if (mModules[index] != NULL)
			mModules[index]->setSampleRate(mSampleRate);
	}
}

void ModularSynth::copy(const ModularSynth& source)
{
	for (int i = 0 ; i < maxModules ; ++i)
	{
		if (source.getModule(i) != NULL)
		{
			addModule(i, source.getModule(i)->getSynthId());
			SynthModule *newModule = getModule(i);

			for (int p = 0 ; p < newModule->getNumParams() ; ++p)
			{
				newModule->setParam(p, source.getModule(i)->getParam(p));
			}
		}
		else
		{
			if (getModule(i) != NULL)
				removeModule(i);
		}
	}

	mNumConnections = 0;

	for (int i = 0 ; i < source.getNumConnections() ; ++i)
	{
		const SynthConnection& connection = source.getConnection(i);
		connectModules(connection.fromModule, connection.toModule, connection.fromOutput, connection.toInput);
	}
}

ModularSynth* ModularSynth::clone() const
{
	ModularSynth *newSynth = new ModularSynth();

	newSynth->copy(*this);

	return newSynth;
}

void ModularSynth::handleTrackState(ITrackState& _trackState)
{
	TrackState& trackState = static_cast<TrackState&>(_trackState);
	SDL_memcpy(mEffectValues, trackState.effectValues, sizeof(mEffectValues));
}

int ModularSynth::getEffectValue(int effect) const
{
	return mEffectValues[effect];
}
<|endoftext|>


<commit_before>/*******************************************************************************
GPU OPTIMIZED MONTE CARLO (GOMC) 2.70
Copyright (C) 2018  GOMC Group
A copy of the GNU General Public License can be found in the COPYRIGHT.txt
along with this program, also can be found at <http://www.gnu.org/licenses/>.
********************************************************************************/
#include "MoveSettings.h"    //header spec
#include "BoxDimensions.h"   //For axis sizes
#include "BoxDimensionsNonOrth.h"
#include "StaticVals.h"      //For init info
#include <cmath>
#include "NumLib.h"          //For bounding functions
#include "GeomLib.h"         //For M_PI

const double MoveSettings::TARGET_ACCEPT_FRACT = 0.5;
const double MoveSettings::TINY_AMOUNT = 1.0e-7;
const double MoveSettings::r_alpha = 0.2;
const double MoveSettings::t_alpha = 0.2;
const double MoveSettings::mp_accept_tol = 0.1;

void MoveSettings::Init(StaticVals const& statV,
                        pdb_setup::Remarks const& remarks,
                        const uint tkind,
                        bool restartFromCheckpoint)
{
  //Set to true so that we calculate the forces for the current system, even if
  //a MultiParticle move is called before any other moves are accepted.

  totKind = tkind;
  perAdjust = statV.simEventFreq.perAdjust;
  if (!restartFromCheckpoint){
    for (uint b; b < BOXES_WITH_U_NB; b++) {
      SetSingleMoveAccepted(b);
    }

    for(uint b = 0; b < BOX_TOTAL; b++) {
      for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; m++) {
        acceptPercent[b][m].resize(totKind, 0);
        scale[b][m].resize(totKind, 0);
        accepted[b][m].resize(totKind, 0);
        tries[b][m].resize(totKind, 0);
        tempAccepted[b][m].resize(totKind, 0);
        tempTries[b][m].resize(totKind, 0);
      }
    }

    for(uint b = 0; b < BOX_TOTAL; b++) {
      for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; m++) {
        for(uint k = 0; k < totKind; k++) {
          if(m == mv::DISPLACE) {
            if(remarks.restart && remarks.disp[b] > 0.0) {
              scale[b][m][k] = remarks.disp[b];
            } else {
              scale[b][m][k] = boxDimRef.axis.Min(b) * 0.25;
            }
          } else if (m == mv::ROTATE) {
            if(remarks.restart && remarks.rotate[b] > 0.0) {
              scale[b][m][k] = remarks.rotate[b];
            } else {
              scale[b][m][k] = M_PI_4;
            }
          }
  #if ENSEMBLE == NPT || ENSEMBLE == GEMC
          else if (m == mv::VOL_TRANSFER) {
            if(remarks.restart && remarks.vol[b] > 0.0) {
              scale[b][m][k] = remarks.vol[b];
            } else {
              scale[b][m][k] = 500;
            }
          }
  #endif
        }
      }
    }

    // Initialize MultiParticle settings
    for(int b = 0; b < BOX_TOTAL; b++) {
      mp_r_max[b] = 0.01 * M_PI;
      mp_t_max[b] = 0.02;
      for(int m = 0; m < mp::MPTOTALTYPES; m++) {
        mp_tries[b][m] = 0;
        mp_accepted[b][m] = 0;
        mp_interval_tries[b][m] = 0;
        mp_interval_accepted[b][m] = 0;
      }
    }
  }
}

//Process results of move we just did in terms of acceptance counters
void MoveSettings::Update(const uint move, const bool isAccepted,
                          const uint box, const uint kind)
{
  tries[box][move][kind]++;
  tempTries[box][move][kind]++;
  if(isAccepted) {
    tempAccepted[box][move][kind]++;
    accepted[box][move][kind]++;

    if(move != mv::MULTIPARTICLE || move != mv::MULTIPARTICLE_BM) {
      SetSingleMoveAccepted(box);
#if ENSEMBLE == GEMC
      //GEMC has multiple boxes and this move changed both boxes, so we
      //need to also mark the other box as having a move accepted.
      if(move == mv::MEMC || move == mv::MOL_TRANSFER || move == mv::NE_MTMC ||
         move == mv::VOL_TRANSFER || move == mv::TARGETED_SWAP) {
        //Simple way to figure out which box is the other one. 0 -->1 and 1-->0
        //Assumes just two boxes.
        uint otherBox = box == 0;
        SetSingleMoveAccepted(otherBox);
      }
#endif
    }
  }

  if(move == mv::MULTIPARTICLE  || move == mv::MULTIPARTICLE_BM)
    UnsetSingleMoveAccepted(box);

  acceptPercent[box][move][kind] = (double)(accepted[box][move][kind]) /
                                   (double)(tries[box][move][kind]);

  //for any move that we don't care about kind of molecule, it should be included
  //in the if condition
  if (move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE || move == mv::MULTIPARTICLE_BM
#if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
#endif
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
#endif
     ) {
    for (uint k = 1; k < totKind; k++) {
      tries[box][move][k]++;
      tempTries[box][move][k]++;
      if(isAccepted) {
        tempAccepted[box][move][k]++;
        accepted[box][move][k]++;
      }
      acceptPercent[box][move][k] = (double)(accepted[box][move][k]) /
                                    (double)(tries[box][move][k]);
    }
  }
}

void MoveSettings::AdjustMoves(const ulong step)
{
  //Check whether we need to adjust this move's scaling.
  if ((step + 1) % perAdjust == 0) {
    for(uint b = 0; b < BOX_TOTAL; b++) {
      for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; ++m) {
        for(uint k = 0; k < totKind; k++) {
          Adjust(b, m, k);
        }
      }
      for(int m = 0; m < mp::MPTOTALTYPES; m++) {
        AdjustMultiParticle(b, m);
      }
    }
  }
}

void MoveSettings::AdjustMultiParticle(const uint box, const uint typePick)
{
  //Make sure we tried some moves of this move type, otherwise move max will be NaN
  if (mp_interval_tries[box][typePick] > 0) {
    //Update totals for the entire simulation
    mp_tries[box][typePick] += mp_interval_tries[box][typePick];
    mp_accepted[box][typePick] += mp_interval_accepted[box][typePick];
    double fractOfTotalAccept = ((double)mp_accepted[box][typePick] /
                                 (double)mp_tries[box][typePick]) / mp::TARGET_ACCEPT_FRACT;
    double fractOfIntervalAccept = ((double)mp_interval_accepted[box][typePick] /
                                    (double)mp_interval_tries[box][typePick]) / mp::TARGET_ACCEPT_FRACT;
    if (typePick == mp::MPDISPLACE) {
      if (fractOfIntervalAccept == 0.0) {
        mp_t_max[box] *= 0.5;
      } else if (fabs(fractOfIntervalAccept - mp::TARGET_ACCEPT_FRACT) > mp_accept_tol) {
        mp_t_max[box] *= ((1.0-t_alpha) * fractOfTotalAccept
                          + t_alpha * fractOfIntervalAccept);
      }
      num::Bound<double>(mp_t_max[box], 0.001, (boxDimRef.axis.Min(box) * 0.5) - 0.001);
    } else {
      if (fractOfIntervalAccept == 0.0) {
        mp_r_max[box] *= 0.5;
      } else if (fabs(fractOfIntervalAccept - mp::TARGET_ACCEPT_FRACT) > mp_accept_tol) {
        mp_r_max[box] *= ((1.0-r_alpha) * fractOfTotalAccept
                          + r_alpha * fractOfIntervalAccept);
      }
      num::Bound<double>(mp_r_max[box], 0.001, M_PI - 0.001);
    }
    //Reset totals for next adjustment period
    mp_interval_accepted[box][typePick] = 0;
    mp_interval_tries[box][typePick] = 0;
  }
}

void MoveSettings::UpdateMoveSettingMultiParticle(const uint box, bool isAccept,
    const uint typePick)
{
  mp_interval_tries[box][typePick]++;
  if(isAccept) {
    mp_interval_accepted[box][typePick]++;
  }
}

//Adjust responsibly
void MoveSettings::Adjust(const uint box, const uint move, const uint kind)
{
  if(move == mv::DISPLACE) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                             (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    num::Bound<double>(scale[box][move][kind], 1.0e-10,
                       (boxDimRef.axis.Min(box) * 0.5) - TINY_AMOUNT);
  } else if(move == mv::ROTATE) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                             (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    num::Bound<double>(scale[box][move][kind], 1.0e-6, M_PI - TINY_AMOUNT);
  }
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
  else if(move == mv::VOL_TRANSFER) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                             (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    //Warning: This will lead to have acceptance > 50%
    double maxVolExchange = boxDimRef.volume[box] - boxDimRef.minVol[box];
    num::Bound<double>(scale[box][move][kind], 0.001,  maxVolExchange - 0.001);
  }
#endif
  tempAccepted[box][move][kind] = 0;
  tempTries[box][move][kind] = 0;
}

uint MoveSettings::GetAcceptTot(const uint box, const uint move) const
{
  uint sum = 0;
  for(uint k = 0; k < totKind; k++) {
    sum += accepted[box][move][k];
  }

  if(move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE || move == mv::MULTIPARTICLE_BM
#if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
#endif
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
#endif
    ) {
    sum /= totKind;
  }
  return sum;
}

double MoveSettings::GetScaleTot(const uint box, const uint move) const
{
  double sum = 0.0;
  for(uint k = 0; k < totKind; k++) {
    sum += scale[box][move][k];
  }
  return sum / (double)(totKind);
}

uint MoveSettings::GetTrialTot(const uint box, const uint move) const
{
  uint sum = 0;
  for(uint k = 0; k < totKind; k++) {
    sum += tries[box][move][k];
  }

  if(move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE || move == mv::MULTIPARTICLE_BM
#if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
#endif
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
#endif
    ) {
    sum /= totKind;
  }

  return sum;
}

#if GOMC_GTEST

  bool MoveSettings::operator==(const MoveSettings & rhs){
    bool result = true;

    result &= (scale == rhs.scale);
    result &= (acceptPercent == rhs.acceptPercent);
    //index [BOX_TOTAL * kind + box] is the first element of that kind/box in
    //molLookup
    //index [BOX_TOTAL * kind + box + 1] is the element after the end
    //of that kind/box
    result &= (accepted == rhs.accepted);
    result &= (tries == rhs.tries);
    result &= (tempAccepted == rhs.tempAccepted);
    result &= (tempTries == rhs.tempTries);
    result &= (mp_accepted == rhs.mp_accepted);
    result &= (mp_tries == rhs.mp_tries); //Kinds that can move intra and inter box
    result &= (mp_interval_accepted == rhs.mp_interval_accepted); //Kinds that can move intra box only
    result &= (mp_interval_tries == rhs.mp_interval_tries); // stores the molecule index for global atom index
    result &= (mp_r_max == rhs.mp_r_max); // stores the local atom index for global atom index
    result &= (mp_t_max == rhs.mp_t_max); // stores the molecule kind for global atom index

    return result;
  }
#endif<commit_msg>Added singleMoveAcc to equal operator.  Thinking about removing the boxDimRef from the constructor of move settings, then I can serialize the whole object.  Will check to see if anything is given a reference to movesettings before checkpoint is loaded.  If not, I will make this change<commit_after>/*******************************************************************************
GPU OPTIMIZED MONTE CARLO (GOMC) 2.70
Copyright (C) 2018  GOMC Group
A copy of the GNU General Public License can be found in the COPYRIGHT.txt
along with this program, also can be found at <http://www.gnu.org/licenses/>.
********************************************************************************/
#include "MoveSettings.h"    //header spec
#include "BoxDimensions.h"   //For axis sizes
#include "BoxDimensionsNonOrth.h"
#include "StaticVals.h"      //For init info
#include <cmath>
#include "NumLib.h"          //For bounding functions
#include "GeomLib.h"         //For M_PI

const double MoveSettings::TARGET_ACCEPT_FRACT = 0.5;
const double MoveSettings::TINY_AMOUNT = 1.0e-7;
const double MoveSettings::r_alpha = 0.2;
const double MoveSettings::t_alpha = 0.2;
const double MoveSettings::mp_accept_tol = 0.1;

void MoveSettings::Init(StaticVals const& statV,
                        pdb_setup::Remarks const& remarks,
                        const uint tkind,
                        bool restartFromCheckpoint)
{
  //Set to true so that we calculate the forces for the current system, even if
  //a MultiParticle move is called before any other moves are accepted.

  totKind = tkind;
  perAdjust = statV.simEventFreq.perAdjust;
  if (!restartFromCheckpoint){
    for (uint b; b < BOXES_WITH_U_NB; b++) {
      SetSingleMoveAccepted(b);
    }

    for(uint b = 0; b < BOX_TOTAL; b++) {
      for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; m++) {
        acceptPercent[b][m].resize(totKind, 0);
        scale[b][m].resize(totKind, 0);
        accepted[b][m].resize(totKind, 0);
        tries[b][m].resize(totKind, 0);
        tempAccepted[b][m].resize(totKind, 0);
        tempTries[b][m].resize(totKind, 0);
      }
    }

    for(uint b = 0; b < BOX_TOTAL; b++) {
      for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; m++) {
        for(uint k = 0; k < totKind; k++) {
          if(m == mv::DISPLACE) {
            if(remarks.restart && remarks.disp[b] > 0.0) {
              scale[b][m][k] = remarks.disp[b];
            } else {
              scale[b][m][k] = boxDimRef.axis.Min(b) * 0.25;
            }
          } else if (m == mv::ROTATE) {
            if(remarks.restart && remarks.rotate[b] > 0.0) {
              scale[b][m][k] = remarks.rotate[b];
            } else {
              scale[b][m][k] = M_PI_4;
            }
          }
  #if ENSEMBLE == NPT || ENSEMBLE == GEMC
          else if (m == mv::VOL_TRANSFER) {
            if(remarks.restart && remarks.vol[b] > 0.0) {
              scale[b][m][k] = remarks.vol[b];
            } else {
              scale[b][m][k] = 500;
            }
          }
  #endif
        }
      }
    }

    // Initialize MultiParticle settings
    for(int b = 0; b < BOX_TOTAL; b++) {
      mp_r_max[b] = 0.01 * M_PI;
      mp_t_max[b] = 0.02;
      for(int m = 0; m < mp::MPTOTALTYPES; m++) {
        mp_tries[b][m] = 0;
        mp_accepted[b][m] = 0;
        mp_interval_tries[b][m] = 0;
        mp_interval_accepted[b][m] = 0;
      }
    }
  }
}

//Process results of move we just did in terms of acceptance counters
void MoveSettings::Update(const uint move, const bool isAccepted,
                          const uint box, const uint kind)
{
  tries[box][move][kind]++;
  tempTries[box][move][kind]++;
  if(isAccepted) {
    tempAccepted[box][move][kind]++;
    accepted[box][move][kind]++;

    if(move != mv::MULTIPARTICLE || move != mv::MULTIPARTICLE_BM) {
      SetSingleMoveAccepted(box);
#if ENSEMBLE == GEMC
      //GEMC has multiple boxes and this move changed both boxes, so we
      //need to also mark the other box as having a move accepted.
      if(move == mv::MEMC || move == mv::MOL_TRANSFER || move == mv::NE_MTMC ||
         move == mv::VOL_TRANSFER || move == mv::TARGETED_SWAP) {
        //Simple way to figure out which box is the other one. 0 -->1 and 1-->0
        //Assumes just two boxes.
        uint otherBox = box == 0;
        SetSingleMoveAccepted(otherBox);
      }
#endif
    }
  }

  if(move == mv::MULTIPARTICLE  || move == mv::MULTIPARTICLE_BM)
    UnsetSingleMoveAccepted(box);

  acceptPercent[box][move][kind] = (double)(accepted[box][move][kind]) /
                                   (double)(tries[box][move][kind]);

  //for any move that we don't care about kind of molecule, it should be included
  //in the if condition
  if (move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE || move == mv::MULTIPARTICLE_BM
#if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
#endif
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
#endif
     ) {
    for (uint k = 1; k < totKind; k++) {
      tries[box][move][k]++;
      tempTries[box][move][k]++;
      if(isAccepted) {
        tempAccepted[box][move][k]++;
        accepted[box][move][k]++;
      }
      acceptPercent[box][move][k] = (double)(accepted[box][move][k]) /
                                    (double)(tries[box][move][k]);
    }
  }
}

void MoveSettings::AdjustMoves(const ulong step)
{
  //Check whether we need to adjust this move's scaling.
  if ((step + 1) % perAdjust == 0) {
    for(uint b = 0; b < BOX_TOTAL; b++) {
      for(uint m = 0; m < mv::MOVE_KINDS_TOTAL; ++m) {
        for(uint k = 0; k < totKind; k++) {
          Adjust(b, m, k);
        }
      }
      for(int m = 0; m < mp::MPTOTALTYPES; m++) {
        AdjustMultiParticle(b, m);
      }
    }
  }
}

void MoveSettings::AdjustMultiParticle(const uint box, const uint typePick)
{
  //Make sure we tried some moves of this move type, otherwise move max will be NaN
  if (mp_interval_tries[box][typePick] > 0) {
    //Update totals for the entire simulation
    mp_tries[box][typePick] += mp_interval_tries[box][typePick];
    mp_accepted[box][typePick] += mp_interval_accepted[box][typePick];
    double fractOfTotalAccept = ((double)mp_accepted[box][typePick] /
                                 (double)mp_tries[box][typePick]) / mp::TARGET_ACCEPT_FRACT;
    double fractOfIntervalAccept = ((double)mp_interval_accepted[box][typePick] /
                                    (double)mp_interval_tries[box][typePick]) / mp::TARGET_ACCEPT_FRACT;
    if (typePick == mp::MPDISPLACE) {
      if (fractOfIntervalAccept == 0.0) {
        mp_t_max[box] *= 0.5;
      } else if (fabs(fractOfIntervalAccept - mp::TARGET_ACCEPT_FRACT) > mp_accept_tol) {
        mp_t_max[box] *= ((1.0-t_alpha) * fractOfTotalAccept
                          + t_alpha * fractOfIntervalAccept);
      }
      num::Bound<double>(mp_t_max[box], 0.001, (boxDimRef.axis.Min(box) * 0.5) - 0.001);
    } else {
      if (fractOfIntervalAccept == 0.0) {
        mp_r_max[box] *= 0.5;
      } else if (fabs(fractOfIntervalAccept - mp::TARGET_ACCEPT_FRACT) > mp_accept_tol) {
        mp_r_max[box] *= ((1.0-r_alpha) * fractOfTotalAccept
                          + r_alpha * fractOfIntervalAccept);
      }
      num::Bound<double>(mp_r_max[box], 0.001, M_PI - 0.001);
    }
    //Reset totals for next adjustment period
    mp_interval_accepted[box][typePick] = 0;
    mp_interval_tries[box][typePick] = 0;
  }
}

void MoveSettings::UpdateMoveSettingMultiParticle(const uint box, bool isAccept,
    const uint typePick)
{
  mp_interval_tries[box][typePick]++;
  if(isAccept) {
    mp_interval_accepted[box][typePick]++;
  }
}

//Adjust responsibly
void MoveSettings::Adjust(const uint box, const uint move, const uint kind)
{
  if(move == mv::DISPLACE) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                             (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    num::Bound<double>(scale[box][move][kind], 1.0e-10,
                       (boxDimRef.axis.Min(box) * 0.5) - TINY_AMOUNT);
  } else if(move == mv::ROTATE) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                             (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    num::Bound<double>(scale[box][move][kind], 1.0e-6, M_PI - TINY_AMOUNT);
  }
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
  else if(move == mv::VOL_TRANSFER) {
    if(tempTries[box][move][kind] > 0) {
      double currentAccept = (double)(tempAccepted[box][move][kind]) /
                             (double)(tempTries[box][move][kind]);
      double fractOfTargetAccept = currentAccept / TARGET_ACCEPT_FRACT;
      if (fractOfTargetAccept > 0.0) {
        scale[box][move][kind] *= fractOfTargetAccept;
      } else {
        scale[box][move][kind] *= 0.5;
      }
    }
    //Warning: This will lead to have acceptance > 50%
    double maxVolExchange = boxDimRef.volume[box] - boxDimRef.minVol[box];
    num::Bound<double>(scale[box][move][kind], 0.001,  maxVolExchange - 0.001);
  }
#endif
  tempAccepted[box][move][kind] = 0;
  tempTries[box][move][kind] = 0;
}

uint MoveSettings::GetAcceptTot(const uint box, const uint move) const
{
  uint sum = 0;
  for(uint k = 0; k < totKind; k++) {
    sum += accepted[box][move][k];
  }

  if(move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE || move == mv::MULTIPARTICLE_BM
#if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
#endif
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
#endif
    ) {
    sum /= totKind;
  }
  return sum;
}

double MoveSettings::GetScaleTot(const uint box, const uint move) const
{
  double sum = 0.0;
  for(uint k = 0; k < totKind; k++) {
    sum += scale[box][move][k];
  }
  return sum / (double)(totKind);
}

uint MoveSettings::GetTrialTot(const uint box, const uint move) const
{
  uint sum = 0;
  for(uint k = 0; k < totKind; k++) {
    sum += tries[box][move][k];
  }

  if(move == mv::INTRA_MEMC || move == mv::MULTIPARTICLE || move == mv::MULTIPARTICLE_BM
#if ENSEMBLE == GEMC || ENSEMBLE == GCMC
      || move == mv::MEMC
#endif
#if ENSEMBLE == NPT || ENSEMBLE == GEMC
      || move == mv::VOL_TRANSFER
#endif
    ) {
    sum /= totKind;
  }

  return sum;
}

#if GOMC_GTEST

  bool MoveSettings::operator==(const MoveSettings & rhs){
    bool result = true;

    result &= (scale == rhs.scale);
    result &= (acceptPercent == rhs.acceptPercent);
    //index [BOX_TOTAL * kind + box] is the first element of that kind/box in
    //molLookup
    //index [BOX_TOTAL * kind + box + 1] is the element after the end
    //of that kind/box
    result &= (accepted == rhs.accepted);
    result &= (tries == rhs.tries);
    result &= (tempAccepted == rhs.tempAccepted);
    result &= (tempTries == rhs.tempTries);
    result &= (mp_accepted == rhs.mp_accepted);
    result &= (mp_tries == rhs.mp_tries); //Kinds that can move intra and inter box
    result &= (mp_interval_accepted == rhs.mp_interval_accepted); //Kinds that can move intra box only
    result &= (mp_interval_tries == rhs.mp_interval_tries); // stores the molecule index for global atom index
    result &= (mp_r_max == rhs.mp_r_max); // stores the local atom index for global atom index
    result &= (mp_t_max == rhs.mp_t_max); // stores the molecule kind for global atom index

    for (int b = 0; b < BOXES_WITH_U_NB; ++b)
      result &= (isSingleMoveAccepted[b] == rhs.isSingleMoveAccepted[b]);

    return result;
  }
#endif<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 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 <logging.h>
#include <util/threadnames.h>
#include <util/time.h>

#include <mutex>

const char * const DEFAULT_DEBUGLOGFILE = "debug.log";

BCLog::Logger& LogInstance()
{
/**
 * NOTE: the logger instances is leaked on exit. This is ugly, but will be
 * cleaned up by the OS/libc. Defining a logger as a global object doesn't work
 * since the order of destruction of static/global objects is undefined.
 * Consider if the logger gets destroyed, and then some later destructor calls
 * LogPrintf, maybe indirectly, and you get a core dump at shutdown trying to
 * access the logger. When the shutdown sequence is fully audited and tested,
 * explicit destruction of these objects can be implemented by changing this
 * from a raw pointer to a std::unique_ptr.
 * Since the destructor is never called, the logger and all its members must
 * have a trivial destructor.
 *
 * This method of initialization was originally introduced in
 * ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c.
 */
    static BCLog::Logger* g_logger{new BCLog::Logger()};
    return *g_logger;
}

bool fLogIPs = DEFAULT_LOGIPS;

static int FileWriteStr(const std::string &str, FILE *fp)
{
    return fwrite(str.data(), 1, str.size(), fp);
}

bool BCLog::Logger::StartLogging()
{
    std::lock_guard<std::mutex> scoped_lock(m_cs);

    assert(m_buffering);
    assert(m_fileout == nullptr);

    if (m_print_to_file) {
        assert(!m_file_path.empty());
        m_fileout = fsbridge::fopen(m_file_path, "a");
        if (!m_fileout) {
            return false;
        }

        setbuf(m_fileout, nullptr); // unbuffered

        // Add newlines to the logfile to distinguish this execution from the
        // last one.
        FileWriteStr("\n\n\n\n\n", m_fileout);
    }

    // dump buffered messages from before we opened the log
    m_buffering = false;
    while (!m_msgs_before_open.empty()) {
        const std::string& s = m_msgs_before_open.front();

        if (m_print_to_file) FileWriteStr(s, m_fileout);
        if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout);
        for (const auto& cb : m_print_callbacks) {
            cb(s);
        }

        m_msgs_before_open.pop_front();
    }
    if (m_print_to_console) fflush(stdout);

    return true;
}

void BCLog::Logger::DisconnectTestLogger()
{
    std::lock_guard<std::mutex> scoped_lock(m_cs);
    m_buffering = true;
    if (m_fileout != nullptr) fclose(m_fileout);
    m_fileout = nullptr;
    m_print_callbacks.clear();
}

void BCLog::Logger::EnableCategory(BCLog::LogFlags flag)
{
    m_categories |= flag;
}

bool BCLog::Logger::EnableCategory(const std::string& str)
{
    BCLog::LogFlags flag;
    if (!GetLogCategory(flag, str)) return false;
    EnableCategory(flag);
    return true;
}

void BCLog::Logger::DisableCategory(BCLog::LogFlags flag)
{
    m_categories &= ~flag;
}

bool BCLog::Logger::DisableCategory(const std::string& str)
{
    BCLog::LogFlags flag;
    if (!GetLogCategory(flag, str)) return false;
    DisableCategory(flag);
    return true;
}

bool BCLog::Logger::WillLogCategory(BCLog::LogFlags category) const
{
    return (m_categories.load(std::memory_order_relaxed) & category) != 0;
}

bool BCLog::Logger::DefaultShrinkDebugFile() const
{
    return m_categories == BCLog::NONE;
}

struct CLogCategoryDesc
{
    BCLog::LogFlags flag;
    std::string category;
};

const CLogCategoryDesc LogCategories[] =
{
    {BCLog::NONE, "0"},
    {BCLog::NONE, "none"},
    {BCLog::NET, "net"},
    {BCLog::TOR, "tor"},
    {BCLog::MEMPOOL, "mempool"},
    {BCLog::HTTP, "http"},
    {BCLog::BENCH, "bench"},
    {BCLog::ZMQ, "zmq"},
    {BCLog::DB, "db"},
    {BCLog::RPC, "rpc"},
    {BCLog::ESTIMATEFEE, "estimatefee"},
    {BCLog::ADDRMAN, "addrman"},
    {BCLog::SELECTCOINS, "selectcoins"},
    {BCLog::REINDEX, "reindex"},
    {BCLog::CMPCTBLOCK, "cmpctblock"},
    {BCLog::RAND, "rand"},
    {BCLog::PRUNE, "prune"},
    {BCLog::PROXY, "proxy"},
    {BCLog::MEMPOOLREJ, "mempoolrej"},
    {BCLog::LIBEVENT, "libevent"},
    {BCLog::COINDB, "coindb"},
    {BCLog::QT, "qt"},
    {BCLog::LEVELDB, "leveldb"},
    {BCLog::ALL, "1"},
    {BCLog::ALL, "all"},
};

bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
{
    if (str == "") {
        flag = BCLog::ALL;
        return true;
    }
    for (const CLogCategoryDesc& category_desc : LogCategories) {
        if (category_desc.category == str) {
            flag = category_desc.flag;
            return true;
        }
    }
    return false;
}

std::string ListLogCategories()
{
    std::string ret;
    int outcount = 0;
    for (const CLogCategoryDesc& category_desc : LogCategories) {
        // Omit the special cases.
        if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
            if (outcount != 0) ret += ", ";
            ret += category_desc.category;
            outcount++;
        }
    }
    return ret;
}

std::vector<CLogCategoryActive> ListActiveLogCategories()
{
    std::vector<CLogCategoryActive> ret;
    for (const CLogCategoryDesc& category_desc : LogCategories) {
        // Omit the special cases.
        if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
            CLogCategoryActive catActive;
            catActive.category = category_desc.category;
            catActive.active = LogAcceptCategory(category_desc.flag);
            ret.push_back(catActive);
        }
    }
    return ret;
}

std::string BCLog::Logger::LogTimestampStr(const std::string& str)
{
    std::string strStamped;

    if (!m_log_timestamps)
        return str;

    if (m_started_new_line) {
        int64_t nTimeMicros = GetTimeMicros();
        strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
        if (m_log_time_micros) {
            strStamped.pop_back();
            strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
        }
        int64_t mocktime = GetMockTime();
        if (mocktime) {
            strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
        }
        strStamped += ' ' + str;
    } else
        strStamped = str;

    return strStamped;
}

namespace BCLog {
    /** Belts and suspenders: make sure outgoing log messages don't contain
     * potentially suspicious characters, such as terminal control codes.
     *
     * This escapes control characters except newline ('\n') in C syntax.
     * It escapes instead of removes them to still allow for troubleshooting
     * issues where they accidentally end up in strings.
     */
    std::string LogEscapeMessage(const std::string& str) {
        std::string ret;
        for (char ch_in : str) {
            uint8_t ch = (uint8_t)ch_in;
            if ((ch >= 32 || ch == '\n') && ch != '\x7f') {
                ret += ch_in;
            } else {
                ret += strprintf("\\x%02x", ch);
            }
        }
        return ret;
    }
}

void BCLog::Logger::LogPrintStr(const std::string& str)
{
    std::lock_guard<std::mutex> scoped_lock(m_cs);
    std::string str_prefixed = LogEscapeMessage(str);

    if (m_log_threadnames && m_started_new_line) {
        str_prefixed.insert(0, "[" + util::ThreadGetInternalName() + "] ");
    }

    str_prefixed = LogTimestampStr(str_prefixed);

    m_started_new_line = !str.empty() && str[str.size()-1] == '\n';

    if (m_buffering) {
        // buffer if we haven't started logging yet
        m_msgs_before_open.push_back(str_prefixed);
        return;
    }

    if (m_print_to_console) {
        // print to console
        fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
        fflush(stdout);
    }
    for (const auto& cb : m_print_callbacks) {
        cb(str_prefixed);
    }
    if (m_print_to_file) {
        assert(m_fileout != nullptr);

        // reopen the log file, if requested
        if (m_reopen_file) {
            m_reopen_file = false;
            FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
            if (new_fileout) {
                setbuf(new_fileout, nullptr); // unbuffered
                fclose(m_fileout);
                m_fileout = new_fileout;
            }
        }
        FileWriteStr(str_prefixed, m_fileout);
    }
}

void BCLog::Logger::ShrinkDebugFile()
{
    // Amount of debug.log to save at end when shrinking (must fit in memory)
    constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;

    assert(!m_file_path.empty());

    // Scroll debug.log if it's getting too big
    FILE* file = fsbridge::fopen(m_file_path, "r");

    // Special files (e.g. device nodes) may not have a size.
    size_t log_size = 0;
    try {
        log_size = fs::file_size(m_file_path);
    } catch (const fs::filesystem_error&) {}

    // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
    // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
    if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
    {
        // Restart the file with some of the end
        std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
        if (fseek(file, -((long)vch.size()), SEEK_END)) {
            LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
            fclose(file);
            return;
        }
        int nBytes = fread(vch.data(), 1, vch.size(), file);
        fclose(file);

        file = fsbridge::fopen(m_file_path, "w");
        if (file)
        {
            fwrite(vch.data(), 1, nBytes, file);
            fclose(file);
        }
    }
    else if (file != nullptr)
        fclose(file);
}
<commit_msg>Rename `db` log category to `walletdb` (like `coindb`)<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 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 <logging.h>
#include <util/threadnames.h>
#include <util/time.h>

#include <mutex>

const char * const DEFAULT_DEBUGLOGFILE = "debug.log";

BCLog::Logger& LogInstance()
{
/**
 * NOTE: the logger instances is leaked on exit. This is ugly, but will be
 * cleaned up by the OS/libc. Defining a logger as a global object doesn't work
 * since the order of destruction of static/global objects is undefined.
 * Consider if the logger gets destroyed, and then some later destructor calls
 * LogPrintf, maybe indirectly, and you get a core dump at shutdown trying to
 * access the logger. When the shutdown sequence is fully audited and tested,
 * explicit destruction of these objects can be implemented by changing this
 * from a raw pointer to a std::unique_ptr.
 * Since the destructor is never called, the logger and all its members must
 * have a trivial destructor.
 *
 * This method of initialization was originally introduced in
 * ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c.
 */
    static BCLog::Logger* g_logger{new BCLog::Logger()};
    return *g_logger;
}

bool fLogIPs = DEFAULT_LOGIPS;

static int FileWriteStr(const std::string &str, FILE *fp)
{
    return fwrite(str.data(), 1, str.size(), fp);
}

bool BCLog::Logger::StartLogging()
{
    std::lock_guard<std::mutex> scoped_lock(m_cs);

    assert(m_buffering);
    assert(m_fileout == nullptr);

    if (m_print_to_file) {
        assert(!m_file_path.empty());
        m_fileout = fsbridge::fopen(m_file_path, "a");
        if (!m_fileout) {
            return false;
        }

        setbuf(m_fileout, nullptr); // unbuffered

        // Add newlines to the logfile to distinguish this execution from the
        // last one.
        FileWriteStr("\n\n\n\n\n", m_fileout);
    }

    // dump buffered messages from before we opened the log
    m_buffering = false;
    while (!m_msgs_before_open.empty()) {
        const std::string& s = m_msgs_before_open.front();

        if (m_print_to_file) FileWriteStr(s, m_fileout);
        if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout);
        for (const auto& cb : m_print_callbacks) {
            cb(s);
        }

        m_msgs_before_open.pop_front();
    }
    if (m_print_to_console) fflush(stdout);

    return true;
}

void BCLog::Logger::DisconnectTestLogger()
{
    std::lock_guard<std::mutex> scoped_lock(m_cs);
    m_buffering = true;
    if (m_fileout != nullptr) fclose(m_fileout);
    m_fileout = nullptr;
    m_print_callbacks.clear();
}

void BCLog::Logger::EnableCategory(BCLog::LogFlags flag)
{
    m_categories |= flag;
}

bool BCLog::Logger::EnableCategory(const std::string& str)
{
    BCLog::LogFlags flag;
    if (!GetLogCategory(flag, str)) {
        if (str == "db") {
            // DEPRECATION: Added in 0.20, should start returning an error in 0.21
            LogPrintf("Warning: logging category 'db' is deprecated, use 'walletdb' instead\n");
            EnableCategory(BCLog::DB);
            return true;
        }
        return false;
    }
    EnableCategory(flag);
    return true;
}

void BCLog::Logger::DisableCategory(BCLog::LogFlags flag)
{
    m_categories &= ~flag;
}

bool BCLog::Logger::DisableCategory(const std::string& str)
{
    BCLog::LogFlags flag;
    if (!GetLogCategory(flag, str)) return false;
    DisableCategory(flag);
    return true;
}

bool BCLog::Logger::WillLogCategory(BCLog::LogFlags category) const
{
    return (m_categories.load(std::memory_order_relaxed) & category) != 0;
}

bool BCLog::Logger::DefaultShrinkDebugFile() const
{
    return m_categories == BCLog::NONE;
}

struct CLogCategoryDesc
{
    BCLog::LogFlags flag;
    std::string category;
};

const CLogCategoryDesc LogCategories[] =
{
    {BCLog::NONE, "0"},
    {BCLog::NONE, "none"},
    {BCLog::NET, "net"},
    {BCLog::TOR, "tor"},
    {BCLog::MEMPOOL, "mempool"},
    {BCLog::HTTP, "http"},
    {BCLog::BENCH, "bench"},
    {BCLog::ZMQ, "zmq"},
    {BCLog::DB, "walletdb"},
    {BCLog::RPC, "rpc"},
    {BCLog::ESTIMATEFEE, "estimatefee"},
    {BCLog::ADDRMAN, "addrman"},
    {BCLog::SELECTCOINS, "selectcoins"},
    {BCLog::REINDEX, "reindex"},
    {BCLog::CMPCTBLOCK, "cmpctblock"},
    {BCLog::RAND, "rand"},
    {BCLog::PRUNE, "prune"},
    {BCLog::PROXY, "proxy"},
    {BCLog::MEMPOOLREJ, "mempoolrej"},
    {BCLog::LIBEVENT, "libevent"},
    {BCLog::COINDB, "coindb"},
    {BCLog::QT, "qt"},
    {BCLog::LEVELDB, "leveldb"},
    {BCLog::ALL, "1"},
    {BCLog::ALL, "all"},
};

bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
{
    if (str == "") {
        flag = BCLog::ALL;
        return true;
    }
    for (const CLogCategoryDesc& category_desc : LogCategories) {
        if (category_desc.category == str) {
            flag = category_desc.flag;
            return true;
        }
    }
    return false;
}

std::string ListLogCategories()
{
    std::string ret;
    int outcount = 0;
    for (const CLogCategoryDesc& category_desc : LogCategories) {
        // Omit the special cases.
        if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
            if (outcount != 0) ret += ", ";
            ret += category_desc.category;
            outcount++;
        }
    }
    return ret;
}

std::vector<CLogCategoryActive> ListActiveLogCategories()
{
    std::vector<CLogCategoryActive> ret;
    for (const CLogCategoryDesc& category_desc : LogCategories) {
        // Omit the special cases.
        if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) {
            CLogCategoryActive catActive;
            catActive.category = category_desc.category;
            catActive.active = LogAcceptCategory(category_desc.flag);
            ret.push_back(catActive);
        }
    }
    return ret;
}

std::string BCLog::Logger::LogTimestampStr(const std::string& str)
{
    std::string strStamped;

    if (!m_log_timestamps)
        return str;

    if (m_started_new_line) {
        int64_t nTimeMicros = GetTimeMicros();
        strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
        if (m_log_time_micros) {
            strStamped.pop_back();
            strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
        }
        int64_t mocktime = GetMockTime();
        if (mocktime) {
            strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
        }
        strStamped += ' ' + str;
    } else
        strStamped = str;

    return strStamped;
}

namespace BCLog {
    /** Belts and suspenders: make sure outgoing log messages don't contain
     * potentially suspicious characters, such as terminal control codes.
     *
     * This escapes control characters except newline ('\n') in C syntax.
     * It escapes instead of removes them to still allow for troubleshooting
     * issues where they accidentally end up in strings.
     */
    std::string LogEscapeMessage(const std::string& str) {
        std::string ret;
        for (char ch_in : str) {
            uint8_t ch = (uint8_t)ch_in;
            if ((ch >= 32 || ch == '\n') && ch != '\x7f') {
                ret += ch_in;
            } else {
                ret += strprintf("\\x%02x", ch);
            }
        }
        return ret;
    }
}

void BCLog::Logger::LogPrintStr(const std::string& str)
{
    std::lock_guard<std::mutex> scoped_lock(m_cs);
    std::string str_prefixed = LogEscapeMessage(str);

    if (m_log_threadnames && m_started_new_line) {
        str_prefixed.insert(0, "[" + util::ThreadGetInternalName() + "] ");
    }

    str_prefixed = LogTimestampStr(str_prefixed);

    m_started_new_line = !str.empty() && str[str.size()-1] == '\n';

    if (m_buffering) {
        // buffer if we haven't started logging yet
        m_msgs_before_open.push_back(str_prefixed);
        return;
    }

    if (m_print_to_console) {
        // print to console
        fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
        fflush(stdout);
    }
    for (const auto& cb : m_print_callbacks) {
        cb(str_prefixed);
    }
    if (m_print_to_file) {
        assert(m_fileout != nullptr);

        // reopen the log file, if requested
        if (m_reopen_file) {
            m_reopen_file = false;
            FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
            if (new_fileout) {
                setbuf(new_fileout, nullptr); // unbuffered
                fclose(m_fileout);
                m_fileout = new_fileout;
            }
        }
        FileWriteStr(str_prefixed, m_fileout);
    }
}

void BCLog::Logger::ShrinkDebugFile()
{
    // Amount of debug.log to save at end when shrinking (must fit in memory)
    constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;

    assert(!m_file_path.empty());

    // Scroll debug.log if it's getting too big
    FILE* file = fsbridge::fopen(m_file_path, "r");

    // Special files (e.g. device nodes) may not have a size.
    size_t log_size = 0;
    try {
        log_size = fs::file_size(m_file_path);
    } catch (const fs::filesystem_error&) {}

    // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
    // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
    if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
    {
        // Restart the file with some of the end
        std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
        if (fseek(file, -((long)vch.size()), SEEK_END)) {
            LogPrintf("Failed to shrink debug log file: fseek(...) failed\n");
            fclose(file);
            return;
        }
        int nBytes = fread(vch.data(), 1, vch.size(), file);
        fclose(file);

        file = fsbridge::fopen(m_file_path, "w");
        if (file)
        {
            fwrite(vch.data(), 1, nBytes, file);
            fclose(file);
        }
    }
    else if (file != nullptr)
        fclose(file);
}
<|endoftext|>


<commit_before>//#include <iostream>
#include <ctime>
#ifndef _NO_CUI_
#include <iostream>
#endif
#include "machine.h"

namespace kagami {
  map<string, Machine> &GetFunctionBase() {
    static map<string, Machine> base;
    return base;
  }

  inline void AddFunction(string id, vector<Processor> proc, vector<string> parms) {
    auto &base = GetFunctionBase();
    base[id] = Machine(proc).SetParameters(parms);
    entry::AddEntry(Entry(FunctionTunnel, id, parms));
  }

  inline Machine *GetFunction(string id) {
    Machine *machine = nullptr;
    auto &base = GetFunctionBase();
    auto it = base.find(id);
    if (it != base.end()) machine = &(it->second);
    return machine;
  }

  Message FunctionTunnel(ObjectMap &p) {
    Message msg;
    Object &funcId = p[kStrUserFunc];
    string id = *static_pointer_cast<string>(funcId.Get());
    Machine *mach = GetFunction(id);
    if (mach != nullptr) {
      msg = mach->RunAsFunction(p);
    }
    return msg;
  }

  inline bool GetBooleanValue(string src) {
    if (src == kStrTrue) return true;
    if (src == kStrFalse) return false;
    if (src == "0" || src.empty()) return false;
    return true;
  }

  void Machine::MakeFunction(size_t start,size_t end, MachCtlBlk *blk) {
    if (start > end) return;
    auto &defHead = blk->defHead;
    string id = defHead[0];
    vector<string> parms;
    vector<Processor> proc;

    for (size_t i = 1; i < defHead.size(); ++i) {
      parms.push_back(defHead[i]);
    }
    for (size_t j = start; j <= end; ++j) {
      proc.push_back(storage[j]);
    }
    AddFunction(id, proc, parms);
  }

  Machine &Machine::SetParameters(vector<string> parms) {
    this->parameters = parms;
    return *this;
  }

  void Machine::Reset(MachCtlBlk *blk) {
    isTerminal = false;
    Kit().CleanupVector(storage);
    while (!blk->cycleNestStack.empty()) blk->cycleNestStack.pop();
    while (!blk->cycleTailStack.empty()) blk->cycleTailStack.pop();
    while (!blk->modeStack.empty()) blk->modeStack.pop();
    while (!blk->conditionStack.empty()) blk->conditionStack.pop();
    delete blk;
  }

  Machine::Machine(const char *target) {
    std::ifstream stream;
    string temp;
    isTerminal = false;
    health = true;
    size_t subscript = 0;

    stream.open(target, std::ios::in);
    if (stream.good()) {
      while (!stream.eof()) {
        std::getline(stream, temp);
        if (!IsBlankStr(temp) && temp.front() != '#') {
          storage.emplace_back(Processor().Build(temp).SetIndex(subscript));
        }
        subscript++;
      }
    }
    stream.close();
  }

  void Machine::DefineSign(string head, MachCtlBlk *blk) {
    blk->defHead = Kit::BuildStringVector(head);
    if (blk->currentMode != kModeDef && blk->currentMode == kModeNormal) {
      blk->currentMode = kModeDef;
      blk->modeStack.push(kModeNormal);
      blk->defStart = blk->current + 1;
    }
    else if (blk->currentMode != kModeNormal) {
      //?
    }
  }

  void Machine::ConditionRoot(bool value, MachCtlBlk *blk) {
    blk->modeStack.push(blk->currentMode);
    entry::CreateManager();
    if (value == true) {
      blk->currentMode = kModeCondition;
      blk->conditionStack.push(true);
    }
    else {
      blk->currentMode = kModeNextCondition;
      blk->conditionStack.push(false);
    }
  }

  void Machine::ConditionBranch(bool value, MachCtlBlk *blk) {
    if (!blk->conditionStack.empty()) {
      if (blk->conditionStack.top() == false && blk->currentMode == kModeNextCondition
        && value == true) {
        entry::CreateManager();
        blk->currentMode = kModeCondition;
        blk->conditionStack.top() = true;
      }
    }
    else {
      //msg.combo
      health = false;
    }
  }

  void Machine::ConditionLeaf(MachCtlBlk *blk) {
    if (!blk->conditionStack.empty()) {
      if (blk->conditionStack.top() == true) {
        blk->currentMode = kModeNextCondition;
      }
      else {
        entry::CreateManager();
        blk->conditionStack.top() = true;
        blk->currentMode = kModeCondition;
      }
    }
    else {
      //msg.combo
      health = false;
    }
  }

  void Machine::HeadSign(bool value, MachCtlBlk *blk) {
    if (blk->cycleNestStack.empty()) {
      blk->modeStack.push(blk->currentMode);
      entry::CreateManager();
    }
    else {
      if (blk->cycleNestStack.top() != blk->current - 1) {
        blk->modeStack.push(blk->currentMode);
        entry::CreateManager();
      }
    }
    if (value == true) {
      blk->currentMode = kModeCycle;
      if (blk->cycleNestStack.empty()) {
        blk->cycleNestStack.push(blk->current - 1);
      }
      else if (blk->cycleNestStack.top() != blk->current - 1) {
        blk->cycleNestStack.push(blk->current - 1);
      }
    }
    else if (value == false) {
      blk->currentMode = kModeCycleJump;
      if (!blk->cycleTailStack.empty()) {
        blk->current = blk->cycleTailStack.top();
      }
    }
    else {
      health = false;
    }
  }

  void Machine::TailSign(MachCtlBlk *blk) {
    if (blk->currentMode == kModeDef) {
      MakeFunction(blk->defStart, blk->current - 1, blk);
      blk->currentMode = blk->modeStack.top();
      blk->modeStack.pop();
      Kit().CleanupVector(blk->defHead);
    }
    else if (blk->currentMode == kModeCondition || blk->currentMode == kModeNextCondition) {
      blk->conditionStack.pop();
      blk->currentMode = blk->modeStack.top();
      blk->modeStack.pop();
      entry::DisposeManager();
    }
    else if (blk->currentMode == kModeCycle || blk->currentMode == kModeCycleJump) {
      switch (blk->currentMode) {
      case kModeCycle:
        if (blk->cycleTailStack.empty() || blk->cycleTailStack.top() != blk->current - 1) {
          blk->cycleTailStack.push(blk->current - 1);
        }
        blk->current = blk->cycleNestStack.top();
        entry::GetCurrentManager().clear();
        break;
      case kModeCycleJump:
        blk->currentMode = blk->modeStack.top();
        blk->modeStack.pop();
        blk->cycleNestStack.pop();
        if (!blk->cycleTailStack.empty()) blk->cycleTailStack.pop();
        entry::DisposeManager();
        break;
      default:break;
      }
    }
  }

  bool Machine::IsBlankStr(string target) {
    if (target == kStrEmpty || target.size() == 0) return true;
    for (const auto unit : target) {
      if (unit != '\n' && unit != ' ' && unit != '\t' && unit != '\r') {
        return false;
      }
    }
    return true;
  }

  Message Machine::Run(bool createManager) {
    Message result;
    MachCtlBlk *blk = new MachCtlBlk();

    blk->currentMode = kModeNormal;
    blk->nestHeadCount = 0;
    blk->current = 0;
    blk->currentMode = kModeNormal;
    blk->defStart = 0;
    health = true;

    if (storage.empty()) return result;

    if (createManager) entry::CreateManager();

    //Main state machine
    while (blk->current < storage.size()) {
      if (!health) break;

      result = storage[blk->current].Activiate(blk->currentMode);
      const auto value = result.GetValue();
      const auto code  = result.GetCode();

      if (value == kStrFatalError) {
        trace::Log(result.SetIndex(storage[blk->current].GetIndex()));
        break;
      }

      if (value == kStrWarning) {
        trace::Log(result.SetIndex(storage[blk->current].GetIndex()));
      }

      if (value == kStrStopSign) {
        break;
      }

      switch (code) {
      case kCodeDefineSign:
        DefineSign(result.GetDetail(), blk);
        break;
      case kCodeConditionRoot:
        ConditionRoot(GetBooleanValue(value), blk);
        break;
      case kCodeConditionBranch:
        if (blk->nestHeadCount > 0) break;
        ConditionBranch(GetBooleanValue(value), blk);
        break;
      case kCodeConditionLeaf:
        if (blk->nestHeadCount > 0) break;
        ConditionLeaf(blk);
        break;
      case kCodeHeadSign:
        HeadSign(GetBooleanValue(value), blk);
        break;
      case kCodeHeadPlaceholder:
        blk->nestHeadCount++;
        break;
      case kCodeTailSign:
        if (blk->nestHeadCount > 0) {
          blk->nestHeadCount--;
          break;
        }
        TailSign(blk);
        break;
      default:break;
      }
      ++blk->current;
    }

    if (createManager) entry::DisposeManager();
    delete blk;
    return result;
  }

  Message Machine::RunAsFunction(ObjectMap &p) {
    Message msg;
    auto &base = entry::CreateManager();
    for (auto &unit : p) {
      base.Add(unit.first, unit.second);
    }
    msg = Run(false);
    if (msg.GetCode() >= kCodeSuccess) {
      msg = Message();
      Object *ret = base.Find(kStrRetValue);
      if (ret != nullptr) {
        Object obj;
        obj.Copy(*ret);
        msg.SetObject(obj, "__result");
      }
    }
    Object *funcSign = entry::GetCurrentManager().Find(kStrUserFunc);
    string funcId = *static_pointer_cast<string>(p[kStrUserFunc].Get());
    while (funcSign == nullptr) {
      entry::DisposeManager();
      funcSign = entry::GetCurrentManager().Find(kStrUserFunc);
      if (funcSign != nullptr) {
        string value = *static_pointer_cast<string>(p[kStrUserFunc].Get());
        if (value == funcId) break;
      }
    }
    entry::DisposeManager();
    return msg;
  }

  void Machine::Terminal() {
    Message msg;
    string buf;
    string head = kStrNormalArrow;
    Processor processor;
    bool subProcess = false;
    bool skip = false;

    entry::CreateManager();

    while (msg.GetCode() != kCodeQuit) {
      msg = Message();
      std::cout << head;
      std::getline(std::cin, buf);
      if (buf.empty()) continue;
      processor.Build(buf);
      auto tokenValue = entry::GetGenericToken(processor.GetFirstToken().first);
      switch (tokenValue) {
      case GT_IF:
      case GT_WHILE:
      case GT_FOR:
        subProcess = true;
        head = kStrDotGroup;
        break;
      case GT_END:
        subProcess = false;
        skip = true;
        storage.emplace_back(processor);
        head = kStrNormalArrow;
        msg = this->Run();
        Kit().CleanupVector(storage);
        break;
      case GT_DEF:
        //
        break;
      default:
        break;
      }
      if (subProcess) {
        storage.emplace_back(processor);
      }
      else {
        if(!skip) msg = processor.Activiate();
      }

      if (msg.GetCode() < kCodeSuccess) {
        std::cout << msg.GetDetail() << std::endl;
        trace::Log(msg);
      }
      if (skip == true) skip = false;
    }

    entry::DisposeManager();
  }
}

<commit_msg>Fix issue in if-elif-else<commit_after>//#include <iostream>
#include <ctime>
#ifndef _NO_CUI_
#include <iostream>
#endif
#include "machine.h"

namespace kagami {
  map<string, Machine> &GetFunctionBase() {
    static map<string, Machine> base;
    return base;
  }

  inline void AddFunction(string id, vector<Processor> proc, vector<string> parms) {
    auto &base = GetFunctionBase();
    base[id] = Machine(proc).SetParameters(parms);
    entry::AddEntry(Entry(FunctionTunnel, id, parms));
  }

  inline Machine *GetFunction(string id) {
    Machine *machine = nullptr;
    auto &base = GetFunctionBase();
    auto it = base.find(id);
    if (it != base.end()) machine = &(it->second);
    return machine;
  }

  Message FunctionTunnel(ObjectMap &p) {
    Message msg;
    Object &funcId = p[kStrUserFunc];
    string id = *static_pointer_cast<string>(funcId.Get());
    Machine *mach = GetFunction(id);
    if (mach != nullptr) {
      msg = mach->RunAsFunction(p);
    }
    return msg;
  }

  inline bool GetBooleanValue(string src) {
    if (src == kStrTrue) return true;
    if (src == kStrFalse) return false;
    if (src == "0" || src.empty()) return false;
    return true;
  }

  void Machine::MakeFunction(size_t start,size_t end, MachCtlBlk *blk) {
    if (start > end) return;
    auto &defHead = blk->defHead;
    string id = defHead[0];
    vector<string> parms;
    vector<Processor> proc;

    for (size_t i = 1; i < defHead.size(); ++i) {
      parms.push_back(defHead[i]);
    }
    for (size_t j = start; j <= end; ++j) {
      proc.push_back(storage[j]);
    }
    AddFunction(id, proc, parms);
  }

  Machine &Machine::SetParameters(vector<string> parms) {
    this->parameters = parms;
    return *this;
  }

  void Machine::Reset(MachCtlBlk *blk) {
    isTerminal = false;
    Kit().CleanupVector(storage);
    while (!blk->cycleNestStack.empty()) blk->cycleNestStack.pop();
    while (!blk->cycleTailStack.empty()) blk->cycleTailStack.pop();
    while (!blk->modeStack.empty()) blk->modeStack.pop();
    while (!blk->conditionStack.empty()) blk->conditionStack.pop();
    delete blk;
  }

  Machine::Machine(const char *target) {
    std::ifstream stream;
    string temp;
    isTerminal = false;
    health = true;
    size_t subscript = 0;

    stream.open(target, std::ios::in);
    if (stream.good()) {
      while (!stream.eof()) {
        std::getline(stream, temp);
        if (!IsBlankStr(temp) && temp.front() != '#') {
          storage.emplace_back(Processor().Build(temp).SetIndex(subscript));
        }
        subscript++;
      }
    }
    stream.close();
  }

  void Machine::DefineSign(string head, MachCtlBlk *blk) {
    blk->defHead = Kit::BuildStringVector(head);
    if (blk->currentMode != kModeDef && blk->currentMode == kModeNormal) {
      blk->currentMode = kModeDef;
      blk->modeStack.push(kModeNormal);
      blk->defStart = blk->current + 1;
    }
    else if (blk->currentMode != kModeNormal) {
      //?
    }
  }

  void Machine::ConditionRoot(bool value, MachCtlBlk *blk) {
    blk->modeStack.push(blk->currentMode);
    entry::CreateManager();
    if (value == true) {
      blk->currentMode = kModeCondition;
      blk->conditionStack.push(true);
    }
    else {
      blk->currentMode = kModeNextCondition;
      blk->conditionStack.push(false);
    }
  }

  void Machine::ConditionBranch(bool value, MachCtlBlk *blk) {
    if (!blk->conditionStack.empty()) {
      if (blk->conditionStack.top() == false && blk->currentMode == kModeNextCondition
        && value == true) {
        entry::CreateManager();
        blk->currentMode = kModeCondition;
        blk->conditionStack.top() = true;
      }
      else if (blk->conditionStack.top() == true && blk->currentMode == kModeCondition) {
        blk->currentMode = kModeNextCondition;
      }
    }
    else {
      //msg.combo
      health = false;
    }
  }

  void Machine::ConditionLeaf(MachCtlBlk *blk) {
    if (!blk->conditionStack.empty()) {
      if (blk->conditionStack.top() == true) {
        blk->currentMode = kModeNextCondition;
      }
      else {
        entry::CreateManager();
        blk->conditionStack.top() = true;
        blk->currentMode = kModeCondition;
      }
    }
    else {
      //msg.combo
      health = false;
    }
  }

  void Machine::HeadSign(bool value, MachCtlBlk *blk) {
    if (blk->cycleNestStack.empty()) {
      blk->modeStack.push(blk->currentMode);
      entry::CreateManager();
    }
    else {
      if (blk->cycleNestStack.top() != blk->current - 1) {
        blk->modeStack.push(blk->currentMode);
        entry::CreateManager();
      }
    }
    if (value == true) {
      blk->currentMode = kModeCycle;
      if (blk->cycleNestStack.empty()) {
        blk->cycleNestStack.push(blk->current - 1);
      }
      else if (blk->cycleNestStack.top() != blk->current - 1) {
        blk->cycleNestStack.push(blk->current - 1);
      }
    }
    else if (value == false) {
      blk->currentMode = kModeCycleJump;
      if (!blk->cycleTailStack.empty()) {
        blk->current = blk->cycleTailStack.top();
      }
    }
    else {
      health = false;
    }
  }

  void Machine::TailSign(MachCtlBlk *blk) {
    if (blk->currentMode == kModeDef) {
      MakeFunction(blk->defStart, blk->current - 1, blk);
      blk->currentMode = blk->modeStack.top();
      blk->modeStack.pop();
      Kit().CleanupVector(blk->defHead);
    }
    else if (blk->currentMode == kModeCondition || blk->currentMode == kModeNextCondition) {
      blk->conditionStack.pop();
      blk->currentMode = blk->modeStack.top();
      blk->modeStack.pop();
      entry::DisposeManager();
    }
    else if (blk->currentMode == kModeCycle || blk->currentMode == kModeCycleJump) {
      switch (blk->currentMode) {
      case kModeCycle:
        if (blk->cycleTailStack.empty() || blk->cycleTailStack.top() != blk->current - 1) {
          blk->cycleTailStack.push(blk->current - 1);
        }
        blk->current = blk->cycleNestStack.top();
        entry::GetCurrentManager().clear();
        break;
      case kModeCycleJump:
        blk->currentMode = blk->modeStack.top();
        blk->modeStack.pop();
        blk->cycleNestStack.pop();
        if (!blk->cycleTailStack.empty()) blk->cycleTailStack.pop();
        entry::DisposeManager();
        break;
      default:break;
      }
    }
  }

  bool Machine::IsBlankStr(string target) {
    if (target == kStrEmpty || target.size() == 0) return true;
    for (const auto unit : target) {
      if (unit != '\n' && unit != ' ' && unit != '\t' && unit != '\r') {
        return false;
      }
    }
    return true;
  }

  Message Machine::Run(bool createManager) {
    Message result;
    MachCtlBlk *blk = new MachCtlBlk();

    blk->currentMode = kModeNormal;
    blk->nestHeadCount = 0;
    blk->current = 0;
    blk->currentMode = kModeNormal;
    blk->defStart = 0;
    health = true;

    if (storage.empty()) return result;

    if (createManager) entry::CreateManager();

    //Main state machine
    while (blk->current < storage.size()) {
      if (!health) break;

      result = storage[blk->current].Activiate(blk->currentMode);
      const auto value = result.GetValue();
      const auto code  = result.GetCode();

      if (value == kStrFatalError) {
        trace::Log(result.SetIndex(storage[blk->current].GetIndex()));
        break;
      }

      if (value == kStrWarning) {
        trace::Log(result.SetIndex(storage[blk->current].GetIndex()));
      }

      if (value == kStrStopSign) {
        break;
      }

      switch (code) {
      case kCodeDefineSign:
        DefineSign(result.GetDetail(), blk);
        break;
      case kCodeConditionRoot:
        ConditionRoot(GetBooleanValue(value), blk);
        break;
      case kCodeConditionBranch:
        if (blk->nestHeadCount > 0) break;
        ConditionBranch(GetBooleanValue(value), blk);
        break;
      case kCodeConditionLeaf:
        if (blk->nestHeadCount > 0) break;
        ConditionLeaf(blk);
        break;
      case kCodeHeadSign:
        HeadSign(GetBooleanValue(value), blk);
        break;
      case kCodeHeadPlaceholder:
        blk->nestHeadCount++;
        break;
      case kCodeTailSign:
        if (blk->nestHeadCount > 0) {
          blk->nestHeadCount--;
          break;
        }
        TailSign(blk);
        break;
      default:break;
      }
      ++blk->current;
    }

    if (createManager) entry::DisposeManager();
    delete blk;
    return result;
  }

  Message Machine::RunAsFunction(ObjectMap &p) {
    Message msg;
    auto &base = entry::CreateManager();
    for (auto &unit : p) {
      base.Add(unit.first, unit.second);
    }
    msg = Run(false);
    if (msg.GetCode() >= kCodeSuccess) {
      msg = Message();
      Object *ret = base.Find(kStrRetValue);
      if (ret != nullptr) {
        Object obj;
        obj.Copy(*ret);
        msg.SetObject(obj, "__result");
      }
    }
    Object *funcSign = entry::GetCurrentManager().Find(kStrUserFunc);
    string funcId = *static_pointer_cast<string>(p[kStrUserFunc].Get());
    while (funcSign == nullptr) {
      entry::DisposeManager();
      funcSign = entry::GetCurrentManager().Find(kStrUserFunc);
      if (funcSign != nullptr) {
        string value = *static_pointer_cast<string>(p[kStrUserFunc].Get());
        if (value == funcId) break;
      }
    }
    entry::DisposeManager();
    return msg;
  }

  void Machine::Terminal() {
    Message msg;
    string buf;
    string head = kStrNormalArrow;
    Processor processor;
    bool subProcess = false;
    bool skip = false;

    entry::CreateManager();

    while (msg.GetCode() != kCodeQuit) {
      msg = Message();
      std::cout << head;
      std::getline(std::cin, buf);
      if (buf.empty()) continue;
      processor.Build(buf);
      auto tokenValue = entry::GetGenericToken(processor.GetFirstToken().first);
      switch (tokenValue) {
      case GT_IF:
      case GT_WHILE:
      case GT_FOR:
        subProcess = true;
        head = kStrDotGroup;
        break;
      case GT_END:
        subProcess = false;
        skip = true;
        storage.emplace_back(processor);
        head = kStrNormalArrow;
        msg = this->Run();
        Kit().CleanupVector(storage);
        break;
      case GT_DEF:
        //
        break;
      default:
        break;
      }
      if (subProcess) {
        storage.emplace_back(processor);
      }
      else {
        if(!skip) msg = processor.Activiate();
      }

      if (msg.GetCode() < kCodeSuccess) {
        std::cout << msg.GetDetail() << std::endl;
        trace::Log(msg);
      }
      if (skip == true) skip = false;
    }

    entry::DisposeManager();
  }
}

<|endoftext|>