<commit_before>#pragma once

#include "shared.hpp"

#include <functional>
#include <type_traits>
#include <typeindex>
#include <vector>
#include <unordered_map>
#include <string>

namespace stx {

class injector {
public:
	injector(injector* fallback = nullptr) noexcept : fallback(fallback) {}
	injector(injector& fallback) noexcept : injector(&fallback) {}

	// Create once, destroy after injector is destroyed
	template<class T, class Implementation = T>
	injector& singleton() noexcept { factories[typeid(T)] = stx::make_shared<SingletonFactory<T, Implementation>>(); return *this; }
	// Do not recreate until all references are gone
	template<class T, class Implementation = T>
	injector& cached()    noexcept { factories[typeid(T)] = stx::make_shared<CachedFactory<T, Implementation>>(); return *this; }
	// Recreate every time
	template<class T, class Implementation = T>
	injector& ephemeral() noexcept {
		factories[typeid(T)] = stx::make_shared<EphemeralFactory<T, Implementation>>();
		return *this;
	}

	template<class T>
	stx::shared<T> get() noexcept {
		auto iter = factories.find(typeid(T));
		if(iter == factories.end()) {
			if(!fallback) return nullptr;
			return fallback->get<T>();
		}
		return iter->second->get(*this).cast_static<T>();
	}

	template<class T>
	stx::shared<T> require() {
		auto result = get<T>();
		if(!result) {
			throw std::runtime_error(std::string("Could not find or construct instance of type") + typeid(T).name());
		}
		return result;
	}

	template<class... Tn> // Call operator injects all arguments
	void operator()(Tn&... t) {
		std::tie(t...) =
			std::tuple<std::remove_reference_t<Tn>...>(
				(std::is_same_v<Tn, Tn> ? *this : *this)... // Hack to repeat *this for Tn...
			);
	}

	template<class T>
	operator stx::shared<T>() noexcept { return get<T>(); }
private:
	injector* fallback = nullptr;

	struct Factory {
		virtual stx::shared<void> get(injector& context) noexcept = 0;
	};

	template<class T>
	class dependency_shared_block final : public shared_block {
		using Tptr = std::remove_all_extents_t<T>*;

		alignas(T) unsigned char m_data[sizeof(T)];
	public:
		std::vector<stx::shared<void>> dependencies;

		template<class... Args>
		dependency_shared_block(Args&&... args) noexcept {
			T* tmp = new(m_data) T(std::forward<Args>(args)...);
			if(!((unsigned char*)tmp == m_data)) std::terminate();
			detail::handle_enable_shared_from_this<T, Tptr>(tmp, this);
		}

		T* value() { return (T*) m_data; }

		void shared_block_destroy() noexcept override {
			value()->~T();
			dependencies.clear();
		}
		void shared_block_free() noexcept override { delete this; }
	};

	template<class T, class Implementation>
	struct SingletonFactory final : public Factory {
		stx::shared<void> instance;
		stx::shared<void> get(injector& context) noexcept {
			if(!instance) {
				instance = context.create<Implementation>().template cast_dynamic<T>();
			}
			return instance;
		}
	};

	template<class T, class Implementation>
	struct CachedFactory final : public Factory {
		stx::weak<void> instance;
		stx::shared<void> get(injector& context) noexcept {
			auto result = instance.lock();
			if(!result) {
				instance = result = context.create<Implementation>().template cast_dynamic<T>();
			}
			return result;
		}
	};

	template<class T, class Implementation>
	struct EphemeralFactory final : public Factory {
		stx::shared<void> get(injector& context) noexcept {
			return context.create<Implementation>().template cast_dynamic<T>();
		}
	};

	template<class DoNotBindTo = void>
	struct autobinder {
		injector* m_injector;

		std::vector<stx::shared<void>> dependencies = {};

		template<class T>
		using basic_type_of = std::remove_reference_t<std::remove_const_t<T>>;

		template<class T>
		const static bool can_bind_to = !std::is_same_v<basic_type_of<T>, DoNotBindTo> && !std::is_same_v<basic_type_of<T>, stx::shared<DoNotBindTo>>;

		template<class T, class = std::enable_if_t<can_bind_to<T>>>
		operator stx::shared<T>() {
			auto result = m_injector->require<T>();
			dependencies.push_back(result);
			return result;
		}

		template<typename T, typename = std::enable_if_t<can_bind_to<T>>>
		operator T&() {
			if constexpr(std::is_same_v<T, stx::injector>) {
				return *m_injector;
			}
			else {
				auto result = m_injector->require<T>();
				dependencies.push_back(result);
				return *result;
			}
		}

		template<typename T, typename = std::enable_if_t<can_bind_to<T>>>
		operator T*() {
			if constexpr(std::is_same_v<T, stx::injector>) {
				return m_injector;
			}
			else {
				auto result = m_injector->get<T>();
				if(result)
					dependencies.push_back(result);
				return result.get();
			}
		}

		autobinder(injector* injector) noexcept : m_injector(injector) {}
		autobinder(autobinder&& other) noexcept                 = delete;
		autobinder& operator=(autobinder&& other) noexcept      = delete;
		autobinder(autobinder const& other) noexcept            = delete;
		autobinder& operator=(autobinder const& other) noexcept = delete;
	};

	template<class T>
	stx::shared<T> create() {
		using binder = autobinder<T>;
		binder binding{this};

		auto construct = [&]<class... Args>(Args&&... args) {
			stx::shared<T> result;
			auto* block = new dependency_shared_block<T>(std::forward<Args>(args)...);
			block->dependencies = std::move(binding.dependencies);
			result._move_reset(block->value(), block);
			return result;
		};

		if constexpr(std::is_constructible_v<T, binder&, binder&, binder&, binder&, binder&, binder&>) { return construct(binding, binding, binding, binding, binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&, binder&, binder&, binder&, binder&>) { return construct(binding, binding, binding, binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&, binder&, binder&, binder&>) { return construct(binding, binding, binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&, binder&, binder&>) { return construct(binding, binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&, binder&>) { return construct(binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&>) { return construct(binding); }
		else if constexpr(std::is_default_constructible_v<T>) { return construct(); }
		else {
			printf("No viable constructor for %s\n", typeid(T).name());
			std::terminate();
		}
	}

	std::unordered_map<std::type_index, stx::shared<Factory>> factories;
};

} // namespace stx
<commit_msg>Added injector::create_singleton<T>() which registers a singleton and creates it<commit_after>#pragma once

#include "shared.hpp"

#include <functional>
#include <type_traits>
#include <typeindex>
#include <vector>
#include <unordered_map>
#include <string>

namespace stx {

class injector {
public:
	injector(injector* fallback = nullptr) noexcept : fallback(fallback) {}
	injector(injector& fallback) noexcept : injector(&fallback) {}

	// Create once, destroy after injector is destroyed
	template<class T, class Implementation = T>
	injector& singleton() noexcept { factories[typeid(T)] = stx::make_shared<SingletonFactory<T, Implementation>>(); return *this; }
	// Do not recreate until all references are gone
	template<class T, class Implementation = T>
	injector& cached()    noexcept { factories[typeid(T)] = stx::make_shared<CachedFactory<T, Implementation>>(); return *this; }
	// Recreate every time
	template<class T, class Implementation = T>
	injector& ephemeral() noexcept {
		factories[typeid(T)] = stx::make_shared<EphemeralFactory<T, Implementation>>();
		return *this;
	}

	template<class T, class Implementation = T>
	stx::shared<T> create_singleton() {
		auto& factory = factories[typeid(T)];
		if(!factory) factory = stx::make_shared<SingletonFactory<T, Implementation>>();
		return factory->get(*this).cast_static<T>();
	}

	template<class T>
	stx::shared<T> get() noexcept {
		auto iter = factories.find(typeid(T));
		if(iter == factories.end()) {
			if(!fallback) return nullptr;
			return fallback->get<T>();
		}
		return iter->second->get(*this).cast_static<T>();
	}

	template<class T>
	stx::shared<T> require() {
		auto result = get<T>();
		if(!result) {
			throw std::runtime_error(std::string("Could not find or construct instance of type") + typeid(T).name());
		}
		return result;
	}

	template<class... Tn> // Call operator injects all arguments
	void operator()(Tn&... t) {
		std::tie(t...) =
			std::tuple<std::remove_reference_t<Tn>...>(
				(std::is_same_v<Tn, Tn> ? *this : *this)... // Hack to repeat *this for Tn...
			);
	}

	template<class T>
	operator stx::shared<T>() noexcept { return get<T>(); }
private:
	injector* fallback = nullptr;

	struct Factory {
		virtual stx::shared<void> get(injector& context) noexcept = 0;
	};

	template<class T>
	class dependency_shared_block final : public shared_block {
		using Tptr = std::remove_all_extents_t<T>*;

		alignas(T) unsigned char m_data[sizeof(T)];
	public:
		std::vector<stx::shared<void>> dependencies;

		template<class... Args>
		dependency_shared_block(Args&&... args) noexcept {
			T* tmp = new(m_data) T(std::forward<Args>(args)...);
			if(!((unsigned char*)tmp == m_data)) std::terminate();
			detail::handle_enable_shared_from_this<T, Tptr>(tmp, this);
		}

		T* value() { return (T*) m_data; }

		void shared_block_destroy() noexcept override {
			value()->~T();
			dependencies.clear();
		}
		void shared_block_free() noexcept override { delete this; }
	};

	template<class T, class Implementation>
	struct SingletonFactory final : public Factory {
		stx::shared<void> instance;
		stx::shared<void> get(injector& context) noexcept {
			if(!instance) {
				instance = context.create<Implementation>().template cast_dynamic<T>();
			}
			return instance;
		}
	};

	template<class T, class Implementation>
	struct CachedFactory final : public Factory {
		stx::weak<void> instance;
		stx::shared<void> get(injector& context) noexcept {
			auto result = instance.lock();
			if(!result) {
				instance = result = context.create<Implementation>().template cast_dynamic<T>();
			}
			return result;
		}
	};

	template<class T, class Implementation>
	struct EphemeralFactory final : public Factory {
		stx::shared<void> get(injector& context) noexcept {
			return context.create<Implementation>().template cast_dynamic<T>();
		}
	};

	template<class DoNotBindTo = void>
	struct autobinder {
		injector* m_injector;

		std::vector<stx::shared<void>> dependencies = {};

		template<class T>
		using basic_type_of = std::remove_reference_t<std::remove_const_t<T>>;

		template<class T>
		const static bool can_bind_to = !std::is_same_v<basic_type_of<T>, DoNotBindTo> && !std::is_same_v<basic_type_of<T>, stx::shared<DoNotBindTo>>;

		template<class T, class = std::enable_if_t<can_bind_to<T>>>
		operator stx::shared<T>() {
			auto result = m_injector->require<T>();
			dependencies.push_back(result);
			return result;
		}

		template<typename T, typename = std::enable_if_t<can_bind_to<T>>>
		operator T&() {
			if constexpr(std::is_same_v<T, stx::injector>) {
				return *m_injector;
			}
			else {
				auto result = m_injector->require<T>();
				dependencies.push_back(result);
				return *result;
			}
		}

		template<typename T, typename = std::enable_if_t<can_bind_to<T>>>
		operator T*() {
			if constexpr(std::is_same_v<T, stx::injector>) {
				return m_injector;
			}
			else {
				auto result = m_injector->get<T>();
				if(result)
					dependencies.push_back(result);
				return result.get();
			}
		}

		autobinder(injector* injector) noexcept : m_injector(injector) {}
		autobinder(autobinder&& other) noexcept                 = delete;
		autobinder& operator=(autobinder&& other) noexcept      = delete;
		autobinder(autobinder const& other) noexcept            = delete;
		autobinder& operator=(autobinder const& other) noexcept = delete;
	};

	template<class T>
	stx::shared<T> create() {
		using binder = autobinder<T>;
		binder binding{this};

		auto construct = [&]<class... Args>(Args&&... args) {
			stx::shared<T> result;
			auto* block = new dependency_shared_block<T>(std::forward<Args>(args)...);
			block->dependencies = std::move(binding.dependencies);
			result._move_reset(block->value(), block);
			return result;
		};

		if constexpr(std::is_constructible_v<T, binder&, binder&, binder&, binder&, binder&, binder&>) { return construct(binding, binding, binding, binding, binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&, binder&, binder&, binder&, binder&>) { return construct(binding, binding, binding, binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&, binder&, binder&, binder&>) { return construct(binding, binding, binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&, binder&, binder&>) { return construct(binding, binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&, binder&>) { return construct(binding, binding); }
		else if constexpr(std::is_constructible_v<T, binder&>) { return construct(binding); }
		else if constexpr(std::is_default_constructible_v<T>) { return construct(); }
		else {
			printf("No viable constructor for %s\n", typeid(T).name());
			std::terminate();
		}
	}

	std::unordered_map<std::type_index, stx::shared<Factory>> factories;
};

} // namespace stx
<|endoftext|>


<commit_before>#include "opengl/renderers/renderer.h"

namespace mtao { namespace opengl { namespace renderers {

    void Renderer::imgui_interface() {

    }
    void Renderer::set_mvp(const glm::mat4& mv, const glm::mat4&p) {
        for(auto&& prg: mvp_programs()) {
            auto active = prg->useRAII();
            prg->getUniform("MV").setMatrix(mv);
            prg->getUniform("P").setMatrix(p);
        }

        set_mvp(p*mv);

    }
    void Renderer::set_mvp(const glm::mat4& mvp) {

        for(auto&& p: mvp_programs()) {
            auto active = p->useRAII();
            p->getUniform("MVP").setMatrix(mvp);
        }
    }

}}}
<commit_msg>potential sigfault<commit_after>#include "opengl/renderers/renderer.h"

namespace mtao { namespace opengl { namespace renderers {

    void Renderer::imgui_interface() {

    }
    void Renderer::set_mvp(const glm::mat4& mv, const glm::mat4&p) {
        for(auto&& prg: mvp_programs()) {
            if(prg) {
                auto active = prg->useRAII();
                prg->getUniform("MV").setMatrix(mv);
                prg->getUniform("P").setMatrix(p);
            }
        }

        set_mvp(p*mv);

    }
    void Renderer::set_mvp(const glm::mat4& mvp) {

        for(auto&& p: mvp_programs()) {
            if(p) {
                auto active = p->useRAII();
                p->getUniform("MVP").setMatrix(mvp);
            }
        }
    }

}}}
<|endoftext|>


<commit_before>// http://www.apache.org/licenses/LICENSE-2.0
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
#include "rccpp.h"
#include "interface/server.h"
#include "core/log.h"
#include <c55/filesys.h>
#include <vector>
#include <string>
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <dlfcn.h>
#include <cstddef>
#include <vector>
#include <cassert>
#include <memory>
#include <string>
#include <unordered_map>
#include <algorithm>
#define MODULE "__rccpp"

namespace rccpp {

// linux
#if 1
static void *library_load(const char *filename){
	return dlopen(filename, RTLD_NOW);
}
static void library_unload(void *module){
	dlclose(module);
}
static void *library_get_address(void *module, const char *name){
	return dlsym(module, name);
}
#elif 0
static void *library_load(const char *filename){
	return LoadLibrary(filename);
}
static void library_unload(void *module){
	FreeLibrary(module);
}
static void *library_get_address(void *module, const char *name){
	return GetProcAddress(module, name);
}
#endif

typedef void *(*RCCPP_Constructor)(interface::Server *server);

struct RCCPP_Info {
	void *module;
	RCCPP_Constructor constructor;
};

struct CCompiler: public Compiler
{
	ss_ m_compiler_command;
	std::unordered_map<std::string, RCCPP_Info> m_module_info;

	CCompiler(const ss_ &compiler_command):
		m_compiler_command(compiler_command)
	{
	}

	bool compile(const std::string &in_path, const std::string &out_path,
			const ss_ &extra_cxxflags, const ss_ &extra_ldflags)
	{
		ss_ command = m_compiler_command;
		// command += " -g -O0 -fPIC -fvisibility=hidden -shared";
		command += " -DRCCPP -g -fPIC -fvisibility=hidden -shared";

		command += " -std=c++11";
		if(extra_cxxflags != "")
			command += ss_()+" "+extra_cxxflags;
		if(extra_ldflags != "")
			command += ss_()+" "+extra_ldflags;

		for(const std::string &dir : include_directories) command += " -I"+dir;
		for(const std::string &dir : library_directories) command += " -L"+dir;

		command += " -o"+out_path;
		command += " "+in_path;

		//log_i(MODULE, ">>> %s", cs(command));

		// Fork for compilation.
		int f = fork();
		if(f == 0){
			execl("/bin/sh", "sh", "-c", command.c_str(), (const char*)nullptr);
		}

		// Wait for the forked process to exit.
		int exit_status;
		while(wait(&exit_status) > 0);

		return exit_status == 0;
	}

	bool build(const std::string &module_name,
			const std::string &in_path, const std::string &out_path,
			const ss_ &extra_cxxflags, const ss_ &extra_ldflags)
	{
		log_ni(MODULE, "Building %s: %s -> %s... ", cs(module_name), cs(in_path),
				cs(out_path));

		std::string out_dir = c55fs::stripFilename(out_path);
		c55fs::CreateAllDirs(out_dir);

		if(!compile(in_path, out_path, extra_cxxflags, extra_ldflags)){
			log_i(MODULE, "Failed!");
			return false;
		}
		log_i(MODULE, "Success!");

		void *new_module = library_load(out_path.c_str());
		if(new_module == NULL){
			log_i(MODULE, "Failed to load compiled library: %s", dlerror());
			return false;
		}

		ss_ constructor_name = ss_()+"createModule_"+module_name;
		RCCPP_Constructor constructor = (RCCPP_Constructor)library_get_address(
				new_module, constructor_name.c_str());
		if(constructor == nullptr){
			log_i(MODULE, "%s is missing from the library", cs(constructor_name));
			return false;
		}

		auto it = m_module_info.find(module_name);
		if(it != m_module_info.end()){
			RCCPP_Info &funcs = it->second;
			funcs.constructor = constructor;
			funcs.module = new_module;
		} else {
			RCCPP_Info funcs;
			funcs.constructor = constructor;
			funcs.module = new_module;
			m_module_info.emplace(module_name, std::move(funcs));
		}
		return true;
	}

	void* construct(const char *name, interface::Server *server)
	{
		auto it = m_module_info.find(name);
		if(it == m_module_info.end()){
			log_w(MODULE, "construct(%s): Module is not loaded", name);
			return NULL;
		}

		RCCPP_Info &info = it->second;
		RCCPP_Constructor constructor = info.constructor;

		return constructor(server);
	}

	void unload(const std::string &module_name)
	{
		auto it = m_module_info.find(module_name);
		if(it == m_module_info.end()){
			assert(nullptr && "Failed to get class info");
			return;
		}
		void *module = it->second.module;
		library_unload(module);
		m_module_info.erase(module_name);
	}
};

Compiler* createCompiler(const ss_ &compiler_command)
{
	return new CCompiler(compiler_command);
}

} // rccpp
<commit_msg>server/rccpp: Use interface/process.h<commit_after>// http://www.apache.org/licenses/LICENSE-2.0
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
#include "rccpp.h"
#include "core/log.h"
#include "interface/server.h"
#include "interface/process.h"
#include <c55/filesys.h>
#include <vector>
#include <string>
#include <iostream>
#include <dlfcn.h>
#include <cstddef>
#include <vector>
#include <cassert>
#include <memory>
#include <string>
#include <unordered_map>
#include <algorithm>
#define MODULE "__rccpp"

namespace rccpp {

// linux
#if 1
static void *library_load(const char *filename){
	return dlopen(filename, RTLD_NOW);
}
static void library_unload(void *module){
	dlclose(module);
}
static void *library_get_address(void *module, const char *name){
	return dlsym(module, name);
}
#elif 0
static void *library_load(const char *filename){
	return LoadLibrary(filename);
}
static void library_unload(void *module){
	FreeLibrary(module);
}
static void *library_get_address(void *module, const char *name){
	return GetProcAddress(module, name);
}
#endif

typedef void *(*RCCPP_Constructor)(interface::Server *server);

struct RCCPP_Info {
	void *module;
	RCCPP_Constructor constructor;
};

struct CCompiler: public Compiler
{
	ss_ m_compiler_command;
	std::unordered_map<std::string, RCCPP_Info> m_module_info;

	CCompiler(const ss_ &compiler_command):
		m_compiler_command(compiler_command)
	{
	}

	bool compile(const std::string &in_path, const std::string &out_path,
			const ss_ &extra_cxxflags, const ss_ &extra_ldflags)
	{
		ss_ command = m_compiler_command;
		command += " -DRCCPP -g -fPIC -fvisibility=hidden -shared";
		command += " -std=c++11";
		if(extra_cxxflags != "")
			command += ss_()+" "+extra_cxxflags;
		if(extra_ldflags != "")
			command += ss_()+" "+extra_ldflags;

		for(const std::string &dir : include_directories) command += " -I"+dir;
		for(const std::string &dir : library_directories) command += " -L"+dir;

		command += " -o"+out_path;
		command += " "+in_path;

		int exit_status = interface::process::shell_exec(command);

		return exit_status == 0;
	}

	bool build(const std::string &module_name,
			const std::string &in_path, const std::string &out_path,
			const ss_ &extra_cxxflags, const ss_ &extra_ldflags)
	{
		log_ni(MODULE, "Building %s: %s -> %s... ", cs(module_name), cs(in_path),
				cs(out_path));

		std::string out_dir = c55fs::stripFilename(out_path);
		c55fs::CreateAllDirs(out_dir);

		if(!compile(in_path, out_path, extra_cxxflags, extra_ldflags)){
			log_i(MODULE, "Failed!");
			return false;
		}
		log_i(MODULE, "Success!");

		void *new_module = library_load(out_path.c_str());
		if(new_module == NULL){
			log_i(MODULE, "Failed to load compiled library: %s", dlerror());
			return false;
		}

		ss_ constructor_name = ss_()+"createModule_"+module_name;
		RCCPP_Constructor constructor = (RCCPP_Constructor)library_get_address(
				new_module, constructor_name.c_str());
		if(constructor == nullptr){
			log_i(MODULE, "%s is missing from the library", cs(constructor_name));
			return false;
		}

		auto it = m_module_info.find(module_name);
		if(it != m_module_info.end()){
			RCCPP_Info &funcs = it->second;
			funcs.constructor = constructor;
			funcs.module = new_module;
		} else {
			RCCPP_Info funcs;
			funcs.constructor = constructor;
			funcs.module = new_module;
			m_module_info.emplace(module_name, std::move(funcs));
		}
		return true;
	}

	void* construct(const char *name, interface::Server *server)
	{
		auto it = m_module_info.find(name);
		if(it == m_module_info.end()){
			log_w(MODULE, "construct(%s): Module is not loaded", name);
			return NULL;
		}

		RCCPP_Info &info = it->second;
		RCCPP_Constructor constructor = info.constructor;

		return constructor(server);
	}

	void unload(const std::string &module_name)
	{
		auto it = m_module_info.find(module_name);
		if(it == m_module_info.end()){
			assert(nullptr && "Failed to get class info");
			return;
		}
		void *module = it->second.module;
		library_unload(module);
		m_module_info.erase(module_name);
	}
};

Compiler* createCompiler(const ss_ &compiler_command)
{
	return new CCompiler(compiler_command);
}

} // rccpp
<|endoftext|>


<commit_before>/* © 2010 David Given.
 * LBW is licensed under the MIT open source license. See the COPYING
 * file in this distribution for the full text.
 */

#include "globals.h"
#include "syscalls.h"
#include "filesystem/RawFD.h"
#include "syscalls/mmap.h"
#include <sys/mman.h>
#include <map>
#include <bitset>

//#define VERBOSE

using std::map;
using std::bitset;

/* Linux wants to be able to map files to 4kB page boundaries when loading
 * executables. Alas, Interix can't do that --- it will only let us map stuff
 * to 64kB boundaries. So what follows is a hideous emulation layer where we
 * try to emulate 4kB blocks on top of 64kB blocks by mmap()ing where we can
 * and just loading code where we can't.
 *
 * For clarity, I'll refer to a 64kB block as a block and a 4kB page as a
 * page.
 */

#undef PAGE_SIZE
static const u32 BLOCK_SIZE   = 0x00010000;
static const u32 PAGE_SIZE    = 0x00001000;
static const u32 RANGE_BOTTOM = 0x08000000;
static const u32 RANGE_TOP    = 0x80000000;

static const u32 BLOCK_COUNT = (RANGE_TOP - RANGE_BOTTOM) / BLOCK_SIZE;

class Block
{
public:
	Block(u8* address):
		_address(address)
	{
	}

	virtual ~Block()
	{
	}

	u8* Address() const
	{
		return _address;
	}

private:
	u8* _address;
};

class FragmentedBlock : public Block
{
public:
	FragmentedBlock(u8* address):
		Block(address)
	{
		void* result = mmap(address, BLOCK_SIZE,
				PROT_READ | PROT_WRITE | PROT_EXEC,
				MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
				-1, 0);
		if (result != address)
			throw errno;

#if defined VERBOSE
		log("FragmentedBlock(%08x)", address);
#endif
		_refcount = 0;
	}

	~FragmentedBlock()
	{
		munmap(Address(), BLOCK_SIZE);
	}

	bitset<16>& Pages()
	{
		return _usage;
	}

private:
	int _refcount;
	bitset<16> _usage;
};

class MappedBlock : public Block
{
public:
	MappedBlock(u8* address, int realfd, u32 offset,
			bool shared, bool w, bool x):
		Block(address)
	{
		int flags = MAP_FIXED;
		if (shared)
			flags |= MAP_SHARED;
		else
			flags |= MAP_PRIVATE;

		int prot = PROT_READ;
		if (w)
			prot |= PROT_WRITE;
		if (x)
			prot |= PROT_EXEC;

		void* result = mmap(address, BLOCK_SIZE, prot, flags, realfd, offset);
		if (result != address)
			throw errno;
#if defined VERBOSE
		log("MappedBlock(%08x)", address);
#endif
	}

	~MappedBlock()
	{
		munmap(Address(), BLOCK_SIZE);
	}
};

class BlockStore
{
public:
	BlockStore()
	{
		memset(_blocks, 0, sizeof(_blocks));
	}

	~BlockStore()
	{
		Reset();
	}

	void Reset()
	{
		for (u32 block = 0; block < BLOCK_COUNT; block++)
		{
			delete _blocks[block];
			_blocks[block] = NULL;
		}
	}

	Block*& GetBlock(u8* address)
	{
		if ((address < (u8*)RANGE_BOTTOM) || (address >= (u8*)RANGE_TOP))
		{
			log("address %08x out of range of refcounted area", address);
			throw EINVAL;
		}

		return _blocks[((u32)address - RANGE_BOTTOM) / BLOCK_SIZE];
	}

	/* address, length, offset must all be 64kB-aligned */
	void Map(u8* address, u32 length, int realfd, u32 offset,
					bool shared, bool w, bool x)
	{
		assert(aligned<BLOCK_SIZE>(address));
		assert(aligned<BLOCK_SIZE>(length));
		assert(aligned<BLOCK_SIZE>(offset));

		try
		{
			for (u32 i = 0; i < length; i += BLOCK_SIZE)
			{
#if defined VERBOSE
				log("create mapped block %08x", address + i);
#endif
				Block*& block = GetBlock(address + i);
				if (block)
					delete block;
				block = new MappedBlock(address + i, realfd, offset + i,
						shared, w, x);
			}
		}
		catch (int e)
		{
			log("Map() I/O error %d, trying to clean up");
			Unmap(address, length);
			throw e;
		}
	}

	/* address must be 64kB-aligned. */
	bitset<16>& GetPageMap(u8* address)
	{
		assert(aligned<BLOCK_SIZE>(address));

		Block*& block = GetBlock(address);
		if (!block)
		{
			/* No block here --- create one! */
			block = new FragmentedBlock(address);
		}

		MappedBlock* mb = dynamic_cast<MappedBlock*>(block);
		if (mb)
		{
			/* Need to convert this MappedBlock into a FragmentedBlock.
			 * This involves copying the data out, unmapping it, mapping
			 * a new one in the same place, and copying the data back in
			 * again.
			 */

			log("converting block at %08x from mapped to fragmented", address);
			u8 copybuffer[BLOCK_SIZE];
			memcpy(copybuffer, address, BLOCK_SIZE);

			delete block;
			FragmentedBlock* fb = new FragmentedBlock(address);
			block = fb;

			memcpy(address, copybuffer, BLOCK_SIZE);
			fb->Pages().set();
		}

		FragmentedBlock* fb = dynamic_cast<FragmentedBlock*>(block);
		assert(fb);
		return fb->Pages();
	}

	/* address must be 64kB-aligned */
	void Unmap(u8* address)
	{
		assert(aligned<BLOCK_SIZE>(address));

		Block*& block = GetBlock(address);
		delete block;
		block = NULL;
	}

	/* address, length must be 64kB-aligned */
	void Unmap(u8* address, u32 length)
	{
		assert(aligned<BLOCK_SIZE>(address));
		assert(aligned<BLOCK_SIZE>(length));

		for (u32 i = 0; i < length; i += BLOCK_SIZE)
			Unmap(address + i);
	}

	/* address must be 4kB-aligned */
	void UsePage(u8* address)
	{
		//log("ref %08x", address);
		assert(aligned<PAGE_SIZE>(address));
		u8* alignedaddress = align<BLOCK_SIZE>(address);
		u32 page = offset<BLOCK_SIZE>(address) / PAGE_SIZE;

		bitset<16>& pagemap = GetPageMap(alignedaddress);
		//log("(refcount is %d)", pagemap.count());
		pagemap[page] = true;
	}

	/* address must be 4kB-aligned */
	void UnusePage(u8* address)
	{
		//log("unref %08x", address);
		assert(aligned<PAGE_SIZE>(address));
		u8* alignedaddress = align<BLOCK_SIZE>(address);
		u32 page = offset<BLOCK_SIZE>(address) / PAGE_SIZE;

		bitset<16>& pagemap = GetPageMap(alignedaddress);
		pagemap[page] = false;
		//log("(refcount is %d)", pagemap.count());

		if (pagemap.none())
		{
			/* This block is no longer in use, so we can nuke it. */

#if defined VERBOSE
			log("nuking block %08x", alignedaddress);
#endif
			Unmap(alignedaddress, BLOCK_SIZE);
		}
	}

private:
	Block* _blocks[BLOCK_COUNT];
};
static BlockStore blockstore;

void UnmapAll()
{
	blockstore.Reset();
}

struct linux_mmap_arg_struct
{
	u32 addr;
	u32 len;
	u32 prot;
	u32 flags;
	u32 fd;
	u32 offset;
};

u32 do_mmap(u8* addr, u32 len, u32 prot, u32 flags, Ref<FD>& ref, u32 offset)
{
	RAIILock locked;

	if (!aligned<PAGE_SIZE>(addr))
		throw EINVAL;
	if (!aligned<PAGE_SIZE>(offset))
		throw EINVAL;

	if (prot & LINUX_PROT_SEM)
	{
		log("mmap(): no support for PROT_SEM, ignoring");
	}

	bool w = prot & LINUX_PROT_WRITE;
	bool x = prot & LINUX_PROT_EXEC;
	bool shared = flags & LINUX_MAP_SHARED;

	if (!(flags & LINUX_MAP_FIXED))
	{
		/* This is a very nasty hack to find an unused memory area to
		 * map the block into. Rather than keep our own range allocator,
		 * we abuse Interix'. This also has the advantage that we
		 * interoperate nicely with Interix' mappings.
		 */

		void* result = mmap(addr, len,
				PROT_READ | PROT_WRITE | PROT_EXEC,
				MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
				-1, 0);
		if (result == MAP_FAILED)
			throw ENOMEM;

#if defined VERBOSE
		log("nonfixed map going to %08x+%08x (app preferred %08x)", result, len, addr);
#endif
		addr = (u8*) result;
		int i = munmap(result, len);
		assert(i == 0);
	}

	if (flags & LINUX_MAP_ANONYMOUS)
	{
#if defined VERBOSE
		log("anonymous");
#endif
		/* Anonymous areas are all fragmented. */

		for (u32 i = 0; i < len; i += PAGE_SIZE)
		{
			blockstore.UsePage(addr + i);
			memset(addr + i, 0, PAGE_SIZE);
		}
	}
	else
	{
#if defined VERBOSE
		log("not anonymous");
#endif
		int realfd = ref->GetRealFD();

		/* If the offset and the address are 64kB-aligned, we can do a proper
		 * mmap(), which we prefer. Otherwise we have to create fragmented
		 * blocks and load the data into RAM (ick, phht).
		 */

		u8* loadaddr = addr;
		if (aligned<BLOCK_SIZE>(addr) && aligned<BLOCK_SIZE>(offset))
		{
#if defined VERBOSE
			log("aligned!");
#endif
			/* ...although remember we can only mmap() whole blocks. */

			u32 alignedlen = align<BLOCK_SIZE>(len);

			blockstore.Map(addr, alignedlen, realfd, offset, shared, w, x);

			/* The rest gets loaded into a fragmented block. */

			len -= alignedlen;
			loadaddr += alignedlen;
			offset += alignedlen;
		}

#if defined VERBOSE
		log("loading %08x+%08x @%08x", loadaddr, len, offset);
#endif
		for (u32 i = 0; i < len; i += PAGE_SIZE)
		{
			blockstore.UsePage(loadaddr + i);

			int r = pread(realfd, loadaddr+i, PAGE_SIZE, offset+i);
			if (r == -1)
				throw errno;
		}
	}

	return (u32) addr;
}

u32 do_mmap(u8* addr, u32 len, u32 prot, u32 flags, u32 fd, u32 offset)
{
	Ref<FD> ref;
	if (!(flags & LINUX_MAP_ANONYMOUS))
		ref = FD::Get(fd);
	return do_mmap(addr, len, prot, flags, ref, offset);
}

void do_munmap(u8* addr, u32 len)
{
	if (aligned<BLOCK_SIZE>(addr))
	{
#if defined VERBOSE
		log("unmapping aligned area %08x+%08x", addr, len);
#endif

		u32 alignedlen = align<BLOCK_SIZE>(len);

		blockstore.Unmap(addr, alignedlen);
		addr += alignedlen;
		len -= alignedlen;
	}

	for (u32 i = 0; i < len; i += PAGE_SIZE)
	{
#if defined VERBOSE
		log("unref %08x", addr + i);
#endif
		blockstore.UnusePage(addr + i);
	}
}

SYSCALL(sys32_mmap)
{
	struct linux_mmap_arg_struct& ma = *(struct linux_mmap_arg_struct*) arg.a0.p;
	return do_mmap((u8*) ma.addr, ma.len, ma.prot, ma.flags, ma.fd, ma.offset);
}

SYSCALL(sys32_mmap2)
{
	u_int32_t addr = arg.a0.u;
	u_int32_t len = arg.a1.u;
	u_int32_t prot = arg.a2.u;
	u_int32_t flags = arg.a3.u;
	int32_t fd = arg.a4.s;
	u_int32_t pgoff = arg.a5.u;

	return do_mmap((u8*) addr, len, prot, flags, fd, pgoff * 4096);
}

SYSCALL(sys_unmap)
{
	void* addr = arg.a0.p;
	size_t len = arg.a1.u;

	do_munmap((u8*) addr, len);
	return 0;
}

SYSCALL(sys32_mprotect)
{
	u_int32_t addr = arg.a0.u;
	u_int32_t len = arg.a1.u;
	u_int32_t prot = arg.a2.u;

	//int iprot = convert_prot_l2i(prot);
	//int result = mprotect((void*) addr, len, iprot);
	log("mprotect(%08x, %08x, %08x)", addr, len, prot);
	//return SysError(result);
	return 0;
}
<commit_msg>All memory is now writeable, to aid in code patching in the GDT perverter.<commit_after>/* © 2010 David Given.
 * LBW is licensed under the MIT open source license. See the COPYING
 * file in this distribution for the full text.
 */

#include "globals.h"
#include "syscalls.h"
#include "filesystem/RawFD.h"
#include "syscalls/mmap.h"
#include "MemOp.h"
#include <sys/mman.h>
#include <map>
#include <bitset>

//#define VERBOSE

using std::map;
using std::bitset;

/* Linux wants to be able to map files to 4kB page boundaries when loading
 * executables. Alas, Interix can't do that --- it will only let us map stuff
 * to 64kB boundaries. So what follows is a hideous emulation layer where we
 * try to emulate 4kB blocks on top of 64kB blocks by mmap()ing where we can
 * and just loading code where we can't.
 *
 * For clarity, I'll refer to a 64kB block as a block and a 4kB page as a
 * page.
 */

#undef PAGE_SIZE
static const u32 BLOCK_SIZE   = 0x00010000;
static const u32 PAGE_SIZE    = 0x00001000;
static const u32 RANGE_BOTTOM = 0x08000000;
static const u32 RANGE_TOP    = 0x80000000;

static const u32 BLOCK_COUNT = (RANGE_TOP - RANGE_BOTTOM) / BLOCK_SIZE;

class Block
{
public:
	Block(u8* address):
		_address(address)
	{
	}

	virtual ~Block()
	{
	}

	u8* Address() const
	{
		return _address;
	}

private:
	u8* _address;
};

class FragmentedBlock : public Block
{
public:
	FragmentedBlock(u8* address):
		Block(address)
	{
		void* result = mmap(address, BLOCK_SIZE,
				PROT_READ | PROT_WRITE | PROT_EXEC,
				MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
				-1, 0);
		if (result != address)
			throw errno;

#if defined VERBOSE
		log("FragmentedBlock(%08x)", address);
#endif
		_refcount = 0;
	}

	~FragmentedBlock()
	{
		munmap(Address(), BLOCK_SIZE);
	}

	bitset<16>& Pages()
	{
		return _usage;
	}

private:
	int _refcount;
	bitset<16> _usage;
};

class MappedBlock : public Block
{
public:
	MappedBlock(u8* address, int realfd, u32 offset,
			bool shared, bool w, bool x):
		Block(address)
	{
		int flags = MAP_FIXED;
		if (shared)
			flags |= MAP_SHARED;
		else
			flags |= MAP_PRIVATE;

		int prot = PROT_READ;
		if (w)
			prot |= PROT_WRITE;
		if (x)
			prot |= PROT_EXEC;

		void* result = mmap(address, BLOCK_SIZE, prot, flags, realfd, offset);
		if (result != address)
			throw errno;
#if defined VERBOSE
		log("MappedBlock(%08x)", address);
#endif
	}

	~MappedBlock()
	{
		munmap(Address(), BLOCK_SIZE);
	}
};

class BlockStore
{
public:
	BlockStore()
	{
		memset(_blocks, 0, sizeof(_blocks));
	}

	~BlockStore()
	{
		Reset();
	}

	void Reset()
	{
		for (u32 block = 0; block < BLOCK_COUNT; block++)
		{
			delete _blocks[block];
			_blocks[block] = NULL;
		}
	}

	Block*& GetBlock(u8* address)
	{
		if ((address < (u8*)RANGE_BOTTOM) || (address >= (u8*)RANGE_TOP))
		{
			log("address %08x out of range of refcounted area", address);
			throw EINVAL;
		}

		return _blocks[((u32)address - RANGE_BOTTOM) / BLOCK_SIZE];
	}

	/* address, length, offset must all be 64kB-aligned */
	void Map(u8* address, u32 length, int realfd, u32 offset,
					bool shared, bool w, bool x)
	{
		assert(MemOp::Aligned<BLOCK_SIZE>(address));
		assert(MemOp::Aligned<BLOCK_SIZE>(length));
		assert(MemOp::Aligned<BLOCK_SIZE>(offset));

		try
		{
			for (u32 i = 0; i < length; i += BLOCK_SIZE)
			{
#if defined VERBOSE
				log("create mapped block %08x", address + i);
#endif
				Block*& block = GetBlock(address + i);
				if (block)
					delete block;
				block = new MappedBlock(address + i, realfd, offset + i,
						shared, w, x);
			}
		}
		catch (int e)
		{
			log("Map() I/O error %d, trying to clean up");
			Unmap(address, length);
			throw e;
		}
	}

	/* address must be 64kB-aligned. */
	bitset<16>& GetPageMap(u8* address)
	{
		assert(MemOp::Aligned<BLOCK_SIZE>(address));

		Block*& block = GetBlock(address);
		if (!block)
		{
			/* No block here --- create one! */
			block = new FragmentedBlock(address);
		}

		MappedBlock* mb = dynamic_cast<MappedBlock*>(block);
		if (mb)
		{
			/* Need to convert this MappedBlock into a FragmentedBlock.
			 * This involves copying the data out, unmapping it, mapping
			 * a new one in the same place, and copying the data back in
			 * again.
			 */

			log("converting block at %08x from mapped to fragmented", address);
			u8 copybuffer[BLOCK_SIZE];
			memcpy(copybuffer, address, BLOCK_SIZE);

			delete block;
			FragmentedBlock* fb = new FragmentedBlock(address);
			block = fb;

			memcpy(address, copybuffer, BLOCK_SIZE);
			fb->Pages().set();
		}

		FragmentedBlock* fb = dynamic_cast<FragmentedBlock*>(block);
		assert(fb);
		return fb->Pages();
	}

	/* address must be 64kB-aligned */
	void Unmap(u8* address)
	{
		assert(MemOp::Aligned<BLOCK_SIZE>(address));

		Block*& block = GetBlock(address);
		delete block;
		block = NULL;
	}

	/* address, length must be 64kB-aligned */
	void Unmap(u8* address, u32 length)
	{
		assert(MemOp::Aligned<BLOCK_SIZE>(address));
		assert(MemOp::Aligned<BLOCK_SIZE>(length));

		for (u32 i = 0; i < length; i += BLOCK_SIZE)
			Unmap(address + i);
	}

	/* address must be 4kB-aligned */
	void UsePage(u8* address)
	{
		//log("ref %08x", address);
		assert(MemOp::Aligned<PAGE_SIZE>(address));
		u8* alignedaddress = MemOp::Align<BLOCK_SIZE>(address);
		u32 page = MemOp::Offset<BLOCK_SIZE>(address) / PAGE_SIZE;

		bitset<16>& pagemap = GetPageMap(alignedaddress);
		//log("(refcount is %d)", pagemap.count());
		pagemap[page] = true;
	}

	/* address must be 4kB-aligned */
	void UnusePage(u8* address)
	{
		//log("unref %08x", address);
		assert(MemOp::Aligned<PAGE_SIZE>(address));
		u8* alignedaddress = MemOp::Align<BLOCK_SIZE>(address);
		u32 page = MemOp::Offset<BLOCK_SIZE>(address) / PAGE_SIZE;

		bitset<16>& pagemap = GetPageMap(alignedaddress);
		pagemap[page] = false;
		//log("(refcount is %d)", pagemap.count());

		if (pagemap.none())
		{
			/* This block is no longer in use, so we can nuke it. */

#if defined VERBOSE
			log("nuking block %08x", alignedaddress);
#endif
			Unmap(alignedaddress, BLOCK_SIZE);
		}
	}

private:
	Block* _blocks[BLOCK_COUNT];
};
static BlockStore blockstore;

void UnmapAll()
{
	blockstore.Reset();
}

struct linux_mmap_arg_struct
{
	u32 addr;
	u32 len;
	u32 prot;
	u32 flags;
	u32 fd;
	u32 offset;
};

u32 do_mmap(u8* addr, u32 len, u32 prot, u32 flags, Ref<FD>& ref, u32 offset)
{
	RAIILock locked;

	if (!MemOp::Aligned<PAGE_SIZE>(addr))
		throw EINVAL;
	if (!MemOp::Aligned<PAGE_SIZE>(offset))
		throw EINVAL;

	if (prot & LINUX_PROT_SEM)
	{
		log("mmap(): no support for PROT_SEM, ignoring");
	}

	bool w = prot & LINUX_PROT_WRITE;
	bool x = prot & LINUX_PROT_EXEC;
	bool shared = flags & LINUX_MAP_SHARED;

	if (!(flags & LINUX_MAP_FIXED))
	{
		/* This is a very nasty hack to find an unused memory area to
		 * map the block into. Rather than keep our own range allocator,
		 * we abuse Interix'. This also has the advantage that we
		 * interoperate nicely with Interix' mappings.
		 */

		void* result = mmap(addr, len,
				PROT_READ | PROT_WRITE | PROT_EXEC,
				MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
				-1, 0);
		if (result == MAP_FAILED)
			throw ENOMEM;

#if defined VERBOSE
		log("nonfixed map going to %08x+%08x (app preferred %08x)", result, len, addr);
#endif
		addr = (u8*) result;
		int i = munmap(result, len);
		assert(i == 0);
	}

	if (flags & LINUX_MAP_ANONYMOUS)
	{
#if defined VERBOSE
		log("anonymous");
#endif
		/* Anonymous areas are all fragmented. */

		for (u32 i = 0; i < len; i += PAGE_SIZE)
		{
			blockstore.UsePage(addr + i);
			memset(addr + i, 0, PAGE_SIZE);
		}
	}
	else
	{
#if defined VERBOSE
		log("not anonymous");
#endif
		int realfd = ref->GetRealFD();

		/* If the offset and the address are 64kB-aligned, we can do a proper
		 * mmap(), which we prefer. Otherwise we have to create fragmented
		 * blocks and load the data into RAM (ick, phht).
		 */

		u8* loadaddr = addr;
		if (MemOp::Aligned<BLOCK_SIZE>(addr) && MemOp::Aligned<BLOCK_SIZE>(offset))
		{
#if defined VERBOSE
			log("aligned!");
#endif
			/* ...although remember we can only mmap() whole blocks. */

			u32 alignedlen = MemOp::Align<BLOCK_SIZE>(len);

			//w = true; // FIXME: all memory is writeable as we may have to patch it.
			blockstore.Map(addr, alignedlen, realfd, offset, shared, w, x);

			/* The rest gets loaded into a fragmented block. */

			len -= alignedlen;
			loadaddr += alignedlen;
			offset += alignedlen;
		}

#if defined VERBOSE
		log("loading %08x+%08x @%08x", loadaddr, len, offset);
#endif
		for (u32 i = 0; i < len; i += PAGE_SIZE)
		{
			blockstore.UsePage(loadaddr + i);

			int r = pread(realfd, loadaddr+i, PAGE_SIZE, offset+i);
			if (r == -1)
				throw errno;
		}
	}

	return (u32) addr;
}

u32 do_mmap(u8* addr, u32 len, u32 prot, u32 flags, u32 fd, u32 offset)
{
	Ref<FD> ref;
	if (!(flags & LINUX_MAP_ANONYMOUS))
		ref = FD::Get(fd);
	return do_mmap(addr, len, prot, flags, ref, offset);
}

void do_munmap(u8* addr, u32 len)
{
	if (MemOp::Aligned<BLOCK_SIZE>(addr))
	{
#if defined VERBOSE
		log("unmapping aligned area %08x+%08x", addr, len);
#endif

		u32 alignedlen = MemOp::Align<BLOCK_SIZE>(len);

		blockstore.Unmap(addr, alignedlen);
		addr += alignedlen;
		len -= alignedlen;
	}

	for (u32 i = 0; i < len; i += PAGE_SIZE)
	{
#if defined VERBOSE
		log("unref %08x", addr + i);
#endif
		blockstore.UnusePage(addr + i);
	}
}

SYSCALL(sys32_mmap)
{
	struct linux_mmap_arg_struct& ma = *(struct linux_mmap_arg_struct*) arg.a0.p;
	return do_mmap((u8*) ma.addr, ma.len, ma.prot, ma.flags, ma.fd, ma.offset);
}

SYSCALL(sys32_mmap2)
{
	u_int32_t addr = arg.a0.u;
	u_int32_t len = arg.a1.u;
	u_int32_t prot = arg.a2.u;
	u_int32_t flags = arg.a3.u;
	int32_t fd = arg.a4.s;
	u_int32_t pgoff = arg.a5.u;

	return do_mmap((u8*) addr, len, prot, flags, fd, pgoff * 4096);
}

SYSCALL(sys_unmap)
{
	void* addr = arg.a0.p;
	size_t len = arg.a1.u;

	do_munmap((u8*) addr, len);
	return 0;
}

SYSCALL(sys32_mprotect)
{
	u_int32_t addr = arg.a0.u;
	u_int32_t len = arg.a1.u;
	u_int32_t prot = arg.a2.u;

	//int iprot = convert_prot_l2i(prot);
	//int result = mprotect((void*) addr, len, iprot);
	log("mprotect(%08x, %08x, %08x)", addr, len, prot);
	//return SysError(result);
	return 0;
}
<|endoftext|>


<commit_before>#include <math.h>

#include "YRTGroup.h"
#include "YRTScene.h"
#include "YRTSphere.h"
#include "YRTTriangle.h"
#include "YRTUtils.h"

#pragma hdrstop

TYRTScene::~TYRTScene(void)
{
    delete _shape;
}

TYRTShape* TYRTScene::GenerateExample_01Triangles(int width, int height)
{
    TYRTGroup *result = new TYRTGroup;
    TYRTTriangle *triangle;

    float y = width / 12;
    float z = width / 6;

    // Plane:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(0, y, z);
    triangle->Points[1] = TYRTVector(width, y, z);
    triangle->Points[2] = TYRTVector(0, y, z + width);
    triangle->Color = (TColor)RGB(0, 0, 255);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(width, y, z + width);
    triangle->Points[1] = TYRTVector(width, y, z);
    triangle->Points[2] = TYRTVector(0, y, z + width);
    triangle->Color = (TColor)RGB(255, 0, 0);
    result->Add(triangle);

    // Crown:
    const int count = 12;
    for (int i = 0; i < count; i++)
    {
        float h = 100 + (rand() * 1.0 / RAND_MAX) * height * 2 / 3;
        float r = width / 3;

        triangle = new TYRTTriangle;

        triangle->Points[0].X = width / 2 + r * sin(i * 2 * PI / count + PI / count / 4);
        triangle->Points[0].Y = y + 0;
        triangle->Points[0].Z = z + width / 2 + r * cos(i * 2 * PI / count + PI / count / 4);

        triangle->Points[1].X = width / 2 + r * sin((i + 1) * 2 * PI / count - PI / count / 4);
        triangle->Points[1].Y = y + 0;
        triangle->Points[1].Z = z + width / 2 + r * cos((i + 1) * 2 * PI / count - PI / count / 4);

        triangle->Points[2].X = width / 2 + (r + h / 8) * sin(i * 2 * PI / count + PI / count);
        triangle->Points[2].Y = y + h;
        triangle->Points[2].Z = z + width / 2 + (r + h / 8) * cos(i * 2 * PI / count + PI / count);

        triangle->Color = (TColor)RGB(0, i * 255 / count, 0);

        result->Add(triangle);
    }

    return result;
}

TYRTShape* TYRTScene::GenerateExample_02Atom(int width, int height)
{
    TYRTGroup *result = new TYRTGroup;
    TYRTSphere *sphere;

    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(0, 0, 0);
    sphere->Radius = 10;
    sphere->Color = clBlue;
    result->Add(sphere);

    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(-5, -5, -3);
    sphere->Radius = 6;
    sphere->Color = clRed;
    result->Add(sphere);

    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(+5, -5, +3);
    sphere->Radius = 6;
    sphere->Color = clRed;
    result->Add(sphere);

    // Zoom/move elements into view:
    result->Zoom(10);
    result->Move(width / 2, height / 2, 0);

    return result;
}

TYRTShape* TYRTScene::GenerateExample_03StarShip(float x, float y, float z)
{
    TYRTGroup *result = new TYRTGroup;
    TYRTTriangle *triangle;
    TYRTSphere *sphere;

    // Bottom:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 0, -1,   0);
    triangle->Points[1] = TYRTVector(-3,  0,  -1);
    triangle->Points[2] = TYRTVector( 0,  0, -10);
    triangle->Color = (TColor)RGB(190, 190, 190);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(0, -1,   0);
    triangle->Points[1] = TYRTVector(3,  0,  -1);
    triangle->Points[2] = TYRTVector(0,  0, -10);
    triangle->Color = (TColor)RGB(190, 190, 190);
    result->Add(triangle);
    // Top:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 0, 1,   0);
    triangle->Points[1] = TYRTVector(-3, 0,  -1);
    triangle->Points[2] = TYRTVector( 0, 0, -10);
    triangle->Color = (TColor)RGB(190, 190, 190);
    triangle->Move(0, 0.1, 0);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(0, 1,   0);
    triangle->Points[1] = TYRTVector(3, 0,  -1);
    triangle->Points[2] = TYRTVector(0, 0, -10);
    triangle->Color = (TColor)RGB(190, 190, 190);
    triangle->Move(0, 0.1, 0);
    result->Add(triangle);
    // Sides:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(-3.0 + 1.0/6, 0.0 - 1.0/18, -1.0);
    triangle->Points[1] = TYRTVector(-3.0 + 1.0/6, 0.1 + 1.0/18, -1.0);
    triangle->Points[2] = TYRTVector(           0,            0, -9.5);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(-3.0 + 1.0/6, 0.1 + 1.0/18, -1.0);
    triangle->Points[1] = TYRTVector(           0,          0.1, -9.5);
    triangle->Points[2] = TYRTVector(           0,          0.0, -9.5);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 3.0 - 1.0/6, 0.0 - 1.0/18, -1.0);
    triangle->Points[1] = TYRTVector( 3.0 - 1.0/6, 0.1 + 1.0/18, -1.0);
    triangle->Points[2] = TYRTVector(           0,            0, -9.5);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 3.0 - 1.0/6, 0.1 + 1.0/18, -1.0);
    triangle->Points[1] = TYRTVector(           0,          0.1, -9.5);
    triangle->Points[2] = TYRTVector(           0,          0.0, -9.5);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    // Bridge:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(-1.0, 0.0, -1.0);
    triangle->Points[1] = TYRTVector(-0.5, 1.5, -1.0);
    triangle->Points[2] = TYRTVector( 0.5, 1.5, -1.0);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 1.0, 0.0, -1.0);
    triangle->Points[1] = TYRTVector(-1.0, 0.0, -1.0);
    triangle->Points[2] = TYRTVector( 0.5, 1.5, -1.0);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    // Bottom generator:
    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(0, -0.45, -2.5);
    sphere->Radius = 0.5;
    sphere->Color = (TColor)RGB(212, 212, 212);
    result->Add(sphere);
    // Top generators:
    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(-0.5 + 0.1, 1.6, -1.0);
    sphere->Radius = 0.1;
    sphere->Color = (TColor)RGB(190, 190, 190);
    result->Add(sphere);
    sphere = new TYRTSphere;
    sphere->Center = TYRTVector( 0.5 - 0.1, 1.6, -1.0);
    sphere->Radius = 0.1;
    sphere->Color = (TColor)RGB(190, 190, 190);
    result->Add(sphere);

    result->Move(x, y, z);

    return result;
}

TYRTShape* TYRTScene::GenerateExample_03StarShips(int width, int height)
{
    TYRTGroup *result = new TYRTGroup;

    result->Add(GenerateExample_03StarShip(0, 0, 0));
    result->Add(GenerateExample_03StarShip(10, 4, 1));
    result->Add(GenerateExample_03StarShip(-1, 6, 14));

    result->Zoom(30);
    result->Move(170, 150, 100);

    return result;
}

TStrings* TYRTScene::GenerateExamples(int width, int height)
{
    TStringList* result = new TStringList;

    result->AddObject("Triangles", GenerateExample_01Triangles(width, height));
    result->AddObject("Atom", GenerateExample_02Atom(width, height));
    result->AddObject("Star ships", GenerateExample_03StarShips(width, height));

    return result;
}

void TYRTScene::GetIntersection(TYRTRay *ray, TColor &color)
{
    TYRTVector point;
    _shape->GetIntersection(ray, point, color);
}

void TYRTScene::RunPrecalculations(void)
{
    _shape->RunPrecalculations();
}

void TYRTScene::SetShape(TYRTShape *shape)
{
    _shape = shape;
}
<commit_msg>Spelling fixes in method names<commit_after>#include <math.h>

#include "YRTGroup.h"
#include "YRTScene.h"
#include "YRTSphere.h"
#include "YRTTriangle.h"
#include "YRTUtils.h"

#pragma hdrstop

TYRTScene::~TYRTScene(void)
{
    delete _shape;
}

TYRTShape* TYRTScene::GenerateExample_01Triangles(int width, int height)
{
    TYRTGroup *result = new TYRTGroup;
    TYRTTriangle *triangle;

    float y = width / 12;
    float z = width / 6;

    // Plane:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(0, y, z);
    triangle->Points[1] = TYRTVector(width, y, z);
    triangle->Points[2] = TYRTVector(0, y, z + width);
    triangle->Color = (TColor)RGB(0, 0, 255);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(width, y, z + width);
    triangle->Points[1] = TYRTVector(width, y, z);
    triangle->Points[2] = TYRTVector(0, y, z + width);
    triangle->Color = (TColor)RGB(255, 0, 0);
    result->Add(triangle);

    // Crown:
    const int count = 12;
    for (int i = 0; i < count; i++)
    {
        float h = 100 + (rand() * 1.0 / RAND_MAX) * height * 2 / 3;
        float r = width / 3;

        triangle = new TYRTTriangle;

        triangle->Points[0].X = width / 2 + r * sin(i * 2 * PI / count + PI / count / 4);
        triangle->Points[0].Y = y + 0;
        triangle->Points[0].Z = z + width / 2 + r * cos(i * 2 * PI / count + PI / count / 4);

        triangle->Points[1].X = width / 2 + r * sin((i + 1) * 2 * PI / count - PI / count / 4);
        triangle->Points[1].Y = y + 0;
        triangle->Points[1].Z = z + width / 2 + r * cos((i + 1) * 2 * PI / count - PI / count / 4);

        triangle->Points[2].X = width / 2 + (r + h / 8) * sin(i * 2 * PI / count + PI / count);
        triangle->Points[2].Y = y + h;
        triangle->Points[2].Z = z + width / 2 + (r + h / 8) * cos(i * 2 * PI / count + PI / count);

        triangle->Color = (TColor)RGB(0, i * 255 / count, 0);

        result->Add(triangle);
    }

    return result;
}

TYRTShape* TYRTScene::GenerateExample_02Atom(int width, int height)
{
    TYRTGroup *result = new TYRTGroup;
    TYRTSphere *sphere;

    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(0, 0, 0);
    sphere->Radius = 10;
    sphere->Color = clBlue;
    result->Add(sphere);

    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(-5, -5, -3);
    sphere->Radius = 6;
    sphere->Color = clRed;
    result->Add(sphere);

    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(+5, -5, +3);
    sphere->Radius = 6;
    sphere->Color = clRed;
    result->Add(sphere);

    // Zoom/move elements into view:
    result->Zoom(10);
    result->Move(width / 2, height / 2, 0);

    return result;
}

TYRTShape* TYRTScene::GenerateExample_03Starship(float x, float y, float z)
{
    TYRTGroup *result = new TYRTGroup;
    TYRTTriangle *triangle;
    TYRTSphere *sphere;

    // Bottom:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 0, -1,   0);
    triangle->Points[1] = TYRTVector(-3,  0,  -1);
    triangle->Points[2] = TYRTVector( 0,  0, -10);
    triangle->Color = (TColor)RGB(190, 190, 190);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(0, -1,   0);
    triangle->Points[1] = TYRTVector(3,  0,  -1);
    triangle->Points[2] = TYRTVector(0,  0, -10);
    triangle->Color = (TColor)RGB(190, 190, 190);
    result->Add(triangle);
    // Top:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 0, 1,   0);
    triangle->Points[1] = TYRTVector(-3, 0,  -1);
    triangle->Points[2] = TYRTVector( 0, 0, -10);
    triangle->Color = (TColor)RGB(190, 190, 190);
    triangle->Move(0, 0.1, 0);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(0, 1,   0);
    triangle->Points[1] = TYRTVector(3, 0,  -1);
    triangle->Points[2] = TYRTVector(0, 0, -10);
    triangle->Color = (TColor)RGB(190, 190, 190);
    triangle->Move(0, 0.1, 0);
    result->Add(triangle);
    // Sides:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(-3.0 + 1.0/6, 0.0 - 1.0/18, -1.0);
    triangle->Points[1] = TYRTVector(-3.0 + 1.0/6, 0.1 + 1.0/18, -1.0);
    triangle->Points[2] = TYRTVector(           0,            0, -9.5);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(-3.0 + 1.0/6, 0.1 + 1.0/18, -1.0);
    triangle->Points[1] = TYRTVector(           0,          0.1, -9.5);
    triangle->Points[2] = TYRTVector(           0,          0.0, -9.5);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 3.0 - 1.0/6, 0.0 - 1.0/18, -1.0);
    triangle->Points[1] = TYRTVector( 3.0 - 1.0/6, 0.1 + 1.0/18, -1.0);
    triangle->Points[2] = TYRTVector(           0,            0, -9.5);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 3.0 - 1.0/6, 0.1 + 1.0/18, -1.0);
    triangle->Points[1] = TYRTVector(           0,          0.1, -9.5);
    triangle->Points[2] = TYRTVector(           0,          0.0, -9.5);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    // Bridge:
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector(-1.0, 0.0, -1.0);
    triangle->Points[1] = TYRTVector(-0.5, 1.5, -1.0);
    triangle->Points[2] = TYRTVector( 0.5, 1.5, -1.0);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    triangle = new TYRTTriangle;
    triangle->Points[0] = TYRTVector( 1.0, 0.0, -1.0);
    triangle->Points[1] = TYRTVector(-1.0, 0.0, -1.0);
    triangle->Points[2] = TYRTVector( 0.5, 1.5, -1.0);
    triangle->Color = (TColor)RGB(127, 127, 127);
    result->Add(triangle);
    // Bottom generator:
    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(0, -0.45, -2.5);
    sphere->Radius = 0.5;
    sphere->Color = (TColor)RGB(212, 212, 212);
    result->Add(sphere);
    // Top generators:
    sphere = new TYRTSphere;
    sphere->Center = TYRTVector(-0.5 + 0.1, 1.6, -1.0);
    sphere->Radius = 0.1;
    sphere->Color = (TColor)RGB(190, 190, 190);
    result->Add(sphere);
    sphere = new TYRTSphere;
    sphere->Center = TYRTVector( 0.5 - 0.1, 1.6, -1.0);
    sphere->Radius = 0.1;
    sphere->Color = (TColor)RGB(190, 190, 190);
    result->Add(sphere);

    result->Move(x, y, z);

    return result;
}

TYRTShape* TYRTScene::GenerateExample_03Starships(int width, int height)
{
    TYRTGroup *result = new TYRTGroup;

    result->Add(GenerateExample_03Starship(0, 0, 0));
    result->Add(GenerateExample_03Starship(10, 4, 1));
    result->Add(GenerateExample_03Starship(-1, 6, 14));

    result->Zoom(30);
    result->Move(170, 150, 100);

    return result;
}

TStrings* TYRTScene::GenerateExamples(int width, int height)
{
    TStringList* result = new TStringList;

    result->AddObject("Triangles", GenerateExample_01Triangles(width, height));
    result->AddObject("Atom", GenerateExample_02Atom(width, height));
    result->AddObject("Starships", GenerateExample_03Starships(width, height));

    return result;
}

void TYRTScene::GetIntersection(TYRTRay *ray, TColor &color)
{
    TYRTVector point;
    _shape->GetIntersection(ray, point, color);
}

void TYRTScene::RunPrecalculations(void)
{
    _shape->RunPrecalculations();
}

void TYRTScene::SetShape(TYRTShape *shape)
{
    _shape = shape;
}
<|endoftext|>


<commit_before>#pragma once

#include <mutex>
#include <condition_variable>

#include "But/Exception.hpp"
#include "WaitWrapper.hpp"

namespace But
{
namespace Threading
{

/** @brief simple synchronization mechanism - one thread signals others that are waiting for an event to happen.
 */
class Event final
{
public:
  BUT_DEFINE_EXCEPTION(Timeout, Exception, "timeout while waiting for event");

  Event():
    blocked_{true}
  { }

  void set()
  {
    {
      Lock lock{m_};
      blocked_ = false;
    }
    unblocked_.notify_all();
  }

  void clear()
  {
    Lock lock{m_};
    blocked_ = true;
  }

  /** @brief wait for an event. can take 0 or 1 arguments. zero means wait forever. one can be either
   * timeout (ex. std::chrono::seconds) or deadline (ex. std::chrono::steady_clock::timepoint).
   */
  template<typename ...Args>
  void wait(Args&& ...args) const
  {
    Lock lock{m_};
    WaitHelper::wait(unblocked_, lock, [&]{ return not blocked_; }, std::forward<Args>(args)...);
  }

private:
  using Lock = std::unique_lock<std::mutex>;
  using WaitHelper = WaitWrapper<Timeout, std::condition_variable, Lock>;

  bool                            blocked_;
  mutable std::mutex              m_;
  mutable std::condition_variable unblocked_;
};

}
}
<commit_msg>Event now notifies under a lock as well<commit_after>#pragma once

#include <mutex>
#include <condition_variable>

#include "But/Exception.hpp"
#include "WaitWrapper.hpp"

namespace But
{
namespace Threading
{

/** @brief simple synchronization mechanism - one thread signals others that are waiting for an event to happen.
 */
class Event final
{
public:
  BUT_DEFINE_EXCEPTION(Timeout, Exception, "timeout while waiting for event");

  Event():
    blocked_{true}
  { }

  void set()
  {
    Lock lock{m_};
    blocked_ = false;
    unblocked_.notify_all();
  }

  void clear()
  {
    Lock lock{m_};
    blocked_ = true;
  }

  /** @brief wait for an event. can take 0 or 1 arguments. zero means wait forever. one can be either
   * timeout (ex. std::chrono::seconds) or deadline (ex. std::chrono::steady_clock::timepoint).
   */
  template<typename ...Args>
  void wait(Args&& ...args) const
  {
    Lock lock{m_};
    WaitHelper::wait(unblocked_, lock, [&]{ return not blocked_; }, std::forward<Args>(args)...);
  }

private:
  using Lock = std::unique_lock<std::mutex>;
  using WaitHelper = WaitWrapper<Timeout, std::condition_variable, Lock>;

  bool                            blocked_;
  mutable std::mutex              m_;
  mutable std::condition_variable unblocked_;
};

}
}
<|endoftext|>


<commit_before>/*
 *  Copyright (C) 2010 Stephen F. Booth <me@sbooth.org>
 *  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 Stephen F. Booth 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 THE COPYRIGHT
 *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CFOperatorOverloads.h"
#include <iomanip>

#define BUFFER_LENGTH 512

std::ostream& operator<<(std::ostream& out, CFStringRef s)
{
	assert(NULL != s);

	char buf [BUFFER_LENGTH];

	CFIndex totalCharacters = CFStringGetLength(s);
	CFIndex currentCharacter = 0;
	CFIndex charactersConverted = 0;
	CFIndex bytesWritten;

	while(currentCharacter < totalCharacters) {
		charactersConverted = CFStringGetBytes(s, CFRangeMake(currentCharacter, totalCharacters), kCFStringEncodingUTF8, 0, false,
												reinterpret_cast<UInt8 *>(buf), BUFFER_LENGTH, &bytesWritten);
		currentCharacter += charactersConverted;
		out.write(buf, bytesWritten);
	};

	return out;
}

// Most of this is stolen from Apple's CAStreamBasicDescription::Print()
std::ostream& operator<<(std::ostream& out, const AudioStreamBasicDescription& format)
{
	unsigned char formatID [5];
	*(UInt32 *)formatID = OSSwapHostToBigInt32(format.mFormatID);
	formatID[4] = '\0';

	// General description
	out << format.mChannelsPerFrame << " ch, " << format.mSampleRate << " Hz, '" << formatID << "' (0x" << std::hex << std::setw(8) << std::setfill('0') << format.mFormatFlags << std::dec << ") ";

	if(kAudioFormatLinearPCM == format.mFormatID) {
		// Bit depth
		UInt32 fractionalBits = ((0x3f << 7)/*kLinearPCMFormatFlagsSampleFractionMask*/ & format.mFormatFlags) >> 7/*kLinearPCMFormatFlagsSampleFractionShift*/;
		if(0 < fractionalBits)
			out << (format.mBitsPerChannel - fractionalBits) << "." << fractionalBits;
		else
			out << format.mBitsPerChannel;

		out << "-bit";

		// Endianness
		bool isInterleaved = !(kAudioFormatFlagIsNonInterleaved & format.mFormatFlags);
		UInt32 interleavedChannelCount = (isInterleaved ? format.mChannelsPerFrame : 1);
		UInt32 sampleSize = (0 < format.mBytesPerFrame && 0 < interleavedChannelCount ? format.mBytesPerFrame / interleavedChannelCount : 0);
		if(1 < sampleSize)
			out << ((kLinearPCMFormatFlagIsBigEndian & format.mFormatFlags) ? " big-endian" : " little-endian");

		// Sign
		bool isInteger = !(kLinearPCMFormatFlagIsFloat & format.mFormatFlags);
		if(isInteger)
			out << ((kLinearPCMFormatFlagIsSignedInteger & format.mFormatFlags) ? " signed " : " unsigned ");

		// Integer or floating
		out << (isInteger ? "integer" : "float");

		// Packedness
		if(0 < sampleSize && ((sampleSize << 3) != format.mBitsPerChannel))
			out << ((kLinearPCMFormatFlagIsPacked & format.mFormatFlags) ? ", packed in " : ", unpacked in ") << sampleSize << " bytes";

		// Alignment
		if((0 < sampleSize && ((sampleSize << 3) != format.mBitsPerChannel)) || (0 != (format.mBitsPerChannel & 7)))
			out << ((kLinearPCMFormatFlagIsAlignedHigh & format.mFormatFlags) ? " high-aligned" : " low-aligned");

		if(!isInterleaved)
			out << ", deinterleaved";
	}
	else if(kAudioFormatAppleLossless == format.mFormatID) {
		UInt32 sourceBitDepth = 0;
		switch(format.mFormatFlags) {
			case kAppleLosslessFormatFlag_16BitSourceData:		sourceBitDepth = 16;	break;
    		case kAppleLosslessFormatFlag_20BitSourceData:		sourceBitDepth = 20;	break;
    		case kAppleLosslessFormatFlag_24BitSourceData:		sourceBitDepth = 24;	break;
    		case kAppleLosslessFormatFlag_32BitSourceData:		sourceBitDepth = 32;	break;
		}

		if(0 != sourceBitDepth)
			out << "from " << sourceBitDepth << "-bit source, ";
		else
			out << "from UNKNOWN source bit depth, ";

		out << format.mFramesPerPacket << " frames/packet";
	}
	else
		out << format.mBitsPerChannel << " bits/channel, " << format.mBytesPerPacket << " bytes/packet, " << format.mFramesPerPacket << " frames/packet, " << format.mBytesPerFrame << " bytes/frame";

	return out;
}
<commit_msg>Fixed output formatting error<commit_after>/*
 *  Copyright (C) 2010 Stephen F. Booth <me@sbooth.org>
 *  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 Stephen F. Booth 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 THE COPYRIGHT
 *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CFOperatorOverloads.h"
#include <iomanip>

#define BUFFER_LENGTH 512

std::ostream& operator<<(std::ostream& out, CFStringRef s)
{
	assert(NULL != s);

	char buf [BUFFER_LENGTH];

	CFIndex totalCharacters = CFStringGetLength(s);
	CFIndex currentCharacter = 0;
	CFIndex charactersConverted = 0;
	CFIndex bytesWritten;

	while(currentCharacter < totalCharacters) {
		charactersConverted = CFStringGetBytes(s, CFRangeMake(currentCharacter, totalCharacters), kCFStringEncodingUTF8, 0, false,
												reinterpret_cast<UInt8 *>(buf), BUFFER_LENGTH, &bytesWritten);
		currentCharacter += charactersConverted;
		out.write(buf, bytesWritten);
	};

	return out;
}

// Most of this is stolen from Apple's CAStreamBasicDescription::Print()
std::ostream& operator<<(std::ostream& out, const AudioStreamBasicDescription& format)
{
	unsigned char formatID [5];
	*(UInt32 *)formatID = OSSwapHostToBigInt32(format.mFormatID);
	formatID[4] = '\0';

	// General description
	out << format.mChannelsPerFrame << " ch, " << format.mSampleRate << " Hz, '" << formatID << "' (0x" << std::hex << std::setw(8) << std::setfill('0') << format.mFormatFlags << std::dec << ") ";

	if(kAudioFormatLinearPCM == format.mFormatID) {
		// Bit depth
		UInt32 fractionalBits = ((0x3f << 7)/*kLinearPCMFormatFlagsSampleFractionMask*/ & format.mFormatFlags) >> 7/*kLinearPCMFormatFlagsSampleFractionShift*/;
		if(0 < fractionalBits)
			out << (format.mBitsPerChannel - fractionalBits) << "." << fractionalBits;
		else
			out << format.mBitsPerChannel;

		out << "-bit";

		// Endianness
		bool isInterleaved = !(kAudioFormatFlagIsNonInterleaved & format.mFormatFlags);
		UInt32 interleavedChannelCount = (isInterleaved ? format.mChannelsPerFrame : 1);
		UInt32 sampleSize = (0 < format.mBytesPerFrame && 0 < interleavedChannelCount ? format.mBytesPerFrame / interleavedChannelCount : 0);
		if(1 < sampleSize)
			out << ((kLinearPCMFormatFlagIsBigEndian & format.mFormatFlags) ? " big-endian" : " little-endian");

		// Sign
		bool isInteger = !(kLinearPCMFormatFlagIsFloat & format.mFormatFlags);
		if(isInteger)
			out << ((kLinearPCMFormatFlagIsSignedInteger & format.mFormatFlags) ? " signed" : " unsigned");

		// Integer or floating
		out << (isInteger ? " integer" : " float");

		// Packedness
		if(0 < sampleSize && ((sampleSize << 3) != format.mBitsPerChannel))
			out << ((kLinearPCMFormatFlagIsPacked & format.mFormatFlags) ? ", packed in " : ", unpacked in ") << sampleSize << " bytes";

		// Alignment
		if((0 < sampleSize && ((sampleSize << 3) != format.mBitsPerChannel)) || (0 != (format.mBitsPerChannel & 7)))
			out << ((kLinearPCMFormatFlagIsAlignedHigh & format.mFormatFlags) ? " high-aligned" : " low-aligned");

		if(!isInterleaved)
			out << ", deinterleaved";
	}
	else if(kAudioFormatAppleLossless == format.mFormatID) {
		UInt32 sourceBitDepth = 0;
		switch(format.mFormatFlags) {
			case kAppleLosslessFormatFlag_16BitSourceData:		sourceBitDepth = 16;	break;
    		case kAppleLosslessFormatFlag_20BitSourceData:		sourceBitDepth = 20;	break;
    		case kAppleLosslessFormatFlag_24BitSourceData:		sourceBitDepth = 24;	break;
    		case kAppleLosslessFormatFlag_32BitSourceData:		sourceBitDepth = 32;	break;
		}

		if(0 != sourceBitDepth)
			out << "from " << sourceBitDepth << "-bit source, ";
		else
			out << "from UNKNOWN source bit depth, ";

		out << format.mFramesPerPacket << " frames/packet";
	}
	else
		out << format.mBitsPerChannel << " bits/channel, " << format.mBytesPerPacket << " bytes/packet, " << format.mFramesPerPacket << " frames/packet, " << format.mBytesPerFrame << " bytes/frame";

	return out;
}
<|endoftext|>


<commit_before>#include "build.h"

#include <stdio.h>

#include "ninja.h"
#include "subprocess.h"

bool Plan::AddTarget(Node* node, string* err) {
  Edge* edge = node->in_edge_;
  if (!edge) {  // Leaf node.
    if (node->dirty_) {
      *err = "'" + node->file_->path_ + "' missing "
             "and no known rule to make it";
    }
    return false;
  }

  assert(edge);
  if (!node->dirty())
    return false;  // Don't need to do anything.
  if (want_.find(edge) != want_.end())
    return true;  // We've already enqueued it.

  bool awaiting_inputs = false;
  for (vector<Node*>::iterator i = edge->inputs_.begin();
       i != edge->inputs_.end(); ++i) {
    if (AddTarget(*i, err))
      awaiting_inputs = true;
    else if (err && !err->empty())
      return false;
  }

  want_.insert(edge);
  if (!awaiting_inputs)
    ready_.insert(edge);

  return true;
}

Edge* Plan::FindWork() {
  if (ready_.empty())
    return NULL;
  set<Edge*>::iterator i = ready_.begin();
  Edge* edge = *i;
  ready_.erase(i);
  return edge;
}

void Plan::EdgeFinished(Edge* edge) {
  want_.erase(edge);

  // Check off any nodes we were waiting for with this edge.
  for (vector<Node*>::iterator i = edge->outputs_.begin();
       i != edge->outputs_.end(); ++i) {
    NodeFinished(*i);
  }
}

void Plan::NodeFinished(Node* node) {
  // See if we we want any edges from this node.
  for (vector<Edge*>::iterator i = node->out_edges_.begin();
       i != node->out_edges_.end(); ++i) {
    if (want_.find(*i) != want_.end()) {
      // See if the edge is now ready.
      bool ready = true;
      for (vector<Node*>::iterator j = (*i)->inputs_.begin();
           j != (*i)->inputs_.end(); ++j) {
        if ((*j)->dirty()) {
          ready = false;
          break;
        }
      }
      if (ready)
        ready_.insert(*i);
    }
  }
}

void Plan::Dump() {
  printf("pending: %d\n", (int)want_.size());
  for (set<Edge*>::iterator i = want_.begin(); i != want_.end(); ++i) {
    (*i)->Dump();
  }
  printf("ready: %d\n", (int)ready_.size());
}

struct RealCommandRunner : public CommandRunner {
  virtual ~RealCommandRunner() {}
  virtual bool CanRunMore();
  virtual bool StartCommand(Edge* edge);
  virtual void WaitForCommands(string* err);
  virtual Edge* NextFinishedCommand();

  SubprocessSet subprocs_;
  map<Subprocess*, Edge*> subproc_to_edge_;
};

bool RealCommandRunner::CanRunMore() {
  const size_t kConcurrency = 3;  // XXX make configurable etc.
  return subprocs_.running_.size() < kConcurrency;
}

bool RealCommandRunner::StartCommand(Edge* edge) {
  string err;
  string command = edge->EvaluateCommand();
  printf("  %s\n", command.c_str());
  Subprocess* subproc = new Subprocess;
  subproc_to_edge_.insert(make_pair(subproc, edge));
  if (!subproc->Start(command, &err))
    return false;

  subprocs_.Add(subproc);
  return true;
}

void RealCommandRunner::WaitForCommands(string* err) {
  while (subprocs_.finished_.empty()) {
    subprocs_.DoWork(err);  // XXX handle err
  }
}

Edge* RealCommandRunner::NextFinishedCommand() {
  Subprocess* subproc = subprocs_.NextFinished();
  if (!subproc)
    return NULL;

  if (!subproc->stdout_.buf_.empty()) {
    printf("%d> %s\n", subproc->pid_, subproc->stdout_.buf_.c_str());
  }
  if (!subproc->stderr_.buf_.empty()) {
    printf("E%d> %s\n", subproc->pid_, subproc->stderr_.buf_.c_str());
  }

  map<Subprocess*, Edge*>::iterator i = subproc_to_edge_.find(subproc);
  Edge* edge = i->second;
  subproc_to_edge_.erase(i);

  delete subproc;
  // XXX extract exit code, etc.
  return edge;
}

Builder::Builder(State* state)
    : state_(state) {
  disk_interface_ = new RealDiskInterface;
  command_runner_ = new RealCommandRunner;
}

Node* Builder::AddTarget(const string& name, string* err) {
  Node* node = state_->LookupNode(name);
  if (!node) {
    *err = "unknown target: '" + name + "'";
    return NULL;
  }
  node->file_->StatIfNecessary(disk_interface_);
  if (node->in_edge_) {
    if (!node->in_edge_->RecomputeDirty(state_, disk_interface_, err))
      return NULL;
  }
  if (!node->dirty_)
    return NULL;  // Intentionally no error.

  if (!plan_.AddTarget(node, err))
    return NULL;
  return node;
}

bool Builder::Build(string* err) {
  if (!plan_.more_to_do()) {
    *err = "no work to do";
    return true;
  }

  while (plan_.more_to_do()) {
    while (command_runner_->CanRunMore()) {
      Edge* edge = plan_.FindWork();
      if (!edge)
        break;

      if (edge->rule_ == &State::kPhonyRule) {
        FinishEdge(edge);
        continue;
      }

      if (!StartEdge(edge, err))
        return false;
    }

    if (Edge* edge = command_runner_->NextFinishedCommand())
      FinishEdge(edge);
    else
      command_runner_->WaitForCommands(err);
  }

  return true;
}

bool Builder::StartEdge(Edge* edge, string* err) {
  // Create directories necessary for outputs.
  // XXX: this will block; do we care?
  for (vector<Node*>::iterator i = edge->outputs_.begin();
       i != edge->outputs_.end(); ++i) {
    if (!disk_interface_->MakeDirs((*i)->file_->path_))
      return false;
  }

  // Compute command and start it.
  string command = edge->EvaluateCommand();
  if (!command_runner_->StartCommand(edge)) {
    err->assign("command '" + command + "' failed.");
    return false;
  }

  return true;
}

void Builder::FinishEdge(Edge* edge) {
  for (vector<Node*>::iterator i = edge->outputs_.begin();
       i != edge->outputs_.end(); ++i) {
    // XXX check that the output actually changed
    // XXX just notify node and have it propagate?
    (*i)->dirty_ = false;
  }
  plan_.EdgeFinished(edge);
}
<commit_msg>simplify output<commit_after>#include "build.h"

#include <stdio.h>

#include "ninja.h"
#include "subprocess.h"

bool Plan::AddTarget(Node* node, string* err) {
  Edge* edge = node->in_edge_;
  if (!edge) {  // Leaf node.
    if (node->dirty_) {
      *err = "'" + node->file_->path_ + "' missing "
             "and no known rule to make it";
    }
    return false;
  }

  assert(edge);
  if (!node->dirty())
    return false;  // Don't need to do anything.
  if (want_.find(edge) != want_.end())
    return true;  // We've already enqueued it.

  bool awaiting_inputs = false;
  for (vector<Node*>::iterator i = edge->inputs_.begin();
       i != edge->inputs_.end(); ++i) {
    if (AddTarget(*i, err))
      awaiting_inputs = true;
    else if (err && !err->empty())
      return false;
  }

  want_.insert(edge);
  if (!awaiting_inputs)
    ready_.insert(edge);

  return true;
}

Edge* Plan::FindWork() {
  if (ready_.empty())
    return NULL;
  set<Edge*>::iterator i = ready_.begin();
  Edge* edge = *i;
  ready_.erase(i);
  return edge;
}

void Plan::EdgeFinished(Edge* edge) {
  want_.erase(edge);

  // Check off any nodes we were waiting for with this edge.
  for (vector<Node*>::iterator i = edge->outputs_.begin();
       i != edge->outputs_.end(); ++i) {
    NodeFinished(*i);
  }
}

void Plan::NodeFinished(Node* node) {
  // See if we we want any edges from this node.
  for (vector<Edge*>::iterator i = node->out_edges_.begin();
       i != node->out_edges_.end(); ++i) {
    if (want_.find(*i) != want_.end()) {
      // See if the edge is now ready.
      bool ready = true;
      for (vector<Node*>::iterator j = (*i)->inputs_.begin();
           j != (*i)->inputs_.end(); ++j) {
        if ((*j)->dirty()) {
          ready = false;
          break;
        }
      }
      if (ready)
        ready_.insert(*i);
    }
  }
}

void Plan::Dump() {
  printf("pending: %d\n", (int)want_.size());
  for (set<Edge*>::iterator i = want_.begin(); i != want_.end(); ++i) {
    (*i)->Dump();
  }
  printf("ready: %d\n", (int)ready_.size());
}

struct RealCommandRunner : public CommandRunner {
  virtual ~RealCommandRunner() {}
  virtual bool CanRunMore();
  virtual bool StartCommand(Edge* edge);
  virtual void WaitForCommands(string* err);
  virtual Edge* NextFinishedCommand();

  SubprocessSet subprocs_;
  map<Subprocess*, Edge*> subproc_to_edge_;
};

bool RealCommandRunner::CanRunMore() {
  const size_t kConcurrency = 3;  // XXX make configurable etc.
  return subprocs_.running_.size() < kConcurrency;
}

bool RealCommandRunner::StartCommand(Edge* edge) {
  string err;
  string command = edge->EvaluateCommand();
  printf("  %s\n", command.c_str());
  Subprocess* subproc = new Subprocess;
  subproc_to_edge_.insert(make_pair(subproc, edge));
  if (!subproc->Start(command, &err))
    return false;

  subprocs_.Add(subproc);
  return true;
}

void RealCommandRunner::WaitForCommands(string* err) {
  while (subprocs_.finished_.empty()) {
    subprocs_.DoWork(err);  // XXX handle err
  }
}

Edge* RealCommandRunner::NextFinishedCommand() {
  Subprocess* subproc = subprocs_.NextFinished();
  if (!subproc)
    return NULL;

  if (!subproc->stdout_.buf_.empty())
    printf("%s\n", subproc->stdout_.buf_.c_str());
  if (!subproc->stderr_.buf_.empty())
    printf("%s\n", subproc->stderr_.buf_.c_str());

  map<Subprocess*, Edge*>::iterator i = subproc_to_edge_.find(subproc);
  Edge* edge = i->second;
  subproc_to_edge_.erase(i);

  delete subproc;
  // XXX extract exit code, etc.
  return edge;
}

Builder::Builder(State* state)
    : state_(state) {
  disk_interface_ = new RealDiskInterface;
  command_runner_ = new RealCommandRunner;
}

Node* Builder::AddTarget(const string& name, string* err) {
  Node* node = state_->LookupNode(name);
  if (!node) {
    *err = "unknown target: '" + name + "'";
    return NULL;
  }
  node->file_->StatIfNecessary(disk_interface_);
  if (node->in_edge_) {
    if (!node->in_edge_->RecomputeDirty(state_, disk_interface_, err))
      return NULL;
  }
  if (!node->dirty_)
    return NULL;  // Intentionally no error.

  if (!plan_.AddTarget(node, err))
    return NULL;
  return node;
}

bool Builder::Build(string* err) {
  if (!plan_.more_to_do()) {
    *err = "no work to do";
    return true;
  }

  while (plan_.more_to_do()) {
    while (command_runner_->CanRunMore()) {
      Edge* edge = plan_.FindWork();
      if (!edge)
        break;

      if (edge->rule_ == &State::kPhonyRule) {
        FinishEdge(edge);
        continue;
      }

      if (!StartEdge(edge, err))
        return false;
    }

    if (Edge* edge = command_runner_->NextFinishedCommand())
      FinishEdge(edge);
    else
      command_runner_->WaitForCommands(err);
  }

  return true;
}

bool Builder::StartEdge(Edge* edge, string* err) {
  // Create directories necessary for outputs.
  // XXX: this will block; do we care?
  for (vector<Node*>::iterator i = edge->outputs_.begin();
       i != edge->outputs_.end(); ++i) {
    if (!disk_interface_->MakeDirs((*i)->file_->path_))
      return false;
  }

  // Compute command and start it.
  string command = edge->EvaluateCommand();
  if (!command_runner_->StartCommand(edge)) {
    err->assign("command '" + command + "' failed.");
    return false;
  }

  return true;
}

void Builder::FinishEdge(Edge* edge) {
  for (vector<Node*>::iterator i = edge->outputs_.begin();
       i != edge->outputs_.end(); ++i) {
    // XXX check that the output actually changed
    // XXX just notify node and have it propagate?
    (*i)->dirty_ = false;
  }
  plan_.EdgeFinished(edge);
}
<|endoftext|>