<commit_before>//
//  Video.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 04/10/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#include "Video.hpp"

#include "../../Outputs/Log.hpp"

#include <algorithm>

using namespace Atari::ST;

namespace {

struct ModeParams {
	const int lines_per_frame;

	const int first_video_line;
	const int final_video_line;

	const int line_length;

	const int end_of_blank;

	const int start_of_display_enable;
	const int end_of_display_enable;

	const int start_of_output;
	const int end_of_output;

	const int start_of_blank;

	const int start_of_hsync;
	const int end_of_hsync;
} modes[3] = {
	{313,	56, 256,	1024,		64,		116, 116+640,	116+48, 116+48+640,		904,	928, 1008	},
	{},
	{}
};

const ModeParams &mode_params_for_mode() {
	// TODO: rest of potential combinations, and accept mode as a paramter.
	return modes[0];
}

}

Video::Video() :
	crt_(1024, 1, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red4Green4Blue4) {
}

void Video::set_ram(uint16_t *ram) {
	ram_ = ram;
}

void Video::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
	crt_.set_scan_target(scan_target);
}

void Video::run_for(HalfCycles duration) {
	int integer_duration = duration.as_int();
	const auto mode_params = mode_params_for_mode();

#define Period(lower, upper, type)	\
	if(x >= lower && x < upper) {	\
		const auto target = std::min(upper, final_x);	\
		type(target - x);	\
		x = target;	\
	}

	// TODO: the below is **way off**. The real hardware does what you'd expect with ongoing state and
	// exact equality tests. Fixes to come.

	while(integer_duration) {
		const int final_x = std::min(x + integer_duration, mode_params.line_length);
		integer_duration -= (final_x - x);

		if(y >= mode_params.first_video_line && y < mode_params.final_video_line) {
			// TODO: Prior to output: collect all necessary data, obeying start_of_display_enable and end_of_display_enable.

			Period(0, 							mode_params.end_of_blank, 		crt_.output_blank);
			Period(mode_params.end_of_blank, 	mode_params.start_of_output, 	output_border);

			if(x >= mode_params.start_of_output && x < mode_params.end_of_output) {
				if(x == mode_params.start_of_output) {
					// TODO: resolutions other than 320.
					pixel_pointer_ = reinterpret_cast<uint16_t *>(crt_.begin_data(320));
				}

				const auto target = std::min(mode_params.end_of_output, final_x);
				while(x < target) {
					if(!(x&31) && pixel_pointer_) {
						uint16_t source[4] = {
							ram_[current_address_ + 0],
							ram_[current_address_ + 1],
							ram_[current_address_ + 2],
							ram_[current_address_ + 3],
						};
						current_address_ += 4;

						for(int c = 0; c < 16; ++c) {
							*pixel_pointer_ = palette_[
								((source[0] >> 12) & 0x8)	|
								((source[1] >> 13) & 0x4)	|
								((source[2] >> 14) & 0x2)	|
								((source[3] >> 15) & 0x1)
							];
							source[0] <<= 1;
							source[1] <<= 1;
							source[2] <<= 1;
							source[3] <<= 1;
							++pixel_pointer_;
						}
					}
					++x;
				}

				if(x == mode_params.end_of_output) {
					crt_.output_data(mode_params.end_of_output - mode_params.start_of_output, 320);
					pixel_pointer_ = nullptr;
				}
			}

			Period(mode_params.end_of_output, 	mode_params.start_of_blank, 	output_border);
			Period(mode_params.start_of_blank, 	mode_params.start_of_hsync,		crt_.output_blank);
			Period(mode_params.start_of_hsync,	mode_params.end_of_hsync,		crt_.output_sync);
			Period(mode_params.end_of_hsync, 	mode_params.line_length,		crt_.output_blank);
		} else {
			// Hard code the first three lines as vertical sync.
			if(y < 3) {
				Period(0,							mode_params.start_of_hsync,	crt_.output_sync);
				Period(mode_params.start_of_hsync,	mode_params.end_of_hsync,	crt_.output_blank);
				Period(mode_params.end_of_hsync,	mode_params.line_length,	crt_.output_sync);
			} else {
				Period(0, 							mode_params.end_of_blank, 		crt_.output_blank);
				Period(mode_params.end_of_blank, 	mode_params.start_of_blank, 	output_border);
				Period(mode_params.start_of_blank, 	mode_params.start_of_hsync,		crt_.output_blank);
				Period(mode_params.start_of_hsync,	mode_params.end_of_hsync,		crt_.output_sync);
				Period(mode_params.end_of_hsync, 	mode_params.line_length,		crt_.output_blank);
			}
		}

		if(x == mode_params.line_length) {
			x = 0;
			y = (y + 1) % mode_params.lines_per_frame;
			if(!y) current_address_ = base_address_;
		}
	}

#undef Period
}

void Video::output_border(int duration) {
	uint16_t *colour_pointer = reinterpret_cast<uint16_t *>(crt_.begin_data(1));
	if(colour_pointer) *colour_pointer = palette_[0];
	crt_.output_level(duration);
}

bool Video::hsync() {
	const auto mode_params = mode_params_for_mode();
	return x >= mode_params.start_of_hsync && x < mode_params.end_of_hsync;
}

bool Video::vsync() {
	return y < 3;
}

bool Video::display_enabled() {
	const auto mode_params = mode_params_for_mode();
	return y >= mode_params.first_video_line && y < mode_params.final_video_line && x >= mode_params.start_of_display_enable && x < mode_params.end_of_display_enable;
}

HalfCycles Video::get_next_sequence_point() {
	// The next hsync transition will occur either this line or the next.
	const auto mode_params = mode_params_for_mode();
	HalfCycles cycles_until_hsync;
	if(x < mode_params.start_of_hsync) {
		cycles_until_hsync = HalfCycles(mode_params.start_of_hsync - x);
	} else if(x < mode_params.end_of_hsync) {
		cycles_until_hsync = HalfCycles(mode_params.end_of_hsync - x);
	} else {
		cycles_until_hsync = HalfCycles(mode_params.start_of_hsync + mode_params.line_length - x);
	}

	// The next vsync transition depends purely on the current y.
	HalfCycles cycles_until_vsync;
	if(y < 3) {
		cycles_until_vsync = HalfCycles(mode_params.line_length - x + (2 - y)*mode_params.line_length);
	} else {
		cycles_until_vsync = HalfCycles(mode_params.line_length - x + (mode_params.lines_per_frame - 1 - y)*mode_params.line_length);
	}

	// The next display enable transition will occur only in the visible area.
	HalfCycles cycles_until_display_enable;
	if(display_enabled()) {
		cycles_until_display_enable = HalfCycles(mode_params.end_of_display_enable - x);
	} else {
		const auto horizontal_cycles = mode_params.start_of_display_enable - x;
		int vertical_lines = 0;
		if(y < mode_params.first_video_line) {
			vertical_lines = mode_params.first_video_line - y;
		} else if(y >= mode_params.final_video_line ) {
			vertical_lines = mode_params.first_video_line + mode_params.lines_per_frame - y;
		}
		if(horizontal_cycles < 0) ++vertical_lines;
		cycles_until_display_enable = HalfCycles(horizontal_cycles + vertical_lines * mode_params.line_length);
	}

	// Determine the minimum of the three
	if(cycles_until_hsync < cycles_until_vsync && cycles_until_hsync < cycles_until_display_enable) {
		return cycles_until_hsync;
	} else {
		return (cycles_until_vsync < cycles_until_display_enable) ? cycles_until_vsync : cycles_until_display_enable;
	}
}

// MARK: - IO dispatch

uint8_t Video::read(int address) {
	LOG("[Video] read " << (address & 0x3f));
	address &= 0x3f;
	switch(address) {
		case 0x00:	return uint8_t(base_address_ >> 16);
		case 0x01:	return uint8_t(base_address_ >> 8);
		case 0x02:	return uint8_t(current_address_ >> 16);
		case 0x03:	return uint8_t(current_address_ >> 8);
		case 0x04:	return uint8_t(current_address_);
	}
	return 0xff;
}

void Video::write(int address, uint16_t value) {
	LOG("[Video] write " << PADHEX(2) << int(value) << " to " << PADHEX(2) << (address & 0x3f));
	address &= 0x3f;
	switch(address) {
		default: break;

		// Start address.
		case 0x00:	base_address_ = (base_address_ & 0x00ffff) | (value << 16);	break;
		case 0x01:	base_address_ = (base_address_ & 0xff00ff) | (value << 8);	break;

		// Palette.
		case 0x20:	case 0x21:	case 0x22:	case 0x23:
		case 0x24:	case 0x25:	case 0x26:	case 0x27:
		case 0x28:	case 0x29:	case 0x2a:	case 0x2b:
		case 0x2c:	case 0x2d:	case 0x2e:	case 0x2f: {
			uint8_t *const entry = reinterpret_cast<uint8_t *>(&palette_[address - 0x20]);
			entry[0] = uint8_t((value & 0x700) >> 7);
			entry[1] = uint8_t((value & 0x77) << 1);
		} break;
	}
}
<commit_msg>Silences temporarily.<commit_after>//
//  Video.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 04/10/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#include "Video.hpp"

#define NDEBUG
#include "../../Outputs/Log.hpp"

#include <algorithm>

using namespace Atari::ST;

namespace {

struct ModeParams {
	const int lines_per_frame;

	const int first_video_line;
	const int final_video_line;

	const int line_length;

	const int end_of_blank;

	const int start_of_display_enable;
	const int end_of_display_enable;

	const int start_of_output;
	const int end_of_output;

	const int start_of_blank;

	const int start_of_hsync;
	const int end_of_hsync;
} modes[3] = {
	{313,	56, 256,	1024,		64,		116, 116+640,	116+48, 116+48+640,		904,	928, 1008	},
	{},
	{}
};

const ModeParams &mode_params_for_mode() {
	// TODO: rest of potential combinations, and accept mode as a paramter.
	return modes[0];
}

}

Video::Video() :
	crt_(1024, 1, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red4Green4Blue4) {
}

void Video::set_ram(uint16_t *ram) {
	ram_ = ram;
}

void Video::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
	crt_.set_scan_target(scan_target);
}

void Video::run_for(HalfCycles duration) {
	int integer_duration = duration.as_int();
	const auto mode_params = mode_params_for_mode();

#define Period(lower, upper, type)	\
	if(x >= lower && x < upper) {	\
		const auto target = std::min(upper, final_x);	\
		type(target - x);	\
		x = target;	\
	}

	// TODO: the below is **way off**. The real hardware does what you'd expect with ongoing state and
	// exact equality tests. Fixes to come.

	while(integer_duration) {
		const int final_x = std::min(x + integer_duration, mode_params.line_length);
		integer_duration -= (final_x - x);

		if(y >= mode_params.first_video_line && y < mode_params.final_video_line) {
			// TODO: Prior to output: collect all necessary data, obeying start_of_display_enable and end_of_display_enable.

			Period(0, 							mode_params.end_of_blank, 		crt_.output_blank);
			Period(mode_params.end_of_blank, 	mode_params.start_of_output, 	output_border);

			if(x >= mode_params.start_of_output && x < mode_params.end_of_output) {
				if(x == mode_params.start_of_output) {
					// TODO: resolutions other than 320.
					pixel_pointer_ = reinterpret_cast<uint16_t *>(crt_.begin_data(320));
				}

				const auto target = std::min(mode_params.end_of_output, final_x);
				while(x < target) {
					if(!(x&31) && pixel_pointer_) {
						uint16_t source[4] = {
							ram_[current_address_ + 0],
							ram_[current_address_ + 1],
							ram_[current_address_ + 2],
							ram_[current_address_ + 3],
						};
						current_address_ += 4;

						for(int c = 0; c < 16; ++c) {
							*pixel_pointer_ = palette_[
								((source[0] >> 12) & 0x8)	|
								((source[1] >> 13) & 0x4)	|
								((source[2] >> 14) & 0x2)	|
								((source[3] >> 15) & 0x1)
							];
							source[0] <<= 1;
							source[1] <<= 1;
							source[2] <<= 1;
							source[3] <<= 1;
							++pixel_pointer_;
						}
					}
					++x;
				}

				if(x == mode_params.end_of_output) {
					crt_.output_data(mode_params.end_of_output - mode_params.start_of_output, 320);
					pixel_pointer_ = nullptr;
				}
			}

			Period(mode_params.end_of_output, 	mode_params.start_of_blank, 	output_border);
			Period(mode_params.start_of_blank, 	mode_params.start_of_hsync,		crt_.output_blank);
			Period(mode_params.start_of_hsync,	mode_params.end_of_hsync,		crt_.output_sync);
			Period(mode_params.end_of_hsync, 	mode_params.line_length,		crt_.output_blank);
		} else {
			// Hard code the first three lines as vertical sync.
			if(y < 3) {
				Period(0,							mode_params.start_of_hsync,	crt_.output_sync);
				Period(mode_params.start_of_hsync,	mode_params.end_of_hsync,	crt_.output_blank);
				Period(mode_params.end_of_hsync,	mode_params.line_length,	crt_.output_sync);
			} else {
				Period(0, 							mode_params.end_of_blank, 		crt_.output_blank);
				Period(mode_params.end_of_blank, 	mode_params.start_of_blank, 	output_border);
				Period(mode_params.start_of_blank, 	mode_params.start_of_hsync,		crt_.output_blank);
				Period(mode_params.start_of_hsync,	mode_params.end_of_hsync,		crt_.output_sync);
				Period(mode_params.end_of_hsync, 	mode_params.line_length,		crt_.output_blank);
			}
		}

		if(x == mode_params.line_length) {
			x = 0;
			y = (y + 1) % mode_params.lines_per_frame;
			if(!y) current_address_ = base_address_;
		}
	}

#undef Period
}

void Video::output_border(int duration) {
	uint16_t *colour_pointer = reinterpret_cast<uint16_t *>(crt_.begin_data(1));
	if(colour_pointer) *colour_pointer = palette_[0];
	crt_.output_level(duration);
}

bool Video::hsync() {
	const auto mode_params = mode_params_for_mode();
	return x >= mode_params.start_of_hsync && x < mode_params.end_of_hsync;
}

bool Video::vsync() {
	return y < 3;
}

bool Video::display_enabled() {
	const auto mode_params = mode_params_for_mode();
	return y >= mode_params.first_video_line && y < mode_params.final_video_line && x >= mode_params.start_of_display_enable && x < mode_params.end_of_display_enable;
}

HalfCycles Video::get_next_sequence_point() {
	// The next hsync transition will occur either this line or the next.
	const auto mode_params = mode_params_for_mode();
	HalfCycles cycles_until_hsync;
	if(x < mode_params.start_of_hsync) {
		cycles_until_hsync = HalfCycles(mode_params.start_of_hsync - x);
	} else if(x < mode_params.end_of_hsync) {
		cycles_until_hsync = HalfCycles(mode_params.end_of_hsync - x);
	} else {
		cycles_until_hsync = HalfCycles(mode_params.start_of_hsync + mode_params.line_length - x);
	}

	// The next vsync transition depends purely on the current y.
	HalfCycles cycles_until_vsync;
	if(y < 3) {
		cycles_until_vsync = HalfCycles(mode_params.line_length - x + (2 - y)*mode_params.line_length);
	} else {
		cycles_until_vsync = HalfCycles(mode_params.line_length - x + (mode_params.lines_per_frame - 1 - y)*mode_params.line_length);
	}

	// The next display enable transition will occur only in the visible area.
	HalfCycles cycles_until_display_enable;
	if(display_enabled()) {
		cycles_until_display_enable = HalfCycles(mode_params.end_of_display_enable - x);
	} else {
		const auto horizontal_cycles = mode_params.start_of_display_enable - x;
		int vertical_lines = 0;
		if(y < mode_params.first_video_line) {
			vertical_lines = mode_params.first_video_line - y;
		} else if(y >= mode_params.final_video_line ) {
			vertical_lines = mode_params.first_video_line + mode_params.lines_per_frame - y;
		}
		if(horizontal_cycles < 0) ++vertical_lines;
		cycles_until_display_enable = HalfCycles(horizontal_cycles + vertical_lines * mode_params.line_length);
	}

	// Determine the minimum of the three
	if(cycles_until_hsync < cycles_until_vsync && cycles_until_hsync < cycles_until_display_enable) {
		return cycles_until_hsync;
	} else {
		return (cycles_until_vsync < cycles_until_display_enable) ? cycles_until_vsync : cycles_until_display_enable;
	}
}

// MARK: - IO dispatch

uint8_t Video::read(int address) {
	LOG("[Video] read " << (address & 0x3f));
	address &= 0x3f;
	switch(address) {
		case 0x00:	return uint8_t(base_address_ >> 16);
		case 0x01:	return uint8_t(base_address_ >> 8);
		case 0x02:	return uint8_t(current_address_ >> 16);
		case 0x03:	return uint8_t(current_address_ >> 8);
		case 0x04:	return uint8_t(current_address_);
	}
	return 0xff;
}

void Video::write(int address, uint16_t value) {
	LOG("[Video] write " << PADHEX(2) << int(value) << " to " << PADHEX(2) << (address & 0x3f));
	address &= 0x3f;
	switch(address) {
		default: break;

		// Start address.
		case 0x00:	base_address_ = (base_address_ & 0x00ffff) | (value << 16);	break;
		case 0x01:	base_address_ = (base_address_ & 0xff00ff) | (value << 8);	break;

		// Palette.
		case 0x20:	case 0x21:	case 0x22:	case 0x23:
		case 0x24:	case 0x25:	case 0x26:	case 0x27:
		case 0x28:	case 0x29:	case 0x2a:	case 0x2b:
		case 0x2c:	case 0x2d:	case 0x2e:	case 0x2f: {
			uint8_t *const entry = reinterpret_cast<uint8_t *>(&palette_[address - 0x20]);
			entry[0] = uint8_t((value & 0x700) >> 7);
			entry[1] = uint8_t((value & 0x77) << 1);
		} break;
	}
}
<|endoftext|>


<commit_before>#ifndef RDB_PROTOCOL_FUNC_HPP_
#define RDB_PROTOCOL_FUNC_HPP_

#include <map>
#include <utility>
#include <vector>

#include "utils.hpp"

#include "containers/ptr_bag.hpp"
#include "containers/scoped.hpp"
#include "protob/protob.hpp"
#include "rdb_protocol/js.hpp"
#include "rdb_protocol/term.hpp"
#include "rpc/serialize_macros.hpp"

namespace ql {

class func_t : public ptr_baggable_t, public pb_rcheckable_t {
public:
    func_t(env_t *env, js::id_t id, term_t *parent);
    func_t(env_t *env, const Term *_source);
    // Some queries, like filter, can take a shortcut object instead of a
    // function as their argument.
    static func_t *new_filter_func(env_t *env, const datum_t *obj,
                                   const pb_rcheckable_t *root);
    static func_t *new_identity_func(env_t *env, const datum_t *obj,
                                     const pb_rcheckable_t *root);
    val_t *call(const std::vector<const datum_t *> &args);
    // Prefer these two version of call.
    val_t *call(const datum_t *arg);
    val_t *call(const datum_t *arg1, const datum_t *arg2);
    bool filter_call(env_t *env, const datum_t *arg);

    void dump_scope(std::map<int, Datum> *out) const;
    bool is_deterministic() const;

private:
    // Pointers to this function's arguments.
    std::vector<const datum_t *> argptrs;
    term_t *body; // body to evaluate with functions bound

    // This is what's serialized over the wire.
    friend class wire_func_t;
    const Term *source;
    bool implicit_bound;

    // TODO: make this smarter (it's sort of slow and shitty as-is)
    std::map<int, const datum_t **> scope;

    term_t *js_parent;
    env_t *js_env;
    js::id_t js_id;
};

class js_result_visitor_t : public boost::static_visitor<val_t *> {
public:
    typedef val_t *result_type;

    js_result_visitor_t(env_t *_env, term_t *_parent) : env(_env), parent(_parent) { }

    // This JS evaluation resulted in an error
    result_type operator()(const std::string err_val) const {
        rfail_target(parent, "%s", err_val.c_str());
        unreachable();
    }

    // This JS call resulted in a JSON value
    result_type operator()(const boost::shared_ptr<scoped_cJSON_t> json_val) const {
        return parent->new_val(new datum_t(json_val, env));
    }

    // This JS evaluation resulted in an id for a js function
    result_type operator()(const id_t id_val) const {
        return parent->new_val(new func_t(env, id_val, parent));
    }

private:
    env_t *env;
    term_t *parent;
};

RDB_MAKE_PROTOB_SERIALIZABLE(Term);
RDB_MAKE_PROTOB_SERIALIZABLE(Datum);

// Used to serialize a function (or gmr) over the wire.
class wire_func_t {
public:
    wire_func_t();
    virtual ~wire_func_t() { }
    wire_func_t(env_t *env, func_t *_func);
    wire_func_t(const Term &_source, std::map<int, Datum> *_scope);

protected:
    func_t *compile(env_t *env);

    // We cache a separate function for every environment.
    std::map<env_t *, func_t *> cached_funcs;

    Term source;
    std::map<int, Datum> scope;
};

class map_wire_func_t : private wire_func_t {
public:
    template <class... Args>
    map_wire_func_t(Args... args) : wire_func_t(args...) { }

    using wire_func_t::compile;
    RDB_MAKE_ME_SERIALIZABLE_2(source, scope);
};

class filter_wire_func_t : private wire_func_t {
public:
    template <class... Args>
    filter_wire_func_t(Args... args) : wire_func_t(args...) { }

    using wire_func_t::compile;
    RDB_MAKE_ME_SERIALIZABLE_2(source, scope);
};

class reduce_wire_func_t : private wire_func_t {
public:
    template <class... Args>
    reduce_wire_func_t(Args... args) : wire_func_t(args...) { }

    using wire_func_t::compile;
    RDB_MAKE_ME_SERIALIZABLE_2(source, scope);
};

class concatmap_wire_func_t : private wire_func_t {
public:
    template <class... Args>
    concatmap_wire_func_t(Args... args) : wire_func_t(args...) { }

    using wire_func_t::compile;
    RDB_MAKE_ME_SERIALIZABLE_2(source, scope);
};

// Count is a fake function because we don't need to send anything.
struct count_wire_func_t { RDB_MAKE_ME_SERIALIZABLE_0() };

// Grouped Map Reduce
class gmr_wire_func_t {
public:
    gmr_wire_func_t() { }
    gmr_wire_func_t(env_t *env, func_t *_group, func_t *_map, func_t *_reduce)
        : group(env, _group), map(env, _map), reduce(env, _reduce) { }
    func_t *compile_group(env_t *env) { return group.compile(env); }
    func_t *compile_map(env_t *env) { return map.compile(env); }
    func_t *compile_reduce(env_t *env) { return reduce.compile(env); }
private:
    map_wire_func_t group;
    map_wire_func_t map;
    reduce_wire_func_t reduce;
public:
    RDB_MAKE_ME_SERIALIZABLE_3(group, map, reduce);
};

// Evaluating this returns a `func_t` wrapped in a `val_t`.
class func_term_t : public term_t {
public:
    func_term_t(env_t *env, const Term *term);
private:
    virtual bool is_deterministic_impl() const;
    virtual val_t *eval_impl();
    virtual const char *name() const { return "func"; }
    func_t *func;
};

} // namespace ql
#endif // RDB_PROTOCOL_FUNC_HPP_
<commit_msg>Just made map_wire_func_t, etc, inherit publicly from wire_func_t.<commit_after>#ifndef RDB_PROTOCOL_FUNC_HPP_
#define RDB_PROTOCOL_FUNC_HPP_

#include <map>
#include <utility>
#include <vector>

#include "utils.hpp"

#include "containers/ptr_bag.hpp"
#include "containers/scoped.hpp"
#include "protob/protob.hpp"
#include "rdb_protocol/js.hpp"
#include "rdb_protocol/term.hpp"
#include "rpc/serialize_macros.hpp"

namespace ql {

class func_t : public ptr_baggable_t, public pb_rcheckable_t {
public:
    func_t(env_t *env, js::id_t id, term_t *parent);
    func_t(env_t *env, const Term *_source);
    // Some queries, like filter, can take a shortcut object instead of a
    // function as their argument.
    static func_t *new_filter_func(env_t *env, const datum_t *obj,
                                   const pb_rcheckable_t *root);
    static func_t *new_identity_func(env_t *env, const datum_t *obj,
                                     const pb_rcheckable_t *root);
    val_t *call(const std::vector<const datum_t *> &args);
    // Prefer these two version of call.
    val_t *call(const datum_t *arg);
    val_t *call(const datum_t *arg1, const datum_t *arg2);
    bool filter_call(env_t *env, const datum_t *arg);

    void dump_scope(std::map<int, Datum> *out) const;
    bool is_deterministic() const;

private:
    // Pointers to this function's arguments.
    std::vector<const datum_t *> argptrs;
    term_t *body; // body to evaluate with functions bound

    // This is what's serialized over the wire.
    friend class wire_func_t;
    const Term *source;
    bool implicit_bound;

    // TODO: make this smarter (it's sort of slow and shitty as-is)
    std::map<int, const datum_t **> scope;

    term_t *js_parent;
    env_t *js_env;
    js::id_t js_id;
};

class js_result_visitor_t : public boost::static_visitor<val_t *> {
public:
    typedef val_t *result_type;

    js_result_visitor_t(env_t *_env, term_t *_parent) : env(_env), parent(_parent) { }

    // This JS evaluation resulted in an error
    result_type operator()(const std::string err_val) const {
        rfail_target(parent, "%s", err_val.c_str());
        unreachable();
    }

    // This JS call resulted in a JSON value
    result_type operator()(const boost::shared_ptr<scoped_cJSON_t> json_val) const {
        return parent->new_val(new datum_t(json_val, env));
    }

    // This JS evaluation resulted in an id for a js function
    result_type operator()(const id_t id_val) const {
        return parent->new_val(new func_t(env, id_val, parent));
    }

private:
    env_t *env;
    term_t *parent;
};

RDB_MAKE_PROTOB_SERIALIZABLE(Term);
RDB_MAKE_PROTOB_SERIALIZABLE(Datum);

// Used to serialize a function (or gmr) over the wire.
class wire_func_t {
public:
    wire_func_t();
    wire_func_t(env_t *env, func_t *_func);
    wire_func_t(const Term &_source, std::map<int, Datum> *_scope);

    func_t *compile(env_t *env);

    RDB_MAKE_ME_SERIALIZABLE_2(source, scope);

private:
    // We cache a separate function for every environment.
    std::map<env_t *, func_t *> cached_funcs;

    Term source;
    std::map<int, Datum> scope;
};

class map_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    map_wire_func_t(Args... args) : wire_func_t(args...) { }
};

class filter_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    filter_wire_func_t(Args... args) : wire_func_t(args...) { }
};

class reduce_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    reduce_wire_func_t(Args... args) : wire_func_t(args...) { }
};

class concatmap_wire_func_t : public wire_func_t {
public:
    template <class... Args>
    concatmap_wire_func_t(Args... args) : wire_func_t(args...) { }
};

// Count is a fake function because we don't need to send anything.
struct count_wire_func_t { RDB_MAKE_ME_SERIALIZABLE_0() };

// Grouped Map Reduce
class gmr_wire_func_t {
public:
    gmr_wire_func_t() { }
    gmr_wire_func_t(env_t *env, func_t *_group, func_t *_map, func_t *_reduce)
        : group(env, _group), map(env, _map), reduce(env, _reduce) { }
    func_t *compile_group(env_t *env) { return group.compile(env); }
    func_t *compile_map(env_t *env) { return map.compile(env); }
    func_t *compile_reduce(env_t *env) { return reduce.compile(env); }
private:
    map_wire_func_t group;
    map_wire_func_t map;
    reduce_wire_func_t reduce;
public:
    RDB_MAKE_ME_SERIALIZABLE_3(group, map, reduce);
};

// Evaluating this returns a `func_t` wrapped in a `val_t`.
class func_term_t : public term_t {
public:
    func_term_t(env_t *env, const Term *term);
private:
    virtual bool is_deterministic_impl() const;
    virtual val_t *eval_impl();
    virtual const char *name() const { return "func"; }
    func_t *func;
};

} // namespace ql
#endif // RDB_PROTOCOL_FUNC_HPP_
<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id:

#include "ballviewDemo.h"
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/common.h>
#include <BALL/KERNEL/system.h>
#include <BALL/VIEW/DIALOGS/displayProperties.h>
#include <BALL/VIEW/WIDGETS/molecularStructure.h>
#include <BALL/VIEW/DIALOGS/FDPBDialog.h>
#include <BALL/FORMAT/PDBFile.h>
#include <BALL/FORMAT/HINFile.h>
#include <BALL/DATATYPE/contourSurface.h>
#include <BALL/VIEW/PRIMITIVES/mesh.h>
#include <BALL/STRUCTURE/HBondProcessor.h>
#include <BALL/VIEW/WIDGETS/scene.h>
#include <BALL/VIEW/DATATYPE/colorTable.h>
#include <BALL/VIEW/DIALOGS/colorMeshDialog.h>
#include <BALL/VIEW/DIALOGS/molecularFileDialog.h>

#include <qlabel.h>
#include <qpushbutton.h>
#include <qwidgetstack.h>

namespace BALL
{
	namespace VIEW
	{

BALLViewDemo::BALLViewDemo(QWidget* parent, const char* name)
	throw()
	:	BALLViewDemoData(parent, name),
		ModularWidget(name)
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "new BALLViewDemo " << this << std::endl;
#endif
	// register the widget with the MainControl
 	ModularWidget::registerWidget(this);
	hide();
}

BALLViewDemo::~BALLViewDemo()
	throw()
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "deleting BALLViewDemo " << this << std::endl;
#endif
}

void BALLViewDemo::show()
{
	widget_stack->raiseWidget(0);
	buttonOk->setEnabled(true);
	DisplayProperties* dp = DisplayProperties::getInstance(0);
	dp->setDrawingPrecision(DRAWING_PRECISION_HIGH);
	dp->setSurfaceDrawingPrecision(6.5);
	dp->enableCreationForNewMolecules(false);
	system_ = new System();

	try
	{
		Path path;
		String file_name(path.getDataPath());
		file_name = file_name.before("data");
		file_name += "data";
		file_name += FileSystem::PATH_SEPARATOR;
		file_name += String("structures");
		file_name += FileSystem::PATH_SEPARATOR;
		file_name += "bpti.pdb";
		MolecularFileDialog* dialog = MolecularFileDialog::getInstance(0);
		system_ = dialog->openFile(file_name);

		system_->apply(getFragmentDB().add_hydrogens);
		system_->apply(getFragmentDB().build_bonds);
		getMainControl()->update(*system_, true);
	}
	catch(Exception::FileNotFound e)
	{
		Log.error() << "Could not open " << e.getFilename() << std::endl;
		return;
	}

	composites_.clear();
	composites_.push_back(system_);
	QDialog::show();
	raise();
}

void BALLViewDemo::onNotify(Message *message)
	throw()
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "BALLViewDemo " << this << " onNotify " << message << std::endl;
#endif

	if (!isVisible()) return;

	RepresentationMessage* rmsg = RTTI::castTo<RepresentationMessage>(*message);

	Index id = widget_stack->id(widget_stack->visibleWidget());

	if (id == 12)
	{
		if (RTTI::isKindOf<FinishedSimulationMessage>(*message))
		{
			nextStep_();
		}
	}
	else if (id == 13)
	{
		RegularData3DMessage* msg = RTTI::castTo<RegularData3DMessage>(*message);
		if (msg != 0 &&
			  ((RegularData3DMessage::RegularDataMessageType)msg->getType()) == RegularDataMessage::NEW)
		{
			grid_ = msg->getData();
			nextStep_();
		}
	}
	else if (id == 14)
	{
		SceneMessage* msg = RTTI::castTo<SceneMessage>(*message);
		if (msg != 0 && msg->getType() == SceneMessage::REBUILD_DISPLAY_LISTS)
		{
 			nextStep_();
		}
	}
	else if (rmsg != 0 &&
					 rmsg->getType() == RepresentationMessage::UPDATE)
	{
		nextStep_();
	}
}

void BALLViewDemo::nextStep_()
{
	widget_stack->raiseWidget(widget_stack->id(widget_stack->visibleWidget()) + 1);
	buttonOk->setEnabled(true);
}

void BALLViewDemo::accept()
{
	Index id = widget_stack->id(widget_stack->visibleWidget());

	if (id == 16) // last page
	{
		hide();
		return;
	}

	MolecularStructure* ms = MolecularStructure::getInstance(0);
	bool disable_button = true;

	// remove representations
	PrimitiveManager& pm = getMainControl()->getPrimitiveManager();
	Size nr = pm.getNumberOfRepresentations();
	list<Representation*> reps = pm.getRepresentations();
	for (Position p = 0; p < nr; p++)
	{
		getMainControl()->remove(**reps.begin());
		reps.pop_front();
	}

	if (id < 7)
	{
		ModelType type = (ModelType) id;
		if (type >= MODEL_SA_SURFACE)
		{
			type = (ModelType)((Index)type + 1);
		}
 		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, type, COLORING_ELEMENT);
		notify_(crmsg);
	}
	else if (id == 7)
	{
		getMainControl()->getMolecularControlSelection().clear();
		getMainControl()->getMolecularControlSelection().push_back(system_);
		ms->calculateHBonds();
   	CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_STICK, COLORING_ELEMENT);
   	notify_(crmsg);
 		crmsg = new CreateRepresentationMessage(composites_, MODEL_HBONDS, COLORING_ELEMENT);
 		notify_(crmsg);
	}
	else if (id == 8)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_VDW, COLORING_TEMPERATURE_FACTOR);
		notify_(crmsg);
	}
	else if (id == 9)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_CARTOON, COLORING_SECONDARY_STRUCTURE);
		notify_(crmsg);
	}
	else if (id == 10)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_CARTOON, COLORING_RESIDUE_INDEX);
		notify_(crmsg);
	}
	else if (id == 11)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_STICK, COLORING_RESIDUE_NAME);
		notify_(crmsg);
	}
	else if (id == 12)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_STICK, COLORING_ELEMENT);
		notify_(crmsg);

		ms->chooseAmberFF();
		ms->getMDSimulationDialog().setTimeStep(0.001);
 		ms->getMDSimulationDialog().setNumberOfSteps(30);
		ms->MDSimulation(false);
	}
	else if (id == 13) //FDPB
	{
		ms->calculateFDPB();
		ms->getFDPBDialog()->okPressed();
		disable_button = false;
	}
	else if (id == 14) // SES colored
	{
		getMainControl()->getPrimitiveManager().setMultithreadingMode(false);
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_SE_SURFACE, COLORING_ELEMENT);
		notify_(crmsg);
		getMainControl()->getPrimitiveManager().setMultithreadingMode(false);

		Representation* rep = *getMainControl()->getPrimitiveManager().begin();
		Mesh* mesh = dynamic_cast<Mesh*> (*rep->getGeometricObjects().begin());

		ColorMeshDialog* cdialog = ColorMeshDialog::getInstance(0);
		cdialog->setMesh(mesh, rep);
		cdialog->setGrid(grid_);
		cdialog->setMinValue(-0.7);
		cdialog->setMaxValue(3.0);
		cdialog->applyPressed();

		rep->setColorProcessor(0);

 		SceneMessage smsg(SceneMessage::REBUILD_DISPLAY_LISTS);
 		getMainControl()->sendMessage(smsg);
		disable_button = false;
	}
	else if (id == 15)
	{
		ContourSurface cs(*grid_, 0.01);
		Mesh* mesh = new Mesh;
		mesh->Surface::operator = (static_cast<Surface&>(cs));

		Vector3 center;
		for (Position i = 0; i < mesh->vertex.size(); i++)
		{
			center += mesh->vertex[i];
		}

		center /= mesh->vertex.size();

		Size nr_of_strange_normals = 0;
		for (Position i = 0; i < mesh->normal.size(); i++)
		{
			if ((mesh->vertex[i] + mesh->normal[i]).getDistance(center) < (mesh->vertex[i] - mesh->normal[i]).getDistance(center))
			{
				nr_of_strange_normals ++;
			}
		}

		if (nr_of_strange_normals < mesh->normal.size() / 2.0)
		{
			for (Position i = 0; i < mesh->normal.size(); i++)
			{
				mesh->normal[i] *= -1;
			}
		}

		// Create a new representation containing the contour surface.
		Representation* rep = getMainControl()->getPrimitiveManager().createRepresentation();
		rep->insert(*mesh);
		rep->setModelType(MODEL_CONTOUR_SURFACE);

		RepresentationMessage* message = new RepresentationMessage(*rep, RepresentationMessage::ADD);
		notify_(message);

   	CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_STICK, COLORING_ELEMENT);
   	notify_(crmsg);
	}

	buttonOk->setEnabled(!disable_button);
}

} } // namespaces
<commit_msg>no message<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id:

#include "ballviewDemo.h"
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/common.h>
#include <BALL/KERNEL/system.h>
#include <BALL/VIEW/DIALOGS/displayProperties.h>
#include <BALL/VIEW/WIDGETS/molecularStructure.h>
#include <BALL/VIEW/DIALOGS/FDPBDialog.h>
#include <BALL/FORMAT/PDBFile.h>
#include <BALL/FORMAT/HINFile.h>
#include <BALL/DATATYPE/contourSurface.h>
#include <BALL/VIEW/PRIMITIVES/mesh.h>
#include <BALL/STRUCTURE/HBondProcessor.h>
#include <BALL/VIEW/WIDGETS/scene.h>
#include <BALL/VIEW/DATATYPE/colorTable.h>
#include <BALL/VIEW/DIALOGS/modifySurfaceDialog.h>
#include <BALL/VIEW/DIALOGS/molecularFileDialog.h>

#include <qlabel.h>
#include <qpushbutton.h>
#include <qwidgetstack.h>

namespace BALL
{
	namespace VIEW
	{

BALLViewDemo::BALLViewDemo(QWidget* parent, const char* name)
	throw()
	:	BALLViewDemoData(parent, name),
		ModularWidget(name)
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "new BALLViewDemo " << this << std::endl;
#endif
	// register the widget with the MainControl
 	ModularWidget::registerWidget(this);
	hide();
}

BALLViewDemo::~BALLViewDemo()
	throw()
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "deleting BALLViewDemo " << this << std::endl;
#endif
}

void BALLViewDemo::show()
{
	widget_stack->raiseWidget(0);
	buttonOk->setEnabled(true);
	DisplayProperties* dp = DisplayProperties::getInstance(0);
	dp->setDrawingPrecision(DRAWING_PRECISION_HIGH);
	dp->setSurfaceDrawingPrecision(6.5);
	dp->enableCreationForNewMolecules(false);
	system_ = new System();

	try
	{
		Path path;
		String file_name(path.getDataPath());
		file_name = file_name.before("data");
		file_name += "data";
		file_name += FileSystem::PATH_SEPARATOR;
		file_name += String("structures");
		file_name += FileSystem::PATH_SEPARATOR;
		file_name += "bpti.pdb";
		MolecularFileDialog* dialog = MolecularFileDialog::getInstance(0);
		system_ = dialog->openFile(file_name);

		system_->apply(getFragmentDB().add_hydrogens);
		system_->apply(getFragmentDB().build_bonds);
		getMainControl()->update(*system_, true);
	}
	catch(Exception::FileNotFound e)
	{
		Log.error() << "Could not open " << e.getFilename() << std::endl;
		return;
	}

	composites_.clear();
	composites_.push_back(system_);
	QDialog::show();
	raise();
}

void BALLViewDemo::onNotify(Message *message)
	throw()
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "BALLViewDemo " << this << " onNotify " << message << std::endl;
#endif

	if (!isVisible()) return;

	RepresentationMessage* rmsg = RTTI::castTo<RepresentationMessage>(*message);

	Index id = widget_stack->id(widget_stack->visibleWidget());

	if (id == 12)
	{
		if (RTTI::isKindOf<FinishedSimulationMessage>(*message))
		{
			nextStep_();
		}
	}
	else if (id == 13)
	{
		RegularData3DMessage* msg = RTTI::castTo<RegularData3DMessage>(*message);
		if (msg != 0 &&
			  ((RegularData3DMessage::RegularDataMessageType)msg->getType()) == RegularDataMessage::NEW)
		{
			grid_ = msg->getData();
			nextStep_();
		}
	}
	else if (id == 14)
	{
		SceneMessage* msg = RTTI::castTo<SceneMessage>(*message);
		if (msg != 0 && msg->getType() == SceneMessage::REBUILD_DISPLAY_LISTS)
		{
 			nextStep_();
		}
	}
	else if (rmsg != 0 &&
					 rmsg->getType() == RepresentationMessage::UPDATE)
	{
		nextStep_();
	}
}

void BALLViewDemo::nextStep_()
{
	widget_stack->raiseWidget(widget_stack->id(widget_stack->visibleWidget()) + 1);
	buttonOk->setEnabled(true);
}

void BALLViewDemo::accept()
{
	Index id = widget_stack->id(widget_stack->visibleWidget());

	if (id == 16) // last page
	{
		hide();
		return;
	}

	MolecularStructure* ms = MolecularStructure::getInstance(0);
	bool disable_button = true;

	// remove representations
	PrimitiveManager& pm = getMainControl()->getPrimitiveManager();
	Size nr = pm.getNumberOfRepresentations();
	list<Representation*> reps = pm.getRepresentations();
	for (Position p = 0; p < nr; p++)
	{
		getMainControl()->remove(**reps.begin());
		reps.pop_front();
	}

	if (id < 7)
	{
		ModelType type = (ModelType) id;
		if (type >= MODEL_SA_SURFACE)
		{
			type = (ModelType)((Index)type + 1);
		}
 		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, type, COLORING_ELEMENT);
		notify_(crmsg);
	}
	else if (id == 7)
	{
		getMainControl()->getMolecularControlSelection().clear();
		getMainControl()->getMolecularControlSelection().push_back(system_);
		ms->calculateHBonds();
   	CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_STICK, COLORING_ELEMENT);
   	notify_(crmsg);
 		crmsg = new CreateRepresentationMessage(composites_, MODEL_HBONDS, COLORING_ELEMENT);
 		notify_(crmsg);
	}
	else if (id == 8)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_VDW, COLORING_TEMPERATURE_FACTOR);
		notify_(crmsg);
	}
	else if (id == 9)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_CARTOON, COLORING_SECONDARY_STRUCTURE);
		notify_(crmsg);
	}
	else if (id == 10)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_CARTOON, COLORING_RESIDUE_INDEX);
		notify_(crmsg);
	}
	else if (id == 11)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_STICK, COLORING_RESIDUE_NAME);
		notify_(crmsg);
	}
	else if (id == 12)
	{
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_STICK, COLORING_ELEMENT);
		notify_(crmsg);

		ms->chooseAmberFF();
		ms->getMDSimulationDialog().setTimeStep(0.001);
 		ms->getMDSimulationDialog().setNumberOfSteps(30);
		ms->MDSimulation(false);
	}
	else if (id == 13) //FDPB
	{
		ms->calculateFDPB();
		ms->getFDPBDialog()->okPressed();
		disable_button = false;
	}
	else if (id == 14) // SES colored
	{
		getMainControl()->getPrimitiveManager().setMultithreadingMode(false);
		CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_SE_SURFACE, COLORING_ELEMENT);
		notify_(crmsg);
		getMainControl()->getPrimitiveManager().setMultithreadingMode(false);

		Representation* rep = *getMainControl()->getPrimitiveManager().begin();
		ModifySurfaceDialog* cdialog = ModifySurfaceDialog::getInstance(0);
		cdialog->setRepresentation(rep);
		cdialog->setGrid(grid_);
		cdialog->setMinValue(-0.7);
		cdialog->setMaxValue(3.0);
		cdialog->applyPressed();

		rep->setColorProcessor(0);

 		SceneMessage smsg(SceneMessage::REBUILD_DISPLAY_LISTS);
 		getMainControl()->sendMessage(smsg);
		disable_button = false;
	}
	else if (id == 15)
	{
		ContourSurface cs(*grid_, 0.01);
		Mesh* mesh = new Mesh;
		mesh->Surface::operator = (static_cast<Surface&>(cs));

		Vector3 center;
		for (Position i = 0; i < mesh->vertex.size(); i++)
		{
			center += mesh->vertex[i];
		}

		center /= mesh->vertex.size();

		Size nr_of_strange_normals = 0;
		for (Position i = 0; i < mesh->normal.size(); i++)
		{
			if ((mesh->vertex[i] + mesh->normal[i]).getDistance(center) < (mesh->vertex[i] - mesh->normal[i]).getDistance(center))
			{
				nr_of_strange_normals ++;
			}
		}

		if (nr_of_strange_normals < mesh->normal.size() / 2.0)
		{
			for (Position i = 0; i < mesh->normal.size(); i++)
			{
				mesh->normal[i] *= -1;
			}
		}

		// Create a new representation containing the contour surface.
		Representation* rep = getMainControl()->getPrimitiveManager().createRepresentation();
		rep->insert(*mesh);
		rep->setModelType(MODEL_CONTOUR_SURFACE);

		RepresentationMessage* message = new RepresentationMessage(*rep, RepresentationMessage::ADD);
		notify_(message);

   	CreateRepresentationMessage* crmsg = new CreateRepresentationMessage(composites_, MODEL_STICK, COLORING_ELEMENT);
   	notify_(crmsg);
	}

	buttonOk->setEnabled(!disable_button);
}

} } // namespaces
<|endoftext|>


<commit_before>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/function/CEvaluationNodeObject.cpp,v $
//   $Revision: 1.29 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2007/10/02 18:18:03 $
// End CVS Header

// Copyright (C) 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include "copasi.h"
#include "CEvaluationNode.h"
#include "CEvaluationTree.h"
#include "CExpression.h"
#include "report/CCopasiObjectName.h"
#include "report/CCopasiObject.h"
#include "report/CCopasiContainer.h"
#include "model/CModel.h"
#include "CopasiDataModel/CCopasiDataModel.h"

#include "sbml/math/ASTNode.h"
#include "sbml/SBase.h"
#include "sbml/SBMLTypeCodes.h"
#include "sbml/Compartment.h"
#include "sbml/Species.h"
#include "sbml/Parameter.h"
#include "sbml/Reaction.h"

CEvaluationNodeObject::CEvaluationNodeObject():
    CEvaluationNode(CEvaluationNode::INVALID, ""),
    mpValue(NULL),
    mRegisteredObjectCN("")
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeObject::CEvaluationNodeObject(const SubType & subType,
    const Data & data):
    CEvaluationNode((Type) (CEvaluationNode::OBJECT | subType), data),
    mpValue(NULL),
    mRegisteredObjectCN(data.substr(1, data.length() - 2))
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeObject::CEvaluationNodeObject(const CEvaluationNodeObject & src):
    CEvaluationNode(src),
    mpValue(src.mpValue),
    mRegisteredObjectCN(src.mRegisteredObjectCN)
{}

CEvaluationNodeObject::~CEvaluationNodeObject() {}

bool CEvaluationNodeObject::compile(const CEvaluationTree * pTree)
{
  const CExpression * pExpression = dynamic_cast< const CExpression * >(pTree);
  if (!pExpression) return false;

  const CCopasiObject * pObject =
    pExpression->getNodeObject(mRegisteredObjectCN);

  if (pObject)
    mpValue = (C_FLOAT64 *) pObject->getValuePointer();
  else
    mpValue = NULL;

  if (mpValue == NULL) return false;
  if (!pObject->isValueDbl()) return false;

  mData = "<" + mRegisteredObjectCN + ">";

  return (getChild() == NULL); // We must not have any children.
}

CEvaluationNode::Data CEvaluationNodeObject::getData() const
{return "<" + mRegisteredObjectCN + ">";}

bool CEvaluationNodeObject::setData(const Data & data)
{
  mData = data;
  mRegisteredObjectCN = data.substr(1, data.length() - 2);

  return true;
}

std::string CEvaluationNodeObject::getInfix() const
  {return "<" + mRegisteredObjectCN + ">";}

#if 0
std::string CEvaluationNodeObject::getDisplayString(const CEvaluationTree * pTree) const
  {
    const CExpression * pExpression = dynamic_cast< const CExpression * >(pTree);
    if (!pExpression) return false;

    const CCopasiObject * pObject =
      CCopasiContainer::ObjectFromName(mRegisteredObjectCN);

    if (pObject == NULL) return "<" + mRegisteredObjectCN + ">";

    return "<" + pObject->getObjectDisplayName() + ">";
  }
#endif

std::string CEvaluationNodeObject::getDisplayString(const CEvaluationTree * /* pTree */) const
  {
    return "<" + mRegisteredObjectCN + ">";
  }

std::string CEvaluationNodeObject::getDisplay_C_String(const CEvaluationTree * /* pTree */) const
  {
    return "<" + mRegisteredObjectCN + ">";
  }

std::string CEvaluationNodeObject::getDisplay_MMD_String(const CEvaluationTree * /* pTree */) const
  {
    return "<" + mRegisteredObjectCN + ">";
  }

std::string CEvaluationNodeObject::getDisplay_XPP_String(const CEvaluationTree * /* pTree */) const
  {
    return "<" + mRegisteredObjectCN + ">";
  }

CEvaluationNode* CEvaluationNodeObject::createNodeFromASTTree(const ASTNode& node)
{
  CEvaluationNodeObject* pNode = NULL;
  ASTNodeType_t type = node.getType();
  switch (type)
    {
    case AST_NAME_TIME:
    case AST_NAME:
      pNode = new CEvaluationNodeObject(ANY, CCopasiObjectName(std::string("<") + node.getName() + std::string(">")));
      break;
    default:
      break;
    }
  return pNode;
}

ASTNode* CEvaluationNodeObject::toAST() const
  {
    ASTNode* node = new ASTNode();
    node->setType(AST_NAME);
    // since I can not get the model in which this node is located, I just
    // assume that it will always be the current global model.
    CCopasiObject* object = CCopasiContainer::ObjectFromName(mRegisteredObjectCN);
    assert(object);
    // if it is a reference, we get the parent of the reference
    if (object->isReference())
      {
        object = object->getObjectParent();
      }
    // actually we need to get the name from the key of the copasi object
    SBase* pSBase = CCopasiDataModel::Global->getCopasi2SBMLMap()[object];
    CModel* pModel = NULL;
    if (pSBase)
      {
        switch (pSBase->getTypeCode())
          {
          case SBML_COMPARTMENT:
            node->setName(dynamic_cast<Compartment*>(pSBase)->getId().c_str());
            break;
          case SBML_SPECIES:
            node->setName(dynamic_cast<Species*>(pSBase)->getId().c_str());
            break;
          case SBML_PARAMETER:
            node->setName(dynamic_cast<Parameter*>(pSBase)->getId().c_str());
            break;
          case SBML_REACTION:
            node->setName(dynamic_cast<Reaction*>(pSBase)->getId().c_str());
            break;
          case SBML_MODEL:
            node->setType(AST_NAME_TIME);
            node->setName("time");
            pModel = dynamic_cast<CModel*>(object);
            if (pModel == NULL)
              {
                fatalError();
              }
            if (pModel->getInitialTime() != 0.0)
              {
                CCopasiMessage(CCopasiMessage::WARNING, MCSBML + 1);
              }
            break;
          default:
            CCopasiMessage(CCopasiMessage::EXCEPTION, MCEvaluationNodeObject + 1);
            break;
          }
      }
    else
      {
        // it must be a local parameter
        node->setName(object->getObjectName().c_str());
      }
    return node;
  }

const CRegisteredObjectName & CEvaluationNodeObject::getObjectCN() const
  {return mRegisteredObjectCN;}

#include "utilities/copasimathml.h"

void CEvaluationNodeObject::writeMathML(std::ostream & out,
                                        const std::vector<std::vector<std::string> > & /* env */,
                                        bool /* expand */,
                                        unsigned C_INT32 l) const
  {
    const CCopasiObject* obj = CCopasiContainer::ObjectFromName(mRegisteredObjectCN);
    out << SPC(l) << CMathMl::getMMLName(obj) << std::endl;
    //or use mValue instead?
  }
<commit_msg>bug fixed: the changes  (from 23.11.2007) in getDisplay_C/MMD/XPPAUT_String are incorrect<commit_after>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/function/CEvaluationNodeObject.cpp,v $
//   $Revision: 1.30 $
//   $Name:  $
//   $Author: nsimus $
//   $Date: 2007/11/27 10:40:33 $
// End CVS Header

// Copyright (C) 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include "copasi.h"
#include "CEvaluationNode.h"
#include "CEvaluationTree.h"
#include "CExpression.h"
#include "report/CCopasiObjectName.h"
#include "report/CCopasiObject.h"
#include "report/CCopasiContainer.h"
#include "model/CModel.h"
#include "CopasiDataModel/CCopasiDataModel.h"

#include "sbml/math/ASTNode.h"
#include "sbml/SBase.h"
#include "sbml/SBMLTypeCodes.h"
#include "sbml/Compartment.h"
#include "sbml/Species.h"
#include "sbml/Parameter.h"
#include "sbml/Reaction.h"

CEvaluationNodeObject::CEvaluationNodeObject():
    CEvaluationNode(CEvaluationNode::INVALID, ""),
    mpValue(NULL),
    mRegisteredObjectCN("")
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeObject::CEvaluationNodeObject(const SubType & subType,
    const Data & data):
    CEvaluationNode((Type) (CEvaluationNode::OBJECT | subType), data),
    mpValue(NULL),
    mRegisteredObjectCN(data.substr(1, data.length() - 2))
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeObject::CEvaluationNodeObject(const CEvaluationNodeObject & src):
    CEvaluationNode(src),
    mpValue(src.mpValue),
    mRegisteredObjectCN(src.mRegisteredObjectCN)
{}

CEvaluationNodeObject::~CEvaluationNodeObject() {}

bool CEvaluationNodeObject::compile(const CEvaluationTree * pTree)
{
  const CExpression * pExpression = dynamic_cast< const CExpression * >(pTree);
  if (!pExpression) return false;

  const CCopasiObject * pObject =
    pExpression->getNodeObject(mRegisteredObjectCN);

  if (pObject)
    mpValue = (C_FLOAT64 *) pObject->getValuePointer();
  else
    mpValue = NULL;

  if (mpValue == NULL) return false;
  if (!pObject->isValueDbl()) return false;

  mData = "<" + mRegisteredObjectCN + ">";

  return (getChild() == NULL); // We must not have any children.
}

CEvaluationNode::Data CEvaluationNodeObject::getData() const
{return "<" + mRegisteredObjectCN + ">";}

bool CEvaluationNodeObject::setData(const Data & data)
{
  mData = data;
  mRegisteredObjectCN = data.substr(1, data.length() - 2);

  return true;
}

std::string CEvaluationNodeObject::getInfix() const
  {return "<" + mRegisteredObjectCN + ">";}

#if 0
std::string CEvaluationNodeObject::getDisplayString(const CEvaluationTree * pTree) const
  {
    const CExpression * pExpression = dynamic_cast< const CExpression * >(pTree);
    if (!pExpression) return false;

    const CCopasiObject * pObject =
      CCopasiContainer::ObjectFromName(mRegisteredObjectCN);

    if (pObject == NULL) return "<" + mRegisteredObjectCN + ">";

    return "<" + pObject->getObjectDisplayName() + ">";
  }
#endif

std::string CEvaluationNodeObject::getDisplayString(const CEvaluationTree * /* pTree */) const
  {
    return "<" + mRegisteredObjectCN + ">";
  }

std::string CEvaluationNodeObject::getDisplay_C_String(const CEvaluationTree * /* pTree */) const
  {
    return mData;
  }

std::string CEvaluationNodeObject::getDisplay_MMD_String(const CEvaluationTree * /* pTree */) const
  {
    return mData;
  }

std::string CEvaluationNodeObject::getDisplay_XPP_String(const CEvaluationTree * /* pTree */) const
  {
    return mData;
  }

CEvaluationNode* CEvaluationNodeObject::createNodeFromASTTree(const ASTNode& node)
{
  CEvaluationNodeObject* pNode = NULL;
  ASTNodeType_t type = node.getType();
  switch (type)
    {
    case AST_NAME_TIME:
    case AST_NAME:
      pNode = new CEvaluationNodeObject(ANY, CCopasiObjectName(std::string("<") + node.getName() + std::string(">")));
      break;
    default:
      break;
    }
  return pNode;
}

ASTNode* CEvaluationNodeObject::toAST() const
  {
    ASTNode* node = new ASTNode();
    node->setType(AST_NAME);
    // since I can not get the model in which this node is located, I just
    // assume that it will always be the current global model.
    CCopasiObject* object = CCopasiContainer::ObjectFromName(mRegisteredObjectCN);
    assert(object);
    // if it is a reference, we get the parent of the reference
    if (object->isReference())
      {
        object = object->getObjectParent();
      }
    // actually we need to get the name from the key of the copasi object
    SBase* pSBase = CCopasiDataModel::Global->getCopasi2SBMLMap()[object];
    CModel* pModel = NULL;
    if (pSBase)
      {
        switch (pSBase->getTypeCode())
          {
          case SBML_COMPARTMENT:
            node->setName(dynamic_cast<Compartment*>(pSBase)->getId().c_str());
            break;
          case SBML_SPECIES:
            node->setName(dynamic_cast<Species*>(pSBase)->getId().c_str());
            break;
          case SBML_PARAMETER:
            node->setName(dynamic_cast<Parameter*>(pSBase)->getId().c_str());
            break;
          case SBML_REACTION:
            node->setName(dynamic_cast<Reaction*>(pSBase)->getId().c_str());
            break;
          case SBML_MODEL:
            node->setType(AST_NAME_TIME);
            node->setName("time");
            pModel = dynamic_cast<CModel*>(object);
            if (pModel == NULL)
              {
                fatalError();
              }
            if (pModel->getInitialTime() != 0.0)
              {
                CCopasiMessage(CCopasiMessage::WARNING, MCSBML + 1);
              }
            break;
          default:
            CCopasiMessage(CCopasiMessage::EXCEPTION, MCEvaluationNodeObject + 1);
            break;
          }
      }
    else
      {
        // it must be a local parameter
        node->setName(object->getObjectName().c_str());
      }
    return node;
  }

const CRegisteredObjectName & CEvaluationNodeObject::getObjectCN() const
  {return mRegisteredObjectCN;}

#include "utilities/copasimathml.h"

void CEvaluationNodeObject::writeMathML(std::ostream & out,
                                        const std::vector<std::vector<std::string> > & /* env */,
                                        bool /* expand */,
                                        unsigned C_INT32 l) const
  {
    const CCopasiObject* obj = CCopasiContainer::ObjectFromName(mRegisteredObjectCN);
    out << SPC(l) << CMathMl::getMMLName(obj) << std::endl;
    //or use mValue instead?
  }
<|endoftext|>


<commit_before><commit_msg>explicitly configuring the viewport to not draw a background<commit_after><|endoftext|>


<commit_before>// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2005 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include "copasi.h"
#include "CEvaluationNode.h"
#include "CEvaluationTree.h"
#include "CExpression.h"
#include "report/CCopasiObjectName.h"
#include "report/CCopasiObject.h"
#include "report/CCopasiContainer.h"
#include "model/CModel.h"
#include "CopasiDataModel/CCopasiDataModel.h"
#include "math/CMathObject.h"
#include "math/CMathContainer.h"
#include "utilities/CValidatedUnit.h"

#include "sbml/math/ASTNode.h"
#include "sbml/SBase.h"
#include "sbml/SBMLTypeCodes.h"
#include "sbml/Compartment.h"
#include "sbml/Species.h"
#include "sbml/Parameter.h"
#include "sbml/Reaction.h"

CEvaluationNodeObject::CEvaluationNodeObject():
  CEvaluationNode(CEvaluationNode::INVALID, ""),
  mpObject(NULL),
  mRegisteredObjectCN("")
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeObject::CEvaluationNodeObject(const SubType & subType,
    const Data & data):
  CEvaluationNode((Type)(CEvaluationNode::OBJECT | subType), data),
  mpObject(NULL),
  mRegisteredObjectCN()
{
  switch (subType)
    {
      case INVALID:
        break;

      case CN:
        mRegisteredObjectCN = data.substr(1, data.length() - 2);
        break;

      case POINTER:
        mpValue = (const C_FLOAT64 *) stringToPointer(data);
        break;
    }

  mPrecedence = PRECEDENCE_NUMBER;
}

CEvaluationNodeObject::CEvaluationNodeObject(const C_FLOAT64 * pValue):
  CEvaluationNode((Type)(CEvaluationNode::OBJECT | POINTER), "pointer"),
  mpObject(NULL),
  mRegisteredObjectCN("")
{
  mPrecedence = PRECEDENCE_NUMBER;
  mpValue = pValue;
  mData = pointerToString(pValue);
}

CEvaluationNodeObject::CEvaluationNodeObject(const CEvaluationNodeObject & src):
  CEvaluationNode(src),
  mpObject(src.mpObject),
  mRegisteredObjectCN(src.mRegisteredObjectCN)
{
  mpValue = src.mpValue;
}

CEvaluationNodeObject::~CEvaluationNodeObject() {}

bool CEvaluationNodeObject::compile(const CEvaluationTree * pTree)
{
  mpObject = NULL;
  mpValue = NULL;

  switch ((int) subType(mType))
    {
      case CN:
      {
        const CExpression * pExpression = dynamic_cast< const CExpression * >(pTree);

        if (!pExpression) return false;

        mpObject =
          pExpression->getNodeObject(mRegisteredObjectCN);

        const CCopasiObject * pDataObject = dynamic_cast< const CCopasiObject * >(mpObject);

        if (pDataObject != NULL)
          {
            // We may have some container objects for which the value is an included
            // reference. For the math model to work this needs to be corrected.
            const CObjectInterface * pObject = pDataObject->getValueObject();

            if (!pObject)
              return false;

            if (mpObject != pObject && pObject != NULL)
              {
                mpObject = pObject;
                mRegisteredObjectCN = mpObject->getCN();
                mData = getData();
              }

            if (pDataObject->isValueDbl())
              {
                mpValue = (C_FLOAT64 *) mpObject->getValuePointer();
              }
          }
        else if (mpObject != NULL)
          {
            mpValue = (C_FLOAT64 *) mpObject->getValuePointer();
          }

        if (mpValue == NULL)
          {
            mValue = std::numeric_limits<C_FLOAT64>::quiet_NaN();
            mpValue = &mValue;
            return false;
          }

        mData = "<" + mRegisteredObjectCN + ">";
      }
      break;

      case POINTER:
        // We need to convert the data into a pointer
        mpValue = (const C_FLOAT64 *) stringToPointer(mData);

        if (pTree != NULL)
          {
            CMathContainer * pContainer = dynamic_cast< CMathContainer * >(pTree->getObjectAncestor("CMathContainer"));

            if (pContainer != NULL)
              {
                mpObject = pContainer->getMathObject(mpValue);
              }
          }

        break;

      case INVALID:
        break;
    }

  return (getChild() == NULL); // We must not have any children.
}

const CEvaluationNode::Data & CEvaluationNodeObject::getData() const
{
  static std::string data;

  switch ((int) subType(mType))
    {
      case CN:
        return data = "<" + mRegisteredObjectCN + ">";
        break;

      case POINTER:
        return mData;
        break;
    }

  return mData;
}

bool CEvaluationNodeObject::setData(const Data & data)
{
  mData = data;

  if ((int) subType(mType) == (int) CN)
    mRegisteredObjectCN = data.substr(1, data.length() - 2);

  return true;
}

// virtual
std::string CEvaluationNodeObject::getInfix(const std::vector< std::string > & /* children */) const
{
  switch ((int) subType(mType))
    {
      case CN:
        return "<" + mRegisteredObjectCN + ">";
        break;

      case POINTER:
        return mData;
        break;
    }

  return mData;
}

#if 0
std::string CEvaluationNodeObject::getDisplayString(const CEvaluationTree * pTree) const
{
  const CExpression * pExpression = dynamic_cast< const CExpression * >(pTree);

  if (!pExpression) return false;

  const CCopasiObject * pObject =
    CCopasiContainer::ObjectFromCN(mRegisteredObjectCN);

  if (pObject == NULL) return "<" + mRegisteredObjectCN + ">";

  return "<" + pObject->getObjectDisplayName() + ">";
}
#endif

// virtual
std::string CEvaluationNodeObject::getDisplayString(const std::vector< std::string > & /* children */) const
{
  const CCopasiObject* object = dynamic_cast<const CCopasiObject*>(mpObject);

  if (object != NULL)
    return object->getObjectDisplayName();

  return "<" + mRegisteredObjectCN + ">";
}

// virtual
std::string CEvaluationNodeObject::getCCodeString(const std::vector< std::string > & /* children */) const
{
  return mData;
}

// virtual
std::string CEvaluationNodeObject::getBerkeleyMadonnaString(const std::vector< std::string > & /* children */) const
{
  return mData;
}

// virtual
std::string CEvaluationNodeObject::getXPPString(const std::vector< std::string > & /* children */) const
{
  return mData;
}

// static
CEvaluationNode * CEvaluationNodeObject::fromAST(const ASTNode * pASTNode, const std::vector< CEvaluationNode * > & children)
{
  assert(pASTNode->getNumChildren() == children.size());

  CEvaluationNodeObject* pNode = NULL;

  switch (pASTNode->getType())
    {
      case AST_NAME_AVOGADRO:
      case AST_NAME_TIME:
      case AST_NAME:
        pNode = new CEvaluationNodeObject(CN, CCopasiObjectName(std::string("<") + pASTNode->getName() + std::string(">")));
        break;

      default:
        break;
    }

  return pNode;
}

ASTNode* CEvaluationNodeObject::toAST(const CCopasiDataModel* pDataModel) const
{
  ASTNode* node = new ASTNode();
  node->setType(AST_NAME);

  if (mRegisteredObjectCN == "rateOf")
    {
      node->setType(AST_FUNCTION);
      const CEvaluationNode* child = dynamic_cast<const CEvaluationNode*>(this->getChild());

      if (child == NULL) fatalError();

      const CEvaluationNodeObject* sibling = dynamic_cast<const CEvaluationNodeObject*>(this->getChild()->getSibling());

      if (sibling == NULL) fatalError();

      node->setName(sibling->getObjectCN().c_str());
      node->addChild(child->toAST(pDataModel));
      return node;
    }

  // since I can not get the model in which this node is located, I just
  // assume that it will always be the current global model.
  const CCopasiObject* pOrigObject = CObjectInterface::DataObject(pDataModel->getObjectFromCN(mRegisteredObjectCN));

  if (pOrigObject == NULL)
    {
      node->setName(mRegisteredObjectCN.c_str());
      return node;
    }

  const CCopasiObject* pObject = pOrigObject;

  // if it is a reference, we get the parent of the reference
  if (pObject->isReference())
    {
      pObject = pObject->getObjectParent();
    }

  const CModelEntity* pME = dynamic_cast<const CModelEntity*>(pObject);

  if (pME != NULL)
    {
      const CModel* pModel = dynamic_cast<const CModel*>(pME);

      if (pModel != NULL)
        {
#if LIBSBML_VERSION >= 40100

          if (pOrigObject->getObjectName() == "Avogadro Constant")
            {
              node->setType(AST_NAME_AVOGADRO);
              node->setName("avogadro");
            }
          else
            {
#endif // LIBSBML_VERSION >= 40100
              node->setType(AST_NAME_TIME);
              node->setName("time");

              if (pModel->getInitialTime() != 0.0)
                {
                  CCopasiMessage(CCopasiMessage::WARNING, MCSBML + 1);
                }

#if LIBSBML_VERSION >= 40100
            }

#endif // LIBSBML_VERSION >= 40100
        }
      else
        {
          node->setName(pME->getSBMLId().c_str());
        }
    }
  else
    {
      const CCopasiParameter* pPara = dynamic_cast<const CCopasiParameter*>(pObject);

      if (pPara != NULL)
        {
          // now we have to use the common name as the name for the
          // node since we need to be able to identify local parameters
          // in arbitrary expressions for the export
          node->setName(pPara->getCN().c_str());
        }
      else
        {
          const CReaction* pReaction = dynamic_cast<const CReaction*>(pObject);

          if (pReaction)
            {
              node->setName(pReaction->getSBMLId().c_str());
            }
          else
            {
              fatalError();
            }
        }
    }

  return node;
}

const CRegisteredObjectName & CEvaluationNodeObject::getObjectCN() const
{return mRegisteredObjectCN;}

const CObjectInterface * CEvaluationNodeObject::getObjectInterfacePtr() const
{
  return mpObject;
}

const C_FLOAT64 * CEvaluationNodeObject::getObjectValuePtr() const
{
  return mpValue;
}

void CEvaluationNodeObject::setObjectValuePtr(C_FLOAT64 * pObjectValue)
{
  assert(pObjectValue);

  switch ((int) subType(mType))
    {
      case CN:
        break;

      case POINTER:

        if (mpValue != pObjectValue)
          {
            mpValue = pObjectValue;
            mData = pointerToString(mpValue);
          }

        break;
    }

  return;
}

#include "utilities/copasimathml.h"

// virtual
std::string CEvaluationNodeObject::getMMLString(const std::vector< std::string > & /* children */ ,
    bool /* expand */,
    const std::vector< std::vector< std::string > > & /* variables */) const
{
  std::ostringstream out;

  const CCopasiObject * pDataObject = CObjectInterface::DataObject(mpObject);

  out << CMathMl::getMMLName(pDataObject) << std::endl;

  return out.str();
}

// virtual
CValidatedUnit CEvaluationNodeObject::getUnit(const CMathContainer & container,
    const std::vector< CValidatedUnit > & units) const
{
  const CObjectInterface * pObject = container.getMathObject(mpValue);
  const CCopasiObject * pDataObject = (pObject != NULL) ? pObject->getDataObject() : NULL;

  if (pDataObject != NULL)
    {
      return CValidatedUnit::merge(units[0], CValidatedUnit(pDataObject->getUnits(), false));
    }

  return CValidatedUnit::merge(units[0], CValidatedUnit());
}
<commit_msg>Fixed assertion failure CEvaluationNodeObject::setObjectValuePtr.<commit_after>// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2005 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

#include "copasi.h"
#include "CEvaluationNode.h"
#include "CEvaluationTree.h"
#include "CExpression.h"
#include "report/CCopasiObjectName.h"
#include "report/CCopasiObject.h"
#include "report/CCopasiContainer.h"
#include "model/CModel.h"
#include "CopasiDataModel/CCopasiDataModel.h"
#include "math/CMathObject.h"
#include "math/CMathContainer.h"
#include "utilities/CValidatedUnit.h"

#include "sbml/math/ASTNode.h"
#include "sbml/SBase.h"
#include "sbml/SBMLTypeCodes.h"
#include "sbml/Compartment.h"
#include "sbml/Species.h"
#include "sbml/Parameter.h"
#include "sbml/Reaction.h"

CEvaluationNodeObject::CEvaluationNodeObject():
  CEvaluationNode(CEvaluationNode::INVALID, ""),
  mpObject(NULL),
  mRegisteredObjectCN("")
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeObject::CEvaluationNodeObject(const SubType & subType,
    const Data & data):
  CEvaluationNode((Type)(CEvaluationNode::OBJECT | subType), data),
  mpObject(NULL),
  mRegisteredObjectCN()
{
  switch (subType)
    {
      case INVALID:
        break;

      case CN:
        mRegisteredObjectCN = data.substr(1, data.length() - 2);
        break;

      case POINTER:
        mpValue = (const C_FLOAT64 *) stringToPointer(data);
        break;
    }

  mPrecedence = PRECEDENCE_NUMBER;
}

CEvaluationNodeObject::CEvaluationNodeObject(const C_FLOAT64 * pValue):
  CEvaluationNode((Type)(CEvaluationNode::OBJECT | POINTER), "pointer"),
  mpObject(NULL),
  mRegisteredObjectCN("")
{
  mPrecedence = PRECEDENCE_NUMBER;
  mpValue = pValue;
  mData = pointerToString(pValue);
}

CEvaluationNodeObject::CEvaluationNodeObject(const CEvaluationNodeObject & src):
  CEvaluationNode(src),
  mpObject(src.mpObject),
  mRegisteredObjectCN(src.mRegisteredObjectCN)
{
  mpValue = src.mpValue;
}

CEvaluationNodeObject::~CEvaluationNodeObject() {}

bool CEvaluationNodeObject::compile(const CEvaluationTree * pTree)
{
  mpObject = NULL;
  mpValue = NULL;

  switch ((int) subType(mType))
    {
      case CN:
      {
        const CExpression * pExpression = dynamic_cast< const CExpression * >(pTree);

        if (!pExpression) return false;

        mpObject =
          pExpression->getNodeObject(mRegisteredObjectCN);

        const CCopasiObject * pDataObject = dynamic_cast< const CCopasiObject * >(mpObject);

        if (pDataObject != NULL)
          {
            // We may have some container objects for which the value is an included
            // reference. For the math model to work this needs to be corrected.
            const CObjectInterface * pObject = pDataObject->getValueObject();

            if (!pObject)
              return false;

            if (mpObject != pObject && pObject != NULL)
              {
                mpObject = pObject;
                mRegisteredObjectCN = mpObject->getCN();
                mData = getData();
              }

            if (pDataObject->isValueDbl())
              {
                mpValue = (C_FLOAT64 *) mpObject->getValuePointer();
              }
          }
        else if (mpObject != NULL)
          {
            mpValue = (C_FLOAT64 *) mpObject->getValuePointer();
          }

        if (mpValue == NULL)
          {
            mValue = std::numeric_limits<C_FLOAT64>::quiet_NaN();
            mpValue = &mValue;
            return false;
          }

        mData = "<" + mRegisteredObjectCN + ">";
      }
      break;

      case POINTER:
        // We need to convert the data into a pointer
        mpValue = (const C_FLOAT64 *) stringToPointer(mData);

        if (pTree != NULL)
          {
            CMathContainer * pContainer = dynamic_cast< CMathContainer * >(pTree->getObjectAncestor("CMathContainer"));

            if (pContainer != NULL)
              {
                mpObject = pContainer->getMathObject(mpValue);
              }
          }

        if (mpValue == NULL)
          {
            mValue = std::numeric_limits<C_FLOAT64>::quiet_NaN();
            mpValue = &mValue;
            return false;
          }

        break;

      case INVALID:
        break;
    }

  return (getChild() == NULL); // We must not have any children.
}

const CEvaluationNode::Data & CEvaluationNodeObject::getData() const
{
  static std::string data;

  switch ((int) subType(mType))
    {
      case CN:
        return data = "<" + mRegisteredObjectCN + ">";
        break;

      case POINTER:
        return mData;
        break;
    }

  return mData;
}

bool CEvaluationNodeObject::setData(const Data & data)
{
  mData = data;

  if ((int) subType(mType) == (int) CN)
    mRegisteredObjectCN = data.substr(1, data.length() - 2);

  return true;
}

// virtual
std::string CEvaluationNodeObject::getInfix(const std::vector< std::string > & /* children */) const
{
  switch ((int) subType(mType))
    {
      case CN:
        return "<" + mRegisteredObjectCN + ">";
        break;

      case POINTER:
        return mData;
        break;
    }

  return mData;
}

#if 0
std::string CEvaluationNodeObject::getDisplayString(const CEvaluationTree * pTree) const
{
  const CExpression * pExpression = dynamic_cast< const CExpression * >(pTree);

  if (!pExpression) return false;

  const CCopasiObject * pObject =
    CCopasiContainer::ObjectFromCN(mRegisteredObjectCN);

  if (pObject == NULL) return "<" + mRegisteredObjectCN + ">";

  return "<" + pObject->getObjectDisplayName() + ">";
}
#endif

// virtual
std::string CEvaluationNodeObject::getDisplayString(const std::vector< std::string > & /* children */) const
{
  const CCopasiObject* object = dynamic_cast<const CCopasiObject*>(mpObject);

  if (object != NULL)
    return object->getObjectDisplayName();

  return "<" + mRegisteredObjectCN + ">";
}

// virtual
std::string CEvaluationNodeObject::getCCodeString(const std::vector< std::string > & /* children */) const
{
  return mData;
}

// virtual
std::string CEvaluationNodeObject::getBerkeleyMadonnaString(const std::vector< std::string > & /* children */) const
{
  return mData;
}

// virtual
std::string CEvaluationNodeObject::getXPPString(const std::vector< std::string > & /* children */) const
{
  return mData;
}

// static
CEvaluationNode * CEvaluationNodeObject::fromAST(const ASTNode * pASTNode, const std::vector< CEvaluationNode * > & children)
{
  assert(pASTNode->getNumChildren() == children.size());

  CEvaluationNodeObject* pNode = NULL;

  switch (pASTNode->getType())
    {
      case AST_NAME_AVOGADRO:
      case AST_NAME_TIME:
      case AST_NAME:
        pNode = new CEvaluationNodeObject(CN, CCopasiObjectName(std::string("<") + pASTNode->getName() + std::string(">")));
        break;

      default:
        break;
    }

  return pNode;
}

ASTNode* CEvaluationNodeObject::toAST(const CCopasiDataModel* pDataModel) const
{
  ASTNode* node = new ASTNode();
  node->setType(AST_NAME);

  if (mRegisteredObjectCN == "rateOf")
    {
      node->setType(AST_FUNCTION);
      const CEvaluationNode* child = dynamic_cast<const CEvaluationNode*>(this->getChild());

      if (child == NULL) fatalError();

      const CEvaluationNodeObject* sibling = dynamic_cast<const CEvaluationNodeObject*>(this->getChild()->getSibling());

      if (sibling == NULL) fatalError();

      node->setName(sibling->getObjectCN().c_str());
      node->addChild(child->toAST(pDataModel));
      return node;
    }

  // since I can not get the model in which this node is located, I just
  // assume that it will always be the current global model.
  const CCopasiObject* pOrigObject = CObjectInterface::DataObject(pDataModel->getObjectFromCN(mRegisteredObjectCN));

  if (pOrigObject == NULL)
    {
      node->setName(mRegisteredObjectCN.c_str());
      return node;
    }

  const CCopasiObject* pObject = pOrigObject;

  // if it is a reference, we get the parent of the reference
  if (pObject->isReference())
    {
      pObject = pObject->getObjectParent();
    }

  const CModelEntity* pME = dynamic_cast<const CModelEntity*>(pObject);

  if (pME != NULL)
    {
      const CModel* pModel = dynamic_cast<const CModel*>(pME);

      if (pModel != NULL)
        {
#if LIBSBML_VERSION >= 40100

          if (pOrigObject->getObjectName() == "Avogadro Constant")
            {
              node->setType(AST_NAME_AVOGADRO);
              node->setName("avogadro");
            }
          else
            {
#endif // LIBSBML_VERSION >= 40100
              node->setType(AST_NAME_TIME);
              node->setName("time");

              if (pModel->getInitialTime() != 0.0)
                {
                  CCopasiMessage(CCopasiMessage::WARNING, MCSBML + 1);
                }

#if LIBSBML_VERSION >= 40100
            }

#endif // LIBSBML_VERSION >= 40100
        }
      else
        {
          node->setName(pME->getSBMLId().c_str());
        }
    }
  else
    {
      const CCopasiParameter* pPara = dynamic_cast<const CCopasiParameter*>(pObject);

      if (pPara != NULL)
        {
          // now we have to use the common name as the name for the
          // node since we need to be able to identify local parameters
          // in arbitrary expressions for the export
          node->setName(pPara->getCN().c_str());
        }
      else
        {
          const CReaction* pReaction = dynamic_cast<const CReaction*>(pObject);

          if (pReaction)
            {
              node->setName(pReaction->getSBMLId().c_str());
            }
          else
            {
              fatalError();
            }
        }
    }

  return node;
}

const CRegisteredObjectName & CEvaluationNodeObject::getObjectCN() const
{return mRegisteredObjectCN;}

const CObjectInterface * CEvaluationNodeObject::getObjectInterfacePtr() const
{
  return mpObject;
}

const C_FLOAT64 * CEvaluationNodeObject::getObjectValuePtr() const
{
  return mpValue;
}

void CEvaluationNodeObject::setObjectValuePtr(C_FLOAT64 * pObjectValue)
{
  switch ((int) subType(mType))
    {
      case CN:
        break;

      case POINTER:

        if (mpValue != pObjectValue)
          {
            mpValue = pObjectValue;
            mData = pointerToString(mpValue);

            if (mpValue == NULL)
              {
                mpValue = &mValue;
              }
          }

        break;
    }

  return;
}

#include "utilities/copasimathml.h"

// virtual
std::string CEvaluationNodeObject::getMMLString(const std::vector< std::string > & /* children */ ,
    bool /* expand */,
    const std::vector< std::vector< std::string > > & /* variables */) const
{
  std::ostringstream out;

  const CCopasiObject * pDataObject = CObjectInterface::DataObject(mpObject);

  out << CMathMl::getMMLName(pDataObject) << std::endl;

  return out.str();
}

// virtual
CValidatedUnit CEvaluationNodeObject::getUnit(const CMathContainer & container,
    const std::vector< CValidatedUnit > & units) const
{
  const CObjectInterface * pObject = container.getMathObject(mpValue);
  const CCopasiObject * pDataObject = (pObject != NULL) ? pObject->getDataObject() : NULL;

  if (pDataObject != NULL)
    {
      return CValidatedUnit::merge(units[0], CValidatedUnit(pDataObject->getUnits(), false));
    }

  return CValidatedUnit::merge(units[0], CValidatedUnit());
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, Moving Pixel Labs (http://www.mp-labs.net)
 * 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 of conditions 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 materials provided with the distribution.
 *    * Neither the name of the Moving Pixel Labs nor the names of its
 *      contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * 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 MOVING PIXEL LABS 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 <QtCore/QBuffer>
#include <QtCore/QByteArray>

#include <gtest/gtest.h>

#include <data/MetaBlock.hpp>

#include <serialization/KoreSerializer.hpp>

#include "../data/MyBlock.hpp"
#include "../data/MyBlock1.hpp"
#include "../data/MyBlock2.hpp"
#include "../data/MyLibrary.hpp"

using namespace DataTestModule;
using namespace Kore::data;
using namespace Kore::serialization;

TEST( SerializationTest, SerializeBlock )
{
    MyBlock1* block = K_BLOCK_CREATE_INSTANCE( MyBlock1 );
    block->setLeInt( 123456 );
    block->setLaString( "Hello World!" );

    QByteArray buffer;
    QBuffer device( & buffer );
    device.open( QIODevice::ReadWrite );

    int err;

    KoreSerializer serializer;
    err = serializer.deflate( & device, block, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    // Reset...
    device.seek( 0 );

    Block* inflatedBlock;
    err = serializer.inflate( & device, & inflatedBlock, K_NULL );

    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;
    ASSERT_TRUE( K_NULL != inflatedBlock );

    ASSERT_TRUE( inflatedBlock->fastInherits< MyBlock1 >() );

    EXPECT_TRUE( block->leInt() == inflatedBlock->to< MyBlock1 >()->leInt() );

    EXPECT_TRUE( block->laString() ==
                 inflatedBlock->to< MyBlock1 >()->laString() );

    delete block;
    delete inflatedBlock;
}

TEST( SerializationTest, SerializeTree )
{
    MyLibrary* lib1 = K_BLOCK_CREATE_INSTANCE( MyLibrary );

    MyBlock1* block1 = K_BLOCK_CREATE_INSTANCE( MyBlock1 );
    block1->setLeInt( 123 );
    block1->setLaString( "Blabla" );
    block1->leCustomType().laString = "Ahahah";
    block1->leCustomType().leInt32 = 254;

    lib1->addBlock( block1 );

    MyLibrary* lib2 = K_BLOCK_CREATE_INSTANCE( MyLibrary );
    lib1->addBlock( lib2 );

    MyBlock1* block2 = K_BLOCK_CREATE_INSTANCE( MyBlock1 );
    block2->setLeInt( 456 );
    block2->setLaString( "Tududu" );
    lib2->addBlock( block2 );

    // This type is not serializable !
    MyBlock2* block3 = K_BLOCK_CREATE_INSTANCE( MyBlock2 );
    lib2->addBlock( block3 );

    ASSERT_TRUE( lib1->size() == 2 );
    ASSERT_TRUE( lib1->at( 0 )->fastInherits< MyBlock1 >() );
    EXPECT_TRUE( lib1->at< MyBlock1 >( 0 )->leInt() == 123 );
    EXPECT_TRUE( lib1->at< MyBlock1 >( 0 )->laString() == "Blabla" );
    EXPECT_TRUE( lib1->at< MyBlock1 >( 0 )->leCustomType().laString ==
                 "Ahahah" );
    EXPECT_TRUE( lib1->at< MyBlock1 >( 0 )->leCustomType().leInt32 == 254 );

    ASSERT_TRUE( lib1->at( 1 )->fastInherits< MyLibrary >() );
    ASSERT_TRUE( lib1->at< MyLibrary >( 1 )->size() == 2 );
    ASSERT_TRUE(
        lib1->at< MyLibrary >( 1 )->at( 0 )->fastInherits< MyBlock1 >() );
    ASSERT_TRUE(
        lib1->at< MyLibrary >( 1 )->at( 1 )->fastInherits< MyBlock2 >() );
    EXPECT_TRUE(
        lib1->at< MyLibrary >( 1 )->at< MyBlock1 >( 0 )->leInt() == 456 );
    EXPECT_TRUE( lib1->at< MyLibrary >( 1 )->at< MyBlock1 >( 0 )->laString() ==
                 "Tududu" );

    // Now serialize
    QByteArray buffer;
    QBuffer device( & buffer );
    device.open( QIODevice::ReadWrite );

    int err;

    KoreSerializer serializer;
    err = serializer.deflate( & device, lib1, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    // Reset...
    device.seek( 0 );

    Block* inflatedBlock;
    err = serializer.inflate( & device, & inflatedBlock, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    ASSERT_TRUE( inflatedBlock->fastInherits< MyLibrary >() );

    MyLibrary* iLib1 = inflatedBlock->to< MyLibrary >();

    ASSERT_TRUE( iLib1->size() == 2 ) << iLib1->size() << " child block(s)";
    ASSERT_TRUE( iLib1->at( 0 )->fastInherits< MyBlock1 >() );
    EXPECT_TRUE( iLib1->at< MyBlock1 >( 0 )->leInt() == 123 );
    EXPECT_TRUE( iLib1->at< MyBlock1 >( 0 )->laString() == "Blabla" );
    EXPECT_TRUE( iLib1->at< MyBlock1 >( 0 )->leCustomType().laString ==
                 "Ahahah" );
    EXPECT_TRUE( iLib1->at< MyBlock1 >( 0 )->leCustomType().leInt32 == 254 );

    ASSERT_TRUE( iLib1->at( 1 )->fastInherits< MyLibrary >() );
    EXPECT_TRUE( iLib1->at< MyLibrary >( 1 )->size() == 1 );
    ASSERT_TRUE(
        iLib1->at< MyLibrary >( 1 )->at( 0 )->fastInherits< MyBlock1 >() );
    EXPECT_TRUE(
        iLib1->at< MyLibrary >( 1 )->at< MyBlock1 >( 0 )->leInt() == 456 );
    EXPECT_TRUE( iLib1->at< MyLibrary >( 1 )->at< MyBlock1 >( 0 )->laString() ==
                 "Tududu" );

    delete lib1;
    delete iLib1;
}
<commit_msg>Adding bigger serialization tests.<commit_after>/*
 * Copyright (c) 2013, Moving Pixel Labs (http://www.mp-labs.net)
 * 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 of conditions 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 materials provided with the distribution.
 *    * Neither the name of the Moving Pixel Labs nor the names of its
 *      contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * 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 MOVING PIXEL LABS 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 <QtCore/QBuffer>
#include <QtCore/QByteArray>

#include <gtest/gtest.h>

#include <data/MetaBlock.hpp>

#include <serialization/KoreSerializer.hpp>

#include "../data/MyBlock.hpp"
#include "../data/MyBlock1.hpp"
#include "../data/MyBlock2.hpp"
#include "../data/MyLibrary.hpp"

using namespace DataTestModule;
using namespace Kore::data;
using namespace Kore::serialization;

TEST( SerializationTest, SerializeBlock )
{
    MyBlock1* block = K_BLOCK_CREATE_INSTANCE( MyBlock1 );
    block->setLeInt( 123456 );
    block->setLaString( "Hello World!" );

    QByteArray buffer;
    QBuffer device( & buffer );
    device.open( QIODevice::ReadWrite );

    int err;

    KoreSerializer serializer;
    err = serializer.deflate( & device, block, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    // Reset...
    device.seek( 0 );

    Block* inflatedBlock;
    err = serializer.inflate( & device, & inflatedBlock, K_NULL );

    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;
    ASSERT_TRUE( K_NULL != inflatedBlock );

    ASSERT_TRUE( inflatedBlock->fastInherits< MyBlock1 >() );

    EXPECT_TRUE( block->leInt() == inflatedBlock->to< MyBlock1 >()->leInt() );

    EXPECT_TRUE( block->laString() ==
                 inflatedBlock->to< MyBlock1 >()->laString() );

    delete block;
    delete inflatedBlock;
}

TEST( SerializationTest, SerializeTree )
{
    MyLibrary* lib1 = K_BLOCK_CREATE_INSTANCE( MyLibrary );

    MyBlock1* block1 = K_BLOCK_CREATE_INSTANCE( MyBlock1 );
    block1->setLeInt( 123 );
    block1->setLaString( "Blabla" );
    block1->leCustomType().laString = "Ahahah";
    block1->leCustomType().leInt32 = 254;

    lib1->addBlock( block1 );

    MyLibrary* lib2 = K_BLOCK_CREATE_INSTANCE( MyLibrary );
    lib1->addBlock( lib2 );

    MyBlock1* block2 = K_BLOCK_CREATE_INSTANCE( MyBlock1 );
    block2->setLeInt( 456 );
    block2->setLaString( "Tududu" );
    lib2->addBlock( block2 );

    // This type is not serializable !
    MyBlock2* block3 = K_BLOCK_CREATE_INSTANCE( MyBlock2 );
    lib2->addBlock( block3 );

    ASSERT_TRUE( lib1->size() == 2 );
    ASSERT_TRUE( lib1->at( 0 )->fastInherits< MyBlock1 >() );
    EXPECT_TRUE( lib1->at< MyBlock1 >( 0 )->leInt() == 123 );
    EXPECT_TRUE( lib1->at< MyBlock1 >( 0 )->laString() == "Blabla" );
    EXPECT_TRUE( lib1->at< MyBlock1 >( 0 )->leCustomType().laString ==
                 "Ahahah" );
    EXPECT_TRUE( lib1->at< MyBlock1 >( 0 )->leCustomType().leInt32 == 254 );

    ASSERT_TRUE( lib1->at( 1 )->fastInherits< MyLibrary >() );
    ASSERT_TRUE( lib1->at< MyLibrary >( 1 )->size() == 2 );
    ASSERT_TRUE(
        lib1->at< MyLibrary >( 1 )->at( 0 )->fastInherits< MyBlock1 >() );
    ASSERT_TRUE(
        lib1->at< MyLibrary >( 1 )->at( 1 )->fastInherits< MyBlock2 >() );
    EXPECT_TRUE(
        lib1->at< MyLibrary >( 1 )->at< MyBlock1 >( 0 )->leInt() == 456 );
    EXPECT_TRUE( lib1->at< MyLibrary >( 1 )->at< MyBlock1 >( 0 )->laString() ==
                 "Tududu" );

    // Now serialize
    QByteArray buffer;
    QBuffer device( & buffer );
    device.open( QIODevice::ReadWrite );

    int err;

    KoreSerializer serializer;
    err = serializer.deflate( & device, lib1, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    // Reset...
    device.seek( 0 );

    Block* inflatedBlock;
    err = serializer.inflate( & device, & inflatedBlock, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    ASSERT_TRUE( inflatedBlock->fastInherits< MyLibrary >() );

    MyLibrary* iLib1 = inflatedBlock->to< MyLibrary >();

    ASSERT_TRUE( iLib1->size() == 2 ) << iLib1->size() << " child block(s)";
    ASSERT_TRUE( iLib1->at( 0 )->fastInherits< MyBlock1 >() );
    EXPECT_TRUE( iLib1->at< MyBlock1 >( 0 )->leInt() == 123 );
    EXPECT_TRUE( iLib1->at< MyBlock1 >( 0 )->laString() == "Blabla" );
    EXPECT_TRUE( iLib1->at< MyBlock1 >( 0 )->leCustomType().laString ==
                 "Ahahah" );
    EXPECT_TRUE( iLib1->at< MyBlock1 >( 0 )->leCustomType().leInt32 == 254 );

    ASSERT_TRUE( iLib1->at( 1 )->fastInherits< MyLibrary >() );
    EXPECT_TRUE( iLib1->at< MyLibrary >( 1 )->size() == 1 );
    ASSERT_TRUE(
        iLib1->at< MyLibrary >( 1 )->at( 0 )->fastInherits< MyBlock1 >() );
    EXPECT_TRUE(
        iLib1->at< MyLibrary >( 1 )->at< MyBlock1 >( 0 )->leInt() == 456 );
    EXPECT_TRUE( iLib1->at< MyLibrary >( 1 )->at< MyBlock1 >( 0 )->laString() ==
                 "Tududu" );

    delete lib1;
    delete iLib1;
}

TEST( SerializationTest, SerializeBigTree128 )
{
    const int childrenNb = 128;

    MyLibrary* lib = K_BLOCK_CREATE_INSTANCE( MyLibrary );

    for( int i = 0; i < childrenNb; ++i )
    {
        MyBlock1* block = K_BLOCK_CREATE_INSTANCE( MyBlock1 );
        lib->addBlock( block );
    }

    ASSERT_TRUE( lib->size() == childrenNb );

    // Now serialize
    QByteArray buffer;
    QBuffer device( & buffer );
    device.open( QIODevice::ReadWrite );

    int err;

    KoreSerializer serializer;
    err = serializer.deflate( & device, lib, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    // Reset...
    device.seek( 0 );

    Block* inflatedBlock;
    err = serializer.inflate( & device, & inflatedBlock, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    ASSERT_TRUE( inflatedBlock->fastInherits< MyLibrary >() );

    MyLibrary* iLib = inflatedBlock->to< MyLibrary >();

    ASSERT_TRUE( iLib->size() == childrenNb ) << iLib->size()
                                              << " child block(s)";

    delete lib;
    delete iLib;
}

TEST( SerializationTest, SerializeBigTree512 )
{
    const int childrenNb = 512;

    MyLibrary* lib = K_BLOCK_CREATE_INSTANCE( MyLibrary );

    for( int i = 0; i < childrenNb; ++i )
    {
        MyBlock1* block = K_BLOCK_CREATE_INSTANCE( MyBlock1 );
        lib->addBlock( block );
    }

    ASSERT_TRUE( lib->size() == childrenNb );

    // Now serialize
    QByteArray buffer;
    QBuffer device( & buffer );
    device.open( QIODevice::ReadWrite );

    int err;

    KoreSerializer serializer;
    err = serializer.deflate( & device, lib, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    // Reset...
    device.seek( 0 );

    Block* inflatedBlock;
    err = serializer.inflate( & device, & inflatedBlock, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    ASSERT_TRUE( inflatedBlock->fastInherits< MyLibrary >() );

    MyLibrary* iLib = inflatedBlock->to< MyLibrary >();

    ASSERT_TRUE( iLib->size() == childrenNb ) << iLib->size()
                                              << " child block(s)";

    delete lib;
    delete iLib;
}

TEST( SerializationTest, SerializeBigTree70000 )
{
    const int childrenNb = 70000;

    MyLibrary* lib = K_BLOCK_CREATE_INSTANCE( MyLibrary );

    for( int i = 0; i < childrenNb; ++i )
    {
        MyBlock1* block = K_BLOCK_CREATE_INSTANCE( MyBlock1 );
        lib->addBlock( block );
    }

    ASSERT_TRUE( lib->size() == childrenNb );

    // Now serialize
    QByteArray buffer;
    QBuffer device( & buffer );
    device.open( QIODevice::ReadWrite );

    int err;

    KoreSerializer serializer;
    err = serializer.deflate( & device, lib, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    // Reset...
    device.seek( 0 );

    Block* inflatedBlock;
    err = serializer.inflate( & device, & inflatedBlock, K_NULL );
    ASSERT_TRUE( KoreSerializer::NoError == err ) << "Error code: " << err;

    ASSERT_TRUE( inflatedBlock->fastInherits< MyLibrary >() );

    MyLibrary* iLib = inflatedBlock->to< MyLibrary >();

    ASSERT_TRUE( iLib->size() == childrenNb ) << iLib->size()
                                              << " child block(s)";

    delete lib;
    delete iLib;
}
<|endoftext|>