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

#include <fstream>
#include <vector>
#include <string>
#include <cmath>
#include <exception>
#include <H5Cpp.h>
#include <dada_hdu.h>
#include <ascii_header.h>

#include <Observation.hpp>
#include <utils.hpp>

#ifndef READ_DATA_HPP
#define READ_DATA_HPP

namespace AstroData {

// Exception: the PSRDada ring buffer does not work
class RingBufferError : public std::exception {
public:
  RingBufferError();
  ~RingBufferError() throw ();

  const char * what() const throw ();
};

template< typename T > void readSIGPROC(Observation & observation, const unsigned int bytestoSkip, std::string inputFilename, std::vector< std::vector< T > * > & data, unsigned int firstSecond = 0);
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, std::vector< std::vector< T > * > & data, unsigned int nrSeconds = 0, unsigned int firstSecond = 0);
template< typename T > void readPSRDadaHeader(Observation & observation, dada_hdu_t & ringBuffer) throw(RingBufferError);
template< typename T > inline void readPSRDada(Observation & observation, dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError);

// Implementation

template< typename T > void readSIGPROC(Observation & observation, unsigned int bytesToSkip, std::string inputFilename, std::vector< std::vector< T > * > & data, unsigned int firstSecond) {
	std::ifstream inputFile;
	const unsigned int BUFFER_DIM = sizeof(T);
	char * buffer = new char [BUFFER_DIM];

	inputFile.open(inputFilename.c_str(), std::ios::binary);
	inputFile.sync_with_stdio(false);
	inputFile.seekg(bytesToSkip, std::ios::beg);
	for ( unsigned int second = 0; second < observation.getNrSeconds(); second++ ) {
		data.at(second) = new std::vector< T >(observation.getNrSamplesPerPaddedSecond() * observation.getNrChannels());

		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
			for ( unsigned int channel = observation.getNrChannels(); channel > 0; channel-- ) {
				inputFile.read(buffer, BUFFER_DIM);
        data.at(second)->at((static_cast< long long unsigned int >(channel - 1) * observation.getNrSamplesPerPaddedSecond()) + sample) = *(reinterpret_cast< T * >(buffer));
			}
		}
	}
	inputFile.close();

	delete [] buffer;
}

template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, std::vector< std::vector< T > * > & data, unsigned int nrSeconds, unsigned int firstSecond) {
  unsigned int nrSubbands, nrChannels;
  float minFreq, channelBandwidth;
	// Read the HDF5 file with the metadata
	H5::H5File headerFile = H5::H5File(headerFilename, H5F_ACC_RDONLY);
	H5::FloatType typeDouble = H5::FloatType(H5::PredType::NATIVE_DOUBLE);
	double valueDouble = 0.0;
	H5::IntType typeUInt = H5::IntType(H5::PredType::NATIVE_UINT);
	unsigned int valueUInt = 0;

	H5::Group currentNode = headerFile.openGroup("/");
	currentNode.openAttribute("OBSERVATION_FREQUENCY_MIN").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  minFreq = valueDouble;
	currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
	currentNode.openAttribute("TOTAL_INTEGRATION_TIME").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
	double totalIntegrationTime = valueDouble;
	currentNode.openAttribute("NOF_BEAMS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	observation.setNrBeams(valueUInt);
	currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
	currentNode.openAttribute("NOF_SAMPLES").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	unsigned int totalSamples = valueUInt;
	currentNode.openAttribute("NOF_STATIONS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	observation.setNrStations(valueUInt);
	currentNode.openAttribute("CHANNELS_PER_SUBBAND").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	nrChannels = valueUInt;
	currentNode.openAttribute("CHANNEL_WIDTH").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  channelBandwidth = valueDouble / 1000000;
	H5::DataSet currentData = currentNode.openDataSet("STOKES_0");
	currentData.openAttribute("NOF_SUBBANDS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	nrSubbands = valueUInt;
	headerFile.close();

	observation.setNrSamplesPerSecond(static_cast< unsigned int >(totalSamples / totalIntegrationTime));
	if ( nrSeconds == 0 ) {
		observation.setNrSeconds(static_cast< unsigned int >(totalIntegrationTime));
	} else {
		if ( static_cast< unsigned int >(totalIntegrationTime) >= (firstSecond + nrSeconds) ) {
			observation.setNrSeconds(nrSeconds);
		} else {
			observation.setNrSeconds(static_cast< unsigned int >(totalIntegrationTime) - firstSecond);
		}
	}
  observation.setFrequencyRange(nrSubbands * nrChannels, minFreq, channelBandwidth);

	// Read the raw file with the actual data
	std::ifstream rawFile;
	rawFile.open(rawFilename.c_str(), std::ios::binary);
	rawFile.sync_with_stdio(false);
	if ( firstSecond > 0 ) {
		rawFile.seekg(firstSecond * observation.getNrSamplesPerSecond() * nrSubbands * nrChannels, std::ios::beg);
	}
	data.resize(observation.getNrSeconds());

	char * word = new char [4];
	for ( unsigned int second = 0; second < observation.getNrSeconds(); second++ ) {
		data.at(second) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond());
		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
			for ( unsigned int subband = 0; subband < nrSubbands; subband++ ) {
				for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
          unsigned int globalChannel = (subband * nrChannels) + channel;

					rawFile.read(word, 4);
          isa::utils::bigEndianToLittleEndian(word);
          data.at(second)->at((globalChannel * observation.getNrSamplesPerPaddedSecond()) + sample) = *(reinterpret_cast< T * >(word));
				}
			}
		}
	}
	rawFile.close();
	delete [] word;
}

template< typename T > void readPSRDadaHeader(Observation & observation, dada_hdu_t & ringBuffer) throw(RingBufferError) {
  // Staging variables for the header elements
  unsigned int uintValue = 0;
  float floatValue[2] = {0.0f, 0.0f};
  // Header string
  uint64_t headerBytes = 0;
  char * header = 0;

  header = ipcbuf_get_next_read(ringBuffer.header_block, &headerBytes);

  if ( (header == 0) || (headerBytes == 0 ) ) {
    throw RingBufferError();
  }

  ascii_header_get(header, "SAMPLES_PER_SECOND", "%d", &uintValue);
  observation.setNrSamplesPerSecond(uintValue);
  ascii_header_get(header, "CHANNELS", "%d", &uintValue);
  ascii_header_get(header, "MIN_FREQUENCY", "%f", &floatValue[0]);
  ascii_header_get(header, "CHANNEL_BANDWIDTH", "%f", &floatValue[1]);
  observation.setFrequencyRange(uintValue, floatValue[0], floatValue[1]);
  ipcbuf_mark_cleared(ringBuffer.header_block);

  delete header;
}

template< typename T > inline void readPSRDada(Observation & observation, dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError) {
  if ( (ipcio_read(ringBuffer.data_block, reinterpret_cast< char * >(data->data()), observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond() * sizeof(T))) < 0 ) {
    throw RingBufferError();
  }
}

} // AstroData

#endif // READ_DATA_HPP

<commit_msg>With readSIGPROC it is now possible to read input files where samples are less than 8 bits.<commit_after>// Copyright 2012 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <fstream>
#include <vector>
#include <string>
#include <cmath>
#include <exception>
#include <H5Cpp.h>
#include <dada_hdu.h>
#include <ascii_header.h>

#include <Observation.hpp>
#include <utils.hpp>

#ifndef READ_DATA_HPP
#define READ_DATA_HPP

namespace AstroData {

// Exception: the PSRDada ring buffer does not work
class RingBufferError : public std::exception {
public:
  RingBufferError();
  ~RingBufferError() throw ();

  const char * what() const throw ();
};

template< typename T > void readSIGPROC(const Observation & observation, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstSecond = 0);
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, std::vector< std::vector< T > * > & data, unsigned int nrSeconds = 0, unsigned int firstSecond = 0);
template< typename T > void readPSRDadaHeader(Observation & observation, dada_hdu_t & ringBuffer) throw(RingBufferError);
template< typename T > inline void readPSRDada(Observation & observation, dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError);

// Implementation

template< typename T > void readSIGPROC(const Observation & observation, const uint8_t inputBits, const unsigned int bytesToSkip, const std::string & inputFilename, std::vector< std::vector< T > * > & data, const unsigned int firstSecond = 0) {
	std::ifstream inputFile;
	const unsigned int BUFFER_DIM = sizeof(T);
	char * buffer = new char [BUFFER_DIM];

	inputFile.open(inputFilename.c_str(), std::ios::binary);
	inputFile.sync_with_stdio(false);
	inputFile.seekg(bytesToSkip, std::ios::beg);
	for ( unsigned int second = 0; second < observation.getNrSeconds(); second++ ) {
    if ( inputBits >= 8 ) {
      data.at(second) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond());
      for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
        for ( unsigned int channel = observation.getNrChannels(); channel > 0; channel-- ) {
          inputFile.read(buffer, BUFFER_DIM);
          data.at(second)->at((static_cast< uint64_t >(channel - 1) * observation.getNrSamplesPerPaddedSecond()) + sample) = *(reinterpret_cast< T * >(buffer));
        }
      }
    } else {
      data.at(second) = new std::vector< T >(observation.getNrChannels() * isa::utils::pad(observation.getNrSamplesPerSecond() / (8 / inputBits), observation.getPadding()));
      for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond() / (8 / inputBits); sample++ ) {
        for ( unsigned int channel = observation.getNrChannels(); channel > 0; channel-- ) {
          inputFile.read(buffer, BUFFER_DIM);
          data.at(second)->at((static_cast< uint64_t >(channel - 1) * (observation.getNrSamplesPerSecond() / (8 / inputBits))) + sample) = *(reinterpret_cast< T * >(buffer));
        }
      }
    }
	}
	inputFile.close();

	delete [] buffer;
}

template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, std::vector< std::vector< T > * > & data, unsigned int nrSeconds, unsigned int firstSecond) {
  unsigned int nrSubbands, nrChannels;
  float minFreq, channelBandwidth;
	// Read the HDF5 file with the metadata
	H5::H5File headerFile = H5::H5File(headerFilename, H5F_ACC_RDONLY);
	H5::FloatType typeDouble = H5::FloatType(H5::PredType::NATIVE_DOUBLE);
	double valueDouble = 0.0;
	H5::IntType typeUInt = H5::IntType(H5::PredType::NATIVE_UINT);
	unsigned int valueUInt = 0;

	H5::Group currentNode = headerFile.openGroup("/");
	currentNode.openAttribute("OBSERVATION_FREQUENCY_MIN").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  minFreq = valueDouble;
	currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
	currentNode.openAttribute("TOTAL_INTEGRATION_TIME").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
	double totalIntegrationTime = valueDouble;
	currentNode.openAttribute("NOF_BEAMS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	observation.setNrBeams(valueUInt);
	currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
	currentNode.openAttribute("NOF_SAMPLES").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	unsigned int totalSamples = valueUInt;
	currentNode.openAttribute("NOF_STATIONS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	observation.setNrStations(valueUInt);
	currentNode.openAttribute("CHANNELS_PER_SUBBAND").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	nrChannels = valueUInt;
	currentNode.openAttribute("CHANNEL_WIDTH").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  channelBandwidth = valueDouble / 1000000;
	H5::DataSet currentData = currentNode.openDataSet("STOKES_0");
	currentData.openAttribute("NOF_SUBBANDS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	nrSubbands = valueUInt;
	headerFile.close();

	observation.setNrSamplesPerSecond(static_cast< unsigned int >(totalSamples / totalIntegrationTime));
	if ( nrSeconds == 0 ) {
		observation.setNrSeconds(static_cast< unsigned int >(totalIntegrationTime));
	} else {
		if ( static_cast< unsigned int >(totalIntegrationTime) >= (firstSecond + nrSeconds) ) {
			observation.setNrSeconds(nrSeconds);
		} else {
			observation.setNrSeconds(static_cast< unsigned int >(totalIntegrationTime) - firstSecond);
		}
	}
  observation.setFrequencyRange(nrSubbands * nrChannels, minFreq, channelBandwidth);

	// Read the raw file with the actual data
	std::ifstream rawFile;
	rawFile.open(rawFilename.c_str(), std::ios::binary);
	rawFile.sync_with_stdio(false);
	if ( firstSecond > 0 ) {
		rawFile.seekg(firstSecond * observation.getNrSamplesPerSecond() * nrSubbands * nrChannels, std::ios::beg);
	}
	data.resize(observation.getNrSeconds());

	char * word = new char [4];
	for ( unsigned int second = 0; second < observation.getNrSeconds(); second++ ) {
		data.at(second) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond());
		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
			for ( unsigned int subband = 0; subband < nrSubbands; subband++ ) {
				for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
          unsigned int globalChannel = (subband * nrChannels) + channel;

					rawFile.read(word, 4);
          isa::utils::bigEndianToLittleEndian(word);
          data.at(second)->at((globalChannel * observation.getNrSamplesPerPaddedSecond()) + sample) = *(reinterpret_cast< T * >(word));
				}
			}
		}
	}
	rawFile.close();
	delete [] word;
}

template< typename T > void readPSRDadaHeader(Observation & observation, dada_hdu_t & ringBuffer) throw(RingBufferError) {
  // Staging variables for the header elements
  unsigned int uintValue = 0;
  float floatValue[2] = {0.0f, 0.0f};
  // Header string
  uint64_t headerBytes = 0;
  char * header = 0;

  header = ipcbuf_get_next_read(ringBuffer.header_block, &headerBytes);

  if ( (header == 0) || (headerBytes == 0 ) ) {
    throw RingBufferError();
  }

  ascii_header_get(header, "SAMPLES_PER_SECOND", "%d", &uintValue);
  observation.setNrSamplesPerSecond(uintValue);
  ascii_header_get(header, "CHANNELS", "%d", &uintValue);
  ascii_header_get(header, "MIN_FREQUENCY", "%f", &floatValue[0]);
  ascii_header_get(header, "CHANNEL_BANDWIDTH", "%f", &floatValue[1]);
  observation.setFrequencyRange(uintValue, floatValue[0], floatValue[1]);
  ipcbuf_mark_cleared(ringBuffer.header_block);

  delete header;
}

template< typename T > inline void readPSRDada(Observation & observation, dada_hdu_t & ringBuffer, std::vector< T > * data) throw(RingBufferError) {
  if ( (ipcio_read(ringBuffer.data_block, reinterpret_cast< char * >(data->data()), observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond() * sizeof(T))) < 0 ) {
    throw RingBufferError();
  }
}

} // AstroData

#endif // READ_DATA_HPP

<|endoftext|>


<commit_before>#include "rosplan_planning_system/PlanDispatcher.h"
#include <map>

namespace KCL_rosplan {

	int PlanDispatcher::getCurrentAction() {
		return current_action;
	}

	void PlanDispatcher::reset() {
		dispatch_paused = false;
		current_action = 0;
		action_received.clear();
		action_completed.clear();
		replan_requested = false;
	}

	/*-----------------*/
	/* action dispatch */
	/*-----------------*/

	/*
	 * Loop through and publish planned actions
	 */
	bool PlanDispatcher::dispatchPlan(const std::vector<rosplan_dispatch_msgs::ActionDispatch> &actionList, double missionStart, double planStart) {

		ros::NodeHandle nh("~");
		ros::Rate loop_rate(10);

		ROS_INFO("KCL: (PS) Dispatching plan");
		replan_requested = false;
		bool repeatAction = false;
		while (ros::ok() && actionList.size() > current_action) {

			// get next action
			rosplan_dispatch_msgs::ActionDispatch currentMessage = actionList[current_action];
			if((unsigned int)currentMessage.action_id != current_action)
				ROS_ERROR("KCL: (PS) Message action_id [%d] does not meet expected [%zu]", currentMessage.action_id, current_action);

			// loop while waiting for dispatch time
			if(!dispatch_on_completion) {
				double wait_period = 10.0;
				int wait_print = (int)(currentMessage.dispatch_time + planStart - ros::WallTime::now().toSec()) / wait_period;
				while (ros::ok() && ros::WallTime::now().toSec() < currentMessage.dispatch_time + planStart) {
					ros::spinOnce();
					loop_rate.sleep();
					double remaining = planStart + currentMessage.dispatch_time - ros::WallTime::now().toSec();
					if(wait_print > (int)remaining / wait_period) {
						ROS_INFO("KCL: (PS) Waiting %f before dispatching action: [%i, %s, %f, %f]",
								remaining,currentMessage.action_id, currentMessage.name.c_str(),
								 (currentMessage.dispatch_time+planStart-missionStart), currentMessage.duration);
						wait_print--;
					}
				}
			}

			if(!checkPreconditions(currentMessage)) {
				ROS_INFO("KCL: (PS) Preconditions not achieved [%i, %s]", currentMessage.action_id, currentMessage.name.c_str());
			}

			// dispatch action
			ROS_INFO("KCL: (PS) Dispatching action [%i, %s, %f, %f]", currentMessage.action_id, currentMessage.name.c_str(), (currentMessage.dispatch_time+planStart-missionStart), currentMessage.duration);
			action_publisher.publish(currentMessage);
			double late_print = (ros::WallTime::now().toSec() - (currentMessage.dispatch_time + planStart));
			if(late_print>0.1) ROS_INFO("KCL: (PS) Action [%i] is %f second(s) late", currentMessage.action_id, late_print);

			// wait for action to complete
			if(dispatch_concurrent) {
				int counter = 0;
				while (ros::ok() && !action_completed[current_action]) {
					ros::spinOnce();
					loop_rate.sleep();
					counter++;
					if (counter == 2000) {
						ROS_INFO("KCL: (PS) Action %i timed out now. Cancelling...", currentMessage.action_id);
						rosplan_dispatch_msgs::ActionDispatch cancelMessage;
						cancelMessage.action_id = currentMessage.action_id;
						cancelMessage.name = "cancel_action";
						action_publisher.publish(cancelMessage);
					}
				}
			}

			// get ready for next action
			if(!repeatAction) current_action++;
			repeatAction = false;
			action_received[current_action] = false;
			action_completed[current_action] = false;

			// finish dispatch and replan
			if(replan_requested) return false;
		}
		return true;
	}

	bool PlanDispatcher::checkPreconditions(rosplan_dispatch_msgs::ActionDispatch msg) {

		// setup service call
		ros::NodeHandle nh;
		ros::ServiceClient queryKnowledgeClient = nh.serviceClient<rosplan_knowledge_msgs::KnowledgeQueryService>("/kcl_rosplan/query_knowledge_base");
		rosplan_knowledge_msgs::KnowledgeQueryService querySrv;

		std::map<std::string, std::vector<std::vector<std::string> > >::iterator oit;
		oit = environment.domain_operator_precondition_map.find(msg.name);
		if(oit==environment.domain_operator_precondition_map.end()) return false;

		// iterate through conditions
		std::vector<std::vector<std::string> >::iterator cit = oit->second.begin();
		for(; cit!=oit->second.end(); cit++) {

			rosplan_knowledge_msgs::KnowledgeItem condition;

			// set fact or function
			std::map<std::string,std::vector<std::string> >::iterator dit = environment.domain_predicates.find((*cit)[0]);
			if(dit!=environment.domain_predicates.end()) condition.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::DOMAIN_ATTRIBUTE;

			dit = environment.domain_functions.find((*cit)[0]);
			if(dit!=environment.domain_functions.end()) condition.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::DOMAIN_FUNCTION;

			// populate parameters
			condition.attribute_name = (*cit)[0];
			std::vector<diagnostic_msgs::KeyValue>::iterator pit;
			for(pit = msg.parameters.begin(); pit!=msg.parameters.end(); pit++)
				condition.values.push_back(*pit);

			querySrv.request.knowledge.push_back(condition);
		}

		// check conditions in knowledge base
		if (queryKnowledgeClient.call(querySrv)) {

			return querySrv.response.all_true;

		} else {
			ROS_ERROR("KCL: (PS) Failed to call service /kcl_rosplan/query_knowledge_base");
		}
	}

	/*------------------*/
	/* general feedback */
	/*------------------*/

	/**
	 * listen to and process actionFeedback topic.
	 */
	void PlanDispatcher::feedbackCallback(const rosplan_dispatch_msgs::ActionFeedback::ConstPtr& msg) {

		// create error if the action is unrecognised
		ROS_INFO("KCL: (PS) Feedback received [%i,%s]", msg->action_id, msg->status.c_str());
		if(current_action != (unsigned int)msg->action_id)
			ROS_ERROR("KCL: (PS) Unexpected action ID: %d; current action: %zu", msg->action_id, current_action);

		// action enabled
		if(!action_received[msg->action_id] && (0 == msg->status.compare("action enabled")))
			action_received[msg->action_id] = true;

		// more specific feedback
		actionFeedback(msg);

		// action completed (successfuly)
		if(!action_completed[msg->action_id] && 0 == msg->status.compare("action achieved"))
			action_completed[msg->action_id] = true;

		// action completed (failed)
		if(!action_completed[msg->action_id] && 0 == msg->status.compare("action failed")) {
			replan_requested = true;
			action_completed[msg->action_id] = true;
		}
	}

	/*---------------------------*/
	/* Specific action responses */
	/*---------------------------*/

	/**
	 * processes single action feedback message.
	 * This method serves as the hook for defining more interesting behaviour on action feedback.
	 */
	void PlanDispatcher::actionFeedback(const rosplan_dispatch_msgs::ActionFeedback::ConstPtr& msg) {
		// nothing yet...
	}
} // close namespace
<commit_msg>Correct flag as online<commit_after>#include "rosplan_planning_system/PlanDispatcher.h"
#include <map>

namespace KCL_rosplan {

	int PlanDispatcher::getCurrentAction() {
		return current_action;
	}

	void PlanDispatcher::reset() {
		dispatch_paused = false;
		current_action = 0;
		action_received.clear();
		action_completed.clear();
		replan_requested = false;
	}

	/*-----------------*/
	/* action dispatch */
	/*-----------------*/

	/*
	 * Loop through and publish planned actions
	 */
	bool PlanDispatcher::dispatchPlan(const std::vector<rosplan_dispatch_msgs::ActionDispatch> &actionList, double missionStart, double planStart) {

		ros::NodeHandle nh("~");
		ros::Rate loop_rate(10);

		ROS_INFO("KCL: (PS) Dispatching plan");
		replan_requested = false;
		bool repeatAction = false;
		while (ros::ok() && actionList.size() > current_action) {

			// get next action
			rosplan_dispatch_msgs::ActionDispatch currentMessage = actionList[current_action];
			if((unsigned int)currentMessage.action_id != current_action)
				ROS_ERROR("KCL: (PS) Message action_id [%d] does not meet expected [%zu]", currentMessage.action_id, current_action);

			// loop while waiting for dispatch time
			if(!dispatch_on_completion) {
				double wait_period = 10.0;
				int wait_print = (int)(currentMessage.dispatch_time + planStart - ros::WallTime::now().toSec()) / wait_period;
				while (ros::ok() && ros::WallTime::now().toSec() < currentMessage.dispatch_time + planStart) {
					ros::spinOnce();
					loop_rate.sleep();
					double remaining = planStart + currentMessage.dispatch_time - ros::WallTime::now().toSec();
					if(wait_print > (int)remaining / wait_period) {
						ROS_INFO("KCL: (PS) Waiting %f before dispatching action: [%i, %s, %f, %f]",
								remaining,currentMessage.action_id, currentMessage.name.c_str(),
								 (currentMessage.dispatch_time+planStart-missionStart), currentMessage.duration);
						wait_print--;
					}
				}
			}

			if(!checkPreconditions(currentMessage)) {
				ROS_INFO("KCL: (PS) Preconditions not achieved [%i, %s]", currentMessage.action_id, currentMessage.name.c_str());
			}

			// dispatch action
			ROS_INFO("KCL: (PS) Dispatching action [%i, %s, %f, %f]", currentMessage.action_id, currentMessage.name.c_str(), (currentMessage.dispatch_time+planStart-missionStart), currentMessage.duration);
			action_publisher.publish(currentMessage);
			double late_print = (ros::WallTime::now().toSec() - (currentMessage.dispatch_time + planStart));
			if(late_print>0.1) ROS_INFO("KCL: (PS) Action [%i] is %f second(s) late", currentMessage.action_id, late_print);

			// wait for action to complete
			if(!dispatch_concurrent) {
				int counter = 0;
				while (ros::ok() && !action_completed[current_action]) {
					ros::spinOnce();
					loop_rate.sleep();
					counter++;
					if (counter == 2000) {
						ROS_INFO("KCL: (PS) Action %i timed out now. Cancelling...", currentMessage.action_id);
						rosplan_dispatch_msgs::ActionDispatch cancelMessage;
						cancelMessage.action_id = currentMessage.action_id;
						cancelMessage.name = "cancel_action";
						action_publisher.publish(cancelMessage);
					}
				}
			}

			// get ready for next action
			if(!repeatAction) current_action++;
			repeatAction = false;
			action_received[current_action] = false;
			action_completed[current_action] = false;

			// finish dispatch and replan
			if(replan_requested) return false;
		}
		return true;
	}

	bool PlanDispatcher::checkPreconditions(rosplan_dispatch_msgs::ActionDispatch msg) {

		// setup service call
		ros::NodeHandle nh;
		ros::ServiceClient queryKnowledgeClient = nh.serviceClient<rosplan_knowledge_msgs::KnowledgeQueryService>("/kcl_rosplan/query_knowledge_base");
		rosplan_knowledge_msgs::KnowledgeQueryService querySrv;

		std::map<std::string, std::vector<std::vector<std::string> > >::iterator oit;
		oit = environment.domain_operator_precondition_map.find(msg.name);
		if(oit==environment.domain_operator_precondition_map.end()) return false;

		// iterate through conditions
		std::vector<std::vector<std::string> >::iterator cit = oit->second.begin();
		for(; cit!=oit->second.end(); cit++) {

			rosplan_knowledge_msgs::KnowledgeItem condition;

			// set fact or function
			std::map<std::string,std::vector<std::string> >::iterator dit = environment.domain_predicates.find((*cit)[0]);
			if(dit!=environment.domain_predicates.end()) condition.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::DOMAIN_ATTRIBUTE;

			dit = environment.domain_functions.find((*cit)[0]);
			if(dit!=environment.domain_functions.end()) condition.knowledge_type = rosplan_knowledge_msgs::KnowledgeItem::DOMAIN_FUNCTION;

			// populate parameters
			condition.attribute_name = (*cit)[0];
			std::vector<diagnostic_msgs::KeyValue>::iterator pit;
			for(pit = msg.parameters.begin(); pit!=msg.parameters.end(); pit++) {
				condition.values.push_back(*pit);
			}

			querySrv.request.knowledge.push_back(condition);
		}

		// check conditions in knowledge base
		if (queryKnowledgeClient.call(querySrv)) {

			return querySrv.response.all_true;

		} else {
			ROS_ERROR("KCL: (PS) Failed to call service /kcl_rosplan/query_knowledge_base");
		}
	}

	/*------------------*/
	/* general feedback */
	/*------------------*/

	/**
	 * listen to and process actionFeedback topic.
	 */
	void PlanDispatcher::feedbackCallback(const rosplan_dispatch_msgs::ActionFeedback::ConstPtr& msg) {

		// create error if the action is unrecognised
		ROS_INFO("KCL: (PS) Feedback received [%i,%s]", msg->action_id, msg->status.c_str());
		if(current_action != (unsigned int)msg->action_id)
			ROS_ERROR("KCL: (PS) Unexpected action ID: %d; current action: %zu", msg->action_id, current_action);

		// action enabled
		if(!action_received[msg->action_id] && (0 == msg->status.compare("action enabled")))
			action_received[msg->action_id] = true;

		// more specific feedback
		actionFeedback(msg);

		// action completed (successfuly)
		if(!action_completed[msg->action_id] && 0 == msg->status.compare("action achieved"))
			action_completed[msg->action_id] = true;

		// action completed (failed)
		if(!action_completed[msg->action_id] && 0 == msg->status.compare("action failed")) {
			replan_requested = true;
			action_completed[msg->action_id] = true;
		}
	}

	/*---------------------------*/
	/* Specific action responses */
	/*---------------------------*/

	/**
	 * processes single action feedback message.
	 * This method serves as the hook for defining more interesting behaviour on action feedback.
	 */
	void PlanDispatcher::actionFeedback(const rosplan_dispatch_msgs::ActionFeedback::ConstPtr& msg) {
		// nothing yet...
	}
} // close namespace
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: atrflyin.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: hr $ $Date: 2007-09-27 09:23:28 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#include "hintids.hxx"
#include "cntfrm.hxx"       // _GetFly
#include "doc.hxx"
#include "pam.hxx"          // fuer SwTxtFlyCnt
#include "flyfrm.hxx"       // fuer SwTxtFlyCnt
#include "ndtxt.hxx"        // SwFlyFrmFmt
#include "frmfmt.hxx"       // SwFlyFrmFmt

#ifndef _FMTFLCNT_HXX //autogen
#include <fmtflcnt.hxx>
#endif
#ifndef _TXTFLCNT_HXX //autogen
#include <txtflcnt.hxx>
#endif
#ifndef _FMTANCHR_HXX //autogen
#include <fmtanchr.hxx>
#endif
#include "swfont.hxx"
#include "txtfrm.hxx"
#include "flyfrms.hxx"
// --> OD 2004-11-09 #i26945#
#ifndef _OBJECTFORMATTER_HXX
#include <objectformatter.hxx>
#endif
// <--

SwFmtFlyCnt::SwFmtFlyCnt( SwFrmFmt *pFrmFmt )
    : SfxPoolItem( RES_TXTATR_FLYCNT ),
    pTxtAttr( 0 ),
    pFmt( pFrmFmt )
{
}

int __EXPORT SwFmtFlyCnt::operator==( const SfxPoolItem& rAttr ) const
{
    ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
    return( pTxtAttr && ((SwFmtFlyCnt&)rAttr).pTxtAttr &&
            *pTxtAttr->GetStart() == *((SwFmtFlyCnt&)rAttr).pTxtAttr->GetStart() &&
            pFmt == ((SwFmtFlyCnt&)rAttr).GetFrmFmt() );
}

SfxPoolItem* __EXPORT SwFmtFlyCnt::Clone( SfxItemPool* ) const
{
    return new SwFmtFlyCnt( pFmt );
}

SwTxtFlyCnt::SwTxtFlyCnt( const SwFmtFlyCnt& rAttr, xub_StrLen nStartPos )
    : SwTxtAttr( rAttr, nStartPos )
{
    ((SwFmtFlyCnt&)rAttr).pTxtAttr = this;
}

/*************************************************************************
 *                  SwTxtFlyCnt::MakeTxtHint()
 *
 * An dieser Stelle soll einmal der Gesamtzusammenhang bei der Erzeugung
 * eines neuen SwTxtFlyCnt erlaeutert werden.
 * Das MakeTxtHint() wird z.B. im SwTxtNode::Copy() gerufen.
 * Fuer die komplette Verdopplung sind folgende Schritte notwendig:
 * 1) Duplizieren des pFmt incl. Inhalt, Attributen etc.
 * 2) Setzen des Ankers
 * 3) Benachrichtigung
 * Da fuer die Bewaeltigung der Aufgaben nicht immer alle Informationen
 * bereitstehen und darueber hinaus bestimmte Methoden erst zu einem
 * spaeteren Zeitpunkt gerufen werden duerfen (weil nocht nicht alle
 * Nodeinformationen vorliegen), verteilt sich der Ablauf.
 * ad 1) MakeTxtHint() wird durch den Aufruf von SwDoc::CopyLayout()
 * der das neue FlyFrmFmt erzeugt und mit dem duplizierten Inhalt des
 * FlyFrm verbunden.
 * ad 2) SetAnchor() wird von SwTxtNode::Insert() gerufen und sorgt fuer das
 * setzen des Ankers (die SwPosition des Dummy-Zeichens wird dem FlyFrmFmt
 * per SetAttr bekannt gegeben). Dies kann nicht im MakeTxtHint erledigt
 * werden, da der Zielnode unbestimmt ist.
 * ad 3) _GetFlyFrm() wird im Formatierungsprozess vom LineIter gerufen
 * und sucht den FlyFrm zum Dummyzeichen des aktuellen CntntFrm. Wird keiner
 * gefunden, so wird ein neuer FlyFrm angelegt.
 * Kritisch an diesem Vorgehen ist, dass das pCntnt->AppendFly() eine
 * sofortige Neuformatierung von pCntnt anstoesst. Die Rekursion kommt
 * allerdings durch den Lockmechanismus in SwTxtFrm::Format() nicht
 * zu stande.
 * Attraktiv ist der Umstand, dass niemand ueber die vom Node abhaengigen
 * CntntFrms iterieren braucht, um die FlyInCntFrm anzulegen. Dies geschieht
 * bei der Arbeit.
 *************************************************************************/

void SwTxtFlyCnt::CopyFlyFmt( SwDoc* pDoc )
{
    SwFrmFmt* pFmt = GetFlyCnt().GetFrmFmt();
    ASSERT( pFmt, "von welchem Format soll ich eine Kopie erzeugen?" )
    // Das FlyFrmFmt muss dupliziert werden.
    // In CopyLayoutFmt (siehe doclay.cxx) wird das FlyFrmFmt erzeugt
    // und der Inhalt dupliziert.

    // fuers kopieren vom Attribut das Undo immer abschalten
    BOOL bUndo = pDoc->DoesUndo();
    pDoc->DoUndo( FALSE );
    SwFmtAnchor aAnchor( pFmt->GetAnchor() );
    if( FLY_PAGE != aAnchor.GetAnchorId() &&
        pDoc != pFmt->GetDoc() )        // Unterschiedliche Docs?
    {
        // JP 03.06.96: dann sorge dafuer, das der koperierte Anker auf
        //              gueltigen Content zeigt! Die Umsetzung auf die
        //              richtige Position erfolgt spaeter.
        SwNodeIndex aIdx( pDoc->GetNodes().GetEndOfExtras(), +2 );
        SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
        if( !pCNd )
            pCNd = pDoc->GetNodes().GoNext( &aIdx );

        SwPosition* pPos = (SwPosition*)aAnchor.GetCntntAnchor();
        pPos->nNode = aIdx;
        if( FLY_IN_CNTNT == aAnchor.GetAnchorId() )
            pPos->nContent.Assign( pCNd, 0 );
        else
        {
            pPos->nContent.Assign( 0, 0 );
            ASSERT( !this, "CopyFlyFmt: Was fuer ein Anker?" );
        }
    }

    SwFrmFmt* pNew = pDoc->CopyLayoutFmt( *pFmt, aAnchor, false, false );
    pDoc->DoUndo( bUndo );
    ((SwFmtFlyCnt&)GetFlyCnt()).SetFlyFmt( pNew );
}

/*************************************************************************
 *                  SwTxtFlyCnt::SetAnchor()
 *
 * SetAnchor() wird von SwTxtNode::Insert() gerufen und sorgt fuer das
 * setzen des Ankers (die SwPosition des Dummy-Zeichens wird dem FlyFrmFmt
 * per SetAttr bekannt gegeben). Dies kann nicht im MakeTxtHint erledigt
 * werden, da der Zielnode unbestimmt ist.
 * (siehe Kommentar in SwTxtFlyCnt::MakeTxtHint)
 *************************************************************************/

void SwTxtFlyCnt::SetAnchor( const SwTxtNode *pNode )
{
    // fuers Undo muss der neue Anker schon bekannt sein !

    // Wir ermitteln den Index im Nodesarray zum Node

    SwDoc* pDoc = (SwDoc*)pNode->GetDoc();

    SwIndex aIdx( (SwTxtNode*)pNode, *GetStart() );
    SwPosition aPos( *pNode->StartOfSectionNode(), aIdx );
    SwFrmFmt* pFmt = GetFlyCnt().GetFrmFmt();
    SwFmtAnchor aAnchor( pFmt->GetAnchor() );

    if( !aAnchor.GetCntntAnchor() ||
        !aAnchor.GetCntntAnchor()->nNode.GetNode().GetNodes().IsDocNodes() ||
        &aAnchor.GetCntntAnchor()->nNode.GetNode() != (SwNode*)pNode )
        aPos.nNode = *pNode;
    else
        aPos.nNode = aAnchor.GetCntntAnchor()->nNode;

    aAnchor.SetType( FLY_IN_CNTNT );        // defaulten !!
    aAnchor.SetAnchor( &aPos );

    // beim Ankerwechsel werden immer alle FlyFrms vom Attribut geloescht
    // JP 25.04.95: wird innerhalb des SplitNodes die Frames verschoben
    //              koennen die Frames erhalten bleiben.
    if( ( !pNode->GetpSwpHints() || !pNode->GetpSwpHints()->IsInSplitNode() )
        && RES_DRAWFRMFMT != pFmt->Which() )
        pFmt->DelFrms();

    // stehen wir noch im falschen Dokument ?
    if( pDoc != pFmt->GetDoc() )
    {
        // fuers kopieren vom Attribut das Undo immer abschalten
        BOOL bUndo = pDoc->DoesUndo();
        pDoc->DoUndo( FALSE );
        SwFrmFmt* pNew = pDoc->CopyLayoutFmt( *pFmt, aAnchor, false, false );
        pDoc->DoUndo( bUndo );

        bUndo = pFmt->GetDoc()->DoesUndo();
        pFmt->GetDoc()->DoUndo( FALSE );
        pFmt->GetDoc()->DelLayoutFmt( pFmt );
        pFmt->GetDoc()->DoUndo( bUndo );
        ((SwFmtFlyCnt&)GetFlyCnt()).SetFlyFmt( pNew );
    }
    else if( pNode->GetpSwpHints() &&
            pNode->GetpSwpHints()->IsInSplitNode() &&
            RES_DRAWFRMFMT != pFmt->Which() )
    {
        pFmt->LockModify();
        pFmt->SetAttr( aAnchor );       // nur den Anker neu setzen
        pFmt->UnlockModify();
    }
    else
        pFmt->SetAttr( aAnchor );       // nur den Anker neu setzen

    // Am Node haengen u.a. abhaengige CntFrms.
    // Fuer jeden CntFrm wird ein SwFlyInCntFrm angelegt.
}

/*************************************************************************
 *                      SwTxtFlyCnt::_GetFlyFrm()
 *
 * _GetFlyFrm() wird im Formatierungsprozess vom LineIter gerufen
 * und sucht den FlyFrm zum Dummyzeichen des aktuellen CntntFrm. Wird keiner
 * gefunden, so wird ein neuer FlyFrm angelegt.
 * (siehe Kommentar ind SwTxtFlyCnt::MakeTxtHint)
 *************************************************************************/

SwFlyInCntFrm *SwTxtFlyCnt::_GetFlyFrm( const SwFrm *pCurrFrm )
{
    SwFrmFmt* pFrmFmt = GetFlyCnt().GetFrmFmt();
    if( RES_DRAWFRMFMT == pFrmFmt->Which() )
    {
        ASSERT(  !this, "SwTxtFlyCnt::_GetFlyFrm: DrawInCnt-Baustelle!" );
        return NULL;
    }

    SwClientIter aIter( *GetFlyCnt().pFmt );
    ASSERT( pCurrFrm->IsTxtFrm(), "SwTxtFlyCnt::_GetFlyFrm for TxtFrms only." );

    if( aIter.GoStart() )
    {
        SwTxtFrm *pFirst = (SwTxtFrm*)pCurrFrm;
        while ( pFirst->IsFollow() )
            pFirst = pFirst->FindMaster();
        do
        {   SwFrm * pFrm = PTR_CAST( SwFrm, aIter() );
            if ( pFrm )
            {
                SwTxtFrm *pTmp = pFirst;
                do
                {   if( ( (SwFlyFrm*)pFrm )->GetAnchorFrm() == (SwFrm*) pTmp )
                    {
                        if ( pTmp != pCurrFrm )
                        {
                            pTmp->RemoveFly( (SwFlyFrm*)pFrm );
                            ((SwTxtFrm*)pCurrFrm)->AppendFly( (SwFlyFrm*)pFrm );
                        }
                        return (SwFlyInCntFrm*)pFrm;
                    }
                    pTmp = pTmp->GetFollow();
                } while ( pTmp );
            }
        } while( aIter++ );
    }

    // Wir haben keinen passenden FlyFrm gefunden, deswegen wird ein
    // neuer angelegt.
    // Dabei wird eine sofortige Neuformatierung von pCurrFrm angestossen.
    // Die Rekursion wird durch den Lockmechanismus in SwTxtFrm::Format()
    // abgewuergt.
    SwFlyInCntFrm *pFly = new SwFlyInCntFrm( (SwFlyFrmFmt*)pFrmFmt, (SwFrm*)pCurrFrm );
    ((SwFrm*)pCurrFrm)->AppendFly( pFly );
    pFly->RegistFlys();

    // 7922: Wir muessen dafuer sorgen, dass der Inhalt des FlyInCnt
    // nach seiner Konstruktion stramm durchformatiert wird.
    // --> OD 2004-11-09 #i26945# - Use new object formatter to format Writer
    // fly frame and its content.
    SwObjectFormatter::FormatObj( *pFly, const_cast<SwFrm*>(pCurrFrm),
                                  pCurrFrm->FindPageFrm() );
    // <--

    return pFly;
}

<commit_msg>INTEGRATION: CWS changefileheader (1.8.242); FILE MERGED 2008/04/01 12:54:27 thb 1.8.242.2: #i85898# Stripping all external header guards 2008/03/31 16:54:58 rt 1.8.242.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: atrflyin.cxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#include "hintids.hxx"
#include "cntfrm.hxx"       // _GetFly
#include "doc.hxx"
#include "pam.hxx"          // fuer SwTxtFlyCnt
#include "flyfrm.hxx"       // fuer SwTxtFlyCnt
#include "ndtxt.hxx"        // SwFlyFrmFmt
#include "frmfmt.hxx"       // SwFlyFrmFmt
#include <fmtflcnt.hxx>
#include <txtflcnt.hxx>
#include <fmtanchr.hxx>
#include "swfont.hxx"
#include "txtfrm.hxx"
#include "flyfrms.hxx"
// --> OD 2004-11-09 #i26945#
#include <objectformatter.hxx>
// <--

SwFmtFlyCnt::SwFmtFlyCnt( SwFrmFmt *pFrmFmt )
    : SfxPoolItem( RES_TXTATR_FLYCNT ),
    pTxtAttr( 0 ),
    pFmt( pFrmFmt )
{
}

int __EXPORT SwFmtFlyCnt::operator==( const SfxPoolItem& rAttr ) const
{
    ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
    return( pTxtAttr && ((SwFmtFlyCnt&)rAttr).pTxtAttr &&
            *pTxtAttr->GetStart() == *((SwFmtFlyCnt&)rAttr).pTxtAttr->GetStart() &&
            pFmt == ((SwFmtFlyCnt&)rAttr).GetFrmFmt() );
}

SfxPoolItem* __EXPORT SwFmtFlyCnt::Clone( SfxItemPool* ) const
{
    return new SwFmtFlyCnt( pFmt );
}

SwTxtFlyCnt::SwTxtFlyCnt( const SwFmtFlyCnt& rAttr, xub_StrLen nStartPos )
    : SwTxtAttr( rAttr, nStartPos )
{
    ((SwFmtFlyCnt&)rAttr).pTxtAttr = this;
}

/*************************************************************************
 *                  SwTxtFlyCnt::MakeTxtHint()
 *
 * An dieser Stelle soll einmal der Gesamtzusammenhang bei der Erzeugung
 * eines neuen SwTxtFlyCnt erlaeutert werden.
 * Das MakeTxtHint() wird z.B. im SwTxtNode::Copy() gerufen.
 * Fuer die komplette Verdopplung sind folgende Schritte notwendig:
 * 1) Duplizieren des pFmt incl. Inhalt, Attributen etc.
 * 2) Setzen des Ankers
 * 3) Benachrichtigung
 * Da fuer die Bewaeltigung der Aufgaben nicht immer alle Informationen
 * bereitstehen und darueber hinaus bestimmte Methoden erst zu einem
 * spaeteren Zeitpunkt gerufen werden duerfen (weil nocht nicht alle
 * Nodeinformationen vorliegen), verteilt sich der Ablauf.
 * ad 1) MakeTxtHint() wird durch den Aufruf von SwDoc::CopyLayout()
 * der das neue FlyFrmFmt erzeugt und mit dem duplizierten Inhalt des
 * FlyFrm verbunden.
 * ad 2) SetAnchor() wird von SwTxtNode::Insert() gerufen und sorgt fuer das
 * setzen des Ankers (die SwPosition des Dummy-Zeichens wird dem FlyFrmFmt
 * per SetAttr bekannt gegeben). Dies kann nicht im MakeTxtHint erledigt
 * werden, da der Zielnode unbestimmt ist.
 * ad 3) _GetFlyFrm() wird im Formatierungsprozess vom LineIter gerufen
 * und sucht den FlyFrm zum Dummyzeichen des aktuellen CntntFrm. Wird keiner
 * gefunden, so wird ein neuer FlyFrm angelegt.
 * Kritisch an diesem Vorgehen ist, dass das pCntnt->AppendFly() eine
 * sofortige Neuformatierung von pCntnt anstoesst. Die Rekursion kommt
 * allerdings durch den Lockmechanismus in SwTxtFrm::Format() nicht
 * zu stande.
 * Attraktiv ist der Umstand, dass niemand ueber die vom Node abhaengigen
 * CntntFrms iterieren braucht, um die FlyInCntFrm anzulegen. Dies geschieht
 * bei der Arbeit.
 *************************************************************************/

void SwTxtFlyCnt::CopyFlyFmt( SwDoc* pDoc )
{
    SwFrmFmt* pFmt = GetFlyCnt().GetFrmFmt();
    ASSERT( pFmt, "von welchem Format soll ich eine Kopie erzeugen?" )
    // Das FlyFrmFmt muss dupliziert werden.
    // In CopyLayoutFmt (siehe doclay.cxx) wird das FlyFrmFmt erzeugt
    // und der Inhalt dupliziert.

    // fuers kopieren vom Attribut das Undo immer abschalten
    BOOL bUndo = pDoc->DoesUndo();
    pDoc->DoUndo( FALSE );
    SwFmtAnchor aAnchor( pFmt->GetAnchor() );
    if( FLY_PAGE != aAnchor.GetAnchorId() &&
        pDoc != pFmt->GetDoc() )        // Unterschiedliche Docs?
    {
        // JP 03.06.96: dann sorge dafuer, das der koperierte Anker auf
        //              gueltigen Content zeigt! Die Umsetzung auf die
        //              richtige Position erfolgt spaeter.
        SwNodeIndex aIdx( pDoc->GetNodes().GetEndOfExtras(), +2 );
        SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
        if( !pCNd )
            pCNd = pDoc->GetNodes().GoNext( &aIdx );

        SwPosition* pPos = (SwPosition*)aAnchor.GetCntntAnchor();
        pPos->nNode = aIdx;
        if( FLY_IN_CNTNT == aAnchor.GetAnchorId() )
            pPos->nContent.Assign( pCNd, 0 );
        else
        {
            pPos->nContent.Assign( 0, 0 );
            ASSERT( !this, "CopyFlyFmt: Was fuer ein Anker?" );
        }
    }

    SwFrmFmt* pNew = pDoc->CopyLayoutFmt( *pFmt, aAnchor, false, false );
    pDoc->DoUndo( bUndo );
    ((SwFmtFlyCnt&)GetFlyCnt()).SetFlyFmt( pNew );
}

/*************************************************************************
 *                  SwTxtFlyCnt::SetAnchor()
 *
 * SetAnchor() wird von SwTxtNode::Insert() gerufen und sorgt fuer das
 * setzen des Ankers (die SwPosition des Dummy-Zeichens wird dem FlyFrmFmt
 * per SetAttr bekannt gegeben). Dies kann nicht im MakeTxtHint erledigt
 * werden, da der Zielnode unbestimmt ist.
 * (siehe Kommentar in SwTxtFlyCnt::MakeTxtHint)
 *************************************************************************/

void SwTxtFlyCnt::SetAnchor( const SwTxtNode *pNode )
{
    // fuers Undo muss der neue Anker schon bekannt sein !

    // Wir ermitteln den Index im Nodesarray zum Node

    SwDoc* pDoc = (SwDoc*)pNode->GetDoc();

    SwIndex aIdx( (SwTxtNode*)pNode, *GetStart() );
    SwPosition aPos( *pNode->StartOfSectionNode(), aIdx );
    SwFrmFmt* pFmt = GetFlyCnt().GetFrmFmt();
    SwFmtAnchor aAnchor( pFmt->GetAnchor() );

    if( !aAnchor.GetCntntAnchor() ||
        !aAnchor.GetCntntAnchor()->nNode.GetNode().GetNodes().IsDocNodes() ||
        &aAnchor.GetCntntAnchor()->nNode.GetNode() != (SwNode*)pNode )
        aPos.nNode = *pNode;
    else
        aPos.nNode = aAnchor.GetCntntAnchor()->nNode;

    aAnchor.SetType( FLY_IN_CNTNT );        // defaulten !!
    aAnchor.SetAnchor( &aPos );

    // beim Ankerwechsel werden immer alle FlyFrms vom Attribut geloescht
    // JP 25.04.95: wird innerhalb des SplitNodes die Frames verschoben
    //              koennen die Frames erhalten bleiben.
    if( ( !pNode->GetpSwpHints() || !pNode->GetpSwpHints()->IsInSplitNode() )
        && RES_DRAWFRMFMT != pFmt->Which() )
        pFmt->DelFrms();

    // stehen wir noch im falschen Dokument ?
    if( pDoc != pFmt->GetDoc() )
    {
        // fuers kopieren vom Attribut das Undo immer abschalten
        BOOL bUndo = pDoc->DoesUndo();
        pDoc->DoUndo( FALSE );
        SwFrmFmt* pNew = pDoc->CopyLayoutFmt( *pFmt, aAnchor, false, false );
        pDoc->DoUndo( bUndo );

        bUndo = pFmt->GetDoc()->DoesUndo();
        pFmt->GetDoc()->DoUndo( FALSE );
        pFmt->GetDoc()->DelLayoutFmt( pFmt );
        pFmt->GetDoc()->DoUndo( bUndo );
        ((SwFmtFlyCnt&)GetFlyCnt()).SetFlyFmt( pNew );
    }
    else if( pNode->GetpSwpHints() &&
            pNode->GetpSwpHints()->IsInSplitNode() &&
            RES_DRAWFRMFMT != pFmt->Which() )
    {
        pFmt->LockModify();
        pFmt->SetAttr( aAnchor );       // nur den Anker neu setzen
        pFmt->UnlockModify();
    }
    else
        pFmt->SetAttr( aAnchor );       // nur den Anker neu setzen

    // Am Node haengen u.a. abhaengige CntFrms.
    // Fuer jeden CntFrm wird ein SwFlyInCntFrm angelegt.
}

/*************************************************************************
 *                      SwTxtFlyCnt::_GetFlyFrm()
 *
 * _GetFlyFrm() wird im Formatierungsprozess vom LineIter gerufen
 * und sucht den FlyFrm zum Dummyzeichen des aktuellen CntntFrm. Wird keiner
 * gefunden, so wird ein neuer FlyFrm angelegt.
 * (siehe Kommentar ind SwTxtFlyCnt::MakeTxtHint)
 *************************************************************************/

SwFlyInCntFrm *SwTxtFlyCnt::_GetFlyFrm( const SwFrm *pCurrFrm )
{
    SwFrmFmt* pFrmFmt = GetFlyCnt().GetFrmFmt();
    if( RES_DRAWFRMFMT == pFrmFmt->Which() )
    {
        ASSERT(  !this, "SwTxtFlyCnt::_GetFlyFrm: DrawInCnt-Baustelle!" );
        return NULL;
    }

    SwClientIter aIter( *GetFlyCnt().pFmt );
    ASSERT( pCurrFrm->IsTxtFrm(), "SwTxtFlyCnt::_GetFlyFrm for TxtFrms only." );

    if( aIter.GoStart() )
    {
        SwTxtFrm *pFirst = (SwTxtFrm*)pCurrFrm;
        while ( pFirst->IsFollow() )
            pFirst = pFirst->FindMaster();
        do
        {   SwFrm * pFrm = PTR_CAST( SwFrm, aIter() );
            if ( pFrm )
            {
                SwTxtFrm *pTmp = pFirst;
                do
                {   if( ( (SwFlyFrm*)pFrm )->GetAnchorFrm() == (SwFrm*) pTmp )
                    {
                        if ( pTmp != pCurrFrm )
                        {
                            pTmp->RemoveFly( (SwFlyFrm*)pFrm );
                            ((SwTxtFrm*)pCurrFrm)->AppendFly( (SwFlyFrm*)pFrm );
                        }
                        return (SwFlyInCntFrm*)pFrm;
                    }
                    pTmp = pTmp->GetFollow();
                } while ( pTmp );
            }
        } while( aIter++ );
    }

    // Wir haben keinen passenden FlyFrm gefunden, deswegen wird ein
    // neuer angelegt.
    // Dabei wird eine sofortige Neuformatierung von pCurrFrm angestossen.
    // Die Rekursion wird durch den Lockmechanismus in SwTxtFrm::Format()
    // abgewuergt.
    SwFlyInCntFrm *pFly = new SwFlyInCntFrm( (SwFlyFrmFmt*)pFrmFmt, (SwFrm*)pCurrFrm );
    ((SwFrm*)pCurrFrm)->AppendFly( pFly );
    pFly->RegistFlys();

    // 7922: Wir muessen dafuer sorgen, dass der Inhalt des FlyInCnt
    // nach seiner Konstruktion stramm durchformatiert wird.
    // --> OD 2004-11-09 #i26945# - Use new object formatter to format Writer
    // fly frame and its content.
    SwObjectFormatter::FormatObj( *pFly, const_cast<SwFrm*>(pCurrFrm),
                                  pCurrFrm->FindPageFrm() );
    // <--

    return pFly;
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: graphics.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef GRAPHICS_HPP
#define GRAPHICS_HPP

#include <cmath>
#include <string>
#include <cassert>
#include "color.hpp"
#include "gamma.hpp"
#include "image_data.hpp"
#include "envelope.hpp"

namespace mapnik
{
    class MAPNIK_DECL Image32
    {
    private:
	unsigned width_;
	unsigned height_;
	Color background_;
	ImageData32 data_;
    public:
	Image32(int width,int height);
	Image32(const Image32& rhs);
	~Image32();
	void setBackground(const Color& background);
	const Color& getBackground() const;
	const ImageData32& data() const;
	inline ImageData32& data() {
	    return data_;
	}
	inline const unsigned char* raw_data() const
	{
	    return data_.getBytes();
	}

	inline unsigned char* raw_data()
	{
	    return data_.getBytes();
	}

	void saveToFile(const std::string& file,const std::string& format="auto");
    private:

	inline bool checkBounds(unsigned x, unsigned y) const
	{
	    return (x < width_ && y < height_);
	}

    public:
	inline void setPixel(int x,int y,unsigned int rgba)
	{
	    if (checkBounds(x,y))
	    {
		data_(x,y)=rgba;
	    }
	}
	inline void blendPixel(int x,int y,unsigned int rgba1,int t)
	{
	    if (checkBounds(x,y))
	    {
		unsigned rgba0 = data_(x,y);
		unsigned a1 = t;//(rgba1 >> 24) & 0xff;
		if (a1 == 0) return;
		unsigned r1 = rgba1 & 0xff;
		unsigned g1 = (rgba1 >> 8 ) & 0xff;
		unsigned b1 = (rgba1 >> 16) & 0xff;

		unsigned a0 = (rgba0 >> 24) & 0xff;
		unsigned r0 = (rgba0 & 0xff) * a0;
		unsigned g0 = ((rgba0 >> 8 ) & 0xff) * a0;
		unsigned b0 = ((rgba0 >> 16) & 0xff) * a0;

		a0 = ((a1 + a0) << 8) - a0*a1;

		r0 = ((((r1 << 8) - r0) * a1 + (r0 << 8)) / a0);
		g0 = ((((g1 << 8) - g0) * a1 + (g0 << 8)) / a0);
		b0 = ((((b1 << 8) - b0) * a1 + (b0 << 8)) / a0);
		a0 = a0 >> 8;
		data_(x,y)= (a0 << 24)| (b0 << 16) |  (g0 << 8) | (r0) ;
	    }
	}

	inline unsigned width() const
	{
	    return width_;
	}

	inline unsigned height() const
	{
	    return height_;
	}

	inline void set_rectangle(int x0,int y0,ImageData32 const& data)
	{
	    Envelope<int> ext0(0,0,width_,height_);
	    Envelope<int> ext1(x0,y0,x0+data.width(),y0+data.height());

	    if (ext0.intersects(ext1))
	    {
		Envelope<int> box = ext0.intersect(ext1);
		for (int y = box.miny(); y < box.maxy(); ++y)
		{
		    for (int x = box.minx(); x < box.maxx(); ++x)
		    {
			if ((data(x-x0,y-y0) & 0xff000000))
			{
			    data_(x,y)=data(x-x0,y-y0);
			}
		    }
		}
	    }
	}

	inline void set_rectangle_alpha(int x0,int y0,const ImageData32& data)
	{
	    Envelope<int> ext0(0,0,width_,height_);
	    Envelope<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());

	    if (ext0.intersects(ext1))
	    {
		Envelope<int> box = ext0.intersect(ext1);
		for (int y = box.miny(); y < box.maxy(); ++y)
		{
		    for (int x = box.minx(); x < box.maxx(); ++x)
		    {
			unsigned rgba0 = data_(x,y);
			unsigned rgba1 = data(x-x0,y-y0);

			unsigned a1 = (rgba1 >> 24) & 0xff;
			if (a1 == 0) continue;
			unsigned r1 = rgba1 & 0xff;
			unsigned g1 = (rgba1 >> 8 ) & 0xff;
			unsigned b1 = (rgba1 >> 16) & 0xff;

			unsigned a0 = (rgba0 >> 24) & 0xff;
			unsigned r0 = (rgba0 & 0xff) * a0;
			unsigned g0 = ((rgba0 >> 8 ) & 0xff) * a0;
			unsigned b0 = ((rgba0 >> 16) & 0xff) * a0;

			a0 = ((a1 + a0) << 8) - a0*a1;

			r0 = ((((r1 << 8) - r0) * a1 + (r0 << 8)) / a0);
			g0 = ((((g1 << 8) - g0) * a1 + (g0 << 8)) / a0);
			b0 = ((((b1 << 8) - b0) * a1 + (b0 << 8)) / a0);
			a0 = a0 >> 8;
			data_(x,y)= (a0 << 24)| (b0 << 16) |  (g0 << 8) | (r0) ;
		    }
		}
	    }
	}
    };
}
#endif //GRAPHICS_HPP
<commit_msg>replaced tabs with spaces<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: graphics.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef GRAPHICS_HPP
#define GRAPHICS_HPP

#include <cmath>
#include <string>
#include <cassert>
#include "color.hpp"
#include "gamma.hpp"
#include "image_data.hpp"
#include "envelope.hpp"

namespace mapnik
{
    class MAPNIK_DECL Image32
    {
    private:
        unsigned width_;
        unsigned height_;
        Color background_;
        ImageData32 data_;
    public:
        Image32(int width,int height);
        Image32(const Image32& rhs);
        ~Image32();
        void setBackground(const Color& background);
        const Color& getBackground() const;
        const ImageData32& data() const;
        inline ImageData32& data() {
            return data_;
        }
        inline const unsigned char* raw_data() const
        {
            return data_.getBytes();
        }

        inline unsigned char* raw_data()
        {
            return data_.getBytes();
        }

        void saveToFile(const std::string& file,const std::string& format="auto");
    private:

        inline bool checkBounds(unsigned x, unsigned y) const
        {
            return (x < width_ && y < height_);
        }

    public:
        inline void setPixel(int x,int y,unsigned int rgba)
        {
            if (checkBounds(x,y))
            {
                data_(x,y)=rgba;
            }
        }
        inline void blendPixel(int x,int y,unsigned int rgba1,int t)
        {
            if (checkBounds(x,y))
            {
                unsigned rgba0 = data_(x,y);
                unsigned a1 = t;//(rgba1 >> 24) & 0xff;
                if (a1 == 0) return;
                unsigned r1 = rgba1 & 0xff;
                unsigned g1 = (rgba1 >> 8 ) & 0xff;
                unsigned b1 = (rgba1 >> 16) & 0xff;

                unsigned a0 = (rgba0 >> 24) & 0xff;
                unsigned r0 = (rgba0 & 0xff) * a0;
                unsigned g0 = ((rgba0 >> 8 ) & 0xff) * a0;
                unsigned b0 = ((rgba0 >> 16) & 0xff) * a0;

                a0 = ((a1 + a0) << 8) - a0*a1;

                r0 = ((((r1 << 8) - r0) * a1 + (r0 << 8)) / a0);
                g0 = ((((g1 << 8) - g0) * a1 + (g0 << 8)) / a0);
                b0 = ((((b1 << 8) - b0) * a1 + (b0 << 8)) / a0);
                a0 = a0 >> 8;
                data_(x,y)= (a0 << 24)| (b0 << 16) |  (g0 << 8) | (r0) ;
            }
        }

        inline unsigned width() const
        {
            return width_;
        }

        inline unsigned height() const
        {
            return height_;
        }

        inline void set_rectangle(int x0,int y0,ImageData32 const& data)
        {
            Envelope<int> ext0(0,0,width_,height_);
            Envelope<int> ext1(x0,y0,x0+data.width(),y0+data.height());

            if (ext0.intersects(ext1))
            {
                Envelope<int> box = ext0.intersect(ext1);
                for (int y = box.miny(); y < box.maxy(); ++y)
                {
                    for (int x = box.minx(); x < box.maxx(); ++x)
                    {
                        if ((data(x-x0,y-y0) & 0xff000000))
                        {
                            data_(x,y)=data(x-x0,y-y0);
                        }
                    }
                }
            }
        }

        inline void set_rectangle_alpha(int x0,int y0,const ImageData32& data)
        {
            Envelope<int> ext0(0,0,width_,height_);
            Envelope<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());

            if (ext0.intersects(ext1))
            {
                Envelope<int> box = ext0.intersect(ext1);
                for (int y = box.miny(); y < box.maxy(); ++y)
                {
                    for (int x = box.minx(); x < box.maxx(); ++x)
                    {
                        unsigned rgba0 = data_(x,y);
                        unsigned rgba1 = data(x-x0,y-y0);

                        unsigned a1 = (rgba1 >> 24) & 0xff;
                        if (a1 == 0) continue;
                        unsigned r1 = rgba1 & 0xff;
                        unsigned g1 = (rgba1 >> 8 ) & 0xff;
                        unsigned b1 = (rgba1 >> 16) & 0xff;

                        unsigned a0 = (rgba0 >> 24) & 0xff;
                        unsigned r0 = (rgba0 & 0xff) * a0;
                        unsigned g0 = ((rgba0 >> 8 ) & 0xff) * a0;
                        unsigned b0 = ((rgba0 >> 16) & 0xff) * a0;

                        a0 = ((a1 + a0) << 8) - a0*a1;

                        r0 = ((((r1 << 8) - r0) * a1 + (r0 << 8)) / a0);
                        g0 = ((((g1 << 8) - g0) * a1 + (g0 << 8)) / a0);
                        b0 = ((((b1 << 8) - b0) * a1 + (b0 << 8)) / a0);
                        a0 = a0 >> 8;
                        data_(x,y)= (a0 << 24)| (b0 << 16) |  (g0 << 8) | (r0) ;
                    }
                }
            }
        }
    };
}
#endif //GRAPHICS_HPP
<|endoftext|>


<commit_before>#include "./headers/Book.h"

/*!
    \fn Book::Book()
    \brief Constructor sets book position to 0,0,0
    Constructor which initialises all the required data members for the class
*/
Book::Book(){
    this->x = 0;
    this->y = 0;
    this->z = 0;
    this->width = BOOK_WIDTH;
    this->height = BOOK_HEIGHT;
    this->noOfPages = 0;
    this->pages = new Page*[MAX_NO_PAGES];
    this->currentPageIndex = 0;
}

/*!
    \fn Book::renderBook()
    \brief Render the book.
    Render the Book with the margin and border on the screen.
*/
void Book::renderBook(){
    int i=0;
    glColor3f(0.0,0.0,0.0);
    setBorder();
}

/*!
    \fn Book::setBorder()
    \brief Set Page Border
    Set the page border based on the size mentioned in the config/constants file.
    Render a 3d image for the book.
*/
void Book::setBorder(){
    glColor3f(0,0,0);
    GLfloat xLimit = x + width;
    GLfloat yLimit = y + height;
    GLfloat zLimit = z - BOOK_THICKNESS;
    cubeConstruction(x, y, z, xLimit, yLimit, zLimit);
    glColor3f(1,1,1);
    fillFaces(xLimit, yLimit, zLimit);
}

/*!
    \fn Book::addPage(GLint type, char s[])
    \brief Add a new Page
    Add a text page to the book by creating a new page from Page class and storing that as
    a page in the created Book object.
    type -> Page type
    s -> String to be rendered onto the page
*/
void Book::addPage(GLint type, char s[]){
    pages[noOfPages] = new Page(type, (x + BOOK_BORDER_SIZE), y + BOOK_BORDER_SIZE, -(noOfPages * (PAGE_THICKNESS + PAGE_GAP)), s);
    noOfPages++;
}

/*!
    \fn Book::addPage(GLint type, void (*pageContent)(GLfloat, GLfloat, GLfloat, GLfloat, GLfloat))
    \brief Add a new Page
    Add a drawing page to the book by creating a new page from Page class and storing that as
    a page in the created Book object.
    type -> Page type
    pageContent -> function pointer which renders the drawing inside the Page.
*/
void Book::addPage(GLint type, void (*pageContent)(GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)){
    pages[noOfPages] = new Page(type, (x + BOOK_BORDER_SIZE), y + BOOK_BORDER_SIZE, -(noOfPages * (PAGE_THICKNESS + PAGE_GAP)), pageContent);
    noOfPages++;
}

/*!
    \fn Book::renderPage()
    \brief Render the Page constructed
    Render the Page pointed by the currentPageIndex.
*/
void Book::renderPage(){
    pages[currentPageIndex]->renderPage();
}

/*!
    \fn Book::renderPage(GLint pageIndex)
    \brief Render the Page constructed
    Render the specified page in the book.
*/
void Book::renderPage(GLint pageIndex){
    if(pageIndex<noOfPages){
        pages[pageIndex]->renderPage();
        currentPageIndex = pageIndex;
    }
}

/*!
    \fn constructPolygon()
    \brief Construct a Polygon for the given vertices
*/
void constructPolygon(GLfloat vertices[][3]){
    glBegin(GL_POLYGON);
        for(int i=0;i<4;i++){
            glVertex3f(vertices[i][0],vertices[i][1],vertices[i][2]);
            glNormal3f(vertices[i][0],vertices[i][1],vertices[i][2]);
        }
    glEnd();
}

/*!
    \fn fillFaces()
    \brief Select each face and construct a Polygon
*/
void Book::fillFaces(GLfloat xLimit, GLfloat yLimit, GLfloat zLimit){
    GLfloat backFace[][3]={
        {x, y, zLimit}, {xLimit, y, zLimit}, {xLimit, yLimit, zLimit}, {x, yLimit, zLimit}
    };
    constructPolygon(backFace);
    GLfloat bottomFace[][3]={
        {x,y,z},{xLimit,y,z},{xLimit,y,zLimit},{x,y,zLimit}
    };
    constructPolygon(bottomFace);
    GLfloat topFace[][3]={
        {x,yLimit,z},{xLimit,yLimit,z},{xLimit,yLimit,zLimit},{x,yLimit,zLimit}
    };
    constructPolygon(topFace);
    GLfloat leftFace[][3]={
        {x,y,z},{x,yLimit,z},{x,yLimit,zLimit},{x,y,zLimit}
    };
    constructPolygon(leftFace);
    GLfloat rightFace[][3]={
        {xLimit,y,zLimit},{xLimit,yLimit,zLimit},{xLimit,yLimit,z},{xLimit,yLimit,z}
    };
    constructPolygon(rightFace);
}<commit_msg>Colouring the Book edges for 360 deg viewing<commit_after>#include "./headers/Book.h"

/*!
    \fn Book::Book()
    \brief Constructor sets book position to 0,0,0
    Constructor which initialises all the required data members for the class
*/
Book::Book(){
    this->x = 0;
    this->y = 0;
    this->z = 0;
    this->width = BOOK_WIDTH;
    this->height = BOOK_HEIGHT;
    this->noOfPages = 0;
    this->pages = new Page*[MAX_NO_PAGES];
    this->currentPageIndex = 0;
}

/*!
    \fn Book::renderBook()
    \brief Render the book.
    Render the Book with the margin and border on the screen.
*/
void Book::renderBook(){
    int i=0;
    glColor3f(0.0,0.0,0.0);
    setBorder();
}

/*!
    \fn Book::setBorder()
    \brief Set Page Border
    Set the page border based on the size mentioned in the config/constants file.
    Render a 3d image for the book.
*/
void Book::setBorder(){
    glColor3f(0,0,0);
    GLfloat xLimit = x + width;
    GLfloat yLimit = y + height;
    GLfloat zLimit = z - BOOK_THICKNESS;
    cubeConstruction(x, y, z, xLimit, yLimit, zLimit);
    glColor3f(1,1,1);
    fillFaces(xLimit, yLimit, zLimit);
}

/*!
    \fn Book::addPage(GLint type, char s[])
    \brief Add a new Page
    Add a text page to the book by creating a new page from Page class and storing that as
    a page in the created Book object.
    type -> Page type
    s -> String to be rendered onto the page
*/
void Book::addPage(GLint type, char s[]){
    pages[noOfPages] = new Page(type, (x + BOOK_BORDER_SIZE), y + BOOK_BORDER_SIZE, -(noOfPages * (PAGE_THICKNESS + PAGE_GAP)), s);
    noOfPages++;
}

/*!
    \fn Book::addPage(GLint type, void (*pageContent)(GLfloat, GLfloat, GLfloat, GLfloat, GLfloat))
    \brief Add a new Page
    Add a drawing page to the book by creating a new page from Page class and storing that as
    a page in the created Book object.
    type -> Page type
    pageContent -> function pointer which renders the drawing inside the Page.
*/
void Book::addPage(GLint type, void (*pageContent)(GLfloat, GLfloat, GLfloat, GLfloat, GLfloat)){
    pages[noOfPages] = new Page(type, (x + BOOK_BORDER_SIZE), y + BOOK_BORDER_SIZE, -(noOfPages * (PAGE_THICKNESS + PAGE_GAP)), pageContent);
    noOfPages++;
}

/*!
    \fn Book::renderPage()
    \brief Render the Page constructed
    Render the Page pointed by the currentPageIndex.
*/
void Book::renderPage(){
    pages[currentPageIndex]->renderPage();
}

/*!
    \fn Book::renderPage(GLint pageIndex)
    \brief Render the Page constructed
    Render the specified page in the book.
*/
void Book::renderPage(GLint pageIndex){
    if(pageIndex<noOfPages){
        pages[pageIndex]->renderPage();
        currentPageIndex = pageIndex;
    }
}

/*!
    \fn constructPolygon()
    \brief Construct a Polygon for the given vertices
*/
void constructPolygon(GLfloat vertices[][3]){
    glBegin(GL_POLYGON);
        for(int i=0;i<4;i++){
            glVertex3f(vertices[i][0],vertices[i][1],vertices[i][2]);
            glNormal3f(vertices[i][0],vertices[i][1],vertices[i][2]);
        }
    glEnd();
}

/*!
    \fn fillFaces()
    \brief Select each face and construct a Polygon
*/
void Book::fillFaces(GLfloat xLimit, GLfloat yLimit, GLfloat zLimit){
    glColor3f(0.5,0,0.5);
    GLfloat backFace[][3]={
        {x, y, zLimit}, {xLimit, y, zLimit}, {xLimit, yLimit, zLimit}, {x, yLimit, zLimit}
    };
    constructPolygon(backFace);
    GLfloat bottomFace[][3]={
        {x,y,z},{xLimit,y,z},{xLimit,y,zLimit},{x,y,zLimit}
    };
    constructPolygon(bottomFace);
    GLfloat topFace[][3]={
        {x,yLimit,z},{xLimit,yLimit,z},{xLimit,yLimit,zLimit},{x,yLimit,zLimit}
    };
    constructPolygon(topFace);
    GLfloat leftFace[][3]={
        {x,y,z},{x,yLimit,z},{x,yLimit,zLimit},{x,y,zLimit}
    };
    constructPolygon(leftFace);
    GLfloat rightFace[][3]={
        {xLimit,y,zLimit},{xLimit,yLimit,zLimit},{xLimit,yLimit,z},{xLimit,yLimit,z}
    };
    constructPolygon(rightFace);
    glColor3f(1,1,1);
}<|endoftext|>


<commit_before>#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("hello world!\n");
    printf("show me the code\n");
    printf("Talk is cheap\n");
    sleep(100);
    // this is first branch.
    return 0;
}

<commit_msg>second line<commit_after>#include <stdio.h>
#include <unistd.h>

int main()
{
    printf("hello world!\n");
    printf("show me the code\n");
    printf("Talk is cheap\n");
    sleep(100);
    // this is first branch.

    // this is the second line.
    return 0;
}

<|endoftext|>


<commit_before>#include "city.h"
#include "../../framework/data.h"

#include <iostream>

std::unique_ptr<City> City::city;

City::City(std::string mapName)
	: sizeX(100), sizeY(100), sizeZ(100)
{
	auto file = DATA->load_file("ufodata/" + mapName, "r");
	if (!file)
	{
		std::cerr << "Failed to open city map:" << mapName << "\n";
		return;
	}

	tiles.resize(sizeZ);

	for (int z = 0; z < sizeZ; z++)
	{
		tiles[z].resize(sizeY);
		for (int y = 0; y < sizeY; y++)
		{
			tiles[z][y].resize(sizeX);
			for (int x = 0; x < sizeX; x++)
			{
				int16_t tileID = al_fread16le(file);
				tiles[z][y][x] = CityTile(tileID);
			}
		}
	}

	al_fclose(file);
}

City::~City()
{

}

CityTile::CityTile(int id)
	: id(id)
{
}
<commit_msg>Citymap is 10 high, not 100<commit_after>#include "city.h"
#include "../../framework/data.h"

#include <iostream>

std::unique_ptr<City> City::city;

City::City(std::string mapName)
	: sizeX(100), sizeY(100), sizeZ(10)
{
	auto file = DATA->load_file("ufodata/" + mapName, "r");
	if (!file)
	{
		std::cerr << "Failed to open city map:" << mapName << "\n";
		return;
	}

	tiles.resize(sizeZ);

	for (int z = 0; z < sizeZ; z++)
	{
		tiles[z].resize(sizeY);
		for (int y = 0; y < sizeY; y++)
		{
			tiles[z][y].resize(sizeX);
			for (int x = 0; x < sizeX; x++)
			{
				int16_t tileID = al_fread16le(file);
				if (tileID == -1 &&
				    al_feof(file))
				{
					std::cerr << "Unexpected EOF reading citymap at x="
						<< x << " y = " << y << " z = " << z << "\n";
					al_fclose(file);
					return;
				}
				tiles[z][y][x] = CityTile(tileID);
			}
		}
	}

	al_fclose(file);
}

City::~City()
{

}

CityTile::CityTile(int id)
	: id(id)
{
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <cstdarg>
#include <algorithm>
#include <iostream>
#include "chunk.hh"
#include "compiler.hh"
#include "vm.hh"

namespace tadpole {

class CallFrame final : public Copyable {
  ClosureObject* closure_{};
  const u8_t* ip_{};
  sz_t stack_begpos_{};
public:
  CallFrame() noexcept {}
  CallFrame(ClosureObject* c, const u8_t* i, sz_t begpos = 0) noexcept
    : closure_(c), ip_(i), stack_begpos_(begpos) {
  }

  inline ClosureObject* closure() const noexcept { return closure_; }
  inline FunctionObject* frame_fn() const noexcept { return closure_->fn(); }
  inline Chunk* frame_chunk() const noexcept { return frame_fn()->chunk(); }
  inline const u8_t* ip() const noexcept { return ip_; }
  inline u8_t get_ip(sz_t i) const noexcept { return ip_[i]; }
  inline u8_t inc_ip() noexcept { return *ip_++; }
  inline u8_t dec_ip() noexcept { return *ip_--; }
  inline sz_t stack_begpos() const noexcept { return stack_begpos_; }
};

VM::VM() noexcept {
  gcompiler_ = new GlobalCompiler();
  stack_.reserve(kDefaultCap);

  // TODO: register built-in functions
}

VM::~VM() {
  delete gcompiler_;

  globals_.clear();
  interned_strings_.clear();

  while (!objects_.empty()) {
    auto* o = objects_.back();
    objects_.pop_back();

    reclaim_object(o);
  }
}

void VM::define_native(const str_t& name, NativeFn&& fn) {
  globals_[name] = NativeObject::create(*this, std::move(fn));
}

void VM::append_object(BaseObject* o) {
  if (objects_.size() >= kGCThreshold)
    collect();

  objects_.push_back(o);
}

void VM::mark_object(BaseObject* o) {
  if (o == nullptr || o->is_marked())
    return;

#if defined(_TADPOLE_DEBUG_GC)
  std::cout << "[" << o << "] mark object: `" << o->stringify() << "`" << std::endl;
#endif

  o->set_marked(true);
  worklist_.push_back(o);
}

void VM::mark_value(const Value& v) {
  if (v.is_object())
    mark_object(v.as_object());
}

InterpretRet VM::interpret(const str_t& source_bytes) {
  FunctionObject* fn = gcompiler_->compile(*this, source_bytes);
  if (fn == nullptr)
    return InterpretRet::ECOMPILE;

  push(fn);
  ClosureObject* closure = ClosureObject::create(*this, fn);
  pop();
  call(closure, 0);

  return run();
}

void VM::collect() {
  // mark root objects
  gcompiler_->mark_compiler();
  for (auto& v : stack_)
    mark_value(v);
  for (auto& f : frames_)
    mark_object(f.closure());
  for (auto& g : globals_)
    mark_value(g.second);
  for (auto* u = open_upvalues_; u != nullptr; u = u->next())
    mark_object(u);

  // mark reference objects
  while (!worklist_.empty()) {
    auto* o = worklist_.back();
    worklist_.pop_back();
    o->gc_blacken(*this);
  }

  // delete unmarked interned string objects
  for (auto it = interned_strings_.begin(); it != interned_strings_.end();) {
    if (!it->second->is_marked())
      interned_strings_.erase(it++);
    else
      ++it;
  }

  // sweep and reclaim unmarked objects
  for (auto it = objects_.begin(); it != objects_.end();) {
    if (!(*it)->is_marked()) {
      reclaim_object(*it);
      objects_.erase(it++);
    }
    else {
      (*it)->set_marked(false);
      ++it;
    }
  }

  gc_threshold_ = std::max(kGCThreshold, objects_.size() * kGCFactor);
}

void VM::reclaim_object(BaseObject* o) {
#if defined(_TADPOLE_DEBUG_GC)
  std::cout << "[" << o << "] reclaim object: `" << o->stringify() << "`" << std::endl;
#endif

  delete o;
}

void VM::reset() {
  stack_.clear();
  frames_.clear();
  open_upvalues_ = nullptr;
}

void VM::runtime_error(const char* format, ...) {
  std::cerr << "Traceback (most recent call last):" << std::endl;
  for (auto it = frames_.rbegin(); it != frames_.rend(); ++it) {
    auto& frame = *it;

    sz_t i = frame.frame_chunk()->offset(frame.ip()) - 1;
    std::cerr
      << "  [LINE: " << frame.frame_chunk()->get_line(i) << "] in "
      << "`" << frame.frame_fn()->name_asstr() << "()`"
      << std::endl;
  }

  va_list ap;
  va_start(ap, format);
  std::vfprintf(stderr, format, ap);
  va_end(ap);
  std::fprintf(stderr, "\n");

  reset();
}

void VM::push(Value value) noexcept {
  stack_.push_back(value);
}

Value VM::pop() noexcept {
  Value value = stack_.back();
  stack_.pop_back();
  return value;
}

const Value& VM::peek(sz_t distance) const noexcept {
  return stack_[stack_.size() - 1 - distance];
}

bool VM::call(ClosureObject* closure, sz_t argc) {
  FunctionObject* fn = closure->fn();
  if (fn->arity() != argc) {
    runtime_error("%s() takes exactly %ud arguments (%ud given)",
        fn->name_asstr(), fn->arity(), argc);
    return false;
  }

  frames_.push_back(CallFrame(closure, fn->chunk()->codes(), stack_.size() - argc - 1));
  return true;
}

bool VM::call(const Value& callee, sz_t argc) {
  if (callee.is_object()) {
    switch (callee.objtype()) {
    case ObjType::NATIVE:
      {
        Value* args = nullptr;
        if (argc > 0 && stack_.size() > argc)
          args = &stack_[stack_.size() - argc];

        Value result = callee.as_native()->fn()(argc, args);
        stack_.resize(stack_.size() - argc - 1);
        push(result);

        return true;
      }
    case ObjType::CLOSURE: return call(callee.as_closure(), argc);
    }
  }

  runtime_error("can only call function");
  return false;
}

UpvalueObject* VM::capture_upvalue(Value* local) {
  if (open_upvalues_ == nullptr) {
    open_upvalues_ = UpvalueObject::create(*this, local);
    return open_upvalues_;
  }

  UpvalueObject* upvalue = open_upvalues_;
  UpvalueObject* prev_upvalue = nullptr;
  while (upvalue != nullptr && upvalue->value() > local) {
    prev_upvalue = upvalue;
    upvalue = upvalue->next();
  }
  if (upvalue != nullptr && upvalue->value() == local)
    return upvalue;

  UpvalueObject* new_upvalue = UpvalueObject::create(*this, local, upvalue);
  if (prev_upvalue == nullptr)
    open_upvalues_ = new_upvalue;
  else
    prev_upvalue->set_next(new_upvalue);
  return new_upvalue;
}

void VM::close_upvalues(Value* last) {
  while (open_upvalues_ != nullptr && open_upvalues_->value() >= last) {
    UpvalueObject* upvalue = open_upvalues_;
    upvalue->set_closed(upvalue->value_asref());
    upvalue->set_value(upvalue->closed_asptr());

    open_upvalues_ = upvalue->next();
  }
}

InterpretRet VM::run() {
  CallFrame* frame = &frames_.back();

#define _RDBYTE()   frame->inc_ip()
#define _RDCONST()  frame->frame_chunk()->get_constant(_RDBYTE())
#define _RDSTR()    _RDCONST().as_string()
#define _RDCSTR()   _RDCONST().as_cstring()
#define _BINOP(op)  do {\
    if (!peek(0).is_numeric() || !peek(1).is_numeric()) {\
      runtime_error("operands must be two numerics");\
      return InterpretRet::ERUNTIME;\
    }\
    double b = pop().as_numeric();\
    double a = pop().as_numeric();\
    push(a op b);\
  } while (false)

  for (;;) {
#if defined(_TADPOLE_DEBUG_VM)
    auto* frame_chunk = frame->frame_chunk();
    std::cout << "          ";
    for (auto& v : stack_)
      std::cout << "[" << v << "]";
    std::cout << std::endl;
    frame_chunk->dis_code(frame_chunk->offset(frame->ip()));
#endif

    switch (Code c = as_type<Code>(_RDBYTE())) {
    case Code::CONSTANT: push(_RDCONST()); break;
    case Code::NIL: push(nullptr); break;
    case Code::FALSE: push(false); break;
    case Code::TRUE: push(true); break;
    case Code::POP: pop(); break;
    case Code::DEF_GLOBAL:
      {
        const char* name = _RDCSTR();
        if (auto it = globals_.find(name); it != globals_.end()) {
          runtime_error("name `%s` is redefined", name);
          return InterpretRet::ERUNTIME;
        }
        else {
          globals_[name] = pop();
        }
      } break;
    case Code::GET_GLOBAL:
      {
        const char* name = _RDCSTR();
        if (auto it = globals_.find(name); it != globals_.end()) {
          push(it->second);
        }
        else {
          runtime_error("name `%s` is not defined", name);
          return InterpretRet::ERUNTIME;
        }
      } break;
    case Code::SET_GLOBAL:
      {
        const char* name = _RDCSTR();
        if (auto it = globals_.find(name); it != globals_.end()) {
          it->second = peek();
        }
        else {
          runtime_error("name `%s` is not defined", name);
          return InterpretRet::ERUNTIME;
        }
      } break;
    case Code::GET_LOCAL: push(stack_[frame->stack_begpos() + _RDBYTE()]); break;
    case Code::SET_LOCAL: stack_[frame->stack_begpos() + _RDBYTE()] = peek(); break;
    case Code::GET_UPVALUE:
      {
        u8_t slot = _RDBYTE();
        push(frame->closure()->get_upvalue(slot)->value_asref());
      } break;
    case Code::SET_UPVALUE:
      {
        u8_t slot = _RDBYTE();
        frame->closure()->get_upvalue(slot)->set_value(peek());
      } break;
    }
  }

#undef _BINOP
#undef _RDCSTR
#undef _RDSTR
#undef _RDCONST
#undef _RDBYTE

  return InterpretRet::OK;
}

}
<commit_msg>:constuction: chore(vm): updated the vm code implementation about calc<commit_after>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <cstdarg>
#include <algorithm>
#include <iostream>
#include "chunk.hh"
#include "compiler.hh"
#include "vm.hh"

namespace tadpole {

class CallFrame final : public Copyable {
  ClosureObject* closure_{};
  const u8_t* ip_{};
  sz_t stack_begpos_{};
public:
  CallFrame() noexcept {}
  CallFrame(ClosureObject* c, const u8_t* i, sz_t begpos = 0) noexcept
    : closure_(c), ip_(i), stack_begpos_(begpos) {
  }

  inline ClosureObject* closure() const noexcept { return closure_; }
  inline FunctionObject* frame_fn() const noexcept { return closure_->fn(); }
  inline Chunk* frame_chunk() const noexcept { return frame_fn()->chunk(); }
  inline const u8_t* ip() const noexcept { return ip_; }
  inline u8_t get_ip(sz_t i) const noexcept { return ip_[i]; }
  inline u8_t inc_ip() noexcept { return *ip_++; }
  inline u8_t dec_ip() noexcept { return *ip_--; }
  inline sz_t stack_begpos() const noexcept { return stack_begpos_; }
};

VM::VM() noexcept {
  gcompiler_ = new GlobalCompiler();
  stack_.reserve(kDefaultCap);

  // TODO: register built-in functions
}

VM::~VM() {
  delete gcompiler_;

  globals_.clear();
  interned_strings_.clear();

  while (!objects_.empty()) {
    auto* o = objects_.back();
    objects_.pop_back();

    reclaim_object(o);
  }
}

void VM::define_native(const str_t& name, NativeFn&& fn) {
  globals_[name] = NativeObject::create(*this, std::move(fn));
}

void VM::append_object(BaseObject* o) {
  if (objects_.size() >= kGCThreshold)
    collect();

  objects_.push_back(o);
}

void VM::mark_object(BaseObject* o) {
  if (o == nullptr || o->is_marked())
    return;

#if defined(_TADPOLE_DEBUG_GC)
  std::cout << "[" << o << "] mark object: `" << o->stringify() << "`" << std::endl;
#endif

  o->set_marked(true);
  worklist_.push_back(o);
}

void VM::mark_value(const Value& v) {
  if (v.is_object())
    mark_object(v.as_object());
}

InterpretRet VM::interpret(const str_t& source_bytes) {
  FunctionObject* fn = gcompiler_->compile(*this, source_bytes);
  if (fn == nullptr)
    return InterpretRet::ECOMPILE;

  push(fn);
  ClosureObject* closure = ClosureObject::create(*this, fn);
  pop();
  call(closure, 0);

  return run();
}

void VM::collect() {
  // mark root objects
  gcompiler_->mark_compiler();
  for (auto& v : stack_)
    mark_value(v);
  for (auto& f : frames_)
    mark_object(f.closure());
  for (auto& g : globals_)
    mark_value(g.second);
  for (auto* u = open_upvalues_; u != nullptr; u = u->next())
    mark_object(u);

  // mark reference objects
  while (!worklist_.empty()) {
    auto* o = worklist_.back();
    worklist_.pop_back();
    o->gc_blacken(*this);
  }

  // delete unmarked interned string objects
  for (auto it = interned_strings_.begin(); it != interned_strings_.end();) {
    if (!it->second->is_marked())
      interned_strings_.erase(it++);
    else
      ++it;
  }

  // sweep and reclaim unmarked objects
  for (auto it = objects_.begin(); it != objects_.end();) {
    if (!(*it)->is_marked()) {
      reclaim_object(*it);
      objects_.erase(it++);
    }
    else {
      (*it)->set_marked(false);
      ++it;
    }
  }

  gc_threshold_ = std::max(kGCThreshold, objects_.size() * kGCFactor);
}

void VM::reclaim_object(BaseObject* o) {
#if defined(_TADPOLE_DEBUG_GC)
  std::cout << "[" << o << "] reclaim object: `" << o->stringify() << "`" << std::endl;
#endif

  delete o;
}

void VM::reset() {
  stack_.clear();
  frames_.clear();
  open_upvalues_ = nullptr;
}

void VM::runtime_error(const char* format, ...) {
  std::cerr << "Traceback (most recent call last):" << std::endl;
  for (auto it = frames_.rbegin(); it != frames_.rend(); ++it) {
    auto& frame = *it;

    sz_t i = frame.frame_chunk()->offset(frame.ip()) - 1;
    std::cerr
      << "  [LINE: " << frame.frame_chunk()->get_line(i) << "] in "
      << "`" << frame.frame_fn()->name_asstr() << "()`"
      << std::endl;
  }

  va_list ap;
  va_start(ap, format);
  std::vfprintf(stderr, format, ap);
  va_end(ap);
  std::fprintf(stderr, "\n");

  reset();
}

void VM::push(Value value) noexcept {
  stack_.push_back(value);
}

Value VM::pop() noexcept {
  Value value = stack_.back();
  stack_.pop_back();
  return value;
}

const Value& VM::peek(sz_t distance) const noexcept {
  return stack_[stack_.size() - 1 - distance];
}

bool VM::call(ClosureObject* closure, sz_t argc) {
  FunctionObject* fn = closure->fn();
  if (fn->arity() != argc) {
    runtime_error("%s() takes exactly %ud arguments (%ud given)",
        fn->name_asstr(), fn->arity(), argc);
    return false;
  }

  frames_.push_back(CallFrame(closure, fn->chunk()->codes(), stack_.size() - argc - 1));
  return true;
}

bool VM::call(const Value& callee, sz_t argc) {
  if (callee.is_object()) {
    switch (callee.objtype()) {
    case ObjType::NATIVE:
      {
        Value* args = nullptr;
        if (argc > 0 && stack_.size() > argc)
          args = &stack_[stack_.size() - argc];

        Value result = callee.as_native()->fn()(argc, args);
        stack_.resize(stack_.size() - argc - 1);
        push(result);

        return true;
      }
    case ObjType::CLOSURE: return call(callee.as_closure(), argc);
    }
  }

  runtime_error("can only call function");
  return false;
}

UpvalueObject* VM::capture_upvalue(Value* local) {
  if (open_upvalues_ == nullptr) {
    open_upvalues_ = UpvalueObject::create(*this, local);
    return open_upvalues_;
  }

  UpvalueObject* upvalue = open_upvalues_;
  UpvalueObject* prev_upvalue = nullptr;
  while (upvalue != nullptr && upvalue->value() > local) {
    prev_upvalue = upvalue;
    upvalue = upvalue->next();
  }
  if (upvalue != nullptr && upvalue->value() == local)
    return upvalue;

  UpvalueObject* new_upvalue = UpvalueObject::create(*this, local, upvalue);
  if (prev_upvalue == nullptr)
    open_upvalues_ = new_upvalue;
  else
    prev_upvalue->set_next(new_upvalue);
  return new_upvalue;
}

void VM::close_upvalues(Value* last) {
  while (open_upvalues_ != nullptr && open_upvalues_->value() >= last) {
    UpvalueObject* upvalue = open_upvalues_;
    upvalue->set_closed(upvalue->value_asref());
    upvalue->set_value(upvalue->closed_asptr());

    open_upvalues_ = upvalue->next();
  }
}

InterpretRet VM::run() {
  CallFrame* frame = &frames_.back();

#define _RDBYTE()   frame->inc_ip()
#define _RDCONST()  frame->frame_chunk()->get_constant(_RDBYTE())
#define _RDSTR()    _RDCONST().as_string()
#define _RDCSTR()   _RDCONST().as_cstring()
#define _BINOP(op)  do {\
    if (!peek(0).is_numeric() || !peek(1).is_numeric()) {\
      runtime_error("operands must be two numerics");\
      return InterpretRet::ERUNTIME;\
    }\
    double b = pop().as_numeric();\
    double a = pop().as_numeric();\
    push(a op b);\
  } while (false)

  for (;;) {
#if defined(_TADPOLE_DEBUG_VM)
    auto* frame_chunk = frame->frame_chunk();
    std::cout << "          ";
    for (auto& v : stack_)
      std::cout << "[" << v << "]";
    std::cout << std::endl;
    frame_chunk->dis_code(frame_chunk->offset(frame->ip()));
#endif

    switch (Code c = as_type<Code>(_RDBYTE())) {
    case Code::CONSTANT: push(_RDCONST()); break;
    case Code::NIL: push(nullptr); break;
    case Code::FALSE: push(false); break;
    case Code::TRUE: push(true); break;
    case Code::POP: pop(); break;
    case Code::DEF_GLOBAL:
      {
        const char* name = _RDCSTR();
        if (auto it = globals_.find(name); it != globals_.end()) {
          runtime_error("name `%s` is redefined", name);
          return InterpretRet::ERUNTIME;
        }
        else {
          globals_[name] = pop();
        }
      } break;
    case Code::GET_GLOBAL:
      {
        const char* name = _RDCSTR();
        if (auto it = globals_.find(name); it != globals_.end()) {
          push(it->second);
        }
        else {
          runtime_error("name `%s` is not defined", name);
          return InterpretRet::ERUNTIME;
        }
      } break;
    case Code::SET_GLOBAL:
      {
        const char* name = _RDCSTR();
        if (auto it = globals_.find(name); it != globals_.end()) {
          it->second = peek();
        }
        else {
          runtime_error("name `%s` is not defined", name);
          return InterpretRet::ERUNTIME;
        }
      } break;
    case Code::GET_LOCAL: push(stack_[frame->stack_begpos() + _RDBYTE()]); break;
    case Code::SET_LOCAL: stack_[frame->stack_begpos() + _RDBYTE()] = peek(); break;
    case Code::GET_UPVALUE:
      {
        u8_t slot = _RDBYTE();
        push(frame->closure()->get_upvalue(slot)->value_asref());
      } break;
    case Code::SET_UPVALUE:
      {
        u8_t slot = _RDBYTE();
        frame->closure()->get_upvalue(slot)->set_value(peek());
      } break;
    case Code::ADD:
      {
        if (peek(0).is_string() && peek(1).is_string()) {
          StringObject* b = peek(0).as_string();
          StringObject* a = peek(1).as_string();
          StringObject* s = StringObject::concat(*this, a, b);
          pop();
          pop();
          push(s);
        }
        else if (peek(0).is_numeric() && peek(1).is_numeric()) {
          double b = pop().as_numeric();
          double a = pop().as_numeric();
          push(a + b);
        }
        else {
          runtime_error("operands must be two strings or two numerics");
          return InterpretRet::ERUNTIME;
        }
      } break;
    case Code::SUB: _BINOP(-); break;
    case Code::MUL: _BINOP(*); break;
    case Code::DIV: _BINOP(/); break;
    }
  }

#undef _BINOP
#undef _RDCSTR
#undef _RDSTR
#undef _RDCONST
#undef _RDBYTE

  return InterpretRet::OK;
}

}
<|endoftext|>