<commit_before>
#include <random>

#include "builtin_bit.hpp"
#ifdef ENABLE_GLFW3
#include "builtin_glfw3.hpp"
#endif
#include "builtin_libc.hpp"
#include "builtin_memory.hpp"
#include "builtin_overflow.hpp"
#include "builtin_posix.hpp"
#include "builtin_va_arg.hpp"
#include "builtin_warp.hpp"

#include "convert.hpp"
#include "definitions.hpp"
#include "error.hpp"
#include "vmachine.hpp"
#include "vmemory.hpp"

using namespace processwarp;

// Destructor for virtual.
VMachineDelegate::~VMachineDelegate() {
  // Do nothing.
}

// Call when send data to other device.
void VMachineDelegate::send_vm_data(const vpid_t& pid,
				    const vtid_t& tid,
				    const dev_id_t& dst_device_id,
				    const std::string& data) {
  // Do nothing.
}

// Call when context switch of process.
void VMachineDelegate::on_switch_proccess(const vpid_t& pid) {
  // Do nothing.
}

// Call when process was finish.
void VMachineDelegate::on_finish_proccess(const vpid_t& pid) {
  // Do nothing.
}

// Call when a thread was finish.
void VMachineDelegate::on_finish_thread(const vpid_t& pid, const vtid_t& tid) {
  // Do nothing.
}

// Call when rise error.
void VMachineDelegate::on_error(const vpid_t& pid,
				const std::string& message) {
  // Do nothing.
}

// Constractor with delegate.
VMachine::VMachine(VMachineDelegate& delegate_,
		   VMemoryDelegate& memory_delegate,
		   const dev_id_t& device_id_,
		   const std::vector<void*>& libs_,
		   const std::map<std::string, std::string>& lib_filter_) :
  device_id(device_id_),
  delegate(delegate_),
  vmemory(memory_delegate, device_id_),
  libs(libs_),
  lib_filter(lib_filter_) {
  // Do nothing.
}

// Main loop.
void VMachine::loop() {
  vpid_t pid;
  vtid_t tid;
  Process* proc;
  Thread*  thread;

  try {
    auto it_proc = procs.begin();
    while (it_proc != procs.end()) {
      pid  = it_proc->first;
      proc = it_proc->second.get();

      auto it_thread = proc->active_threads.begin();
      while(it_thread != proc->active_threads.end()) {
	try {
	  tid    = *it_thread;
	  thread = &proc->get_thread(tid);

	  if (thread->status == Thread::NORMAL ||
	      thread->status == Thread::WAIT_WARP ||
	      thread->status == Thread::BEFOR_WARP ||
	      thread->status == Thread::AFTER_WARP) {

	    delegate.on_switch_proccess(pid);
	    // run thread
	    proc->execute(tid, 100);

	  } else if (thread->status == Thread::WARP) {
	    do_warp_process(pid);

	  } else if (thread->status == Thread::ERROR) {
	    delegate.on_error(pid, "");

	  } else if (thread->status == Thread::FINISH) {
	    delegate.on_finish_thread(pid, tid);

	    if (tid == proc->root_tid) {
	      delegate.on_finish_proccess(pid);
	      it_proc = procs.erase(it_proc);
	      // continue double loop
	      goto next_proc;

	    } else {
	      it_thread = proc->active_threads.erase(it_thread);
	      proc->threads.erase(tid);
	      continue;
	    }
	  }
	} catch (VMemory::WaitingException& e) {
	  // Skip thread because waiting to update memroy data.
	}

	it_thread ++;
      }

      it_proc ++;
    next_proc:
      ;
    }

  } catch (Error& e) {
    delegate.on_error(pid, "");
    thread->status = Thread::FINISH;

  }
#ifdef NDEBUG
  catch (std::exception& e) {
    delegate.on_error(pid, e.what());
    thread->status = Thread::FINISH;

  } catch (...) {
    delegate.on_error(pid, "unknown exception");
    thread->status = Thread::FINISH;
  }
#endif

  delegate.on_switch_proccess("");
}

// Pass data from other device.
void VMachine::recv_packet(const vpid_t& pid,
			   const vtid_t& tid,
			   const std::string& data) {
  try {
    picojson::value v;
    std::istringstream is(data);
    std::string err = picojson::parse(v, is);
    if (!err.empty()) {
      std::cerr << err << std::endl;
      assert(false);
      /// @todo error
    }

    picojson::object json = v.get<picojson::object>();

    // select cmd
    std::string cmd = json.at("cmd").get<std::string>();
    if (cmd == "warp") {
      recv_process_warp(pid, json);

    } else {
      assert(false);
      /// @todo error
    }

    return;

  } catch (Error& e) {
    std::cerr << e.reason << ":" << e.mesg << std::endl;

  }
#ifdef NDEBUG
  catch (std::exception& e) {
    std::cerr << e.what() << std::endl;

  } catch (...) {
    std::cerr << "unknown exception" << std::endl;
  }
#endif

  assert(false);
  /// @todo error
}

// Create empty process.
void VMachine::create_process(const vpid_t& pid, const vtid_t& root_tid, vaddr_t proc_addr) {
  assert(procs.find(pid) == procs.end());
  procs.insert(std::make_pair(pid, std::move(Process::alloc
					     (*this, pid, root_tid, libs, lib_filter, builtin_funcs, proc_addr))));
  procs.at(pid)->setup();
}

// Delete process.
void VMachine::delete_process(const vpid_t& pid) {
  if (procs.find(pid) == procs.end()) return;
  procs.erase(pid);
  warp_dest.erase(pid);
}

// Start exiting process.
void VMachine::exit_process(const vpid_t& pid) {
  if (procs.find(pid) == procs.end()) return;
  procs.at(pid)->exit();
}

// Get process instance by process-id.
Process& VMachine::get_process(const vpid_t& pid) {
  return *procs.at(pid);
}

// Check whether process has contain in this device.
bool VMachine::have_process(const vpid_t& pid) {
  return (procs.find(pid) != procs.end());
}

// Start warp process.
void VMachine::warp_process(const vpid_t& pid,
			    const vtid_t& tid,
			    const dev_id_t& dst_device_id) {
  warp_dest[pid] = dst_device_id;
  // Change vm's status for setup to warp.
  if (tid == ALL_THREAD) {
    for (auto& it : procs.at(pid)->active_threads) {
      procs.at(pid)->setup_warpin(it, dst_device_id);
    }

  } else {
    procs.at(pid)->setup_warpin(tid, dst_device_id);
  }
}

// @inheritDoc
std::unique_ptr<VMemory::Accessor> VMachine::assign_accessor(const vpid_t& pid) {
  return std::move(vmemory.get_accessor(Convert::vpid2str(pid)));
}

// Dump and send data to warp process.
void VMachine::do_warp_process(const vpid_t& pid) {
  /// TODO:
  assert(false);
  /*
  Process& proc    = *procs.at(pid);
  VMemory::Accessor& memory = *proc.proc_memory;

  // Dump process.
  Convert convert(proc);
  Convert::Related related;
  picojson::object body;
  picojson::object dump;
  picojson::object threads;
  body.insert(std::make_pair("cmd", picojson::value(std::string("warp"))));
  body.insert(std::make_pair("pid", Convert::vpid2json(pid)));
  body.insert(std::make_pair("root_tid", Convert::vtid2json(proc.root_tid)));
  for (auto& it : proc.threads) {
    threads.insert(std::make_pair(Convert::vtid2str(it.first),
				  convert.export_thread(*it.second, related)));
  }
  body.insert(std::make_pair("threads", picojson::value(threads)));

  std::set<vaddr_t> all = proc.vmemory.get_alladdr();
  for (auto it : all) {
    // Don't export null instance.
    if (it == VADDR_NULL || it == VADDR_NON) continue;
    // Don't export build in instance.
    if (proc.builtin_addrs.find(it) != proc.builtin_addrs.end()) continue;

    dump.insert(std::make_pair(Util::vaddr2str(it), convert.export_store(it, related)));
    // Free allocated data.
    if (!VMemory::addr_is_func(it) && !VMemory::addr_is_type(it)) {
      vmemory.free(it);
    }
  }
  body.insert(std::make_pair("dump", picojson::value(dump)));

  std::string data = picojson::value(body).serialize();
  delegate.send_warp_data(pid, 1, warp_dest.at(pid), data);

  warp_dest.erase(pid);
  for (auto& it_thread : proc.threads) {
    it_thread.second->status = Thread::PASSIVE;
  }
  */
}

void VMachine::recv_process_warp(const vpid_t& pid, picojson::object& json) {
  /// TODO
  assert(false);
  /*
  Process& proc = *procs.at(pid);
  VMemory& vmemory = proc.vmemory;
  Convert convert(proc);

  // Expand transported instance data.
  picojson::object dump = json.at("dump").get<picojson::object>();
  for (auto it : dump) {
    if(!vmemory.addr_is_used(Util::str2vaddr(it.first))) {
      convert.import_store(Util::str2vaddr(it.first), it.second);
    }
  }

  // Expand thread data.
  for (auto& it : json.at("threads").get<picojson::object>()) {
    convert.import_thread(Util::hex_str2num<vtid_t>(it.first), it.second);
  }

  proc.setup_warpout(1);

  // Turn on proc.
  for (auto& it_thread : proc.threads) {
    it_thread.second->status = Thread::NORMAL;
  }
  */
}

// Regist built-in function to virtual machine.
void VMachine::regist_builtin_func(const std::string& name,
				   builtin_func_t func, int i64) {
  BuiltinFuncParam param;
  param.i64 = i64;
  builtin_funcs.insert(std::make_pair(name, std::make_pair(func, param)));
}

// Regist built-in function to virtual machine.
void VMachine::regist_builtin_func(const std::string& name,
				   builtin_func_t func, void* ptr) {
  BuiltinFuncParam param;
  param.ptr = ptr;
  builtin_funcs.insert(std::make_pair(name, std::make_pair(func, param)));
}

// Setup virtual machine.
void VMachine::setup_builtin() {
  // VMの組み込み関数をロード
  BuiltinBit::regist(*this);
#ifdef ENABLE_GLFW3
  BuiltinGlfw3::regist(*this);
#endif
  BuiltinLibc::regist(*this);
  BuiltinMemory::regist(*this);
  BuiltinOverflow::regist(*this);
  BuiltinPosix::regist(*this);
  BuiltinVaArg::regist(*this);
  BuiltinWarp::regist(*this);
}
<commit_msg>fix memory leak<commit_after>
#include <random>

#include "builtin_bit.hpp"
#ifdef ENABLE_GLFW3
#include "builtin_glfw3.hpp"
#endif
#include "builtin_libc.hpp"
#include "builtin_memory.hpp"
#include "builtin_overflow.hpp"
#include "builtin_posix.hpp"
#include "builtin_va_arg.hpp"
#include "builtin_warp.hpp"

#include "convert.hpp"
#include "definitions.hpp"
#include "error.hpp"
#include "vmachine.hpp"
#include "vmemory.hpp"

using namespace processwarp;

// Destructor for virtual.
VMachineDelegate::~VMachineDelegate() {
  // Do nothing.
}

// Call when send data to other device.
void VMachineDelegate::send_vm_data(const vpid_t& pid,
				    const vtid_t& tid,
				    const dev_id_t& dst_device_id,
				    const std::string& data) {
  // Do nothing.
}

// Call when context switch of process.
void VMachineDelegate::on_switch_proccess(const vpid_t& pid) {
  // Do nothing.
}

// Call when process was finish.
void VMachineDelegate::on_finish_proccess(const vpid_t& pid) {
  // Do nothing.
}

// Call when a thread was finish.
void VMachineDelegate::on_finish_thread(const vpid_t& pid, const vtid_t& tid) {
  // Do nothing.
}

// Call when rise error.
void VMachineDelegate::on_error(const vpid_t& pid,
				const std::string& message) {
  // Do nothing.
}

// Constractor with delegate.
VMachine::VMachine(VMachineDelegate& delegate_,
		   VMemoryDelegate& memory_delegate,
		   const dev_id_t& device_id_,
		   const std::vector<void*>& libs_,
		   const std::map<std::string, std::string>& lib_filter_) :
  device_id(device_id_),
  delegate(delegate_),
  vmemory(memory_delegate, device_id_),
  libs(libs_),
  lib_filter(lib_filter_) {
  // Do nothing.
}

// Main loop.
void VMachine::loop() {
  vpid_t pid;
  vtid_t tid;
  Process* proc;
  Thread*  thread;

  try {
    auto it_proc = procs.begin();
    while (it_proc != procs.end()) {
      pid  = it_proc->first;
      proc = it_proc->second.get();

      auto it_thread = proc->active_threads.begin();
      while(it_thread != proc->active_threads.end()) {
	try {
	  tid    = *it_thread;
	  thread = &proc->get_thread(tid);

	  if (thread->status == Thread::NORMAL ||
	      thread->status == Thread::WAIT_WARP ||
	      thread->status == Thread::BEFOR_WARP ||
	      thread->status == Thread::AFTER_WARP) {

	    delegate.on_switch_proccess(pid);
	    // run thread
	    proc->execute(tid, 100);

	  } else if (thread->status == Thread::WARP) {
	    do_warp_process(pid);

	  } else if (thread->status == Thread::ERROR) {
	    delegate.on_error(pid, "");

	  } else if (thread->status == Thread::FINISH) {
	    delegate.on_finish_thread(pid, tid);

	    if (tid == proc->root_tid) {
	      delegate.on_finish_proccess(pid);
	      it_proc = procs.erase(it_proc);
	      // continue double loop
	      goto next_proc;

	    } else {
	      it_thread = proc->active_threads.erase(it_thread);
	      proc->threads.erase(tid);
	      proc->proc_memory->free(tid);
	      continue;
	    }
	  }
	} catch (VMemory::WaitingException& e) {
	  // Skip thread because waiting to update memroy data.
	}

	it_thread ++;
      }

      it_proc ++;
    next_proc:
      ;
    }

  } catch (Error& e) {
    delegate.on_error(pid, "");
    thread->status = Thread::FINISH;

  }
#ifdef NDEBUG
  catch (std::exception& e) {
    delegate.on_error(pid, e.what());
    thread->status = Thread::FINISH;

  } catch (...) {
    delegate.on_error(pid, "unknown exception");
    thread->status = Thread::FINISH;
  }
#endif

  delegate.on_switch_proccess("");
}

// Pass data from other device.
void VMachine::recv_packet(const vpid_t& pid,
			   const vtid_t& tid,
			   const std::string& data) {
  try {
    picojson::value v;
    std::istringstream is(data);
    std::string err = picojson::parse(v, is);
    if (!err.empty()) {
      std::cerr << err << std::endl;
      assert(false);
      /// @todo error
    }

    picojson::object json = v.get<picojson::object>();

    // select cmd
    std::string cmd = json.at("cmd").get<std::string>();
    if (cmd == "warp") {
      recv_process_warp(pid, json);

    } else {
      assert(false);
      /// @todo error
    }

    return;

  } catch (Error& e) {
    std::cerr << e.reason << ":" << e.mesg << std::endl;

  }
#ifdef NDEBUG
  catch (std::exception& e) {
    std::cerr << e.what() << std::endl;

  } catch (...) {
    std::cerr << "unknown exception" << std::endl;
  }
#endif

  assert(false);
  /// @todo error
}

// Create empty process.
void VMachine::create_process(const vpid_t& pid, const vtid_t& root_tid, vaddr_t proc_addr) {
  assert(procs.find(pid) == procs.end());
  procs.insert(std::make_pair(pid, std::move(Process::alloc
					     (*this, pid, root_tid, libs, lib_filter, builtin_funcs, proc_addr))));
  procs.at(pid)->setup();
}

// Delete process.
void VMachine::delete_process(const vpid_t& pid) {
  if (procs.find(pid) == procs.end()) return;
  procs.erase(pid);
  warp_dest.erase(pid);
}

// Start exiting process.
void VMachine::exit_process(const vpid_t& pid) {
  if (procs.find(pid) == procs.end()) return;
  procs.at(pid)->exit();
}

// Get process instance by process-id.
Process& VMachine::get_process(const vpid_t& pid) {
  return *procs.at(pid);
}

// Check whether process has contain in this device.
bool VMachine::have_process(const vpid_t& pid) {
  return (procs.find(pid) != procs.end());
}

// Start warp process.
void VMachine::warp_process(const vpid_t& pid,
			    const vtid_t& tid,
			    const dev_id_t& dst_device_id) {
  warp_dest[pid] = dst_device_id;
  // Change vm's status for setup to warp.
  if (tid == ALL_THREAD) {
    for (auto& it : procs.at(pid)->active_threads) {
      procs.at(pid)->setup_warpin(it, dst_device_id);
    }

  } else {
    procs.at(pid)->setup_warpin(tid, dst_device_id);
  }
}

// @inheritDoc
std::unique_ptr<VMemory::Accessor> VMachine::assign_accessor(const vpid_t& pid) {
  return std::move(vmemory.get_accessor(Convert::vpid2str(pid)));
}

// Dump and send data to warp process.
void VMachine::do_warp_process(const vpid_t& pid) {
  /// TODO:
  assert(false);
  /*
  Process& proc    = *procs.at(pid);
  VMemory::Accessor& memory = *proc.proc_memory;

  // Dump process.
  Convert convert(proc);
  Convert::Related related;
  picojson::object body;
  picojson::object dump;
  picojson::object threads;
  body.insert(std::make_pair("cmd", picojson::value(std::string("warp"))));
  body.insert(std::make_pair("pid", Convert::vpid2json(pid)));
  body.insert(std::make_pair("root_tid", Convert::vtid2json(proc.root_tid)));
  for (auto& it : proc.threads) {
    threads.insert(std::make_pair(Convert::vtid2str(it.first),
				  convert.export_thread(*it.second, related)));
  }
  body.insert(std::make_pair("threads", picojson::value(threads)));

  std::set<vaddr_t> all = proc.vmemory.get_alladdr();
  for (auto it : all) {
    // Don't export null instance.
    if (it == VADDR_NULL || it == VADDR_NON) continue;
    // Don't export build in instance.
    if (proc.builtin_addrs.find(it) != proc.builtin_addrs.end()) continue;

    dump.insert(std::make_pair(Util::vaddr2str(it), convert.export_store(it, related)));
    // Free allocated data.
    if (!VMemory::addr_is_func(it) && !VMemory::addr_is_type(it)) {
      vmemory.free(it);
    }
  }
  body.insert(std::make_pair("dump", picojson::value(dump)));

  std::string data = picojson::value(body).serialize();
  delegate.send_warp_data(pid, 1, warp_dest.at(pid), data);

  warp_dest.erase(pid);
  for (auto& it_thread : proc.threads) {
    it_thread.second->status = Thread::PASSIVE;
  }
  */
}

void VMachine::recv_process_warp(const vpid_t& pid, picojson::object& json) {
  /// TODO
  assert(false);
  /*
  Process& proc = *procs.at(pid);
  VMemory& vmemory = proc.vmemory;
  Convert convert(proc);

  // Expand transported instance data.
  picojson::object dump = json.at("dump").get<picojson::object>();
  for (auto it : dump) {
    if(!vmemory.addr_is_used(Util::str2vaddr(it.first))) {
      convert.import_store(Util::str2vaddr(it.first), it.second);
    }
  }

  // Expand thread data.
  for (auto& it : json.at("threads").get<picojson::object>()) {
    convert.import_thread(Util::hex_str2num<vtid_t>(it.first), it.second);
  }

  proc.setup_warpout(1);

  // Turn on proc.
  for (auto& it_thread : proc.threads) {
    it_thread.second->status = Thread::NORMAL;
  }
  */
}

// Regist built-in function to virtual machine.
void VMachine::regist_builtin_func(const std::string& name,
				   builtin_func_t func, int i64) {
  BuiltinFuncParam param;
  param.i64 = i64;
  builtin_funcs.insert(std::make_pair(name, std::make_pair(func, param)));
}

// Regist built-in function to virtual machine.
void VMachine::regist_builtin_func(const std::string& name,
				   builtin_func_t func, void* ptr) {
  BuiltinFuncParam param;
  param.ptr = ptr;
  builtin_funcs.insert(std::make_pair(name, std::make_pair(func, param)));
}

// Setup virtual machine.
void VMachine::setup_builtin() {
  // VMの組み込み関数をロード
  BuiltinBit::regist(*this);
#ifdef ENABLE_GLFW3
  BuiltinGlfw3::regist(*this);
#endif
  BuiltinLibc::regist(*this);
  BuiltinMemory::regist(*this);
  BuiltinOverflow::regist(*this);
  BuiltinPosix::regist(*this);
  BuiltinVaArg::regist(*this);
  BuiltinWarp::regist(*this);
}
<|endoftext|>


<commit_before>/* Copyright 2016 Kristofer Björnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** @file Diagonalizer.cpp
 *
 *  @author Kristofer Björnson
 */

#include "TBTK/Solver/Diagonalizer.h"
#include "TBTK/Streams.h"
#include "TBTK/TBTKMacros.h"

using namespace std;

namespace TBTK{
namespace Solver{

Diagonalizer::Diagonalizer() : Communicator(true){
	hamiltonian = nullptr;
	eigenValues = nullptr;
	eigenVectors = nullptr;
	basisTransformation = nullptr;

	maxIterations = 50;
	selfConsistencyCallback = nullptr;
}

Diagonalizer::~Diagonalizer(){
	if(hamiltonian != nullptr)
		delete [] hamiltonian;
	if(eigenValues != nullptr)
		delete [] eigenValues;
	if(eigenVectors != nullptr)
		delete [] eigenVectors;
	if(basisTransformation != nullptr)
		delete [] basisTransformation;
}

void Diagonalizer::run(){
	int iterationCounter = 0;
	init();

	if(getGlobalVerbose() && getVerbose())
		Streams::out << "Running Diagonalizer\n";
	while(iterationCounter++ < maxIterations){
		if(getGlobalVerbose() && getVerbose()){
			if(iterationCounter%10 == 1)
				Streams::out << " ";
			if(iterationCounter%50 == 1)
				Streams::out << "\n";
			Streams::out << "." << flush;
		}

		solve();

		if(selfConsistencyCallback){
			if(selfConsistencyCallback(*this))
				break;
			else
				update();
		}
		else{
			break;
		}
	}
	if(getGlobalVerbose() && getVerbose())
		Streams::out << "\n";
}

void Diagonalizer::init(){
	if(getGlobalVerbose() && getVerbose())
		Streams::out << "Initializing Diagonalizer\n";

	int basisSize = getModel().getBasisSize();
	if(getGlobalVerbose() && getVerbose())
		Streams::out << "\tBasis size: " << basisSize << "\n";

	if(hamiltonian != nullptr)
		delete [] hamiltonian;
	if(eigenValues != nullptr)
		delete [] eigenValues;
	if(eigenVectors != nullptr)
		delete [] eigenVectors;

	hamiltonian = new complex<double>[(basisSize*(basisSize+1))/2];
	eigenValues = new double[basisSize];
	eigenVectors = new complex<double>[basisSize*basisSize];

	setupBasisTransformation();
	update();
}

void Diagonalizer::update(){
	const Model &model = getModel();
	int basisSize = model.getBasisSize();

	for(int n = 0; n < (basisSize*(basisSize+1))/2; n++)
		hamiltonian[n] = 0.;

	for(
		HoppingAmplitudeSet::ConstIterator iterator
			= model.getHoppingAmplitudeSet().cbegin();
		iterator != model.getHoppingAmplitudeSet().cend();
		++iterator
	){
		int from = model.getHoppingAmplitudeSet().getBasisIndex(
			(*iterator).getFromIndex()
		);
		int to = model.getHoppingAmplitudeSet().getBasisIndex(
			(*iterator).getToIndex()
		);
		if(from >= to)
			hamiltonian[to + (from*(from+1))/2] += (*iterator).getAmplitude();
	}

	transformToOrthonormalBasis();
}

//Lapack function for matrix diagonalization of triangular matrix.
extern "C" void zhpev_(char *jobz,		//'E' = Eigenvalues only, 'V' = Eigenvalues and eigenvectors.
			char *uplo,		//'U' = Stored as upper triangular, 'L' = Stored as lower triangular.
			int *n,			//n*n = Matrix size
			complex<double> *ap,	//Input matrix
			double *w,		//Eigenvalues, is in accending order if info = 0
			complex<double> *z,	//Eigenvectors
			int *ldz,		//
			complex<double> *work,	//Workspace, dimension = max(1, 2*N-1)
			double *rwork,		//Workspace, dimension = max(1, 3*N-2)
			int *info);		//0 = successful, <0 = -info value was illegal, >0 = info number of off-diagonal elements failed to converge.

//Lapack function for matrix diagonalization of banded triangular matrix
extern "C" void zhbeb_(
	char *jobz,		//'E' = Eigenvalues only, 'V' = Eigenvalues and eigenvectors.
	char *uplo,		//'U' = Stored as upper triangular, 'L' = Stored as lower triangular.
	int *n,			//n*n = Matrix size
	int *kd,		//Number of (sub/super)diagonal elements
	complex<double> *ab,	//Input matrix
	int *ldab,		//Leading dimension of array ab. ldab >= kd + 1
	double *w,		//Eigenvalues, is in accending order if info = 0
	complex<double> *z,	//Eigenvectors
	int *ldz,		//
	complex<double> *work,	//Workspace, dimension = max(1, 2*N-1)
	double *rwork,		//Workspace, dimension = max(1, 3*N-2)
	int *info);		//0 = successful, <0 = -info value was illegal, >0 = info number of off-diagonal elements failed to converge.

void Diagonalizer::setupBasisTransformation(){
	//Get the OverlapAmplitudeSet.
	const OverlapAmplitudeSet &overlapAmplitudeSet
		= getModel().getOverlapAmplitudeSet();

	//Skip if the basis is assumed to be orthonormal.
	if(overlapAmplitudeSet.getAssumeOrthonormalBasis())
		return;

	//Fill the overlap matrix.
	int basisSize = getModel().getBasisSize();
	complex<double> *overlapMatrix
		= new complex<double>[(basisSize*(basisSize+1))/2];
	for(int n = 0; n < (basisSize*(basisSize+1))/2; n++)
		overlapMatrix[n] = 0;

	for(
		OverlapAmplitudeSet::ConstIterator iterator
			= overlapAmplitudeSet.cbegin();
		iterator != overlapAmplitudeSet.cend();
		++iterator
	){
		int row = getModel().getHoppingAmplitudeSet().getBasisIndex(
			(*iterator).getBraIndex()
		);
		int col = getModel().getHoppingAmplitudeSet().getBasisIndex(
			(*iterator).getKetIndex()
		);
		if(col >= row){
			overlapMatrix[row + (col*(col+1))/2]
				+= (*iterator).getAmplitude();
		}
	}

	//Diagonalize the overlap matrix.
	char jobz = 'V';
	char uplo = 'U';
	int n = basisSize;

	complex<double> *work = new complex<double>[2*n-1];
	double *rwork = new double[3*n-2];
	int info;

	double *overlapMatrixEigenValues = new double[basisSize];
	complex<double> *overlapMatrixEigenVectors
		= new complex<double>[basisSize*basisSize];

	zhpev_(
		&jobz,
		&uplo,
		&n,
		overlapMatrix,
		overlapMatrixEigenValues,
		overlapMatrixEigenVectors,
		&n,
		work,
		rwork,
		&info
	);

	delete [] work;
	delete [] rwork;

	//Setup basisTransformation storage.
	if(basisTransformation != nullptr)
		delete [] basisTransformation;
	basisTransformation = new complex<double>[basisSize*basisSize];

	//Calculate the basis transformation using canonical orthogonalization.
	//See for example section 3.4.5 in Moder Quantum Chemistry, Attila
	//Szabo and Neil S. Ostlund.
	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			basisTransformation[row + basisSize*col]
				= overlapMatrixEigenVectors[
					row + basisSize*col
				]/sqrt(
					overlapMatrixEigenValues[col]
				);
		}
	}

	delete [] overlapMatrixEigenValues;
	delete [] overlapMatrixEigenVectors;
}

void Diagonalizer::transformToOrthonormalBasis(){
	//Skip if no basis transformation has been set up (the original basis
	//is assumed to be orthonormal).
	if(basisTransformation == nullptr)
		return;

	int basisSize = getModel().getBasisSize();

	//Perform the transformation H' = U^{\dagger}HU, where U is the
	//transform to the orthonormal basis.
	Matrix<complex<double>> h(basisSize, basisSize);
	Matrix<complex<double>> U(basisSize, basisSize);
	Matrix<complex<double>> Udagger(basisSize, basisSize);
	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			if(col >= row){
				h.at(row, col)
					= hamiltonian[row + (col*(col+1))/2];
			}
			else{
				h.at(row, col) = conj(
					hamiltonian[col + (row*(row+1))/2]
				);
			}

			U.at(row, col)
				= basisTransformation[row + basisSize*col];

			Udagger.at(row, col) = conj(
				basisTransformation[col + basisSize*row]
			);
		}
	}

	Matrix<complex<double>> hp = Udagger*h*U;

	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			if(col >= row){
				hamiltonian[row + (col*(col+1))/2]
					= hp.at(row, col);
			}
		}
	}
}

void Diagonalizer::transformToOriginalBasis(){
	//Skip if no basis transformation has been set up (the original basis
	//is assumed to be orthonormal).
	if(basisTransformation == nullptr)
		return;

	int basisSize = getModel().getBasisSize();

	//Perform the transformation v = Uv', where U is the transformation to
	//the orthonormal basis and v and v' are the eigenvectors in the
	//original and orthonormal basis, respectively.
	Matrix<complex<double>> U(basisSize, basisSize);
	Matrix<complex<double>> Vp(basisSize, basisSize);
	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			U.at(row, col)
				= basisTransformation[row + basisSize*col];

			Vp.at(row, col) = eigenVectors[row + basisSize*col];
		}
	}

	Matrix<complex<double>> V = U*Vp;

	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			eigenVectors[row + basisSize*col]
				= V.at(row, col);
		}
	}
}

void Diagonalizer::solve(){
	if(true){//Currently no support for banded matrices.
		//Setup zhpev to calculate...
		char jobz = 'V';		//...eigenvalues and eigenvectors...
		char uplo = 'U';		//...for an upper triangular...
		int n = getModel().getBasisSize();	//...nxn-matrix.
		//Initialize workspaces
		complex<double> *work = new complex<double>[(2*n-1)];
		double *rwork = new double[3*n-2];
		int info;
		//Solve brop
		zhpev_(&jobz, &uplo, &n, hamiltonian, eigenValues, eigenVectors, &n, work, rwork, &info);

		TBTKAssert(
			info == 0,
			"Diagonalizer:solve()",
			"Diagonalization routine zhpev exited with INFO=" + to_string(info) + ".",
			"See LAPACK documentation for zhpev for further information."
		);

		//Delete workspaces
		delete [] work;
		delete [] rwork;
	}
/*	else{
		int kd;
		if(size_z != 1)
			kd = orbitals*size_x*size_y*size_z;
		else if(size_y != 1)
			kd = orbitals*size_x*size_y;
		else
			kd = orbitals*size_x;
		//Setup zhbev to calculate...
		char jobz = 'V';			//...eigenvalues and eigenvectors...
		char uplo = 'U';			//...for and upper triangluar...
		int n = orbitals*size_x*size_y*size_z;	//...nxn-matrix.
		int ldab = kd + 1;
		//Initialize workspaces
		complex<double> *work = new complex<double>[n];
		double *rwork = new double[3*n-2];
		int info;
		//Solve brop
		zhbev_(&jobz, &uplo, &n, &kd, hamiltonian, &ldab, eigenValues, eigenVectors, &n, work, rwork, &info);

		//delete workspaces
		delete [] work;
		delete [] rwork;
	}*/

	transformToOriginalBasis();
}

};	//End of namespace Solver
};	//End of namespace TBTK
<commit_msg>Moved creation of basis transformation from Diagonalizer::init() to Diagonalizer::update() to ensure that updates to the basis functions are taken into account in the self-consistent loop.<commit_after>/* Copyright 2016 Kristofer Björnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** @file Diagonalizer.cpp
 *
 *  @author Kristofer Björnson
 */

#include "TBTK/Solver/Diagonalizer.h"
#include "TBTK/Streams.h"
#include "TBTK/TBTKMacros.h"

using namespace std;

namespace TBTK{
namespace Solver{

Diagonalizer::Diagonalizer() : Communicator(true){
	hamiltonian = nullptr;
	eigenValues = nullptr;
	eigenVectors = nullptr;
	basisTransformation = nullptr;

	maxIterations = 50;
	selfConsistencyCallback = nullptr;
}

Diagonalizer::~Diagonalizer(){
	if(hamiltonian != nullptr)
		delete [] hamiltonian;
	if(eigenValues != nullptr)
		delete [] eigenValues;
	if(eigenVectors != nullptr)
		delete [] eigenVectors;
	if(basisTransformation != nullptr)
		delete [] basisTransformation;
}

void Diagonalizer::run(){
	int iterationCounter = 0;
	init();

	if(getGlobalVerbose() && getVerbose())
		Streams::out << "Running Diagonalizer\n";
	while(iterationCounter++ < maxIterations){
		if(getGlobalVerbose() && getVerbose()){
			if(iterationCounter%10 == 1)
				Streams::out << " ";
			if(iterationCounter%50 == 1)
				Streams::out << "\n";
			Streams::out << "." << flush;
		}

		solve();

		if(selfConsistencyCallback){
			if(selfConsistencyCallback(*this))
				break;
			else
				update();
		}
		else{
			break;
		}
	}
	if(getGlobalVerbose() && getVerbose())
		Streams::out << "\n";
}

void Diagonalizer::init(){
	if(getGlobalVerbose() && getVerbose())
		Streams::out << "Initializing Diagonalizer\n";

	int basisSize = getModel().getBasisSize();
	if(getGlobalVerbose() && getVerbose())
		Streams::out << "\tBasis size: " << basisSize << "\n";

	if(hamiltonian != nullptr)
		delete [] hamiltonian;
	if(eigenValues != nullptr)
		delete [] eigenValues;
	if(eigenVectors != nullptr)
		delete [] eigenVectors;

	hamiltonian = new complex<double>[(basisSize*(basisSize+1))/2];
	eigenValues = new double[basisSize];
	eigenVectors = new complex<double>[basisSize*basisSize];

	update();
}

void Diagonalizer::update(){
	const Model &model = getModel();
	int basisSize = model.getBasisSize();

	for(int n = 0; n < (basisSize*(basisSize+1))/2; n++)
		hamiltonian[n] = 0.;

	for(
		HoppingAmplitudeSet::ConstIterator iterator
			= model.getHoppingAmplitudeSet().cbegin();
		iterator != model.getHoppingAmplitudeSet().cend();
		++iterator
	){
		int from = model.getHoppingAmplitudeSet().getBasisIndex(
			(*iterator).getFromIndex()
		);
		int to = model.getHoppingAmplitudeSet().getBasisIndex(
			(*iterator).getToIndex()
		);
		if(from >= to)
			hamiltonian[to + (from*(from+1))/2] += (*iterator).getAmplitude();
	}

	setupBasisTransformation();
	transformToOrthonormalBasis();
}

//Lapack function for matrix diagonalization of triangular matrix.
extern "C" void zhpev_(char *jobz,		//'E' = Eigenvalues only, 'V' = Eigenvalues and eigenvectors.
			char *uplo,		//'U' = Stored as upper triangular, 'L' = Stored as lower triangular.
			int *n,			//n*n = Matrix size
			complex<double> *ap,	//Input matrix
			double *w,		//Eigenvalues, is in accending order if info = 0
			complex<double> *z,	//Eigenvectors
			int *ldz,		//
			complex<double> *work,	//Workspace, dimension = max(1, 2*N-1)
			double *rwork,		//Workspace, dimension = max(1, 3*N-2)
			int *info);		//0 = successful, <0 = -info value was illegal, >0 = info number of off-diagonal elements failed to converge.

//Lapack function for matrix diagonalization of banded triangular matrix
extern "C" void zhbeb_(
	char *jobz,		//'E' = Eigenvalues only, 'V' = Eigenvalues and eigenvectors.
	char *uplo,		//'U' = Stored as upper triangular, 'L' = Stored as lower triangular.
	int *n,			//n*n = Matrix size
	int *kd,		//Number of (sub/super)diagonal elements
	complex<double> *ab,	//Input matrix
	int *ldab,		//Leading dimension of array ab. ldab >= kd + 1
	double *w,		//Eigenvalues, is in accending order if info = 0
	complex<double> *z,	//Eigenvectors
	int *ldz,		//
	complex<double> *work,	//Workspace, dimension = max(1, 2*N-1)
	double *rwork,		//Workspace, dimension = max(1, 3*N-2)
	int *info);		//0 = successful, <0 = -info value was illegal, >0 = info number of off-diagonal elements failed to converge.

void Diagonalizer::setupBasisTransformation(){
	//Get the OverlapAmplitudeSet.
	const OverlapAmplitudeSet &overlapAmplitudeSet
		= getModel().getOverlapAmplitudeSet();

	//Skip if the basis is assumed to be orthonormal.
	if(overlapAmplitudeSet.getAssumeOrthonormalBasis())
		return;

	//Fill the overlap matrix.
	int basisSize = getModel().getBasisSize();
	complex<double> *overlapMatrix
		= new complex<double>[(basisSize*(basisSize+1))/2];
	for(int n = 0; n < (basisSize*(basisSize+1))/2; n++)
		overlapMatrix[n] = 0;

	for(
		OverlapAmplitudeSet::ConstIterator iterator
			= overlapAmplitudeSet.cbegin();
		iterator != overlapAmplitudeSet.cend();
		++iterator
	){
		int row = getModel().getHoppingAmplitudeSet().getBasisIndex(
			(*iterator).getBraIndex()
		);
		int col = getModel().getHoppingAmplitudeSet().getBasisIndex(
			(*iterator).getKetIndex()
		);
		if(col >= row){
			overlapMatrix[row + (col*(col+1))/2]
				+= (*iterator).getAmplitude();
		}
	}

	//Diagonalize the overlap matrix.
	char jobz = 'V';
	char uplo = 'U';
	int n = basisSize;

	complex<double> *work = new complex<double>[2*n-1];
	double *rwork = new double[3*n-2];
	int info;

	double *overlapMatrixEigenValues = new double[basisSize];
	complex<double> *overlapMatrixEigenVectors
		= new complex<double>[basisSize*basisSize];

	zhpev_(
		&jobz,
		&uplo,
		&n,
		overlapMatrix,
		overlapMatrixEigenValues,
		overlapMatrixEigenVectors,
		&n,
		work,
		rwork,
		&info
	);

	delete [] work;
	delete [] rwork;

	//Setup basisTransformation storage.
	if(basisTransformation != nullptr)
		delete [] basisTransformation;
	basisTransformation = new complex<double>[basisSize*basisSize];

	//Calculate the basis transformation using canonical orthogonalization.
	//See for example section 3.4.5 in Moder Quantum Chemistry, Attila
	//Szabo and Neil S. Ostlund.
	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			basisTransformation[row + basisSize*col]
				= overlapMatrixEigenVectors[
					row + basisSize*col
				]/sqrt(
					overlapMatrixEigenValues[col]
				);
		}
	}

	delete [] overlapMatrixEigenValues;
	delete [] overlapMatrixEigenVectors;
}

void Diagonalizer::transformToOrthonormalBasis(){
	//Skip if no basis transformation has been set up (the original basis
	//is assumed to be orthonormal).
	if(basisTransformation == nullptr)
		return;

	int basisSize = getModel().getBasisSize();

	//Perform the transformation H' = U^{\dagger}HU, where U is the
	//transform to the orthonormal basis.
	Matrix<complex<double>> h(basisSize, basisSize);
	Matrix<complex<double>> U(basisSize, basisSize);
	Matrix<complex<double>> Udagger(basisSize, basisSize);
	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			if(col >= row){
				h.at(row, col)
					= hamiltonian[row + (col*(col+1))/2];
			}
			else{
				h.at(row, col) = conj(
					hamiltonian[col + (row*(row+1))/2]
				);
			}

			U.at(row, col)
				= basisTransformation[row + basisSize*col];

			Udagger.at(row, col) = conj(
				basisTransformation[col + basisSize*row]
			);
		}
	}

	Matrix<complex<double>> hp = Udagger*h*U;

	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			if(col >= row){
				hamiltonian[row + (col*(col+1))/2]
					= hp.at(row, col);
			}
		}
	}
}

void Diagonalizer::transformToOriginalBasis(){
	//Skip if no basis transformation has been set up (the original basis
	//is assumed to be orthonormal).
	if(basisTransformation == nullptr)
		return;

	int basisSize = getModel().getBasisSize();

	//Perform the transformation v = Uv', where U is the transformation to
	//the orthonormal basis and v and v' are the eigenvectors in the
	//original and orthonormal basis, respectively.
	Matrix<complex<double>> U(basisSize, basisSize);
	Matrix<complex<double>> Vp(basisSize, basisSize);
	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			U.at(row, col)
				= basisTransformation[row + basisSize*col];

			Vp.at(row, col) = eigenVectors[row + basisSize*col];
		}
	}

	Matrix<complex<double>> V = U*Vp;

	for(int row = 0; row < basisSize; row++){
		for(int col = 0; col < basisSize; col++){
			eigenVectors[row + basisSize*col]
				= V.at(row, col);
		}
	}
}

void Diagonalizer::solve(){
	if(true){//Currently no support for banded matrices.
		//Setup zhpev to calculate...
		char jobz = 'V';		//...eigenvalues and eigenvectors...
		char uplo = 'U';		//...for an upper triangular...
		int n = getModel().getBasisSize();	//...nxn-matrix.
		//Initialize workspaces
		complex<double> *work = new complex<double>[(2*n-1)];
		double *rwork = new double[3*n-2];
		int info;
		//Solve brop
		zhpev_(&jobz, &uplo, &n, hamiltonian, eigenValues, eigenVectors, &n, work, rwork, &info);

		TBTKAssert(
			info == 0,
			"Diagonalizer:solve()",
			"Diagonalization routine zhpev exited with INFO=" + to_string(info) + ".",
			"See LAPACK documentation for zhpev for further information."
		);

		//Delete workspaces
		delete [] work;
		delete [] rwork;
	}
/*	else{
		int kd;
		if(size_z != 1)
			kd = orbitals*size_x*size_y*size_z;
		else if(size_y != 1)
			kd = orbitals*size_x*size_y;
		else
			kd = orbitals*size_x;
		//Setup zhbev to calculate...
		char jobz = 'V';			//...eigenvalues and eigenvectors...
		char uplo = 'U';			//...for and upper triangluar...
		int n = orbitals*size_x*size_y*size_z;	//...nxn-matrix.
		int ldab = kd + 1;
		//Initialize workspaces
		complex<double> *work = new complex<double>[n];
		double *rwork = new double[3*n-2];
		int info;
		//Solve brop
		zhbev_(&jobz, &uplo, &n, &kd, hamiltonian, &ldab, eigenValues, eigenVectors, &n, work, rwork, &info);

		//delete workspaces
		delete [] work;
		delete [] rwork;
	}*/

	transformToOriginalBasis();
}

};	//End of namespace Solver
};	//End of namespace TBTK
<|endoftext|>


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

#include "version.h"

// Name of client reported in the 'version' message. Report the same name
// for both bitcoind and bitcoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
const std::string CLIENT_NAME("POC");

// Client version number
#define CLIENT_VERSION_SUFFIX   "1.1"

// The following part of the code determines the CLIENT_BUILD variable.
// Several mechanisms are used for this:
// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
//   generated by the build environment, possibly containing the output
//   of git-describe in a macro called BUILD_DESC
// * secondly, if this is an exported version of the code, GIT_ARCHIVE will
//   be defined (automatically using the export-subst git attribute), and
//   GIT_COMMIT will contain the commit id.
// * then, three options exist for determining CLIENT_BUILD:
//   * if BUILD_DESC is defined, use that literally (output of git-describe)
//   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
//   * otherwise, use v[maj].[min].[rev].[build]-unk
// finally CLIENT_VERSION_SUFFIX is added

// First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#    include "build.h"
#endif

// git will put "#define GIT_ARCHIVE 1" on the next line inside archives.
#define GIT_ARCHIVE 1
#ifdef GIT_ARCHIVE
#    define GIT_COMMIT_ID "POC"
#    define GIT_COMMIT_DATE "$Format:%cD"
#endif

#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-g" commit

#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk"

#ifndef BUILD_DESC
#    ifdef GIT_COMMIT_ID
#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
#    else
#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
#    endif
#endif

#ifndef BUILD_DATE
#    ifdef GIT_COMMIT_DATE
#        define BUILD_DATE GIT_COMMIT_DATE
#    else
#        define BUILD_DATE __DATE__ ", " __TIME__
#    endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
<commit_msg>version 1.1<commit_after>// Copyright (c) 2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <string>

#include "version.h"

// Name of client reported in the 'version' message. Report the same name
// for both bitcoind and bitcoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
const std::string CLIENT_NAME("POC");

// Client version number
#define CLIENT_VERSION_SUFFIX   "1.1"

// The following part of the code determines the CLIENT_BUILD variable.
// Several mechanisms are used for this:
// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
//   generated by the build environment, possibly containing the output
//   of git-describe in a macro called BUILD_DESC
// * secondly, if this is an exported version of the code, GIT_ARCHIVE will
//   be defined (automatically using the export-subst git attribute), and
//   GIT_COMMIT will contain the commit id.
// * then, three options exist for determining CLIENT_BUILD:
//   * if BUILD_DESC is defined, use that literally (output of git-describe)
//   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
//   * otherwise, use v[maj].[min].[rev].[build]-unk
// finally CLIENT_VERSION_SUFFIX is added

// First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#    include "build.h"
#endif

// git will put "#define GIT_ARCHIVE 1" on the next line inside archives.
#define GIT_ARCHIVE 1
#ifdef GIT_ARCHIVE
#    define GIT_COMMIT_ID "POC"
#    define GIT_COMMIT_DATE "17 April 2014"
#endif

#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-g" commit

#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk"

#ifndef BUILD_DESC
#    ifdef GIT_COMMIT_ID
#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD, GIT_COMMIT_ID)
#    else
#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, CLIENT_VERSION_REVISION, CLIENT_VERSION_BUILD)
#    endif
#endif

#ifndef BUILD_DATE
#    ifdef GIT_COMMIT_DATE
#        define BUILD_DATE GIT_COMMIT_DATE
#    else
#        define BUILD_DATE __DATE__ ", " __TIME__
#    endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "stdafx.h"
#include "../latency-benchmark.h"
#include "../screenscraper.h"
#include "../clioptions.h"

void run_server(clioptions*);

static BOOL (APIENTRY *wglSwapIntervalEXT)(int) = 0;
static HGLRC context = NULL;
static uint8_t pattern[pattern_bytes];
static int scrolls = 0;
static int key_downs = 0;
static int esc_presses = 0;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  int64_t paint_time = get_nanoseconds();
  switch(msg) {
  case WM_DESTROY:
    PostQuitMessage(0);
    break;
  case WM_MOUSEWHEEL:
    scrolls++;
    InvalidateRect(hwnd, NULL, false);
    break;
  case WM_KEYDOWN:
    if (wParam == VK_ESCAPE) {
      esc_presses++;
    }
    key_downs++;
    InvalidateRect(hwnd, NULL, false);
    break;
  case WM_PAINT:
    PAINTSTRUCT ps;
    BeginPaint(hwnd, &ps);
    wglMakeCurrent(ps.hdc, context);
    draw_pattern_with_opengl(pattern, scrolls, key_downs, esc_presses);
    SwapBuffers(ps.hdc);
    EndPaint(hwnd, &ps);
    break;
  default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
  }
  return 0;
}

static const char *window_class_name = "window_class_name";
void message_loop(HANDLE parent_process) {
  WNDCLASS window_class;
  if (!GetClassInfo(GetModuleHandle(NULL), window_class_name, &window_class)) {
    memset(&window_class, 0, sizeof(WNDCLASS));
    window_class.hInstance = GetModuleHandle(NULL);
    window_class.lpszClassName = window_class_name;
    window_class.hbrBackground = (HBRUSH)(COLOR_WINDOWTEXT + 1);
    window_class.lpfnWndProc = WndProc;
    ATOM a = RegisterClass(&window_class);
    assert(a);
  }
  HWND native_reference_window = NULL;
  native_reference_window = CreateWindowEx(WS_EX_TOPMOST, // Top most window and No taskbar button
                                window_class_name,
                                "Web Latency Benchmark test window",
                                WS_DISABLED | WS_POPUP, // Borderless and user-inputs Disabled
                                200, 200, pattern_pixels, 1,
                                NULL, NULL, window_class.hInstance, NULL);
  assert(native_reference_window);
  PIXELFORMATDESCRIPTOR pfd;
  ZeroMemory(&pfd, sizeof(pfd));
  pfd.nSize = sizeof(pfd);
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_DEPTH_DONTCARE;
  pfd.iPixelType = PFD_TYPE_RGBA;
  pfd.cColorBits = 32;
  HDC hdc = GetDC(native_reference_window);
  int pixel_format = ChoosePixelFormat(hdc, &pfd);
  assert(pixel_format);
  if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
    debug_log("SetPixelFormat failed");
    exit(1);
  }
  context = wglCreateContext(hdc);
  assert(context);
  if (!wglMakeCurrent(hdc, context)) {
    debug_log("Failed to init OpenGL");
    exit(1);
  }
  wglSwapIntervalEXT = (BOOL (APIENTRY *)(int)) wglGetProcAddress("wglSwapIntervalEXT");
  if (wglSwapIntervalEXT == NULL) {
    debug_log("Failed to get wglSwapIntervalEXT");
    exit(1);
  }
  if (!wglSwapIntervalEXT(0)) {
    debug_log("Failed to disable vsync");
    exit(1);
  }
  ReleaseDC(native_reference_window, hdc);
  ShowWindow(native_reference_window, SW_SHOWNORMAL);
  SetWindowPos(native_reference_window, HWND_TOPMOST, 0, 0, 0, 0,
      SWP_NOMOVE | SWP_NOSIZE);
  SetForegroundWindow(native_reference_window);
  UpdateWindow(native_reference_window);

  MSG msg;
  while(1) {
    while(!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
      InvalidateRect(native_reference_window, NULL, false);
      if (parent_process && WaitForSingleObject(parent_process, 0) != WAIT_TIMEOUT) {
        debug_log("parent process died, exiting");
        exit(1);
      }
      usleep(1000);
    }
    if (msg.message == WM_QUIT)
      break;
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
}

// Override the default behavior for assertion failures to break into the
// debugger.
int __cdecl CrtDbgHook(int nReportType, char* szMsg, int* pnRet) {
  // Break into the debugger, and then report that the exception was handled.
  _CrtDbgBreak();
  return TRUE;
}

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                       _In_opt_ HINSTANCE hPrevInstance,
                       _In_ LPTSTR    lpCmdLine,
                       _In_ int       nCmdShow)
{
  UNREFERENCED_PARAMETER(hInstance);
  UNREFERENCED_PARAMETER(hPrevInstance);
  UNREFERENCED_PARAMETER(lpCmdLine);
  UNREFERENCED_PARAMETER(nCmdShow);
  debug_log("starting process");

  // Prevent error dialogs.
  _set_error_mode(_OUT_TO_STDERR);
  _CrtSetReportHook(CrtDbgHook);
  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
      SEM_NOOPENFILEERRORBOX);

  // The Visual Studio debugger starts us in the build\ subdirectory by
  // default, which will prevent us from finding the test files in the html\
  // directory. This workaround will locate the html\ directory even if it's
  // in the parent directory so we will work in the debugger out of the box.
  WIN32_FIND_DATA find_data;
  HANDLE h = FindFirstFile("html", &find_data);
  if (h == INVALID_HANDLE_VALUE) {
    h = FindFirstFile("..\\html", &find_data);
    if (h != INVALID_HANDLE_VALUE) {
      SetCurrentDirectory("..");
    }
  }
  if (h != INVALID_HANDLE_VALUE) {
    FindClose(h);
  }

  // Prevent automatic DPI scaling.
  SetProcessDPIAware();

  clioptions opts;
  parse_commandline(__argc, (const char **)__argv, &opts);

  if (opts.magic_pattern) {
    assert(opts.parent_handle);
    debug_log("opening native reference window");
    // The -p argument is the magic pattern to draw on the window, encoded as hex.
    memset(pattern, 0, sizeof(pattern));
    if (!parse_hex_magic_pattern(opts.magic_pattern, pattern)) {
      debug_log("Failed to parse pattern");
      return 1;
    }
    // The -h argument is the HANDLE of the parent process, encoded as hex.
    HANDLE parent_process = (HANDLE)_strtoui64(opts.parent_handle, NULL, 16);
    message_loop(parent_process);
    return 0;
  }

  debug_log("running server");
  HDC desktop = GetDC(NULL);
  assert(desktop);
  if (GetDeviceCaps(desktop, LOGPIXELSX) != 96) {
    MessageBox(NULL, "Unfortunately, due to browser bugs you must set the Windows DPI scaling factor to \"100%\" or \"Smaller\" (96 DPI) for this test to work. Please change it and reboot.",
                "Unsupported DPI", MB_ICONERROR | MB_OK);
    WinExec("DpiScaling.exe", SW_NORMAL);
    return 1;
  }
  ReleaseDC(NULL, desktop);
  run_server(&opts);
  return 0;
}
<commit_msg>Fix console output for Windows.<commit_after>/*
 * Copyright 2013 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "stdafx.h"
#include "../latency-benchmark.h"
#include "../screenscraper.h"
#include "../clioptions.h"

void run_server(clioptions*);

static BOOL (APIENTRY *wglSwapIntervalEXT)(int) = 0;
static HGLRC context = NULL;
static uint8_t pattern[pattern_bytes];
static int scrolls = 0;
static int key_downs = 0;
static int esc_presses = 0;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  int64_t paint_time = get_nanoseconds();
  switch(msg) {
  case WM_DESTROY:
    PostQuitMessage(0);
    break;
  case WM_MOUSEWHEEL:
    scrolls++;
    InvalidateRect(hwnd, NULL, false);
    break;
  case WM_KEYDOWN:
    if (wParam == VK_ESCAPE) {
      esc_presses++;
    }
    key_downs++;
    InvalidateRect(hwnd, NULL, false);
    break;
  case WM_PAINT:
    PAINTSTRUCT ps;
    BeginPaint(hwnd, &ps);
    wglMakeCurrent(ps.hdc, context);
    draw_pattern_with_opengl(pattern, scrolls, key_downs, esc_presses);
    SwapBuffers(ps.hdc);
    EndPaint(hwnd, &ps);
    break;
  default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
  }
  return 0;
}

static const char *window_class_name = "window_class_name";
void message_loop(HANDLE parent_process) {
  WNDCLASS window_class;
  if (!GetClassInfo(GetModuleHandle(NULL), window_class_name, &window_class)) {
    memset(&window_class, 0, sizeof(WNDCLASS));
    window_class.hInstance = GetModuleHandle(NULL);
    window_class.lpszClassName = window_class_name;
    window_class.hbrBackground = (HBRUSH)(COLOR_WINDOWTEXT + 1);
    window_class.lpfnWndProc = WndProc;
    ATOM a = RegisterClass(&window_class);
    assert(a);
  }
  HWND native_reference_window = NULL;
  native_reference_window = CreateWindowEx(WS_EX_TOPMOST, // Top most window and No taskbar button
                                window_class_name,
                                "Web Latency Benchmark test window",
                                WS_DISABLED | WS_POPUP, // Borderless and user-inputs Disabled
                                200, 200, pattern_pixels, 1,
                                NULL, NULL, window_class.hInstance, NULL);
  assert(native_reference_window);
  PIXELFORMATDESCRIPTOR pfd;
  ZeroMemory(&pfd, sizeof(pfd));
  pfd.nSize = sizeof(pfd);
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER | PFD_DEPTH_DONTCARE;
  pfd.iPixelType = PFD_TYPE_RGBA;
  pfd.cColorBits = 32;
  HDC hdc = GetDC(native_reference_window);
  int pixel_format = ChoosePixelFormat(hdc, &pfd);
  assert(pixel_format);
  if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
    debug_log("SetPixelFormat failed");
    exit(1);
  }
  context = wglCreateContext(hdc);
  assert(context);
  if (!wglMakeCurrent(hdc, context)) {
    debug_log("Failed to init OpenGL");
    exit(1);
  }
  wglSwapIntervalEXT = (BOOL (APIENTRY *)(int)) wglGetProcAddress("wglSwapIntervalEXT");
  if (wglSwapIntervalEXT == NULL) {
    debug_log("Failed to get wglSwapIntervalEXT");
    exit(1);
  }
  if (!wglSwapIntervalEXT(0)) {
    debug_log("Failed to disable vsync");
    exit(1);
  }
  ReleaseDC(native_reference_window, hdc);
  ShowWindow(native_reference_window, SW_SHOWNORMAL);
  SetWindowPos(native_reference_window, HWND_TOPMOST, 0, 0, 0, 0,
      SWP_NOMOVE | SWP_NOSIZE);
  SetForegroundWindow(native_reference_window);
  UpdateWindow(native_reference_window);

  MSG msg;
  while(1) {
    while(!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
      InvalidateRect(native_reference_window, NULL, false);
      if (parent_process && WaitForSingleObject(parent_process, 0) != WAIT_TIMEOUT) {
        debug_log("parent process died, exiting");
        exit(1);
      }
      usleep(1000);
    }
    if (msg.message == WM_QUIT)
      break;
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
}

// Override the default behavior for assertion failures to break into the
// debugger.
int __cdecl CrtDbgHook(int nReportType, char* szMsg, int* pnRet) {
  // Break into the debugger, and then report that the exception was handled.
  _CrtDbgBreak();
  return TRUE;
}

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                       _In_opt_ HINSTANCE hPrevInstance,
                       _In_ LPTSTR    lpCmdLine,
                       _In_ int       nCmdShow)
{
  UNREFERENCED_PARAMETER(hInstance);
  UNREFERENCED_PARAMETER(hPrevInstance);
  UNREFERENCED_PARAMETER(lpCmdLine);
  UNREFERENCED_PARAMETER(nCmdShow);
  debug_log("starting process");

  // Prevent error dialogs.
  _set_error_mode(_OUT_TO_STDERR);
  _CrtSetReportHook(CrtDbgHook);
  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
      SEM_NOOPENFILEERRORBOX);
  // Make stderr/stdout work from a non-console app.
  if (AttachConsole(ATTACH_PARENT_PROCESS)) {
    freopen("CONOUT$", "wb", stdout);
    freopen("CONOUT$", "wb", stderr);
  }

  // The Visual Studio debugger starts us in the build\ subdirectory by
  // default, which will prevent us from finding the test files in the html\
  // directory. This workaround will locate the html\ directory even if it's
  // in the parent directory so we will work in the debugger out of the box.
  WIN32_FIND_DATA find_data;
  HANDLE h = FindFirstFile("html", &find_data);
  if (h == INVALID_HANDLE_VALUE) {
    h = FindFirstFile("..\\html", &find_data);
    if (h != INVALID_HANDLE_VALUE) {
      SetCurrentDirectory("..");
    }
  }
  if (h != INVALID_HANDLE_VALUE) {
    FindClose(h);
  }

  // Prevent automatic DPI scaling.
  SetProcessDPIAware();

  clioptions opts;
  parse_commandline(__argc, (const char **)__argv, &opts);

  if (opts.magic_pattern) {
    assert(opts.parent_handle);
    debug_log("opening native reference window");
    // The -p argument is the magic pattern to draw on the window, encoded as hex.
    memset(pattern, 0, sizeof(pattern));
    if (!parse_hex_magic_pattern(opts.magic_pattern, pattern)) {
      debug_log("Failed to parse pattern");
      return 1;
    }
    // The -h argument is the HANDLE of the parent process, encoded as hex.
    HANDLE parent_process = (HANDLE)_strtoui64(opts.parent_handle, NULL, 16);
    message_loop(parent_process);
    return 0;
  }

  debug_log("running server");
  HDC desktop = GetDC(NULL);
  assert(desktop);
  if (GetDeviceCaps(desktop, LOGPIXELSX) != 96) {
    MessageBox(NULL, "Unfortunately, due to browser bugs you must set the Windows DPI scaling factor to \"100%\" or \"Smaller\" (96 DPI) for this test to work. Please change it and reboot.",
                "Unsupported DPI", MB_ICONERROR | MB_OK);
    WinExec("DpiScaling.exe", SW_NORMAL);
    return 1;
  }
  ReleaseDC(NULL, desktop);
  run_server(&opts);
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The paccoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <string>

#include "version.h"

// Name of client reported in the 'version' message. Report the same name
// for both paccoind and paccoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
const std::string CLIENT_NAME("paccoin");

// Client version number
#define CLIENT_VERSION_SUFFIX   "-beta"

// The following part of the code determines the CLIENT_BUILD variable.
// Several mechanisms are used for this:
// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
//   generated by the build environment, possibly containing the output
//   of git-describe in a macro called BUILD_DESC
// * secondly, if this is an exported version of the code, GIT_ARCHIVE will
//   be defined (automatically using the export-subst git attribute), and
//   GIT_COMMIT will contain the commit id.
// * then, three options exist for determining CLIENT_BUILD:
//   * if BUILD_DESC is defined, use that literally (output of git-describe)
//   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
//   * otherwise, use v[maj].[min].[rev].[build]-unk
// finally CLIENT_VERSION_SUFFIX is added

// First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#    include "build.h"
#endif

// git will put "#define GIT_ARCHIVE 1" on the next line inside archives.
#define GIT_ARCHIVE 1
#ifdef GIT_ARCHIVE
#    define GIT_COMMIT_ID "$Format:%h$"
#    define GIT_COMMIT_DATE "$Format:%cD"
#endif

#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-g" commit

#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk"

#ifndef BUILD_DESC
#    ifdef GIT_COMMIT_ID
#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(DISPLAY_VERSION_MAJOR, DISPLAY_VERSION_MINOR, DISPLAY_VERSION_REVISION, DISPLAY_VERSION_BUILD, GIT_COMMIT_ID)
#    else
#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(DISPLAY_VERSION_MAJOR, DISPLAY_VERSION_MINOR, DISPLAY_VERSION_REVISION, DISPLAY_VERSION_BUILD)
#    endif
#endif

#ifndef BUILD_DATE
#    ifdef GIT_COMMIT_DATE
#        define BUILD_DATE GIT_COMMIT_DATE
#    else
#        define BUILD_DATE __DATE__ ", " __TIME__
#    endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
<commit_msg>Update version.cpp<commit_after>// Copyright (c) 2012 The paccoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <string>

#include "version.h"

// Name of client reported in the 'version' message. Report the same name
// for both paccoind and paccoin-qt, to make it harder for attackers to
// target servers or GUI users specifically.
const std::string CLIENT_NAME("Satoshi");

// Client version number
#define CLIENT_VERSION_SUFFIX   "-beta"

// The following part of the code determines the CLIENT_BUILD variable.
// Several mechanisms are used for this:
// * first, if HAVE_BUILD_INFO is defined, include build.h, a file that is
//   generated by the build environment, possibly containing the output
//   of git-describe in a macro called BUILD_DESC
// * secondly, if this is an exported version of the code, GIT_ARCHIVE will
//   be defined (automatically using the export-subst git attribute), and
//   GIT_COMMIT will contain the commit id.
// * then, three options exist for determining CLIENT_BUILD:
//   * if BUILD_DESC is defined, use that literally (output of git-describe)
//   * if not, but GIT_COMMIT is defined, use v[maj].[min].[rev].[build]-g[commit]
//   * otherwise, use v[maj].[min].[rev].[build]-unk
// finally CLIENT_VERSION_SUFFIX is added

// First, include build.h if requested
#ifdef HAVE_BUILD_INFO
#    include "build.h"
#endif

// git will put "#define GIT_ARCHIVE 1" on the next line inside archives.
#define GIT_ARCHIVE 1
#ifdef GIT_ARCHIVE
#    define GIT_COMMIT_ID "$Format:%h$"
#    define GIT_COMMIT_DATE "$Format:%cD"
#endif

#define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-g" commit

#define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \
    "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "-unk"

#ifndef BUILD_DESC
#    ifdef GIT_COMMIT_ID
#        define BUILD_DESC BUILD_DESC_FROM_COMMIT(DISPLAY_VERSION_MAJOR, DISPLAY_VERSION_MINOR, DISPLAY_VERSION_REVISION, DISPLAY_VERSION_BUILD, GIT_COMMIT_ID)
#    else
#        define BUILD_DESC BUILD_DESC_FROM_UNKNOWN(DISPLAY_VERSION_MAJOR, DISPLAY_VERSION_MINOR, DISPLAY_VERSION_REVISION, DISPLAY_VERSION_BUILD)
#    endif
#endif

#ifndef BUILD_DATE
#    ifdef GIT_COMMIT_DATE
#        define BUILD_DATE GIT_COMMIT_DATE
#    else
#        define BUILD_DATE __DATE__ ", " __TIME__
#    endif
#endif

const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
<|endoftext|>


<commit_before>#include <nan.h>
#include <zstd.h>

static NAN_METHOD(Compress) {

  if (info.Length() < 1 || !node::Buffer::HasInstance(info[0])) {
    return Nan::ThrowError("First argument should be a buffer");
  }

  v8::Local<v8::Object> buf = info[0]->ToObject();
  char *src = node::Buffer::Data(buf);
  size_t srcSize = node::Buffer::Length(buf);

  size_t dstCapacity = ZSTD_compressBound(srcSize);
  char *dst = (char*)malloc(dstCapacity);
  if (NULL == dst) {
    return Nan::ThrowError("Too large, Out of memory!");
  }

  int compressionLevel = 1;
  if (info.Length() == 2) {
    compressionLevel = info[1]->IsUndefined() ? 0 : info[1]->NumberValue();
  }

  size_t cSize = ZSTD_compress(dst, dstCapacity, src, srcSize, compressionLevel);
  if (ZSTD_isError(cSize)) {
    return Nan::ThrowError("Compress failed!");
  }

  Nan::MaybeLocal<v8::Object> dstBuf = Nan::NewBuffer(dst, cSize);

  return info.GetReturnValue().Set(dstBuf.ToLocalChecked());
}

static NAN_METHOD(Decompress) {

  if (info.Length() < 1 || !node::Buffer::HasInstance(info[0])) {
    return Nan::ThrowError("First argument should be a buffer");
  }

  v8::Local<v8::Object> buf = info[0]->ToObject();
  char *src = node::Buffer::Data(buf);
  size_t srcSize = node::Buffer::Length(buf);

  size_t dstCapacity = ZSTD_getDecompressedSize(src, srcSize);
  if (0 == dstCapacity) {
    return Nan::ThrowError("Compressed size unknown");
  }

  char *dst = (char*)malloc(dstCapacity);
  if (NULL == dst) {
    return Nan::ThrowError("Too large, Out of memory!");
  }

  size_t dSize = ZSTD_decompress(dst, dstCapacity, src, srcSize);
  if (ZSTD_isError(dSize))  {
    return Nan::ThrowError("Decompress failed!");
  }

  Nan::MaybeLocal<v8::Object> dstBuf = Nan::NewBuffer(dst, dSize);

  return info.GetReturnValue().Set(dstBuf.ToLocalChecked());
}

static NAN_METHOD(CompressUsingCDict) {

  if (info.Length() < 2 ||
      !node::Buffer::HasInstance(info[0]) ||
      !node::Buffer::HasInstance(info[1])) {
    return Nan::ThrowError("First and second argument should be a buffer");
  }

  v8::Local<v8::Object> dictBuf = info[1]->ToObject();
  char *dict = node::Buffer::Data(dictBuf);
  size_t dictSize = node::Buffer::Length(dictBuf);

  int compressionLevel = 1;
  if (info.Length() == 3) {
    compressionLevel = info[2]->IsUndefined() ? 0 : info[2]->NumberValue();
  }

  ZSTD_CDict *cdict = ZSTD_createCDict(dict, dictSize, compressionLevel);

  v8::Local<v8::Object> inputBuf = info[0]->ToObject();
  char *src = node::Buffer::Data(inputBuf);
  size_t srcSize = node::Buffer::Length(inputBuf);

  size_t dstCapacity = ZSTD_compressBound(srcSize);
  char *dst = (char*)malloc(dstCapacity);
  if (NULL == dst) {
    return Nan::ThrowError("Too large, Out of memory!");
  }

  ZSTD_CCtx* const cctx = ZSTD_createCCtx();
  size_t const cSize = ZSTD_compress_usingCDict(cctx, dst, dstCapacity, src, srcSize, cdict);
  ZSTD_freeCCtx(cctx);
  if (ZSTD_isError(cSize)) {
    return Nan::ThrowError("Compress failed!");
  }

  Nan::MaybeLocal<v8::Object> dstBuf = Nan::NewBuffer(dst, cSize);

  return info.GetReturnValue().Set(dstBuf.ToLocalChecked());
}

static NAN_METHOD(DecompressUsingDDict) {

  if (info.Length() < 2 ||
      !node::Buffer::HasInstance(info[0]) ||
      !node::Buffer::HasInstance(info[1])) {
    return Nan::ThrowError("First and second argument should be a buffer");
  }

  v8::Local<v8::Object> dictBuf = info[1]->ToObject();
  char *dict = node::Buffer::Data(dictBuf);
  size_t dictSize = node::Buffer::Length(dictBuf);

  int compressionLevel = 1;
  if (info.Length() == 3) {
    compressionLevel = info[2]->IsUndefined() ? 0 : info[2]->NumberValue();
  }

  ZSTD_DDict *ddict = ZSTD_createDDict(dict, dictSize);

  v8::Local<v8::Object> inputBuf = info[0]->ToObject();
  char *src = node::Buffer::Data(inputBuf);
  size_t srcSize = node::Buffer::Length(inputBuf);

  size_t dstCapacity = ZSTD_getDecompressedSize(src, srcSize);
  if (0 == dstCapacity) {
    return Nan::ThrowError("Compressed size unknown");
  }

  char *dst = (char*)malloc(dstCapacity);
  if (NULL == dst) {
    return Nan::ThrowError("Too large, Out of memory!");
  }

  ZSTD_DCtx* dctx = ZSTD_createDCtx();
  size_t dSize = ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ddict);
  ZSTD_freeDCtx(dctx);
  if (ZSTD_isError(dSize))  {
    return Nan::ThrowError("Decompress failed!");
  }

  Nan::MaybeLocal<v8::Object> dstBuf = Nan::NewBuffer(dst, dSize);

  return info.GetReturnValue().Set(dstBuf.ToLocalChecked());
}

NAN_MODULE_INIT(Init) {
  NAN_EXPORT(target, Compress);
  NAN_EXPORT(target, Decompress);
  NAN_EXPORT(target, CompressUsingCDict);
  NAN_EXPORT(target, DecompressUsingDDict);
}

NODE_MODULE(node_zstd, Init)
<commit_msg>refactor<zstd_wrap>: remove unused code<commit_after>#include <nan.h>
#include <zstd.h>

static NAN_METHOD(Compress) {

  if (info.Length() < 1 || !node::Buffer::HasInstance(info[0])) {
    return Nan::ThrowError("First argument should be a buffer");
  }

  v8::Local<v8::Object> buf = info[0]->ToObject();
  char *src = node::Buffer::Data(buf);
  size_t srcSize = node::Buffer::Length(buf);

  size_t dstCapacity = ZSTD_compressBound(srcSize);
  char *dst = (char*)malloc(dstCapacity);
  if (NULL == dst) {
    return Nan::ThrowError("Too large, Out of memory!");
  }

  int compressionLevel = 1;
  if (info.Length() == 2) {
    compressionLevel = info[1]->IsUndefined() ? 0 : info[1]->NumberValue();
  }

  size_t cSize = ZSTD_compress(dst, dstCapacity, src, srcSize, compressionLevel);
  if (ZSTD_isError(cSize)) {
    return Nan::ThrowError("Compress failed!");
  }

  Nan::MaybeLocal<v8::Object> dstBuf = Nan::NewBuffer(dst, cSize);

  return info.GetReturnValue().Set(dstBuf.ToLocalChecked());
}

static NAN_METHOD(Decompress) {

  if (info.Length() < 1 || !node::Buffer::HasInstance(info[0])) {
    return Nan::ThrowError("First argument should be a buffer");
  }

  v8::Local<v8::Object> buf = info[0]->ToObject();
  char *src = node::Buffer::Data(buf);
  size_t srcSize = node::Buffer::Length(buf);

  size_t dstCapacity = ZSTD_getDecompressedSize(src, srcSize);
  if (0 == dstCapacity) {
    return Nan::ThrowError("Compressed size unknown");
  }

  char *dst = (char*)malloc(dstCapacity);
  if (NULL == dst) {
    return Nan::ThrowError("Too large, Out of memory!");
  }

  size_t dSize = ZSTD_decompress(dst, dstCapacity, src, srcSize);
  if (ZSTD_isError(dSize))  {
    return Nan::ThrowError("Decompress failed!");
  }

  Nan::MaybeLocal<v8::Object> dstBuf = Nan::NewBuffer(dst, dSize);

  return info.GetReturnValue().Set(dstBuf.ToLocalChecked());
}

static NAN_METHOD(CompressUsingCDict) {

  if (info.Length() < 2 ||
      !node::Buffer::HasInstance(info[0]) ||
      !node::Buffer::HasInstance(info[1])) {
    return Nan::ThrowError("First and second argument should be a buffer");
  }

  v8::Local<v8::Object> dictBuf = info[1]->ToObject();
  char *dict = node::Buffer::Data(dictBuf);
  size_t dictSize = node::Buffer::Length(dictBuf);

  int compressionLevel = 1;
  if (info.Length() == 3) {
    compressionLevel = info[2]->IsUndefined() ? 0 : info[2]->NumberValue();
  }

  ZSTD_CDict *cdict = ZSTD_createCDict(dict, dictSize, compressionLevel);

  v8::Local<v8::Object> inputBuf = info[0]->ToObject();
  char *src = node::Buffer::Data(inputBuf);
  size_t srcSize = node::Buffer::Length(inputBuf);

  size_t dstCapacity = ZSTD_compressBound(srcSize);
  char *dst = (char*)malloc(dstCapacity);
  if (NULL == dst) {
    return Nan::ThrowError("Too large, Out of memory!");
  }

  ZSTD_CCtx* const cctx = ZSTD_createCCtx();
  size_t const cSize = ZSTD_compress_usingCDict(cctx, dst, dstCapacity, src, srcSize, cdict);
  ZSTD_freeCCtx(cctx);
  if (ZSTD_isError(cSize)) {
    return Nan::ThrowError("Compress failed!");
  }

  Nan::MaybeLocal<v8::Object> dstBuf = Nan::NewBuffer(dst, cSize);

  return info.GetReturnValue().Set(dstBuf.ToLocalChecked());
}

static NAN_METHOD(DecompressUsingDDict) {

  if (info.Length() < 2 ||
      !node::Buffer::HasInstance(info[0]) ||
      !node::Buffer::HasInstance(info[1])) {
    return Nan::ThrowError("First and second argument should be a buffer");
  }

  v8::Local<v8::Object> dictBuf = info[1]->ToObject();
  char *dict = node::Buffer::Data(dictBuf);
  size_t dictSize = node::Buffer::Length(dictBuf);

  ZSTD_DDict *ddict = ZSTD_createDDict(dict, dictSize);

  v8::Local<v8::Object> inputBuf = info[0]->ToObject();
  char *src = node::Buffer::Data(inputBuf);
  size_t srcSize = node::Buffer::Length(inputBuf);

  size_t dstCapacity = ZSTD_getDecompressedSize(src, srcSize);
  if (0 == dstCapacity) {
    return Nan::ThrowError("Compressed size unknown");
  }

  char *dst = (char*)malloc(dstCapacity);
  if (NULL == dst) {
    return Nan::ThrowError("Too large, Out of memory!");
  }

  ZSTD_DCtx* dctx = ZSTD_createDCtx();
  size_t dSize = ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ddict);
  ZSTD_freeDCtx(dctx);
  if (ZSTD_isError(dSize))  {
    return Nan::ThrowError("Decompress failed!");
  }

  Nan::MaybeLocal<v8::Object> dstBuf = Nan::NewBuffer(dst, dSize);

  return info.GetReturnValue().Set(dstBuf.ToLocalChecked());
}

NAN_MODULE_INIT(Init) {
  NAN_EXPORT(target, Compress);
  NAN_EXPORT(target, Decompress);
  NAN_EXPORT(target, CompressUsingCDict);
  NAN_EXPORT(target, DecompressUsingDDict);
}

NODE_MODULE(node_zstd, Init)
<|endoftext|>


<commit_before>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "namespaces.h"
#include "xmlattribute.h"
#include "xmlnode.h"

#include <algorithm>
#include <string>

#include <libxml/parser.h>
#include <libxml/tree.h>

namespace libcellml {

/**
 * @brief The XmlNode::XmlNodeImpl struct.
 *
 * This struct is the private implementation struct for the XmlNode class.  Separating
 * the implementation from the definition allows for greater flexibility when
 * distributing the code.
 */
struct XmlNode::XmlNodeImpl
{
    xmlNodePtr mXmlNodePtr;
};

XmlNode::XmlNode()
    : mPimpl(new XmlNodeImpl())
{
}

XmlNode::~XmlNode()
{
    delete mPimpl;
}

void XmlNode::setXmlNode(const xmlNodePtr &node)
{
    mPimpl->mXmlNodePtr = node;
}

std::string XmlNode::namespaceUri() const
{
    if (mPimpl->mXmlNodePtr->ns == nullptr) {
        return std::string();
    }
    return std::string(reinterpret_cast<const char *>(mPimpl->mXmlNodePtr->ns->href));
}

void XmlNode::addNamespaceDefinition(const std::string &uri, const std::string &prefix)
{
    xmlNsPtr nsPtr = xmlNewNs(mPimpl->mXmlNodePtr, reinterpret_cast<const xmlChar *>(uri.c_str()), reinterpret_cast<const xmlChar *>(prefix.c_str()));
    auto last = mPimpl->mXmlNodePtr->nsDef;
    while (last != nullptr) {
        last = last->next;
    }
    last = nsPtr;
}

void XmlNode::removeNamespaceDefinition(const std::string &uri)
{
    xmlNsPtr previous = nullptr;
    xmlNsPtr next = nullptr;
    auto current = mPimpl->mXmlNodePtr->nsDef;
    while (current != nullptr) {
        next = current->next;
        xmlNsPtr namespaceToRemove = nullptr;
        if (xmlStrcmp(reinterpret_cast<const xmlChar *>(uri.c_str()), reinterpret_cast<const xmlChar *>(current->href)) == 0) {
            namespaceToRemove = current;
        } else {
            previous = current;
        }
        current = current->next;
        if (namespaceToRemove != nullptr) {
            if (previous == nullptr) {
                mPimpl->mXmlNodePtr->nsDef = next;
            } else {
                previous->next = next;
            }
            namespaceToRemove->next = nullptr;
            xmlFreeNs(namespaceToRemove);
        }
    }
}

bool XmlNode::hasNamespaceDefinition(const std::string &uri)
{
    bool has = false;
    if (mPimpl->mXmlNodePtr->nsDef != nullptr) {
        auto next = mPimpl->mXmlNodePtr->nsDef;
        while (next != nullptr && !has) {
            std::string href;
            if (next->href != nullptr) {
                href = std::string(reinterpret_cast<const char *>(next->href));
            }
            if (href == uri) {
                has = true;
            }
            next = next->next;
        }
    }
    return has;
}

XmlNamespaceMap XmlNode::definedNamespaces() const
{
    XmlNamespaceMap namespaceMap;
    if (mPimpl->mXmlNodePtr->nsDef != nullptr) {
        auto next = mPimpl->mXmlNodePtr->nsDef;
        while (next != nullptr) {
            std::string prefix;
            if (next->prefix != nullptr) {
                prefix = std::string(reinterpret_cast<const char *>(next->prefix));
            }
            std::string href;
            if (next->href != nullptr) {
                href = std::string(reinterpret_cast<const char *>(next->href));
            }
            namespaceMap[prefix] = href;
            next = next->next;
        }
    }
    return namespaceMap;
}

bool XmlNode::isElement(const char *name, const char *ns) const
{
    bool found = false;
    if ((mPimpl->mXmlNodePtr->type == XML_ELEMENT_NODE)
        && (xmlStrcmp(reinterpret_cast<const xmlChar *>(namespaceUri().c_str()), reinterpret_cast<const xmlChar *>(ns)) == 0)
        && ((name == nullptr) || (xmlStrcmp(mPimpl->mXmlNodePtr->name, reinterpret_cast<const xmlChar *>(name)) == 0))) {
        found = true;
    }
    return found;
}

bool XmlNode::isCellmlElement(const char *name) const
{
    return isElement(name, CELLML_2_0_NS);
}

bool XmlNode::isMathmlElement(const char *name) const
{
    return isElement(name, MATHML_NS);
}

bool XmlNode::isText() const
{
    return mPimpl->mXmlNodePtr->type == XML_TEXT_NODE;
}

bool XmlNode::isComment() const
{
    return mPimpl->mXmlNodePtr->type == XML_COMMENT_NODE;
}

std::string XmlNode::name() const
{
    return std::string(reinterpret_cast<const char *>(mPimpl->mXmlNodePtr->name));
}

bool XmlNode::hasAttribute(const char *attributeName) const
{
    bool found = false;
    xmlAttrPtr attribute = xmlHasProp(mPimpl->mXmlNodePtr, reinterpret_cast<const xmlChar *>(attributeName));
    if (attribute != nullptr) {
        found = true;
    }
    return found;
}

std::string XmlNode::attribute(const char *attributeName) const
{
    std::string attributeValueString;
    if (hasAttribute(attributeName)) {
        xmlChar *attributeValue = xmlGetProp(mPimpl->mXmlNodePtr, reinterpret_cast<const xmlChar *>(attributeName));
        attributeValueString = std::string(reinterpret_cast<const char *>(attributeValue));
        xmlFree(attributeValue);
    }
    return attributeValueString;
}

XmlAttributePtr XmlNode::firstAttribute() const
{
    xmlAttrPtr attribute = mPimpl->mXmlNodePtr->properties;
    XmlAttributePtr attributeHandle = nullptr;
    if (attribute != nullptr) {
        attributeHandle = std::make_shared<XmlAttribute>();
        attributeHandle->setXmlAttribute(attribute);
    }
    return attributeHandle;
}

XmlNodePtr XmlNode::firstChild() const
{
    xmlNodePtr child = mPimpl->mXmlNodePtr->children;
    XmlNodePtr childHandle = nullptr;
    while (child != nullptr) {
        childHandle = std::make_shared<XmlNode>();
        childHandle->setXmlNode(child);
        bool textNode = childHandle->isText();
        if (textNode && !childHandle->convertToStrippedString().empty()) {
            break;
        } else if (!textNode) {
            break;
        }
        child = child->next;
    }
    return childHandle;
}

XmlNodePtr XmlNode::next() const
{
    xmlNodePtr next = mPimpl->mXmlNodePtr->next;
    XmlNodePtr nextHandle = nullptr;
    if (next != nullptr) {
        nextHandle = std::make_shared<XmlNode>();
        nextHandle->setXmlNode(next);
    }
    return nextHandle;
}

XmlNodePtr XmlNode::parent() const
{
    xmlNodePtr parent = mPimpl->mXmlNodePtr->parent;
    XmlNodePtr parentHandle = nullptr;
    if (parent != nullptr) {
        parentHandle = std::make_shared<XmlNode>();
        parentHandle->setXmlNode(parent);
    }
    return parentHandle;
}

std::string XmlNode::convertToString(bool format) const
{
    std::string contentString;
    xmlBufferPtr buffer = xmlBufferCreate();
    if (format) {
        xmlKeepBlanksDefault(0);
    }
    int len = xmlNodeDump(buffer, mPimpl->mXmlNodePtr->doc, mPimpl->mXmlNodePtr, 0, format ? 1 : 0);
    if (len > 0) {
        contentString = std::string(reinterpret_cast<const char *>(buffer->content));
    }
    xmlBufferFree(buffer);
    return contentString;
}

std::string XmlNode::convertToStrippedString() const
{
    std::string contentString = convertToString();
    contentString.erase(contentString.begin(), find_if_not(contentString.begin(), contentString.end(), [](int c) { return isspace(c); }));
    contentString.erase(find_if_not(contentString.rbegin(), contentString.rend(), [](int c) { return isspace(c); }).base(), contentString.end());
    return contentString;
}

} // namespace libcellml
<commit_msg>Fix firstChild code to please clang-tidy.<commit_after>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "namespaces.h"
#include "xmlattribute.h"
#include "xmlnode.h"

#include <algorithm>
#include <string>

#include <libxml/parser.h>
#include <libxml/tree.h>

namespace libcellml {

/**
 * @brief The XmlNode::XmlNodeImpl struct.
 *
 * This struct is the private implementation struct for the XmlNode class.  Separating
 * the implementation from the definition allows for greater flexibility when
 * distributing the code.
 */
struct XmlNode::XmlNodeImpl
{
    xmlNodePtr mXmlNodePtr;
};

XmlNode::XmlNode()
    : mPimpl(new XmlNodeImpl())
{
}

XmlNode::~XmlNode()
{
    delete mPimpl;
}

void XmlNode::setXmlNode(const xmlNodePtr &node)
{
    mPimpl->mXmlNodePtr = node;
}

std::string XmlNode::namespaceUri() const
{
    if (mPimpl->mXmlNodePtr->ns == nullptr) {
        return std::string();
    }
    return std::string(reinterpret_cast<const char *>(mPimpl->mXmlNodePtr->ns->href));
}

void XmlNode::addNamespaceDefinition(const std::string &uri, const std::string &prefix)
{
    xmlNsPtr nsPtr = xmlNewNs(mPimpl->mXmlNodePtr, reinterpret_cast<const xmlChar *>(uri.c_str()), reinterpret_cast<const xmlChar *>(prefix.c_str()));
    auto last = mPimpl->mXmlNodePtr->nsDef;
    while (last != nullptr) {
        last = last->next;
    }
    last = nsPtr;
}

void XmlNode::removeNamespaceDefinition(const std::string &uri)
{
    xmlNsPtr previous = nullptr;
    xmlNsPtr next = nullptr;
    auto current = mPimpl->mXmlNodePtr->nsDef;
    while (current != nullptr) {
        next = current->next;
        xmlNsPtr namespaceToRemove = nullptr;
        if (xmlStrcmp(reinterpret_cast<const xmlChar *>(uri.c_str()), reinterpret_cast<const xmlChar *>(current->href)) == 0) {
            namespaceToRemove = current;
        } else {
            previous = current;
        }
        current = current->next;
        if (namespaceToRemove != nullptr) {
            if (previous == nullptr) {
                mPimpl->mXmlNodePtr->nsDef = next;
            } else {
                previous->next = next;
            }
            namespaceToRemove->next = nullptr;
            xmlFreeNs(namespaceToRemove);
        }
    }
}

bool XmlNode::hasNamespaceDefinition(const std::string &uri)
{
    bool has = false;
    if (mPimpl->mXmlNodePtr->nsDef != nullptr) {
        auto next = mPimpl->mXmlNodePtr->nsDef;
        while (next != nullptr && !has) {
            std::string href;
            if (next->href != nullptr) {
                href = std::string(reinterpret_cast<const char *>(next->href));
            }
            if (href == uri) {
                has = true;
            }
            next = next->next;
        }
    }
    return has;
}

XmlNamespaceMap XmlNode::definedNamespaces() const
{
    XmlNamespaceMap namespaceMap;
    if (mPimpl->mXmlNodePtr->nsDef != nullptr) {
        auto next = mPimpl->mXmlNodePtr->nsDef;
        while (next != nullptr) {
            std::string prefix;
            if (next->prefix != nullptr) {
                prefix = std::string(reinterpret_cast<const char *>(next->prefix));
            }
            std::string href;
            if (next->href != nullptr) {
                href = std::string(reinterpret_cast<const char *>(next->href));
            }
            namespaceMap[prefix] = href;
            next = next->next;
        }
    }
    return namespaceMap;
}

bool XmlNode::isElement(const char *name, const char *ns) const
{
    bool found = false;
    if ((mPimpl->mXmlNodePtr->type == XML_ELEMENT_NODE)
        && (xmlStrcmp(reinterpret_cast<const xmlChar *>(namespaceUri().c_str()), reinterpret_cast<const xmlChar *>(ns)) == 0)
        && ((name == nullptr) || (xmlStrcmp(mPimpl->mXmlNodePtr->name, reinterpret_cast<const xmlChar *>(name)) == 0))) {
        found = true;
    }
    return found;
}

bool XmlNode::isCellmlElement(const char *name) const
{
    return isElement(name, CELLML_2_0_NS);
}

bool XmlNode::isMathmlElement(const char *name) const
{
    return isElement(name, MATHML_NS);
}

bool XmlNode::isText() const
{
    return mPimpl->mXmlNodePtr->type == XML_TEXT_NODE;
}

bool XmlNode::isComment() const
{
    return mPimpl->mXmlNodePtr->type == XML_COMMENT_NODE;
}

std::string XmlNode::name() const
{
    return std::string(reinterpret_cast<const char *>(mPimpl->mXmlNodePtr->name));
}

bool XmlNode::hasAttribute(const char *attributeName) const
{
    bool found = false;
    xmlAttrPtr attribute = xmlHasProp(mPimpl->mXmlNodePtr, reinterpret_cast<const xmlChar *>(attributeName));
    if (attribute != nullptr) {
        found = true;
    }
    return found;
}

std::string XmlNode::attribute(const char *attributeName) const
{
    std::string attributeValueString;
    if (hasAttribute(attributeName)) {
        xmlChar *attributeValue = xmlGetProp(mPimpl->mXmlNodePtr, reinterpret_cast<const xmlChar *>(attributeName));
        attributeValueString = std::string(reinterpret_cast<const char *>(attributeValue));
        xmlFree(attributeValue);
    }
    return attributeValueString;
}

XmlAttributePtr XmlNode::firstAttribute() const
{
    xmlAttrPtr attribute = mPimpl->mXmlNodePtr->properties;
    XmlAttributePtr attributeHandle = nullptr;
    if (attribute != nullptr) {
        attributeHandle = std::make_shared<XmlAttribute>();
        attributeHandle->setXmlAttribute(attribute);
    }
    return attributeHandle;
}

XmlNodePtr XmlNode::firstChild() const
{
    xmlNodePtr child = mPimpl->mXmlNodePtr->children;
    XmlNodePtr childHandle = nullptr;
    bool nodeWithContentFound = false;
    while (child != nullptr && !nodeWithContentFound) {
        childHandle = std::make_shared<XmlNode>();
        childHandle->setXmlNode(child);
        bool textNode = childHandle->isText();
        if (textNode && !childHandle->convertToStrippedString().empty()) {
            nodeWithContentFound = true;
        } else if (!textNode) {
            nodeWithContentFound = true;
        } else {
            child = child->next;
        }
    }
    return childHandle;
}

XmlNodePtr XmlNode::next() const
{
    xmlNodePtr next = mPimpl->mXmlNodePtr->next;
    XmlNodePtr nextHandle = nullptr;
    if (next != nullptr) {
        nextHandle = std::make_shared<XmlNode>();
        nextHandle->setXmlNode(next);
    }
    return nextHandle;
}

XmlNodePtr XmlNode::parent() const
{
    xmlNodePtr parent = mPimpl->mXmlNodePtr->parent;
    XmlNodePtr parentHandle = nullptr;
    if (parent != nullptr) {
        parentHandle = std::make_shared<XmlNode>();
        parentHandle->setXmlNode(parent);
    }
    return parentHandle;
}

std::string XmlNode::convertToString(bool format) const
{
    std::string contentString;
    xmlBufferPtr buffer = xmlBufferCreate();
    if (format) {
        xmlKeepBlanksDefault(0);
    }
    int len = xmlNodeDump(buffer, mPimpl->mXmlNodePtr->doc, mPimpl->mXmlNodePtr, 0, format ? 1 : 0);
    if (len > 0) {
        contentString = std::string(reinterpret_cast<const char *>(buffer->content));
    }
    xmlBufferFree(buffer);
    return contentString;
}

std::string XmlNode::convertToStrippedString() const
{
    std::string contentString = convertToString();
    contentString.erase(contentString.begin(), find_if_not(contentString.begin(), contentString.end(), [](int c) { return isspace(c); }));
    contentString.erase(find_if_not(contentString.rbegin(), contentString.rend(), [](int c) { return isspace(c); }).base(), contentString.end());
    return contentString;
}

} // namespace libcellml
<|endoftext|>