<commit_before>#include "control.hpp"
#include "math.hpp"
#include "model.hpp"

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <GL/glu.h>
#include <SOIL/SOIL.h>

#include <chrono>
#include <cmath>
#include <iostream>
#include <memory>
#include <sstream>
#include <thread>

#include "omp.h"

namespace Control {

	void control::deadzone(float &x, float &y) {
		float r = sqrt(x*x + y*y), theta = atan2(y, x);
		if(r < r_dead) {
			x = y = 0;
		} else {
			x = (x/r - r_dead) / (1-r_dead);
			y = (y/r - r_dead) / (1-r_dead);
		}
	}

	bool control::init(std::atomic_bool &alive) {
		//using namespace Util;
		// Task 1: view before model (splash)
		using namespace View;
		glfwSetInputMode(viewer.win, GLFW_STICKY_KEYS, 1);
		glfwMakeContextCurrent(viewer.win);

		glGenBuffers(1, &viewer.ids[view::e_id_vbuf]);
		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, model.floats.size() * sizeof(float),
			(void*) &model.floats[0], GL_STATIC_DRAW);

		glGenBuffers(1, &viewer.ids[view::e_id_fbuf]);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
			viewer.ids[view::e_id_fbuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, model.ints.size() * sizeof(int),
			(void*) &model.ints[0], GL_STATIC_DRAW);
		viewer.nTriangles = model.ints.size()/3;
		return alive;
		//return viewer.init(alive);
	}

	bool control::poll(std::atomic_bool &alive) {
		std::ostringstream oss;
		if(alive)
			viewer.poll(alive);
		if(alive) {
			if(glfwGetKey(viewer.win, GLFW_KEY_ESCAPE) == GLFW_PRESS)
				alive = false;
			int nButtons;
			const uint8_t *buttons =
				glfwGetJoystickButtons(GLFW_JOYSTICK_1, &nButtons);
			for(int i = 0; i < nButtons; i++) {
				if(buttons[i] == GLFW_PRESS) {
					if(i == 8) alive = false;
					else if(i == 7)
						viewer.x = viewer.y = viewer.z = 0;
					else if(i == 4)
						viewer.y -= .1;
					else if(i == 5)
						viewer.y += .1;
				}
			}
			int nAxes;
			const GLfloat *axes =
				glfwGetJoystickAxes(GLFW_JOYSTICK_1, &nAxes);
			if(nAxes >= 2) {
				float x = axes[0], y = axes[1];
				deadzone(x, y);
				viewer.x -= x/20;
				viewer.z -= y/20;
			}
			if(nAxes >= 5) {
				float theta = axes[3], phi = axes[4];
				viewer.theta = theta*M_PI;
				viewer.phi = phi*M_PI;
			}
		}
		return alive;
	}

	bool control::run(std::atomic_bool &alive) {
		auto delay = 150;

		int frame = 0, dFrames = 0, fps = 0;
		auto kill = [&alive] {alive = false;};
		double t1 = glfwGetTime(), t2;
		while(true) {
			if(poll(alive))
				viewer.run(alive);
			if(delay > 1) {
				std::this_thread::sleep_for(
						std::chrono::milliseconds(delay));
			} else {
				delay = 1;
			}
			t2 = glfwGetTime() - t1;
			frame++;
			dFrames++;
			if(t2 > 1.0) {
				delay *= dFrames / t2 / 60;
				std::cout << "FPS: " << int(dFrames/t2) << std::endl;
				t1 += t2;
				dFrames = 0;
			}
			if(!alive) break;
		}
		return alive;
	}

	control::control(std::atomic_bool &alive,
			const Model::model &model, View::view &view):
		task(), model(model), viewer(view) {}
}
<commit_msg>Removed buffer generation (expected in view)<commit_after>#include "control.hpp"
#include "math.hpp"
#include "model.hpp"

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <GL/glu.h>
#include <SOIL/SOIL.h>

#include <chrono>
#include <cmath>
#include <iostream>
#include <memory>
#include <sstream>
#include <thread>

#include "omp.h"

namespace Control {

	void control::deadzone(float &x, float &y) {
		float r = sqrt(x*x + y*y), theta = atan2(y, x);
		if(r < r_dead) {
			x = y = 0;
		} else {
			x = (x/r - r_dead) / (1-r_dead);
			y = (y/r - r_dead) / (1-r_dead);
		}
	}

	bool control::init(std::atomic_bool &alive) {
		//using namespace Util;
		// Task 1: view before model (splash)
		using namespace View;
		glfwSetInputMode(viewer.win, GLFW_STICKY_KEYS, 1);
		glfwMakeContextCurrent(viewer.win);

		glBindBuffer(GL_ARRAY_BUFFER, viewer.ids[view::e_id_vbuf]);
		glBufferData(GL_ARRAY_BUFFER, model.floats.size() * sizeof(float),
			(void*) &model.floats[0], GL_STATIC_DRAW);

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
			viewer.ids[view::e_id_fbuf]);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, model.ints.size() * sizeof(int),
			(void*) &model.ints[0], GL_STATIC_DRAW);
		viewer.nTriangles = model.ints.size()/3;
		return alive;
		//return viewer.init(alive);
	}

	bool control::poll(std::atomic_bool &alive) {
		std::ostringstream oss;
		if(alive)
			viewer.poll(alive);
		if(alive) {
			if(glfwGetKey(viewer.win, GLFW_KEY_ESCAPE) == GLFW_PRESS)
				alive = false;
			int nButtons;
			const uint8_t *buttons =
				glfwGetJoystickButtons(GLFW_JOYSTICK_1, &nButtons);
			for(int i = 0; i < nButtons; i++) {
				if(buttons[i] == GLFW_PRESS) {
					if(i == 8) alive = false;
					else if(i == 7)
						viewer.x = viewer.y = viewer.z = 0;
					else if(i == 4)
						viewer.y -= .1;
					else if(i == 5)
						viewer.y += .1;
				}
			}
			int nAxes;
			const GLfloat *axes =
				glfwGetJoystickAxes(GLFW_JOYSTICK_1, &nAxes);
			if(nAxes >= 2) {
				float x = axes[0], y = axes[1];
				deadzone(x, y);
				viewer.x -= x/20;
				viewer.z -= y/20;
			}
			if(nAxes >= 5) {
				float theta = axes[3], phi = axes[4];
				viewer.theta = theta*M_PI;
				viewer.phi = phi*M_PI;
			}
		}
		return alive;
	}

	bool control::run(std::atomic_bool &alive) {
		auto delay = 150;

		int frame = 0, dFrames = 0, fps = 0;
		auto kill = [&alive] {alive = false;};
		double t1 = glfwGetTime(), t2;
		while(true) {
			if(poll(alive))
				viewer.run(alive);
			if(delay > 1) {
				std::this_thread::sleep_for(
						std::chrono::milliseconds(delay));
			} else {
				delay = 1;
			}
			t2 = glfwGetTime() - t1;
			frame++;
			dFrames++;
			if(t2 > 1.0) {
				delay *= dFrames / t2 / 60;
				std::cout << "FPS: " << int(dFrames/t2) << std::endl;
				t1 += t2;
				dFrames = 0;
			}
			if(!alive) break;
		}
		return alive;
	}

	control::control(std::atomic_bool &alive,
			const Model::model &model, View::view &view):
		task(), model(model), viewer(view) {}
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 - 2022 by Apex.AI 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.
//
// SPDX-License-Identifier: Apache-2.0
#ifndef IOX_HOOFS_MAC_PLATFORM_PTHREAD_HPP
#define IOX_HOOFS_MAC_PLATFORM_PTHREAD_HPP

#include <pthread.h>

#define PTHREAD_MUTEX_STALLED 1
#define PTHREAD_MUTEX_ROBUST 2

using iox_pthread_t = pthread_t;
using iox_pthread_attr_t = pthread_attr_t;

int iox_pthread_setname_np(iox_pthread_t, const char*);

int iox_pthread_getname_np(iox_pthread_t thread, char* name, size_t len);

int iox_pthread_create(iox_pthread_t* thread, const iox_pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);

int iox_pthread_join(iox_pthread_t thread, void** retval);

iox_pthread_t iox_pthread_self();
int pthread_mutexattr_setrobust(pthread_mutexattr_t*, int);

#endif // IOX_HOOFS_MAC_PLATFORM_PTHREAD_HPP
<commit_msg>iox-#1036 Add pthread_mutex_consistent to mac os platform<commit_after>// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 - 2022 by Apex.AI 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.
//
// SPDX-License-Identifier: Apache-2.0
#ifndef IOX_HOOFS_MAC_PLATFORM_PTHREAD_HPP
#define IOX_HOOFS_MAC_PLATFORM_PTHREAD_HPP

#include <pthread.h>

#define PTHREAD_MUTEX_STALLED 1
#define PTHREAD_MUTEX_ROBUST 2

using iox_pthread_t = pthread_t;
using iox_pthread_attr_t = pthread_attr_t;

int iox_pthread_setname_np(iox_pthread_t, const char*);

int iox_pthread_getname_np(iox_pthread_t thread, char* name, size_t len);

int iox_pthread_create(iox_pthread_t* thread, const iox_pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);

int iox_pthread_join(iox_pthread_t thread, void** retval);

iox_pthread_t iox_pthread_self();
int pthread_mutexattr_setrobust(pthread_mutexattr_t*, int);

inline int pthread_mutex_consistent(pthread_mutex_t*)
{
    return 0;
}

#endif // IOX_HOOFS_MAC_PLATFORM_PTHREAD_HPP
<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file linear_observation_model.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__MODELS_PROCESS_MODELS_LINEAR_GAUSSIAN_OBSERVATION_MODEL_HPP
#define FL__MODELS_PROCESS_MODELS_LINEAR_GAUSSIAN_OBSERVATION_MODEL_HPP

#include <fl/util/traits.hpp>
#include <fl/distribution/gaussian.hpp>

namespace fl
{

// Forward declarations
template <typename Obsrv, typename State> class LinearGaussianObservationModel;

template <typename Observation_,
          typename State_>
struct Traits<
           LinearGaussianObservationModel<Observation_, State_>>
{
    typedef State_ State;
    typedef Observation_ Observation;
    typedef Gaussian<Observation_> GaussianBase;
    typedef typename Traits<GaussianBase>::Scalar Scalar;
    typedef typename Traits<GaussianBase>::SecondMoment SecondMoment;
    typedef typename Traits<GaussianBase>::StandardVariate Noise;
    typedef Eigen::Matrix<Scalar,
                          Observation::SizeAtCompileTime,
                          State::SizeAtCompileTime> SensorMatrix;
};

/**
 * \ingroup observation_models
 */
template <typename Observation_,typename State_>
class LinearGaussianObservationModel
    : public Traits<
                 LinearGaussianObservationModel<Observation_, State_>
             >::GaussianBase
{
public:
    typedef LinearGaussianObservationModel<Observation_, State_> This;

    typedef typename Traits<This>::State State;
    typedef typename Traits<This>::Observation Observation;
    typedef typename Traits<This>::Noise Noise;
    typedef typename Traits<This>::Scalar Scalar;
    typedef typename Traits<This>::SecondMoment SecondMoment;
    typedef typename Traits<This>::SensorMatrix SensorMatrix;

    using Traits<This>::GaussianBase::mean;
    using Traits<This>::GaussianBase::covariance;
    using Traits<This>::GaussianBase::dimension;

public:
    LinearGaussianObservationModel(
            const SecondMoment& noise_covariance,
            const size_t observation_dimension = Observation::SizeAtCompileTime,
            const size_t state_dimension = State::SizeAtCompileTime):
        Traits<This>::GaussianBase(observation_dimension),
        state_dimension_(state_dimension == Eigen::Dynamic? 0 : state_dimension),
        H_(SensorMatrix::Zero(dimension(), StateDimension()))
    {
        covariance(noise_covariance);
    }

    ~LinearGaussianObservationModel() { }

    virtual void condition(const State& x)
    {
        mean(H_ * x);
    }

    virtual const SensorMatrix& H() const
    {
        return H_;
    }

    virtual void H(const SensorMatrix& sensor_matrix)
    {
        H_ = sensor_matrix;
    }

    virtual size_t StateDimension() const
    {
        return state_dimension_;
    }

protected:
    size_t state_dimension_;
    SensorMatrix H_;
};

// Forward declarations
template <typename Observation_, typename State_a_, typename State_b_>
class FactorizedLinearGaussianObservationModel;

template <typename Observation_, typename State_a_, typename State_b_>
struct Traits<FactorizedLinearGaussianObservationModel<Observation_,
                                                      State_a_,
                                                      State_b_>>
{
    typedef Observation_ Observation;
    typedef State_a_ State_a;
    typedef State_b_ State_b;
    typedef Gaussian<Observation_> GaussianBase;
    typedef typename Traits<GaussianBase>::Scalar Scalar;
    typedef typename Traits<GaussianBase>::SecondMoment SecondMoment;
    typedef typename Traits<GaussianBase>::StandardVariate Noise;
    typedef Eigen::Matrix<Scalar,
                          Observation::SizeAtCompileTime,
                          State_a::SizeAtCompileTime> SensorMatrix_a;
    typedef Eigen::Matrix<Scalar,
                          Observation::SizeAtCompileTime,
                          State_b::SizeAtCompileTime> SensorMatrix_b;
};

template <typename Observation_,typename State_a_, typename State_b_>
class FactorizedLinearGaussianObservationModel:
    public Traits<
               FactorizedLinearGaussianObservationModel<
                   Observation_, State_a_, State_b_>>::GaussianBase
{
public:
    typedef FactorizedLinearGaussianObservationModel<
                Observation_,
                State_a_,
                State_b_
            > This;

    typedef typename Traits<This>::Noise Noise;
    typedef typename Traits<This>::Scalar Scalar;
    typedef typename Traits<This>::SecondMoment SecondMoment;
    typedef typename Traits<This>::Observation Observation;
    typedef typename Traits<This>::State_a State_a;
    typedef typename Traits<This>::State_b State_b;
    typedef typename Traits<This>::SensorMatrix_a SensorMatrix_a;
    typedef typename Traits<This>::SensorMatrix_b SensorMatrix_b;

    using Traits<This>::GaussianBase::mean;
    using Traits<This>::GaussianBase::covariance;
    using Traits<This>::GaussianBase::dimension;

public:
    FactorizedLinearGaussianObservationModel(
            const SecondMoment& noise_covariance,
            const size_t observation_dimension = Observation::SizeAtCompileTime,
            const size_t state_a_dimension = State_a::SizeAtCompileTime,
            const size_t state_b_dimension = State_b::SizeAtCompileTime):
        Traits<This>::GaussianBase(observation_dimension),
        state_a_dimension_(state_a_dimension),
        state_b_dimension_(state_b_dimension),
        H_a_(SensorMatrix_a::Zero(dimension(), State_a_dimension())),
        H_b_(SensorMatrix_b::Zero(dimension(), State_b_dimension()))
    {
        covariance(noise_covariance);
    }

    ~FactorizedLinearGaussianObservationModel() { }

    virtual Observation Predict(const Noise& noise) const
    {
        return map_standard_normal(noise);
    }

    virtual void condition(const State_a& state_a,
                           const State_b& state_b,
                           size_t state_index,
                           size_t pixel_index)
    {
        mean(H_a_ * state_a + H_b_ * state_b);
    }

    virtual const SensorMatrix_a& H_a() const
    {
        return H_a_;
    }

    virtual const SensorMatrix_b& H_b() const
    {
        return H_b_;
    }

    virtual void H_a(const SensorMatrix_a& sensor_matrix_a)
    {
        H_a_ = sensor_matrix_a;
    }

    virtual void H_b(const SensorMatrix_b& sensor_matrix_b)
    {
        H_b_ = sensor_matrix_b;
    }

    virtual size_t State_a_dimension() const
    {
        return state_a_dimension_;
    }

    virtual size_t State_b_dimension() const
    {
        return state_b_dimension_;
    }

protected:
    size_t state_a_dimension_;
    size_t state_b_dimension_;
    SensorMatrix_a H_a_;
    SensorMatrix_b H_b_;
};

//template <typename Observation_,typename State_a_, typename State_b_>
//class FactorizedLinearGaussianOservationModel2;

//template <typename Observation_, typename State_a_, typename State_b_>
//struct Traits<FactorizedLinearGaussianOservationModel2<Observation_,
//                                                       State_a_,
//                                                       State_b_>>
//{
//    typedef Observation_ Observation;

//    typedef Gaussian<Observation_> GaussianBase;
//    typedef typename Traits<GaussianBase>::Scalar Scalar;
//    typedef typename Traits<GaussianBase>::SecondMoment SecondMoment;
//    typedef typename Traits<GaussianBase>::Noise Noise;

//    typedef State_a_ State_a;
//    typedef State_b_ State_b;

//    enum
//    {
//        Dim_ab = (State_a::SizeAtCompileTime == Eigen::Dynamic ||
//                  State_b::SizeAtCompileTime == Eigen::Dynamic)
//                    ? Eigen::Dynamic
//                    : State_a::SizeAtCompileTime + State_b::SizeAtCompileTime
//    };

//    typedef Eigen::Matrix<Scalar, Dim_ab, 1> State_ab;
//    typedef Eigen::Matrix<Scalar, Dim_ab, Dim_ab> SensorMatrix_ab;

//    typedef Eigen::Matrix<Scalar,
//                          Observation::SizeAtCompileTime,
//                          State_a::SizeAtCompileTime> SensorMatrix_a;
//    typedef Eigen::Matrix<Scalar,
//                          Observation::SizeAtCompileTime,
//                          State_b::SizeAtCompileTime> SensorMatrix_b;

//    typedef LinearGaussianOservationModel<Observation, State_ab> Base;
//};

//template <typename Observation_,typename State_a_, typename State_b_>
//class FactorizedLinearGaussianOservationModel2:
//        public Traits<FactorizedLinearGaussianOservationModel2<
//                    Observation_, State_a_, State_b_>>::Base
//{
//public:
//    typedef FactorizedLinearGaussianOservationModel2<Observation_, State_a_, State_b_> Traits;

//    typedef typename Traits<This>::State_a State_a;
//    typedef typename Traits<This>::State_b State_b;
//    typedef typename Traits<This>::Observation Observation;
//    typedef typename Traits<This>::Noise Noise;
//    typedef typename Traits<This>::Scalar Scalar;
//    typedef typename Traits<This>::SecondMoment SecondMoment;
//    typedef typename Traits<This>::SensorMatrix_a SensorMatrix_a;
//    typedef typename Traits<This>::SensorMatrix_b SensorMatrix_b;

//    using Traits<This>::GaussianBase::Mean;
//    using Traits<This>::GaussianBase::Covariance;
//    using Traits<This>::GaussianBase::Dimension;
//    using Traits<This>::Base::map_standard_normal;
//    using Traits<This>::Base::H;
//    using Traits<This>::Base::StateDimension;

//public:
//    FactorizedLinearGaussianOservationModel2(
//            const SecondMoment& noise_covariance,
//            const size_t observation_dimension = Observation::SizeAtCompileTime,
//            const size_t state_a_dimension = State_a::SizeAtCompileTime,
//            const size_t state_b_dimension = State_b::SizeAtCompileTime):
//        Traits<This>::GaussianBase(observation_dimension),
//        state_a_dimension_(State_a::SizeAtCompileTime),
//        state_b_dimension_(State_b::SizeAtCompileTime),
//        H_a_(SensorMatrix_a::Zero(dimension(), State_a_dimension())),
//        H_b_(SensorMatrix_b::Zero(dimension(), State_b_dimension())),
//        Traits<This>::Base(noise_covariance, )
//    {
//        covariance(noise_covariance);
//    }

//protected:
//    virtual void condition(const State_a& state_a,
//                           const State_b& state_b,
//                           size_t state_index,
//                           size_t pixel_index)
//    {
//        // delta_time_ = delta_time;

//        mean(H_a_ * state_a + H_b_ * state_b);
//    }

//    virtual const SensorMatrix_a& H_a() const
//    {
//        return H_a_;
//    }

//    virtual const SensorMatrix_b& H_b() const
//    {
//        return H_b_;
//    }

//    virtual void H_a(const SensorMatrix_a& sensor_matrix_a)
//    {
//        H_a_ = sensor_matrix_a;
//    }

//    virtual void H_b(const SensorMatrix_b& sensor_matrix_b)
//    {
//        H_b_ = sensor_matrix_b;
//    }

//    virtual size_t State_a_dimension() const
//    {
//        return state_a_dimension_;
//    }

//    virtual size_t State_b_dimension() const
//    {
//        return state_b_dimension_;
//    }

//protected:
//    size_t state_a_dimension_;
//    size_t state_b_dimension_;
//    SensorMatrix_a H_a_;
//    SensorMatrix_b H_b_;
//};

}

#endif

<commit_msg>Implemented linear model using the observation interface<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file linear_observation_model.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__MODEL__OBSERVATION__LINEAR_OBSERVATION_MODEL_HPP
#define FL__MODEL__OBSERVATION__LINEAR_OBSERVATION_MODEL_HPP

#include <fl/util/traits.hpp>
#include <fl/distribution/gaussian.hpp>
#include <fl/model/observation/observation_model_interface.hpp>

namespace fl
{

// Forward declarations
template <
    typename Observation,
    typename State
>
class LinearGaussianObservationModel;

/**
 * Linear Gaussian observation model traits. This trait definition contains all
 * types used internally within the model. Additionally, it provides the types
 * needed externally to use the linear Gaussian model.
 */
template <
    typename Observation_,
    typename State_
>
struct Traits<
           LinearGaussianObservationModel<Observation_, State_>
       >
{
    typedef State_ State;
    typedef Observation_ Observation;

    typedef Gaussian<Observation> GaussianBase;
    typedef typename Traits<GaussianBase>::Scalar Scalar;
    typedef typename Traits<GaussianBase>::SecondMoment SecondMoment;
    typedef typename Traits<GaussianBase>::StandardVariate Noise;

    typedef Eigen::Matrix<
                Scalar,
                Observation::SizeAtCompileTime,
                State::SizeAtCompileTime
            > SensorMatrix;

    typedef ObservationModelInterface<
                Observation,
                State,
                Noise
            > ObservationModelBase;
};

/**
 * \ingroup observation_models
 */
template <typename Observation,typename State>
class LinearGaussianObservationModel
    : public Traits<
                 LinearGaussianObservationModel<Observation, State>
             >::ObservationModelBase,
      public Traits<
                 LinearGaussianObservationModel<Observation, State>
             >::GaussianBase
{
public:
    typedef LinearGaussianObservationModel<Observation, State> This;

    typedef typename Traits<This>::Noise Noise;
    typedef typename Traits<This>::Scalar Scalar;
    typedef typename Traits<This>::SecondMoment SecondMoment;
    typedef typename Traits<This>::SensorMatrix SensorMatrix;

    using Traits<This>::GaussianBase::mean;
    using Traits<This>::GaussianBase::covariance;
    using Traits<This>::GaussianBase::dimension;

public:
    LinearGaussianObservationModel(
            const SecondMoment& noise_covariance,
            const size_t observation_dim = DimensionOf<Observation>(),
            const size_t state_dim = DimensionOf<State>())
        : Traits<This>::GaussianBase(observation_dim),
          state_dimension_(state_dim),
          H_(SensorMatrix::Zero(observation_dimension(),
                                state_dimension()))
    {
        covariance(noise_covariance);
    }

    ~LinearGaussianObservationModel() { }

    virtual void condition(const State& x)
    {
        mean(H_ * x);
    }

    virtual const SensorMatrix& H() const
    {
        return H_;
    }

    virtual void H(const SensorMatrix& sensor_matrix)
    {
        H_ = sensor_matrix;
    }

    virtual Observation predict_observation(const State& state,
                                            const Noise& noise,
                                            double delta_time)
    {
        condition(state);
        return Traits<This>::GaussianBase::map_standard_normal(noise);
    }

    virtual size_t observation_dimension() const
    {
        return Traits<This>::GaussianBase::dimension();
    }

    virtual size_t noise_dimension() const
    {
        return Traits<This>::GaussianBase::standard_variate_dimension();
    }

    virtual size_t state_dimension() const
    {
        return state_dimension_;
    }

protected:
    size_t state_dimension_;
    SensorMatrix H_;
};

//// Forward declarations
//template <typename Observation_, typename State_a_, typename State_b_>
//class FactorizedLinearGaussianObservationModel;

//template <typename Observation_, typename State_a_, typename State_b_>
//struct Traits<FactorizedLinearGaussianObservationModel<Observation_,
//                                                      State_a_,
//                                                      State_b_>>
//{
//    typedef Observation_ Observation;
//    typedef State_a_ State_a;
//    typedef State_b_ State_b;
//    typedef Gaussian<Observation_> GaussianBase;
//    typedef typename Traits<GaussianBase>::Scalar Scalar;
//    typedef typename Traits<GaussianBase>::SecondMoment SecondMoment;
//    typedef typename Traits<GaussianBase>::StandardVariate Noise;
//    typedef Eigen::Matrix<Scalar,
//                          Observation::SizeAtCompileTime,
//                          State_a::SizeAtCompileTime> SensorMatrix_a;
//    typedef Eigen::Matrix<Scalar,
//                          Observation::SizeAtCompileTime,
//                          State_b::SizeAtCompileTime> SensorMatrix_b;
//};

//template <typename Observation_,typename State_a_, typename State_b_>
//class FactorizedLinearGaussianObservationModel:
//    public Traits<
//               FactorizedLinearGaussianObservationModel<
//                   Observation_, State_a_, State_b_>>::GaussianBase
//{
//public:
//    typedef FactorizedLinearGaussianObservationModel<
//                Observation_,
//                State_a_,
//                State_b_
//            > This;

//    typedef typename Traits<This>::Noise Noise;
//    typedef typename Traits<This>::Scalar Scalar;
//    typedef typename Traits<This>::SecondMoment SecondMoment;
//    typedef typename Traits<This>::Observation Observation;
//    typedef typename Traits<This>::State_a State_a;
//    typedef typename Traits<This>::State_b State_b;
//    typedef typename Traits<This>::SensorMatrix_a SensorMatrix_a;
//    typedef typename Traits<This>::SensorMatrix_b SensorMatrix_b;

//    using Traits<This>::GaussianBase::mean;
//    using Traits<This>::GaussianBase::covariance;
//    using Traits<This>::GaussianBase::dimension;

//public:
//    FactorizedLinearGaussianObservationModel(
//            const SecondMoment& noise_covariance,
//            const size_t observation_dimension = Observation::SizeAtCompileTime,
//            const size_t state_a_dimension = State_a::SizeAtCompileTime,
//            const size_t state_b_dimension = State_b::SizeAtCompileTime):
//        Traits<This>::GaussianBase(observation_dimension),
//        state_a_dimension_(state_a_dimension),
//        state_b_dimension_(state_b_dimension),
//        H_a_(SensorMatrix_a::Zero(dimension(), State_a_dimension())),
//        H_b_(SensorMatrix_b::Zero(dimension(), State_b_dimension()))
//    {
//        covariance(noise_covariance);
//    }

//    ~FactorizedLinearGaussianObservationModel() { }

//    virtual Observation Predict(const Noise& noise) const
//    {
//        return map_standard_normal(noise);
//    }

//    virtual void condition(const State_a& state_a,
//                           const State_b& state_b,
//                           size_t state_index,
//                           size_t pixel_index)
//    {
//        mean(H_a_ * state_a + H_b_ * state_b);
//    }

//    virtual const SensorMatrix_a& H_a() const
//    {
//        return H_a_;
//    }

//    virtual const SensorMatrix_b& H_b() const
//    {
//        return H_b_;
//    }

//    virtual void H_a(const SensorMatrix_a& sensor_matrix_a)
//    {
//        H_a_ = sensor_matrix_a;
//    }

//    virtual void H_b(const SensorMatrix_b& sensor_matrix_b)
//    {
//        H_b_ = sensor_matrix_b;
//    }

//    virtual size_t State_a_dimension() const
//    {
//        return state_a_dimension_;
//    }

//    virtual size_t State_b_dimension() const
//    {
//        return state_b_dimension_;
//    }

//protected:
//    size_t state_a_dimension_;
//    size_t state_b_dimension_;
//    SensorMatrix_a H_a_;
//    SensorMatrix_b H_b_;
//};

//template <typename Observation_,typename State_a_, typename State_b_>
//class FactorizedLinearGaussianOservationModel2;

//template <typename Observation_, typename State_a_, typename State_b_>
//struct Traits<FactorizedLinearGaussianOservationModel2<Observation_,
//                                                       State_a_,
//                                                       State_b_>>
//{
//    typedef Observation_ Observation;

//    typedef Gaussian<Observation_> GaussianBase;
//    typedef typename Traits<GaussianBase>::Scalar Scalar;
//    typedef typename Traits<GaussianBase>::SecondMoment SecondMoment;
//    typedef typename Traits<GaussianBase>::Noise Noise;

//    typedef State_a_ State_a;
//    typedef State_b_ State_b;

//    enum
//    {
//        Dim_ab = (State_a::SizeAtCompileTime == Eigen::Dynamic ||
//                  State_b::SizeAtCompileTime == Eigen::Dynamic)
//                    ? Eigen::Dynamic
//                    : State_a::SizeAtCompileTime + State_b::SizeAtCompileTime
//    };

//    typedef Eigen::Matrix<Scalar, Dim_ab, 1> State_ab;
//    typedef Eigen::Matrix<Scalar, Dim_ab, Dim_ab> SensorMatrix_ab;

//    typedef Eigen::Matrix<Scalar,
//                          Observation::SizeAtCompileTime,
//                          State_a::SizeAtCompileTime> SensorMatrix_a;
//    typedef Eigen::Matrix<Scalar,
//                          Observation::SizeAtCompileTime,
//                          State_b::SizeAtCompileTime> SensorMatrix_b;

//    typedef LinearGaussianOservationModel<Observation, State_ab> Base;
//};

//template <typename Observation_,typename State_a_, typename State_b_>
//class FactorizedLinearGaussianOservationModel2:
//        public Traits<FactorizedLinearGaussianOservationModel2<
//                    Observation_, State_a_, State_b_>>::Base
//{
//public:
//    typedef FactorizedLinearGaussianOservationModel2<Observation_, State_a_, State_b_> Traits;

//    typedef typename Traits<This>::State_a State_a;
//    typedef typename Traits<This>::State_b State_b;
//    typedef typename Traits<This>::Observation Observation;
//    typedef typename Traits<This>::Noise Noise;
//    typedef typename Traits<This>::Scalar Scalar;
//    typedef typename Traits<This>::SecondMoment SecondMoment;
//    typedef typename Traits<This>::SensorMatrix_a SensorMatrix_a;
//    typedef typename Traits<This>::SensorMatrix_b SensorMatrix_b;

//    using Traits<This>::GaussianBase::Mean;
//    using Traits<This>::GaussianBase::Covariance;
//    using Traits<This>::GaussianBase::Dimension;
//    using Traits<This>::Base::map_standard_normal;
//    using Traits<This>::Base::H;
//    using Traits<This>::Base::StateDimension;

//public:
//    FactorizedLinearGaussianOservationModel2(
//            const SecondMoment& noise_covariance,
//            const size_t observation_dimension = Observation::SizeAtCompileTime,
//            const size_t state_a_dimension = State_a::SizeAtCompileTime,
//            const size_t state_b_dimension = State_b::SizeAtCompileTime):
//        Traits<This>::GaussianBase(observation_dimension),
//        state_a_dimension_(State_a::SizeAtCompileTime),
//        state_b_dimension_(State_b::SizeAtCompileTime),
//        H_a_(SensorMatrix_a::Zero(dimension(), State_a_dimension())),
//        H_b_(SensorMatrix_b::Zero(dimension(), State_b_dimension())),
//        Traits<This>::Base(noise_covariance, )
//    {
//        covariance(noise_covariance);
//    }

//protected:
//    virtual void condition(const State_a& state_a,
//                           const State_b& state_b,
//                           size_t state_index,
//                           size_t pixel_index)
//    {
//        // delta_time_ = delta_time;

//        mean(H_a_ * state_a + H_b_ * state_b);
//    }

//    virtual const SensorMatrix_a& H_a() const
//    {
//        return H_a_;
//    }

//    virtual const SensorMatrix_b& H_b() const
//    {
//        return H_b_;
//    }

//    virtual void H_a(const SensorMatrix_a& sensor_matrix_a)
//    {
//        H_a_ = sensor_matrix_a;
//    }

//    virtual void H_b(const SensorMatrix_b& sensor_matrix_b)
//    {
//        H_b_ = sensor_matrix_b;
//    }

//    virtual size_t State_a_dimension() const
//    {
//        return state_a_dimension_;
//    }

//    virtual size_t State_b_dimension() const
//    {
//        return state_b_dimension_;
//    }

//protected:
//    size_t state_a_dimension_;
//    size_t state_b_dimension_;
//    SensorMatrix_a H_a_;
//    SensorMatrix_b H_b_;
//};

}

#endif

<|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "nearest_neighbor_recommender.hpp"

#include <string>
#include <utility>
#include <vector>
#include "jubatus/util/data/serialization.h"
#include "../common/exception.hpp"

namespace jubatus {
namespace core {
namespace recommender {

nearest_neighbor_recommender::nearest_neighbor_recommender(
    jubatus::util::lang::shared_ptr<nearest_neighbor::nearest_neighbor_base>
    nearest_neighbor_engine)
    : nearest_neighbor_engine_(nearest_neighbor_engine) {
}

void nearest_neighbor_recommender::similar_row(
    const common::sfv_t& query,
    std::vector<std::pair<std::string, float> >& ids,
    size_t ret_num) const {
  nearest_neighbor_engine_->similar_row(query, ids, ret_num);
}

void nearest_neighbor_recommender::neighbor_row(
    const common::sfv_t& query,
    std::vector<std::pair<std::string, float> >& ids,
    size_t ret_num) const {
  nearest_neighbor_engine_->neighbor_row(query, ids, ret_num);
}

void nearest_neighbor_recommender::clear() {
  orig_.clear();
  nearest_neighbor_engine_->clear();
}

void nearest_neighbor_recommender::clear_row(const std::string& id) {
  throw JUBATUS_EXCEPTION(common::unsupported_method(__func__));
}

void nearest_neighbor_recommender::update_row(
    const std::string& id,
    const common::sfv_t& diff) {
  orig_.set_row(id, diff);
  common::sfv_t row;
  orig_.get_row(id, row);
  nearest_neighbor_engine_->set_row(id, row);
}

void nearest_neighbor_recommender::get_all_row_ids(
    std::vector<std::string>& ids) const {
  nearest_neighbor_engine_->get_all_row_ids(ids);
}

std::string nearest_neighbor_recommender::type() const {
  return "nearest_neighbor_recommender:" + nearest_neighbor_engine_->type();
}

framework::mixable* nearest_neighbor_recommender::get_mixable() const {
  // TODO: implement
  //return nearest_neighbor_engine_->get_mixable();
  return 0;
}

void nearest_neighbor_recommender::pack(framework::packer& packer) const {
  // TODO: implement
}

void nearest_neighbor_recommender::unpack(msgpack::object o) {
  // TODO: implement
}

}  // namespace recommender
}  // namespace core
}  // namespace jubatus
<commit_msg>Implement pack/unpack/get_mixable methods in nearest_neighbor_recommender<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2013 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "nearest_neighbor_recommender.hpp"

#include <string>
#include <utility>
#include <vector>
#include "jubatus/util/data/serialization.h"
#include "../common/exception.hpp"

namespace jubatus {
namespace core {
namespace recommender {

nearest_neighbor_recommender::nearest_neighbor_recommender(
    jubatus::util::lang::shared_ptr<nearest_neighbor::nearest_neighbor_base>
    nearest_neighbor_engine)
    : nearest_neighbor_engine_(nearest_neighbor_engine) {
}

void nearest_neighbor_recommender::similar_row(
    const common::sfv_t& query,
    std::vector<std::pair<std::string, float> >& ids,
    size_t ret_num) const {
  nearest_neighbor_engine_->similar_row(query, ids, ret_num);
}

void nearest_neighbor_recommender::neighbor_row(
    const common::sfv_t& query,
    std::vector<std::pair<std::string, float> >& ids,
    size_t ret_num) const {
  nearest_neighbor_engine_->neighbor_row(query, ids, ret_num);
}

void nearest_neighbor_recommender::clear() {
  orig_.clear();
  nearest_neighbor_engine_->clear();
}

void nearest_neighbor_recommender::clear_row(const std::string& id) {
  throw JUBATUS_EXCEPTION(common::unsupported_method(__func__));
}

void nearest_neighbor_recommender::update_row(
    const std::string& id,
    const common::sfv_t& diff) {
  orig_.set_row(id, diff);
  common::sfv_t row;
  orig_.get_row(id, row);
  nearest_neighbor_engine_->set_row(id, row);
}

void nearest_neighbor_recommender::get_all_row_ids(
    std::vector<std::string>& ids) const {
  nearest_neighbor_engine_->get_all_row_ids(ids);
}

std::string nearest_neighbor_recommender::type() const {
  return "nearest_neighbor_recommender:" + nearest_neighbor_engine_->type();
}

framework::mixable* nearest_neighbor_recommender::get_mixable() const {
  return nearest_neighbor_engine_->get_mixable();
}

void nearest_neighbor_recommender::pack(framework::packer& packer) const {
  packer.pack_array(2);
  orig_.pack(packer);
  nearest_neighbor_engine_->pack(packer);
}

void nearest_neighbor_recommender::unpack(msgpack::object o) {
  if (o.type != msgpack::type::ARRAY || o.via.array.size != 2) {
    throw msgpack::type_error();
  }
  orig_.unpack(o.via.array.ptr[0]);
  nearest_neighbor_engine_->unpack(o.via.array.ptr[1]);
}

}  // namespace recommender
}  // namespace core
}  // namespace jubatus
<|endoftext|>


<commit_before>#include <cstdlib>
#include <sqlite3.h>
#include <nan.h>
#include "macros.h"
#include "database.h"

namespace NODE_SQLITE3_PLUS_DATABASE {
    int WRITE_MODE = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
    int READ_MODE = SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX;
    v8::PropertyAttribute FROZEN = static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly);
    bool CONSTRUCTING_STATEMENT = false;
    enum STATE {CONNECTING, READY, DONE};

    class Database : public Nan::ObjectWrap {
        public:
            Database(char*);
            ~Database();
            static NAN_MODULE_INIT(Init);

            friend class OpenWorker;
            friend class CloseWorker;

        private:
            static CONSTRUCTOR(constructor);
            static NAN_METHOD(New);
            static NAN_GETTER(OpenGetter);
            static NAN_METHOD(Close);
            static NAN_METHOD(Prepare);

            char* filename;
            sqlite3* readHandle;
            sqlite3* writeHandle;
            STATE state;
    };

    class Statement : public Nan::ObjectWrap {
        public:
            Statement();
            ~Statement();
            static void Init();

            friend class Database;

        private:
            static CONSTRUCTOR(constructor);
            static NAN_METHOD(New);

            sqlite3_stmt* handle;
            bool dead;
    };

    class OpenWorker : public Nan::AsyncWorker {
        public:
            OpenWorker(Database*);
            ~OpenWorker();
            void Execute();
            void HandleOKCallback();
            void HandleErrorCallback();
        private:
            Database* db;
    };

    class CloseWorker : public Nan::AsyncWorker {
        public:
            CloseWorker(Database*, bool);
            ~CloseWorker();
            void Execute();
            void HandleOKCallback();
            void HandleErrorCallback();
        private:
            Database* db;
            bool doNothing;
    };

    Database::Database(char* filename) : Nan::ObjectWrap(),
        filename(filename),
        readHandle(NULL),
        writeHandle(NULL),
        state(CONNECTING) {}
    Database::~Database() {
        state = DONE;
        sqlite3_close(readHandle);
        sqlite3_close(writeHandle);
        readHandle = NULL;
        writeHandle = NULL;
        free(filename);
        filename = NULL;
    }
    NAN_MODULE_INIT(Database::Init) {
        Nan::HandleScope scope;

        v8::Local<v8::FunctionTemplate> t = Nan::New<v8::FunctionTemplate>(New);
        t->InstanceTemplate()->SetInternalFieldCount(1);
        t->SetClassName(Nan::New("Database").ToLocalChecked());

        Nan::SetPrototypeMethod(t, "disconnect", Close);
        Nan::SetPrototypeMethod(t, "prepare", Prepare);
        Nan::SetAccessor(t->InstanceTemplate(), Nan::New("connected").ToLocalChecked(), OpenGetter);

        constructor.Reset(Nan::GetFunction(t).ToLocalChecked());
        Nan::Set(target, Nan::New("Database").ToLocalChecked(),
            Nan::GetFunction(t).ToLocalChecked());
    }
    CONSTRUCTOR(Database::constructor);
    NAN_METHOD(Database::New) {
        REQUIRE_ARGUMENTS(1);
        if (!info.IsConstructCall()) {
            v8::Local<v8::Value> args[1] = {info[0]};
            v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
            info.GetReturnValue().Set(cons->NewInstance(1, args));
        } else {
            REQUIRE_ARGUMENT_STRING(0, filename);

            Database* db = new Database(RAW_STRING(filename));
            db->Wrap(info.This());

            db->Ref();
            AsyncQueueWorker(new OpenWorker(db));

            info.GetReturnValue().Set(info.This());
        }
    }
    NAN_GETTER(Database::OpenGetter) {
        Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
        info.GetReturnValue().Set(db->state == READY);
    }
    NAN_METHOD(Database::Close) {
        Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());

        if (db->state != DONE) {
            db->Ref();
            // --
            // This should wait in queue for all pending transactions to finish. (writes AND reads).
            // This should be invoked right away if there are no pending transactions (which will)
            // always be the case if it's still connecting. db->state == DONE simply means that it
            // was READY when Close was invoked, and therefore should be treated equally, as shown
            // below.
            AsyncQueueWorker(new CloseWorker(db, db->state == CONNECTING));
            // --
            db->state = DONE;
        }

        info.GetReturnValue().Set(info.This());
    }
    NAN_METHOD(Database::Prepare) {
        REQUIRE_ARGUMENT_STRING(0, source);
        v8::Local<v8::Function> cons = Nan::New<v8::Function>(Statement::constructor);

        CONSTRUCTING_STATEMENT = true;
        v8::Local<v8::Object> statement = cons->NewInstance(0, NULL);
        CONSTRUCTING_STATEMENT = false;

        Nan::ForceSet(statement, Nan::New("database").ToLocalChecked(), info.This(), FROZEN);
        Nan::ForceSet(statement, Nan::New("source").ToLocalChecked(), source, FROZEN);

        info.GetReturnValue().Set(statement);
    }

    Statement::Statement() : Nan::ObjectWrap(),
        handle(NULL),
        dead(false) {}
    Statement::~Statement() {
        dead = true;
        sqlite3_finalize(handle);
        handle = NULL;
    }
    void Statement::Init() {
        Nan::HandleScope scope;

        v8::Local<v8::FunctionTemplate> t = Nan::New<v8::FunctionTemplate>(New);
        t->InstanceTemplate()->SetInternalFieldCount(1);
        t->SetClassName(Nan::New("Statement").ToLocalChecked());

        constructor.Reset(Nan::GetFunction(t).ToLocalChecked());
    }
    CONSTRUCTOR(Statement::constructor);
    NAN_METHOD(Statement::New) {
        if (!CONSTRUCTING_STATEMENT) {
            return Nan::ThrowSyntaxError("Statements can only be constructed by the db.prepare() method.");
        }
        Statement* stmt = new Statement();
        stmt->Wrap(info.This());
        info.GetReturnValue().Set(info.This());
    }

    OpenWorker::OpenWorker(Database* db)
        : Nan::AsyncWorker(NULL), db(db) {}
    OpenWorker::~OpenWorker() {}
    void OpenWorker::Execute() {
        int status;

        status = sqlite3_open_v2(db->filename, &db->writeHandle, WRITE_MODE, NULL);
        if (status != SQLITE_OK) {
            SetErrorMessage(sqlite3_errmsg(db->writeHandle));
            sqlite3_close(db->writeHandle);
            db->writeHandle = NULL;
            return;
        }

        status = sqlite3_open_v2(db->filename, &db->readHandle, READ_MODE, NULL);
        if (status != SQLITE_OK) {
            SetErrorMessage(sqlite3_errmsg(db->readHandle));
            sqlite3_close(db->writeHandle);
            sqlite3_close(db->readHandle);
            db->writeHandle = NULL;
            db->readHandle = NULL;
            return;
        }

        sqlite3_busy_timeout(db->writeHandle, 30000);
        sqlite3_busy_timeout(db->readHandle, 30000);
    }
    void OpenWorker::HandleOKCallback() {
        Nan::HandleScope scope;
        if (db->state == DONE) {
            sqlite3_close(db->writeHandle);
            sqlite3_close(db->readHandle);
            db->writeHandle = NULL;
            db->readHandle = NULL;
        } else {
            db->state = READY;
            v8::Local<v8::Value> args[1] = {Nan::New("connect").ToLocalChecked()};
            EMIT_EVENT(db->handle(), 1, args);
        }
        db->Unref();
    }
    void OpenWorker::HandleErrorCallback() {
        Nan::HandleScope scope;
        if (db->state != DONE) {
            db->state = DONE;
            v8::Local<v8::Value> args[2] = {
                Nan::New("disconnect").ToLocalChecked(),
                v8::Exception::Error(Nan::New<v8::String>(ErrorMessage()).ToLocalChecked())
            };
            EMIT_EVENT(db->handle(), 2, args);
        }
        db->Unref();
    }

    CloseWorker::CloseWorker(Database* db, bool doNothing)
        : Nan::AsyncWorker(NULL), db(db), doNothing(doNothing) {}
    CloseWorker::~CloseWorker() {}
    void CloseWorker::Execute() {
        if (!doNothing) {
            int status1 = sqlite3_close(db->writeHandle);
            int status2 = sqlite3_close(db->readHandle);
            db->writeHandle = NULL;
            db->readHandle = NULL;
            if (status1 != SQLITE_OK) {
                SetErrorMessage(sqlite3_errmsg(db->writeHandle));
            } else if (status2 != SQLITE_OK) {
                SetErrorMessage(sqlite3_errmsg(db->readHandle));
            }
        }
    }
    void CloseWorker::HandleOKCallback() {
        Nan::HandleScope scope;
        v8::Local<v8::Value> args[2] = {Nan::New("disconnect").ToLocalChecked(), Nan::Null()};
        EMIT_EVENT(db->handle(), 2, args);
        db->Unref();
    }
    void CloseWorker::HandleErrorCallback() {
        Nan::HandleScope scope;
        v8::Local<v8::Value> args[2] = {
            Nan::New("disconnect").ToLocalChecked(),
            v8::Exception::Error(Nan::New<v8::String>(ErrorMessage()).ToLocalChecked())
        };
        EMIT_EVENT(db->handle(), 2, args);
        db->Unref();
    }

    NAN_MODULE_INIT(InitDatabase) {
        Database::Init(target);
        Statement::Init();
    }
}
<commit_msg>minor change<commit_after>#include <cstdlib>
#include <sqlite3.h>
#include <nan.h>
#include "macros.h"
#include "database.h"

namespace NODE_SQLITE3_PLUS_DATABASE {
    int WRITE_MODE = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
    int READ_MODE = SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX;
    v8::PropertyAttribute FROZEN = static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly);
    enum STATE {CONNECTING, READY, DONE};
    bool CONSTRUCTING_STATEMENT = false;

    class Database : public Nan::ObjectWrap {
        public:
            Database(char*);
            ~Database();
            static NAN_MODULE_INIT(Init);

            friend class OpenWorker;
            friend class CloseWorker;

        private:
            static CONSTRUCTOR(constructor);
            static NAN_METHOD(New);
            static NAN_GETTER(OpenGetter);
            static NAN_METHOD(Close);
            static NAN_METHOD(Prepare);

            char* filename;
            sqlite3* readHandle;
            sqlite3* writeHandle;
            STATE state;
    };

    class Statement : public Nan::ObjectWrap {
        public:
            Statement();
            ~Statement();
            static void Init();

            friend class Database;

        private:
            static CONSTRUCTOR(constructor);
            static NAN_METHOD(New);

            sqlite3_stmt* handle;
            bool dead;
    };

    class OpenWorker : public Nan::AsyncWorker {
        public:
            OpenWorker(Database*);
            ~OpenWorker();
            void Execute();
            void HandleOKCallback();
            void HandleErrorCallback();
        private:
            Database* db;
    };

    class CloseWorker : public Nan::AsyncWorker {
        public:
            CloseWorker(Database*, bool);
            ~CloseWorker();
            void Execute();
            void HandleOKCallback();
            void HandleErrorCallback();
        private:
            Database* db;
            bool doNothing;
    };

    Database::Database(char* filename) : Nan::ObjectWrap(),
        filename(filename),
        readHandle(NULL),
        writeHandle(NULL),
        state(CONNECTING) {}
    Database::~Database() {
        state = DONE;
        sqlite3_close(readHandle);
        sqlite3_close(writeHandle);
        readHandle = NULL;
        writeHandle = NULL;
        free(filename);
        filename = NULL;
    }
    NAN_MODULE_INIT(Database::Init) {
        Nan::HandleScope scope;

        v8::Local<v8::FunctionTemplate> t = Nan::New<v8::FunctionTemplate>(New);
        t->InstanceTemplate()->SetInternalFieldCount(1);
        t->SetClassName(Nan::New("Database").ToLocalChecked());

        Nan::SetPrototypeMethod(t, "disconnect", Close);
        Nan::SetPrototypeMethod(t, "prepare", Prepare);
        Nan::SetAccessor(t->InstanceTemplate(), Nan::New("connected").ToLocalChecked(), OpenGetter);

        constructor.Reset(Nan::GetFunction(t).ToLocalChecked());
        Nan::Set(target, Nan::New("Database").ToLocalChecked(),
            Nan::GetFunction(t).ToLocalChecked());
    }
    CONSTRUCTOR(Database::constructor);
    NAN_METHOD(Database::New) {
        REQUIRE_ARGUMENTS(1);
        if (!info.IsConstructCall()) {
            v8::Local<v8::Value> args[1] = {info[0]};
            v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
            info.GetReturnValue().Set(cons->NewInstance(1, args));
        } else {
            REQUIRE_ARGUMENT_STRING(0, filename);

            Database* db = new Database(RAW_STRING(filename));
            db->Wrap(info.This());

            db->Ref();
            AsyncQueueWorker(new OpenWorker(db));

            info.GetReturnValue().Set(info.This());
        }
    }
    NAN_GETTER(Database::OpenGetter) {
        Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
        info.GetReturnValue().Set(db->state == READY);
    }
    NAN_METHOD(Database::Close) {
        Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());

        if (db->state != DONE) {
            db->Ref();
            // --
            // This should wait in queue for all pending transactions to finish. (writes AND reads).
            // This should be invoked right away if there are no pending transactions (which will)
            // always be the case if it's still connecting. db->state == DONE simply means that it
            // was READY when Close was invoked, and therefore should be treated equally, as shown
            // below.
            AsyncQueueWorker(new CloseWorker(db, db->state == CONNECTING));
            // --
            db->state = DONE;
        }

        info.GetReturnValue().Set(info.This());
    }
    NAN_METHOD(Database::Prepare) {
        REQUIRE_ARGUMENT_STRING(0, source);
        v8::Local<v8::Function> cons = Nan::New<v8::Function>(Statement::constructor);

        CONSTRUCTING_STATEMENT = true;
        v8::Local<v8::Object> statement = cons->NewInstance(0, NULL);
        CONSTRUCTING_STATEMENT = false;

        Nan::ForceSet(statement, Nan::New("database").ToLocalChecked(), info.This(), FROZEN);
        Nan::ForceSet(statement, Nan::New("source").ToLocalChecked(), source, FROZEN);

        info.GetReturnValue().Set(statement);
    }

    Statement::Statement() : Nan::ObjectWrap(),
        handle(NULL),
        dead(false) {}
    Statement::~Statement() {
        dead = true;
        sqlite3_finalize(handle);
        handle = NULL;
    }
    void Statement::Init() {
        Nan::HandleScope scope;

        v8::Local<v8::FunctionTemplate> t = Nan::New<v8::FunctionTemplate>(New);
        t->InstanceTemplate()->SetInternalFieldCount(1);
        t->SetClassName(Nan::New("Statement").ToLocalChecked());

        constructor.Reset(Nan::GetFunction(t).ToLocalChecked());
    }
    CONSTRUCTOR(Statement::constructor);
    NAN_METHOD(Statement::New) {
        if (!CONSTRUCTING_STATEMENT) {
            return Nan::ThrowSyntaxError("Statements can only be constructed by the db.prepare() method.");
        }
        Statement* stmt = new Statement();
        stmt->Wrap(info.This());
        info.GetReturnValue().Set(info.This());
    }

    OpenWorker::OpenWorker(Database* db)
        : Nan::AsyncWorker(NULL), db(db) {}
    OpenWorker::~OpenWorker() {}
    void OpenWorker::Execute() {
        int status;

        status = sqlite3_open_v2(db->filename, &db->writeHandle, WRITE_MODE, NULL);
        if (status != SQLITE_OK) {
            SetErrorMessage(sqlite3_errmsg(db->writeHandle));
            sqlite3_close(db->writeHandle);
            db->writeHandle = NULL;
            return;
        }

        status = sqlite3_open_v2(db->filename, &db->readHandle, READ_MODE, NULL);
        if (status != SQLITE_OK) {
            SetErrorMessage(sqlite3_errmsg(db->readHandle));
            sqlite3_close(db->writeHandle);
            sqlite3_close(db->readHandle);
            db->writeHandle = NULL;
            db->readHandle = NULL;
            return;
        }

        sqlite3_busy_timeout(db->writeHandle, 30000);
        sqlite3_busy_timeout(db->readHandle, 30000);
    }
    void OpenWorker::HandleOKCallback() {
        Nan::HandleScope scope;
        if (db->state == DONE) {
            sqlite3_close(db->writeHandle);
            sqlite3_close(db->readHandle);
            db->writeHandle = NULL;
            db->readHandle = NULL;
        } else {
            db->state = READY;
            v8::Local<v8::Value> args[1] = {Nan::New("connect").ToLocalChecked()};
            EMIT_EVENT(db->handle(), 1, args);
        }
        db->Unref();
    }
    void OpenWorker::HandleErrorCallback() {
        Nan::HandleScope scope;
        if (db->state != DONE) {
            db->state = DONE;
            v8::Local<v8::Value> args[2] = {
                Nan::New("disconnect").ToLocalChecked(),
                v8::Exception::Error(Nan::New<v8::String>(ErrorMessage()).ToLocalChecked())
            };
            EMIT_EVENT(db->handle(), 2, args);
        }
        db->Unref();
    }

    CloseWorker::CloseWorker(Database* db, bool doNothing)
        : Nan::AsyncWorker(NULL), db(db), doNothing(doNothing) {}
    CloseWorker::~CloseWorker() {}
    void CloseWorker::Execute() {
        if (!doNothing) {
            int status1 = sqlite3_close(db->writeHandle);
            int status2 = sqlite3_close(db->readHandle);
            db->writeHandle = NULL;
            db->readHandle = NULL;
            if (status1 != SQLITE_OK) {
                SetErrorMessage(sqlite3_errmsg(db->writeHandle));
            } else if (status2 != SQLITE_OK) {
                SetErrorMessage(sqlite3_errmsg(db->readHandle));
            }
        }
    }
    void CloseWorker::HandleOKCallback() {
        Nan::HandleScope scope;
        v8::Local<v8::Value> args[2] = {Nan::New("disconnect").ToLocalChecked(), Nan::Null()};
        EMIT_EVENT(db->handle(), 2, args);
        db->Unref();
    }
    void CloseWorker::HandleErrorCallback() {
        Nan::HandleScope scope;
        v8::Local<v8::Value> args[2] = {
            Nan::New("disconnect").ToLocalChecked(),
            v8::Exception::Error(Nan::New<v8::String>(ErrorMessage()).ToLocalChecked())
        };
        EMIT_EVENT(db->handle(), 2, args);
        db->Unref();
    }

    NAN_MODULE_INIT(InitDatabase) {
        Database::Init(target);
        Statement::Init();
    }
}
<|endoftext|>


<commit_before>#include "debugger.h"

#include "gameboy.h"
#include "cpu/cpu.h"
#include "util/log.h"
#include "util/string.h"

#include <iostream>

Debugger::Debugger(Gameboy& inGameboy, bool should_debug) :
    gameboy(inGameboy),
    enabled(should_debug)
{
}

void Debugger::cycle() {
    if (!enabled) return;

    steps++;

    if (breakpoint_addr != 0 && !debugger_enabled) {
        if (gameboy.cpu.pc.value() != breakpoint_addr) { return; }
        debugger_enabled = true;
    }

    if (!debugger_enabled) { return; }

    if (counter > 0) {
        counter--;
        return;
    }

    while (true) {
        Command cmd = get_command();

        bool should_continue = execute(cmd);

        if (should_continue) break;
    }
}

bool Debugger::execute(Command command) {
    switch (command.type) {
        case CommandType::Step:
            /* Note: 'Step' allows the program to break
             * out of the debugger loop so the boolean
             * return value of this function is returned */
            return command_step(command.args);

        case CommandType::Run:
            debugger_enabled = false;
            return true;

        case CommandType::BreakAddr:
            command_breakaddr(command.args);
            break;

        case CommandType::Registers:
            command_registers(command.args);
            break;

        case CommandType::Flags:
            command_flags(command.args);
            break;

        case CommandType::Memory:
            command_memory(command.args);
            break;

        case CommandType::MemoryCell:
            command_memory_cell(command.args);
            break;

        case CommandType::Steps:
            command_steps(command.args);
            break;

        case CommandType::Log:
            command_log(command.args);
            break;

        case CommandType::Exit:
            command_exit(command.args);
            break;

        case CommandType::Help:
            command_help(command.args);
            break;

        case CommandType::Unknown:
            printf("Unknown command\n");
            break;
    }

    return false;
}

bool Debugger::command_step(Args args) {
    switch (args.size()) {
        case 0:
            return true;
        case 1:
            /* TODO: Clean this up
             * Try/catch should be moved somewhere (could use optional?)
             * Should be able to avoid subtracting 1 */
            try {
                int nsteps = std::stoi(args[0]);
                if (nsteps == 0) {
                    log_error("Cannot step zero times");
                    return false;
                }
                if (nsteps < 0) {
                    log_error("Cannot step a negative number of times");
                    return false;
                }
                counter = static_cast<uint>(nsteps - 1);
            } catch (std::invalid_argument&) {
                log_error("Invalid number of steps: %s", args[0].c_str());
                /* If an invalid argument was encountered, the program
                 * should not step at all, thus false is returned */
                return false;
            }
            return true;
        default:
            log_error("Invalid arguments to 'step'");
            return false;
    }
}

void Debugger::command_registers(Args args) {
    unused(args);

    /* printf("A: %02X | B: %02X | C: %02X | D: %02X | E: %02X | F: %02X\n", */
        /* gameboy.cpu.a.value(), */
        /* gameboy.cpu.b.value(), */
        /* gameboy.cpu.c.value(), */
        /* gameboy.cpu.d.value(), */
        /* gameboy.cpu.e.value(), */
        /* gameboy.cpu.f.value()); */

    printf("AF: %04X\n", gameboy.cpu.af.value());
    printf("BC: %04X\n", gameboy.cpu.bc.value());
    printf("DE: %04X\n", gameboy.cpu.de.value());
    printf("HL: %04X\n", gameboy.cpu.hl.value());
    printf("SP: %04X\n", gameboy.cpu.sp.value());
    printf("PC: %04X\n", gameboy.cpu.pc.value());
}

void Debugger::command_flags(Args args) {
    unused(args);

    printf("Zero: %d\n", gameboy.cpu.f.flag_zero_value());
    printf("Subtract: %d\n", gameboy.cpu.f.flag_subtract_value());
    printf("Half Carry: %d\n", gameboy.cpu.f.flag_half_carry_value());
    printf("Carry: %d\n", gameboy.cpu.f.flag_carry_value());
}

void Debugger::command_memory(Args args) {
    if (args.size() > 3) {
        log_error("Invalid arguments to command");
        return;
    }

    /* TODO: Error handling for mis-parsed arguments */
    u16 memory_location = static_cast<u16>(std::stoul(args[0], nullptr, 16));

    uint lines = 10;
    if (args.size() >= 2) {
        lines = static_cast<uint>(std::stoi(args[1]));
    }

    uint line_length = 16;
    if (args.size() == 3) {
        line_length = static_cast<uint>(std::stoul(args[2]));
    }

    for (uint i = 0; i < lines; i++) {
        Address addr = static_cast<u16>(memory_location + i * line_length);
        printf("0x%04X | ", addr.value());

        for (uint cell = 0; cell < line_length; cell++) {
            Address cell_addr = static_cast<u16>(addr.value() + cell);
            printf("%02X ", gameboy.mmu.read(cell_addr));
        }

        printf("\n");
    }
}

void Debugger::command_memory_cell(Args args) {
    if (args.size() != 1) {
        log_error("Invalid arguments to command");
        return;
    }

    u16 memory_location = static_cast<u16>(std::stoul(args[0], nullptr, 16));

    printf("0x%02X\n", gameboy.mmu.read(memory_location));
    return;
}

void Debugger::command_breakaddr(Args args) {
    if (args.size() != 1) {
        log_error("Invalid arguments to command");
        return;
    }

    u16 addr = static_cast<u16>(std::stoul(args[0], nullptr, 16));
    breakpoint_addr = addr;
    log_info("Breakpoint set for address 0x%04X", breakpoint_addr);
}

void Debugger::command_steps(Args args) {
    unused(args);

    printf("Steps: %d\n", steps);
}

void Debugger::command_log(Args args) {
    if (args.size() != 1) {
        log_error("Invalid arguments to command");
        return;
    }

    std::string desired_log_level = args[0];
    std::transform(desired_log_level.begin(), desired_log_level.end(), desired_log_level.begin(), ::tolower);

    if (desired_log_level == "none") {
        log_set_level(LogLevel::Error);
        printf("Log level: Error\n");
    } else if (desired_log_level == "error") {
        log_set_level(LogLevel::Error);
        printf("Log level: Error\n");
    } else if (desired_log_level == "debug") {
        log_set_level(LogLevel::Debug);
        printf("Log level: Debug\n");
    } else if (desired_log_level == "trace") {
        log_set_level(LogLevel::Trace);
        printf("Log level: Trace\n");
    } else {
        log_error("Invalid log level");
    }
}

void Debugger::command_exit(Args args) {
    unused(args);

    log_error("Exiting");
    exit(1);
}

void Debugger::command_help(Args args) {
    unused(args);

    printf("\n");
    printf("= Flow Control\n");
    printf("step $steps=1        Run $steps cycles\n");
    printf("run                  Run until the next breakpoint\n");
    printf("breakaddr $addr      Set a breakpoint at $addr\n");
    printf("\n");
    printf("= Debug Information\n");
    printf("registers            Print a dump of the CPU registers\n");
    printf("flags                Print a dump of the CPU flags\n");
    printf("memory $start $lines Print a dump of memory from $start to $end\n");
    printf("memorycell $addr     Print the value of the memory at $addr\n");
    printf("\n");
    printf("= Other\n");
    printf("steps                Print the number of steps so far\n");
    printf("help                 Print this help page\n");
    printf("exit                 Exit the emulator\n");
    printf("\n");
}

Command Debugger::get_command() const {
    printf("%s", PROMPT);
    std::string input_line;
    std::getline(std::cin, input_line);
    return parse(input_line);
}

Command Debugger::parse(std::string input) const {
    using std::string;
    using std::vector;

    vector<string> elems = split(input);

    /* If nothing was entered, step */
    /* TODO: This could repeat the last command, similar to GDB */
    if (elems.size() < 1) return { CommandType::Step, vector<string>() };

    string cmd = elems[0];
    CommandType cmd_type = parse_command(cmd);

    vector<string> args(elems.begin() + 1, elems.end());

    return { cmd_type, args };
}

CommandType Debugger::parse_command(std::string cmd) const {
    std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::tolower);

    if (cmd == "step") return CommandType::Step;
    if (cmd == "run") return CommandType::Run;

    if (cmd == "breakaddr") return CommandType::BreakAddr;

    if (cmd == "regs") return CommandType::Registers;
    if (cmd == "flags") return CommandType::Flags;
    if (cmd == "mem") return CommandType::Memory;
    if (cmd == "memcell") return CommandType::MemoryCell;
    if (cmd == "steps") return CommandType::Steps;

    if (cmd == "log") return CommandType::Log;

    if (cmd == "exit") return CommandType::Exit;
    if (cmd == "help") return CommandType::Help;

    return CommandType::Unknown;
}
<commit_msg>Permit 's' and 'r' as aliases for 'step' and 'run'<commit_after>#include "debugger.h"

#include "gameboy.h"
#include "cpu/cpu.h"
#include "util/log.h"
#include "util/string.h"

#include <iostream>

Debugger::Debugger(Gameboy& inGameboy, bool should_debug) :
    gameboy(inGameboy),
    enabled(should_debug)
{
}

void Debugger::cycle() {
    if (!enabled) return;

    steps++;

    if (breakpoint_addr != 0 && !debugger_enabled) {
        if (gameboy.cpu.pc.value() != breakpoint_addr) { return; }
        debugger_enabled = true;
    }

    if (!debugger_enabled) { return; }

    if (counter > 0) {
        counter--;
        return;
    }

    while (true) {
        Command cmd = get_command();

        bool should_continue = execute(cmd);

        if (should_continue) break;
    }
}

bool Debugger::execute(Command command) {
    switch (command.type) {
        case CommandType::Step:
            /* Note: 'Step' allows the program to break
             * out of the debugger loop so the boolean
             * return value of this function is returned */
            return command_step(command.args);

        case CommandType::Run:
            debugger_enabled = false;
            return true;

        case CommandType::BreakAddr:
            command_breakaddr(command.args);
            break;

        case CommandType::Registers:
            command_registers(command.args);
            break;

        case CommandType::Flags:
            command_flags(command.args);
            break;

        case CommandType::Memory:
            command_memory(command.args);
            break;

        case CommandType::MemoryCell:
            command_memory_cell(command.args);
            break;

        case CommandType::Steps:
            command_steps(command.args);
            break;

        case CommandType::Log:
            command_log(command.args);
            break;

        case CommandType::Exit:
            command_exit(command.args);
            break;

        case CommandType::Help:
            command_help(command.args);
            break;

        case CommandType::Unknown:
            printf("Unknown command\n");
            break;
    }

    return false;
}

bool Debugger::command_step(Args args) {
    switch (args.size()) {
        case 0:
            return true;
        case 1:
            /* TODO: Clean this up
             * Try/catch should be moved somewhere (could use optional?)
             * Should be able to avoid subtracting 1 */
            try {
                int nsteps = std::stoi(args[0]);
                if (nsteps == 0) {
                    log_error("Cannot step zero times");
                    return false;
                }
                if (nsteps < 0) {
                    log_error("Cannot step a negative number of times");
                    return false;
                }
                counter = static_cast<uint>(nsteps - 1);
            } catch (std::invalid_argument&) {
                log_error("Invalid number of steps: %s", args[0].c_str());
                /* If an invalid argument was encountered, the program
                 * should not step at all, thus false is returned */
                return false;
            }
            return true;
        default:
            log_error("Invalid arguments to 'step'");
            return false;
    }
}

void Debugger::command_registers(Args args) {
    unused(args);

    /* printf("A: %02X | B: %02X | C: %02X | D: %02X | E: %02X | F: %02X\n", */
        /* gameboy.cpu.a.value(), */
        /* gameboy.cpu.b.value(), */
        /* gameboy.cpu.c.value(), */
        /* gameboy.cpu.d.value(), */
        /* gameboy.cpu.e.value(), */
        /* gameboy.cpu.f.value()); */

    printf("AF: %04X\n", gameboy.cpu.af.value());
    printf("BC: %04X\n", gameboy.cpu.bc.value());
    printf("DE: %04X\n", gameboy.cpu.de.value());
    printf("HL: %04X\n", gameboy.cpu.hl.value());
    printf("SP: %04X\n", gameboy.cpu.sp.value());
    printf("PC: %04X\n", gameboy.cpu.pc.value());
}

void Debugger::command_flags(Args args) {
    unused(args);

    printf("Zero: %d\n", gameboy.cpu.f.flag_zero_value());
    printf("Subtract: %d\n", gameboy.cpu.f.flag_subtract_value());
    printf("Half Carry: %d\n", gameboy.cpu.f.flag_half_carry_value());
    printf("Carry: %d\n", gameboy.cpu.f.flag_carry_value());
}

void Debugger::command_memory(Args args) {
    if (args.size() > 3) {
        log_error("Invalid arguments to command");
        return;
    }

    /* TODO: Error handling for mis-parsed arguments */
    u16 memory_location = static_cast<u16>(std::stoul(args[0], nullptr, 16));

    uint lines = 10;
    if (args.size() >= 2) {
        lines = static_cast<uint>(std::stoi(args[1]));
    }

    uint line_length = 16;
    if (args.size() == 3) {
        line_length = static_cast<uint>(std::stoul(args[2]));
    }

    for (uint i = 0; i < lines; i++) {
        Address addr = static_cast<u16>(memory_location + i * line_length);
        printf("0x%04X | ", addr.value());

        for (uint cell = 0; cell < line_length; cell++) {
            Address cell_addr = static_cast<u16>(addr.value() + cell);
            printf("%02X ", gameboy.mmu.read(cell_addr));
        }

        printf("\n");
    }
}

void Debugger::command_memory_cell(Args args) {
    if (args.size() != 1) {
        log_error("Invalid arguments to command");
        return;
    }

    u16 memory_location = static_cast<u16>(std::stoul(args[0], nullptr, 16));

    printf("0x%02X\n", gameboy.mmu.read(memory_location));
    return;
}

void Debugger::command_breakaddr(Args args) {
    if (args.size() != 1) {
        log_error("Invalid arguments to command");
        return;
    }

    u16 addr = static_cast<u16>(std::stoul(args[0], nullptr, 16));
    breakpoint_addr = addr;
    log_info("Breakpoint set for address 0x%04X", breakpoint_addr);
}

void Debugger::command_steps(Args args) {
    unused(args);

    printf("Steps: %d\n", steps);
}

void Debugger::command_log(Args args) {
    if (args.size() != 1) {
        log_error("Invalid arguments to command");
        return;
    }

    std::string desired_log_level = args[0];
    std::transform(desired_log_level.begin(), desired_log_level.end(), desired_log_level.begin(), ::tolower);

    if (desired_log_level == "none") {
        log_set_level(LogLevel::Error);
        printf("Log level: Error\n");
    } else if (desired_log_level == "error") {
        log_set_level(LogLevel::Error);
        printf("Log level: Error\n");
    } else if (desired_log_level == "debug") {
        log_set_level(LogLevel::Debug);
        printf("Log level: Debug\n");
    } else if (desired_log_level == "trace") {
        log_set_level(LogLevel::Trace);
        printf("Log level: Trace\n");
    } else {
        log_error("Invalid log level");
    }
}

void Debugger::command_exit(Args args) {
    unused(args);

    log_error("Exiting");
    exit(1);
}

void Debugger::command_help(Args args) {
    unused(args);

    printf("\n");
    printf("= Flow Control\n");
    printf("step $steps=1        Run $steps cycles\n");
    printf("run                  Run until the next breakpoint\n");
    printf("breakaddr $addr      Set a breakpoint at $addr\n");
    printf("\n");
    printf("= Debug Information\n");
    printf("registers            Print a dump of the CPU registers\n");
    printf("flags                Print a dump of the CPU flags\n");
    printf("memory $start $lines Print a dump of memory from $start to $end\n");
    printf("memorycell $addr     Print the value of the memory at $addr\n");
    printf("\n");
    printf("= Other\n");
    printf("steps                Print the number of steps so far\n");
    printf("help                 Print this help page\n");
    printf("exit                 Exit the emulator\n");
    printf("\n");
}

Command Debugger::get_command() const {
    printf("%s", PROMPT);
    std::string input_line;
    std::getline(std::cin, input_line);
    return parse(input_line);
}

Command Debugger::parse(std::string input) const {
    using std::string;
    using std::vector;

    vector<string> elems = split(input);

    /* If nothing was entered, step */
    /* TODO: This could repeat the last command, similar to GDB */
    if (elems.size() < 1) return { CommandType::Step, vector<string>() };

    string cmd = elems[0];
    CommandType cmd_type = parse_command(cmd);

    vector<string> args(elems.begin() + 1, elems.end());

    return { cmd_type, args };
}

CommandType Debugger::parse_command(std::string cmd) const {
    std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::tolower);

    if (cmd == "step" || cmd == "s") return CommandType::Step;
    if (cmd == "run" || cmd == "r") return CommandType::Run;

    if (cmd == "breakaddr") return CommandType::BreakAddr;

    if (cmd == "regs") return CommandType::Registers;
    if (cmd == "flags") return CommandType::Flags;
    if (cmd == "mem") return CommandType::Memory;
    if (cmd == "memcell") return CommandType::MemoryCell;
    if (cmd == "steps") return CommandType::Steps;

    if (cmd == "log") return CommandType::Log;

    if (cmd == "exit") return CommandType::Exit;
    if (cmd == "help") return CommandType::Help;

    return CommandType::Unknown;
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstddef>
#include <cstring>
#include <string>
#include <iostream>
#include <system_error>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <pwd.h>

#include "control-cmds.h"
#include "service-constants.h"
#include "cpbuffer.h"

// dinitctl:  utility to control the Dinit daemon, including starting and stopping of services.

// This utility communicates with the dinit daemon via a unix socket (/dev/initctl).

using handle_t = uint32_t;

class ReadCPException
{
    public:
    int errcode;
    ReadCPException(int err) : errcode(err) { }
};

static void fillBufferTo(CPBuffer *buf, int fd, int rlength)
{
    int r = buf->fillTo(fd, rlength);
    if (r == -1) {
        throw ReadCPException(errno);
    }
    else if (r == 0) {
        throw ReadCPException(0);
    }
}

static const char * describeState(bool stopped)
{
    return stopped ? "stopped" : "started";
}

static const char * describeVerb(bool stop)
{
    return stop ? "stop" : "start";
}

// Wait for a reply packet, skipping over any information packets
// that are received in the meantime.
static void wait_for_reply(CPBuffer &rbuffer, int fd)
{
    fillBufferTo(&rbuffer, fd, 1);

    while (rbuffer[0] >= 100) {
        // Information packet; discard.
        fillBufferTo(&rbuffer, fd, 1);
        int pktlen = (unsigned char) rbuffer[1];
        fillBufferTo(&rbuffer, fd, pktlen);
        rbuffer.consume(pktlen);
    }
}

// Write *all* the requested buffer and re-try if necessary until
// the buffer is written or an unrecoverable error occurs.
static int write_all(int fd, const void *buf, size_t count)
{
    const char *cbuf = static_cast<const char *>(buf);
    int w = 0;
    while (count > 0) {
        int r = write(fd, cbuf, count);
        if (r == -1) {
            if (errno == EINTR) continue;
            return r;
        }
        w += r;
        cbuf += r;
        count -= r;
    }
    return w;
}

int main(int argc, char **argv)
{
    using namespace std;

    bool do_stop = false;
    bool show_help = argc < 2;
    char *service_name = nullptr;

    std::string control_socket_str;
    const char * control_socket_path = nullptr;

    bool verbose = true;
    bool sys_dinit = false;  // communicate with system daemon
    bool wait_for_service = true;

    int command = 0;

    constexpr int START_SERVICE = 1;
    constexpr int STOP_SERVICE = 2;

    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            if (strcmp(argv[i], "--help") == 0) {
                show_help = true;
                break;
            }
            else if (strcmp(argv[i], "--no-wait") == 0) {
                wait_for_service = false;
            }
            else if (strcmp(argv[i], "--quiet") == 0) {
                verbose = false;
            }
            else if (strcmp(argv[i], "--system") == 0 || strcmp(argv[i], "-s") == 0) {
                sys_dinit = true;
            }
            else {
                cerr << "Unrecognized command-line parameter: " << argv[i] << endl;
                return 1;
            }
        }
        else if (command == 0) {
            if (strcmp(argv[i], "start") == 0) {
                command = START_SERVICE;
            }
            else if (strcmp(argv[i], "stop") == 0) {
                command = STOP_SERVICE;
            }
            else {
                show_help = true;
                break;
            }
        }
        else {
            // service name
            service_name = argv[i];
            // TODO support multiple services (or at least give error if multiple
            //      services supplied)
        }
    }

    if (service_name == nullptr || command == 0) {
        show_help = true;
    }

    if (show_help) {
        cout << "dinit-start:   start a dinit service" << endl;
        cout << "  --help           : show this help" << endl;
        cout << "  --no-wait        : don't wait for service startup/shutdown to complete" << endl;
        cout << "  --quiet          : suppress output (except errors)" << endl;
        cout << "  -s, --system     : control system daemon instead of user daemon" << endl;
        cout << "  <service-name>   : start the named service" << endl;
        return 1;
    }

    do_stop = (command == STOP_SERVICE);

    control_socket_path = "/dev/dinitctl";

    if (! sys_dinit) {
        char * userhome = getenv("HOME");
        if (userhome == nullptr) {
            struct passwd * pwuid_p = getpwuid(getuid());
            if (pwuid_p != nullptr) {
                userhome = pwuid_p->pw_dir;
            }
        }

        if (userhome != nullptr) {
            control_socket_str = userhome;
            control_socket_str += "/.dinitctl";
            control_socket_path = control_socket_str.c_str();
        }
        else {
            cerr << "Cannot locate user home directory (set HOME or check /etc/passwd file)" << endl;
            return 1;
        }
    }

    int socknum = socket(AF_UNIX, SOCK_STREAM, 0);
    if (socknum == -1) {
        perror("socket");
        return 1;
    }

    struct sockaddr_un * name;
    uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(control_socket_path) + 1;
    name = (struct sockaddr_un *) malloc(sockaddr_size);
    if (name == nullptr) {
        cerr << "dinit-start: out of memory" << endl;
        return 1;
    }

    name->sun_family = AF_UNIX;
    strcpy(name->sun_path, control_socket_path);

    int connr = connect(socknum, (struct sockaddr *) name, sockaddr_size);
    if (connr == -1) {
        perror("connect");
        return 1;
    }

    // TODO should start by querying protocol version

    // Build buffer;
    uint16_t sname_len = strlen(service_name);
    int bufsize = 3 + sname_len;
    char * buf = new char[bufsize];

    buf[0] = DINIT_CP_LOADSERVICE;
    memcpy(buf + 1, &sname_len, 2);
    memcpy(buf + 3, service_name, sname_len);

    int r = write_all(socknum, buf, bufsize);
    delete [] buf;
    if (r == -1) {
        perror("write");
        return 1;
    }

    // Now we expect a reply:
    // NOTE: should skip over information packets.

    try {
        CPBuffer rbuffer;
        wait_for_reply(rbuffer, socknum);

        ServiceState state;
        ServiceState target_state;
        handle_t handle;

        if (rbuffer[0] == DINIT_RP_SERVICERECORD) {
            fillBufferTo(&rbuffer, socknum, 2 + sizeof(handle));
            rbuffer.extract((char *) &handle, 2, sizeof(handle));
            state = static_cast<ServiceState>(rbuffer[1]);
            target_state = static_cast<ServiceState>(rbuffer[2 + sizeof(handle)]);
            rbuffer.consume(3 + sizeof(handle));
        }
        else if (rbuffer[0] == DINIT_RP_NOSERVICE) {
            cerr << "Failed to find/load service." << endl;
            return 1;
        }
        else {
            cerr << "Protocol error." << endl;
            return 1;
        }

        ServiceState wanted_state = do_stop ? ServiceState::STOPPED : ServiceState::STARTED;
        int command = do_stop ? DINIT_CP_STOPSERVICE : DINIT_CP_STARTSERVICE;

        // Need to issue STOPSERVICE/STARTSERVICE
        if (target_state != wanted_state) {
            buf = new char[2 + sizeof(handle)];
            buf[0] = command;
            buf[1] = 0;  // don't pin
            memcpy(buf + 2, &handle, sizeof(handle));
            r = write_all(socknum, buf, 2 + sizeof(handle));
            delete buf;

            if (r == -1) {
                perror("write");
                return 1;
            }

            wait_for_reply(rbuffer, socknum);
            if (rbuffer[0] != DINIT_RP_ACK) {
                cerr << "Protocol error." << endl;
                return 1;
            }
            rbuffer.consume(1);
        }

        if (state == wanted_state) {
            if (verbose) {
                cout << "Service already " << describeState(do_stop) << "." << endl;
            }
            return 0; // success!
        }

        if (! wait_for_service) {
            return 0;
        }

        ServiceEvent completionEvent;
        ServiceEvent cancelledEvent;

        if (do_stop) {
            completionEvent = ServiceEvent::STOPPED;
            cancelledEvent = ServiceEvent::STOPCANCELLED;
        }
        else {
            completionEvent = ServiceEvent::STARTED;
            cancelledEvent = ServiceEvent::STARTCANCELLED;
        }

        // Wait until service started:
        r = rbuffer.fillTo(socknum, 2);
        while (r > 0) {
            if (rbuffer[0] >= 100) {
                int pktlen = (unsigned char) rbuffer[1];
                fillBufferTo(&rbuffer, socknum, pktlen);

                if (rbuffer[0] == DINIT_IP_SERVICEEVENT) {
                    handle_t ev_handle;
                    rbuffer.extract((char *) &ev_handle, 2, sizeof(ev_handle));
                    ServiceEvent event = static_cast<ServiceEvent>(rbuffer[2 + sizeof(ev_handle)]);
                    if (ev_handle == handle) {
                        if (event == completionEvent) {
                            if (verbose) {
                                cout << "Service " << describeState(do_stop) << "." << endl;
                            }
                            return 0;
                        }
                        else if (event == cancelledEvent) {
                            if (verbose) {
                                cout << "Service " << describeVerb(do_stop) << " cancelled." << endl;
                            }
                            return 1;
                        }
                        else if (! do_stop && event == ServiceEvent::FAILEDSTART) {
                            if (verbose) {
                                cout << "Service failed to start." << endl;
                            }
                            return 1;
                        }
                    }
                }

                rbuffer.consume(pktlen);
                r = rbuffer.fillTo(socknum, 2);
            }
            else {
                // Not an information packet?
                cerr << "protocol error" << endl;
                return 1;
            }
        }

        if (r == -1) {
            perror("read");
        }
        else {
            cerr << "protocol error (connection closed by server)" << endl;
        }
        return 1;
    }
    catch (ReadCPException &exc) {
        cerr << "control socket read failure or protocol error" << endl;
        return 1;
    }
    catch (std::bad_alloc &exc) {
        cerr << "out of memory" << endl;
        return 1;
    }

    return 0;
}
<commit_msg>Fix "skip to reply packet" method.<commit_after>#include <cstdio>
#include <cstddef>
#include <cstring>
#include <string>
#include <iostream>
#include <system_error>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <pwd.h>

#include "control-cmds.h"
#include "service-constants.h"
#include "cpbuffer.h"

// dinitctl:  utility to control the Dinit daemon, including starting and stopping of services.

// This utility communicates with the dinit daemon via a unix socket (/dev/initctl).

using handle_t = uint32_t;

class ReadCPException
{
    public:
    int errcode;
    ReadCPException(int err) : errcode(err) { }
};

static void fillBufferTo(CPBuffer *buf, int fd, int rlength)
{
    int r = buf->fillTo(fd, rlength);
    if (r == -1) {
        throw ReadCPException(errno);
    }
    else if (r == 0) {
        throw ReadCPException(0);
    }
}

static const char * describeState(bool stopped)
{
    return stopped ? "stopped" : "started";
}

static const char * describeVerb(bool stop)
{
    return stop ? "stop" : "start";
}

// Wait for a reply packet, skipping over any information packets
// that are received in the meantime.
static void wait_for_reply(CPBuffer &rbuffer, int fd)
{
    fillBufferTo(&rbuffer, fd, 1);

    while (rbuffer[0] >= 100) {
        // Information packet; discard.
        fillBufferTo(&rbuffer, fd, 1);
        int pktlen = (unsigned char) rbuffer[1];

        rbuffer.consume(1);  // Consume one byte so we'll read one byte of the next packet
        fillBufferTo(&rbuffer, fd, pktlen);
        rbuffer.consume(pktlen - 1);
    }
}

// Write *all* the requested buffer and re-try if necessary until
// the buffer is written or an unrecoverable error occurs.
static int write_all(int fd, const void *buf, size_t count)
{
    const char *cbuf = static_cast<const char *>(buf);
    int w = 0;
    while (count > 0) {
        int r = write(fd, cbuf, count);
        if (r == -1) {
            if (errno == EINTR) continue;
            return r;
        }
        w += r;
        cbuf += r;
        count -= r;
    }
    return w;
}

int main(int argc, char **argv)
{
    using namespace std;

    bool do_stop = false;
    bool show_help = argc < 2;
    char *service_name = nullptr;

    std::string control_socket_str;
    const char * control_socket_path = nullptr;

    bool verbose = true;
    bool sys_dinit = false;  // communicate with system daemon
    bool wait_for_service = true;

    int command = 0;

    constexpr int START_SERVICE = 1;
    constexpr int STOP_SERVICE = 2;

    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            if (strcmp(argv[i], "--help") == 0) {
                show_help = true;
                break;
            }
            else if (strcmp(argv[i], "--no-wait") == 0) {
                wait_for_service = false;
            }
            else if (strcmp(argv[i], "--quiet") == 0) {
                verbose = false;
            }
            else if (strcmp(argv[i], "--system") == 0 || strcmp(argv[i], "-s") == 0) {
                sys_dinit = true;
            }
            else {
                cerr << "Unrecognized command-line parameter: " << argv[i] << endl;
                return 1;
            }
        }
        else if (command == 0) {
            if (strcmp(argv[i], "start") == 0) {
                command = START_SERVICE;
            }
            else if (strcmp(argv[i], "stop") == 0) {
                command = STOP_SERVICE;
            }
            else {
                show_help = true;
                break;
            }
        }
        else {
            // service name
            service_name = argv[i];
            // TODO support multiple services (or at least give error if multiple
            //      services supplied)
        }
    }

    if (service_name == nullptr || command == 0) {
        show_help = true;
    }

    if (show_help) {
        cout << "dinit-start:   start a dinit service" << endl;
        cout << "  --help           : show this help" << endl;
        cout << "  --no-wait        : don't wait for service startup/shutdown to complete" << endl;
        cout << "  --quiet          : suppress output (except errors)" << endl;
        cout << "  -s, --system     : control system daemon instead of user daemon" << endl;
        cout << "  <service-name>   : start the named service" << endl;
        return 1;
    }

    do_stop = (command == STOP_SERVICE);

    control_socket_path = "/dev/dinitctl";

    if (! sys_dinit) {
        char * userhome = getenv("HOME");
        if (userhome == nullptr) {
            struct passwd * pwuid_p = getpwuid(getuid());
            if (pwuid_p != nullptr) {
                userhome = pwuid_p->pw_dir;
            }
        }

        if (userhome != nullptr) {
            control_socket_str = userhome;
            control_socket_str += "/.dinitctl";
            control_socket_path = control_socket_str.c_str();
        }
        else {
            cerr << "Cannot locate user home directory (set HOME or check /etc/passwd file)" << endl;
            return 1;
        }
    }

    int socknum = socket(AF_UNIX, SOCK_STREAM, 0);
    if (socknum == -1) {
        perror("socket");
        return 1;
    }

    struct sockaddr_un * name;
    uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(control_socket_path) + 1;
    name = (struct sockaddr_un *) malloc(sockaddr_size);
    if (name == nullptr) {
        cerr << "dinit-start: out of memory" << endl;
        return 1;
    }

    name->sun_family = AF_UNIX;
    strcpy(name->sun_path, control_socket_path);

    int connr = connect(socknum, (struct sockaddr *) name, sockaddr_size);
    if (connr == -1) {
        perror("connect");
        return 1;
    }

    // TODO should start by querying protocol version

    // Build buffer;
    uint16_t sname_len = strlen(service_name);
    int bufsize = 3 + sname_len;
    char * buf = new char[bufsize];

    buf[0] = DINIT_CP_LOADSERVICE;
    memcpy(buf + 1, &sname_len, 2);
    memcpy(buf + 3, service_name, sname_len);

    int r = write_all(socknum, buf, bufsize);
    delete [] buf;
    if (r == -1) {
        perror("write");
        return 1;
    }

    // Now we expect a reply:
    // NOTE: should skip over information packets.

    try {
        CPBuffer rbuffer;
        wait_for_reply(rbuffer, socknum);

        ServiceState state;
        ServiceState target_state;
        handle_t handle;

        if (rbuffer[0] == DINIT_RP_SERVICERECORD) {
            fillBufferTo(&rbuffer, socknum, 2 + sizeof(handle));
            rbuffer.extract((char *) &handle, 2, sizeof(handle));
            state = static_cast<ServiceState>(rbuffer[1]);
            target_state = static_cast<ServiceState>(rbuffer[2 + sizeof(handle)]);
            rbuffer.consume(3 + sizeof(handle));
        }
        else if (rbuffer[0] == DINIT_RP_NOSERVICE) {
            cerr << "Failed to find/load service." << endl;
            return 1;
        }
        else {
            cerr << "Protocol error." << endl;
            return 1;
        }

        ServiceState wanted_state = do_stop ? ServiceState::STOPPED : ServiceState::STARTED;
        int command = do_stop ? DINIT_CP_STOPSERVICE : DINIT_CP_STARTSERVICE;

        // Need to issue STOPSERVICE/STARTSERVICE
        if (target_state != wanted_state) {
            buf = new char[2 + sizeof(handle)];
            buf[0] = command;
            buf[1] = 0;  // don't pin
            memcpy(buf + 2, &handle, sizeof(handle));
            r = write_all(socknum, buf, 2 + sizeof(handle));
            delete buf;

            if (r == -1) {
                perror("write");
                return 1;
            }

            wait_for_reply(rbuffer, socknum);
            if (rbuffer[0] != DINIT_RP_ACK) {
                cerr << "Protocol error." << endl;
                return 1;
            }
            rbuffer.consume(1);
        }

        if (state == wanted_state) {
            if (verbose) {
                cout << "Service already " << describeState(do_stop) << "." << endl;
            }
            return 0; // success!
        }

        if (! wait_for_service) {
            return 0;
        }

        ServiceEvent completionEvent;
        ServiceEvent cancelledEvent;

        if (do_stop) {
            completionEvent = ServiceEvent::STOPPED;
            cancelledEvent = ServiceEvent::STOPCANCELLED;
        }
        else {
            completionEvent = ServiceEvent::STARTED;
            cancelledEvent = ServiceEvent::STARTCANCELLED;
        }

        // Wait until service started:
        r = rbuffer.fillTo(socknum, 2);
        while (r > 0) {
            if (rbuffer[0] >= 100) {
                int pktlen = (unsigned char) rbuffer[1];
                fillBufferTo(&rbuffer, socknum, pktlen);

                if (rbuffer[0] == DINIT_IP_SERVICEEVENT) {
                    handle_t ev_handle;
                    rbuffer.extract((char *) &ev_handle, 2, sizeof(ev_handle));
                    ServiceEvent event = static_cast<ServiceEvent>(rbuffer[2 + sizeof(ev_handle)]);
                    if (ev_handle == handle) {
                        if (event == completionEvent) {
                            if (verbose) {
                                cout << "Service " << describeState(do_stop) << "." << endl;
                            }
                            return 0;
                        }
                        else if (event == cancelledEvent) {
                            if (verbose) {
                                cout << "Service " << describeVerb(do_stop) << " cancelled." << endl;
                            }
                            return 1;
                        }
                        else if (! do_stop && event == ServiceEvent::FAILEDSTART) {
                            if (verbose) {
                                cout << "Service failed to start." << endl;
                            }
                            return 1;
                        }
                    }
                }

                rbuffer.consume(pktlen);
                r = rbuffer.fillTo(socknum, 2);
            }
            else {
                // Not an information packet?
                cerr << "protocol error" << endl;
                return 1;
            }
        }

        if (r == -1) {
            perror("read");
        }
        else {
            cerr << "protocol error (connection closed by server)" << endl;
        }
        return 1;
    }
    catch (ReadCPException &exc) {
        cerr << "control socket read failure or protocol error" << endl;
        return 1;
    }
    catch (std::bad_alloc &exc) {
        cerr << "out of memory" << endl;
        return 1;
    }

    return 0;
}
<|endoftext|>