<commit_before>/*
Copyright (c) 2015-2018 Alternative Games Ltd / Turo Lamminen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <cstring>
#include <cassert>

#include <sys/stat.h>

#include "Utils.h"

#include <SDL.h>

struct FILEDeleter {
	void operator()(FILE *f) { fclose(f); }
};

static FILE *logFile;

void logInit() {
	assert(!logFile);

	char *logFilePath = SDL_GetPrefPath("", "SMAADemo");
	std::string logFileName(logFilePath);
	SDL_free(logFilePath);
	logFileName += "logfile.txt";
	logFile = fopen(logFileName.c_str(), "wb");
}

void logWrite(const char* message, ...) {
	va_list argp;
	va_start(argp, message);

	if (logFile) {
		vfprintf(logFile, message, argp);
	} else {
		// Write to console if opening log file failed
		vprintf(message, argp);
	}

	va_end(argp);
}

void logShutdown() {
	assert(logFile);

	fflush(logFile);
	fclose(logFile);
	logFile = nullptr;
}

void logFlush() {
	assert(logFile);

	fflush(logFile);
}

std::vector<char> readTextFile(std::string filename) {
	std::unique_ptr<FILE, FILEDeleter> file(fopen(filename.c_str(), "rb"));

	if (!file) {
		// TODO: better exception
		throw std::runtime_error("file not found " + filename);
	}

	int fd = fileno(file.get());
	if (fd < 0) {
		// TODO: better exception
		throw std::runtime_error("no fd");
	}

	struct stat statbuf;
	memset(&statbuf, 0, sizeof(struct stat));
	int retval = fstat(fd, &statbuf);
	if (retval < 0) {
		// TODO: better exception
		throw std::runtime_error("fstat failed");
	}

	unsigned int filesize = static_cast<unsigned int>(statbuf.st_size);
	// ensure NUL -termination
	std::vector<char> buf(filesize + 1, '\0');

	size_t ret = fread(&buf[0], 1, filesize, file.get());
	if (ret != filesize)
	{
		// TODO: better exception
		throw std::runtime_error("fread failed");
	}

	return buf;
}

std::vector<char> readFile(std::string filename) {
	std::unique_ptr<FILE, FILEDeleter> file(fopen(filename.c_str(), "rb"));

	if (!file) {
		// TODO: better exception
		throw std::runtime_error("file not found " + filename);
	}

	int fd = fileno(file.get());
	if (fd < 0) {
		// TODO: better exception
		throw std::runtime_error("no fd");
	}

	struct stat statbuf;
	memset(&statbuf, 0, sizeof(struct stat));
	int retval = fstat(fd, &statbuf);
	if (retval < 0) {
		// TODO: better exception
		throw std::runtime_error("fstat failed");
	}

	unsigned int filesize = static_cast<unsigned int>(statbuf.st_size);
	std::vector<char> buf(filesize, '\0');

	size_t ret = fread(&buf[0], 1, filesize, file.get());
	if (ret != filesize)
	{
		// TODO: better exception
		throw std::runtime_error("fread failed");
	}

	return buf;
}

void writeFile(const std::string &filename, const void *contents, size_t size) {
	std::unique_ptr<FILE, FILEDeleter> file(fopen(filename.c_str(), "wb"));

	fwrite(contents, 1, size, file.get());
}

bool fileExists(const std::string &filename) {
	std::unique_ptr<FILE, FILEDeleter> file(fopen(filename.c_str(), "rb"));

	if (file) {
		return true;
	} else {
		return false;
	}
}

int64_t getFileTimestamp(const std::string &filename) {
	struct stat statbuf;
	memset(&statbuf, 0, sizeof(struct stat));
	int retval = stat(filename.c_str(), &statbuf);
	if (retval < 0) {
		// TODO: better exception
		throw std::runtime_error("fstat failed");
	}
	return statbuf.st_mtime;
}
<commit_msg>Add missing include<commit_after>/*
Copyright (c) 2015-2018 Alternative Games Ltd / Turo Lamminen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <cstring>
#include <cassert>

#include <sys/stat.h>

#include <stdexcept>

#include "Utils.h"

#include <SDL.h>

struct FILEDeleter {
	void operator()(FILE *f) { fclose(f); }
};

static FILE *logFile;

void logInit() {
	assert(!logFile);

	char *logFilePath = SDL_GetPrefPath("", "SMAADemo");
	std::string logFileName(logFilePath);
	SDL_free(logFilePath);
	logFileName += "logfile.txt";
	logFile = fopen(logFileName.c_str(), "wb");
}

void logWrite(const char* message, ...) {
	va_list argp;
	va_start(argp, message);

	if (logFile) {
		vfprintf(logFile, message, argp);
	} else {
		// Write to console if opening log file failed
		vprintf(message, argp);
	}

	va_end(argp);
}

void logShutdown() {
	assert(logFile);

	fflush(logFile);
	fclose(logFile);
	logFile = nullptr;
}

void logFlush() {
	assert(logFile);

	fflush(logFile);
}

std::vector<char> readTextFile(std::string filename) {
	std::unique_ptr<FILE, FILEDeleter> file(fopen(filename.c_str(), "rb"));

	if (!file) {
		// TODO: better exception
		throw std::runtime_error("file not found " + filename);
	}

	int fd = fileno(file.get());
	if (fd < 0) {
		// TODO: better exception
		throw std::runtime_error("no fd");
	}

	struct stat statbuf;
	memset(&statbuf, 0, sizeof(struct stat));
	int retval = fstat(fd, &statbuf);
	if (retval < 0) {
		// TODO: better exception
		throw std::runtime_error("fstat failed");
	}

	unsigned int filesize = static_cast<unsigned int>(statbuf.st_size);
	// ensure NUL -termination
	std::vector<char> buf(filesize + 1, '\0');

	size_t ret = fread(&buf[0], 1, filesize, file.get());
	if (ret != filesize)
	{
		// TODO: better exception
		throw std::runtime_error("fread failed");
	}

	return buf;
}

std::vector<char> readFile(std::string filename) {
	std::unique_ptr<FILE, FILEDeleter> file(fopen(filename.c_str(), "rb"));

	if (!file) {
		// TODO: better exception
		throw std::runtime_error("file not found " + filename);
	}

	int fd = fileno(file.get());
	if (fd < 0) {
		// TODO: better exception
		throw std::runtime_error("no fd");
	}

	struct stat statbuf;
	memset(&statbuf, 0, sizeof(struct stat));
	int retval = fstat(fd, &statbuf);
	if (retval < 0) {
		// TODO: better exception
		throw std::runtime_error("fstat failed");
	}

	unsigned int filesize = static_cast<unsigned int>(statbuf.st_size);
	std::vector<char> buf(filesize, '\0');

	size_t ret = fread(&buf[0], 1, filesize, file.get());
	if (ret != filesize)
	{
		// TODO: better exception
		throw std::runtime_error("fread failed");
	}

	return buf;
}

void writeFile(const std::string &filename, const void *contents, size_t size) {
	std::unique_ptr<FILE, FILEDeleter> file(fopen(filename.c_str(), "wb"));

	fwrite(contents, 1, size, file.get());
}

bool fileExists(const std::string &filename) {
	std::unique_ptr<FILE, FILEDeleter> file(fopen(filename.c_str(), "rb"));

	if (file) {
		return true;
	} else {
		return false;
	}
}

int64_t getFileTimestamp(const std::string &filename) {
	struct stat statbuf;
	memset(&statbuf, 0, sizeof(struct stat));
	int retval = stat(filename.c_str(), &statbuf);
	if (retval < 0) {
		// TODO: better exception
		throw std::runtime_error("fstat failed");
	}
	return statbuf.st_mtime;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2019 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <seastar/core/shared_ptr.hh>
#include <seastar/core/file.hh>
#include "seastarx.hh"

#include "db/timeout_clock.hh"

struct reader_resources {
    int count = 0;
    ssize_t memory = 0;

    static reader_resources with_memory(ssize_t memory) { return reader_resources(0, memory); }

    reader_resources() = default;

    reader_resources(int count, ssize_t memory)
        : count(count)
        , memory(memory) {
    }

    bool operator>=(const reader_resources& other) const {
        return count >= other.count && memory >= other.memory;
    }

    reader_resources operator-(const reader_resources& other) const {
        return reader_resources{count - other.count, memory - other.memory};
    }

    reader_resources& operator-=(const reader_resources& other) {
        count -= other.count;
        memory -= other.memory;
        return *this;
    }

    reader_resources operator+(const reader_resources& other) const {
        return reader_resources{count + other.count, memory + other.memory};
    }

    reader_resources& operator+=(const reader_resources& other) {
        count += other.count;
        memory += other.memory;
        return *this;
    }

    explicit operator bool() const {
        return count > 0 || memory > 0;
    }
};

class reader_concurrency_semaphore;

/// A permit for a specific read.
///
/// Used to track the read's resource consumption and wait for admission to read
/// from the disk.
/// Use `consume_memory()` to register memory usage. Use `wait_admission()` to
/// wait for admission, before reading from the disk. Both methods return a
/// `resource_units` RAII object that should be held onto while the respective
/// resources are in use.
class reader_permit {
    friend class reader_concurrency_semaphore;

public:
    class resource_units;

private:
    class impl;
    shared_ptr<impl> _impl;

private:
    explicit reader_permit(reader_concurrency_semaphore& semaphore);

    void on_admission();

public:
    ~reader_permit();

    reader_permit(const reader_permit&) = default;
    reader_permit(reader_permit&&) = default;

    reader_permit& operator=(const reader_permit&) = default;
    reader_permit& operator=(reader_permit&&) = default;

    bool operator==(const reader_permit& o) const {
        return _impl == o._impl;
    }

    reader_concurrency_semaphore& semaphore();

    future<resource_units> wait_admission(size_t memory, db::timeout_clock::time_point timeout);

    void consume(reader_resources res);

    void signal(reader_resources res);

    resource_units consume_memory(size_t memory = 0);

    resource_units consume_resources(reader_resources res);
};

class reader_permit::resource_units {
    reader_permit _permit;
    reader_resources _resources;

    friend class reader_permit;
    friend class reader_concurrency_semaphore;
private:
    resource_units(reader_permit permit, reader_resources res) noexcept;
public:
    resource_units(const resource_units&) = delete;
    resource_units(resource_units&&) noexcept;
    ~resource_units();
    resource_units& operator=(const resource_units&) = delete;
    resource_units& operator=(resource_units&&) noexcept;
    void add(resource_units&& o);
    void reset(reader_resources res = {});
};

template <typename Char>
temporary_buffer<Char> make_tracked_temporary_buffer(temporary_buffer<Char> buf, reader_permit& permit) {
    return temporary_buffer<Char>(buf.get_write(), buf.size(),
            make_deleter(buf.release(), [units = permit.consume_memory(buf.size())] () mutable { units.reset(); }));
}

file make_tracked_file(file f, reader_permit p);
<commit_msg>reader_permit: introduce tracking_allocator<commit_after>/*
 * Copyright (C) 2019 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <seastar/core/shared_ptr.hh>
#include <seastar/core/file.hh>
#include "seastarx.hh"

#include "db/timeout_clock.hh"

struct reader_resources {
    int count = 0;
    ssize_t memory = 0;

    static reader_resources with_memory(ssize_t memory) { return reader_resources(0, memory); }

    reader_resources() = default;

    reader_resources(int count, ssize_t memory)
        : count(count)
        , memory(memory) {
    }

    bool operator>=(const reader_resources& other) const {
        return count >= other.count && memory >= other.memory;
    }

    reader_resources operator-(const reader_resources& other) const {
        return reader_resources{count - other.count, memory - other.memory};
    }

    reader_resources& operator-=(const reader_resources& other) {
        count -= other.count;
        memory -= other.memory;
        return *this;
    }

    reader_resources operator+(const reader_resources& other) const {
        return reader_resources{count + other.count, memory + other.memory};
    }

    reader_resources& operator+=(const reader_resources& other) {
        count += other.count;
        memory += other.memory;
        return *this;
    }

    explicit operator bool() const {
        return count > 0 || memory > 0;
    }
};

class reader_concurrency_semaphore;

/// A permit for a specific read.
///
/// Used to track the read's resource consumption and wait for admission to read
/// from the disk.
/// Use `consume_memory()` to register memory usage. Use `wait_admission()` to
/// wait for admission, before reading from the disk. Both methods return a
/// `resource_units` RAII object that should be held onto while the respective
/// resources are in use.
class reader_permit {
    friend class reader_concurrency_semaphore;

public:
    class resource_units;

private:
    class impl;
    shared_ptr<impl> _impl;

private:
    explicit reader_permit(reader_concurrency_semaphore& semaphore);

    void on_admission();

public:
    ~reader_permit();

    reader_permit(const reader_permit&) = default;
    reader_permit(reader_permit&&) = default;

    reader_permit& operator=(const reader_permit&) = default;
    reader_permit& operator=(reader_permit&&) = default;

    bool operator==(const reader_permit& o) const {
        return _impl == o._impl;
    }

    reader_concurrency_semaphore& semaphore();

    future<resource_units> wait_admission(size_t memory, db::timeout_clock::time_point timeout);

    void consume(reader_resources res);

    void signal(reader_resources res);

    resource_units consume_memory(size_t memory = 0);

    resource_units consume_resources(reader_resources res);
};

class reader_permit::resource_units {
    reader_permit _permit;
    reader_resources _resources;

    friend class reader_permit;
    friend class reader_concurrency_semaphore;
private:
    resource_units(reader_permit permit, reader_resources res) noexcept;
public:
    resource_units(const resource_units&) = delete;
    resource_units(resource_units&&) noexcept;
    ~resource_units();
    resource_units& operator=(const resource_units&) = delete;
    resource_units& operator=(resource_units&&) noexcept;
    void add(resource_units&& o);
    void reset(reader_resources res = {});
};

template <typename Char>
temporary_buffer<Char> make_tracked_temporary_buffer(temporary_buffer<Char> buf, reader_permit& permit) {
    return temporary_buffer<Char>(buf.get_write(), buf.size(),
            make_deleter(buf.release(), [units = permit.consume_memory(buf.size())] () mutable { units.reset(); }));
}

file make_tracked_file(file f, reader_permit p);

template <typename T>
class tracking_allocator {
public:
    using value_type = T;
    using propagate_on_container_move_assignment = std::true_type;
    using is_always_equal = std::false_type;

private:
    reader_permit _permit;
    std::allocator<T> _alloc;

public:
    tracking_allocator(reader_permit permit) noexcept : _permit(std::move(permit)) { }

    T* allocate(size_t n) {
        auto p = _alloc.allocate(n);
        _permit.consume(reader_resources::with_memory(n * sizeof(T)));
        return p;
    }
    void deallocate(T* p, size_t n) {
        _alloc.deallocate(p, n);
        if (n) {
            _permit.signal(reader_resources::with_memory(n * sizeof(T)));
        }
    }

    template <typename U>
    friend bool operator==(const tracking_allocator<U>& a, const tracking_allocator<U>& b);
};

template <typename T>
bool operator==(const tracking_allocator<T>& a, const tracking_allocator<T>& b) {
    return a._semaphore == b._semaphore;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 INRA
 * Copyright (C) 2013 ULCO
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. 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.
 *
 * THIS SOFTWARE IS PROVIDED "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 <vle/environment.hpp>
#include <vle/path.hpp>
#include <vle/dbg.hpp>
#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <chrono>
#include "i18n.hpp"
#include "config.h"
#include <ctime>

namespace vle {

struct Environment::Pimpl
{
    Pimpl()
        : verbose_level(0)
    {
    }

    int init(const std::string &filepath)
    {
        char *home = NULL;

        if ((home = ::getenv("VLE_HOME")) == NULL)
            if ((home = ::getenv("HOME")) == NULL)
                if ((home = ::getenv("PWD")) == NULL)
                    home = ::getenv("TMP");

        if (!home)
            return -1;

        std::vector < std::string > lst = { home, ".vle" };
        prefix_path = vle::Path::make_path(lst.begin(), lst.end());

        lst.push_back("pkgs-2.0");
        pkgs_path = vle::Path::make_path(lst.begin(), lst.end());

        if (!vle::Path::exist_directory(prefix_path))
            if (!vle::Path::create_directories(prefix_path))
                return -2;

        if (!vle::Path::exist_directory(pkgs_path))
            if (!vle::Path::create_directories(pkgs_path))
                return -3;

        logfilepath = filepath;
        if (logfilepath.empty())
            logfilepath = vle::Path::make_path({ prefix_path, "vle-2.0.log" });

        logfile.open(logfilepath);
        if (!logfile.is_open())
            return -4;

        return 0;
    }

    ~Pimpl()
    {
    }

    typedef std::recursive_mutex lock_type;
    typedef std::unique_lock <lock_type> scoped_lock_type;

    lock_type mutex;
    std::ofstream logfile;
    std::string logfilepath;
    std::string prefix_path;
    std::string pkgs_path;
    std::string current_package;
    int verbose_level;
#ifndef VLE_NDEBUG_MODE
    std::chrono::time_point <std::chrono::system_clock> start;
    std::chrono::time_point <std::chrono::system_clock> end;
#endif
};

std::tuple <EnvironmentPtr, std::string> Environment::create()
{
    EnvironmentPtr ret = new vle::Environment();
    int state = ret->m->init(std::string());
    std::string msg;

    if (state < 0) {
        switch (state) {
        case -1:
            msg = _("Failed to read VLE_HOME, HOME and TMP environment"
                    " variables");
            break;
        case -2:
            msg = _("Failed to initialize VLE_HOME directory: ")
                + ret->m->prefix_path;
            break;
        case -3:
            msg = _("Failed to initialize packages directory: ")
                + ret->m->pkgs_path;
            break;
        case -4:
            msg = _("Failed to initialize log file: ") + ret->m->logfilepath;
            break;
        }
        ret.reset();
    }
    return std::make_tuple(ret, msg);
}

std::tuple <EnvironmentPtr, std::string> Environment::create(
    const std::string &logfilepath)
{
    EnvironmentPtr ret = new vle::Environment();
    int state = ret->m->init(logfilepath);
    std::string msg;

    if (state < 0) {
        switch (state) {
        case -1:
            msg = _("Failed to read VLE_HOME, HOME and TMP environment"
                    " variables");
            break;
        case -2:
            msg = _("Failed to initialize VLE_HOME directory: ")
                + ret->m->prefix_path;
            break;
        case -3:
            msg = _("Failed to initialize packages directory: ")
                + ret->m->pkgs_path;
            break;
        case -4:
            msg = _("Failed to initialize log file: ") + ret->m->logfilepath;
            break;
        }
        ret.reset();
    }
    return std::make_tuple(ret, msg);
}

Environment::Environment()
    : references(0), m(new Environment::Pimpl())
{
#ifndef VLE_NDEBUG_MODE
    m->start = std::chrono::system_clock::now();
    std::time_t end_time = std::chrono::system_clock::to_time_t(m->start);
    dInfo("Environment is created at time", std::ctime(&end_time));
#endif
}

Environment::~Environment()
{
#ifndef VLE_NDEBUG_MODE
    m->end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = m->end - m->start;
    dInfo("Environment is deleted. Elapsed time: ", elapsed_seconds.count(), "s");
#endif
}

void Environment::print(const std::string& msg)
{
    m->logfile << msg << std::endl;
}

void Environment::warning(const std::string& msg)
{
    m->logfile << _("[Warning] ") << msg << std::endl;
}

void Environment::error(const std::string& msg)
{
    m->logfile << _("[Error] ") << msg << std::endl;
}

void Environment::set_verbose_level(int level)
{
    m->verbose_level = std::min(3, std::max(0, level));
}

int Environment::get_verbose_level() const
{
    return m->verbose_level;
}

void Environment::get_version(int *major, int *minor, int *patch) const
{
    if (*major)
        *major = VERS_MAJ;

    if (*minor)
        *minor= VERS_MIC;

    if (*patch)
        *patch = VERS_MIN;
}

std::string Environment::get_prefix_path() const
{
    return m->prefix_path;
}

bool Environment::set_current_package(const std::string &package)
{
    if (package.empty())
        return false;

    m->current_package = package;

    return true;
}

std::string Environment::get_current_package() const
{
    return m->current_package;
}

std::string Environment::get_current_package_path() const
{
    return Path::make_path({ m->pkgs_path, m->current_package});
}

}
<commit_msg>lib: add string into gettext<commit_after>/*
 * Copyright (C) 2013 INRA
 * Copyright (C) 2013 ULCO
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. 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.
 *
 * THIS SOFTWARE IS PROVIDED "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 <vle/environment.hpp>
#include <vle/path.hpp>
#include <vle/dbg.hpp>
#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <chrono>
#include "i18n.hpp"
#include "config.h"
#include <ctime>

namespace vle {

struct Environment::Pimpl
{
    Pimpl()
        : verbose_level(0)
    {
    }

    int init(const std::string &filepath)
    {
        char *home = NULL;

        if ((home = ::getenv("VLE_HOME")) == NULL)
            if ((home = ::getenv("HOME")) == NULL)
                if ((home = ::getenv("PWD")) == NULL)
                    home = ::getenv("TMP");

        if (!home)
            return -1;

        std::vector < std::string > lst = { home, ".vle" };
        prefix_path = vle::Path::make_path(lst.begin(), lst.end());

        lst.push_back("pkgs-2.0");
        pkgs_path = vle::Path::make_path(lst.begin(), lst.end());

        if (!vle::Path::exist_directory(prefix_path))
            if (!vle::Path::create_directories(prefix_path))
                return -2;

        if (!vle::Path::exist_directory(pkgs_path))
            if (!vle::Path::create_directories(pkgs_path))
                return -3;

        logfilepath = filepath;
        if (logfilepath.empty())
            logfilepath = vle::Path::make_path({ prefix_path, "vle-2.0.log" });

        logfile.open(logfilepath);
        if (!logfile.is_open())
            return -4;

        return 0;
    }

    ~Pimpl()
    {
    }

    typedef std::recursive_mutex lock_type;
    typedef std::unique_lock <lock_type> scoped_lock_type;

    lock_type mutex;
    std::ofstream logfile;
    std::string logfilepath;
    std::string prefix_path;
    std::string pkgs_path;
    std::string current_package;
    int verbose_level;
#ifndef VLE_NDEBUG_MODE
    std::chrono::time_point <std::chrono::system_clock> start;
    std::chrono::time_point <std::chrono::system_clock> end;
#endif
};

std::tuple <EnvironmentPtr, std::string> Environment::create()
{
    EnvironmentPtr ret = new vle::Environment();
    int state = ret->m->init(std::string());
    std::string msg;

    if (state < 0) {
        switch (state) {
        case -1:
            msg = _("Failed to read VLE_HOME, HOME and TMP environment"
                    " variables");
            break;
        case -2:
            msg = _("Failed to initialize VLE_HOME directory: ")
                + ret->m->prefix_path;
            break;
        case -3:
            msg = _("Failed to initialize packages directory: ")
                + ret->m->pkgs_path;
            break;
        case -4:
            msg = _("Failed to initialize log file: ") + ret->m->logfilepath;
            break;
        }
        ret.reset();
    }
    return std::make_tuple(ret, msg);
}

std::tuple <EnvironmentPtr, std::string> Environment::create(
    const std::string &logfilepath)
{
    EnvironmentPtr ret = new vle::Environment();
    int state = ret->m->init(logfilepath);
    std::string msg;

    if (state < 0) {
        switch (state) {
        case -1:
            msg = _("Failed to read VLE_HOME, HOME and TMP environment"
                    " variables");
            break;
        case -2:
            msg = _("Failed to initialize VLE_HOME directory: ")
                + ret->m->prefix_path;
            break;
        case -3:
            msg = _("Failed to initialize packages directory: ")
                + ret->m->pkgs_path;
            break;
        case -4:
            msg = _("Failed to initialize log file: ") + ret->m->logfilepath;
            break;
        }
        ret.reset();
    }
    return std::make_tuple(ret, msg);
}

Environment::Environment()
    : references(0), m(new Environment::Pimpl())
{
#ifndef VLE_NDEBUG_MODE
    m->start = std::chrono::system_clock::now();
    std::time_t end_time = std::chrono::system_clock::to_time_t(m->start);
    dInfo(_("Environment is created at time: "), std::ctime(&end_time));
#endif
}

Environment::~Environment()
{
#ifndef VLE_NDEBUG_MODE
    m->end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = m->end - m->start;
    dInfo(_("Environment is deleted. Elapsed time: "), elapsed_seconds.count(), "s");
#endif
}

void Environment::print(const std::string& msg)
{
    m->logfile << msg << std::endl;
}

void Environment::warning(const std::string& msg)
{
    m->logfile << _("[Warning] ") << msg << std::endl;
}

void Environment::error(const std::string& msg)
{
    m->logfile << _("[Error] ") << msg << std::endl;
}

void Environment::set_verbose_level(int level)
{
    m->verbose_level = std::min(3, std::max(0, level));
}

int Environment::get_verbose_level() const
{
    return m->verbose_level;
}

void Environment::get_version(int *major, int *minor, int *patch) const
{
    if (*major)
        *major = VERS_MAJ;

    if (*minor)
        *minor= VERS_MIC;

    if (*patch)
        *patch = VERS_MIN;
}

std::string Environment::get_prefix_path() const
{
    return m->prefix_path;
}

bool Environment::set_current_package(const std::string &package)
{
    if (package.empty())
        return false;

    m->current_package = package;

    return true;
}

std::string Environment::get_current_package() const
{
    return m->current_package;
}

std::string Environment::get_current_package_path() const
{
    return Path::make_path({ m->pkgs_path, m->current_package});
}

}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
// Copyright  2007, mC2 team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other 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 OWNER 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 "pch.hpp"
#include "core/PlaybackQueue.h"
#include "core/LibraryFactory.h"

#include <boost/algorithm/string.hpp>

using namespace musik::core;

//////////////////////////////////////////////////////////////////////////////

PlaybackQueue PlaybackQueue::sInstance;

//////////////////////////////////////////
///\brief
///Constructor
///
///Will connect the appropiate signals in the transport
//////////////////////////////////////////
PlaybackQueue::PlaybackQueue(void) :
    nowPlaying( new musik::core::tracklist::Standard() ),
    signalDisabled(false),
    playing(false)
{
    this->transport.MixpointReached.connect(this,&PlaybackQueue::OnPlaybackEndOrFail);
//    this->transport.PlaybackStoppedFail.connect(this,&PlaybackQueue::OnPlaybackEndOrFail);
}

//////////////////////////////////////////
///\brief
///Destructor
//////////////////////////////////////////
PlaybackQueue::~PlaybackQueue(void)
{
    this->transport.Stop(0);
}

//////////////////////////////////////////
///\brief
///Private method for the transporters signals
//////////////////////////////////////////
void PlaybackQueue::OnPlaybackEndOrFail(){
    this->playing   = false;
    if(!this->signalDisabled){
        this->Next();
    }
}

//////////////////////////////////////////
///\brief
///Return a shared_ptr to the now playing tracklist
//////////////////////////////////////////
tracklist::Standard::Ptr PlaybackQueue::NowPlayingTracklist(){
    return this->nowPlaying;
}

//////////////////////////////////////////
///\brief
///Start playing the current track.
//////////////////////////////////////////
void PlaybackQueue::Play(){

    TrackPtr track(this->CurrentTrack());

    if(track){
        // If current track exists
        utfstring path(track->GetValue("path"));

        this->Stop();

        this->playing   = true;
        this->transport.Start(path);
    }

}

//////////////////////////////////////////
///\brief
///Start playing the next track.
//////////////////////////////////////////
void PlaybackQueue::Next(){
    musik::core::TrackPtr track( this->nowPlaying->NextTrack() );
    if(track){
        this->SetCurrentTrack(track->Copy());
        this->Play();
    }
}

//////////////////////////////////////////
///\brief
///Start playing the previous track.
//////////////////////////////////////////
void PlaybackQueue::Previous(){
    musik::core::TrackPtr track( this->nowPlaying->PreviousTrack() );
    if(track){
        this->SetCurrentTrack(track->Copy());
        this->Play();
    }
}

//////////////////////////////////////////
///\brief
///Stop playing
//////////////////////////////////////////
void PlaybackQueue::Stop(){
    this->signalDisabled    = true;
    if( this->playing ){
        this->transport.Stop(0);
    }
    this->signalDisabled    = false;
}

//////////////////////////////////////////
///\brief
///Return the current running track
//////////////////////////////////////////
TrackPtr PlaybackQueue::CurrentTrack(){
    if(!this->currentTrack){
        // If the current track is empty, get a track from the nowPlaying tracklist
        this->SetCurrentTrack( this->nowPlaying->CurrentTrack()->Copy() );

    }
    return this->currentTrack;
}

//////////////////////////////////////////
///\brief
///Set the current track
///
///Setting the current track will also query
///for all the tracks metadata
//////////////////////////////////////////
void PlaybackQueue::SetCurrentTrack(TrackPtr track){
    if(this->currentTrack!=track){
        this->currentTrack  = track;

        // Get all metadata to the track
        if(this->currentTrack){
            this->metadataQuery.Clear();
            this->metadataQuery.RequestAllMetakeys();
            this->metadataQuery.RequestTrack(this->currentTrack);
            this->nowPlaying->Library()->AddQuery(this->metadataQuery,musik::core::Query::Wait|musik::core::Query::AutoCallback|musik::core::Query::UnCanceable|musik::core::Query::Prioritize);
        }

        // Call the signal if track updates
        this->CurrentTrackChanged(track);
    }
}

//////////////////////////////////////////
///\brief
///Copy the tracklist to the now playing and start playing it
///
///\param tracklist
///Tracklist that should be copied to now playing
//////////////////////////////////////////
void PlaybackQueue::Play(tracklist::IRandomAccess &tracklist){
    this->currentTrack.reset();
    this->nowPlaying->CopyTracks(tracklist);
    this->Play();
}

short PlaybackQueue::Volume() const{
    return this->transport.Volume();
}

void PlaybackQueue::SetVolume(short volume){
    this->transport.ChangeVolume(volume);
}

<commit_msg>Fixed crash on pressing play button (closes #38)<commit_after>//////////////////////////////////////////////////////////////////////////////
// Copyright  2007, mC2 team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other 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 OWNER 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 "pch.hpp"
#include "core/PlaybackQueue.h"
#include "core/LibraryFactory.h"

#include <boost/algorithm/string.hpp>

using namespace musik::core;

//////////////////////////////////////////////////////////////////////////////

PlaybackQueue PlaybackQueue::sInstance;

//////////////////////////////////////////
///\brief
///Constructor
///
///Will connect the appropiate signals in the transport
//////////////////////////////////////////
PlaybackQueue::PlaybackQueue(void) :
    nowPlaying( new musik::core::tracklist::Standard() ),
    signalDisabled(false),
    playing(false)
{
    this->transport.MixpointReached.connect(this,&PlaybackQueue::OnPlaybackEndOrFail);
//    this->transport.PlaybackStoppedFail.connect(this,&PlaybackQueue::OnPlaybackEndOrFail);
}

//////////////////////////////////////////
///\brief
///Destructor
//////////////////////////////////////////
PlaybackQueue::~PlaybackQueue(void)
{
    this->transport.Stop(0);
}

//////////////////////////////////////////
///\brief
///Private method for the transporters signals
//////////////////////////////////////////
void PlaybackQueue::OnPlaybackEndOrFail(){
    this->playing   = false;
    if(!this->signalDisabled){
        this->Next();
    }
}

//////////////////////////////////////////
///\brief
///Return a shared_ptr to the now playing tracklist
//////////////////////////////////////////
tracklist::Standard::Ptr PlaybackQueue::NowPlayingTracklist(){
    return this->nowPlaying;
}

//////////////////////////////////////////
///\brief
///Start playing the current track.
//////////////////////////////////////////
void PlaybackQueue::Play(){

    TrackPtr track(this->CurrentTrack());

    if(track){
        // If current track exists
        utfstring path(track->GetValue("path"));

        this->Stop();

        this->playing   = true;
        this->transport.Start(path);
    }
}

//////////////////////////////////////////
///\brief
///Start playing the next track.
//////////////////////////////////////////
void PlaybackQueue::Next(){
    musik::core::TrackPtr track( this->nowPlaying->NextTrack() );
    if(track){
        this->SetCurrentTrack(track->Copy());
        this->Play();
    }
}

//////////////////////////////////////////
///\brief
///Start playing the previous track.
//////////////////////////////////////////
void PlaybackQueue::Previous(){
    musik::core::TrackPtr track( this->nowPlaying->PreviousTrack() );
    if(track){
        this->SetCurrentTrack(track->Copy());
        this->Play();
    }
}

//////////////////////////////////////////
///\brief
///Stop playing
//////////////////////////////////////////
void PlaybackQueue::Stop(){
    this->signalDisabled    = true;
    if( this->playing ){
        this->transport.Stop(0);
    }
    this->signalDisabled    = false;
}

//////////////////////////////////////////
///\brief
///Return the current running track
//////////////////////////////////////////
TrackPtr PlaybackQueue::CurrentTrack(){
    if (this->nowPlaying->Size() <= 0)
    {
        return TrackPtr();
    }

    if(!this->currentTrack){
        // If the current track is empty, get a track from the nowPlaying tracklist
        this->SetCurrentTrack( this->nowPlaying->CurrentTrack()->Copy() );

    }
    return this->currentTrack;
}

//////////////////////////////////////////
///\brief
///Set the current track
///
///Setting the current track will also query
///for all the tracks metadata
//////////////////////////////////////////
void PlaybackQueue::SetCurrentTrack(TrackPtr track){
    if(this->currentTrack!=track){
        this->currentTrack  = track;

        // Get all metadata to the track
        if(this->currentTrack){
            this->metadataQuery.Clear();
            this->metadataQuery.RequestAllMetakeys();
            this->metadataQuery.RequestTrack(this->currentTrack);
            this->nowPlaying->Library()->AddQuery(this->metadataQuery,musik::core::Query::Wait|musik::core::Query::AutoCallback|musik::core::Query::UnCanceable|musik::core::Query::Prioritize);
        }

        // Call the signal if track updates
        this->CurrentTrackChanged(track);
    }
}

//////////////////////////////////////////
///\brief
///Copy the tracklist to the now playing and start playing it
///
///\param tracklist
///Tracklist that should be copied to now playing
//////////////////////////////////////////
void PlaybackQueue::Play(tracklist::IRandomAccess &tracklist){
    this->currentTrack.reset();
    this->nowPlaying->CopyTracks(tracklist);
    this->Play();
}

short PlaybackQueue::Volume() const{
    return this->transport.Volume();
}

void PlaybackQueue::SetVolume(short volume){
    this->transport.ChangeVolume(volume);
}

<|endoftext|>


<commit_before>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>

#include <memory>

#include "binder/bind.hh"

#include "kernel/userver.hh"
#include "kernel/uconnection.hh"

#include "object/alien.hh"
#include "object/system-class.hh"

#include "parser/parse.hh"
#include "parser/parse-result.hh"

#include "runner/at_handler.hh"
#include "runner/runner.hh"
#include "runner/interpreter.hh"

#include "ast/nary.hh"

namespace object
{
  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)					\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    CHECK_ARG_COUNT (1);						\
    ::urbiserver->Function();						\
    return void_class;							\
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static rObject
  system_class_sleep (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, Float);
    libport::utime_t deadline;
    if (arg1->value_get() == std::numeric_limits<ufloat>::infinity())
      deadline = std::numeric_limits<libport::utime_t>::max();
    else
      deadline = r.scheduler_get().get_time() +
	static_cast<libport::utime_t>(arg1->value_get() * 1000.0);
    r.yield_until (deadline);
    return void_class;
  }

  static rObject
  system_class_time (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh(r.scheduler_get().get_time() / 1000.0);
  }

  static rObject
  system_class_shiftedTime (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh ((r.scheduler_get().get_time() -
			  r.time_shift_get()) / 1000.0);
  }

  static rObject
  execute_parsed (runner::Runner& r,
                  parser::parse_result_type p, UrbiException e)
  {
    ast::Nary errs;
    p->process_errors(errs);
    errs.accept(dynamic_cast<runner::Interpreter&>(r));
    if (ast::Nary* ast = p->ast_take().release())
    {
      binder::bind(*ast);
      // FIXME: Release AST.
      return dynamic_cast<runner::Interpreter&>(r).eval(*ast);
    }
    else
      throw e;
  }

  static rObject
  system_class_assert_(runner::Runner&, objects_type args)
  {
    CHECK_ARG_COUNT(3);
    FETCH_ARG(2, String);
    if (!is_true(args[1]))
      throw PrimitiveError
	("assert_",
	 "assertion `" + arg2->value_get().name_get() + "' failed");
    return void_class;
  }

  static rObject
  system_class_eval (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(2);
    FETCH_ARG(1, String);
    parser::parse_result_type p();
    return
      execute_parsed(r,
                     parser::parse(arg1->value_get()),
                     PrimitiveError("",
                                    std::string("Error executing command.")));
  }

  static rObject
  system_class_registerAtJob (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(4);
    runner::register_at_job(dynamic_cast<runner::Interpreter&>(r),
			    args[1], args[2], args[3]);
    return object::void_class;
  }

  static rObject
  system_class_searchFile (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, String);

    UServer& s = r.lobby_get()->value_get().connection.server_get();
    try
    {
      return String::fresh(libport::Symbol(
			     s.find_file(arg1->value_get ().name_get ())));
    }
    catch (libport::file_library::Not_found&)
    {
      throw
	PrimitiveError("searchFile",
		       "Unable to find file: "
		       + arg1->value_get().name_get());
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static rObject
  system_class_loadFile (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, String);

    std::string filename = arg1->value_get().name_get();

    if (!libport::path (filename).exists ())
      throw PrimitiveError("loadFile",
			   "No such file: " + filename);

    return
      execute_parsed(r,
                     parser::parse_file(filename),
		     PrimitiveError("", //same message than k1
				    "Error loading file: " + filename));
  }

  static rObject
  system_class_currentRunner (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    rObject res = object::Object::fresh();
    res->proto_add (task_class);
    res->slot_set (SYMBOL (runner), box (scheduler::rJob, r.myself_get ()));
    return res;
  }

  static rObject
  system_class_cycle (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh (r.scheduler_get ().cycle_get ());
  }

  static rObject
  system_class_fresh (runner::Runner&, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return String::fresh(libport::Symbol::fresh());
  }

  static rObject
  system_class_lobby (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return r.lobby_get();
  }

  static rObject
  system_class_nonInterruptible (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    r.non_interruptible_set (true);
    return void_class;
  }

  static rObject
  system_class_quit (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    r.lobby_get()->value_get().connection.close();
    return void_class;
  }

#define SERVER_SET_VAR(Function, Variable, Value)			\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    CHECK_ARG_COUNT (1);						\
    ::urbiserver->Variable = Value;					\
    return void_class;							\
  }

  SERVER_SET_VAR(debugoff, debugOutput, false)
  SERVER_SET_VAR(debugon, debugOutput, true)
  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  void
  system_class_initialize ()
  {
    /// \a Call gives the name of the C++ function, and \a Name that in Urbi.
#define DECLARE(Name)				\
    DECLARE_PRIMITIVE(system, Name)

    DECLARE(assert_);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(debugoff);
    DECLARE(debugon);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(loadFile);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(searchFile);
    DECLARE(shiftedTime);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(stopall);
    DECLARE(time);
#undef DECLARE
  }

}; // namespace object
<commit_msg>Add a method to get a backtrace from urbi.<commit_after>/**
 ** \file object/system-class.cc
 ** \brief Creation of the URBI object system.
 */

//#define ENABLE_DEBUG_TRACES
#include <libport/compiler.hh>

#include <memory>

#include "binder/bind.hh"

#include "kernel/userver.hh"
#include "kernel/uconnection.hh"

#include "object/alien.hh"
#include "object/system-class.hh"

#include "parser/parse.hh"
#include "parser/parse-result.hh"

#include "runner/at_handler.hh"
#include "runner/runner.hh"
#include "runner/interpreter.hh"

#include "ast/nary.hh"

namespace object
{
  rObject system_class;

  /*--------------------.
  | System primitives.  |
  `--------------------*/

#define SERVER_FUNCTION(Function)					\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    CHECK_ARG_COUNT (1);						\
    ::urbiserver->Function();						\
    return void_class;							\
  }

  SERVER_FUNCTION(reboot)
  SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION

  static rObject
  system_class_sleep (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, Float);
    libport::utime_t deadline;
    if (arg1->value_get() == std::numeric_limits<ufloat>::infinity())
      deadline = std::numeric_limits<libport::utime_t>::max();
    else
      deadline = r.scheduler_get().get_time() +
	static_cast<libport::utime_t>(arg1->value_get() * 1000.0);
    r.yield_until (deadline);
    return void_class;
  }

  static rObject
  system_class_time (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh(r.scheduler_get().get_time() / 1000.0);
  }

  static rObject
  system_class_shiftedTime (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh ((r.scheduler_get().get_time() -
			  r.time_shift_get()) / 1000.0);
  }

  static rObject
  execute_parsed (runner::Runner& r,
                  parser::parse_result_type p, UrbiException e)
  {
    ast::Nary errs;
    p->process_errors(errs);
    errs.accept(dynamic_cast<runner::Interpreter&>(r));
    if (ast::Nary* ast = p->ast_take().release())
    {
      binder::bind(*ast);
      // FIXME: Release AST.
      return dynamic_cast<runner::Interpreter&>(r).eval(*ast);
    }
    else
      throw e;
  }

  static rObject
  system_class_assert_(runner::Runner&, objects_type args)
  {
    CHECK_ARG_COUNT(3);
    FETCH_ARG(2, String);
    if (!is_true(args[1]))
      throw PrimitiveError
	("assert_",
	 "assertion `" + arg2->value_get().name_get() + "' failed");
    return void_class;
  }

  static rObject
  system_class_eval (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(2);
    FETCH_ARG(1, String);
    parser::parse_result_type p();
    return
      execute_parsed(r,
                     parser::parse(arg1->value_get()),
                     PrimitiveError("",
                                    std::string("Error executing command.")));
  }

  static rObject
  system_class_registerAtJob (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT(4);
    runner::register_at_job(dynamic_cast<runner::Interpreter&>(r),
			    args[1], args[2], args[3]);
    return object::void_class;
  }

  static rObject
  system_class_searchFile (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, String);

    UServer& s = r.lobby_get()->value_get().connection.server_get();
    try
    {
      return String::fresh(libport::Symbol(
			     s.find_file(arg1->value_get ().name_get ())));
    }
    catch (libport::file_library::Not_found&)
    {
      throw
	PrimitiveError("searchFile",
		       "Unable to find file: "
		       + arg1->value_get().name_get());
      // Never reached
      assertion(false);
      return 0;
    }
  }

  static rObject
  system_class_loadFile (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (2);
    FETCH_ARG(1, String);

    std::string filename = arg1->value_get().name_get();

    if (!libport::path (filename).exists ())
      throw PrimitiveError("loadFile",
			   "No such file: " + filename);

    return
      execute_parsed(r,
                     parser::parse_file(filename),
		     PrimitiveError("", //same message than k1
				    "Error loading file: " + filename));
  }

  static rObject
  system_class_currentRunner (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    rObject res = object::Object::fresh();
    res->proto_add (task_class);
    res->slot_set (SYMBOL (runner), box (scheduler::rJob, r.myself_get ()));
    return res;
  }

  static rObject
  system_class_cycle (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return Float::fresh (r.scheduler_get ().cycle_get ());
  }

  static rObject
  system_class_fresh (runner::Runner&, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return String::fresh(libport::Symbol::fresh());
  }

  static rObject
  system_class_lobby (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    return r.lobby_get();
  }

  static rObject
  system_class_nonInterruptible (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    r.non_interruptible_set (true);
    return void_class;
  }

  static rObject
  system_class_quit (runner::Runner& r, objects_type args)
  {
    CHECK_ARG_COUNT (1);
    r.lobby_get()->value_get().connection.close();
    return void_class;
  }

  // This should give a backtrace as an urbi object.
  static rObject
  system_class_backtrace(runner::Runner&r, objects_type args)
  {
    // FIXME: This method sucks a bit, because show_backtrace sucks a
    // bit, because our channeling/message-sending system sucks a lot.
    CHECK_ARG_COUNT (1);
    runner::Runner::call_stack_type bt = r.call_stack_get();
    bt.pop_back(); // Remove "backtrace" itself from the backtrace
    r.show_backtrace(bt, "");
    return void_class;
  }

#define SERVER_SET_VAR(Function, Variable, Value)			\
  static rObject							\
  system_class_ ## Function (runner::Runner&, objects_type args)	\
  {									\
    CHECK_ARG_COUNT (1);						\
    ::urbiserver->Variable = Value;					\
    return void_class;							\
  }

  SERVER_SET_VAR(debugoff, debugOutput, false)
  SERVER_SET_VAR(debugon, debugOutput, true)
  SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

  void
  system_class_initialize ()
  {
    /// \a Call gives the name of the C++ function, and \a Name that in Urbi.
#define DECLARE(Name)				\
    DECLARE_PRIMITIVE(system, Name)

    DECLARE(assert_);
    DECLARE(backtrace);
    DECLARE(currentRunner);
    DECLARE(cycle);
    DECLARE(debugoff);
    DECLARE(debugon);
    DECLARE(eval);
    DECLARE(fresh);
    DECLARE(loadFile);
    DECLARE(lobby);
    DECLARE(nonInterruptible);
    DECLARE(quit);
    DECLARE(reboot);
    DECLARE(registerAtJob);
    DECLARE(searchFile);
    DECLARE(shiftedTime);
    DECLARE(shutdown);
    DECLARE(sleep);
    DECLARE(stopall);
    DECLARE(time);
#undef DECLARE
  }

}; // namespace object
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <algorithm>
#include "printer.h"
#include "environment.h"
#include "exception.h"

namespace lean {
bool is_atomic(expr const & e) {
    switch (e.kind()) {
    case expr_kind::Var: case expr_kind::Constant: case expr_kind::Value: case expr_kind::Type:
        return true;
    case expr_kind::App: case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Eq: case expr_kind::Let:
        return false;
    }
    return false;
}

struct print_expr_fn {
    std::ostream & m_out;

    std::ostream & out() { return m_out; }

    void print_child(expr const & a, context const & c) {
        if (is_atomic(a)) {
            print(a, c);
        } else {
            out() << "(";
            print(a, c);
            out() << ")";
        }
    }

    void print_value(expr const & a) {
        to_value(a).display(out());
    }

    void print_type(expr const & a) {
        if (a == Type()) {
            out() << "Type";
        } else {
            out() << "Type " << ty_level(a);
        }
    }

    void print_eq(expr const & a, context const & c) {
        print_child(eq_lhs(a), c);
        out() << " = ";
        print_child(eq_rhs(a), c);
    }

    void print_app(expr const & a, context const & c) {
        print_child(arg(a, 0), c);
        for (unsigned i = 1; i < num_args(a); i++) {
            out() << " ";
            print_child(arg(a, i), c);
        }
    }

    void print_arrow_body(expr const & a, context const & c) {
        if (is_atomic(a) || is_arrow(a))
            return print(a, c);
        else
            return print_child(a, c);
    }

    void print(expr const & a, context const & c) {
        switch (a.kind()) {
        case expr_kind::Var:
            try {
                out() << lookup(c, var_idx(a)).get_name();
            } catch (exception & ex) {
                out() << "#" << var_idx(a);
            }
            break;
        case expr_kind::Constant:
            out() << const_name(a);
            break;
        case expr_kind::App:
            print_app(a, c);
            break;
        case expr_kind::Eq:
            print_eq(a, c);
            break;
        case expr_kind::Lambda:
            out() << "fun " << abst_name(a) << " : ";
            print_child(abst_domain(a), c);
            out() << ", ";
            print_child(abst_body(a), extend(c, abst_name(a), abst_domain(a)));
            break;
        case expr_kind::Pi:
            if (!is_arrow(a)) {
                out() << "Pi " << abst_name(a) << " : ";
                print_child(abst_domain(a), c);
                out() << ", ";
                print_child(abst_body(a), extend(c, abst_name(a), abst_domain(a)));
                break;
            } else {
                print_child(abst_domain(a), c);
                out() << " -> ";
                print_arrow_body(abst_body(a), extend(c, abst_name(a), abst_domain(a)));
            }
            break;
        case expr_kind::Let:
            out() << "let " << let_name(a) << " := ";
            print(let_value(a), c);
            out() << " in ";
            print_child(let_body(a), extend(c, let_name(a), let_value(a)));
            break;
        case expr_kind::Type:
            print_type(a);
            break;
        case expr_kind::Value:
            print_value(a);
            break;
        }
    }

    print_expr_fn(std::ostream & out):m_out(out) {}

    void operator()(expr const & e, context const & c) {
        print(e, c);
    }
};

std::ostream & operator<<(std::ostream & out, expr const & e) {
    print_expr_fn pr(out);
    pr(e, context());
    return out;
}

std::ostream & operator<<(std::ostream & out, std::pair<expr const &, context const &> const & p) {
    print_expr_fn pr(out);
    pr(p.first, p.second);
    return out;
}

std::ostream & operator<<(std::ostream & out, context const & ctx) {
    if (ctx) {
        out << tail(ctx);
        out << head(ctx).get_name() << " : " << head(ctx).get_domain();
        if (head(ctx).get_body()) {
            out << " := " << mk_pair(head(ctx).get_body(), tail(ctx));
        }
        out << "\n";
    }
    return out;
}

std::ostream & operator<<(std::ostream & out, object const & obj) {
    out << obj.keyword() << " ";
    switch (obj.kind()) {
    case object_kind::UVarDeclaration:
        out << obj.get_name() << " >= " << obj.get_cnstr_level(); break;
    case object_kind::Postulate:
        out << obj.get_name() << " : " << obj.get_type(); break;
    case object_kind::Definition:
        out << obj.get_name() << " : " << obj.get_type() << " :=\n    " << obj.get_value(); break;
    case object_kind::Neutral:
        break;
    }
    return out;
}

std::ostream & operator<<(std::ostream & out, environment const & env) {
    std::for_each(env.begin_objects(),
                  env.end_objects(),
                  [&](object const & obj) { out << obj << "\n"; });
    return out;
}
}
void print(lean::expr const & a) { std::cout << a << std::endl; }
void print(lean::expr const & a, lean::context const & c) { std::cout << mk_pair(a, c) << std::endl; }
void print(lean::context const & c) { std::cout << c << std::endl; }
void print(lean::environment const & e) { std::cout << e << std::endl; }
<commit_msg>Modify basic printer for contexts<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <algorithm>
#include "printer.h"
#include "environment.h"
#include "exception.h"

namespace lean {
bool is_atomic(expr const & e) {
    switch (e.kind()) {
    case expr_kind::Var: case expr_kind::Constant: case expr_kind::Value: case expr_kind::Type:
        return true;
    case expr_kind::App: case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Eq: case expr_kind::Let:
        return false;
    }
    return false;
}

struct print_expr_fn {
    std::ostream & m_out;

    std::ostream & out() { return m_out; }

    void print_child(expr const & a, context const & c) {
        if (is_atomic(a)) {
            print(a, c);
        } else {
            out() << "(";
            print(a, c);
            out() << ")";
        }
    }

    void print_value(expr const & a) {
        to_value(a).display(out());
    }

    void print_type(expr const & a) {
        if (a == Type()) {
            out() << "Type";
        } else {
            out() << "Type " << ty_level(a);
        }
    }

    void print_eq(expr const & a, context const & c) {
        print_child(eq_lhs(a), c);
        out() << " = ";
        print_child(eq_rhs(a), c);
    }

    void print_app(expr const & a, context const & c) {
        print_child(arg(a, 0), c);
        for (unsigned i = 1; i < num_args(a); i++) {
            out() << " ";
            print_child(arg(a, i), c);
        }
    }

    void print_arrow_body(expr const & a, context const & c) {
        if (is_atomic(a) || is_arrow(a))
            return print(a, c);
        else
            return print_child(a, c);
    }

    void print(expr const & a, context const & c) {
        switch (a.kind()) {
        case expr_kind::Var:
            try {
                out() << lookup(c, var_idx(a)).get_name();
            } catch (exception & ex) {
                out() << "#" << var_idx(a);
            }
            break;
        case expr_kind::Constant:
            out() << const_name(a);
            break;
        case expr_kind::App:
            print_app(a, c);
            break;
        case expr_kind::Eq:
            print_eq(a, c);
            break;
        case expr_kind::Lambda:
            out() << "fun " << abst_name(a) << " : ";
            print_child(abst_domain(a), c);
            out() << ", ";
            print_child(abst_body(a), extend(c, abst_name(a), abst_domain(a)));
            break;
        case expr_kind::Pi:
            if (!is_arrow(a)) {
                out() << "Pi " << abst_name(a) << " : ";
                print_child(abst_domain(a), c);
                out() << ", ";
                print_child(abst_body(a), extend(c, abst_name(a), abst_domain(a)));
                break;
            } else {
                print_child(abst_domain(a), c);
                out() << " -> ";
                print_arrow_body(abst_body(a), extend(c, abst_name(a), abst_domain(a)));
            }
            break;
        case expr_kind::Let:
            out() << "let " << let_name(a) << " := ";
            print(let_value(a), c);
            out() << " in ";
            print_child(let_body(a), extend(c, let_name(a), let_value(a)));
            break;
        case expr_kind::Type:
            print_type(a);
            break;
        case expr_kind::Value:
            print_value(a);
            break;
        }
    }

    print_expr_fn(std::ostream & out):m_out(out) {}

    void operator()(expr const & e, context const & c) {
        print(e, c);
    }
};

std::ostream & operator<<(std::ostream & out, expr const & e) {
    print_expr_fn pr(out);
    pr(e, context());
    return out;
}

std::ostream & operator<<(std::ostream & out, std::pair<expr const &, context const &> const & p) {
    print_expr_fn pr(out);
    pr(p.first, p.second);
    return out;
}

static void display_context_core(std::ostream & out, context const & ctx) {
    if (ctx) {
        display_context_core(out, tail(ctx));
        if (tail(ctx))
            out << "; ";
        out << head(ctx).get_name() << " : " << head(ctx).get_domain();
        if (head(ctx).get_body()) {
            out << " := " << mk_pair(head(ctx).get_body(), tail(ctx));
        }
    }
}

std::ostream & operator<<(std::ostream & out, context const & ctx) {
    out << "[";
    display_context_core(out, ctx);
    out << "]";
    return out;
}

std::ostream & operator<<(std::ostream & out, object const & obj) {
    out << obj.keyword() << " ";
    switch (obj.kind()) {
    case object_kind::UVarDeclaration:
        out << obj.get_name() << " >= " << obj.get_cnstr_level(); break;
    case object_kind::Postulate:
        out << obj.get_name() << " : " << obj.get_type(); break;
    case object_kind::Definition:
        out << obj.get_name() << " : " << obj.get_type() << " :=\n    " << obj.get_value(); break;
    case object_kind::Neutral:
        break;
    }
    return out;
}

std::ostream & operator<<(std::ostream & out, environment const & env) {
    std::for_each(env.begin_objects(),
                  env.end_objects(),
                  [&](object const & obj) { out << obj << "\n"; });
    return out;
}
}
void print(lean::expr const & a) { std::cout << a << std::endl; }
void print(lean::expr const & a, lean::context const & c) { std::cout << mk_pair(a, c) << std::endl; }
void print(lean::context const & c) { std::cout << c << std::endl; }
void print(lean::environment const & e) { std::cout << e << std::endl; }
<|endoftext|>


<commit_before>/**
 * This file is part of the Marble Desktop Globe.
 *
 * Copyright 2005-2007 Torsten Rahn <tackat@kde.org>
 * Copyright 2007      Inge Wallin  <ingwa@kde.org>
 * Copyright 2008,2009 Jens-Michael Hoffmann <jensmh@gmx.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "TileLoader.h"

#include "global.h"
#include "GeoSceneLayer.h"
#include "GeoSceneTexture.h"
#include "HttpDownloadManager.h"
#include "DatasetProvider.h"
#include "TextureTile.h"
#include "MarbleDirs.h"
#include "MarbleModel.h"
#include "TileLoaderHelper.h"
#include "MarbleDebug.h"

#include <QtCore/QCache>
#include <QtCore/QDateTime>
#include <QtCore/QHash>
#include <QtGui/QImage>

#ifdef Q_CC_MSVC
# ifndef KDEWIN_MATH_H
   long double log(int i) { return log((long double)i); }
# endif
#endif

namespace Marble
{

class TileLoaderPrivate
{
    public:
        TileLoaderPrivate()
            : m_datasetProvider( 0 ),
              m_downloadManager( 0 ),
              m_layer( 0 ),
              m_tileWidth( 0 ),
              m_tileHeight( 0 )
        {
            m_tileCache.setMaxCost( 20000 * 1024 ); // Cache size measured in bytes
        }

        DatasetProvider *m_datasetProvider;
        HttpDownloadManager *m_downloadManager;
        GeoSceneLayer *m_layer;
        QHash <TileId, TextureTile*>  m_tilesOnDisplay;
        int           m_tileWidth;
        int           m_tileHeight;
        QCache <TileId, TextureTile>  m_tileCache;
};

TileLoader::TileLoader( HttpDownloadManager *downloadManager, MarbleModel* parent)
    : d( new TileLoaderPrivate() ),
      m_parent(parent)
{
    setDownloadManager( downloadManager );
}

TileLoader::~TileLoader()
{
    flush();
    d->m_tileCache.clear();
    if ( d->m_downloadManager != 0 )
        d->m_downloadManager->disconnect( this );

    delete d;
}

void TileLoader::setDownloadManager( HttpDownloadManager *downloadManager )
{
    if ( d->m_downloadManager != 0 ) {
        d->m_downloadManager->disconnect( this );
        d->m_downloadManager = 0;
    }

    d->m_downloadManager = downloadManager;
    if ( d->m_downloadManager != 0 ) {
        connect( d->m_downloadManager, SIGNAL( downloadComplete( QString, QString ) ),
                 this,              SLOT( reloadTile( QString, QString ) ) );
    }
}

void TileLoader::setLayer( GeoSceneLayer * layer )
{
    // Initialize map theme.
    flush();
    d->m_tileCache.clear();

    if ( !layer ) {
        mDebug() << "No layer specified! (GeoSceneLayer * layer = 0)";
        return;
    }

    d->m_layer = layer;

    TileId id( 0, 0, 0 );
    TextureTile tile( id );

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

    tile.loadDataset( texture, id );

    // We assume that all tiles have the same size. TODO: check to be safe
    d->m_tileWidth  = tile.rawtile().width();
    d->m_tileHeight = tile.rawtile().height();
}

void TileLoader::resetTilehash()
{
    QHash<TileId, TextureTile*>::const_iterator it = d->m_tilesOnDisplay.constBegin();
    QHash<TileId, TextureTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
    for (; it != end; ++it ) {
        it.value()->setUsed( false );
    }
}

void TileLoader::cleanupTilehash()
{
    // Make sure that tiles which haven't been used during the last
    // rendering of the map at all get removed from the tile hash.

    QHashIterator<TileId, TextureTile*> it( d->m_tilesOnDisplay );
    while ( it.hasNext() ) {
        it.next();
        if ( !it.value()->used() ) {
            // If insert call result is false then the cache is too small to store the tile
            // but the item will get deleted nevertheless and the pointer we have
            // doesn't get set to zero (so don't delete it in this case or it will crash!)
            d->m_tileCache.insert( it.key(), it.value(), it.value()->numBytes() );
            d->m_tilesOnDisplay.remove( it.key() );
        }
    }
}

void TileLoader::flush()
{
    // Remove all tiles from m_tilesOnDisplay
    QHashIterator<TileId, TextureTile*> it( d->m_tilesOnDisplay );
    while ( it.hasNext() ) {
        it.next();
        // If insert call result is false then the cache is too small to store the tile
        // but the item will get deleted nevertheless and the pointer we have
        // doesn't get set to zero (so don't delete it in this case or it will crash!)
        d->m_tileCache.insert( it.key(), it.value(), it.value()->numBytes() );
        d->m_tilesOnDisplay.remove( it.key() );
    }

    d->m_tilesOnDisplay.clear();
}

int TileLoader::tileWidth() const
{
    return d->m_tileWidth;
}

int TileLoader::tileHeight() const
{
    return d->m_tileHeight;
}

int TileLoader::globalWidth( int level ) const
{
    if ( !d->m_layer ) return 0;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

    return d->m_tileWidth * TileLoaderHelper::levelToColumn(
                                texture->levelZeroColumns(), level );
}

int TileLoader::globalHeight( int level ) const
{
    if ( !d->m_layer ) return 0;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

    return d->m_tileHeight * TileLoaderHelper::levelToRow(
                                texture->levelZeroRows(), level );
}

TextureTile* TileLoader::loadTile( int tilx, int tily, int tileLevel )
{
    if ( !d->m_layer ) return 0;

    TileId tileId( tileLevel, tilx, tily );

    // check if the tile is in the hash
    TextureTile * tile = d->m_tilesOnDisplay.value( tileId, 0 );
    if ( tile ) {
        tile->setUsed( true );
        return tile;
    }
    // here ends the performance critical section of this method

    // the tile was not in the hash or has been removed because of expiration
    // so check if it is in the cache
    tile = d->m_tileCache.take( tileId );

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

    if ( tile ) {
        // the tile was in the cache, but is it up to date?
        const QDateTime now = QDateTime::currentDateTime();

        if ( tile->created().secsTo( now ) < texture->expire()) {
            d->m_tilesOnDisplay[tileId] = tile;
            tile->setUsed( true );
            return tile;
        } else {
            delete tile;
            tile = 0;
        }
    }

    // tile (valid) has not been found in hash or cache, so load it from disk
    // and place it in the hash from where it will get transferred to the cache

    // mDebug() << "load Tile from Disk: " << tileId.toString();
    tile = new TextureTile( tileId );
    d->m_tilesOnDisplay[tileId] = tile;

    // FIXME: Implement asynchronous tile loading
    // d->m_datasetProvider->loadDatasets( tile );

    if ( d->m_downloadManager != 0 ) {
        connect( tile, SIGNAL( downloadTile( QUrl, QString, QString, DownloadUsage ) ),
                 d->m_downloadManager, SLOT( addJob( QUrl, QString, QString, DownloadUsage ) ) );
    }
    connect( tile, SIGNAL( tileUpdateDone() ),
             this, SIGNAL( tileUpdateAvailable() ) );

    tile->loadDataset( texture, tileId, &d->m_tileCache );
    tile->initJumpTables( false );

    // TODO should emit signal rather than directly calling paintTile
    // emit paintTile( tile, tilx, tily, tileLevel, d->m_theme, false );
    m_parent->paintTile( tile, texture, false );

    return tile;
}

GeoSceneLayer * TileLoader::layer() const
{
    return d->m_layer;
}

quint64 TileLoader::volatileCacheLimit() const
{
    return d->m_tileCache.maxCost() / 1024;
}

QList<TileId> TileLoader::tilesOnDisplay() const
{
    QList<TileId> result;
    QHash<TileId, TextureTile*>::const_iterator pos = d->m_tilesOnDisplay.constBegin();
    QHash<TileId, TextureTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
    for (; pos != end; ++pos ) {
        if ( pos.value()->used() ) {
            result.append( pos.key() );
        }
    }
    return result;
}

int TileLoader::maxPartialTileLevel( GeoSceneLayer * layer )
{
    int maxtilelevel = -1;

    if ( !layer ) return maxtilelevel;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( layer->groundDataset() );

    if ( !texture ) return maxtilelevel;

    QString tilepath = MarbleDirs::path( TileLoaderHelper::themeStr( texture ) );
//    mDebug() << "TileLoader::maxPartialTileLevel tilepath" << tilepath;
    QStringList leveldirs = QDir( tilepath ).entryList( QDir::AllDirs | QDir::NoSymLinks | QDir::NoDotAndDotDot );

    bool ok = true;

    QStringList::const_iterator it = leveldirs.constBegin();
    QStringList::const_iterator const end = leveldirs.constEnd();
    for (; it != end; ++it ) {
        int value = (*it).toInt( &ok, 10 );
        if ( ok && value > maxtilelevel )
            maxtilelevel = value;
    }

//    mDebug() << "Detected maximum tile level that contains data: "
//             << maxtilelevel;

    return maxtilelevel;
}

bool TileLoader::baseTilesAvailable( GeoSceneLayer * layer )
{
    if ( !layer ) return false;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( layer->groundDataset() );

    const int  levelZeroColumns = texture->levelZeroColumns();
    const int  levelZeroRows    = texture->levelZeroRows();

    bool noerr = true;

    // Check whether the tiles from the lowest texture level are available
    //
    for ( int column = 0; noerr && column < levelZeroColumns; ++column ) {
        for ( int row = 0; noerr && row < levelZeroRows; ++row ) {

            const QString tilepath = MarbleDirs::path( TileLoaderHelper::relativeTileFileName(
                texture, 0, column, row ));
            noerr = QFile::exists( tilepath );
        }
    }

    return noerr;
}

void TileLoader::setVolatileCacheLimit( quint64 kiloBytes )
{
    mDebug() << QString("Setting tile cache to %1 kilobytes.").arg( kiloBytes );
    d->m_tileCache.setMaxCost( kiloBytes * 1024 );
}

void TileLoader::reloadTile( const QString &idStr )
{
    if ( !d->m_layer ) return;

//    mDebug() << "TileLoader::reloadTile:" << idStr;

    const TileId id = TileId::fromString( idStr );
    if ( d->m_tilesOnDisplay.contains( id ) ) {

        // TODO should emit signal rather than directly calling paintTile
//         emit paintTile( d->m_tilesOnDisplay[id], x, y, level, d->m_theme, true );
        GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

        d->m_tilesOnDisplay[id]->loadDataset( texture, id, &d->m_tileCache );
        m_parent->paintTile( d->m_tilesOnDisplay[id], texture, true );
//         (d->m_tilesOnDisplay[id])->reloadTile( x, y, level, d->m_theme );
    } else {
      // Remove "false" tile from cache so it doesn't get loaded anymore
      d->m_tileCache.remove( id );
      mDebug() << "No such ID:" << idStr;
    }
}

void TileLoader::reloadTile( const QString &relativeUrlString, const QString &_id )
{
    Q_UNUSED( relativeUrlString );
    // mDebug() << "Reloading Tile" << relativeUrlString << "id:" << _id;

    reloadTile( _id );
}

void TileLoader::update()
{
    mDebug() << "TileLoader::update()";
    flush(); // trigger a reload of all tiles that are currently in use
    d->m_tileCache.clear(); // clear the tile cache in physical memory
    emit tileUpdateAvailable();
}

}

#include "TileLoader.moc"
<commit_msg>Coding style changes.<commit_after>/**
 * This file is part of the Marble Desktop Globe.
 *
 * Copyright 2005-2007 Torsten Rahn <tackat@kde.org>
 * Copyright 2007      Inge Wallin  <ingwa@kde.org>
 * Copyright 2008,2009 Jens-Michael Hoffmann <jensmh@gmx.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "TileLoader.h"

#include "global.h"
#include "GeoSceneLayer.h"
#include "GeoSceneTexture.h"
#include "HttpDownloadManager.h"
#include "DatasetProvider.h"
#include "TextureTile.h"
#include "MarbleDirs.h"
#include "MarbleModel.h"
#include "TileLoaderHelper.h"
#include "MarbleDebug.h"

#include <QtCore/QCache>
#include <QtCore/QDateTime>
#include <QtCore/QHash>
#include <QtGui/QImage>

#ifdef Q_CC_MSVC
# ifndef KDEWIN_MATH_H
   long double log(int i) { return log((long double)i); }
# endif
#endif

namespace Marble
{

class TileLoaderPrivate
{
public:
    TileLoaderPrivate()
        : m_datasetProvider( 0 ),
          m_downloadManager( 0 ),
          m_layer( 0 ),
          m_tileWidth( 0 ),
          m_tileHeight( 0 )
    {
        m_tileCache.setMaxCost( 20000 * 1024 ); // Cache size measured in bytes
    }

    DatasetProvider *m_datasetProvider;
    HttpDownloadManager *m_downloadManager;
    GeoSceneLayer *m_layer;
    QHash <TileId, TextureTile*>  m_tilesOnDisplay;
    int           m_tileWidth;
    int           m_tileHeight;
    QCache <TileId, TextureTile>  m_tileCache;
};

TileLoader::TileLoader( HttpDownloadManager *downloadManager, MarbleModel* parent )
    : d( new TileLoaderPrivate() ),
      m_parent( parent )
{
    setDownloadManager( downloadManager );
}

TileLoader::~TileLoader()
{
    flush();
    d->m_tileCache.clear();
    if ( d->m_downloadManager != 0 )
        d->m_downloadManager->disconnect( this );

    delete d;
}

void TileLoader::setDownloadManager( HttpDownloadManager *downloadManager )
{
    if ( d->m_downloadManager != 0 ) {
        d->m_downloadManager->disconnect( this );
        d->m_downloadManager = 0;
    }

    d->m_downloadManager = downloadManager;
    if ( d->m_downloadManager != 0 ) {
        connect( d->m_downloadManager, SIGNAL( downloadComplete( QString, QString ) ),
                 this,              SLOT( reloadTile( QString, QString ) ) );
    }
}

void TileLoader::setLayer( GeoSceneLayer * layer )
{
    // Initialize map theme.
    flush();
    d->m_tileCache.clear();

    if ( !layer ) {
        mDebug() << "No layer specified! (GeoSceneLayer * layer = 0)";
        return;
    }

    d->m_layer = layer;

    TileId id( 0, 0, 0 );
    TextureTile tile( id );

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

    tile.loadDataset( texture, id );

    // We assume that all tiles have the same size. TODO: check to be safe
    d->m_tileWidth  = tile.rawtile().width();
    d->m_tileHeight = tile.rawtile().height();
}

void TileLoader::resetTilehash()
{
    QHash<TileId, TextureTile*>::const_iterator it = d->m_tilesOnDisplay.constBegin();
    QHash<TileId, TextureTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
    for (; it != end; ++it ) {
        it.value()->setUsed( false );
    }
}

void TileLoader::cleanupTilehash()
{
    // Make sure that tiles which haven't been used during the last
    // rendering of the map at all get removed from the tile hash.

    QHashIterator<TileId, TextureTile*> it( d->m_tilesOnDisplay );
    while ( it.hasNext() ) {
        it.next();
        if ( !it.value()->used() ) {
            // If insert call result is false then the cache is too small to store the tile
            // but the item will get deleted nevertheless and the pointer we have
            // doesn't get set to zero (so don't delete it in this case or it will crash!)
            d->m_tileCache.insert( it.key(), it.value(), it.value()->numBytes() );
            d->m_tilesOnDisplay.remove( it.key() );
        }
    }
}

void TileLoader::flush()
{
    // Remove all tiles from m_tilesOnDisplay
    QHashIterator<TileId, TextureTile*> it( d->m_tilesOnDisplay );
    while ( it.hasNext() ) {
        it.next();
        // If insert call result is false then the cache is too small to store the tile
        // but the item will get deleted nevertheless and the pointer we have
        // doesn't get set to zero (so don't delete it in this case or it will crash!)
        d->m_tileCache.insert( it.key(), it.value(), it.value()->numBytes() );
        d->m_tilesOnDisplay.remove( it.key() );
    }

    d->m_tilesOnDisplay.clear();
}

int TileLoader::tileWidth() const
{
    return d->m_tileWidth;
}

int TileLoader::tileHeight() const
{
    return d->m_tileHeight;
}

int TileLoader::globalWidth( int level ) const
{
    if ( !d->m_layer ) return 0;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

    return d->m_tileWidth * TileLoaderHelper::levelToColumn(
                                texture->levelZeroColumns(), level );
}

int TileLoader::globalHeight( int level ) const
{
    if ( !d->m_layer ) return 0;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

    return d->m_tileHeight * TileLoaderHelper::levelToRow(
                                texture->levelZeroRows(), level );
}

TextureTile* TileLoader::loadTile( int tilx, int tily, int tileLevel )
{
    if ( !d->m_layer ) return 0;

    TileId tileId( tileLevel, tilx, tily );

    // check if the tile is in the hash
    TextureTile * tile = d->m_tilesOnDisplay.value( tileId, 0 );
    if ( tile ) {
        tile->setUsed( true );
        return tile;
    }
    // here ends the performance critical section of this method

    // the tile was not in the hash or has been removed because of expiration
    // so check if it is in the cache
    tile = d->m_tileCache.take( tileId );

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

    if ( tile ) {
        // the tile was in the cache, but is it up to date?
        const QDateTime now = QDateTime::currentDateTime();

        if ( tile->created().secsTo( now ) < texture->expire()) {
            d->m_tilesOnDisplay[tileId] = tile;
            tile->setUsed( true );
            return tile;
        } else {
            delete tile;
            tile = 0;
        }
    }

    // tile (valid) has not been found in hash or cache, so load it from disk
    // and place it in the hash from where it will get transferred to the cache

    // mDebug() << "load Tile from Disk: " << tileId.toString();
    tile = new TextureTile( tileId );
    d->m_tilesOnDisplay[tileId] = tile;

    // FIXME: Implement asynchronous tile loading
    // d->m_datasetProvider->loadDatasets( tile );

    if ( d->m_downloadManager != 0 ) {
        connect( tile, SIGNAL( downloadTile( QUrl, QString, QString, DownloadUsage ) ),
                 d->m_downloadManager, SLOT( addJob( QUrl, QString, QString, DownloadUsage ) ) );
    }
    connect( tile, SIGNAL( tileUpdateDone() ),
             this, SIGNAL( tileUpdateAvailable() ) );

    tile->loadDataset( texture, tileId, &d->m_tileCache );
    tile->initJumpTables( false );

    // TODO should emit signal rather than directly calling paintTile
    // emit paintTile( tile, tilx, tily, tileLevel, d->m_theme, false );
    m_parent->paintTile( tile, texture, false );

    return tile;
}

GeoSceneLayer * TileLoader::layer() const
{
    return d->m_layer;
}

quint64 TileLoader::volatileCacheLimit() const
{
    return d->m_tileCache.maxCost() / 1024;
}

QList<TileId> TileLoader::tilesOnDisplay() const
{
    QList<TileId> result;
    QHash<TileId, TextureTile*>::const_iterator pos = d->m_tilesOnDisplay.constBegin();
    QHash<TileId, TextureTile*>::const_iterator const end = d->m_tilesOnDisplay.constEnd();
    for (; pos != end; ++pos ) {
        if ( pos.value()->used() ) {
            result.append( pos.key() );
        }
    }
    return result;
}

int TileLoader::maxPartialTileLevel( GeoSceneLayer * layer )
{
    int maxtilelevel = -1;

    if ( !layer ) return maxtilelevel;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( layer->groundDataset() );

    if ( !texture ) return maxtilelevel;

    QString tilepath = MarbleDirs::path( TileLoaderHelper::themeStr( texture ) );
//    mDebug() << "TileLoader::maxPartialTileLevel tilepath" << tilepath;
    QStringList leveldirs = QDir( tilepath ).entryList( QDir::AllDirs | QDir::NoSymLinks
                                                        | QDir::NoDotAndDotDot );

    bool ok = true;

    QStringList::const_iterator it = leveldirs.constBegin();
    QStringList::const_iterator const end = leveldirs.constEnd();
    for (; it != end; ++it ) {
        int value = (*it).toInt( &ok, 10 );
        if ( ok && value > maxtilelevel )
            maxtilelevel = value;
    }

//    mDebug() << "Detected maximum tile level that contains data: "
//             << maxtilelevel;

    return maxtilelevel;
}

bool TileLoader::baseTilesAvailable( GeoSceneLayer * layer )
{
    if ( !layer ) return false;

    GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( layer->groundDataset() );

    const int  levelZeroColumns = texture->levelZeroColumns();
    const int  levelZeroRows    = texture->levelZeroRows();

    bool noerr = true;

    // Check whether the tiles from the lowest texture level are available
    //
    for ( int column = 0; noerr && column < levelZeroColumns; ++column ) {
        for ( int row = 0; noerr && row < levelZeroRows; ++row ) {

            const QString tilepath = MarbleDirs::path( TileLoaderHelper::relativeTileFileName(
                texture, 0, column, row ));
            noerr = QFile::exists( tilepath );
        }
    }

    return noerr;
}

void TileLoader::setVolatileCacheLimit( quint64 kiloBytes )
{
    mDebug() << QString("Setting tile cache to %1 kilobytes.").arg( kiloBytes );
    d->m_tileCache.setMaxCost( kiloBytes * 1024 );
}

void TileLoader::reloadTile( const QString &idStr )
{
    if ( !d->m_layer ) return;

//    mDebug() << "TileLoader::reloadTile:" << idStr;

    const TileId id = TileId::fromString( idStr );
    if ( d->m_tilesOnDisplay.contains( id ) ) {

        // TODO should emit signal rather than directly calling paintTile
//         emit paintTile( d->m_tilesOnDisplay[id], x, y, level, d->m_theme, true );
        GeoSceneTexture * texture = static_cast<GeoSceneTexture *>( d->m_layer->groundDataset() );

        d->m_tilesOnDisplay[id]->loadDataset( texture, id, &d->m_tileCache );
        m_parent->paintTile( d->m_tilesOnDisplay[id], texture, true );
//         (d->m_tilesOnDisplay[id])->reloadTile( x, y, level, d->m_theme );
    } else {
        // Remove "false" tile from cache so it doesn't get loaded anymore
        d->m_tileCache.remove( id );
        mDebug() << "No such ID:" << idStr;
    }
}

void TileLoader::reloadTile( const QString &relativeUrlString, const QString &id )
{
    Q_UNUSED( relativeUrlString );
    // mDebug() << "Reloading Tile" << relativeUrlString << "id:" << id;

    reloadTile( id );
}

void TileLoader::update()
{
    mDebug() << "TileLoader::update()";
    flush(); // trigger a reload of all tiles that are currently in use
    d->m_tileCache.clear(); // clear the tile cache in physical memory
    emit tileUpdateAvailable();
}

}

#include "TileLoader.moc"
<|endoftext|>