<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#include "core/thread.hh"
#include "core/do_with.hh"
#include "test-utils.hh"
#include "core/sstring.hh"
#include "core/reactor.hh"
#include "core/semaphore.hh"
#include "core/do_with.hh"
#include "core/future-util.hh"
#include "core/sleep.hh"

using namespace seastar;
using namespace std::chrono_literals;

SEASTAR_TEST_CASE(test_thread_1) {
    return do_with(sstring(), [] (sstring& x) {
        auto t1 = new thread([&x] {
            x = "abc";
        });
        return t1->join().then([&x, t1] {
            BOOST_REQUIRE_EQUAL(x, "abc");
            delete t1;
        });
    });
}

SEASTAR_TEST_CASE(test_thread_2) {
    struct tmp {
        std::vector<thread> threads;
        semaphore sem1{0};
        semaphore sem2{0};
        int counter = 0;
        void thread_fn() {
            sem1.wait(1).get();
            ++counter;
            sem2.signal(1);
        }
    };
    return do_with(tmp(), [] (tmp& x) {
        auto n = 10;
        for (int i = 0; i < n; ++i) {
            x.threads.emplace_back(std::bind(&tmp::thread_fn, &x));
        }
        BOOST_REQUIRE_EQUAL(x.counter, 0);
        x.sem1.signal(n);
        return x.sem2.wait(n).then([&x, n] {
            BOOST_REQUIRE_EQUAL(x.counter, n);
            return parallel_for_each(x.threads.begin(), x.threads.end(), std::mem_fn(&thread::join));
        });
    });
}

SEASTAR_TEST_CASE(test_thread_async) {
    sstring x = "x";
    sstring y = "y";
    auto concat = [] (sstring x, sstring y) {
        sleep(10ms).get();
        return x + y;
    };
    return async(concat, x, y).then([] (sstring xy) {
        BOOST_REQUIRE_EQUAL(xy, "xy");
    });
}

SEASTAR_TEST_CASE(test_thread_async_immed) {
    return async([] { return 3; }).then([] (int three) {
        BOOST_REQUIRE_EQUAL(three, 3);
    });
}

SEASTAR_TEST_CASE(test_thread_async_nested) {
    return async([] {
        return async([] {
            return 3;
        }).get0();
    }).then([] (int three) {
        BOOST_REQUIRE_EQUAL(three, 3);
    });
}

void compute(float& result, bool& done, uint64_t& ctr) {
    while (!done) {
        for (int n = 0; n < 10000; ++n) {
            result += 1 / (result + 1);
            ++ctr;
        }
        thread::yield();
    }
}

SEASTAR_TEST_CASE(test_thread_sched_group) {
    return async([] {
        float metered_ratio = 0.2;
        thread_scheduling_group sched_group(1ms, metered_ratio);
        float metered_result = 0;
        float unmetered_result = 0;
        bool done = false;
        uint64_t u_ctr = 0, m_ctr = 0;
        thread unmetered([&] { compute(unmetered_result, done, u_ctr); });
        thread_attributes metered_thread_attributes;
        metered_thread_attributes.scheduling_group = &sched_group;
        thread metered(metered_thread_attributes, [&] { compute(metered_result, done, m_ctr); });
        sleep(500ms).get();
        done = true;
        when_all(metered.join(), unmetered.join()).discard_result().get();
        auto ratio = float(m_ctr) / (u_ctr + m_ctr);
#ifndef DEBUG
        BOOST_REQUIRE(ratio > metered_ratio - 0.05);
        BOOST_REQUIRE(ratio < metered_ratio + 0.05);
#else
        // debug mode is too slow to test this accurately
        (void)ratio;
#endif
    });
}
<commit_msg>tests/thread: add test for asan false positives<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#include "core/thread.hh"
#include "core/do_with.hh"
#include "test-utils.hh"
#include "core/sstring.hh"
#include "core/reactor.hh"
#include "core/semaphore.hh"
#include "core/do_with.hh"
#include "core/future-util.hh"
#include "core/sleep.hh"

using namespace seastar;
using namespace std::chrono_literals;

SEASTAR_TEST_CASE(test_thread_1) {
    return do_with(sstring(), [] (sstring& x) {
        auto t1 = new thread([&x] {
            x = "abc";
        });
        return t1->join().then([&x, t1] {
            BOOST_REQUIRE_EQUAL(x, "abc");
            delete t1;
        });
    });
}

SEASTAR_TEST_CASE(test_thread_2) {
    struct tmp {
        std::vector<thread> threads;
        semaphore sem1{0};
        semaphore sem2{0};
        int counter = 0;
        void thread_fn() {
            sem1.wait(1).get();
            ++counter;
            sem2.signal(1);
        }
    };
    return do_with(tmp(), [] (tmp& x) {
        auto n = 10;
        for (int i = 0; i < n; ++i) {
            x.threads.emplace_back(std::bind(&tmp::thread_fn, &x));
        }
        BOOST_REQUIRE_EQUAL(x.counter, 0);
        x.sem1.signal(n);
        return x.sem2.wait(n).then([&x, n] {
            BOOST_REQUIRE_EQUAL(x.counter, n);
            return parallel_for_each(x.threads.begin(), x.threads.end(), std::mem_fn(&thread::join));
        });
    });
}

SEASTAR_TEST_CASE(test_thread_async) {
    sstring x = "x";
    sstring y = "y";
    auto concat = [] (sstring x, sstring y) {
        sleep(10ms).get();
        return x + y;
    };
    return async(concat, x, y).then([] (sstring xy) {
        BOOST_REQUIRE_EQUAL(xy, "xy");
    });
}

SEASTAR_TEST_CASE(test_thread_async_immed) {
    return async([] { return 3; }).then([] (int three) {
        BOOST_REQUIRE_EQUAL(three, 3);
    });
}

SEASTAR_TEST_CASE(test_thread_async_nested) {
    return async([] {
        return async([] {
            return 3;
        }).get0();
    }).then([] (int three) {
        BOOST_REQUIRE_EQUAL(three, 3);
    });
}

void compute(float& result, bool& done, uint64_t& ctr) {
    while (!done) {
        for (int n = 0; n < 10000; ++n) {
            result += 1 / (result + 1);
            ++ctr;
        }
        thread::yield();
    }
}

SEASTAR_TEST_CASE(test_thread_sched_group) {
    return async([] {
        float metered_ratio = 0.2;
        thread_scheduling_group sched_group(1ms, metered_ratio);
        float metered_result = 0;
        float unmetered_result = 0;
        bool done = false;
        uint64_t u_ctr = 0, m_ctr = 0;
        thread unmetered([&] { compute(unmetered_result, done, u_ctr); });
        thread_attributes metered_thread_attributes;
        metered_thread_attributes.scheduling_group = &sched_group;
        thread metered(metered_thread_attributes, [&] { compute(metered_result, done, m_ctr); });
        sleep(500ms).get();
        done = true;
        when_all(metered.join(), unmetered.join()).discard_result().get();
        auto ratio = float(m_ctr) / (u_ctr + m_ctr);
#ifndef DEBUG
        BOOST_REQUIRE(ratio > metered_ratio - 0.05);
        BOOST_REQUIRE(ratio < metered_ratio + 0.05);
#else
        // debug mode is too slow to test this accurately
        (void)ratio;
#endif
    });
}

#if defined(ASAN_ENABLED) && defined(HAVE_ASAN_FIBER_SUPPORT)
volatile int force_write;
volatile void* shut_up_gcc;

[[gnu::noinline]]
void throw_exception() {
    volatile char buf[1024];
    shut_up_gcc = &buf;
    for (int i = 0; i < 1024; i++) {
        buf[i] = force_write;
    }
    throw 1;
}

[[gnu::noinline]]
void use_stack() {
    volatile char buf[2 * 1024];
    shut_up_gcc = &buf;
    for (int i = 0; i < 2 * 1024; i++) {
        buf[i] = force_write;
    }
}

SEASTAR_TEST_CASE(test_asan_false_positive) {
    return async([] {
        try {
            throw_exception();
        } catch (...) {
            use_stack();
        }
    });
}
#endif
<|endoftext|>


<commit_before>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef RDB_PROTOCOL_LAZY_JSON_HPP_
#define RDB_PROTOCOL_LAZY_JSON_HPP_

#include "buffer_cache/alt/alt.hpp"
#include "buffer_cache/alt/blob.hpp"
#include "rdb_protocol/datum.hpp"

struct rdb_value_t {
    char contents[];

public:
    int inline_size(max_block_size_t bs) const {
        return blob::ref_size(bs, contents, blob::btree_maxreflen);
    }

    int64_t value_size() const {
        return blob::value_size(contents, blob::btree_maxreflen);
    }

    const char *value_ref() const {
        return contents;
    }

    char *value_ref() {
        return contents;
    }
};

counted_t<const ql::datum_t> get_data(const rdb_value_t *value,
                                      buf_parent_t parent);

class lazy_json_pointee_t : public single_threaded_countable_t<lazy_json_pointee_t> {
    lazy_json_pointee_t(const rdb_value_t *_rdb_value, buf_parent_t _parent)
        : rdb_value(_rdb_value), parent(_parent) {
        guarantee(rdb_value != NULL);
    }

    explicit lazy_json_pointee_t(const counted_t<const ql::datum_t> &_ptr)
        : ptr(_ptr), rdb_value(NULL), parent() {
        guarantee(ptr);
    }

    friend class lazy_json_t;

    // If empty, we haven't loaded the value yet.
    counted_t<const ql::datum_t> ptr;

    // A pointer to the rdb value buffer in the leaf node (or perhaps a copy), and
    // the transaction with which to load it.  Non-NULL only if ptr is empty.
    const rdb_value_t *rdb_value;
    buf_parent_t parent;

    DISABLE_COPYING(lazy_json_pointee_t);
};

class lazy_json_t {
public:
    explicit lazy_json_t(const counted_t<const ql::datum_t> &ptr)
        : pointee(new lazy_json_pointee_t(ptr)) { }

    lazy_json_t(const rdb_value_t *rdb_value, buf_parent_t parent)
        : pointee(new lazy_json_pointee_t(rdb_value, parent)) { }

    const counted_t<const ql::datum_t> &get() const;
    bool references_parent() const;
    void reset();

private:
    counted_t<lazy_json_pointee_t> pointee;
};

#endif  // RDB_PROTOCOL_LAZY_JSON_HPP_
<commit_msg>Added two newlines near the end of lazy_json.hpp.e<commit_after>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef RDB_PROTOCOL_LAZY_JSON_HPP_
#define RDB_PROTOCOL_LAZY_JSON_HPP_

#include "buffer_cache/alt/alt.hpp"
#include "buffer_cache/alt/blob.hpp"
#include "rdb_protocol/datum.hpp"

struct rdb_value_t {
    char contents[];

public:
    int inline_size(max_block_size_t bs) const {
        return blob::ref_size(bs, contents, blob::btree_maxreflen);
    }

    int64_t value_size() const {
        return blob::value_size(contents, blob::btree_maxreflen);
    }

    const char *value_ref() const {
        return contents;
    }

    char *value_ref() {
        return contents;
    }
};

counted_t<const ql::datum_t> get_data(const rdb_value_t *value,
                                      buf_parent_t parent);

class lazy_json_pointee_t : public single_threaded_countable_t<lazy_json_pointee_t> {
    lazy_json_pointee_t(const rdb_value_t *_rdb_value, buf_parent_t _parent)
        : rdb_value(_rdb_value), parent(_parent) {
        guarantee(rdb_value != NULL);
    }

    explicit lazy_json_pointee_t(const counted_t<const ql::datum_t> &_ptr)
        : ptr(_ptr), rdb_value(NULL), parent() {
        guarantee(ptr);
    }

    friend class lazy_json_t;

    // If empty, we haven't loaded the value yet.
    counted_t<const ql::datum_t> ptr;

    // A pointer to the rdb value buffer in the leaf node (or perhaps a copy), and
    // the transaction with which to load it.  Non-NULL only if ptr is empty.
    const rdb_value_t *rdb_value;
    buf_parent_t parent;

    DISABLE_COPYING(lazy_json_pointee_t);
};

class lazy_json_t {
public:
    explicit lazy_json_t(const counted_t<const ql::datum_t> &ptr)
        : pointee(new lazy_json_pointee_t(ptr)) { }

    lazy_json_t(const rdb_value_t *rdb_value, buf_parent_t parent)
        : pointee(new lazy_json_pointee_t(rdb_value, parent)) { }

    const counted_t<const ql::datum_t> &get() const;
    bool references_parent() const;
    void reset();

private:
    counted_t<lazy_json_pointee_t> pointee;
};

#endif  // RDB_PROTOCOL_LAZY_JSON_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "array.h"
#include "compile_options.h"
#include "macros.h"
#include "map.h"
#include "math_utils.h"
#include "physics_resource.h"
#include "sjson.h"
#include "sort_map.h"
#include "temp_allocator.h"
#include "unit_compiler.h"
#include "unit_resource.h"
#include "world_types.h"

namespace crown
{
struct ProjectionInfo
{
	const char* name;
	ProjectionType::Enum type;
};

static const ProjectionInfo s_projection[] =
{
	{ "perspective",  ProjectionType::PERSPECTIVE  },
	{ "orthographic", ProjectionType::ORTHOGRAPHIC }
};
CE_STATIC_ASSERT(CE_COUNTOF(s_projection) == ProjectionType::COUNT);

struct LightInfo
{
	const char* name;
	LightType::Enum type;
};

static const LightInfo s_light[] =
{
	{ "directional", LightType::DIRECTIONAL },
	{ "omni",        LightType::OMNI        },
	{ "spot",        LightType::SPOT        }
};
CE_STATIC_ASSERT(CE_COUNTOF(s_light) == LightType::COUNT);

static ProjectionType::Enum projection_name_to_enum(const char* name)
{
	for (u32 i = 0; i < CE_COUNTOF(s_projection); ++i)
	{
		if (strcmp(name, s_projection[i].name) == 0)
			return s_projection[i].type;
	}

	return ProjectionType::COUNT;
}

static LightType::Enum light_name_to_enum(const char* name)
{
	for (u32 i = 0; i < CE_COUNTOF(s_light); ++i)
	{
		if (strcmp(name, s_light[i].name) == 0)
			return s_light[i].type;
	}

	return LightType::COUNT;
}

static Buffer compile_transform(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	TransformDesc td;
	td.position = sjson::parse_vector3   (obj["position"]);
	td.rotation = sjson::parse_quaternion(obj["rotation"]);
	td.scale    = sjson::parse_vector3   (obj["scale"]);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&td, sizeof(td));
	return buf;
}

static Buffer compile_camera(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	DynamicString type(ta);
	sjson::parse_string(obj["projection"], type);

	ProjectionType::Enum pt = projection_name_to_enum(type.c_str());
	RESOURCE_COMPILER_ASSERT(pt != ProjectionType::COUNT
		, opts
		, "Unknown projection type: '%s'"
		, type.c_str()
		);

	CameraDesc cd;
	cd.type       = pt;
	cd.fov        = sjson::parse_float(obj["fov"]);
	cd.near_range = sjson::parse_float(obj["near_range"]);
	cd.far_range  = sjson::parse_float(obj["far_range"]);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&cd, sizeof(cd));
	return buf;
}

static Buffer compile_mesh_renderer(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	MeshRendererDesc mrd;
	mrd.mesh_resource     = sjson::parse_resource_id(obj["mesh_resource"]);
	mrd.geometry_name     = sjson::parse_string_id  (obj["geometry_name"]);
	mrd.material_resource = sjson::parse_resource_id(obj["material"]);
	mrd.visible           = sjson::parse_bool       (obj["visible"]);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&mrd, sizeof(mrd));
	return buf;
}

static Buffer compile_sprite_renderer(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	SpriteRendererDesc srd;
	srd.sprite_resource   = sjson::parse_resource_id(obj["resource"]);
	srd.material_resource = sjson::parse_resource_id(obj["material"]);
	srd.visible           = sjson::parse_bool       (obj["visible"]);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&srd, sizeof(srd));
	return buf;
}

static Buffer compile_light(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	DynamicString type(ta);
	sjson::parse_string(obj["light"], type);

	LightType::Enum lt = light_name_to_enum(type.c_str());
	RESOURCE_COMPILER_ASSERT(lt != LightType::COUNT
		, opts
		, "Unknown light type: '%s'"
		, type.c_str()
		);

	LightDesc ld;
	ld.type       = lt;
	ld.range      = sjson::parse_float  (obj["range"]);
	ld.intensity  = sjson::parse_float  (obj["intensity"]);
	ld.spot_angle = sjson::parse_float  (obj["spot_angle"]);
	ld.color      = sjson::parse_vector3(obj["color"]);

	// FIXME: remove conversion to radians
	ld.spot_angle = frad(ld.spot_angle);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&ld, sizeof(ld));
	return buf;
}

UnitCompiler::UnitCompiler(CompileOptions& opts)
	: _opts(opts)
	, _num_units(0)
	, _component_data(default_allocator())
{
	register_component_compiler("transform",       &compile_transform, 0.0f);
	register_component_compiler("camera",          &compile_camera, 1.0f);
	register_component_compiler("mesh_renderer",   &compile_mesh_renderer, 1.0f);
	register_component_compiler("sprite_renderer", &compile_sprite_renderer, 1.0f);
	register_component_compiler("light",           &compile_light, 1.0f);
	register_component_compiler("controller",      &physics_resource::compile_controller, 1.0f);
	register_component_compiler("collider",        &physics_resource::compile_collider, 1.0f);
	register_component_compiler("actor",           &physics_resource::compile_actor, 1.0f);
	register_component_compiler("joint",           &physics_resource::compile_joint, 1.0f);
}

void UnitCompiler::compile_unit(const char* path)
{
	Buffer buf = _opts.read(path);
	array::push_back(buf, '\0');
	array::pop_back(buf);
	compile_unit_from_json(array::begin(buf));
}

void UnitCompiler::compile_unit_from_json(const char* json)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	const char* prefab = map::get(obj, FixedString("prefab"), (const char*)NULL);
	if (prefab)
	{
		TempAllocator512 ta;
		DynamicString path(ta);
		sjson::parse_string(prefab, path);

		path += "." RESOURCE_EXTENSION_UNIT;
		compile_unit(path.c_str());
	}

	const char* components = map::get(obj, FixedString("components"), (const char*)NULL);
	if (components)
	{
		JsonObject keys(ta);
		sjson::parse(components, keys);

		auto begin = map::begin(keys);
		auto end = map::end(keys);

		for (; begin != end; ++begin)
		{
			const char* value = begin->pair.second;

			TempAllocator512 ta;
			JsonObject component(ta);
			sjson::parse(value, component);

			const StringId32 type = sjson::parse_string_id(component["type"]);

			Buffer buf = compile_component(type, value);
			add_component_data(type, buf, _num_units);
		}

		++_num_units;
	}
}

void UnitCompiler::compile_multiple_units(const char* json)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	const JsonObject::Node* begin = map::begin(obj);
	const JsonObject::Node* end = map::end(obj);

	for (; begin != end; ++begin)
	{
		const char* unit = begin->pair.second;

		compile_unit_from_json(unit);
	}
}

Buffer UnitCompiler::blob()
{
	UnitResource ur;
	ur.version = RESOURCE_VERSION_UNIT;
	ur.num_units = _num_units;
	ur.num_component_types = sort_map::size(_component_data);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&ur, sizeof(ur));

	const SortMap<StringId32, ComponentTypeData>::Entry* begin = sort_map::begin(_component_data);
	const SortMap<StringId32, ComponentTypeData>::Entry* end = sort_map::end(_component_data);

	while (begin != end)
	{
		const StringId32 type        = (end-1)->pair.first;
		const Buffer& data           = (end-1)->pair.second._data;
		const Array<u32>& unit_index = (end-1)->pair.second._unit_index;
		const u32 num                = (end-1)->pair.second._num;

		ComponentData cd;
		cd.type = type;
		cd.num_instances = num;
		cd.size = array::size(data) + sizeof(u32)*array::size(unit_index);

		array::push(buf, (char*)&cd, sizeof(cd));
		array::push(buf, (char*)array::begin(unit_index), sizeof(u32)*array::size(unit_index));
		array::push(buf, array::begin(data), array::size(data));

		--end;
	}

	return buf;
}

void UnitCompiler::add_component_data(StringId32 type, const Buffer& data, u32 unit_index)
{
	ComponentTypeData& ctd = const_cast<ComponentTypeData&>(sort_map::get(_component_data, type, ComponentTypeData(default_allocator())));

	array::push(ctd._data, array::begin(data), array::size(data));
	array::push_back(ctd._unit_index, unit_index);
	++ctd._num;
}

void UnitCompiler::register_component_compiler(const char* type, CompileFunction fn, f32 spawn_order)
{
	ComponentTypeData ctd(default_allocator());
	ctd._compiler = fn;

	sort_map::set(_component_data, StringId32(type), ctd);
	sort_map::sort(_component_data);
}

Buffer UnitCompiler::compile_component(StringId32 type, const char* json)
{
	RESOURCE_COMPILER_ASSERT(sort_map::has(_component_data, type), _opts, "Unknown component");

	return sort_map::get(_component_data, type, ComponentTypeData(default_allocator()))._compiler(json, _opts);
}

} // namespace crown
<commit_msg>Use separate object to store data<commit_after>/*
 * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "array.h"
#include "compile_options.h"
#include "macros.h"
#include "map.h"
#include "math_utils.h"
#include "physics_resource.h"
#include "sjson.h"
#include "sort_map.h"
#include "temp_allocator.h"
#include "unit_compiler.h"
#include "unit_resource.h"
#include "world_types.h"

namespace crown
{
struct ProjectionInfo
{
	const char* name;
	ProjectionType::Enum type;
};

static const ProjectionInfo s_projection[] =
{
	{ "perspective",  ProjectionType::PERSPECTIVE  },
	{ "orthographic", ProjectionType::ORTHOGRAPHIC }
};
CE_STATIC_ASSERT(CE_COUNTOF(s_projection) == ProjectionType::COUNT);

struct LightInfo
{
	const char* name;
	LightType::Enum type;
};

static const LightInfo s_light[] =
{
	{ "directional", LightType::DIRECTIONAL },
	{ "omni",        LightType::OMNI        },
	{ "spot",        LightType::SPOT        }
};
CE_STATIC_ASSERT(CE_COUNTOF(s_light) == LightType::COUNT);

static ProjectionType::Enum projection_name_to_enum(const char* name)
{
	for (u32 i = 0; i < CE_COUNTOF(s_projection); ++i)
	{
		if (strcmp(name, s_projection[i].name) == 0)
			return s_projection[i].type;
	}

	return ProjectionType::COUNT;
}

static LightType::Enum light_name_to_enum(const char* name)
{
	for (u32 i = 0; i < CE_COUNTOF(s_light); ++i)
	{
		if (strcmp(name, s_light[i].name) == 0)
			return s_light[i].type;
	}

	return LightType::COUNT;
}

static Buffer compile_transform(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	TransformDesc td;
	td.position = sjson::parse_vector3   (obj["position"]);
	td.rotation = sjson::parse_quaternion(obj["rotation"]);
	td.scale    = sjson::parse_vector3   (obj["scale"]);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&td, sizeof(td));
	return buf;
}

static Buffer compile_camera(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	DynamicString type(ta);
	sjson::parse_string(obj["projection"], type);

	ProjectionType::Enum pt = projection_name_to_enum(type.c_str());
	RESOURCE_COMPILER_ASSERT(pt != ProjectionType::COUNT
		, opts
		, "Unknown projection type: '%s'"
		, type.c_str()
		);

	CameraDesc cd;
	cd.type       = pt;
	cd.fov        = sjson::parse_float(obj["fov"]);
	cd.near_range = sjson::parse_float(obj["near_range"]);
	cd.far_range  = sjson::parse_float(obj["far_range"]);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&cd, sizeof(cd));
	return buf;
}

static Buffer compile_mesh_renderer(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	MeshRendererDesc mrd;
	mrd.mesh_resource     = sjson::parse_resource_id(obj["mesh_resource"]);
	mrd.geometry_name     = sjson::parse_string_id  (obj["geometry_name"]);
	mrd.material_resource = sjson::parse_resource_id(obj["material"]);
	mrd.visible           = sjson::parse_bool       (obj["visible"]);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&mrd, sizeof(mrd));
	return buf;
}

static Buffer compile_sprite_renderer(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	SpriteRendererDesc srd;
	srd.sprite_resource   = sjson::parse_resource_id(obj["resource"]);
	srd.material_resource = sjson::parse_resource_id(obj["material"]);
	srd.visible           = sjson::parse_bool       (obj["visible"]);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&srd, sizeof(srd));
	return buf;
}

static Buffer compile_light(const char* json, CompileOptions& opts)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	DynamicString type(ta);
	sjson::parse_string(obj["light"], type);

	LightType::Enum lt = light_name_to_enum(type.c_str());
	RESOURCE_COMPILER_ASSERT(lt != LightType::COUNT
		, opts
		, "Unknown light type: '%s'"
		, type.c_str()
		);

	LightDesc ld;
	ld.type       = lt;
	ld.range      = sjson::parse_float  (obj["range"]);
	ld.intensity  = sjson::parse_float  (obj["intensity"]);
	ld.spot_angle = sjson::parse_float  (obj["spot_angle"]);
	ld.color      = sjson::parse_vector3(obj["color"]);

	// FIXME: remove conversion to radians
	ld.spot_angle = frad(ld.spot_angle);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&ld, sizeof(ld));
	return buf;
}

UnitCompiler::UnitCompiler(CompileOptions& opts)
	: _opts(opts)
	, _num_units(0)
	, _component_data(default_allocator())
{
	register_component_compiler("transform",       &compile_transform, 0.0f);
	register_component_compiler("camera",          &compile_camera, 1.0f);
	register_component_compiler("mesh_renderer",   &compile_mesh_renderer, 1.0f);
	register_component_compiler("sprite_renderer", &compile_sprite_renderer, 1.0f);
	register_component_compiler("light",           &compile_light, 1.0f);
	register_component_compiler("controller",      &physics_resource::compile_controller, 1.0f);
	register_component_compiler("collider",        &physics_resource::compile_collider, 1.0f);
	register_component_compiler("actor",           &physics_resource::compile_actor, 1.0f);
	register_component_compiler("joint",           &physics_resource::compile_joint, 1.0f);
}

void UnitCompiler::compile_unit(const char* path)
{
	Buffer buf = _opts.read(path);
	array::push_back(buf, '\0');
	array::pop_back(buf);
	compile_unit_from_json(array::begin(buf));
}

void UnitCompiler::compile_unit_from_json(const char* json)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	const char* prefab = map::get(obj, FixedString("prefab"), (const char*)NULL);
	if (prefab)
	{
		TempAllocator512 ta;
		DynamicString path(ta);
		sjson::parse_string(prefab, path);

		path += "." RESOURCE_EXTENSION_UNIT;
		compile_unit(path.c_str());
	}

	const char* components = map::get(obj, FixedString("components"), (const char*)NULL);
	if (components)
	{
		JsonObject keys(ta);
		sjson::parse(components, keys);

		auto begin = map::begin(keys);
		auto end = map::end(keys);
		for (; begin != end; ++begin)
		{
			const char* value = begin->pair.second;

			TempAllocator512 ta;
			JsonObject component(ta);
			sjson::parse(value, component);

			const StringId32 type = sjson::parse_string_id(component["type"]);

			Buffer buf = compile_component(type, component["data"]);
			add_component_data(type, buf, _num_units);
		}

		++_num_units;
	}
}

void UnitCompiler::compile_multiple_units(const char* json)
{
	TempAllocator4096 ta;
	JsonObject obj(ta);
	sjson::parse(json, obj);

	const JsonObject::Node* begin = map::begin(obj);
	const JsonObject::Node* end = map::end(obj);

	for (; begin != end; ++begin)
	{
		const char* unit = begin->pair.second;

		compile_unit_from_json(unit);
	}
}

Buffer UnitCompiler::blob()
{
	UnitResource ur;
	ur.version = RESOURCE_VERSION_UNIT;
	ur.num_units = _num_units;
	ur.num_component_types = sort_map::size(_component_data);

	Buffer buf(default_allocator());
	array::push(buf, (char*)&ur, sizeof(ur));

	const SortMap<StringId32, ComponentTypeData>::Entry* begin = sort_map::begin(_component_data);
	const SortMap<StringId32, ComponentTypeData>::Entry* end = sort_map::end(_component_data);

	while (begin != end)
	{
		const StringId32 type        = (end-1)->pair.first;
		const Buffer& data           = (end-1)->pair.second._data;
		const Array<u32>& unit_index = (end-1)->pair.second._unit_index;
		const u32 num                = (end-1)->pair.second._num;

		ComponentData cd;
		cd.type = type;
		cd.num_instances = num;
		cd.size = array::size(data) + sizeof(u32)*array::size(unit_index);

		array::push(buf, (char*)&cd, sizeof(cd));
		array::push(buf, (char*)array::begin(unit_index), sizeof(u32)*array::size(unit_index));
		array::push(buf, array::begin(data), array::size(data));

		--end;
	}

	return buf;
}

void UnitCompiler::add_component_data(StringId32 type, const Buffer& data, u32 unit_index)
{
	ComponentTypeData& ctd = const_cast<ComponentTypeData&>(sort_map::get(_component_data, type, ComponentTypeData(default_allocator())));

	array::push(ctd._data, array::begin(data), array::size(data));
	array::push_back(ctd._unit_index, unit_index);
	++ctd._num;
}

void UnitCompiler::register_component_compiler(const char* type, CompileFunction fn, f32 spawn_order)
{
	ComponentTypeData ctd(default_allocator());
	ctd._compiler = fn;

	sort_map::set(_component_data, StringId32(type), ctd);
	sort_map::sort(_component_data);
}

Buffer UnitCompiler::compile_component(StringId32 type, const char* json)
{
	RESOURCE_COMPILER_ASSERT(sort_map::has(_component_data, type), _opts, "Unknown component");

	return sort_map::get(_component_data, type, ComponentTypeData(default_allocator()))._compiler(json, _opts);
}

} // namespace crown
<|endoftext|>


<commit_before>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2004-2007 Torsten Rahn <tackat@kde.org>"
// Copyright 2007      Inge Wallin  <ingwa@kde.org>"
//

#include "GeoPolygon.h"

#include <stdlib.h>
#include <fcntl.h>
#include <cmath>

#include <QtCore/QFile>
#include <QtCore/QDataStream>
#include <QtCore/QDebug>
#include <QtCore/QTime>
#ifdef Q_OS_UNIX
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/mman.h> /* mmap() is defined in this header */
#endif

const double ARCMINUTE = 10800; // distance of 180deg in arcminutes
const double INT2RAD = M_PI / 10800.0;

GeoPolygon::GeoPolygon()
{
    m_dateLineCrossing = false;
    m_closed  = false;

    m_index = 0;
    m_lonLeft    = 0;
    m_latTop     = 0;
    m_lonRight   = 0;
    m_latBottom  = 0;
}

GeoPolygon::~GeoPolygon()
{
}

void GeoPolygon::setBoundary( double lonLeft, double latTop, double lonRight, double latBottom)
{
    m_lonLeft   = lonLeft;
    m_latTop    = latTop;
    m_lonRight  = lonRight;
    m_latBottom = latBottom;

    m_boundary.clear();
    if ( getDateLine() == GeoPolygon::Even ) {
        double xcenter = ( lonLeft + ( 2 * M_PI + lonRight) ) / 2;

        if ( xcenter > M_PI )
            xcenter -=  2 * M_PI;
        if ( xcenter < -M_PI )
            xcenter +=  2 * M_PI;

        m_boundary.append( GeoDataPoint( xcenter, 0.5 * (latTop + latBottom), 0.0, GeoDataPoint::Radian, 1 ) );
    }
    else
        m_boundary.append( GeoDataPoint( 0.5 * (lonLeft + lonRight), 0.5 * (latTop + latBottom), 0.0, GeoDataPoint::Radian, 1 ) );

    m_boundary.append(GeoDataPoint( lonLeft,  latTop,    0.0, GeoDataPoint::Radian, 1 ));
    m_boundary.append(GeoDataPoint( lonRight, latBottom, 0.0, GeoDataPoint::Radian, 1 ));
    m_boundary.append(GeoDataPoint( lonRight, latTop,    0.0, GeoDataPoint::Radian, 1 ));
    m_boundary.append(GeoDataPoint( lonLeft,  latBottom, 0.0, GeoDataPoint::Radian, 1 ));

}

void GeoPolygon::displayBoundary(){
    Quaternion  q;
    double      lon;
    double      lat;
    m_boundary.at(0).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;
    m_boundary.at(1).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;
    m_boundary.at(2).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;
    m_boundary.at(3).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;
    m_boundary.at(4).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;

//    qDebug() << "Points#: " << size() << " File: " << m_sourceFileName << " dateline " << getDateLine();
}

// ================================================================
//                               class PntMap

PntMap::PntMap()
{
}

PntMap::~PntMap()
{
    qDeleteAll( begin(), end() );
}

void PntMap::load(const QString &filename)
{
//    qDebug("PntMap::load trying to load: " + filename.toLocal8Bit());
    QTime *timer = new QTime();
    timer->restart();

#ifdef Q_OS_UNIX
    // MMAP Start
    int          fd;
    unsigned char* src;
    struct stat  statbuf;

    if ( (fd = open (filename.toLatin1(), O_RDONLY) ) < 0)
        qDebug() << "cannot open" << filename << " for reading";

    if ( fstat (fd,&statbuf) < 0 )
        qDebug() << "fstat error";

    int  filelength = statbuf.st_size;

    if ((src = (unsigned char*) mmap (0, filelength, PROT_READ, MAP_SHARED, fd, 0)) == (unsigned char*) (caddr_t) -1)
        qDebug() << "mmap error for input";

    short  header;
    short  iLat;
    short  iLon;
    int    count = 0;

    //const int halfFileLength = filelength / 2;

    for (int i=0; i < filelength; i+=6){
        header = src[i] | (src[i+1] << 8);
        iLat = src[i+2] | (src[i+3] << 8);
        iLon = src[i+4] | (src[i+5] << 8);

        // Transforming Range of Coordinates to iLat [0,ARCMINUTE] ,
        // iLon [0,2 * ARCMINUTE]

        //
        // 90 00N =   -ARCMINUTE / 2
        // 90 00S =   ARCMINUTE / 2
        // 180 00W =  -ARCMINUTE
        // 180 00E =   ARCMINUTE
        //
        if ( header > 5 ) {

            // qDebug(QString("header: %1 iLat: %2 iLon: %3").arg(header).arg(iLat).arg(iLon).toLatin1());

            GeoPolygon  *polyline = new GeoPolygon();
            append( polyline );

//            polyline->m_sourceFileName=filename;
            polyline->setIndex( header );

            // Find out whether the Polyline is a river or a closed polygon
            if ( ( header >= 7000 && header < 8000 )
                 || ( header >= 9000 && header < 20000 ) )
                polyline->setClosed( false );
            else
                polyline->setClosed( true );

            polyline->append( GeoDataPoint( (double)(iLon) * INT2RAD, (double)(iLat) * INT2RAD, 0.0, GeoDataPoint::Radian, 5 ) );
        }
        else {
            // qDebug(QString("header: %1 iLat: %2 iLon: %3").arg(header).arg(iLat).arg(iLon).toLatin1());
            last()->append( GeoDataPoint( (double)(iLon) * INT2RAD, (double)(iLat) * INT2RAD, 0.0, GeoDataPoint::Radian, (int)(header) ) );
        }
        ++count;
    }
    munmap(src,filelength);
    close(fd);

    // qDebug(QString("Opened %1 with %2 Polylines and %3 Points").arg(filename).arg(this->count()).arg(count).toLatin1());
    // MMAP End
#else
#  ifdef Q_OS_WIN

    // qDebug("Loading PntMap ...");
    int    count = 0;
    QFile  file( filename );

    file.open( QIODevice::ReadOnly );
    QDataStream stream( &file );  // read the data serialized from the file
    stream.setByteOrder( QDataStream::LittleEndian );

    short  header;
    short  iLat;
    short  iLon;

    // Iterator that points to current PolyLine in PntMap
    //	QList<GeoPolygon*>::iterator it = begin();
    //	int count = 0;

    while( !stream.atEnd() ){
        stream >> header >> iLat >> iLon;
        // Transforming Range of Coordinates to iLat [0,ARCMINUTE] , iLon [0,2 * ARCMINUTE]

        if ( header > 5 ) {

            // qDebug(QString("header: %1 iLat: %2 iLon: %3").arg(header).arg(iLat).arg(iLon).toLatin1());
            GeoPolygon  *polyline = new GeoPolygon();
            append( polyline );

            polyline->setIndex(header);

            // Find out whether the Polyline is a river or a closed polygon
            if ( ( header >= 7000 && header < 8000 )
                 || ( header >= 9000 && header < 20000 ) )
                polyline->setClosed( false );
            else
                polyline->setClosed( true );

            polyline->append( GeoDataPoint( (double)(iLon) * INT2RAD, (double)(iLat) * INT2RAD, 0.0, GeoDataPoint::Radian, 5 ) );
        }
        else {
            // qDebug(QString("header: %1 iLat: %2 iLon: %3").arg(header).arg(iLat).arg(iLon).toLatin1());
            last()->append( GeoDataPoint( (double)(iLon) * INT2RAD, (double)(iLat) * INT2RAD, 0.0, GeoDataPoint::Radian, (int)(header) ) );
        }
        ++count;
    }

    file.close();
    // qDebug(QString("Opened %1 with %2 Polylines and %3 Points").arg(filename).arg(this->count()).arg(count).toLatin1());

#  else
#  warning Your OS is not supported!
#  endif
#endif

    // To optimize performance we compute the boundaries of the
    // polygons.  To detect inside/outside we need to detect the
    // dateline first We probably won't need this for spherical
    // projection but for flat projection
    //
    // FIXME: Break this out into its own function.

    double  lon     = 0.0;
    double  lastLon = 0.0;
    double  lat     = 0.0;
    int lastSign    = 0;

    GeoPolygon::PtrVector::Iterator       itPolyLine;
    GeoPolygon::PtrVector::ConstIterator  itEndPolyLine = end();
    GeoDataPoint::Vector::ConstIterator   itPoint;

    // Now we calculate the boundaries

    for ( itPolyLine = begin(); itPolyLine != itEndPolyLine; ++itPolyLine ) {

        double  lonLeft       =  +M_PI;
        double  lonRight      =  -M_PI;
        double  otherLonLeft  =  +M_PI;
        double  otherLonRight =  -M_PI;
        double  latTop        =  -M_PI / 2.0;
        double  latBottom     =  +M_PI / 2.0;

        bool isCrossingDateLine = false;
        bool isOriginalSide = true;
        int  lastSign     = 0;

        GeoDataPoint::Vector::ConstIterator  itEndPoint = (*itPolyLine)->end();

        for ( itPoint = (*itPolyLine)->begin();
                itPoint != itEndPoint;
                ++itPoint )
        {
            (*itPoint).geoCoordinates( lon, lat );

            int currentSign = ( lon > 0 ) ? 1 : -1 ;

            if( itPoint == (*itPolyLine)->begin() ) {
                lastSign = currentSign;
                lastLon  = lon;
            }

            if ( lastSign != currentSign && fabs(lastLon) + fabs(lon) > M_PI ) {
                isOriginalSide = !isOriginalSide;
                isCrossingDateLine = true;
            }

            if ( isOriginalSide == true ) {
                if ( lon < lonLeft  ) lonLeft = lon;
                if ( lon > lonRight ) lonRight = lon;
			} else {
                if ( lon < otherLonLeft  ) otherLonLeft = lon;
                if ( lon > otherLonRight ) otherLonRight = lon;
            }

            if ( lat > latTop )    latTop = lat;
            if ( lat < latBottom ) latBottom = lat;

            lastSign = currentSign;
            lastLon  = lon;
        }

        if ( isOriginalSide == false ) {
            (*itPolyLine)->setDateLine( GeoPolygon::Odd );
//            qDebug() << "Odd  >> File: " << (*itPolyLine)->m_sourceFileName;
            (*itPolyLine)->setBoundary( -M_PI, latTop, +M_PI, M_PI / 2 );
        }

        if ( isOriginalSide == true && isCrossingDateLine == true ) {
            (*itPolyLine)->setDateLine( GeoPolygon::Even );
//            qDebug() << "Even >> File: " << (*itPolyLine)->m_sourceFileName << " Size: " << (*itPolyLine)->size();

//            qDebug() << " lonLeft: " << lonLeft << " lonRight: " << lonRight << " otherLonLeft: " << otherLonLeft << " otherlonRight: " << otherLonRight;

            double leftLonRight, rightLonLeft;

            if ( fabs( M_PI * lonRight/fabs(lonRight) - lonRight ) >
                 fabs( M_PI * otherLonRight/fabs(otherLonRight) - otherLonRight ) ) {
                rightLonLeft = otherLonLeft;
                leftLonRight = lonRight;
            } else {
                rightLonLeft = lonLeft;
                leftLonRight = otherLonRight;
            }

            (*itPolyLine)->setBoundary( rightLonLeft, latTop, leftLonRight, latBottom );

//            qDebug() << "Crosses: lonLeft: " << rightLonLeft << " is right from: lonRight: " << leftLonRight;

        }
        (*itPolyLine)->setBoundary( lonLeft, latTop, lonRight, latBottom );
    }
//    qDebug() << "Elapsed: " << timer->elapsed();
    delete timer;
}

<commit_msg>Small fix<commit_after>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2004-2007 Torsten Rahn <tackat@kde.org>"
// Copyright 2007      Inge Wallin  <ingwa@kde.org>"
//

#include "GeoPolygon.h"

#include <stdlib.h>
#include <fcntl.h>
#include <cmath>

#include <QtCore/QFile>
#include <QtCore/QDataStream>
#include <QtCore/QDebug>
#include <QtCore/QTime>
#ifdef Q_OS_UNIX
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/mman.h> /* mmap() is defined in this header */
#endif

const double ARCMINUTE = 10800; // distance of 180deg in arcminutes
const double INT2RAD = M_PI / 10800.0;

GeoPolygon::GeoPolygon()
{
    m_dateLineCrossing = false;
    m_closed  = false;

    m_index = 0;
    m_lonLeft    = 0;
    m_latTop     = 0;
    m_lonRight   = 0;
    m_latBottom  = 0;
}

GeoPolygon::~GeoPolygon()
{
}

void GeoPolygon::setBoundary( double lonLeft, double latTop, double lonRight, double latBottom)
{
    m_lonLeft   = lonLeft;
    m_latTop    = latTop;
    m_lonRight  = lonRight;
    m_latBottom = latBottom;

    m_boundary.clear();
    if ( getDateLine() == GeoPolygon::Even ) {
        double xcenter = ( lonLeft + ( 2 * M_PI + lonRight) ) / 2;

        if ( xcenter > M_PI )
            xcenter -=  2 * M_PI;
        if ( xcenter < -M_PI )
            xcenter +=  2 * M_PI;

        m_boundary.append( GeoDataPoint( xcenter, 0.5 * (latTop + latBottom), 0.0, GeoDataPoint::Radian, 1 ) );
    }
    else
        m_boundary.append( GeoDataPoint( 0.5 * (lonLeft + lonRight), 0.5 * (latTop + latBottom), 0.0, GeoDataPoint::Radian, 1 ) );

    m_boundary.append(GeoDataPoint( lonLeft,  latTop,    0.0, GeoDataPoint::Radian, 1 ));
    m_boundary.append(GeoDataPoint( lonRight, latBottom, 0.0, GeoDataPoint::Radian, 1 ));
    m_boundary.append(GeoDataPoint( lonRight, latTop,    0.0, GeoDataPoint::Radian, 1 ));
    m_boundary.append(GeoDataPoint( lonLeft,  latBottom, 0.0, GeoDataPoint::Radian, 1 ));

}

void GeoPolygon::displayBoundary(){
    Quaternion  q;
    double      lon;
    double      lat;
    m_boundary.at(0).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;
    m_boundary.at(1).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;
    m_boundary.at(2).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;
    m_boundary.at(3).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;
    m_boundary.at(4).geoCoordinates(lon, lat, GeoDataPoint::Degree);
    qDebug() << "Boundary:" << lon << ", " << lat;

//    qDebug() << "Points#: " << size() << " File: " << m_sourceFileName << " dateline " << getDateLine();
}

// ================================================================
//                               class PntMap

PntMap::PntMap()
{
}

PntMap::~PntMap()
{
    qDeleteAll( begin(), end() );
}

void PntMap::load(const QString &filename)
{
//    qDebug("PntMap::load trying to load: " + filename.toLocal8Bit());
    QTime *timer = new QTime();
    timer->restart();

#ifdef Q_OS_UNIX
    // MMAP Start
    int          fd;
    unsigned char* src;
    struct stat  statbuf;

    if ( (fd = open (filename.toLatin1(), O_RDONLY) ) < 0)
        qDebug() << "cannot open" << filename << " for reading";

    if ( fstat (fd,&statbuf) < 0 )
        qDebug() << "fstat error";

    int  filelength = statbuf.st_size;

    if ((src = (unsigned char*) mmap (0, filelength, PROT_READ, MAP_SHARED, fd, 0)) == (unsigned char*) (caddr_t) -1)
        qDebug() << "mmap error for input";

    short  header;
    short  iLat;
    short  iLon;
    int    count = 0;

    //const int halfFileLength = filelength / 2;

    for (int i=0; i < filelength; i+=6){
        header = src[i] | (src[i+1] << 8);
        iLat = src[i+2] | (src[i+3] << 8);
        iLon = src[i+4] | (src[i+5] << 8);

        // Transforming Range of Coordinates to iLat [0,ARCMINUTE] ,
        // iLon [0,2 * ARCMINUTE]

        //
        // 90 00N =   -ARCMINUTE / 2
        // 90 00S =   ARCMINUTE / 2
        // 180 00W =  -ARCMINUTE
        // 180 00E =   ARCMINUTE
        //
        if ( header > 5 ) {

            // qDebug(QString("header: %1 iLat: %2 iLon: %3").arg(header).arg(iLat).arg(iLon).toLatin1());

            GeoPolygon  *polyline = new GeoPolygon();
            append( polyline );

//            polyline->m_sourceFileName=filename;
            polyline->setIndex( header );

            // Find out whether the Polyline is a river or a closed polygon
            if ( ( header >= 7000 && header < 8000 )
                 || ( header >= 9000 && header < 20000 ) )
                polyline->setClosed( false );
            else
                polyline->setClosed( true );

            polyline->append( GeoDataPoint( (double)(iLon) * INT2RAD, (double)(iLat) * INT2RAD, 0.0, GeoDataPoint::Radian, 5 ) );
        }
        else {
            // qDebug(QString("header: %1 iLat: %2 iLon: %3").arg(header).arg(iLat).arg(iLon).toLatin1());
            last()->append( GeoDataPoint( (double)(iLon) * INT2RAD, (double)(iLat) * INT2RAD, 0.0, GeoDataPoint::Radian, (int)(header) ) );
        }
        ++count;
    }
    munmap(src,filelength);
    close(fd);

    // qDebug(QString("Opened %1 with %2 Polylines and %3 Points").arg(filename).arg(this->count()).arg(count).toLatin1());
    // MMAP End
#else
#  ifdef Q_OS_WIN

    // qDebug("Loading PntMap ...");
    int    count = 0;
    QFile  file( filename );

    file.open( QIODevice::ReadOnly );
    QDataStream stream( &file );  // read the data serialized from the file
    stream.setByteOrder( QDataStream::LittleEndian );

    short  header;
    short  iLat;
    short  iLon;

    // Iterator that points to current PolyLine in PntMap
    //	QList<GeoPolygon*>::iterator it = begin();
    //	int count = 0;

    while( !stream.atEnd() ){
        stream >> header >> iLat >> iLon;
        // Transforming Range of Coordinates to iLat [0,ARCMINUTE] , iLon [0,2 * ARCMINUTE]

        if ( header > 5 ) {

            // qDebug(QString("header: %1 iLat: %2 iLon: %3").arg(header).arg(iLat).arg(iLon).toLatin1());
            GeoPolygon  *polyline = new GeoPolygon();
            append( polyline );

            polyline->setIndex(header);

            // Find out whether the Polyline is a river or a closed polygon
            if ( ( header >= 7000 && header < 8000 )
                 || ( header >= 9000 && header < 20000 ) )
                polyline->setClosed( false );
            else
                polyline->setClosed( true );

            polyline->append( GeoDataPoint( (double)(iLon) * INT2RAD, (double)(iLat) * INT2RAD, 0.0, GeoDataPoint::Radian, 5 ) );
        }
        else {
            // qDebug(QString("header: %1 iLat: %2 iLon: %3").arg(header).arg(iLat).arg(iLon).toLatin1());
            last()->append( GeoDataPoint( (double)(iLon) * INT2RAD, (double)(iLat) * INT2RAD, 0.0, GeoDataPoint::Radian, (int)(header) ) );
        }
        ++count;
    }

    file.close();
    // qDebug(QString("Opened %1 with %2 Polylines and %3 Points").arg(filename).arg(this->count()).arg(count).toLatin1());

#  else
#  warning Your OS is not supported!
#  endif
#endif

    // To optimize performance we compute the boundaries of the
    // polygons.  To detect inside/outside we need to detect the
    // dateline first We probably won't need this for spherical
    // projection but for flat projection
    //
    // FIXME: Break this out into its own function.

    double  lon     = 0.0;
    double  lastLon = 0.0;
    double  lat     = 0.0;
    int lastSign    = 0;

    GeoPolygon::PtrVector::Iterator       itPolyLine;
    GeoPolygon::PtrVector::ConstIterator  itEndPolyLine = end();
    GeoDataPoint::Vector::ConstIterator   itPoint;

    // Now we calculate the boundaries

    for ( itPolyLine = begin(); itPolyLine != itEndPolyLine; ++itPolyLine ) {

        double  lonLeft       =  +M_PI;
        double  lonRight      =  -M_PI;
        double  otherLonLeft  =  +M_PI;
        double  otherLonRight =  -M_PI;
        double  latTop        =  -M_PI / 2.0;
        double  latBottom     =  +M_PI / 2.0;

        bool isCrossingDateLine = false;
        bool isOriginalSide = true;
        int  lastSign     = 0;

        GeoDataPoint::Vector::ConstIterator  itEndPoint = (*itPolyLine)->end();

        for ( itPoint = (*itPolyLine)->begin();
                itPoint != itEndPoint;
                ++itPoint )
        {
            (*itPoint).geoCoordinates( lon, lat );

            int currentSign = ( lon > 0 ) ? 1 : -1 ;

            if( itPoint == (*itPolyLine)->begin() ) {
                lastSign = currentSign;
                lastLon  = lon;
            }

            if ( lastSign != currentSign && fabs(lastLon) + fabs(lon) > M_PI ) {
                isOriginalSide = !isOriginalSide;
                isCrossingDateLine = true;
            }

            if ( isOriginalSide == true ) {
                if ( lon < lonLeft  ) lonLeft = lon;
                if ( lon > lonRight ) lonRight = lon;
			} else {
                if ( lon < otherLonLeft  ) otherLonLeft = lon;
                if ( lon > otherLonRight ) otherLonRight = lon;
            }

            if ( lat > latTop )    latTop = lat;
            if ( lat < latBottom ) latBottom = lat;

            lastSign = currentSign;
            lastLon  = lon;
        }

        if ( isOriginalSide == false ) {
            (*itPolyLine)->setDateLine( GeoPolygon::Odd );
//            qDebug() << "Odd  >> File: " << (*itPolyLine)->m_sourceFileName;
            (*itPolyLine)->setBoundary( -M_PI, latTop, +M_PI, M_PI / 2 );
        }

        if ( isOriginalSide == true && isCrossingDateLine == true ) {
            (*itPolyLine)->setDateLine( GeoPolygon::Even );
//            qDebug() << "Even >> File: " << (*itPolyLine)->m_sourceFileName << " Size: " << (*itPolyLine)->size();

//            qDebug() << " lonLeft: " << lonLeft << " lonRight: " << lonRight << " otherLonLeft: " << otherLonLeft << " otherlonRight: " << otherLonRight;

            double leftLonRight, rightLonLeft;

            if ( fabs( M_PI * lonRight/fabs(lonRight) - lonRight ) >
                 fabs( M_PI * otherLonRight/fabs(otherLonRight) - otherLonRight ) ) {
                rightLonLeft = otherLonLeft;
                leftLonRight = lonRight;
            } else {
                rightLonLeft = lonLeft;
                leftLonRight = otherLonRight;
            }

            (*itPolyLine)->setBoundary( rightLonLeft, latTop, leftLonRight, latBottom );

//            qDebug() << "Crosses: lonLeft: " << rightLonLeft << " is right from: lonRight: " << leftLonRight;

        }
        if ( isCrossingDateLine == false ) {
            (*itPolyLine)->setDateLine( GeoPolygon::None );
            (*itPolyLine)->setBoundary( lonLeft, latTop, lonRight, latBottom );
        }
    }
//    qDebug() << "Elapsed: " << timer->elapsed();
    delete timer;
}

<|endoftext|>


<commit_before>/*
 * cnn_scorer.cpp
 *
 *  Created on: May 2, 2016
 *      Author: dkoes
 */

#include "cnn_scorer.h"
#include "gridoptions.h"

#include "caffe/layer.hpp"
#include "caffe/net.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/layers/ndim_data_layer.hpp"

using namespace caffe;
using namespace std;

//initialize from commandline options
//throw error if missing required info
CNNScorer::CNNScorer(const cnn_options& cnnopts, const vec& center,
		const model& m) :
		rotations(cnnopts.cnn_rotations)
{
	if (cnnopts.cnn_scoring)
	{
		if (cnnopts.cnn_model.size() == 0)
		{
			throw usage_error("Missing model for cnn scoring.");
		}
		if (cnnopts.cnn_weights.size() == 0)
		{
			throw usage_error("Missing weights for cnn scoring.");
		}

		//load cnn model
		NetParameter param;
		ReadNetParamsFromTextFileOrDie(cnnopts.cnn_model, &param);
		param.mutable_state()->set_phase(TEST);
		LayerParameter *first = param.mutable_layer(0);
		//must be ndim
		NDimDataParameter *ndimparam = first->mutable_ndim_data_param();
		if (ndimparam == NULL)
		{
			throw usage_error("First layer of model must be NDimData.");
		}
		ndimparam->set_inmemory(true);

		//set batch size to 1
		ndimparam->set_batch_size(1);
		//let user specify rotations
		ndimparam->set_rotate(min(24U, cnnopts.cnn_rotations));

		net.reset(new Net<float>(param));

		//load weights
		net->CopyTrainedLayersFrom(cnnopts.cnn_weights);

		//check that network matches our expectations

		//the first layer must be NDimData
		const vector<shared_ptr<Layer<Dtype> > >& layers = net->layers();

		//we also need an output layer
		if (layers.size() < 1)
		{
			throw usage_error("No layers in model!");
		}

		ndim = dynamic_cast<NDimDataLayer<Dtype>*>(layers[0].get());
		if (ndim == NULL)
		{
			throw usage_error("First layer of model must be NDimData.");
		}

		if (!net->has_blob("output"))
		{
			throw usage_error("Model must have output layer named \"output\".");
		}
		if (net->blob_by_name("output")->count() != 2)
		{
			throw usage_error(
					"Model output layer does not have exactly two outputs.");
		}

		//initialize receptor part of grid
		BlobShape shape = ndim->layer_param().ndim_data_param().shape();
		if (shape.dim_size() != 4)
		{
			throw usage_error(
					"Input data layer does not have correct number of dimensions.");
		}
		unsigned nchannels = shape.dim(0);
		unsigned dim = shape.dim(1);
		if (dim != shape.dim(2) || dim != shape.dim(3))
		{
			throw usage_error(
					"Input data layer does not have cubic dimensions.");
		}

		gridoptions gopt;
		gopt.res = cnnopts.resolution;
		gopt.dim = round((dim - 1) * gopt.res);

		gopt.x = center[0];
		gopt.y = center[1];
		gopt.z = center[2];

		grid.initialize(gopt);
		grid.setReceptor(m);

	}

}

//return score of model, assumes receptor has not changed from initialization
float CNNScorer::score(const model& m)
{
	if (!initialized())
		return -1.0;
	grid.setLigand(m);

	grid.outputMem(ndim->getMemoryData());
	ndim->memoryIsSet();

	unsigned n = 1;
	if (rotations > 0)
		n = rotations;

	double score = 0.0;
	const shared_ptr<Blob<Dtype> > outblob = net->blob_by_name("output");

	//take average of all rotations if requested
	for (unsigned i = 0; i < n; i++)
	{
		net->Forward();
		const Dtype* out = outblob->cpu_data();
		score += out[1];
		cout << out[1] << "\n";
	}
	return score / n;

}
<commit_msg>checkpoint batched rotations - currently hanging<commit_after>/*
 * cnn_scorer.cpp
 *
 *  Created on: May 2, 2016
 *      Author: dkoes
 */

#include "cnn_scorer.h"
#include "gridoptions.h"

#include "caffe/layer.hpp"
#include "caffe/net.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/layers/ndim_data_layer.hpp"

using namespace caffe;
using namespace std;

//initialize from commandline options
//throw error if missing required info
CNNScorer::CNNScorer(const cnn_options& cnnopts, const vec& center,
		const model& m) :
		rotations(cnnopts.cnn_rotations)
{
	if (cnnopts.cnn_scoring)
	{
		if (cnnopts.cnn_model.size() == 0)
		{
			throw usage_error("Missing model for cnn scoring.");
		}
		if (cnnopts.cnn_weights.size() == 0)
		{
			throw usage_error("Missing weights for cnn scoring.");
		}

		//load cnn model
		NetParameter param;
		ReadNetParamsFromTextFileOrDie(cnnopts.cnn_model, &param);
		param.mutable_state()->set_phase(TEST);
		LayerParameter *first = param.mutable_layer(0);
		//must be ndim
		NDimDataParameter *ndimparam = first->mutable_ndim_data_param();
		if (ndimparam == NULL)
		{
			throw usage_error("First layer of model must be NDimData.");
		}
		ndimparam->set_inmemory(true);

		//set batch size to 1
		unsigned bsize = 1;
		//unless we have rotations, in which case do them all at once
		if(cnnopts.cnn_rotations > 0) {
			//let user specify rotations
			unsigned nrot = min(24U, cnnopts.cnn_rotations);
			ndimparam->set_rotate(nrot);
			bsize = nrot;
		}
		ndimparam->set_batch_size(bsize);

		net.reset(new Net<float>(param));

		//load weights
		net->CopyTrainedLayersFrom(cnnopts.cnn_weights);

		//check that network matches our expectations

		//the first layer must be NDimData
		const vector<shared_ptr<Layer<Dtype> > >& layers = net->layers();

		//we also need an output layer
		if (layers.size() < 1)
		{
			throw usage_error("No layers in model!");
		}

		ndim = dynamic_cast<NDimDataLayer<Dtype>*>(layers[0].get());
		if (ndim == NULL)
		{
			throw usage_error("First layer of model must be NDimData.");
		}

		if (!net->has_blob("output"))
		{
			throw usage_error("Model must have output layer named \"output\".");
		}
		if (net->blob_by_name("output")->count() != 2*bsize)
		{
			throw usage_error(
					"Model output layer does not have exactly two outputs.");
		}

		//initialize receptor part of grid
		BlobShape shape = ndim->layer_param().ndim_data_param().shape();
		if (shape.dim_size() != 4)
		{
			throw usage_error(
					"Input data layer does not have correct number of dimensions.");
		}
		unsigned nchannels = shape.dim(0);
		unsigned dim = shape.dim(1);
		if (dim != shape.dim(2) || dim != shape.dim(3))
		{
			throw usage_error(
					"Input data layer does not have cubic dimensions.");
		}

		gridoptions gopt;
		gopt.res = cnnopts.resolution;
		gopt.dim = round((dim - 1) * gopt.res);

		gopt.x = center[0];
		gopt.y = center[1];
		gopt.z = center[2];

		grid.initialize(gopt);
		grid.setReceptor(m);

	}

}

//return score of model, assumes receptor has not changed from initialization
float CNNScorer::score(const model& m)
{
	if (!initialized())
		return -1.0;
	grid.setLigand(m);

	grid.outputMem(ndim->getMemoryData());
	ndim->memoryIsSet();

	unsigned n = 1;
	if (rotations > 0)
		n = rotations;

	double score = 0.0;
	const shared_ptr<Blob<Dtype> > outblob = net->blob_by_name("output");

	net->Forward(); //do all rotations at once if requested

	//take average of all rotations if requested
	for (unsigned i = 0; i < n; i++)
	{
		net->Forward();
		const Dtype* out = outblob->cpu_data();
		score += out[2*i+1];
		cout << out[2*i+1] << "\n";
	}
	return score / n;

}
<|endoftext|>


<commit_before>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/function/CEvaluationNodeCall.cpp,v $
//   $Revision: 1.21 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2007/07/24 18:40:21 $
// End CVS Header

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

#include <sbml/math/ASTNode.h>

#include "copasi.h"

#include "mathematics.h"
#include "CEvaluationNode.h"
#include "CEvaluationTree.h"
#include "CFunction.h"
#include "CExpression.h"
#include "CFunctionDB.h"
#include "CopasiDataModel/CCopasiDataModel.h"

CEvaluationNodeCall::CEvaluationNodeCall():
    CEvaluationNode(CEvaluationNode::INVALID, ""),
    mpFunction(NULL),
    mpExpression(NULL),
    mCallNodes(),
    mpCallParameters(NULL)
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeCall::CEvaluationNodeCall(const SubType & subType,
    const Data & data):
    CEvaluationNode((Type) (CEvaluationNode::CALL | subType), data),
    mpFunction(NULL),
    mpExpression(NULL),
    mCallNodes(),
    mpCallParameters(NULL)
{
  switch (subType)
    {
    case FUNCTION:
    case EXPRESSION:
      break;

    default:
      fatalError();
      break;
    }

  mPrecedence = PRECEDENCE_FUNCTION;
}

CEvaluationNodeCall::CEvaluationNodeCall(const CEvaluationNodeCall & src):
    CEvaluationNode(src),
    mpFunction(src.mpFunction),
    mpExpression(src.mpExpression),
    mCallNodes(src.mCallNodes),
    mpCallParameters(NULL)
{mpCallParameters = buildParameters(mCallNodes);}

CEvaluationNodeCall::~CEvaluationNodeCall() {}

const C_FLOAT64 & CEvaluationNodeCall::value() const
  {
    C_FLOAT64 &Value = *const_cast<C_FLOAT64 *>(&mValue);
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {
          std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
          std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

          for (; it != end; ++it) (*it)->value();
        }
        return Value = mpFunction->calcValue(*mpCallParameters);
        break;

      case EXPRESSION:
        return Value = mpExpression->calcValue();
        break;

      default:
        return Value = std::numeric_limits<C_FLOAT64>::quiet_NaN();
        break;
      }
  }

bool CEvaluationNodeCall::compile(const CEvaluationTree * pTree)
{
  bool success = true;

  switch (mType & 0x00FFFFFF)
    {
    case FUNCTION:
      mpFunction =
        dynamic_cast<CFunction *>(CCopasiDataModel::Global->getFunctionList()->findFunction(mData));
      if (!mpFunction) return false;

      // We need to check whether the provided arguments match the on needed by the
      // function;
      if (!verifyParameters(mCallNodes, mpFunction->getVariables())) return false;

      clearParameters(mpCallParameters, mCallNodes);
      mpCallParameters = buildParameters(mCallNodes);

      break;

    case EXPRESSION:
      mpExpression =
        dynamic_cast<CExpression *>(CCopasiDataModel::Global->getFunctionList()->findFunction(mData));
      if (!mpExpression)
        {
          // We may have a function with no arguments the parser is not able to destinguish
          // between that and an expression.
          mpFunction =
            dynamic_cast<CFunction *>(CCopasiDataModel::Global->getFunctionList()->findFunction(mData));
          if (!mpFunction) return false;

          mType = (CEvaluationNode::Type) (CEvaluationNode::CALL | FUNCTION);

          success = compile(pTree);
        }
      else
        success = mpExpression->compile(static_cast<const CExpression *>(pTree)->getListOfContainer());

      break;

    default:
      success = false;
      break;
    }

  return success;
}

bool CEvaluationNodeCall::calls(std::set< std::string > & list) const
  {
    if (list.count(mData)) return true;

    CEvaluationTree * pTree =
      CCopasiDataModel::Global->getFunctionList()->findFunction(mData);

    if (pTree) return pTree->calls(list);

    return false;
  }

std::string CEvaluationNodeCall::getInfix() const
  {
    std::string Infix = mData + "(";
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {
          std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
          std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

          if (it != end) Infix += (*it++)->getInfix();

          for (; it != end; ++it)
            Infix += "," + (*it)->getInfix();
        }

        break;

      case EXPRESSION:
        break;

      default:
        return "@";
        break;
      }
    return Infix + ")";
  }

std::string CEvaluationNodeCall::getDisplayString(const CEvaluationTree * pTree) const
  {
    std::string DisplayString = mData + "(";
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {
          std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
          std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

          if (it != end) DisplayString += (*it++)->getDisplayString(pTree);

          for (; it != end; ++it)
            DisplayString += "," + (*it)->getDisplayString(pTree);
        }

        break;

      case EXPRESSION:
        break;

      default:
        return "@";
        break;
      }
    return DisplayString + ")";
  }

std::string CEvaluationNodeCall::getDisplay_C_String(const CEvaluationTree * pTree) const
  {
    std::string DisplayString = mData + "(";
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {
          std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
          std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

          if (it != end) DisplayString += (*it++)->getDisplay_C_String(pTree);

          for (; it != end; ++it)
            DisplayString += "," + (*it)->getDisplay_C_String(pTree);
        }

        break;

      case EXPRESSION:
        break;

      default:
        return "@";
        break;
      }
    return DisplayString + ")";
  }

std::string CEvaluationNodeCall::getDisplay_MMD_String(const CEvaluationTree * /* pTree */) const
  {
    std::string DisplayString = mData;

    return DisplayString;
  }

std::string CEvaluationNodeCall::getDisplay_XPP_String(const CEvaluationTree * /* pTree */) const
  {
    std::string DisplayString = mData;

    return DisplayString;
  }

CEvaluationNode* CEvaluationNodeCall::createNodeFromASTTree(const ASTNode& node)
{
  SubType subType = CEvaluationNodeCall::FUNCTION;
  std::string data = node.getName();

  CEvaluationNodeCall* convertedNode = new CEvaluationNodeCall(subType, data);
  unsigned int i, iMax = node.getNumChildren();
  for (i = 0; i < iMax;++i)
    {
      convertedNode->addChild(CEvaluationTree::convertASTNode(*node.getChild(i)));
    }
  return convertedNode;
}

ASTNode* CEvaluationNodeCall::toAST() const
  {
    ASTNode* node = new ASTNode(AST_FUNCTION);
    const std::string funName = this->getData();
    CEvaluationTree* pFun = CCopasiDataModel::Global->getFunctionList()->findFunction(funName);
    if (pFun->getSBMLId() != "")
      {
        node->setName(pFun->getSBMLId().c_str());
      }
    else
      {
        node->setName(funName.c_str());
        pFun->setSBMLId(funName);
      }
    const CEvaluationNode* child = static_cast<const CEvaluationNode*>(this->getChild());
    while (child)
      {
        node->addChild(child->toAST());
        child = static_cast<const CEvaluationNode*>(child->getSibling());
      }
    return node;
  }

bool CEvaluationNodeCall::addChild(CCopasiNode< Data > * pChild,
                                   CCopasiNode< Data > * pAfter)
{
  CCopasiNode< Data >::addChild(pChild, pAfter);
  mCallNodes.push_back(static_cast<CEvaluationNode *>(pChild));

  return true;
}

bool CEvaluationNodeCall::removeChild(CCopasiNode< Data > * pChild)
{
  std::vector<CEvaluationNode *>::iterator it = mCallNodes.begin();
  std::vector<CEvaluationNode *>::iterator end = mCallNodes.end();

  while (it != end && *it != pChild) ++it;
  if (it != end) mCallNodes.erase(it);

  return CCopasiNode< Data >::removeChild(pChild);
}

CCallParameters< C_FLOAT64 > *
CEvaluationNodeCall::buildParameters(const std::vector<CEvaluationNode *> & vector)
{
  std::vector<CEvaluationNode *>::const_iterator it = vector.begin();
  std::vector<CEvaluationNode *>::const_iterator end = vector.end();

  CCallParameters< C_FLOAT64 > * pCallParameters =
    new CCallParameters< C_FLOAT64 >(vector.size());
  unsigned C_INT32 i;
  for (i = 0; it != end; ++it, i++)
    {
      if (type((*it)->getType()) == CEvaluationNode::VECTOR)
        (*pCallParameters)[i].vector = buildParameters(static_cast<const CEvaluationNodeVector *>(*it)->getVector());
      else
        (*pCallParameters)[i].value = (*it)->getValuePointer();
    }

  return pCallParameters;
}

void
CEvaluationNodeCall::clearParameters(CCallParameters< C_FLOAT64 > * pCallParameters,
                                     const std::vector<CEvaluationNode *> & vector)
{
  if (!pCallParameters) return;

  std::vector<CEvaluationNode *>::const_iterator it = vector.begin();
  std::vector<CEvaluationNode *>::const_iterator end = vector.end();

  unsigned C_INT32 i;
  for (i = 0; it != end; ++it, i++)
    {
      if (type((*it)->getType()) == CEvaluationNode::VECTOR)
        clearParameters((*pCallParameters)[i].vector,
                        static_cast<const CEvaluationNodeVector *>(*it)->getVector());
    }

  delete pCallParameters;
  return;
}

bool
CEvaluationNodeCall::verifyParameters(const std::vector<CEvaluationNode *> & vector,
                                      const CFunctionParameters & functionParameters)
{
  if (vector.size() != functionParameters.size()) return false;

  std::vector<CEvaluationNode *>::const_iterator it = vector.begin();
  std::vector<CEvaluationNode *>::const_iterator end = vector.end();

  unsigned C_INT32 i;

  for (i = 0; it != end; ++it, i++)
    {
      if ((type((*it)->getType()) == CEvaluationNode::VECTOR &&
           functionParameters[i]->getType() != CFunctionParameter::VFLOAT64) ||
          functionParameters[i]->getType() == CFunctionParameter::VFLOAT64)
        return false;
    }

  return true;
}

const CEvaluationTree * CEvaluationNodeCall::getCalledTree() const
  {
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        return mpFunction;

      case EXPRESSION:
        return mpExpression;

      default:
        return NULL;
      }
  }

#include "utilities/copasimathml.h"

void CEvaluationNodeCall::writeMathML(std::ostream & out,
                                      const std::vector<std::vector<std::string> > & env,
                                      bool expand,
                                      unsigned C_INT32 l) const
  {
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {

#if 0
          if (!expand)
            {
#endif
              out << SPC(l) << "<mrow>" << std::endl;

              out << SPC(l + 1) << "<mi>" << mData << "</mi>" << std::endl;
              out << SPC(l + 1) << "<mo>  </mo>" << std::endl;
              out << SPC(l + 1) << "<mrow>" << std::endl;
              out << SPC(l + 2) << "<mo> (</mo>" << std::endl;
              out << SPC(l + 2) << "<mrow>" << std::endl;

              std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
              std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

              if (it != end) (*it++)->writeMathML(out, env, expand, l + 3);

              for (; it != end; ++it)
                {

                  out << SPC(l + 3) << "<mo> , </mo>" << std::endl;
                  (*it)->writeMathML(out, env, expand, l + 3);
                }

              out << SPC(l + 2) << "</mrow>" << std::endl;
              out << SPC(l + 2) << "<mo>) </mo>" << std::endl;

              out << SPC(l + 1) << "</mrow>" << std::endl;
              out << SPC(l) << "</mrow>" << std::endl;
#if 0
            }
          // else  :TODO
#endif
        }
        break;

      case EXPRESSION:
        break;

      default:
        break;
      }

    return;
  }
<commit_msg>Fixed Bug 899. The infix name of a called function or expression is now quoted whenever it contains a character representing an operator or structure element.<commit_after>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/function/CEvaluationNodeCall.cpp,v $
//   $Revision: 1.22 $
//   $Name:  $
//   $Author: shoops $
//   $Date: 2007/10/12 18:29:09 $
// End CVS Header

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

#include <sbml/math/ASTNode.h>

#include "copasi.h"

#include "mathematics.h"
#include "CEvaluationNode.h"
#include "CEvaluationTree.h"
#include "CFunction.h"
#include "CExpression.h"
#include "CFunctionDB.h"
#include "CopasiDataModel/CCopasiDataModel.h"
#include "utilities/utility.cpp"

CEvaluationNodeCall::CEvaluationNodeCall():
    CEvaluationNode(CEvaluationNode::INVALID, ""),
    mpFunction(NULL),
    mpExpression(NULL),
    mCallNodes(),
    mpCallParameters(NULL)
{mPrecedence = PRECEDENCE_NUMBER;}

CEvaluationNodeCall::CEvaluationNodeCall(const SubType & subType,
    const Data & data):
    CEvaluationNode((Type) (CEvaluationNode::CALL | subType), data),
    mpFunction(NULL),
    mpExpression(NULL),
    mCallNodes(),
    mpCallParameters(NULL)
{
  mData = unQuote(mData);

  switch (subType)
    {
    case FUNCTION:
    case EXPRESSION:
      break;

    default:
      fatalError();
      break;
    }

  mPrecedence = PRECEDENCE_FUNCTION;
}

CEvaluationNodeCall::CEvaluationNodeCall(const CEvaluationNodeCall & src):
    CEvaluationNode(src),
    mpFunction(src.mpFunction),
    mpExpression(src.mpExpression),
    mCallNodes(src.mCallNodes),
    mpCallParameters(NULL)
{mpCallParameters = buildParameters(mCallNodes);}

CEvaluationNodeCall::~CEvaluationNodeCall() {}

const C_FLOAT64 & CEvaluationNodeCall::value() const
  {
    C_FLOAT64 &Value = *const_cast<C_FLOAT64 *>(&mValue);
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {
          std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
          std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

          for (; it != end; ++it) (*it)->value();
        }
        return Value = mpFunction->calcValue(*mpCallParameters);
        break;

      case EXPRESSION:
        return Value = mpExpression->calcValue();
        break;

      default:
        return Value = std::numeric_limits<C_FLOAT64>::quiet_NaN();
        break;
      }
  }

bool CEvaluationNodeCall::compile(const CEvaluationTree * pTree)
{
  bool success = true;

  switch (mType & 0x00FFFFFF)
    {
    case FUNCTION:
      mpFunction =
        dynamic_cast<CFunction *>(CCopasiDataModel::Global->getFunctionList()->findFunction(mData));
      if (!mpFunction) return false;

      // We need to check whether the provided arguments match the on needed by the
      // function;
      if (!verifyParameters(mCallNodes, mpFunction->getVariables())) return false;

      clearParameters(mpCallParameters, mCallNodes);
      mpCallParameters = buildParameters(mCallNodes);

      break;

    case EXPRESSION:
      mpExpression =
        dynamic_cast<CExpression *>(CCopasiDataModel::Global->getFunctionList()->findFunction(mData));
      if (!mpExpression)
        {
          // We may have a function with no arguments the parser is not able to destinguish
          // between that and an expression.
          mpFunction =
            dynamic_cast<CFunction *>(CCopasiDataModel::Global->getFunctionList()->findFunction(mData));
          if (!mpFunction) return false;

          mType = (CEvaluationNode::Type) (CEvaluationNode::CALL | FUNCTION);

          success = compile(pTree);
        }
      else
        success = mpExpression->compile(static_cast<const CExpression *>(pTree)->getListOfContainer());

      break;

    default:
      success = false;
      break;
    }

  return success;
}

bool CEvaluationNodeCall::calls(std::set< std::string > & list) const
  {
    if (list.count(mData)) return true;

    CEvaluationTree * pTree =
      CCopasiDataModel::Global->getFunctionList()->findFunction(mData);

    if (pTree) return pTree->calls(list);

    return false;
  }

std::string CEvaluationNodeCall::getInfix() const
  {
    std::string Infix = quote(mData, "-+^*/%(){},\t\r\n") + "(";
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {
          std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
          std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

          if (it != end) Infix += (*it++)->getInfix();

          for (; it != end; ++it)
            Infix += "," + (*it)->getInfix();
        }

        break;

      case EXPRESSION:
        break;

      default:
        return "@";
        break;
      }
    return Infix + ")";
  }

std::string CEvaluationNodeCall::getDisplayString(const CEvaluationTree * pTree) const
  {
    std::string DisplayString = quote(mData, "-+^*/%(){},\t\r\n") + "(";
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {
          std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
          std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

          if (it != end) DisplayString += (*it++)->getDisplayString(pTree);

          for (; it != end; ++it)
            DisplayString += "," + (*it)->getDisplayString(pTree);
        }

        break;

      case EXPRESSION:
        break;

      default:
        return "@";
        break;
      }
    return DisplayString + ")";
  }

std::string CEvaluationNodeCall::getDisplay_C_String(const CEvaluationTree * pTree) const
  {
    std::string DisplayString = quote(mData, "-+^*/%(){},\t\r\n") + "(";
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {
          std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
          std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

          if (it != end) DisplayString += (*it++)->getDisplay_C_String(pTree);

          for (; it != end; ++it)
            DisplayString += "," + (*it)->getDisplay_C_String(pTree);
        }

        break;

      case EXPRESSION:
        break;

      default:
        return "@";
        break;
      }
    return DisplayString + ")";
  }

std::string CEvaluationNodeCall::getDisplay_MMD_String(const CEvaluationTree * /* pTree */) const
  {
    std::string DisplayString = quote(mData, "-+^*/%(){},\t\r\n");

    return DisplayString;
  }

std::string CEvaluationNodeCall::getDisplay_XPP_String(const CEvaluationTree * /* pTree */) const
  {
    std::string DisplayString = quote(mData, "-+^*/%(){},\t\r\n");

    return DisplayString;
  }

CEvaluationNode* CEvaluationNodeCall::createNodeFromASTTree(const ASTNode& node)
{
  SubType subType = CEvaluationNodeCall::FUNCTION;
  std::string data = node.getName();

  CEvaluationNodeCall* convertedNode = new CEvaluationNodeCall(subType, data);
  unsigned int i, iMax = node.getNumChildren();
  for (i = 0; i < iMax;++i)
    {
      convertedNode->addChild(CEvaluationTree::convertASTNode(*node.getChild(i)));
    }
  return convertedNode;
}

ASTNode* CEvaluationNodeCall::toAST() const
  {
    ASTNode* node = new ASTNode(AST_FUNCTION);
    const std::string funName = this->getData();
    CEvaluationTree* pFun = CCopasiDataModel::Global->getFunctionList()->findFunction(funName);
    if (pFun->getSBMLId() != "")
      {
        node->setName(pFun->getSBMLId().c_str());
      }
    else
      {
        node->setName(funName.c_str());
        pFun->setSBMLId(funName);
      }
    const CEvaluationNode* child = static_cast<const CEvaluationNode*>(this->getChild());
    while (child)
      {
        node->addChild(child->toAST());
        child = static_cast<const CEvaluationNode*>(child->getSibling());
      }
    return node;
  }

bool CEvaluationNodeCall::addChild(CCopasiNode< Data > * pChild,
                                   CCopasiNode< Data > * pAfter)
{
  CCopasiNode< Data >::addChild(pChild, pAfter);
  mCallNodes.push_back(static_cast<CEvaluationNode *>(pChild));

  return true;
}

bool CEvaluationNodeCall::removeChild(CCopasiNode< Data > * pChild)
{
  std::vector<CEvaluationNode *>::iterator it = mCallNodes.begin();
  std::vector<CEvaluationNode *>::iterator end = mCallNodes.end();

  while (it != end && *it != pChild) ++it;
  if (it != end) mCallNodes.erase(it);

  return CCopasiNode< Data >::removeChild(pChild);
}

CCallParameters< C_FLOAT64 > *
CEvaluationNodeCall::buildParameters(const std::vector<CEvaluationNode *> & vector)
{
  std::vector<CEvaluationNode *>::const_iterator it = vector.begin();
  std::vector<CEvaluationNode *>::const_iterator end = vector.end();

  CCallParameters< C_FLOAT64 > * pCallParameters =
    new CCallParameters< C_FLOAT64 >(vector.size());
  unsigned C_INT32 i;
  for (i = 0; it != end; ++it, i++)
    {
      if (type((*it)->getType()) == CEvaluationNode::VECTOR)
        (*pCallParameters)[i].vector = buildParameters(static_cast<const CEvaluationNodeVector *>(*it)->getVector());
      else
        (*pCallParameters)[i].value = (*it)->getValuePointer();
    }

  return pCallParameters;
}

void
CEvaluationNodeCall::clearParameters(CCallParameters< C_FLOAT64 > * pCallParameters,
                                     const std::vector<CEvaluationNode *> & vector)
{
  if (!pCallParameters) return;

  std::vector<CEvaluationNode *>::const_iterator it = vector.begin();
  std::vector<CEvaluationNode *>::const_iterator end = vector.end();

  unsigned C_INT32 i;
  for (i = 0; it != end; ++it, i++)
    {
      if (type((*it)->getType()) == CEvaluationNode::VECTOR)
        clearParameters((*pCallParameters)[i].vector,
                        static_cast<const CEvaluationNodeVector *>(*it)->getVector());
    }

  delete pCallParameters;
  return;
}

bool
CEvaluationNodeCall::verifyParameters(const std::vector<CEvaluationNode *> & vector,
                                      const CFunctionParameters & functionParameters)
{
  if (vector.size() != functionParameters.size()) return false;

  std::vector<CEvaluationNode *>::const_iterator it = vector.begin();
  std::vector<CEvaluationNode *>::const_iterator end = vector.end();

  unsigned C_INT32 i;

  for (i = 0; it != end; ++it, i++)
    {
      if ((type((*it)->getType()) == CEvaluationNode::VECTOR &&
           functionParameters[i]->getType() != CFunctionParameter::VFLOAT64) ||
          functionParameters[i]->getType() == CFunctionParameter::VFLOAT64)
        return false;
    }

  return true;
}

const CEvaluationTree * CEvaluationNodeCall::getCalledTree() const
  {
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        return mpFunction;

      case EXPRESSION:
        return mpExpression;

      default:
        return NULL;
      }
  }

#include "utilities/copasimathml.h"

void CEvaluationNodeCall::writeMathML(std::ostream & out,
                                      const std::vector<std::vector<std::string> > & env,
                                      bool expand,
                                      unsigned C_INT32 l) const
  {
    switch (mType & 0x00FFFFFF)
      {
      case FUNCTION:
        {

#if 0
          if (!expand)
            {
#endif
              out << SPC(l) << "<mrow>" << std::endl;

              out << SPC(l + 1) << "<mi>" << mData << "</mi>" << std::endl;
              out << SPC(l + 1) << "<mo>  </mo>" << std::endl;
              out << SPC(l + 1) << "<mrow>" << std::endl;
              out << SPC(l + 2) << "<mo> (</mo>" << std::endl;
              out << SPC(l + 2) << "<mrow>" << std::endl;

              std::vector< CEvaluationNode * >::const_iterator it = mCallNodes.begin();
              std::vector< CEvaluationNode * >::const_iterator end = mCallNodes.end();

              if (it != end) (*it++)->writeMathML(out, env, expand, l + 3);

              for (; it != end; ++it)
                {

                  out << SPC(l + 3) << "<mo> , </mo>" << std::endl;
                  (*it)->writeMathML(out, env, expand, l + 3);
                }

              out << SPC(l + 2) << "</mrow>" << std::endl;
              out << SPC(l + 2) << "<mo>) </mo>" << std::endl;

              out << SPC(l + 1) << "</mrow>" << std::endl;
              out << SPC(l) << "</mrow>" << std::endl;
#if 0
            }
          // else  :TODO
#endif
        }
        break;

      case EXPRESSION:
        break;

      default:
        break;
      }

    return;
  }
<|endoftext|>


<commit_before>#include <sys/task.h>
#include <sys/syscall.h>
#include <kernel/task.H>
#include <kernel/taskmgr.H>
#include <kernel/cpu.H>
#include <sys/vfs.h>
#include <sys/msg.h>

using namespace Systemcalls;

void task_yield()
{
    _syscall0(TASK_YIELD);
    return;
}

tid_t task_create(void(*fn)(void*), void* ptr)
{
    return (tid_t)(uint64_t) _syscall2(TASK_START, (void*)fn, ptr);
}

void task_end()
{
    _syscall0(TASK_END); // no return.
    return;
}

tid_t task_gettid()
{
    // Even though we have a syscall for GETTID, we also have the task in
    // GRP13.

    register task_t* task;
    asm volatile("addi %0, 13, 0" : "=r"(task));
    return task->tid;
    //return (tid_t)_syscall0(TASK_GETTID);
}

cpuid_t task_getcpuid()
{
    register task_t* task;
    asm volatile("addi %0, 13, 0" : "=r"(task));
    return task->cpu->cpu;
}

tid_t task_exec(const char* file, void* ptr)
{
    // The VFS process is responsible for finding the module and creating the
    // new process.  So, we send a message over to that process.

    tid_t child = -1;

    // Create message, send.
    msg_q_t vfsQ = (msg_q_t)_syscall0(MSGQ_RESOLVE_ROOT);
    msg_t* msg = msg_allocate();
    msg->type = VFS_MSG_EXEC;
    msg->data[0] = (uint64_t) file;
    msg->data[1] = (uint64_t) ptr;
    int rc = msg_sendrecv(vfsQ, msg);

    if (0 == rc)
    {
	// Get child ID from message data 0.
	child = (tid_t) msg->data[0];
    }
    else
    {
	child = rc;
    }

    msg_free(msg);
    return child;
}
<commit_msg>Read task_create function pointer from user space for memory protection validation.<commit_after>#include <sys/task.h>
#include <sys/syscall.h>
#include <kernel/task.H>
#include <kernel/taskmgr.H>
#include <kernel/cpu.H>
#include <sys/vfs.h>
#include <sys/msg.h>

using namespace Systemcalls;

void task_yield()
{
    _syscall0(TASK_YIELD);
    return;
}

tid_t task_create(void(*fn)(void*), void* ptr)
{
    // Verify we have (memory) permissions to load the function pointer so
    // we don't load bad memory from kernel space.
    register uint64_t function = (uint64_t) fn;
    asm volatile("ld %0, 0(%1)" : "=b"(function) : "b" (function));

    return (tid_t)(uint64_t) _syscall2(TASK_START, (void*)fn, ptr);
}

void task_end()
{
    _syscall0(TASK_END); // no return.
    return;
}

tid_t task_gettid()
{
    // Even though we have a syscall for GETTID, we also have the task in
    // GRP13.

    register task_t* task;
    asm volatile("addi %0, 13, 0" : "=r"(task));
    return task->tid;
    //return (tid_t)_syscall0(TASK_GETTID);
}

cpuid_t task_getcpuid()
{
    register task_t* task;
    asm volatile("addi %0, 13, 0" : "=r"(task));
    return task->cpu->cpu;
}

tid_t task_exec(const char* file, void* ptr)
{
    // The VFS process is responsible for finding the module and creating the
    // new process.  So, we send a message over to that process.

    tid_t child = -1;

    // Create message, send.
    msg_q_t vfsQ = (msg_q_t)_syscall0(MSGQ_RESOLVE_ROOT);
    msg_t* msg = msg_allocate();
    msg->type = VFS_MSG_EXEC;
    msg->data[0] = (uint64_t) file;
    msg->data[1] = (uint64_t) ptr;
    int rc = msg_sendrecv(vfsQ, msg);

    if (0 == rc)
    {
	// Get child ID from message data 0.
	child = (tid_t) msg->data[0];
    }
    else
    {
	child = rc;
    }

    msg_free(msg);
    return child;
}
<|endoftext|>