<commit_before>/***************************************************************************
            dump.c  -  Skeleton of backends to access the Key Database
                             -------------------
    begin                : Mon May  3 15:22:44 CEST 2010
    copyright            : by Markus Raab
    email                : elektra@markus-raab.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the BSD License (revised).                      *
 *                                                                         *
 ***************************************************************************/

#include "dump.hpp"

extern "C" {

void serialize(std::ostream &os, ckdb::KeySet *ks)
{
	ckdb::Key *cur;

	os << "ksNew " << ckdb::ksGetSize(ks) << std::endl;

	ksRewind(ks);
	while ((cur = ksNext(ks)) != 0)
	{
		size_t namesize = ckdb::keyGetNameSize(cur);
		size_t valuesize = ckdb::keyGetValueSize(cur);
		os << "keyNew " << namesize
		   << " " << valuesize << std::endl;
		os.write(ckdb::keyName(cur), namesize);
		os.write(static_cast<const char*>(ckdb::keyValue(cur)), valuesize);
		os << std::endl;

		const char *metaname;
		const char *metavalue;
		ckdb::keyRewindMeta(cur);
		while ((metaname = ckdb::keyNextMeta(cur)) != 0)
		{
			metavalue = ckdb::keyCurrentMeta(cur);
			size_t metanamesize = ckdb::kdbiStrLen(metaname);
			size_t metavaluesize = ckdb::kdbiStrLen(metavalue);

			os << "keyMeta " << metanamesize
			   << " " << metavaluesize << std::endl;
			os.write (metaname, metanamesize);
			os.write (metavalue, metavaluesize);
			os << std::endl;
		}
		os << "keyEnd" << std::endl;
	}
	os << "ksEnd" << std::endl;
}

void unserialize(std::istream &is, ckdb::KeySet *ks)
{
	ckdb::Key *cur = 0;

	std::vector<char> namebuffer(4048);
	std::vector<char> valuebuffer(4048);
	std::string line;
	std::string command;
	size_t nrKeys;
	size_t namesize;
	size_t valuesize;

	while(std::getline (is, line))
	{
		std::stringstream ss (line);
		ss >> command;

		if (command == "ksNew")
		{
			ss >> nrKeys;

			ksClear(ks);
		}
		else if (command == "keyNew")
		{
			cur = ckdb::keyNew(0);

			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size()) namebuffer.resize(namesize);
			is.read(&namebuffer[0], namesize);
			namebuffer[namesize] = 0;
			ckdb::keySetName(cur, &namebuffer[0]);

			if (valuesize > valuebuffer.size()) valuebuffer.resize(valuesize);
			is.read(&valuebuffer[0], valuesize);
			ckdb::keySetRaw (cur, &valuebuffer[0], valuesize);
			std::getline (is, line);
		}
		else if (command == "keyMeta")
		{
			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size()) namebuffer.resize(namesize);
			is.read(&namebuffer[0], namesize);
			namebuffer[namesize] = 0;

			if (valuesize > valuebuffer.size()) valuebuffer.resize(valuesize);
			is.read(&valuebuffer[0], valuesize);

			keySetMeta (cur, &namebuffer[0], &valuebuffer[0]);
			std::getline (is, line);
		}
		else if (command == "keyEnd")
		{
			ckdb::keyClearSync(cur);
			ckdb::ksAppendKey(ks, cur);
			cur = 0;
		}
		else if (command == "ksEnd")
		{
			break;
		} else {
			std::cerr << "unkown command: " << command << std::endl;
		}
	}
}

int kdbOpen_dump(ckdb::KDB *handle)
{
	int errnosave = errno;
	ckdb::KeySet *ks;
	ckdb::Key *k;

	KDBCap * cap = ckdb::kdbhGetCapability(handle);
	cap->onlyFullGet=1;
	cap->onlyRemoveAll=1;
	cap->onlyAddKeys=1;
	cap->onlyFullSet=1;
	cap->onlySystem=1;
	cap->onlyUser=1;

	ks = ckdb::kdbhGetConfig (handle);
	ckdb::ksRewind (ks);
	while ((k = ckdb::ksNext (ks)) != 0)
	{
		const char *name;
		std::string f;
		size_t pos;

		name = ckdb::keyName(k);
		if (!name) continue;
		f = std::string(name);
		pos = f.find_last_of('/');
		std::string postfix = f.substr(pos);
		if (postfix == "/path") {
			ckdb::kdbhSetBackendData (handle, new std::string((char*)ckdb::keyValue(k)));
		}
	}
	if (!ckdb::kdbhGetBackendData (handle)) ckdb::kdbhSetBackendData (handle, new std::string(DUMP_PATH));

	errno = errnosave;
	return 0;
}

int kdbClose_dump(ckdb::KDB *handle)
{
	int errnosave = errno;

	delete static_cast<std::string*>(ckdb::kdbhGetBackendData (handle));

	errno = errnosave;
	return 0; /* success */
}

ssize_t kdbGet_dump(ckdb::KDB *handle, ckdb::KeySet *returned, const ckdb::Key *parentKey)
{
	int errnosave = errno;

	if (strcmp (keyName(kdbhGetMountpoint(handle)), keyName(parentKey))) return 0;

	std::ifstream ofs(static_cast<std::string*>(ckdb::kdbhGetBackendData (handle))->c_str());
	unserialize (ofs, returned);

	errno = errnosave;
	return ksGetSize(returned); /* success */
}

ssize_t kdbSet_dump(ckdb::KDB *handle, ckdb::KeySet *returned, const ckdb::Key *parentKey)
{
	int errnosave = errno;

	if (strcmp (keyName(kdbhGetMountpoint(handle)), keyName(parentKey))) return 0;

	std::ofstream ifs(static_cast<std::string*>(ckdb::kdbhGetBackendData (handle))->c_str());
	serialize (ifs, returned);

	errno = errnosave;
	return ksGetSize(returned);
}

ckdb::KDB *KDBEXPORT(dump)
{
	return kdbBackendExport(BACKENDNAME,
		KDB_BE_OPEN,	&kdbOpen_dump,
		KDB_BE_CLOSE,	&kdbClose_dump,
		KDB_BE_GET,	&kdbGet_dump,
		KDB_BE_SET,	&kdbSet_dump,
		KDB_BE_VERSION,        BACKENDVERSION,
		KDB_BE_AUTHOR,	"Full Name <email@libelektra.org>",
		KDB_BE_LICENCE,	"BSD",
		KDB_BE_DESCRIPTION,
			"Add description here",
		KDB_BE_END);
}

} // extern C

<commit_msg>dump now uses new meta API<commit_after>/***************************************************************************
            dump.c  -  Skeleton of backends to access the Key Database
                             -------------------
    begin                : Mon May  3 15:22:44 CEST 2010
    copyright            : by Markus Raab
    email                : elektra@markus-raab.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the BSD License (revised).                      *
 *                                                                         *
 ***************************************************************************/

#include "dump.hpp"

extern "C" {

void serialize(std::ostream &os, ckdb::KeySet *ks)
{
	ckdb::Key *cur;

	os << "ksNew " << ckdb::ksGetSize(ks) << std::endl;

	ksRewind(ks);
	while ((cur = ksNext(ks)) != 0)
	{
		size_t namesize = ckdb::keyGetNameSize(cur);
		size_t valuesize = ckdb::keyGetValueSize(cur);
		os << "keyNew " << namesize
		   << " " << valuesize << std::endl;
		os.write(ckdb::keyName(cur), namesize);
		os.write(static_cast<const char*>(ckdb::keyValue(cur)), valuesize);
		os << std::endl;

		const ckdb::Key *meta;
		ckdb::keyRewindMeta(cur);
		while ((meta = ckdb::keyNextMeta(cur)) != 0)
		{
			size_t metanamesize = ckdb::keyGetNameSize(meta);
			size_t metavaluesize = ckdb::keyGetValueSize(meta);

			os << "keyMeta " << metanamesize
			   << " " << metavaluesize << std::endl;
			os.write (ckdb::keyName(meta), metanamesize);
			os.write (static_cast<const char*>(ckdb::keyValue(meta)), metavaluesize);
			os << std::endl;
		}
		os << "keyEnd" << std::endl;
	}
	os << "ksEnd" << std::endl;
}

void unserialize(std::istream &is, ckdb::KeySet *ks)
{
	ckdb::Key *cur = 0;

	std::vector<char> namebuffer(4048);
	std::vector<char> valuebuffer(4048);
	std::string line;
	std::string command;
	size_t nrKeys;
	size_t namesize;
	size_t valuesize;

	while(std::getline (is, line))
	{
		std::stringstream ss (line);
		ss >> command;

		if (command == "ksNew")
		{
			ss >> nrKeys;

			ksClear(ks);
		}
		else if (command == "keyNew")
		{
			cur = ckdb::keyNew(0);

			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size()) namebuffer.resize(namesize);
			is.read(&namebuffer[0], namesize);
			namebuffer[namesize] = 0;
			ckdb::keySetName(cur, &namebuffer[0]);

			if (valuesize > valuebuffer.size()) valuebuffer.resize(valuesize);
			is.read(&valuebuffer[0], valuesize);
			ckdb::keySetRaw (cur, &valuebuffer[0], valuesize);
			std::getline (is, line);
		}
		else if (command == "keyMeta")
		{
			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size()) namebuffer.resize(namesize);
			is.read(&namebuffer[0], namesize);
			namebuffer[namesize] = 0;

			if (valuesize > valuebuffer.size()) valuebuffer.resize(valuesize);
			is.read(&valuebuffer[0], valuesize);

			keySetMeta (cur, &namebuffer[0], &valuebuffer[0]);
			std::getline (is, line);
		}
		else if (command == "keyEnd")
		{
			ckdb::keyClearSync(cur);
			ckdb::ksAppendKey(ks, cur);
			cur = 0;
		}
		else if (command == "ksEnd")
		{
			break;
		} else {
			std::cerr << "unkown command: " << command << std::endl;
		}
	}
}

int kdbOpen_dump(ckdb::KDB *handle)
{
	int errnosave = errno;
	ckdb::KeySet *ks;
	ckdb::Key *k;

	KDBCap * cap = ckdb::kdbhGetCapability(handle);
	cap->onlyFullGet=1;
	cap->onlyRemoveAll=1;
	cap->onlyAddKeys=1;
	cap->onlyFullSet=1;
	cap->onlySystem=1;
	cap->onlyUser=1;

	ks = ckdb::kdbhGetConfig (handle);
	ckdb::ksRewind (ks);
	while ((k = ckdb::ksNext (ks)) != 0)
	{
		const char *name;
		std::string f;
		size_t pos;

		name = ckdb::keyName(k);
		if (!name) continue;
		f = std::string(name);
		pos = f.find_last_of('/');
		std::string postfix = f.substr(pos);
		if (postfix == "/path") {
			ckdb::kdbhSetBackendData (handle, new std::string((char*)ckdb::keyValue(k)));
		}
	}
	if (!ckdb::kdbhGetBackendData (handle)) ckdb::kdbhSetBackendData (handle, new std::string(DUMP_PATH));

	errno = errnosave;
	return 0;
}

int kdbClose_dump(ckdb::KDB *handle)
{
	int errnosave = errno;

	delete static_cast<std::string*>(ckdb::kdbhGetBackendData (handle));

	errno = errnosave;
	return 0; /* success */
}

ssize_t kdbGet_dump(ckdb::KDB *handle, ckdb::KeySet *returned, const ckdb::Key *parentKey)
{
	int errnosave = errno;

	if (strcmp (keyName(kdbhGetMountpoint(handle)), keyName(parentKey))) return 0;

	std::ifstream ofs(static_cast<std::string*>(ckdb::kdbhGetBackendData (handle))->c_str());
	unserialize (ofs, returned);

	errno = errnosave;
	return ksGetSize(returned); /* success */
}

ssize_t kdbSet_dump(ckdb::KDB *handle, ckdb::KeySet *returned, const ckdb::Key *parentKey)
{
	int errnosave = errno;

	if (strcmp (keyName(kdbhGetMountpoint(handle)), keyName(parentKey))) return 0;

	std::ofstream ifs(static_cast<std::string*>(ckdb::kdbhGetBackendData (handle))->c_str());
	serialize (ifs, returned);

	errno = errnosave;
	return ksGetSize(returned);
}

ckdb::KDB *KDBEXPORT(dump)
{
	return kdbBackendExport(BACKENDNAME,
		KDB_BE_OPEN,	&kdbOpen_dump,
		KDB_BE_CLOSE,	&kdbClose_dump,
		KDB_BE_GET,	&kdbGet_dump,
		KDB_BE_SET,	&kdbSet_dump,
		KDB_BE_VERSION,        BACKENDVERSION,
		KDB_BE_AUTHOR,	"Full Name <email@libelektra.org>",
		KDB_BE_LICENCE,	"BSD",
		KDB_BE_DESCRIPTION,
			"Add description here",
		KDB_BE_END);
}

} // extern C

<|endoftext|>


<commit_before>// http://www.boost.org/doc/libs/1_47_0/libs/test/doc/html/utf/testing-tools/reference.html

#include <boost/test/unit_test.hpp>
#include "riak_client/cxx/riak_client.hpp"
#include "riak_client/cxx/easy.hpp"

#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

using namespace std;

namespace std
{
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}

/// Formatted string, allows to use stream operators and returns a std::string with the resulting format
#define fs(a) \
   (static_cast<const std::ostringstream&>(((*make_unique<std::ostringstream>().get()) << a)).str ())

namespace
{
int err_sys(std::string s)
{
    std::string err;
    char *err_str = std::strerror(errno);
    if (err_str)
        err = s + " error: " + std::strerror(errno)  + "\n";
    else
        err = s + " error: unknown (strerror returned NULL)\n";
    throw std::runtime_error(err);
}
}

/**
 * @author larroy
 * @addtogroup unit_tests
 * @{
 */

struct RiakTextFixture
{
    RiakTextFixture():
        m_pid(-1)
    {
        if ( (m_pid = fork()) > 0)
        {
            // waiting for the server to be started and stabilized
            sleep(1);
        }
        else if (m_pid == 0)
        {
            vector<char*> arglist;
            arglist.push_back(const_cast<char*>(s_riak_test_server_bin.c_str()));
            arglist.push_back(const_cast<char*>(s_port.c_str())); // 8087 is the one used by the real riak
            arglist.push_back(nullptr);

            cout << "Starting riak test server on port: " << s_port << endl;
            execvp(s_riak_test_server_bin.c_str(), &arglist[0]);
            perror("execvp");
            exit(EXIT_FAILURE);
        }
        else
        {
            throw std::runtime_error(fs("fork() error: " << m_pid));
        }
    }

    ~RiakTextFixture()
    {
        cout << "Sending SIGTERM to riak test server pid: " << m_pid << " ..." << flush;
        if (kill(m_pid, SIGTERM))
            err_sys(fs("kill" << m_pid << " failed"));
        int status = 0;
        if( waitpid(m_pid, &status, 0) < 0 )
        {
            perror("wait failed");
            exit(EXIT_FAILURE);
        }
        cout << "Done." << endl;
    }

    int m_pid;
    static const std::string s_port;
    static const std::string s_host;
    static const std::string s_riak_test_server_bin;
};

const std::string RiakTextFixture::s_port = "8086";
const std::string RiakTextFixture::s_host = "127.0.0.1"; // avoid using localhost as it might fail depending on resolver and interface status in Linux

#ifdef DEBUG
const std::string RiakTextFixture::s_riak_test_server_bin = "build/debug/riak_test_server";
#else
const std::string RiakTextFixture::s_riak_test_server_bin = "build/release/riak_test_server";
#endif

static const std::string TEST_BUCKET("riak-cxx-test");
static const std::string TEST_KEY("riak-cxx-test");

BOOST_GLOBAL_FIXTURE(RiakTextFixture);

BOOST_AUTO_TEST_CASE(riak_test_01)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    bool ping = c->ping();
    BOOST_REQUIRE(ping);
    c->client_id(42);
    BOOST_REQUIRE(c->client_id() == 42);
}

BOOST_AUTO_TEST_CASE (test_set_bucket)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::bucket_properties properties;
    properties.allow_mult(true);
    properties.n_val(3);
    BOOST_REQUIRE(c->set_bucket(TEST_BUCKET, properties) == true);
}

BOOST_AUTO_TEST_CASE (test_fetch_bucket)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::bucket_properties result = c->fetch_bucket(TEST_BUCKET);
    BOOST_REQUIRE(result.allow_mult());
    BOOST_REQUIRE(result.n_val() == 3);
}

BOOST_AUTO_TEST_CASE (test_put)
{
    //std::cout << riak::tss_client_id() << std::endl;
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    c->client_id(42);
    riak::store_params sp;
    sp.w(3).dw(3).return_body(true);
    riak::result_ptr fetch_result = c->fetch(TEST_BUCKET, TEST_KEY, 2);
    riak::object_ptr o;
    if (fetch_result->not_found())
    {
        o = riak::make_object(TEST_BUCKET, TEST_KEY, TEST_KEY);
        riak::link_vector v = o->update_content().links();
        v.push_back(riak::link("foo", "bar", "baz"));
        o->update_content().links(v);
    }
    else
        o = fetch_result->choose_sibling(0);
    riak::string_map usermeta(o->update_metadata().usermeta());
    usermeta["foo"] = "bar";
    riak::riak_metadata md(usermeta);
    o->update_metadata(md);
    riak::result_ptr r(c->store(o, sp));
    riak::object_ptr o2(r->choose_sibling(0));
}

BOOST_AUTO_TEST_CASE (test_fetch)
{
    riak::client_ptr c(riak::new_client("127.0.0.1", RiakTextFixture::s_port));
    riak::result_ptr fr(c->fetch(TEST_BUCKET, TEST_KEY, 3));
    BOOST_REQUIRE(fr->contents()[0].value() == TEST_KEY);
}

BOOST_AUTO_TEST_CASE (test_list_buckets)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::string_vector v = c->list_buckets();
    BOOST_REQUIRE(std::find(v.begin(), v.end(), TEST_BUCKET) != v.end());
}

BOOST_AUTO_TEST_CASE (test_list_keys)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::string_vector v = c->list_keys(TEST_BUCKET);
    BOOST_REQUIRE(v.size() > 0);
}

BOOST_AUTO_TEST_CASE (test_del)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::string_vector v = c->list_keys(TEST_BUCKET);
    for (riak::string_vector::size_type i=0;
         i < v.size(); ++i)
    {
        BOOST_REQUIRE(c->del(TEST_BUCKET, v[i], 3) == true);
    }
}

BOOST_AUTO_TEST_CASE (test_client)
{
    riak::cluster cluster(riak::node("127.0.0.1", RiakTextFixture::s_port));
    riak::client client(cluster.make_client());
    riak::basic_bucket<std::string> bucket = client.bucket<std::string>("bucket");
    bucket.del("foo").rw(2)();
    std::string value = bucket.fetch("foo").r(3)();
    BOOST_REQUIRE(value == "");
    value = bucket.store("foo", "bar")
        .r(2)
        .w(2)
        .dw(2)();
    value = bucket.fetch("foo").r(3)();
    BOOST_REQUIRE(value == "bar");
}

BOOST_AUTO_TEST_CASE(test_easy1)
{
    riak::easy::Client client(RiakTextFixture::s_host, RiakTextFixture::s_port);
}

BOOST_AUTO_TEST_CASE(test_easy2)
{
    riak::easy::Client client(RiakTextFixture::s_host, RiakTextFixture::s_port);
    string bucket = "test_easy2";
    string key = "key";
    string value = "value";
    BOOST_CHECK_EQUAL("", client.fetch_value(bucket, key));
}

BOOST_AUTO_TEST_CASE(test_easy3)
{
    riak::easy::Client client(RiakTextFixture::s_host, RiakTextFixture::s_port);
    string bucket = "test_easy3";
    string key = "key";
    string value = "value";
    client.put(bucket, key, value);
    BOOST_CHECK_EQUAL(value, client.fetch_value(bucket, key));
}

// TODO
#if 0
BOOST_AUTO_TEST_CASE (test_client2)
{
    riak::cluster cluster(riak::node("127.0.0.1", "8087"));
    riak::client client(cluster.make_client());
    riak::basic_bucket<std::string> bucket = client.bucket<std::string>("bucket");
    bucket.del("foo").rw(2)();
    std::string value = bucket.fetch("foo").r(3)();
    BOOST_REQUIRE(value == "");
    value = bucket.store("foo", "bar").w(1)();
    value = bucket.fetch("foo").r(3)();
    BOOST_REQUIRE(value == "bar");
}

#endif

/// @}
<commit_msg>check updating value on existing key<commit_after>// http://www.boost.org/doc/libs/1_47_0/libs/test/doc/html/utf/testing-tools/reference.html

#include <boost/test/unit_test.hpp>
#include "riak_client/cxx/riak_client.hpp"
#include "riak_client/cxx/easy.hpp"

#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>

using namespace std;

namespace std
{
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}

/// Formatted string, allows to use stream operators and returns a std::string with the resulting format
#define fs(a) \
   (static_cast<const std::ostringstream&>(((*make_unique<std::ostringstream>().get()) << a)).str ())

namespace
{
int err_sys(std::string s)
{
    std::string err;
    char *err_str = std::strerror(errno);
    if (err_str)
        err = s + " error: " + std::strerror(errno)  + "\n";
    else
        err = s + " error: unknown (strerror returned NULL)\n";
    throw std::runtime_error(err);
}
}

/**
 * @author larroy
 * @addtogroup unit_tests
 * @{
 */

struct RiakTextFixture
{
    RiakTextFixture():
        m_pid(-1)
    {
        if ( (m_pid = fork()) > 0)
        {
            // waiting for the server to be started and stabilized
            sleep(1);
        }
        else if (m_pid == 0)
        {
            vector<char*> arglist;
            arglist.push_back(const_cast<char*>(s_riak_test_server_bin.c_str()));
            arglist.push_back(const_cast<char*>(s_port.c_str())); // 8087 is the one used by the real riak
            arglist.push_back(nullptr);

            cout << "Starting riak test server on port: " << s_port << endl;
            execvp(s_riak_test_server_bin.c_str(), &arglist[0]);
            perror("execvp");
            exit(EXIT_FAILURE);
        }
        else
        {
            throw std::runtime_error(fs("fork() error: " << m_pid));
        }
    }

    ~RiakTextFixture()
    {
        cout << "Sending SIGTERM to riak test server pid: " << m_pid << " ..." << flush;
        if (kill(m_pid, SIGTERM))
            err_sys(fs("kill" << m_pid << " failed"));
        int status = 0;
        if( waitpid(m_pid, &status, 0) < 0 )
        {
            perror("wait failed");
            exit(EXIT_FAILURE);
        }
        cout << "Done." << endl;
    }

    int m_pid;
    static const std::string s_port;
    static const std::string s_host;
    static const std::string s_riak_test_server_bin;
};

const std::string RiakTextFixture::s_port = "8086";
const std::string RiakTextFixture::s_host = "127.0.0.1"; // avoid using localhost as it might fail depending on resolver and interface status in Linux

#ifdef DEBUG
const std::string RiakTextFixture::s_riak_test_server_bin = "build/debug/riak_test_server";
#else
const std::string RiakTextFixture::s_riak_test_server_bin = "build/release/riak_test_server";
#endif

static const std::string TEST_BUCKET("riak-cxx-test");
static const std::string TEST_KEY("riak-cxx-test");

BOOST_GLOBAL_FIXTURE(RiakTextFixture);

BOOST_AUTO_TEST_CASE(riak_test_01)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    bool ping = c->ping();
    BOOST_REQUIRE(ping);
    c->client_id(42);
    BOOST_REQUIRE(c->client_id() == 42);
}

BOOST_AUTO_TEST_CASE (test_set_bucket)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::bucket_properties properties;
    properties.allow_mult(true);
    properties.n_val(3);
    BOOST_REQUIRE(c->set_bucket(TEST_BUCKET, properties) == true);
}

BOOST_AUTO_TEST_CASE (test_fetch_bucket)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::bucket_properties result = c->fetch_bucket(TEST_BUCKET);
    BOOST_REQUIRE(result.allow_mult());
    BOOST_REQUIRE(result.n_val() == 3);
}

BOOST_AUTO_TEST_CASE (test_put)
{
    //std::cout << riak::tss_client_id() << std::endl;
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    c->client_id(42);
    riak::store_params sp;
    sp.w(3).dw(3).return_body(true);
    riak::result_ptr fetch_result = c->fetch(TEST_BUCKET, TEST_KEY, 2);
    riak::object_ptr o;
    if (fetch_result->not_found())
    {
        o = riak::make_object(TEST_BUCKET, TEST_KEY, TEST_KEY);
        riak::link_vector v = o->update_content().links();
        v.push_back(riak::link("foo", "bar", "baz"));
        o->update_content().links(v);
    }
    else
        o = fetch_result->choose_sibling(0);
    riak::string_map usermeta(o->update_metadata().usermeta());
    usermeta["foo"] = "bar";
    riak::riak_metadata md(usermeta);
    o->update_metadata(md);
    riak::result_ptr r(c->store(o, sp));
    riak::object_ptr o2(r->choose_sibling(0));
}

BOOST_AUTO_TEST_CASE (test_fetch)
{
    riak::client_ptr c(riak::new_client("127.0.0.1", RiakTextFixture::s_port));
    riak::result_ptr fr(c->fetch(TEST_BUCKET, TEST_KEY, 3));
    BOOST_REQUIRE(fr->contents()[0].value() == TEST_KEY);
}

BOOST_AUTO_TEST_CASE (test_list_buckets)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::string_vector v = c->list_buckets();
    BOOST_REQUIRE(std::find(v.begin(), v.end(), TEST_BUCKET) != v.end());
}

BOOST_AUTO_TEST_CASE (test_list_keys)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::string_vector v = c->list_keys(TEST_BUCKET);
    BOOST_REQUIRE(v.size() > 0);
}

BOOST_AUTO_TEST_CASE (test_del)
{
    riak::client_ptr c = riak::new_client("127.0.0.1", RiakTextFixture::s_port);
    riak::string_vector v = c->list_keys(TEST_BUCKET);
    for (riak::string_vector::size_type i=0;
         i < v.size(); ++i)
    {
        BOOST_REQUIRE(c->del(TEST_BUCKET, v[i], 3) == true);
    }
}

BOOST_AUTO_TEST_CASE (test_client)
{
    riak::cluster cluster(riak::node("127.0.0.1", RiakTextFixture::s_port));
    riak::client client(cluster.make_client());
    riak::basic_bucket<std::string> bucket = client.bucket<std::string>("bucket");
    bucket.del("foo").rw(2)();
    std::string value = bucket.fetch("foo").r(3)();
    BOOST_REQUIRE(value == "");
    value = bucket.store("foo", "bar")
        .r(2)
        .w(2)
        .dw(2)();
    value = bucket.fetch("foo").r(3)();
    BOOST_REQUIRE(value == "bar");
}

BOOST_AUTO_TEST_CASE(test_easy1)
{
    riak::easy::Client client(RiakTextFixture::s_host, RiakTextFixture::s_port);
}

BOOST_AUTO_TEST_CASE(test_easy2)
{
    riak::easy::Client client(RiakTextFixture::s_host, RiakTextFixture::s_port);
    string bucket = "test_easy2";
    string key = "key";
    string value = "value";
    BOOST_CHECK_EQUAL("", client.fetch_value(bucket, key));
}

BOOST_AUTO_TEST_CASE(test_easy3)
{
    riak::easy::Client client(RiakTextFixture::s_host, RiakTextFixture::s_port);
    string bucket = "test_easy3";
    string key = "key";
    string value = "value";
    client.put(bucket, key, value);
    BOOST_CHECK_EQUAL(value, client.fetch_value(bucket, key));
}

BOOST_AUTO_TEST_CASE(test_easy4)
{
    riak::easy::Client client(RiakTextFixture::s_host, RiakTextFixture::s_port);
    string bucket = "test_easy3";
    string key = "key";
    string value = "value2";
    client.put(bucket, key, value);
    BOOST_CHECK_EQUAL(value, client.fetch_value(bucket, key));
}

// TODO
#if 0
BOOST_AUTO_TEST_CASE (test_client2)
{
    riak::cluster cluster(riak::node("127.0.0.1", "8087"));
    riak::client client(cluster.make_client());
    riak::basic_bucket<std::string> bucket = client.bucket<std::string>("bucket");
    bucket.del("foo").rw(2)();
    std::string value = bucket.fetch("foo").r(3)();
    BOOST_REQUIRE(value == "");
    value = bucket.store("foo", "bar").w(1)();
    value = bucket.fetch("foo").r(3)();
    BOOST_REQUIRE(value == "bar");
}

#endif

/// @}
<|endoftext|>


<commit_before>#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include <roomba_clean_actions/basic_cleanAction.h>
#include <roomba_serial/SendButton.h>
#include <roomba_serial/SetMode.h>
#include <roomba_serial/Sensors.h>
#include <ctime>

class basic_cleanAction {
protected:
  ros::NodeHandle nh_;
  ros::ServiceClient client = nh_.serviceClient<roomba_serial::Sensors>("GetSensors");
  actionlib::SimpleActionServer<roomba_clean_actions::basic_cleanAction> cleanserv_;
  std::string action_name_;
  roomba_clean_actions::basic_cleanFeedback feedback_;
  roomba_clean_actions::basic_cleanResult result_;
  ros::Publisher button_pub = nh_.advertise<roomba_serial::SendButton>("BUTTON_OUT", 100);
  ros::Publisher mode_pub = nh_.advertise<roomba_serial::SetMode>("MODE_CHANGES", 100);

public:
  basic_cleanAction(std::string name) :
  cleanserv_(nh_, name, boost::bind(&basic_cleanAction::executeCB, this, _1), false), action_name_(name) {
    cleanserv_.start();
    ROS_INFO("Clean server started.");
  }

  ~basic_cleanAction(void) {
  }

  void executeCB(const roomba_clean_actions::basic_cleanGoalConstPtr &goal) {
    ROS_INFO("Got goal of %d seconds", goal->seconds);
    ros::Rate r(0.5);
    roomba_serial::SendButton dock;
    dock.buttoncode = 10;
    roomba_serial::Sensors sensorServer;
    int distance = 0;
    float charge;
    sensorServer.request.request = 0;
    bool success = true;
    time_t base = time(NULL);
    time_t curr = base;
    roomba_serial::SetMode mode;
    roomba_serial::SendButton button;
    mode.modecode = 2; // Safe mode, to start cleaning cycle
    button.buttoncode = 3;
    bool running = false;
    mode_pub.publish(mode);
    r.sleep();
    while(!running) {
      if(cleanserv_.isPreemptRequested() || !ros::ok()) {
        button_pub.publish(dock);
        ROS_INFO("%s: Preempted, now docking", action_name_.c_str());
        cleanserv_.setPreempted();
        success = false;
        break;
      }
      button_pub.publish(button);
      r.sleep();
      client.call(sensorServer);
      ROS_INFO("Current into battery is %d mA", sensorServer.response.current);
      for(int i = 0; i < 5; i++) {
        r.sleep();
      }
      running = (sensorServer.response.current < -100);
    }
    ROS_INFO("Roomba Away!");
    while(curr < base + goal->seconds) {
      if(cleanserv_.isPreemptRequested() || !ros::ok()) {
        button_pub.publish(dock);
        ROS_INFO("%s: Preempted, now docking", action_name_.c_str());
        cleanserv_.setPreempted();
        success = false;
        break;
      }
      curr = time(NULL);
      if(client.call(sensorServer)) {
        distance = distance + sensorServer.response.distance;
        charge = (float) (sensorServer.response.charge / sensorServer.response.capacity);
      }
      else {
        ROS_INFO("%s: Didn't get sensor response, sending stale data.", action_name_.c_str());
      }
      feedback_.seconds = (uint16_t) (curr - base);
      feedback_.millimeters = distance;
      feedback_.battery_charge = charge;
      cleanserv_.publishFeedback(feedback_);
      r.sleep();
    }
    mode_pub.publish(mode);
    r.sleep();
    button_pub.publish(dock);
    bool charging = false;
    while(!charging) {
      while(!client.call(sensorServer)) {r.sleep();}
      charging = (sensorServer.response.current > 0);
      feedback_.millimeters = distance + sensorServer.response.distance;
      feedback_.battery_charge = (float) (sensorServer.response.charge / sensorServer.response.capacity);
      feedback_.seconds = time(NULL) - base;
      cleanserv_.publishFeedback(feedback_);
      r.sleep();
    }
    result_.seconds = feedback_.seconds;
    result_.millimeters = feedback_.millimeters;
    result_.battery_charge = feedback_.battery_charge;
    cleanserv_.setSucceeded(result_);
  }
};

int main(int argc, char** argv) {
  ros::init(argc, argv, "basic_clean");
  basic_cleanAction bc(ros::this_node::getName());
  ros::spin();
}
<commit_msg>Revert "Made changes to use max length clean cycle."<commit_after>#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include <roomba_clean_actions/basic_cleanAction.h>
#include <roomba_serial/SendButton.h>
#include <roomba_serial/SetMode.h>
#include <roomba_serial/Sensors.h>
#include <ctime>

class basic_cleanAction {
protected:
  ros::NodeHandle nh_;
  ros::ServiceClient client = nh_.serviceClient<roomba_serial::Sensors>("GetSensors");
  actionlib::SimpleActionServer<roomba_clean_actions::basic_cleanAction> cleanserv_;
  std::string action_name_;
  roomba_clean_actions::basic_cleanFeedback feedback_;
  roomba_clean_actions::basic_cleanResult result_;
  ros::Publisher button_pub = nh_.advertise<roomba_serial::SendButton>("BUTTON_OUT", 100);
  ros::Publisher mode_pub = nh_.advertise<roomba_serial::SetMode>("MODE_CHANGES", 100);

public:
  basic_cleanAction(std::string name) :
  cleanserv_(nh_, name, boost::bind(&basic_cleanAction::executeCB, this, _1), false), action_name_(name) {
    cleanserv_.start();
    ROS_INFO("Clean server started.");
  }

  ~basic_cleanAction(void) {
  }

  void executeCB(const roomba_clean_actions::basic_cleanGoalConstPtr &goal) {
    ROS_INFO("Got goal of %d seconds", goal->seconds);
    ros::Rate r(0.5);
    roomba_serial::SendButton dock;
    dock.buttoncode = 10;
    roomba_serial::Sensors sensorServer;
    int distance = 0;
    float charge;
    sensorServer.request.request = 0;
    bool success = true;
    time_t base = time(NULL);
    time_t curr = base;
    roomba_serial::SetMode mode;
    roomba_serial::SendButton button;
    mode.modecode = 2; // Safe mode, to start cleaning cycle
    button.buttoncode = 2;
    bool running = false;
    mode_pub.publish(mode);
    r.sleep();
    while(!running) {
      if(cleanserv_.isPreemptRequested() || !ros::ok()) {
        button_pub.publish(dock);
        ROS_INFO("%s: Preempted, now docking", action_name_.c_str());
        cleanserv_.setPreempted();
        success = false;
        break;
      }
      button_pub.publish(button);
      r.sleep();
      client.call(sensorServer);
      ROS_INFO("Current into battery is %d mA", sensorServer.response.current);
      for(int i = 0; i < 5; i++) {
        r.sleep();
      }
      running = (sensorServer.response.current < -100);
    }
    ROS_INFO("Roomba Away!");
    while(curr < base + goal->seconds) {
      if(cleanserv_.isPreemptRequested() || !ros::ok()) {
        button_pub.publish(dock);
        ROS_INFO("%s: Preempted, now docking", action_name_.c_str());
        cleanserv_.setPreempted();
        success = false;
        break;
      }
      curr = time(NULL);
      if(client.call(sensorServer)) {
        distance = distance + sensorServer.response.distance;
        charge = (float) (sensorServer.response.charge / sensorServer.response.capacity);
      }
      else {
        ROS_INFO("%s: Didn't get sensor response, sending stale data.", action_name_.c_str());
      }
      feedback_.seconds = (uint16_t) (curr - base);
      feedback_.millimeters = distance;
      feedback_.battery_charge = charge;
      cleanserv_.publishFeedback(feedback_);
      r.sleep();
    }
    button_pub.publish(dock);
    bool charging = false;
    while(!charging) {
      while(!client.call(sensorServer)) {r.sleep();}
      charging = (sensorServer.response.current > 0);
      feedback_.millimeters = distance + sensorServer.response.distance;
      feedback_.battery_charge = (float) (sensorServer.response.charge / sensorServer.response.capacity);
      feedback_.seconds = time(NULL) - base;
      cleanserv_.publishFeedback(feedback_);
      r.sleep();
    }
    result_.seconds = feedback_.seconds;
    result_.millimeters = feedback_.millimeters;
    result_.battery_charge = feedback_.battery_charge;
    cleanserv_.setSucceeded(result_);
  }
};

int main(int argc, char** argv) {
  ros::init(argc, argv, "basic_clean");
  basic_cleanAction bc(ros::this_node::getName());
  ros::spin();
}
<|endoftext|>


<commit_before>//
//  src/utils/directory.cc
//  tbd
//
//  Created by inoahdev on 10/17/17.
//  Copyright © 2017 inoahdev. All rights reserved.
//

#include "directory.h"

namespace utils {
    directory::open_result directory::open(const char *path) {
        dir = opendir(path);
        if (!dir) {
            return open_result::failed_to_open_directory;
        }

        this->path = path;
        return open_result::ok;
    }

    directory::open_result directory::open(const std::string &path) {
        dir = opendir(path.data());
        if (!dir) {
            return open_result::failed_to_open_directory;
        }

        this->path = path;
        return open_result::ok;
    }

    directory::~directory() noexcept {
        if (dir != nullptr) {
            closedir(dir);
            dir = nullptr;
        }
    }
}
<commit_msg>Fix bug where directories would fail to open when recursing<commit_after>//
//  src/utils/directory.cc
//  tbd
//
//  Created by inoahdev on 10/17/17.
//  Copyright © 2017 inoahdev. All rights reserved.
//

#include "directory.h"

namespace utils {
    directory::open_result directory::open(const char *path) {
        this->path = path;
        this->dir = opendir(path);

        if (!dir) {
            return open_result::failed_to_open_directory;
        }

        return open_result::ok;
    }

    directory::open_result directory::open(const std::string &path) {
        this->path = path;
        this->dir = opendir(path.data());

        if (!dir) {
            return open_result::failed_to_open_directory;
        }

        return open_result::ok;
    }

    directory::~directory() noexcept {
        if (dir != nullptr) {
            closedir(dir);
            dir = nullptr;
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

/*
 * Session management.
 */

#pragma once

#include "Id.hxx"
#include "http/CookieJar.hxx"
#include "pool/Ptr.hxx"
#include "util/AllocatedArray.hxx"
#include "util/AllocatedString.hxx"
#include "util/Expiry.hxx"

#include <boost/intrusive/set.hpp>
#include <boost/intrusive/unordered_set_hook.hpp>

#include <chrono>

#include <string.h>

struct RealmSession;
struct HttpAddress;

/**
 * Session data associated with a widget instance (struct widget).
 */
struct WidgetSession
	: boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

	struct Compare {
		[[gnu::pure]]
		bool operator()(const WidgetSession &a, const WidgetSession &b) const noexcept {
			return strcmp(a.id.c_str(), b.id.c_str()) < 0;
		}

		[[gnu::pure]]
		bool operator()(const WidgetSession &a, const char *b) const noexcept {
			return strcmp(a.id.c_str(), b) < 0;
		}

		[[gnu::pure]]
		bool operator()(const char *a, const WidgetSession &b) const noexcept {
			return strcmp(a, b.id.c_str()) < 0;
		}
	};

	using Set = boost::intrusive::set<WidgetSession,
					  boost::intrusive::compare<Compare>,
					  boost::intrusive::constant_time_size<false>>;

	/** local id of this widget; must not be nullptr since widgets
	    without an id cannot have a session */
	const AllocatedString id;

	Set children;

	/** last relative URI */
	AllocatedString path_info;

	/** last query string */
	AllocatedString query_string;

	template<typename I>
	explicit WidgetSession(I &&_id) noexcept
		:id(std::forward<I>(_id)) {}

	~WidgetSession() noexcept;

	static void Attach(Set &dest, Set &&src) noexcept;
	void Attach(WidgetSession &&other) noexcept;

	[[gnu::pure]]
	WidgetSession *GetChild(const char *child_id, bool create) noexcept;
};

struct Session;

/**
 * A session associated with a user.
 */
struct RealmSession
	: boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

	static constexpr auto link_mode = boost::intrusive::normal_link;
	using LinkMode = boost::intrusive::link_mode<link_mode>;
	using SetHook = boost::intrusive::unordered_set_member_hook<LinkMode>;
	SetHook set_hook;

	SetHook by_attach_hook;

	Session &parent;

	struct Compare {
		[[gnu::pure]]
		bool operator()(const RealmSession &a, const RealmSession &b) const noexcept {
			return strcmp(a.realm.c_str(), b.realm.c_str()) < 0;
		}

		[[gnu::pure]]
		bool operator()(const RealmSession &a, const char *b) const noexcept {
			return strcmp(a.realm.c_str(), b) < 0;
		}

		[[gnu::pure]]
		bool operator()(const char *a, const RealmSession &b) const noexcept {
			return strcmp(a, b.realm.c_str()) < 0;
		}
	};

	/**
	 * The name of this session's realm.  It is always non-nullptr.
	 */
	const AllocatedString realm;

	/**
	 * The site name as provided by the translation server in the
	 * packet #TRANSLATE_SESSION_SITE.
	 */
	AllocatedString site;

	/** the user name which is logged in (nullptr if anonymous), provided
	    by the translation server */
	AllocatedString user;

	/** when will the #user attribute expire? */
	Expiry user_expires = Expiry::Never();

	/** a map of widget path to WidgetSession */
	WidgetSession::Set widgets;

	/** all cookies received by widget servers */
	CookieJar cookies;

	template<typename R>
	RealmSession(Session &_parent, R &&_realm) noexcept
		:parent(_parent),
		 realm(std::forward<R>(_realm))
	{
	}

	RealmSession(Session &_parent, RealmSession &&src) noexcept
		:parent(_parent),
		 realm(src.realm),
		 site(std::move(src.site)),
		 user(std::move(src.user)),
		 user_expires(src.user_expires),
		 widgets(std::move(src.widgets)),
		 cookies(std::move(src.cookies))
	{
	}

	~RealmSession() noexcept;

	void Attach(RealmSession &&other) noexcept;

	void ClearSite() noexcept {
		site = nullptr;
	}

	void SetSite(const char *_site) noexcept {
		site = _site;
	}

	/**
	 * @param max_age 0 = expires immediately; negative = never
	 * expires.
	 */
	void SetUser(const char *user, std::chrono::seconds max_age) noexcept;
	void ClearUser() noexcept {
		user = nullptr;
	}

	void Expire(Expiry now) noexcept;

	[[gnu::pure]]
	WidgetSession *GetWidget(const char *widget_id, bool create) noexcept;
};

struct Session {
	static constexpr auto link_mode = boost::intrusive::normal_link;
	using LinkMode = boost::intrusive::link_mode<link_mode>;
	using SetHook = boost::intrusive::unordered_set_member_hook<LinkMode>;
	SetHook set_hook;

	using ByAttachHook = boost::intrusive::unordered_set_member_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
	ByAttachHook by_attach_hook;

	/** identification number of this session */
	const SessionId id;

	/** a secret used to generate CSRF tokens */
	const SessionId csrf_salt;

	/** when will this session expire? */
	Expiry expires;

	/**
	 * Counts how often this session has been used.
	 */
	unsigned counter = 1;

	/** has a HTTP cookie with this session id already been sent? */
	bool cookie_sent = false;

	/** has a HTTP cookie with this session id already been received? */
	bool cookie_received = false;

	/** an opaque string for the translation server */
	AllocatedArray<std::byte> translate;

	AllocatedString recover;

	/** an opaque string for attaching sessions; if this is set,
	    then the session is in
	    SessionContainer::sessions_by_attach */
	AllocatedArray<std::byte> attach;

	/** optional  for the "Accept-Language" header, provided
	    by the translation server */
	AllocatedString language;

	PoolPtr external_manager_pool;

	/** @see #TRANSLATE_EXTERNAL_SESSION_MANAGER */
	HttpAddress *external_manager = nullptr;

	/** @see #TRANSLATE_EXTERNAL_SESSION_KEEPALIVE */
	std::chrono::duration<uint16_t> external_keepalive;

	std::chrono::steady_clock::time_point next_external_keepalive;

	using RealmSessionSet =
		boost::intrusive::set<RealmSession,
				      boost::intrusive::compare<RealmSession::Compare>,
				      boost::intrusive::constant_time_size<false>>;

	RealmSessionSet realms;

	Session(SessionId _id, SessionId _csrf_salt) noexcept;
	~Session() noexcept;

	/**
	 * Calculates the score for purging the session: higher score
	 * means more likely to be purged.
	 */
	[[gnu::pure]]
	unsigned GetPurgeScore() const noexcept;

	[[gnu::pure]]
	bool HasUser() const noexcept {
		for (auto &realm : realms)
			if (realm.user != nullptr)
				return true;

		return false;
	}

	void SetTranslate(std::span<const std::byte> translate) noexcept;
	void ClearTranslate() noexcept;

	/**
	 * @return true if the value modified
	 */
	bool SetRecover(const char *_recover) noexcept;

	/**
	 * Does this session have the specified "attach" value?
	 */
	[[gnu::pure]]
	bool IsAttach(std::span<const std::byte> other) const noexcept;

	void Attach(Session &&other) noexcept;

	void SetLanguage(const char *_language) noexcept {
		language = _language;
	}

	void ClearLanguage() noexcept {
		language = nullptr;
	}

	void SetExternalManager(const HttpAddress &address,
				std::chrono::steady_clock::time_point now,
				std::chrono::duration<uint16_t> keepalive) noexcept;

	void Expire(Expiry now) noexcept;

	[[gnu::pure]]
	RealmSession *GetRealm(const char *realm) noexcept;
};

/**
 * Deletes the session with the specified id.  The current process
 * must not hold a sssion lock.
 */
void
session_delete(SessionId id) noexcept;
<commit_msg>bp/session/Session: move RealmSession::realm in move ctor<commit_after>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

/*
 * Session management.
 */

#pragma once

#include "Id.hxx"
#include "http/CookieJar.hxx"
#include "pool/Ptr.hxx"
#include "util/AllocatedArray.hxx"
#include "util/AllocatedString.hxx"
#include "util/Expiry.hxx"

#include <boost/intrusive/set.hpp>
#include <boost/intrusive/unordered_set_hook.hpp>

#include <chrono>

#include <string.h>

struct RealmSession;
struct HttpAddress;

/**
 * Session data associated with a widget instance (struct widget).
 */
struct WidgetSession
	: boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

	struct Compare {
		[[gnu::pure]]
		bool operator()(const WidgetSession &a, const WidgetSession &b) const noexcept {
			return strcmp(a.id.c_str(), b.id.c_str()) < 0;
		}

		[[gnu::pure]]
		bool operator()(const WidgetSession &a, const char *b) const noexcept {
			return strcmp(a.id.c_str(), b) < 0;
		}

		[[gnu::pure]]
		bool operator()(const char *a, const WidgetSession &b) const noexcept {
			return strcmp(a, b.id.c_str()) < 0;
		}
	};

	using Set = boost::intrusive::set<WidgetSession,
					  boost::intrusive::compare<Compare>,
					  boost::intrusive::constant_time_size<false>>;

	/** local id of this widget; must not be nullptr since widgets
	    without an id cannot have a session */
	const AllocatedString id;

	Set children;

	/** last relative URI */
	AllocatedString path_info;

	/** last query string */
	AllocatedString query_string;

	template<typename I>
	explicit WidgetSession(I &&_id) noexcept
		:id(std::forward<I>(_id)) {}

	~WidgetSession() noexcept;

	static void Attach(Set &dest, Set &&src) noexcept;
	void Attach(WidgetSession &&other) noexcept;

	[[gnu::pure]]
	WidgetSession *GetChild(const char *child_id, bool create) noexcept;
};

struct Session;

/**
 * A session associated with a user.
 */
struct RealmSession
	: boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {

	static constexpr auto link_mode = boost::intrusive::normal_link;
	using LinkMode = boost::intrusive::link_mode<link_mode>;
	using SetHook = boost::intrusive::unordered_set_member_hook<LinkMode>;
	SetHook set_hook;

	SetHook by_attach_hook;

	Session &parent;

	struct Compare {
		[[gnu::pure]]
		bool operator()(const RealmSession &a, const RealmSession &b) const noexcept {
			return strcmp(a.realm.c_str(), b.realm.c_str()) < 0;
		}

		[[gnu::pure]]
		bool operator()(const RealmSession &a, const char *b) const noexcept {
			return strcmp(a.realm.c_str(), b) < 0;
		}

		[[gnu::pure]]
		bool operator()(const char *a, const RealmSession &b) const noexcept {
			return strcmp(a, b.realm.c_str()) < 0;
		}
	};

	/**
	 * The name of this session's realm.  It is always non-nullptr.
	 */
	const AllocatedString realm;

	/**
	 * The site name as provided by the translation server in the
	 * packet #TRANSLATE_SESSION_SITE.
	 */
	AllocatedString site;

	/** the user name which is logged in (nullptr if anonymous), provided
	    by the translation server */
	AllocatedString user;

	/** when will the #user attribute expire? */
	Expiry user_expires = Expiry::Never();

	/** a map of widget path to WidgetSession */
	WidgetSession::Set widgets;

	/** all cookies received by widget servers */
	CookieJar cookies;

	template<typename R>
	RealmSession(Session &_parent, R &&_realm) noexcept
		:parent(_parent),
		 realm(std::forward<R>(_realm))
	{
	}

	RealmSession(Session &_parent, RealmSession &&src) noexcept
		:parent(_parent),
		 realm(std::move(src.realm)),
		 site(std::move(src.site)),
		 user(std::move(src.user)),
		 user_expires(src.user_expires),
		 widgets(std::move(src.widgets)),
		 cookies(std::move(src.cookies))
	{
	}

	~RealmSession() noexcept;

	void Attach(RealmSession &&other) noexcept;

	void ClearSite() noexcept {
		site = nullptr;
	}

	void SetSite(const char *_site) noexcept {
		site = _site;
	}

	/**
	 * @param max_age 0 = expires immediately; negative = never
	 * expires.
	 */
	void SetUser(const char *user, std::chrono::seconds max_age) noexcept;
	void ClearUser() noexcept {
		user = nullptr;
	}

	void Expire(Expiry now) noexcept;

	[[gnu::pure]]
	WidgetSession *GetWidget(const char *widget_id, bool create) noexcept;
};

struct Session {
	static constexpr auto link_mode = boost::intrusive::normal_link;
	using LinkMode = boost::intrusive::link_mode<link_mode>;
	using SetHook = boost::intrusive::unordered_set_member_hook<LinkMode>;
	SetHook set_hook;

	using ByAttachHook = boost::intrusive::unordered_set_member_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>;
	ByAttachHook by_attach_hook;

	/** identification number of this session */
	const SessionId id;

	/** a secret used to generate CSRF tokens */
	const SessionId csrf_salt;

	/** when will this session expire? */
	Expiry expires;

	/**
	 * Counts how often this session has been used.
	 */
	unsigned counter = 1;

	/** has a HTTP cookie with this session id already been sent? */
	bool cookie_sent = false;

	/** has a HTTP cookie with this session id already been received? */
	bool cookie_received = false;

	/** an opaque string for the translation server */
	AllocatedArray<std::byte> translate;

	AllocatedString recover;

	/** an opaque string for attaching sessions; if this is set,
	    then the session is in
	    SessionContainer::sessions_by_attach */
	AllocatedArray<std::byte> attach;

	/** optional  for the "Accept-Language" header, provided
	    by the translation server */
	AllocatedString language;

	PoolPtr external_manager_pool;

	/** @see #TRANSLATE_EXTERNAL_SESSION_MANAGER */
	HttpAddress *external_manager = nullptr;

	/** @see #TRANSLATE_EXTERNAL_SESSION_KEEPALIVE */
	std::chrono::duration<uint16_t> external_keepalive;

	std::chrono::steady_clock::time_point next_external_keepalive;

	using RealmSessionSet =
		boost::intrusive::set<RealmSession,
				      boost::intrusive::compare<RealmSession::Compare>,
				      boost::intrusive::constant_time_size<false>>;

	RealmSessionSet realms;

	Session(SessionId _id, SessionId _csrf_salt) noexcept;
	~Session() noexcept;

	/**
	 * Calculates the score for purging the session: higher score
	 * means more likely to be purged.
	 */
	[[gnu::pure]]
	unsigned GetPurgeScore() const noexcept;

	[[gnu::pure]]
	bool HasUser() const noexcept {
		for (auto &realm : realms)
			if (realm.user != nullptr)
				return true;

		return false;
	}

	void SetTranslate(std::span<const std::byte> translate) noexcept;
	void ClearTranslate() noexcept;

	/**
	 * @return true if the value modified
	 */
	bool SetRecover(const char *_recover) noexcept;

	/**
	 * Does this session have the specified "attach" value?
	 */
	[[gnu::pure]]
	bool IsAttach(std::span<const std::byte> other) const noexcept;

	void Attach(Session &&other) noexcept;

	void SetLanguage(const char *_language) noexcept {
		language = _language;
	}

	void ClearLanguage() noexcept {
		language = nullptr;
	}

	void SetExternalManager(const HttpAddress &address,
				std::chrono::steady_clock::time_point now,
				std::chrono::duration<uint16_t> keepalive) noexcept;

	void Expire(Expiry now) noexcept;

	[[gnu::pure]]
	RealmSession *GetRealm(const char *realm) noexcept;
};

/**
 * Deletes the session with the specified id.  The current process
 * must not hold a sssion lock.
 */
void
session_delete(SessionId id) noexcept;
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestCxxFeatures.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

// .NAME TestCxxFeatures
// .SECTION Description
// Provides a reference for the set of C++ features that can be used
// by VTK.

#include "vtkConfigure.h"

//----------------------------------------------------------------------------

/* Check for known compilers.  */

#if defined(_MSC_VER)
# define VTK_CXX_MSVC
#endif

#if defined(__sgi) && !defined(__GNUC__) && !defined(_COMPILER_VERSION)
# define VTK_CXX_SGI_6
#endif

#if defined(__HP_aCC)
# define VTK_CXX_ACC
#endif

#if defined(__SUNPRO_CC)
# define VTK_CXX_SUNPRO
#endif

#if defined(__GNUC__) && (__GNUC__ < 3)
# if (__GNUC__ < 3)
#  define VTK_CXX_GCC_2
# elif (__GNUC__ == 3)
#  define VTK_CXX_GCC_3
# endif
#endif

//----------------------------------------------------------------------------

/* Check for known compiler limitations.  */

// Check for IRIX64-6.5-CC-o32 (old SGI compiler).
#if defined(VTK_CXX_SGI_6)
# define VTK_TYPENAME /* empty */
# define VTK_CLASS_TEMPLATE_SPECIALIZATION /* empty */
#endif

// Check for MSVC.
#if defined(VTK_CXX_MSVC)
# define VTK_TYPENAME /* empty */
#endif

// Assume standard behavior if symbol is not already defined.
#if !defined(VTK_TYPENAME)
# define VTK_TYPENAME typename
#endif

// Assume standard behavior if symbol is not already defined.
#if !defined(VTK_CLASS_TEMPLATE_SPECIALIZATION)
# define VTK_CLASS_TEMPLATE_SPECIALIZATION template <>
#endif

//----------------------------------------------------------------------------

#include "vtkSystemIncludes.h"

//----------------------------------------------------------------------------

/* Test inclusion of sstream header.  */
//#if !(defined(VTK_CXX_GCC_2) || defined(VTK_CXX_ACC) || defined(VTK_CXX_SGI_6))
#if defined(VTK_CXX_GCC_3)
# include <sstream>
#endif

//----------------------------------------------------------------------------

/* Test inclusion of some stl headers.  */
#include <vector>
#ifndef VTK_NO_STD_NAMESPACE
# define vtkstd std
#else
# define vtkstd
#endif

#if !defined(VTK_CXX_SGI_6)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
void UsingStdVector()
{
  using vtkstd::vector;
  vector<int>();
}
#endif

//----------------------------------------------------------------------------

/* Test full template specialization of functions.  */
template <class T>
int FullySpecializedFunction(T*)
{
  return 0;
}

#if !defined(VTK_CXX_SGI_6)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
template <>
int FullySpecializedFunction<int>(int*)
{
  return 1;
}
#else
// Let overload resolution pick this one instead.
int FullySpecializedFunction(int*)
{
  return 1;
}
#endif

int TestFullySpecializedFunction()
{
  int result = 1;
  int should_be_0 = FullySpecializedFunction(static_cast<float*>(0));
  if(should_be_0 != 0)
    {
    cerr << "FullySpecializedFunction<float*>() returned "
         << should_be_0 << ", not 0.\n";
    result = 0;
    }
  int should_be_1 = FullySpecializedFunction(static_cast<int*>(0));
  if(should_be_1 != 1)
    {
    cerr << "FullySpecializedFunction(int*) returned "
         << should_be_1 << ", not 1.\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test use of standard "bool" type and values.  */

#if !defined(VTK_CXX_SGI_6)
bool GetFalse()
{
  return false;
}

bool GetTrue()
{
  return true;
}

int TestBool()
{
  int result = 1;
  bool should_be_false = GetFalse();
  bool should_be_true = GetTrue();
  if(should_be_false)
    {
    cerr << "GetFalse() returned " << should_be_false << ", not false.\n";
    result = 0;
    }
  if(!should_be_true)
    {
    cerr << "GetTrue() returned " << should_be_true << ", not true.\n";
    result = 0;
    }
  return result;
}
#endif
//----------------------------------------------------------------------------

/* Test full template specialization of classes.  */

template <class T>
struct FullySpecializedClass
{
  static int Method() { return 0; }
  typedef T Type;
};

VTK_CLASS_TEMPLATE_SPECIALIZATION
struct FullySpecializedClass<float>
{
  static int Method() { return 1; }
  typedef int Type;
};

template <class T>
int TestFullySpecializedClassTrait(T*)
{
  typedef VTK_TYPENAME FullySpecializedClass<T>::Type Type;
  if(static_cast<Type>(3.1) == 3.1)
    {
    return 0;
    }
  return 1;
}

int TestFullySpecializedClass()
{
  int result = 1;
  int should_be_0 = FullySpecializedClass<int>::Method();
  if(should_be_0 != 0)
    {
    cerr << "FullySpecializedClass<int>::Method() returned "
         << should_be_0 << ", not 0.\n";
    result = 0;
    }
  int should_be_1 = FullySpecializedClass<float>::Method();
  if(should_be_1 != 1)
    {
    cerr << "FullySpecializedClass<float>::Method() returned "
         << should_be_1 << ", not 1.\n";
    result = 0;
    }
  if(!TestFullySpecializedClassTrait(static_cast<float*>(0)))
    {
    cerr << "Trait lookup of float didn't produce int.";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test if(int x = f()) style scoping.  */

int TestIfScopeHelper(int i)
{
  int result = 1;
  if(int x = i)
    {
    if(x != i)
      {
      cerr << "TestIfScope: x != " << i << "\n";
      result = 0;
      }
    }
  else
    {
    if(x != i)
      {
      cerr << "TestIfScope: x != " << i << "\n";
      result = 0;
      }
    }
  int x = result;
  return x;
}

int TestIfScope()
{
  int result = 1;
  if(!TestIfScopeHelper(1))
    {
    result = 0;
    }
  if(!TestIfScopeHelper(0))
    {
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test non-type template parameter.  */

template <int I>
struct NonTypeTemplate
{
  static int GetValue() { return I; }
};

int TestNonTypeTemplate()
{
  int result = 1;
  if(NonTypeTemplate<0>::GetValue() != 0)
    {
    cerr << "NonTypeTemplate<0>::GetValue() != 0\n";
    result = 0;
    }
  if(NonTypeTemplate<1>::GetValue() != 1)
    {
    cerr << "NonTypeTemplate<1>::GetValue() != 1\n";
    result = 0;
    }
  if(NonTypeTemplate<2>::GetValue() != 2)
    {
    cerr << "NonTypeTemplate<2>::GetValue() != 2\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

#define DO_TEST(x) \
  if(x()) { cout << "Passed: " #x "\n"; } \
  else { cout << "Failed: " #x "\n"; result = 1; }

int main()
{
  int result = 0;
  DO_TEST(TestFullySpecializedFunction);
#if !defined(VTK_CXX_SGI_6)
  DO_TEST(TestBool);
#endif
  DO_TEST(TestFullySpecializedClass);
  DO_TEST(TestIfScope);
  DO_TEST(TestNonTypeTemplate);
  return result;
}
<commit_msg>ERR: Fully specialized functions do not work on SGI's new compiler.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestCxxFeatures.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

// .NAME TestCxxFeatures
// .SECTION Description
// Provides a reference for the set of C++ features that can be used
// by VTK.

#include "vtkConfigure.h"

//----------------------------------------------------------------------------

/* Check for known compilers.  */

#if defined(_MSC_VER)
# define VTK_CXX_MSVC
#endif

#if defined(__sgi) && !defined(__GNUC__)
# define VTK_CXX_SGI
# if !defined(_COMPILER_VERSION)
#  define VTK_CXX_SGI_6
# endif
#endif

#if defined(__HP_aCC)
# define VTK_CXX_ACC
#endif

#if defined(__SUNPRO_CC)
# define VTK_CXX_SUNPRO
#endif

#if defined(__GNUC__) && (__GNUC__ < 3)
# if (__GNUC__ < 3)
#  define VTK_CXX_GCC_2
# elif (__GNUC__ == 3)
#  define VTK_CXX_GCC_3
# endif
#endif

//----------------------------------------------------------------------------

/* Check for known compiler limitations.  */

// Check for IRIX64-6.5-CC-o32 (old SGI compiler).
#if defined(VTK_CXX_SGI_6)
# define VTK_TYPENAME /* empty */
# define VTK_CLASS_TEMPLATE_SPECIALIZATION /* empty */
#endif

// Check for MSVC.
#if defined(VTK_CXX_MSVC)
# define VTK_TYPENAME /* empty */
#endif

// Assume standard behavior if symbol is not already defined.
#if !defined(VTK_TYPENAME)
# define VTK_TYPENAME typename
#endif

// Assume standard behavior if symbol is not already defined.
#if !defined(VTK_CLASS_TEMPLATE_SPECIALIZATION)
# define VTK_CLASS_TEMPLATE_SPECIALIZATION template <>
#endif

//----------------------------------------------------------------------------

#include "vtkSystemIncludes.h"

//----------------------------------------------------------------------------

/* Test inclusion of sstream header.  */
//#if !(defined(VTK_CXX_GCC_2) || defined(VTK_CXX_ACC) || defined(VTK_CXX_SGI_6))
#if defined(VTK_CXX_GCC_3)
# include <sstream>
#endif

//----------------------------------------------------------------------------

/* Test inclusion of some stl headers.  */
#include <vector>
#ifndef VTK_NO_STD_NAMESPACE
# define vtkstd std
#else
# define vtkstd
#endif

#if !defined(VTK_CXX_SGI_6)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
void UsingStdVector()
{
  using vtkstd::vector;
  vector<int>();
}
#endif

//----------------------------------------------------------------------------

/* Test full template specialization of functions.  */
template <class T>
int FullySpecializedFunction(T*)
{
  return 0;
}

#if !defined(VTK_CXX_SGI)
// Fails on kulu.crd IRIX64-6.5-CC-o32 (old SGI compiler).
// Fails on manifold.crd IRIX64-6.5-CC-n32 (new SGI compiler).
template <>
int FullySpecializedFunction<int>(int*)
{
  return 1;
}
#else
// Let overload resolution pick this one instead.
int FullySpecializedFunction(int*)
{
  return 1;
}
#endif

int TestFullySpecializedFunction()
{
  int result = 1;
  int should_be_0 = FullySpecializedFunction(static_cast<float*>(0));
  if(should_be_0 != 0)
    {
    cerr << "FullySpecializedFunction<float*>() returned "
         << should_be_0 << ", not 0.\n";
    result = 0;
    }
  int should_be_1 = FullySpecializedFunction(static_cast<int*>(0));
  if(should_be_1 != 1)
    {
    cerr << "FullySpecializedFunction(int*) returned "
         << should_be_1 << ", not 1.\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test use of standard "bool" type and values.  */

#if !defined(VTK_CXX_SGI_6)
bool GetFalse()
{
  return false;
}

bool GetTrue()
{
  return true;
}

int TestBool()
{
  int result = 1;
  bool should_be_false = GetFalse();
  bool should_be_true = GetTrue();
  if(should_be_false)
    {
    cerr << "GetFalse() returned " << should_be_false << ", not false.\n";
    result = 0;
    }
  if(!should_be_true)
    {
    cerr << "GetTrue() returned " << should_be_true << ", not true.\n";
    result = 0;
    }
  return result;
}
#endif
//----------------------------------------------------------------------------

/* Test full template specialization of classes.  */

template <class T>
struct FullySpecializedClass
{
  static int Method() { return 0; }
  typedef T Type;
};

VTK_CLASS_TEMPLATE_SPECIALIZATION
struct FullySpecializedClass<float>
{
  static int Method() { return 1; }
  typedef int Type;
};

template <class T>
int TestFullySpecializedClassTrait(T*)
{
  typedef VTK_TYPENAME FullySpecializedClass<T>::Type Type;
  if(static_cast<Type>(3.1) == 3.1)
    {
    return 0;
    }
  return 1;
}

int TestFullySpecializedClass()
{
  int result = 1;
  int should_be_0 = FullySpecializedClass<int>::Method();
  if(should_be_0 != 0)
    {
    cerr << "FullySpecializedClass<int>::Method() returned "
         << should_be_0 << ", not 0.\n";
    result = 0;
    }
  int should_be_1 = FullySpecializedClass<float>::Method();
  if(should_be_1 != 1)
    {
    cerr << "FullySpecializedClass<float>::Method() returned "
         << should_be_1 << ", not 1.\n";
    result = 0;
    }
  if(!TestFullySpecializedClassTrait(static_cast<float*>(0)))
    {
    cerr << "Trait lookup of float didn't produce int.";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test if(int x = f()) style scoping.  */

int TestIfScopeHelper(int i)
{
  int result = 1;
  if(int x = i)
    {
    if(x != i)
      {
      cerr << "TestIfScope: x != " << i << "\n";
      result = 0;
      }
    }
  else
    {
    if(x != i)
      {
      cerr << "TestIfScope: x != " << i << "\n";
      result = 0;
      }
    }
  int x = result;
  return x;
}

int TestIfScope()
{
  int result = 1;
  if(!TestIfScopeHelper(1))
    {
    result = 0;
    }
  if(!TestIfScopeHelper(0))
    {
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

/* Test non-type template parameter.  */

template <int I>
struct NonTypeTemplate
{
  static int GetValue() { return I; }
};

int TestNonTypeTemplate()
{
  int result = 1;
  if(NonTypeTemplate<0>::GetValue() != 0)
    {
    cerr << "NonTypeTemplate<0>::GetValue() != 0\n";
    result = 0;
    }
  if(NonTypeTemplate<1>::GetValue() != 1)
    {
    cerr << "NonTypeTemplate<1>::GetValue() != 1\n";
    result = 0;
    }
  if(NonTypeTemplate<2>::GetValue() != 2)
    {
    cerr << "NonTypeTemplate<2>::GetValue() != 2\n";
    result = 0;
    }
  return result;
}

//----------------------------------------------------------------------------

#define DO_TEST(x) \
  if(x()) { cout << "Passed: " #x "\n"; } \
  else { cout << "Failed: " #x "\n"; result = 1; }

int main()
{
  int result = 0;
  DO_TEST(TestFullySpecializedFunction);
#if !defined(VTK_CXX_SGI_6)
  DO_TEST(TestBool);
#endif
  DO_TEST(TestFullySpecializedClass);
  DO_TEST(TestIfScope);
  DO_TEST(TestNonTypeTemplate);
  return result;
}
<|endoftext|>


<commit_before>#include <omp.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#include "CNN.h"

void Read_MNIST(char training_set_images[], char training_set_labels[], char test_set_images[], char test_set_labels[], int number_training, int number_test, double **input, double **target_output){
	FILE *file;

	if(file = fopen(training_set_images, "rb")){
		for(int h = 0, value;h < 4;h++){
			fread(&value, sizeof(int), 1, file);
		}
		for(int h = 0;h < number_training;h++){
			unsigned char pixel;

			for(int j = 0;j < 28 * 28;j++){
				fread(&pixel, sizeof(unsigned char), 1, file);
				input[h][j] = pixel / 255.0;
			}
		}
		fclose(file);
	}
	else{
		fprintf(stderr, "[Read_MNIST], %s not found\n", training_set_images);
	}

	if(file = fopen(training_set_labels, "rb")){
		for(int h = 0, value;h < 2;h++){
			fread(&value, sizeof(int), 1, file);
		}
		for(int h = 0;h < number_training;h++){
			unsigned char label;

			fread(&label, sizeof(unsigned char), 1, file);

			for(int j = 0;j < 10;j++){
				target_output[h][j] = (j == label);
			}
		}
		fclose(file);
	}
	else{
		fprintf(stderr, "[Read_MNIST], %s not found\n", training_set_labels);
	}

	if(file = fopen(test_set_images, "rb")){
		for(int h = 0, value;h < 4;h++){
			fread(&value, sizeof(int), 1, file);
		}
		for(int h = number_training;h < number_training + number_test;h++){
			unsigned char pixel;

			for(int j = 0;j < 28 * 28;j++){
				fread(&pixel, sizeof(unsigned char), 1, file);
				input[h][j] = pixel / 255.0;
			}
		}
		fclose(file);
	}
	else{
		fprintf(stderr, "[Read_MNIST], %s not found\n", test_set_images);
	}

	if(file = fopen(test_set_labels, "rb")){
		for(int h = 0, value;h < 2;h++){
			fread(&value, sizeof(int), 1, file);
		}
		for(int h = number_training;h < number_training + number_test;h++){
			unsigned char label;

			fread(&label, sizeof(unsigned char), 1, file);

			for(int j = 0;j < 10;j++){
				target_output[h][j] = (j == label);
			}
		}
		fclose(file);
	}
	else{
		fprintf(stderr, "[Read_MNIST], %s not found\n", test_set_labels);
	}
}

int main(){
	char *type_layer[] = {"MNIST", "Cbn", "Pmax", "Cbn", "Pmax", "Cbn", "Lce,sm"};

	int batch_size		 = 60;
	int length_map[]	 = {28,	24, 12,  8,  4,   1,  1};
	int number_map[]	 = { 1, 24, 24, 48, 48, 192, 10};
	int number_iteration = 100;
	int number_layer	 = sizeof(type_layer) / sizeof(type_layer[0]);
	int number_thread	 = 4;
	int number_training	 = 6000;
	int number_test		 = 1000;

	/* Training using the entire dataset takes more than 700 seconds per iteration on the i7-4790K with 4 threads.
	int number_training	 = 60000;
	int number_test		 = 10000;
	*/

	double epsilon		 = 0.001;
	double learning_rate = 0.005;

	double **input			= new double*[number_training + number_test];
	double **target_output	= new double*[number_training + number_test];

	Convolutional_Neural_Networks *CNN = new Convolutional_Neural_Networks(type_layer, number_layer, length_map, number_map);

	for(int h = 0;h < number_training + number_test;h++){
		input[h]		 = new double[number_map[0] * length_map[0] * length_map[0]];
		target_output[h] = new double[number_map[number_layer - 1]];
	}
	Read_MNIST("train-images.idx3-ubyte", "train-labels.idx1-ubyte", "t10k-images.idx3-ubyte", "t10k-labels.idx1-ubyte", number_training, number_test, input, target_output);

	CNN->Initialize_Parameter(0, 0.2, -0.1);
	omp_set_num_threads(number_thread);

	for(int h = 0, time = clock();h < number_iteration;h++){
		int number_correct[2] = {0, };

		double loss = CNN->Train(batch_size, number_training, epsilon, learning_rate, input, target_output);

		double *output = new double[number_map[number_layer - 1]];

		for(int i = 0;i < number_training + number_test;i++){
			int argmax;

			double max = 0;

			CNN->Test(input[i], output);

			for(int j = 0;j < number_map[number_layer - 1];j++){
				if(max < output[j]){
					argmax = j;
					max = output[j];
				}
			}
			number_correct[(i < number_training) ? (0):(1)] += (int)target_output[i][argmax];
		}
		printf("score: %d / %d, %d / %d  loss: %lf  step %d  %.2lf sec\n", number_correct[0], number_training, number_correct[1], number_test, loss, h + 1, (double)(clock() - time) / CLOCKS_PER_SEC);
		learning_rate *= 0.993;

		delete[] output;
	}

	for(int h = 0;h < number_training + number_test;h++){
		delete[] input[h];
		delete[] target_output[h];
	}
	delete[] input;
	delete[] target_output;
	delete CNN;

	return 0;
}
<commit_msg>Update main.cpp<commit_after>#include <omp.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#include "CNN.h"

void Read_MNIST(char training_set_images[], char training_set_labels[], char test_set_images[], char test_set_labels[], int number_training, int number_test, double **input, double **target_output){
	FILE *file;

	if(file = fopen(training_set_images, "rb")){
		for(int h = 0, value;h < 4;h++){
			fread(&value, sizeof(int), 1, file);
		}
		for(int h = 0;h < number_training;h++){
			unsigned char pixel;

			for(int j = 0;j < 28 * 28;j++){
				fread(&pixel, sizeof(unsigned char), 1, file);
				input[h][j] = pixel / 255.0;
			}
		}
		fclose(file);
	}
	else{
		fprintf(stderr, "[Read_MNIST], %s not found\n", training_set_images);
	}

	if(file = fopen(training_set_labels, "rb")){
		for(int h = 0, value;h < 2;h++){
			fread(&value, sizeof(int), 1, file);
		}
		for(int h = 0;h < number_training;h++){
			unsigned char label;

			fread(&label, sizeof(unsigned char), 1, file);

			for(int j = 0;j < 10;j++){
				target_output[h][j] = (j == label);
			}
		}
		fclose(file);
	}
	else{
		fprintf(stderr, "[Read_MNIST], %s not found\n", training_set_labels);
	}

	if(file = fopen(test_set_images, "rb")){
		for(int h = 0, value;h < 4;h++){
			fread(&value, sizeof(int), 1, file);
		}
		for(int h = number_training;h < number_training + number_test;h++){
			unsigned char pixel;

			for(int j = 0;j < 28 * 28;j++){
				fread(&pixel, sizeof(unsigned char), 1, file);
				input[h][j] = pixel / 255.0;
			}
		}
		fclose(file);
	}
	else{
		fprintf(stderr, "[Read_MNIST], %s not found\n", test_set_images);
	}

	if(file = fopen(test_set_labels, "rb")){
		for(int h = 0, value;h < 2;h++){
			fread(&value, sizeof(int), 1, file);
		}
		for(int h = number_training;h < number_training + number_test;h++){
			unsigned char label;

			fread(&label, sizeof(unsigned char), 1, file);

			for(int j = 0;j < 10;j++){
				target_output[h][j] = (j == label);
			}
		}
		fclose(file);
	}
	else{
		fprintf(stderr, "[Read_MNIST], %s not found\n", test_set_labels);
	}
}

int main(){
	char *type_layer[] = {"MNIST", "Cbn", "Pmax", "Cbn", "Pmax", "Cbn", "Lce,sm"};

	int batch_size		 = 60;
	int length_map[]	 = {28,	24, 12,  8,  4,   1,  1};
	int number_map[]	 = { 1, 24, 24, 48, 48, 192, 10};
	int number_iteration = 100;
	int number_layer	 = sizeof(type_layer) / sizeof(type_layer[0]);
	int number_thread	 = 6;
	int number_training	 = 6000;
	int number_test		 = 1000;

	/* Training using the entire dataset takes about 400 seconds per iteration on the i7-4790K with 6 threads.
	int number_training	 = 60000;
	int number_test		 = 10000;
	*/

	double epsilon		 = 0.001;
	double learning_rate = 0.005;

	double **input			= new double*[number_training + number_test];
	double **target_output	= new double*[number_training + number_test];

	Convolutional_Neural_Networks *CNN = new Convolutional_Neural_Networks(type_layer, number_layer, length_map, number_map);

	for(int h = 0;h < number_training + number_test;h++){
		input[h]		 = new double[number_map[0] * length_map[0] * length_map[0]];
		target_output[h] = new double[number_map[number_layer - 1]];
	}
	Read_MNIST("train-images.idx3-ubyte", "train-labels.idx1-ubyte", "t10k-images.idx3-ubyte", "t10k-labels.idx1-ubyte", number_training, number_test, input, target_output);

	CNN->Initialize_Parameter(0, 0.2, -0.1);
	omp_set_num_threads(number_thread);

	for(int h = 0, time = clock();h < number_iteration;h++){
		int number_correct[2] = {0, };

		double loss = CNN->Train(batch_size, number_training, epsilon, learning_rate, input, target_output);

		double *output = new double[number_map[number_layer - 1]];

		for(int i = number_training;i < number_training + number_test;i++){
			int argmax;

			double max = 0;

			CNN->Test(input[i], output);

			for(int j = 0;j < number_map[number_layer - 1];j++){
				if(max < output[j]){
					argmax = j;
					max = output[j];
				}
			}
			number_correct[(i < number_training) ? (0):(1)] += (int)target_output[i][argmax];
		}
		printf("score: %d / %d, %d / %d  loss: %lf  step %d  %.2lf sec\n", number_correct[0], number_training, number_correct[1], number_test, loss, h + 1, (double)(clock() - time) / CLOCKS_PER_SEC);
		learning_rate *= 0.993;

		delete[] output;
	}

	for(int h = 0;h < number_training + number_test;h++){
		delete[] input[h];
		delete[] target_output[h];
	}
	delete[] input;
	delete[] target_output;
	delete CNN;

	return 0;
}
<|endoftext|>


<commit_before>/*
 Copyright (C) 2011 by Ivan Safrin

 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 "PolySceneMesh.h"
#include "PolyCoreServices.h"
#include "PolyBone.h"
#include "PolyMaterial.h"
#include "PolyPolygon.h"
#include "PolyRenderer.h"
#include "PolyMaterial.h"
#include "PolyMesh.h"
#include "PolyShader.h"
#include "PolySkeleton.h"
#include "PolyResourceManager.h"
#include "PolyMaterialManager.h"

using namespace Polycode;

SceneMesh::SceneMesh(const String& fileName) : SceneEntity(), texture(NULL), material(NULL) {
	mesh = new Mesh(fileName);
	bBoxRadius = mesh->getRadius();
	bBox = mesh->calculateBBox();
	skeleton = NULL;
	lightmapIndex=0;
	showVertexNormals = false;
	useVertexBuffer = false;
}

SceneMesh::SceneMesh(Mesh *mesh) : SceneEntity(), texture(NULL), material(NULL), skeleton(NULL), localShaderOptions(NULL) {
	this->mesh = mesh;
	bBoxRadius = mesh->getRadius();
	bBox = mesh->calculateBBox();
	lightmapIndex=0;
	showVertexNormals = false;
	useVertexBuffer = false;
}

SceneMesh::SceneMesh(int meshType) : texture(NULL), material(NULL) {
	mesh = new Mesh(meshType);
	bBoxRadius = mesh->getRadius();
	bBox = mesh->calculateBBox();
	skeleton = NULL;
	lightmapIndex=0;
	showVertexNormals = false;
	useVertexBuffer = false;
}

void SceneMesh::setMesh(Mesh *mesh) {
	this->mesh = mesh;
	bBoxRadius = mesh->getRadius();
	bBox = mesh->calculateBBox();
	showVertexNormals = false;
	useVertexBuffer = false;
}

SceneMesh::~SceneMesh() {
	delete mesh;
	delete texture;
	delete material;
	delete skeleton;
	delete localShaderOptions;
}

Mesh *SceneMesh::getMesh() {
	return mesh;
}

void SceneMesh::setTexture(Texture *texture) {
	this->texture = texture;
}

void SceneMesh::setMaterial(Material *material) {
	this->material = material;
	localShaderOptions = material->getShader(0)->createBinding();
	if(texture) {
		localShaderOptions->clearTexture("diffuse");
		localShaderOptions->addTexture("diffuse", texture);
	}

}

void SceneMesh::setMaterialByName(const String& materialName) {
	Material *material =  (Material*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_MATERIAL, materialName);
	if(!material)
		return;
	setMaterial(material);
}

Texture *SceneMesh::getTexture() {
	return texture;
}

void SceneMesh::loadTexture(const String& fileName, bool clamp) {
	texture = CoreServices::getInstance()->getMaterialManager()->createTextureFromFile(fileName, clamp);
}

ShaderBinding *SceneMesh::getLocalShaderOptions() {
	return localShaderOptions;
}

void SceneMesh::loadSkeleton(const String& fileName) {
	skeleton = new Skeleton(fileName);
	addEntity(skeleton);

	setSkeleton(skeleton);
}

void SceneMesh::setSkeleton(Skeleton *skeleton) {
	this->skeleton = skeleton;
	for(int i=0; i < mesh->getPolygonCount(); i++) {
		Polygon *polygon = mesh->getPolygon(i);
		unsigned int vCount = polygon->getVertexCount();
		for(int j=0; j < vCount; j++) {
			Vertex *vertex = polygon->getVertex(j);
			for(int k=0; k < vertex->getNumBoneAssignments(); k++) {
				vertex->getBoneAssignment(k)->bone = skeleton->getBone(vertex->getBoneAssignment(k)->boneID);
			}
		}
	}
}

Material *SceneMesh::getMaterial() {
	return material;
}

Skeleton *SceneMesh::getSkeleton() {
	return skeleton;
}

void SceneMesh::renderMeshLocally() {
	Renderer *renderer = CoreServices::getInstance()->getRenderer();

	if(skeleton) {
		for(int i=0; i < mesh->getPolygonCount(); i++) {
			Polygon *polygon = mesh->getPolygon(i);
			unsigned int vCount = polygon->getVertexCount();
			for(int j=0; j < vCount; j++) {
				Vertex *vert = polygon->getVertex(j);
				Vector3 norm;

					Vector3 aPos = vert->restPosition;
					Vector3 tPos;

					Number mult = 1;
/*
					Number mult = 0;
					for(int b =0; b < vert->getNumBoneAssignments(); b++) {
						BoneAssignment *bas = vert->getBoneAssignment(b);
						mult += bas->weight;
					}
					mult = 1.0f/mult;
*/
					for(int b =0; b < vert->getNumBoneAssignments(); b++) {
						BoneAssignment *bas = vert->getBoneAssignment(b);
						Bone *bone = bas->bone;
						if(bone) {

							Matrix4 restMatrix = bone->getRestMatrix();
							Matrix4 finalMatrix = bone->getFinalMatrix();

							Vector3 vec = restMatrix * aPos;
							tPos += finalMatrix * vec * (bas->weight*mult);

							Vector3 nvec = vert->restNormal;
							nvec = restMatrix.rotateVector(nvec);
							nvec = finalMatrix.rotateVector(nvec);

							norm += nvec * (bas->weight*mult);
						}
					}

					vert->x = tPos.x;
					vert->y = tPos.y;
					vert->z = tPos.z;

					norm.Normalize();
					vert->setNormal(norm.x, norm.y, norm.z);

			}
		}
		mesh->arrayDirtyMap[RenderDataArray::VERTEX_DATA_ARRAY] = true;
		mesh->arrayDirtyMap[RenderDataArray::NORMAL_DATA_ARRAY] = true;
		mesh->arrayDirtyMap[RenderDataArray::TANGENT_DATA_ARRAY] = true;
	}

	if(mesh->useVertexColors) {
		renderer->pushDataArrayForMesh(mesh, RenderDataArray::COLOR_DATA_ARRAY);
	}

	renderer->pushDataArrayForMesh(mesh, RenderDataArray::VERTEX_DATA_ARRAY);
	renderer->pushDataArrayForMesh(mesh, RenderDataArray::NORMAL_DATA_ARRAY);
	renderer->pushDataArrayForMesh(mesh, RenderDataArray::TANGENT_DATA_ARRAY);
	renderer->pushDataArrayForMesh(mesh, RenderDataArray::TEXCOORD_DATA_ARRAY);

	renderer->drawArrays(mesh->getMeshType());
}

void SceneMesh::cacheToVertexBuffer(bool cache) {

	if(cache && !mesh->hasVertexBuffer()) {
		CoreServices::getInstance()->getRenderer()->createVertexBufferForMesh(mesh);
	}
	useVertexBuffer = cache;
}

void SceneMesh::Render() {

	Renderer *renderer = CoreServices::getInstance()->getRenderer();

	if(material) {
		renderer->applyMaterial(material, localShaderOptions,0);
	} else {
		if(texture)
			renderer->setTexture(texture);
		else
			renderer->setTexture(NULL);
	}

	if(useVertexBuffer) {
		renderer->drawVertexBuffer(mesh->getVertexBuffer(), mesh->useVertexColors);
	} else {
		renderMeshLocally();
	}

	if(material)
		renderer->clearShader();

	if(showVertexNormals) {
		renderer->setTexture(NULL);
		/*
		for(int i=0; i < mesh->getPolygonCount(); i++) {
			Polygon *polygon = mesh->getPolygon(i);
			unsigned int vCount = polygon->getVertexCount();
			for(int j=0; j < vCount; j++) {
				Vertex *vert = polygon->getVertex(j);
				Vector3 norm = *vert->normal;
				CoreServices::getInstance()->getRenderer()->draw3DLine(*vert, norm, 0.4f, Color(0.0f,0.7f,1.0f,0.5f));
			}
		}
		 */
	}
}
<commit_msg>Fix crash bug in SceneMesh memory management<commit_after>/*
 Copyright (C) 2011 by Ivan Safrin

 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 "PolySceneMesh.h"
#include "PolyCoreServices.h"
#include "PolyBone.h"
#include "PolyMaterial.h"
#include "PolyPolygon.h"
#include "PolyRenderer.h"
#include "PolyMaterial.h"
#include "PolyMesh.h"
#include "PolyShader.h"
#include "PolySkeleton.h"
#include "PolyResourceManager.h"
#include "PolyMaterialManager.h"

using namespace Polycode;

SceneMesh::SceneMesh(const String& fileName) : SceneEntity(), texture(NULL), material(NULL), skeleton(NULL), localShaderOptions(NULL) {
	mesh = new Mesh(fileName);
	bBoxRadius = mesh->getRadius();
	bBox = mesh->calculateBBox();
	lightmapIndex=0;
	showVertexNormals = false;
	useVertexBuffer = false;
}

SceneMesh::SceneMesh(Mesh *mesh) : SceneEntity(), texture(NULL), material(NULL), skeleton(NULL), localShaderOptions(NULL) {
	this->mesh = mesh;
	bBoxRadius = mesh->getRadius();
	bBox = mesh->calculateBBox();
	lightmapIndex=0;
	showVertexNormals = false;
	useVertexBuffer = false;
}

SceneMesh::SceneMesh(int meshType) : texture(NULL), material(NULL), skeleton(NULL), localShaderOptions(NULL) {
	mesh = new Mesh(meshType);
	bBoxRadius = mesh->getRadius();
	bBox = mesh->calculateBBox();
	lightmapIndex=0;
	showVertexNormals = false;
	useVertexBuffer = false;
}

void SceneMesh::setMesh(Mesh *mesh) {
	this->mesh = mesh;
	bBoxRadius = mesh->getRadius();
	bBox = mesh->calculateBBox();
	showVertexNormals = false;
	useVertexBuffer = false;
}

SceneMesh::~SceneMesh() {
	delete mesh;
	delete texture;
	delete material;
	delete skeleton;
	delete localShaderOptions;
}

Mesh *SceneMesh::getMesh() {
	return mesh;
}

void SceneMesh::setTexture(Texture *texture) {
	this->texture = texture;
}

void SceneMesh::setMaterial(Material *material) {
	this->material = material;
	localShaderOptions = material->getShader(0)->createBinding();
	if(texture) {
		localShaderOptions->clearTexture("diffuse");
		localShaderOptions->addTexture("diffuse", texture);
	}

}

void SceneMesh::setMaterialByName(const String& materialName) {
	Material *material =  (Material*)CoreServices::getInstance()->getResourceManager()->getResource(Resource::RESOURCE_MATERIAL, materialName);
	if(!material)
		return;
	setMaterial(material);
}

Texture *SceneMesh::getTexture() {
	return texture;
}

void SceneMesh::loadTexture(const String& fileName, bool clamp) {
	texture = CoreServices::getInstance()->getMaterialManager()->createTextureFromFile(fileName, clamp);
}

ShaderBinding *SceneMesh::getLocalShaderOptions() {
	return localShaderOptions;
}

void SceneMesh::loadSkeleton(const String& fileName) {
	skeleton = new Skeleton(fileName);
	addEntity(skeleton);

	setSkeleton(skeleton);
}

void SceneMesh::setSkeleton(Skeleton *skeleton) {
	this->skeleton = skeleton;
	for(int i=0; i < mesh->getPolygonCount(); i++) {
		Polygon *polygon = mesh->getPolygon(i);
		unsigned int vCount = polygon->getVertexCount();
		for(int j=0; j < vCount; j++) {
			Vertex *vertex = polygon->getVertex(j);
			for(int k=0; k < vertex->getNumBoneAssignments(); k++) {
				vertex->getBoneAssignment(k)->bone = skeleton->getBone(vertex->getBoneAssignment(k)->boneID);
			}
		}
	}
}

Material *SceneMesh::getMaterial() {
	return material;
}

Skeleton *SceneMesh::getSkeleton() {
	return skeleton;
}

void SceneMesh::renderMeshLocally() {
	Renderer *renderer = CoreServices::getInstance()->getRenderer();

	if(skeleton) {
		for(int i=0; i < mesh->getPolygonCount(); i++) {
			Polygon *polygon = mesh->getPolygon(i);
			unsigned int vCount = polygon->getVertexCount();
			for(int j=0; j < vCount; j++) {
				Vertex *vert = polygon->getVertex(j);
				Vector3 norm;

					Vector3 aPos = vert->restPosition;
					Vector3 tPos;

					Number mult = 1;
/*
					Number mult = 0;
					for(int b =0; b < vert->getNumBoneAssignments(); b++) {
						BoneAssignment *bas = vert->getBoneAssignment(b);
						mult += bas->weight;
					}
					mult = 1.0f/mult;
*/
					for(int b =0; b < vert->getNumBoneAssignments(); b++) {
						BoneAssignment *bas = vert->getBoneAssignment(b);
						Bone *bone = bas->bone;
						if(bone) {

							Matrix4 restMatrix = bone->getRestMatrix();
							Matrix4 finalMatrix = bone->getFinalMatrix();

							Vector3 vec = restMatrix * aPos;
							tPos += finalMatrix * vec * (bas->weight*mult);

							Vector3 nvec = vert->restNormal;
							nvec = restMatrix.rotateVector(nvec);
							nvec = finalMatrix.rotateVector(nvec);

							norm += nvec * (bas->weight*mult);
						}
					}

					vert->x = tPos.x;
					vert->y = tPos.y;
					vert->z = tPos.z;

					norm.Normalize();
					vert->setNormal(norm.x, norm.y, norm.z);

			}
		}
		mesh->arrayDirtyMap[RenderDataArray::VERTEX_DATA_ARRAY] = true;
		mesh->arrayDirtyMap[RenderDataArray::NORMAL_DATA_ARRAY] = true;
		mesh->arrayDirtyMap[RenderDataArray::TANGENT_DATA_ARRAY] = true;
	}

	if(mesh->useVertexColors) {
		renderer->pushDataArrayForMesh(mesh, RenderDataArray::COLOR_DATA_ARRAY);
	}

	renderer->pushDataArrayForMesh(mesh, RenderDataArray::VERTEX_DATA_ARRAY);
	renderer->pushDataArrayForMesh(mesh, RenderDataArray::NORMAL_DATA_ARRAY);
	renderer->pushDataArrayForMesh(mesh, RenderDataArray::TANGENT_DATA_ARRAY);
	renderer->pushDataArrayForMesh(mesh, RenderDataArray::TEXCOORD_DATA_ARRAY);

	renderer->drawArrays(mesh->getMeshType());
}

void SceneMesh::cacheToVertexBuffer(bool cache) {

	if(cache && !mesh->hasVertexBuffer()) {
		CoreServices::getInstance()->getRenderer()->createVertexBufferForMesh(mesh);
	}
	useVertexBuffer = cache;
}

void SceneMesh::Render() {

	Renderer *renderer = CoreServices::getInstance()->getRenderer();

	if(material) {
		renderer->applyMaterial(material, localShaderOptions,0);
	} else {
		if(texture)
			renderer->setTexture(texture);
		else
			renderer->setTexture(NULL);
	}

	if(useVertexBuffer) {
		renderer->drawVertexBuffer(mesh->getVertexBuffer(), mesh->useVertexColors);
	} else {
		renderMeshLocally();
	}

	if(material)
		renderer->clearShader();

	if(showVertexNormals) {
		renderer->setTexture(NULL);
		/*
		for(int i=0; i < mesh->getPolygonCount(); i++) {
			Polygon *polygon = mesh->getPolygon(i);
			unsigned int vCount = polygon->getVertexCount();
			for(int j=0; j < vCount; j++) {
				Vertex *vert = polygon->getVertex(j);
				Vector3 norm = *vert->normal;
				CoreServices::getInstance()->getRenderer()->draw3DLine(*vert, norm, 0.4f, Color(0.0f,0.7f,1.0f,0.5f));
			}
		}
		 */
	}
}
<|endoftext|>