<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.
 */

#include "Client.hxx"
#include "Marshal.hxx"
#include "translation/Parser.hxx"
#include "translation/Request.hxx"
#include "translation/Response.hxx"
#include "translation/Handler.hxx"
#include "event/net/BufferedSocket.hxx"
#include "stopwatch.hxx"
#include "pool/pool.hxx"
#include "system/Error.hxx"
#include "util/Cancellable.hxx"
#include "util/Exception.hxx"
#include "lease.hxx"

#include <stdexcept>

#include <assert.h>
#include <string.h>

static const uint8_t PROTOCOL_VERSION = 3;

class TranslateClient final : BufferedSocketHandler, Cancellable {
	const StopwatchPtr stopwatch;

	BufferedSocket socket;
	LeasePtr lease_ref;

	/** the marshalled translate request */
	GrowingBufferReader request;

	TranslateHandler &handler;

	TranslateParser parser;

public:
	TranslateClient(AllocatorPtr alloc, EventLoop &event_loop,
			StopwatchPtr &&_stopwatch,
			SocketDescriptor fd, Lease &lease,
			const TranslateRequest &request2,
			GrowingBuffer &&_request,
			TranslateHandler &_handler,
			CancellablePointer &cancel_ptr) noexcept;

	bool TryWrite() noexcept;

private:
	void Destroy() noexcept {
		this->~TranslateClient();
	}

	void ReleaseSocket(bool reuse) noexcept;

	void Fail(std::exception_ptr ep) noexcept;

	BufferedResult Feed(std::span<const std::byte> src) noexcept;

	/* virtual methods from class BufferedSocketHandler */
	BufferedResult OnBufferedData() override {
		auto r = socket.ReadBuffer();
		assert(!r.empty());
		return Feed(r);
	}

	bool OnBufferedClosed() noexcept override {
		ReleaseSocket(false);
		return true;
	}

	bool OnBufferedWrite() override {
		return TryWrite();
	}

	void OnBufferedError(std::exception_ptr ep) noexcept override {
		Fail(NestException(ep,
				   std::runtime_error("Translation server connection failed")));
	}

	/* virtual methods from class Cancellable */
	void Cancel() noexcept override {
		stopwatch.RecordEvent("cancel");
		ReleaseSocket(false);
		Destroy();
	}
};

static constexpr auto translate_read_timeout = std::chrono::minutes(1);
static constexpr auto translate_write_timeout = std::chrono::seconds(10);

void
TranslateClient::ReleaseSocket(bool reuse) noexcept
{
	assert(socket.IsConnected());

	socket.Abandon();
	socket.Destroy();

	lease_ref.Release(reuse);
}

void
TranslateClient::Fail(std::exception_ptr ep) noexcept
{
	stopwatch.RecordEvent("error");

	ReleaseSocket(false);

	auto &_handler = handler;

	Destroy();

	_handler.OnTranslateError(ep);
}

/*
 * receive response
 *
 */

inline BufferedResult
TranslateClient::Feed(std::span<const std::byte> src) noexcept
try {
	while (!src.empty()) {
		size_t nbytes = parser.Feed(src);
		if (nbytes == 0)
			/* need more data */
			break;

		src = src.subspan(nbytes);
		socket.DisposeConsumed(nbytes);

		auto result = parser.Process();
		switch (result) {
		case TranslateParser::Result::MORE:
			break;

		case TranslateParser::Result::DONE:
			ReleaseSocket(true);

			{
				auto &_handler = handler;
				auto &response = parser.GetResponse();
				Destroy();
				_handler.OnTranslateResponse(response);
			}

			return BufferedResult::CLOSED;
		}
	}

	return BufferedResult::MORE;
} catch (...) {
	Fail(std::current_exception());
	return BufferedResult::CLOSED;
}

/*
 * send requests
 *
 */

bool
TranslateClient::TryWrite() noexcept
{
	auto src = request.Read();
	assert(!src.empty());

	ssize_t nbytes = socket.Write(src.data(), src.size());
	if (gcc_unlikely(nbytes < 0)) {
		if (gcc_likely(nbytes == WRITE_BLOCKING))
			return true;

		Fail(std::make_exception_ptr(MakeErrno("write error to translation server")));
		return false;
	}

	request.Consume(nbytes);
	if (request.IsEOF()) {
		/* the buffer is empty, i.e. the request has been sent */

		stopwatch.RecordEvent("request_end");

		socket.UnscheduleWrite();
		return socket.Read(true);
	}

	socket.ScheduleWrite();
	return true;
}

/*
 * constructor
 *
 */

inline
TranslateClient::TranslateClient(AllocatorPtr alloc, EventLoop &event_loop,
				 StopwatchPtr &&_stopwatch,
				 SocketDescriptor fd, Lease &lease,
				 const TranslateRequest &request2,
				 GrowingBuffer &&_request,
				 TranslateHandler &_handler,
				 CancellablePointer &cancel_ptr) noexcept
	:stopwatch(std::move(_stopwatch)),
	 socket(event_loop), lease_ref(lease),
	 request(std::move(_request)),
	 handler(_handler),
	 parser(alloc, request2, *alloc.New<TranslateResponse>())
{
	socket.Init(fd, FdType::FD_SOCKET,
		    translate_read_timeout,
		    translate_write_timeout,
		    *this);

	cancel_ptr = *this;

	socket.DeferWrite();
}

void
translate(AllocatorPtr alloc, EventLoop &event_loop,
	  StopwatchPtr stopwatch,
	  SocketDescriptor fd, Lease &lease,
	  const TranslateRequest &request,
	  TranslateHandler &handler,
	  CancellablePointer &cancel_ptr) noexcept
try {
	assert(fd.IsDefined());
	assert(request.uri != nullptr || request.widget_type != nullptr ||
	       request.http_auth.data() != nullptr ||
	       request.token_auth.data() != nullptr ||
	       request.chain.data() != nullptr ||
	       request.pool != nullptr ||
	       (request.content_type_lookup.data() != nullptr &&
		request.suffix != nullptr));

	GrowingBuffer gb = MarshalTranslateRequest(PROTOCOL_VERSION,
						   request);

	alloc.New<TranslateClient>(alloc, event_loop,
				   std::move(stopwatch),
				   fd, lease,
				   request, std::move(gb),
				   handler, cancel_ptr);
} catch (...) {
	lease.ReleaseLease(true);

	handler.OnTranslateError(std::current_exception());
}
<commit_msg>translation/Client: eliminate extra recvfrom() system call<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.
 */

#include "Client.hxx"
#include "Marshal.hxx"
#include "translation/Parser.hxx"
#include "translation/Request.hxx"
#include "translation/Response.hxx"
#include "translation/Handler.hxx"
#include "event/net/BufferedSocket.hxx"
#include "stopwatch.hxx"
#include "pool/pool.hxx"
#include "system/Error.hxx"
#include "util/Cancellable.hxx"
#include "util/Exception.hxx"
#include "lease.hxx"

#include <stdexcept>

#include <assert.h>
#include <string.h>

static const uint8_t PROTOCOL_VERSION = 3;

class TranslateClient final : BufferedSocketHandler, Cancellable {
	const StopwatchPtr stopwatch;

	BufferedSocket socket;
	LeasePtr lease_ref;

	/** the marshalled translate request */
	GrowingBufferReader request;

	TranslateHandler &handler;

	TranslateParser parser;

public:
	TranslateClient(AllocatorPtr alloc, EventLoop &event_loop,
			StopwatchPtr &&_stopwatch,
			SocketDescriptor fd, Lease &lease,
			const TranslateRequest &request2,
			GrowingBuffer &&_request,
			TranslateHandler &_handler,
			CancellablePointer &cancel_ptr) noexcept;

	bool TryWrite() noexcept;

private:
	void Destroy() noexcept {
		this->~TranslateClient();
	}

	void ReleaseSocket(bool reuse) noexcept;

	void Fail(std::exception_ptr ep) noexcept;

	BufferedResult Feed(std::span<const std::byte> src) noexcept;

	/* virtual methods from class BufferedSocketHandler */
	BufferedResult OnBufferedData() override {
		auto r = socket.ReadBuffer();
		assert(!r.empty());
		return Feed(r);
	}

	bool OnBufferedClosed() noexcept override {
		ReleaseSocket(false);
		return true;
	}

	bool OnBufferedWrite() override {
		return TryWrite();
	}

	void OnBufferedError(std::exception_ptr ep) noexcept override {
		Fail(NestException(ep,
				   std::runtime_error("Translation server connection failed")));
	}

	/* virtual methods from class Cancellable */
	void Cancel() noexcept override {
		stopwatch.RecordEvent("cancel");
		ReleaseSocket(false);
		Destroy();
	}
};

static constexpr auto translate_read_timeout = std::chrono::minutes(1);
static constexpr auto translate_write_timeout = std::chrono::seconds(10);

void
TranslateClient::ReleaseSocket(bool reuse) noexcept
{
	assert(socket.IsConnected());

	socket.Abandon();
	socket.Destroy();

	lease_ref.Release(reuse);
}

void
TranslateClient::Fail(std::exception_ptr ep) noexcept
{
	stopwatch.RecordEvent("error");

	ReleaseSocket(false);

	auto &_handler = handler;

	Destroy();

	_handler.OnTranslateError(ep);
}

/*
 * receive response
 *
 */

inline BufferedResult
TranslateClient::Feed(std::span<const std::byte> src) noexcept
try {
	while (!src.empty()) {
		size_t nbytes = parser.Feed(src);
		if (nbytes == 0)
			/* need more data */
			break;

		src = src.subspan(nbytes);
		socket.DisposeConsumed(nbytes);

		auto result = parser.Process();
		switch (result) {
		case TranslateParser::Result::MORE:
			break;

		case TranslateParser::Result::DONE:
			ReleaseSocket(true);

			{
				auto &_handler = handler;
				auto &response = parser.GetResponse();
				Destroy();
				_handler.OnTranslateResponse(response);
			}

			return BufferedResult::CLOSED;
		}
	}

	return BufferedResult::MORE;
} catch (...) {
	Fail(std::current_exception());
	return BufferedResult::CLOSED;
}

/*
 * send requests
 *
 */

bool
TranslateClient::TryWrite() noexcept
{
	auto src = request.Read();
	assert(!src.empty());

	ssize_t nbytes = socket.Write(src.data(), src.size());
	if (gcc_unlikely(nbytes < 0)) {
		if (gcc_likely(nbytes == WRITE_BLOCKING))
			return true;

		Fail(std::make_exception_ptr(MakeErrno("write error to translation server")));
		return false;
	}

	request.Consume(nbytes);
	if (request.IsEOF()) {
		/* the buffer is empty, i.e. the request has been sent */

		stopwatch.RecordEvent("request_end");

		socket.UnscheduleWrite();
		socket.ScheduleReadTimeout(true,
					   translate_read_timeout);
		return true;
	}

	socket.ScheduleWrite();
	return true;
}

/*
 * constructor
 *
 */

inline
TranslateClient::TranslateClient(AllocatorPtr alloc, EventLoop &event_loop,
				 StopwatchPtr &&_stopwatch,
				 SocketDescriptor fd, Lease &lease,
				 const TranslateRequest &request2,
				 GrowingBuffer &&_request,
				 TranslateHandler &_handler,
				 CancellablePointer &cancel_ptr) noexcept
	:stopwatch(std::move(_stopwatch)),
	 socket(event_loop), lease_ref(lease),
	 request(std::move(_request)),
	 handler(_handler),
	 parser(alloc, request2, *alloc.New<TranslateResponse>())
{
	socket.Init(fd, FdType::FD_SOCKET,
		    translate_read_timeout,
		    translate_write_timeout,
		    *this);

	cancel_ptr = *this;

	socket.DeferWrite();
}

void
translate(AllocatorPtr alloc, EventLoop &event_loop,
	  StopwatchPtr stopwatch,
	  SocketDescriptor fd, Lease &lease,
	  const TranslateRequest &request,
	  TranslateHandler &handler,
	  CancellablePointer &cancel_ptr) noexcept
try {
	assert(fd.IsDefined());
	assert(request.uri != nullptr || request.widget_type != nullptr ||
	       request.http_auth.data() != nullptr ||
	       request.token_auth.data() != nullptr ||
	       request.chain.data() != nullptr ||
	       request.pool != nullptr ||
	       (request.content_type_lookup.data() != nullptr &&
		request.suffix != nullptr));

	GrowingBuffer gb = MarshalTranslateRequest(PROTOCOL_VERSION,
						   request);

	alloc.New<TranslateClient>(alloc, event_loop,
				   std::move(stopwatch),
				   fd, lease,
				   request, std::move(gb),
				   handler, cancel_ptr);
} catch (...) {
	lease.ReleaseLease(true);

	handler.OnTranslateError(std::current_exception());
}
<|endoftext|>


<commit_before>/* configuration.cc
   Jeremy Barnesm, 18 February 2007
   Copyright (c) 2007 Jeremy Barnes.  All rights reserved.

   Configuration file parser.
*/

#include "configuration.h"
#include "parse_context.h"
#include "utils/string_functions.h"

using namespace std;

namespace ML {

/*****************************************************************************/
/* CONFIGURATION::DATA                                                       */
/*****************************************************************************/

struct Configuration::Data {
    typedef std::map<std::string, std::string> Entries;
    Entries entries;

    void copy_entries(const std::string & from,
                      const std::string & to)
    {
        //cerr << "** Copying entries from " << from << " to " << to << endl;

        if (to.find(from) == 0)
            throw Exception("Attempt to copy entries to within their tree");

        string from2 = from + ".";

        for (Entries::const_iterator it = entries.lower_bound(from);
             it != entries.end() && it->first.find(from2) == 0; ++it) {
            string rest(it->first, from2.size());
            string key = add_prefix(to, rest);
            entries[key] = it->second;

            //cerr << "copying " << it->first << "=" << it->second << " to "
            //     << key << endl;
        }
    }
};

/*****************************************************************************/
/* CONFIGURATION                                                             */
/*****************************************************************************/

Configuration::
Configuration()
    : data_(new Data()), prefix_(""), writeable_(true)
{
}

Configuration::
Configuration(const Configuration & other,
              const std::string & prefix,
              Prefix_Op op)
    : data_(other.data_), writeable_(false)
{
    if (op == PREFIX_REPLACE)
        prefix_ = prefix;
    else prefix_ = add_prefix(other.prefix(), prefix);

    //cerr << "created new config with prefix=" << prefix_ << " from "
    //     << other.prefix_ << endl;
}

Configuration::Accessor
Configuration::
operator [] (const std::string & key)
{
    string real_key = find_key(key, false /* find_parents */);
    return Accessor(this, real_key);
}

std::string
Configuration::
operator [] (const std::string & key) const
{
    string real_key = find_key(key, false /* find_parents */);
    return data_->entries[real_key];
}

bool
Configuration::
count(const std::string & key, bool search_parents) const
{
    string real_key = find_key(key, search_parents);
    return data_->entries.count(real_key);
}

namespace {

bool shorter_prefix(string & prefix)
{
    size_t pos = prefix.rfind('.');
    if (pos == string::npos) {
        if (prefix == "") return false;
        prefix = "";
        return true;
    }
    prefix = string(prefix, 0, pos);
    return true;
}

void lengthen(string & prefix, const std::string & name)
{
    if (prefix == "") prefix = name;
    else prefix += "." + name;
}

} // file scope

std::string
Configuration::
find_key(const std::string & key,
         bool search_parents) const
{
    //cerr << "find_key(" << key << ", " << search_parents << ")" << endl;

    /* If we search parents, then we look at succeedingly shorter prefixes
       until we find it. */

    string prefix = prefix_;

    do {
        string full = add_prefix(prefix, key);
        //cerr << " prefix = " << prefix << " full = " << full << endl;
        if (data_->entries.count(full)) {
            //cerr << "  --> found under " << full << endl;
            return full;
        }
    } while (search_parents && shorter_prefix(prefix));

    //cerr << "  --> not found" << endl;
    return add_prefix(prefix_, key);  // not found; return first location
}

void
Configuration::
load(const std::string & filename)
{
    Parse_Context context(filename);
    parse(context);
}

void
Configuration::
parse_string(const std::string & str, const std::string & filename)
{
    Parse_Context context(filename, str.c_str(), str.c_str() + str.size());
    parse(context);
}

namespace {

struct Found_End_Name {
    bool operator () (char c) const
    {
        if (isalnum(c) || c == '_' || c == '.') return false;
        return true;
    }
};

std::string expect_name(Parse_Context & context)
{
    std::string result;
    if (!context.match_text(result, Found_End_Name())
        || result.empty())
        context.exception("expected name of option");
    return result;
}

struct Found_End_Value {
    bool operator () (char c) const
    {
        return c == '\n' || c == ';' || c == ' ' || c == '\t';
    }
};

std::string expect_value(Parse_Context & context)
{
    std::string result;
    if (!context.match_text(result, Found_End_Value())
        || result.empty())
        context.exception("expected name of option");
    return result;
}

} // file scope

void
Configuration::
parse(Parse_Context & context)
{
    string scope;

    while (context) {
        //cerr << "scope = " << scope << endl;
        context.skip_whitespace();
        if (context.match_eol()) continue;  // blank line
        else if (context.match_literal('#')) {
            // comment
            context.skip_line();
            continue;
        }
        else if (context.match_literal('}')) {
            // end of scope
            //cerr << "end of scope = " << scope << endl;
            if (!shorter_prefix(scope))
                context.exception("configuration tried to close unopened "
                                  "scope");
            continue;
        }

        string name = expect_name(context);

        context.skip_whitespace();

        if (context.match_literal('=')) {
            context.skip_whitespace();
            string value = expect_value(context);

            context.match_literal(';');
            context.expect_eol();

            data_->entries[add_prefix(scope, name)] = value;
        }
        else if (context.match_literal(':')) {
            // start a new scope copying from another
            context.skip_whitespace();
            string copy_from = expect_name(context);
            context.skip_whitespace();
            context.expect_literal('{');
            lengthen(scope, name);

            data_->copy_entries(copy_from, scope);
        }
        else if (context.match_literal('{')) {
            // start a new scope
            lengthen(scope, name);
        }
        else context.exception("expected :, = or { after name");
    }

    if (!scope.empty()) {
        context.exception("configuration ended with scope " + scope
                          + " open");
    }
}

void
Configuration::
parse_command_line(const std::vector<std::string> & options)
{
    /* Each option should be in the form key=value.  We parse these simply. */
    if (!writeable_)
        throw Exception("Configuration::parse_command_line(): "
                        "object not writeable");

    for (unsigned i = 0;  i < options.size();  ++i) {
        parse_string(options[i],
                     format("command line:%d:\"%s\"", i, options[i].c_str()));
    }
}

std::string
Configuration::
add_prefix(const std::string & prefix, const std::string & rest)
{
    string result = prefix;
    lengthen(result, rest);
    return result;
}

void
Configuration::
raw_set(const std::string & key, const std::string & value)
{
    if (!writeable_)
        throw Exception("Configuration::operator []: "
                        "object is not writeable");

    data_->entries[key] = value;
}

std::string
Configuration::
raw_get(const std::string & key) const
{
    return data_->entries[key];
}

bool
Configuration::
raw_count(const std::string & key) const
{
    return data_->entries.count(key);
}

std::ostream &
operator << (std::ostream & stream, const Configuration::Accessor & acc)
{
    return stream << acc.operator std::string();
}

} // namespace ML
<commit_msg>allowed comments on end of line in configuration file<commit_after>/* configuration.cc
   Jeremy Barnesm, 18 February 2007
   Copyright (c) 2007 Jeremy Barnes.  All rights reserved.

   Configuration file parser.
*/

#include "configuration.h"
#include "parse_context.h"
#include "utils/string_functions.h"

using namespace std;

namespace ML {

/*****************************************************************************/
/* CONFIGURATION::DATA                                                       */
/*****************************************************************************/

struct Configuration::Data {
    typedef std::map<std::string, std::string> Entries;
    Entries entries;

    void copy_entries(const std::string & from,
                      const std::string & to)
    {
        //cerr << "** Copying entries from " << from << " to " << to << endl;

        if (to.find(from) == 0)
            throw Exception("Attempt to copy entries to within their tree");

        string from2 = from + ".";

        for (Entries::const_iterator it = entries.lower_bound(from);
             it != entries.end() && it->first.find(from2) == 0; ++it) {
            string rest(it->first, from2.size());
            string key = add_prefix(to, rest);
            entries[key] = it->second;

            //cerr << "copying " << it->first << "=" << it->second << " to "
            //     << key << endl;
        }
    }
};

/*****************************************************************************/
/* CONFIGURATION                                                             */
/*****************************************************************************/

Configuration::
Configuration()
    : data_(new Data()), prefix_(""), writeable_(true)
{
}

Configuration::
Configuration(const Configuration & other,
              const std::string & prefix,
              Prefix_Op op)
    : data_(other.data_), writeable_(false)
{
    if (op == PREFIX_REPLACE)
        prefix_ = prefix;
    else prefix_ = add_prefix(other.prefix(), prefix);

    //cerr << "created new config with prefix=" << prefix_ << " from "
    //     << other.prefix_ << endl;
}

Configuration::Accessor
Configuration::
operator [] (const std::string & key)
{
    string real_key = find_key(key, false /* find_parents */);
    return Accessor(this, real_key);
}

std::string
Configuration::
operator [] (const std::string & key) const
{
    string real_key = find_key(key, false /* find_parents */);
    return data_->entries[real_key];
}

bool
Configuration::
count(const std::string & key, bool search_parents) const
{
    string real_key = find_key(key, search_parents);
    return data_->entries.count(real_key);
}

namespace {

bool shorter_prefix(string & prefix)
{
    size_t pos = prefix.rfind('.');
    if (pos == string::npos) {
        if (prefix == "") return false;
        prefix = "";
        return true;
    }
    prefix = string(prefix, 0, pos);
    return true;
}

void lengthen(string & prefix, const std::string & name)
{
    if (prefix == "") prefix = name;
    else prefix += "." + name;
}

} // file scope

std::string
Configuration::
find_key(const std::string & key,
         bool search_parents) const
{
    //cerr << "find_key(" << key << ", " << search_parents << ")" << endl;

    /* If we search parents, then we look at succeedingly shorter prefixes
       until we find it. */

    string prefix = prefix_;

    do {
        string full = add_prefix(prefix, key);
        //cerr << " prefix = " << prefix << " full = " << full << endl;
        if (data_->entries.count(full)) {
            //cerr << "  --> found under " << full << endl;
            return full;
        }
    } while (search_parents && shorter_prefix(prefix));

    //cerr << "  --> not found" << endl;
    return add_prefix(prefix_, key);  // not found; return first location
}

void
Configuration::
load(const std::string & filename)
{
    Parse_Context context(filename);
    parse(context);
}

void
Configuration::
parse_string(const std::string & str, const std::string & filename)
{
    Parse_Context context(filename, str.c_str(), str.c_str() + str.size());
    parse(context);
}

namespace {

struct Found_End_Name {
    bool operator () (char c) const
    {
        if (isalnum(c) || c == '_' || c == '.') return false;
        return true;
    }
};

std::string expect_name(Parse_Context & context)
{
    std::string result;
    if (!context.match_text(result, Found_End_Name())
        || result.empty())
        context.exception("expected name of option");
    return result;
}

struct Found_End_Value {
    bool operator () (char c) const
    {
        return c == '\n' || c == ';' || c == ' ' || c == '\t';
    }
};

std::string expect_value(Parse_Context & context)
{
    std::string result;
    if (!context.match_text(result, Found_End_Value())
        || result.empty())
        context.exception("expected name of option");
    return result;
}

} // file scope

void
Configuration::
parse(Parse_Context & context)
{
    string scope;

    while (context) {
        //cerr << "scope = " << scope << endl;
        context.skip_whitespace();
        if (context.match_eol()) continue;  // blank line
        else if (context.match_literal('#')) {
            // comment
            context.skip_line();
            continue;
        }
        else if (context.match_literal('}')) {
            // end of scope
            //cerr << "end of scope = " << scope << endl;
            if (!shorter_prefix(scope))
                context.exception("configuration tried to close unopened "
                                  "scope");
            continue;
        }

        string name = expect_name(context);

        context.skip_whitespace();

        if (context.match_literal('=')) {
            context.skip_whitespace();
            string value = expect_value(context);

            context.match_literal(';');
            context.skip_whitespace();
            if (context.match_literal('#'))
                context.expect_text('\n', true, "expected comment");

            context.expect_eol();

            data_->entries[add_prefix(scope, name)] = value;
        }
        else if (context.match_literal(':')) {
            // start a new scope copying from another
            context.skip_whitespace();
            string copy_from = expect_name(context);
            context.skip_whitespace();
            context.expect_literal('{');
            lengthen(scope, name);

            data_->copy_entries(copy_from, scope);
        }
        else if (context.match_literal('{')) {
            // start a new scope
            lengthen(scope, name);
        }
        else context.exception("expected :, = or { after name");
    }

    if (!scope.empty()) {
        context.exception("configuration ended with scope " + scope
                          + " open");
    }
}

void
Configuration::
parse_command_line(const std::vector<std::string> & options)
{
    /* Each option should be in the form key=value.  We parse these simply. */
    if (!writeable_)
        throw Exception("Configuration::parse_command_line(): "
                        "object not writeable");

    for (unsigned i = 0;  i < options.size();  ++i) {
        parse_string(options[i],
                     format("command line:%d:\"%s\"", i, options[i].c_str()));
    }
}

std::string
Configuration::
add_prefix(const std::string & prefix, const std::string & rest)
{
    string result = prefix;
    lengthen(result, rest);
    return result;
}

void
Configuration::
raw_set(const std::string & key, const std::string & value)
{
    if (!writeable_)
        throw Exception("Configuration::operator []: "
                        "object is not writeable");

    data_->entries[key] = value;
}

std::string
Configuration::
raw_get(const std::string & key) const
{
    return data_->entries[key];
}

bool
Configuration::
raw_count(const std::string & key) const
{
    return data_->entries.count(key);
}

std::ostream &
operator << (std::ostream & stream, const Configuration::Accessor & acc)
{
    return stream << acc.operator std::string();
}

} // namespace ML
<|endoftext|>


<commit_before>#include "memstorage.h"
#include "../utils/utils.h"
#include "../compression.h"
#include "../flags.h"
#include "subscribe.h"
#include "chunk.h"
#include "../timeutil.h"
#include "inner_readers.h"

#include <limits>
#include <algorithm>
#include <map>
#include <tuple>
#include <assert.h>
#include <mutex>
#include <atomic>

using namespace dariadb;
using namespace dariadb::compression;
using namespace dariadb::storage;

typedef std::map<Id, ChuncksList> ChunkMap;

class MemoryStorage::Private
{
public:
	Private(size_t size) :
		_size(size),
		_min_time(std::numeric_limits<dariadb::Time>::max()),
		_max_time(std::numeric_limits<dariadb::Time>::min()),
		_subscribe_notify(new SubscribeNotificator),
		_chunks_count(0)
	{
		_subscribe_notify->start();

	}

	~Private() {
		_subscribe_notify->stop();
		_chuncks.clear();
	}

	Time minTime() { return _min_time; }
	Time maxTime() { return _max_time; }

	Chunk_Ptr getFreeChunk(dariadb::Id id) {
		Chunk_Ptr resulted_chunk = nullptr;
		auto ch_iter = _free_chunks.find(id);
		if (ch_iter != _free_chunks.end()) {
			if (!ch_iter->second->is_full()) {
				return ch_iter->second;
			}
		}
		return resulted_chunk;
	}

	Chunk_Ptr make_chunk(dariadb::Meas first) {
		auto ptr = new Chunk(_size, first);
		auto chunk = Chunk_Ptr{ ptr };
		this->_chuncks[first.id].push_back(chunk);
		this->_free_chunks[first.id] = chunk;
		_chunks_count++;
		return chunk;
	}

	append_result append(const Meas& value) {
		std::lock_guard<std::mutex> lg(_mutex);

		Chunk_Ptr chunk = this->getFreeChunk(value.id);

		if (chunk == nullptr) {
			chunk=make_chunk(value);
		}
		else {
            //std::cout<<"append new "<<chunk->count<< " chunks: "<<this->chunks_total_size()<<std::endl;
			if (!chunk->append(value)) {
				assert(chunk->is_full());
				chunk = make_chunk(value);
			}
		}

		assert(chunk->last.time == value.time);

		_min_time = std::min(_min_time, value.time);
		_max_time = std::max(_max_time, value.time);

		_subscribe_notify->on_append(value);

		return dariadb::append_result(1, 0);
	}

	append_result append(const Meas::PMeas begin, const size_t size) {
		dariadb::append_result result{};
		for (size_t i = 0; i < size; i++) {
			result = result + append(begin[i]);
		}
		return result;

	}

    size_t size()const { return _size; }
	size_t chunks_size()const { return _chuncks.size(); }

	size_t chunks_total_size()const {
		return _chunks_count;
	}

	void subscribe(const IdArray&ids, const Flag& flag, const ReaderClb_ptr &clbk) {
		auto new_s = std::make_shared<SubscribeInfo>(ids, flag, clbk);
		_subscribe_notify->add(new_s);
	}

	Reader_ptr currentValue(const IdArray&ids, const Flag& flag) {
        std::lock_guard<std::mutex> lg(_mutex);
		auto res_raw = new InnerCurrentValuesReader();
		Reader_ptr res{ res_raw };
		for (auto &kv : _free_chunks) {
			auto l = kv.second->last;
			if ((ids.size() != 0) && (std::find(ids.begin(), ids.end(), l.id) == ids.end())) {
				continue;
			}
			if ((flag == 0) || (l.flag == flag)) {
				res_raw->_cur_values.push_back(l);
			}
		}
		return res;
	}

	dariadb::storage::ChuncksList drop_old_chunks(const dariadb::Time min_time) {
        std::lock_guard<std::mutex> lg(_mutex);
		ChuncksList result;
		auto now = dariadb::timeutil::current_time();

		for (auto& kv : _chuncks) {
			while ((kv.second.size() > 0)) {
				auto past = (now - min_time);
				if ((kv.second.front()->maxTime < past)&&(kv.second.front()->is_full())) {
					auto chunk = kv.second.front();
					result.push_back(chunk);
					kv.second.pop_front();
					if (this->_free_chunks[kv.first] == chunk) {
						this->_free_chunks.erase(kv.first);
					}
				}else {
					break;
				}
			}
		}
		if (result.size() > size_t(0)){
			update_max_min_after_drop();
		}
		_chunks_count= _chunks_count -long(result.size());
		return result;
	}

	//by memory limit
	ChuncksList drop_old_chunks_by_limit(const size_t max_limit) {
		ChuncksList result{};
		if (chunks_total_size() > max_limit) {
			std::lock_guard<std::mutex> lg(_mutex);
			int64_t iterations = (int64_t(chunks_total_size()) - (max_limit - size_t(max_limit / 3)));
			if (iterations < 0) {
				return result;
			}
			while (int64_t(result.size())<iterations) {
				for (auto& kv : _chuncks) {
					if ((kv.second.size() > 1)) {
						dariadb::storage::Chunk_Ptr chunk = kv.second.front();
						if (chunk->is_full()) {
							result.push_back(chunk);
							kv.second.pop_front();
						}

					}
					if ((chunks_total_size() <= (max_limit - size_t(max_limit / 3)))) {
						break;
					}

				}
			}
			if (result.size() > size_t(0))
			{
				update_max_min_after_drop();
				_chunks_count = _chunks_count - long(result.size());
			}
		}
		return result;
	}

	void update_max_min_after_drop() {
		this->_min_time = std::numeric_limits<dariadb::Time>::max();
		this->_max_time = std::numeric_limits<dariadb::Time>::min();
		for (auto& kv : _chuncks) {
			for (auto &c : kv.second) {
				_min_time = std::min(c->minTime, _min_time);
				_max_time = std::max(c->maxTime, _max_time);
			}
		}
	}

	dariadb::storage::ChuncksList drop_all() {
        std::lock_guard<std::mutex> lg(_mutex);
		ChuncksList result;

		for (auto& kv : _chuncks) {
			for (auto chunk : kv.second) {
				result.push_back(chunk);
			}
		}
		this->_free_chunks.clear();
		this->_chuncks.clear();
		//update min max
		this->_min_time = std::numeric_limits<dariadb::Time>::max();
		this->_max_time = std::numeric_limits<dariadb::Time>::min();

		return result;
	}

	ChuncksList chunksByIterval(const IdArray &ids, Flag flag, Time from, Time to) {
		ChuncksList result{};

		for (auto ch : _chuncks) {
			if ((ids.size() != 0) && (std::find(ids.begin(), ids.end(), ch.first) == ids.end())) {
				continue;
			}
			for (auto &cur_chunk : ch.second) {
				if (flag != 0) {
					if (!cur_chunk->check_flag(flag)) {
						continue;
					}
				}
				if ((utils::inInterval(from, to, cur_chunk->minTime)) || (utils::inInterval(from, to, cur_chunk->maxTime))) {
					result.push_back(cur_chunk);
				}
			}

		}
		return result;
	}

	IdToChunkMap chunksBeforeTimePoint(const IdArray &ids, Flag flag, Time timePoint) {
		IdToChunkMap result;
		for (auto ch : _chuncks) {
			if ((ids.size() != 0) && (std::find(ids.begin(), ids.end(), ch.first) == ids.end())) {
				continue;
			}
			auto chunks = &ch.second;
			for (auto it = chunks->rbegin(); it != chunks->crend(); ++it) {
				auto cur_chunk = *it;
				if (!cur_chunk->check_flag(flag)) {
					continue;
				}
				if (cur_chunk->minTime <= timePoint) {
					result[ch.first] = cur_chunk;
					break;
				}
			}
		}
		return result;
	}

	dariadb::IdArray getIds()const {
		dariadb::IdArray result;
		result.resize(_chuncks.size());
		size_t pos = 0;
		for (auto&kv : _chuncks) {
			result[pos] = kv.first;
			pos++;
		}
		return result;
	}

	void add_chunks(const ChuncksList&clist) {
		for (auto c : clist) {
			_chuncks[c->first.id].push_back(c);
			auto search_res = _free_chunks.find(c->first.id);
			if (search_res == _free_chunks.end()) {
				_free_chunks[c->first.id] = c;
			}
			else {
				assert(false);
			}
		}
	}
protected:
	size_t _size;

	ChunkMap _chuncks;
	IdToChunkMap _free_chunks;
	Time _min_time, _max_time;
	std::unique_ptr<SubscribeNotificator> _subscribe_notify;
	mutable std::mutex _mutex;
	std::atomic_int64_t _chunks_count;
};

MemoryStorage::MemoryStorage(size_t size)
	:_Impl(new MemoryStorage::Private(size)) {
}

MemoryStorage::~MemoryStorage() {
}

Time MemoryStorage::minTime() {
	return _Impl->minTime();
}

Time MemoryStorage::maxTime() {
	return _Impl->maxTime();
}

append_result MemoryStorage::append(const dariadb::Meas &value) {
	return _Impl->append(value);
}

append_result MemoryStorage::append(const dariadb::Meas::PMeas begin, const size_t size) {
	return _Impl->append(begin, size);
}

size_t  MemoryStorage::size()const {
	return _Impl->size();
}

size_t  MemoryStorage::chunks_size()const {
	return _Impl->chunks_size();
}

size_t MemoryStorage::chunks_total_size()const {
	return _Impl->chunks_total_size();
}

void MemoryStorage::subscribe(const IdArray&ids, const Flag& flag, const ReaderClb_ptr &clbk) {
	return _Impl->subscribe(ids, flag, clbk);
}

Reader_ptr MemoryStorage::currentValue(const IdArray&ids, const Flag& flag) {
	return  _Impl->currentValue(ids, flag);
}

void MemoryStorage::flush()
{
}

dariadb::storage::ChuncksList MemoryStorage::drop_old_chunks(const dariadb::Time min_time){
	return _Impl->drop_old_chunks(min_time);
}

dariadb::storage::ChuncksList MemoryStorage::drop_old_chunks_by_limit(const size_t max_limit) {
	return _Impl->drop_old_chunks_by_limit(max_limit);
}
dariadb::storage::ChuncksList MemoryStorage::drop_all()
{
	return _Impl->drop_all();
}

ChuncksList MemoryStorage::chunksByIterval(const IdArray &ids, Flag flag, Time from, Time to) {
	return _Impl->chunksByIterval(ids, flag, from, to);
}

IdToChunkMap MemoryStorage::chunksBeforeTimePoint(const IdArray &ids, Flag flag, Time timePoint) {
	return _Impl->chunksBeforeTimePoint(ids, flag, timePoint);
}

dariadb::IdArray MemoryStorage::getIds()const {
	return _Impl->getIds();
}

void MemoryStorage::add_chunks(const ChuncksList&clist) {
	return _Impl->add_chunks(clist);
}
<commit_msg>chunks_count type.<commit_after>#include "memstorage.h"
#include "../utils/utils.h"
#include "../compression.h"
#include "../flags.h"
#include "subscribe.h"
#include "chunk.h"
#include "../timeutil.h"
#include "inner_readers.h"

#include <limits>
#include <algorithm>
#include <map>
#include <tuple>
#include <assert.h>
#include <mutex>
#include <atomic>

using namespace dariadb;
using namespace dariadb::compression;
using namespace dariadb::storage;

typedef std::map<Id, ChuncksList> ChunkMap;

class MemoryStorage::Private
{
public:
	Private(size_t size) :
		_size(size),
		_min_time(std::numeric_limits<dariadb::Time>::max()),
		_max_time(std::numeric_limits<dariadb::Time>::min()),
		_subscribe_notify(new SubscribeNotificator),
		_chunks_count(0)
	{
		_subscribe_notify->start();

	}

	~Private() {
		_subscribe_notify->stop();
		_chuncks.clear();
	}

	Time minTime() { return _min_time; }
	Time maxTime() { return _max_time; }

	Chunk_Ptr getFreeChunk(dariadb::Id id) {
		Chunk_Ptr resulted_chunk = nullptr;
		auto ch_iter = _free_chunks.find(id);
		if (ch_iter != _free_chunks.end()) {
			if (!ch_iter->second->is_full()) {
				return ch_iter->second;
			}
		}
		return resulted_chunk;
	}

	Chunk_Ptr make_chunk(dariadb::Meas first) {
		auto ptr = new Chunk(_size, first);
		auto chunk = Chunk_Ptr{ ptr };
		this->_chuncks[first.id].push_back(chunk);
		this->_free_chunks[first.id] = chunk;
		_chunks_count++;
		return chunk;
	}

	append_result append(const Meas& value) {
		std::lock_guard<std::mutex> lg(_mutex);

		Chunk_Ptr chunk = this->getFreeChunk(value.id);

		if (chunk == nullptr) {
			chunk=make_chunk(value);
		}
		else {
            //std::cout<<"append new "<<chunk->count<< " chunks: "<<this->chunks_total_size()<<std::endl;
			if (!chunk->append(value)) {
				assert(chunk->is_full());
				chunk = make_chunk(value);
			}
		}

		assert(chunk->last.time == value.time);

		_min_time = std::min(_min_time, value.time);
		_max_time = std::max(_max_time, value.time);

		_subscribe_notify->on_append(value);

		return dariadb::append_result(1, 0);
	}

	append_result append(const Meas::PMeas begin, const size_t size) {
		dariadb::append_result result{};
		for (size_t i = 0; i < size; i++) {
			result = result + append(begin[i]);
		}
		return result;

	}

    size_t size()const { return _size; }
	size_t chunks_size()const { return _chuncks.size(); }

	size_t chunks_total_size()const {
		return _chunks_count;
	}

	void subscribe(const IdArray&ids, const Flag& flag, const ReaderClb_ptr &clbk) {
		auto new_s = std::make_shared<SubscribeInfo>(ids, flag, clbk);
		_subscribe_notify->add(new_s);
	}

	Reader_ptr currentValue(const IdArray&ids, const Flag& flag) {
        std::lock_guard<std::mutex> lg(_mutex);
		auto res_raw = new InnerCurrentValuesReader();
		Reader_ptr res{ res_raw };
		for (auto &kv : _free_chunks) {
			auto l = kv.second->last;
			if ((ids.size() != 0) && (std::find(ids.begin(), ids.end(), l.id) == ids.end())) {
				continue;
			}
			if ((flag == 0) || (l.flag == flag)) {
				res_raw->_cur_values.push_back(l);
			}
		}
		return res;
	}

	dariadb::storage::ChuncksList drop_old_chunks(const dariadb::Time min_time) {
        std::lock_guard<std::mutex> lg(_mutex);
		ChuncksList result;
		auto now = dariadb::timeutil::current_time();

		for (auto& kv : _chuncks) {
			while ((kv.second.size() > 0)) {
				auto past = (now - min_time);
				if ((kv.second.front()->maxTime < past)&&(kv.second.front()->is_full())) {
					auto chunk = kv.second.front();
					result.push_back(chunk);
					kv.second.pop_front();
					if (this->_free_chunks[kv.first] == chunk) {
						this->_free_chunks.erase(kv.first);
					}
				}else {
					break;
				}
			}
		}
		if (result.size() > size_t(0)){
			update_max_min_after_drop();
		}
		_chunks_count= _chunks_count -long(result.size());
		return result;
	}

	//by memory limit
	ChuncksList drop_old_chunks_by_limit(const size_t max_limit) {
		ChuncksList result{};
		if (chunks_total_size() > max_limit) {
			std::lock_guard<std::mutex> lg(_mutex);
			int64_t iterations = (int64_t(chunks_total_size()) - (max_limit - size_t(max_limit / 3)));
			if (iterations < 0) {
				return result;
			}
			while (int64_t(result.size())<iterations) {
				for (auto& kv : _chuncks) {
					if ((kv.second.size() > 1)) {
						dariadb::storage::Chunk_Ptr chunk = kv.second.front();
						if (chunk->is_full()) {
							result.push_back(chunk);
							kv.second.pop_front();
						}

					}
					if ((chunks_total_size() <= (max_limit - size_t(max_limit / 3)))) {
						break;
					}

				}
			}
			if (result.size() > size_t(0))
			{
				update_max_min_after_drop();
				_chunks_count = _chunks_count - long(result.size());
			}
		}
		return result;
	}

	void update_max_min_after_drop() {
		this->_min_time = std::numeric_limits<dariadb::Time>::max();
		this->_max_time = std::numeric_limits<dariadb::Time>::min();
		for (auto& kv : _chuncks) {
			for (auto &c : kv.second) {
				_min_time = std::min(c->minTime, _min_time);
				_max_time = std::max(c->maxTime, _max_time);
			}
		}
	}

	dariadb::storage::ChuncksList drop_all() {
        std::lock_guard<std::mutex> lg(_mutex);
		ChuncksList result;

		for (auto& kv : _chuncks) {
			for (auto chunk : kv.second) {
				result.push_back(chunk);
			}
		}
		this->_free_chunks.clear();
		this->_chuncks.clear();
		//update min max
		this->_min_time = std::numeric_limits<dariadb::Time>::max();
		this->_max_time = std::numeric_limits<dariadb::Time>::min();

		return result;
	}

	ChuncksList chunksByIterval(const IdArray &ids, Flag flag, Time from, Time to) {
		ChuncksList result{};

		for (auto ch : _chuncks) {
			if ((ids.size() != 0) && (std::find(ids.begin(), ids.end(), ch.first) == ids.end())) {
				continue;
			}
			for (auto &cur_chunk : ch.second) {
				if (flag != 0) {
					if (!cur_chunk->check_flag(flag)) {
						continue;
					}
				}
				if ((utils::inInterval(from, to, cur_chunk->minTime)) || (utils::inInterval(from, to, cur_chunk->maxTime))) {
					result.push_back(cur_chunk);
				}
			}

		}
		return result;
	}

	IdToChunkMap chunksBeforeTimePoint(const IdArray &ids, Flag flag, Time timePoint) {
		IdToChunkMap result;
		for (auto ch : _chuncks) {
			if ((ids.size() != 0) && (std::find(ids.begin(), ids.end(), ch.first) == ids.end())) {
				continue;
			}
			auto chunks = &ch.second;
			for (auto it = chunks->rbegin(); it != chunks->crend(); ++it) {
				auto cur_chunk = *it;
				if (!cur_chunk->check_flag(flag)) {
					continue;
				}
				if (cur_chunk->minTime <= timePoint) {
					result[ch.first] = cur_chunk;
					break;
				}
			}
		}
		return result;
	}

	dariadb::IdArray getIds()const {
		dariadb::IdArray result;
		result.resize(_chuncks.size());
		size_t pos = 0;
		for (auto&kv : _chuncks) {
			result[pos] = kv.first;
			pos++;
		}
		return result;
	}

	void add_chunks(const ChuncksList&clist) {
		for (auto c : clist) {
			_chuncks[c->first.id].push_back(c);
			auto search_res = _free_chunks.find(c->first.id);
			if (search_res == _free_chunks.end()) {
				_free_chunks[c->first.id] = c;
			}
			else {
				assert(false);
			}
		}
	}
protected:
	size_t _size;

	ChunkMap _chuncks;
	IdToChunkMap _free_chunks;
	Time _min_time, _max_time;
	std::unique_ptr<SubscribeNotificator> _subscribe_notify;
	mutable std::mutex _mutex;
	std::atomic<int64_t> _chunks_count;
};

MemoryStorage::MemoryStorage(size_t size)
	:_Impl(new MemoryStorage::Private(size)) {
}

MemoryStorage::~MemoryStorage() {
}

Time MemoryStorage::minTime() {
	return _Impl->minTime();
}

Time MemoryStorage::maxTime() {
	return _Impl->maxTime();
}

append_result MemoryStorage::append(const dariadb::Meas &value) {
	return _Impl->append(value);
}

append_result MemoryStorage::append(const dariadb::Meas::PMeas begin, const size_t size) {
	return _Impl->append(begin, size);
}

size_t  MemoryStorage::size()const {
	return _Impl->size();
}

size_t  MemoryStorage::chunks_size()const {
	return _Impl->chunks_size();
}

size_t MemoryStorage::chunks_total_size()const {
	return _Impl->chunks_total_size();
}

void MemoryStorage::subscribe(const IdArray&ids, const Flag& flag, const ReaderClb_ptr &clbk) {
	return _Impl->subscribe(ids, flag, clbk);
}

Reader_ptr MemoryStorage::currentValue(const IdArray&ids, const Flag& flag) {
	return  _Impl->currentValue(ids, flag);
}

void MemoryStorage::flush()
{
}

dariadb::storage::ChuncksList MemoryStorage::drop_old_chunks(const dariadb::Time min_time){
	return _Impl->drop_old_chunks(min_time);
}

dariadb::storage::ChuncksList MemoryStorage::drop_old_chunks_by_limit(const size_t max_limit) {
	return _Impl->drop_old_chunks_by_limit(max_limit);
}
dariadb::storage::ChuncksList MemoryStorage::drop_all()
{
	return _Impl->drop_all();
}

ChuncksList MemoryStorage::chunksByIterval(const IdArray &ids, Flag flag, Time from, Time to) {
	return _Impl->chunksByIterval(ids, flag, from, to);
}

IdToChunkMap MemoryStorage::chunksBeforeTimePoint(const IdArray &ids, Flag flag, Time timePoint) {
	return _Impl->chunksBeforeTimePoint(ids, flag, timePoint);
}

dariadb::IdArray MemoryStorage::getIds()const {
	return _Impl->getIds();
}

void MemoryStorage::add_chunks(const ChuncksList&clist) {
	return _Impl->add_chunks(clist);
}
<|endoftext|>


<commit_before>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2009-2014 The Regents of
the University of Michigan All rights reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

You may redistribute, use, and create derivate works of HOOMD-blue, in source
and binary forms, provided you abide by the following conditions:

* Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer both in the code and
prominently in any materials provided with the distribution.

* 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.

* All publications and presentations based on HOOMD-blue, including any reports
or published results obtained, in whole or in part, with HOOMD-blue, will
acknowledge its use according to the terms posted at the time of submission on:
http://codeblue.umich.edu/hoomd-blue/citations.html

* Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
http://codeblue.umich.edu/hoomd-blue/

* Apart from the above required attributions, neither the name of the copyright
holder nor the names of HOOMD-blue's contributors may be used to endorse or
promote products derived from this software without specific prior written
permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// Maintainer: joaander

/*! \file MSDAnalyzer.cc
    \brief Defines the MSDAnalyzer class
*/

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4244 )
#endif

#include "MSDAnalyzer.h"
#include "HOOMDInitializer.h"

#ifdef ENABLE_MPI
#include "Communicator.h"
#endif

#include <boost/python.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
using namespace boost::python;
using namespace boost::filesystem;

#include <iomanip>
using namespace std;

/*! \param sysdef SystemDefinition containing the Particle data to analyze
    \param fname File name to write output to
    \param header_prefix String to print before the file header
    \param overwrite Will overwite an exiting file if true (default is to append)

    On construction, the initial coordinates of all parrticles in the system are recoreded. The file is opened
    (and overwritten if told to). Nothing is initially written to the file, that will occur on the first call to
    analyze()
*/
MSDAnalyzer::MSDAnalyzer(boost::shared_ptr<SystemDefinition> sysdef,
                         std::string fname,
                         const std::string& header_prefix,
                         bool overwrite)
    : Analyzer(sysdef), m_delimiter("\t"), m_header_prefix(header_prefix), m_appending(false),
      m_columns_changed(false)
    {
    m_exec_conf->msg->notice(5) << "Constructing MSDAnalyzer: " << fname << " " << header_prefix << " " << overwrite << endl;

    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        return;
        }
#endif

    // open the file
    if (exists(fname) && !overwrite)
        {
        m_exec_conf->msg->notice(3) << "analyze.msd: Appending msd to existing file \"" << fname << "\"" << endl;
        m_file.open(fname.c_str(), ios_base::in | ios_base::out | ios_base::ate);
        m_appending = true;
        }
    else
        {
        m_exec_conf->msg->notice(3) << "analyze.msd: Creating new msd in file \"" << fname << "\"" << endl;
        m_file.open(fname.c_str(), ios_base::out);
        }

    if (!m_file.good())
        {
        m_exec_conf->msg->error() << "analyze.msd: Unable to open file " << fname << endl;
        throw runtime_error("Error initializing analyze.msd");
        }

    // record the initial particle positions by tag
    m_initial_x.resize(m_pdata->getNGlobal());
    m_initial_y.resize(m_pdata->getNGlobal());
    m_initial_z.resize(m_pdata->getNGlobal());

    BoxDim box = m_pdata->getGlobalBox();

    // for each particle in the data
    for (unsigned int tag = 0; tag < snapshot.size; tag++)
        {
        // save its initial position
        Scalar3 pos = snapshot.pos[tag];
        Scalar3 unwrapped = box.shift(pos, snapshot.image[tag]);
        m_initial_x[tag] = unwrapped.x;
        m_initial_y[tag] = unwrapped.y;
        m_initial_z[tag] = unwrapped.z;
        }
    }

MSDAnalyzer::~MSDAnalyzer()
    {
    m_exec_conf->msg->notice(5) << "Destroying MSDAnalyzer" << endl;
    }

/*!\param timestep Current time step of the simulation

    analyze() will first write out the file header if the columns have changed.

    On every call, analyze() will write calculate the MSD for each group and write out a row in the file.
*/
void MSDAnalyzer::analyze(unsigned int timestep)
    {
    if (m_prof)
        m_prof->push("Analyze MSD");

    // take particle data snapshot
    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        if (m_prof) m_prof->pop();
        return;
        }
#endif

    // error check
    if (m_columns.size() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: No columns specified in the MSD analysis" << endl;
        return;
        }

    // ignore writing the header on the first call when appending the file
    if (m_columns_changed && m_appending)
        {
        m_appending = false;
        m_columns_changed = false;
        }

    // write out the header only once if the columns change
    if (m_columns_changed)
        {
        writeHeader();
        m_columns_changed = false;
        }

    // write out the row every time
    writeRow(timestep, snapshot);

    if (m_prof)
        m_prof->pop();
    }

/*! \param delimiter New delimiter to set

    The delimiter is printed between every element in the row of the output
*/
void MSDAnalyzer::setDelimiter(const std::string& delimiter)
    {
    m_delimiter = delimiter;
    }

/*! \param group Particle group to calculate the MSD of
    \param name Name to print in the header of the file

    After a column is added with addColumn(), future calls to analyze() will calculate the MSD of the particles defined
    in \a group and print out an entry under the \a name header in the file.
*/
void MSDAnalyzer::addColumn(boost::shared_ptr<ParticleGroup> group, const std::string& name)
    {
    m_columns.push_back(column(group, name));
    m_columns_changed = true;
    }

/*! \param xml_fname Name of the XML file to read in to the r0 positions

    \post \a xml_fname is read and all initial r0 positions are assigned from that file.
*/
void MSDAnalyzer::setR0(const std::string& xml_fname)
    {
    // read in the xml file
    HOOMDInitializer xml(m_exec_conf,xml_fname);

    // take particle data snapshot
    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_pdata->getDomainDecomposition() && !m_exec_conf->isRoot())
        {
        return;
        }
#endif

    // verify that the input matches the current system size
    unsigned int nparticles = m_pdata->getNGlobal();
    if (nparticles != xml.getPos().size())
        {
        m_exec_conf->msg->error() << "analyze.msd: Found " << xml.getPos().size() << " particles in "
             << xml_fname << ", but there are " << nparticles << " in the current simulation." << endl;
        throw runtime_error("Error setting r0 in analyze.msd");
        }

    // determine if we have image data
    bool have_image = (xml.getImage().size() == nparticles);
    if (!have_image)
        {
        m_exec_conf->msg->warning() << "analyze.msd: Image data missing or corrupt in " << xml_fname
             << ". Computed msd values will not be correct." << endl;
        }

    // reset the initial positions
    BoxDim box = m_pdata->getGlobalBox();

    // for each particle in the data
    for (unsigned int tag = 0; tag < nparticles; tag++)
        {
        // save its initial position
        HOOMDInitializer::vec pos = xml.getPos()[tag];
        m_initial_x[tag] = pos.x;
        m_initial_y[tag] = pos.y;
        m_initial_z[tag] = pos.z;

        // adjust the positions by the image flags if we have them
        if (have_image)
            {
            HOOMDInitializer::vec_int image = xml.getImage()[tag];
            Scalar3 pos = make_scalar3(m_initial_x[tag], m_initial_y[tag], m_initial_z[tag]);
            int3 image_i = make_int3(image.x, image.y, image.z);
            Scalar3 unwrapped = box.shift(pos, image_i);
            m_initial_x[tag] += unwrapped.x;
            m_initial_y[tag] += unwrapped.y;
            m_initial_z[tag] += unwrapped.z;
            }
        }
    }

/*! The entire header row is written to the file. First, timestep is written as every file includes it and then the
    columns are looped through and their names printed, separated by the delimiter.
*/
void MSDAnalyzer::writeHeader()
    {
    // write out the header prefix
    m_file << m_header_prefix;

    // timestep is always output
    m_file << "timestep";

    if (m_columns.size() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: No columns specified in the MSD analysis" << endl;
        return;
        }

    // only print the delimiter after the timestep if there are more columns
    m_file << m_delimiter;

    // write all but the last of the quantities separated by the delimiter
    for (unsigned int i = 0; i < m_columns.size()-1; i++)
        m_file << m_columns[i].m_name << m_delimiter;
    // write the last one with no delimiter after it
    m_file << m_columns[m_columns.size()-1].m_name << endl;
    m_file.flush();
    }

/*! \param group Particle group to calculate the MSD of
    Loop through all particles in the given group and calculate the MSD over them.
    \returns The calculated MSD
*/
Scalar MSDAnalyzer::calcMSD(boost::shared_ptr<ParticleGroup const> group, const SnapshotParticleData& snapshot)
    {
    BoxDim box = m_pdata->getGlobalBox();

    // initial sum for the average
    Scalar msd = Scalar(0.0);

    // handle the case where there are 0 members gracefully
    if (group->getNumMembersGlobal() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: Group has 0 members, reporting a calculated msd of 0.0" << endl;
        return Scalar(0.0);
        }

    // for each particle in the group
    for (unsigned int group_idx = 0; group_idx < group->getNumMembersGlobal(); group_idx++)
        {
        // get the tag for the current group member from the group
        unsigned int tag = group->getMemberTag(group_idx);
        Scalar3 pos = snapshot.pos[tag];
        int3 image = snapshot.image[tag];
        Scalar3 unwrapped = box.shift(pos, image);
        Scalar dx = unwrapped.x - m_initial_x[tag];
        Scalar dy = unwrapped.y - m_initial_y[tag];
        Scalar dz = unwrapped.z - m_initial_z[tag];

        msd += dx*dx + dy*dy + dz*dz;
        }

    // divide to complete the average
    msd /= Scalar(group->getNumMembersGlobal());
    return msd;
    }

/*! \param timestep current time step of the simulation

    Performs all the steps needed in order to calculate the MSDs for all the groups in the columns and writes out an
    entire row to the file.
*/
void MSDAnalyzer::writeRow(unsigned int timestep, const SnapshotParticleData& snapshot)
    {
    if (m_prof) m_prof->push("MSD");

    // The timestep is always output
    m_file << setprecision(10) << timestep;

    // quit now if there is nothing to log
    if (m_columns.size() == 0)
        {
        return;
        }

    // only print the delimiter after the timestep if there are more columns
    m_file << m_delimiter;

    // write all but the last of the columns separated by the delimiter
    for (unsigned int i = 0; i < m_columns.size()-1; i++)
        m_file << setprecision(10) << calcMSD(m_columns[i].m_group, snapshot) << m_delimiter;
    // write the last one with no delimiter after it
    m_file << setprecision(10) << calcMSD(m_columns[m_columns.size()-1].m_group, snapshot) << endl;
    m_file.flush();

    if (!m_file.good())
        {
        m_exec_conf->msg->error() << "analyze.msd: I/O error while writing file" << endl;
        throw runtime_error("Error writting msd file");
        }

    if (m_prof) m_prof->pop();
    }

void export_MSDAnalyzer()
    {
    class_<MSDAnalyzer, boost::shared_ptr<MSDAnalyzer>, bases<Analyzer>, boost::noncopyable>
    ("MSDAnalyzer", init< boost::shared_ptr<SystemDefinition>, const std::string&, const std::string&, bool >())
    .def("setDelimiter", &MSDAnalyzer::setDelimiter)
    .def("addColumn", &MSDAnalyzer::addColumn)
    .def("setR0", &MSDAnalyzer::setR0)
    ;
    }

#ifdef WIN32
#pragma warning( pop )
#endif
<commit_msg>Handle images correctly in analyze.msd<commit_after>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2009-2014 The Regents of
the University of Michigan All rights reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

You may redistribute, use, and create derivate works of HOOMD-blue, in source
and binary forms, provided you abide by the following conditions:

* Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer both in the code and
prominently in any materials provided with the distribution.

* 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.

* All publications and presentations based on HOOMD-blue, including any reports
or published results obtained, in whole or in part, with HOOMD-blue, will
acknowledge its use according to the terms posted at the time of submission on:
http://codeblue.umich.edu/hoomd-blue/citations.html

* Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
http://codeblue.umich.edu/hoomd-blue/

* Apart from the above required attributions, neither the name of the copyright
holder nor the names of HOOMD-blue's contributors may be used to endorse or
promote products derived from this software without specific prior written
permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// Maintainer: joaander

/*! \file MSDAnalyzer.cc
    \brief Defines the MSDAnalyzer class
*/

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4244 )
#endif

#include "MSDAnalyzer.h"
#include "HOOMDInitializer.h"

#ifdef ENABLE_MPI
#include "Communicator.h"
#endif

#include <boost/python.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
using namespace boost::python;
using namespace boost::filesystem;

#include <iomanip>
using namespace std;

/*! \param sysdef SystemDefinition containing the Particle data to analyze
    \param fname File name to write output to
    \param header_prefix String to print before the file header
    \param overwrite Will overwite an exiting file if true (default is to append)

    On construction, the initial coordinates of all parrticles in the system are recoreded. The file is opened
    (and overwritten if told to). Nothing is initially written to the file, that will occur on the first call to
    analyze()
*/
MSDAnalyzer::MSDAnalyzer(boost::shared_ptr<SystemDefinition> sysdef,
                         std::string fname,
                         const std::string& header_prefix,
                         bool overwrite)
    : Analyzer(sysdef), m_delimiter("\t"), m_header_prefix(header_prefix), m_appending(false),
      m_columns_changed(false)
    {
    m_exec_conf->msg->notice(5) << "Constructing MSDAnalyzer: " << fname << " " << header_prefix << " " << overwrite << endl;

    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        return;
        }
#endif

    // open the file
    if (exists(fname) && !overwrite)
        {
        m_exec_conf->msg->notice(3) << "analyze.msd: Appending msd to existing file \"" << fname << "\"" << endl;
        m_file.open(fname.c_str(), ios_base::in | ios_base::out | ios_base::ate);
        m_appending = true;
        }
    else
        {
        m_exec_conf->msg->notice(3) << "analyze.msd: Creating new msd in file \"" << fname << "\"" << endl;
        m_file.open(fname.c_str(), ios_base::out);
        }

    if (!m_file.good())
        {
        m_exec_conf->msg->error() << "analyze.msd: Unable to open file " << fname << endl;
        throw runtime_error("Error initializing analyze.msd");
        }

    // record the initial particle positions by tag
    m_initial_x.resize(m_pdata->getNGlobal());
    m_initial_y.resize(m_pdata->getNGlobal());
    m_initial_z.resize(m_pdata->getNGlobal());

    BoxDim box = m_pdata->getGlobalBox();

    // for each particle in the data
    for (unsigned int tag = 0; tag < snapshot.size; tag++)
        {
        // save its initial position
        Scalar3 pos = snapshot.pos[tag];
        Scalar3 unwrapped = box.shift(pos, snapshot.image[tag]);
        m_initial_x[tag] = unwrapped.x;
        m_initial_y[tag] = unwrapped.y;
        m_initial_z[tag] = unwrapped.z;
        }
    }

MSDAnalyzer::~MSDAnalyzer()
    {
    m_exec_conf->msg->notice(5) << "Destroying MSDAnalyzer" << endl;
    }

/*!\param timestep Current time step of the simulation

    analyze() will first write out the file header if the columns have changed.

    On every call, analyze() will write calculate the MSD for each group and write out a row in the file.
*/
void MSDAnalyzer::analyze(unsigned int timestep)
    {
    if (m_prof)
        m_prof->push("Analyze MSD");

    // take particle data snapshot
    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        if (m_prof) m_prof->pop();
        return;
        }
#endif

    // error check
    if (m_columns.size() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: No columns specified in the MSD analysis" << endl;
        return;
        }

    // ignore writing the header on the first call when appending the file
    if (m_columns_changed && m_appending)
        {
        m_appending = false;
        m_columns_changed = false;
        }

    // write out the header only once if the columns change
    if (m_columns_changed)
        {
        writeHeader();
        m_columns_changed = false;
        }

    // write out the row every time
    writeRow(timestep, snapshot);

    if (m_prof)
        m_prof->pop();
    }

/*! \param delimiter New delimiter to set

    The delimiter is printed between every element in the row of the output
*/
void MSDAnalyzer::setDelimiter(const std::string& delimiter)
    {
    m_delimiter = delimiter;
    }

/*! \param group Particle group to calculate the MSD of
    \param name Name to print in the header of the file

    After a column is added with addColumn(), future calls to analyze() will calculate the MSD of the particles defined
    in \a group and print out an entry under the \a name header in the file.
*/
void MSDAnalyzer::addColumn(boost::shared_ptr<ParticleGroup> group, const std::string& name)
    {
    m_columns.push_back(column(group, name));
    m_columns_changed = true;
    }

/*! \param xml_fname Name of the XML file to read in to the r0 positions

    \post \a xml_fname is read and all initial r0 positions are assigned from that file.
*/
void MSDAnalyzer::setR0(const std::string& xml_fname)
    {
    // read in the xml file
    HOOMDInitializer xml(m_exec_conf,xml_fname);

    // take particle data snapshot
    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_pdata->getDomainDecomposition() && !m_exec_conf->isRoot())
        {
        return;
        }
#endif

    // verify that the input matches the current system size
    unsigned int nparticles = m_pdata->getNGlobal();
    if (nparticles != xml.getPos().size())
        {
        m_exec_conf->msg->error() << "analyze.msd: Found " << xml.getPos().size() << " particles in "
             << xml_fname << ", but there are " << nparticles << " in the current simulation." << endl;
        throw runtime_error("Error setting r0 in analyze.msd");
        }

    // determine if we have image data
    bool have_image = (xml.getImage().size() == nparticles);
    if (!have_image)
        {
        m_exec_conf->msg->warning() << "analyze.msd: Image data missing or corrupt in " << xml_fname
             << ". Computed msd values will not be correct." << endl;
        }

    // reset the initial positions
    BoxDim box = m_pdata->getGlobalBox();

    // for each particle in the data
    for (unsigned int tag = 0; tag < nparticles; tag++)
        {
        // save its initial position
        HOOMDInitializer::vec pos = xml.getPos()[tag];
        m_initial_x[tag] = pos.x;
        m_initial_y[tag] = pos.y;
        m_initial_z[tag] = pos.z;

        // adjust the positions by the image flags if we have them
        if (have_image)
            {
            HOOMDInitializer::vec_int image = xml.getImage()[tag];
            Scalar3 pos = make_scalar3(m_initial_x[tag], m_initial_y[tag], m_initial_z[tag]);
            int3 image_i = make_int3(image.x, image.y, image.z);
            Scalar3 unwrapped = box.shift(pos, image_i);
            m_initial_x[tag] = unwrapped.x;
            m_initial_y[tag] = unwrapped.y;
            m_initial_z[tag] = unwrapped.z;
            }
        }
    }

/*! The entire header row is written to the file. First, timestep is written as every file includes it and then the
    columns are looped through and their names printed, separated by the delimiter.
*/
void MSDAnalyzer::writeHeader()
    {
    // write out the header prefix
    m_file << m_header_prefix;

    // timestep is always output
    m_file << "timestep";

    if (m_columns.size() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: No columns specified in the MSD analysis" << endl;
        return;
        }

    // only print the delimiter after the timestep if there are more columns
    m_file << m_delimiter;

    // write all but the last of the quantities separated by the delimiter
    for (unsigned int i = 0; i < m_columns.size()-1; i++)
        m_file << m_columns[i].m_name << m_delimiter;
    // write the last one with no delimiter after it
    m_file << m_columns[m_columns.size()-1].m_name << endl;
    m_file.flush();
    }

/*! \param group Particle group to calculate the MSD of
    Loop through all particles in the given group and calculate the MSD over them.
    \returns The calculated MSD
*/
Scalar MSDAnalyzer::calcMSD(boost::shared_ptr<ParticleGroup const> group, const SnapshotParticleData& snapshot)
    {
    BoxDim box = m_pdata->getGlobalBox();

    // initial sum for the average
    Scalar msd = Scalar(0.0);

    // handle the case where there are 0 members gracefully
    if (group->getNumMembersGlobal() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: Group has 0 members, reporting a calculated msd of 0.0" << endl;
        return Scalar(0.0);
        }

    // for each particle in the group
    for (unsigned int group_idx = 0; group_idx < group->getNumMembersGlobal(); group_idx++)
        {
        // get the tag for the current group member from the group
        unsigned int tag = group->getMemberTag(group_idx);
        Scalar3 pos = snapshot.pos[tag];
        int3 image = snapshot.image[tag];
        Scalar3 unwrapped = box.shift(pos, image);
        Scalar dx = unwrapped.x - m_initial_x[tag];
        Scalar dy = unwrapped.y - m_initial_y[tag];
        Scalar dz = unwrapped.z - m_initial_z[tag];

        msd += dx*dx + dy*dy + dz*dz;
        }

    // divide to complete the average
    msd /= Scalar(group->getNumMembersGlobal());
    return msd;
    }

/*! \param timestep current time step of the simulation

    Performs all the steps needed in order to calculate the MSDs for all the groups in the columns and writes out an
    entire row to the file.
*/
void MSDAnalyzer::writeRow(unsigned int timestep, const SnapshotParticleData& snapshot)
    {
    if (m_prof) m_prof->push("MSD");

    // The timestep is always output
    m_file << setprecision(10) << timestep;

    // quit now if there is nothing to log
    if (m_columns.size() == 0)
        {
        return;
        }

    // only print the delimiter after the timestep if there are more columns
    m_file << m_delimiter;

    // write all but the last of the columns separated by the delimiter
    for (unsigned int i = 0; i < m_columns.size()-1; i++)
        m_file << setprecision(10) << calcMSD(m_columns[i].m_group, snapshot) << m_delimiter;
    // write the last one with no delimiter after it
    m_file << setprecision(10) << calcMSD(m_columns[m_columns.size()-1].m_group, snapshot) << endl;
    m_file.flush();

    if (!m_file.good())
        {
        m_exec_conf->msg->error() << "analyze.msd: I/O error while writing file" << endl;
        throw runtime_error("Error writting msd file");
        }

    if (m_prof) m_prof->pop();
    }

void export_MSDAnalyzer()
    {
    class_<MSDAnalyzer, boost::shared_ptr<MSDAnalyzer>, bases<Analyzer>, boost::noncopyable>
    ("MSDAnalyzer", init< boost::shared_ptr<SystemDefinition>, const std::string&, const std::string&, bool >())
    .def("setDelimiter", &MSDAnalyzer::setDelimiter)
    .def("addColumn", &MSDAnalyzer::addColumn)
    .def("setR0", &MSDAnalyzer::setR0)
    ;
    }

#ifdef WIN32
#pragma warning( pop )
#endif
<|endoftext|>


<commit_before>/*
    kopeteprefs.cpp - Kopete Preferences Container-Class

    Copyright (c) 2002      by Stefan Gehn            <sgehn@gmx.net>

    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopeteprefs.h"

#include <qfile.h>
#include <qtextstream.h>

#include <kapplication.h>
#include <klocale.h>
#include <qcolor.h>
#include <kconfig.h>
#include <kglobal.h>
#include <kdebug.h>
#include <kstandarddirs.h>
//#include <kopetechatwindow.h> // FIXME: I do not like this dependency; mETz

KopetePrefs *KopetePrefs::s_prefs = 0L;

KopetePrefs *KopetePrefs::prefs()
{
	if( !s_prefs )
		s_prefs = new KopetePrefs;
	return s_prefs;
}

KopetePrefs::KopetePrefs() : QObject( kapp, "KopetePrefs" )
{
	config = KGlobal::config();

	load();
}

KopetePrefs::~KopetePrefs()
{
//	save(); // crashes because KopeteApp is already destructed!
}

void KopetePrefs::load()
{

//	kdDebug(14010) << "KopetePrefs::load()" << endl;
	config->setGroup("Appearance");

	mIconTheme		= config->readEntry("EmoticonTheme", defaultTheme());
	mUseEmoticons		= config->readBoolEntry("Use Emoticons", true);
	mShowOffline		= config->readBoolEntry("ShowOfflineUsers", true);
	mGreyIdle		= config->readBoolEntry("GreyIdleMetaContacts", true);
	mSortByGroup		= config->readBoolEntry("SortByGroup" , true);
	mTreeView		= config->readBoolEntry("TreeView", true);
	mStartDocked		= config->readBoolEntry("StartDocked", false);
	mUseQueue		= config->readBoolEntry("Use Queue", true);
	mRaiseMsgWindow		= config->readBoolEntry("Raise Msg Window", false);
	mShowEvents		= config->readBoolEntry("Show Events in Chat Window", true);
	mTrayflashNotify	= config->readBoolEntry("Trayflash Notification", true);
	mBalloonNotify		= config->readBoolEntry("Balloon Notification", true);
	mSoundIfAway		= config->readBoolEntry("Sound Notification If Away", false);
	mChatWindowPolicy	= config->readNumEntry("Chatwindow Policy", 0);
	mTransparencyEnabled	= config->readBoolEntry("ChatView Transparency Enabled", false);
	mTransparencyValue	= config->readNumEntry("ChatView Transparency Value", 50);

	mTransparencyColor	= config->readColorEntry("ChatView Transparency Tint Color", &Qt::white);
	mChatViewBufferSize	= config->readNumEntry("ChatView BufferSize", 250);

	mHighlightBackground	= config->readColorEntry("Highlight Background Color", &Qt::black);
	mHighlightForeground	= config->readColorEntry("Highlight Foreground Color", &Qt::yellow);
	mHighlightEnabled	= config->readBoolEntry("Highlighting Enabled", true);
	mBgOverride		= config->readBoolEntry("ChatView Override Background", true);
	mInterfacePreference	= config->readNumEntry("Interface Preference", 1);
	mTextColor		= config->readColorEntry("Text Color", &Qt::black );
	mBgColor		= config->readColorEntry("Bg Color", &Qt::white );
	mLinkColor		= config->readColorEntry("Link Color", &Qt::blue );
	mFontFace		= config->readFontEntry("Font Face");

	mShowTray		= config->readBoolEntry( "Show Systemtray", true);
	mStyleSheet     	= config->readEntry("Stylesheet", locate("appdata",QString::fromLatin1("styles/Kopete.xsl") ) );
	mStyleContents		= fileContents( mStyleSheet );

	config->setGroup("Appearance");
	mTransparancyChanged = false;
}

void KopetePrefs::save()
{
//	kdDebug(14010) << "KopetePrefs::save()" << endl;

	config->setGroup ( "Appearance");

	config->writeEntry("EmoticonTheme", mIconTheme);
	config->writeEntry("Use Emoticons", mUseEmoticons);
	config->writeEntry("ShowOfflineUsers", mShowOffline);
	config->writeEntry("GreyIdleMetaContacts", mGreyIdle);
	config->writeEntry("TreeView", mTreeView);
	config->writeEntry("SortByGroup", mSortByGroup);
	config->writeEntry("StartDocked", mStartDocked);
	config->writeEntry("Use Queue", mUseQueue);
	config->writeEntry("Raise Msg Window", mRaiseMsgWindow);
	config->writeEntry("Show Events in Chat Window", mShowEvents);
	config->writeEntry("Trayflash Notification", mTrayflashNotify);
	config->writeEntry("Balloon Notification", mBalloonNotify);
	config->writeEntry("Sound Notification If Away", mSoundIfAway);
	config->writeEntry("Chatwindow Policy", mChatWindowPolicy);
	config->writeEntry("ChatView Transparency Enabled", mTransparencyEnabled);
	config->writeEntry("ChatView Transparency Value", mTransparencyValue);
	config->writeEntry("ChatView Transparency Tint Color", mTransparencyColor);
	config->writeEntry("ChatView Override Background", mBgOverride);
	config->writeEntry("ChatView BufferSize", mChatViewBufferSize);
	config->writeEntry("Highlight Background Color", mHighlightBackground);
	config->writeEntry("Highlight Foreground Color", mHighlightForeground);
	config->writeEntry("Highlighting Enabled", mHighlightEnabled );
	config->writeEntry("Font Face", mFontFace);
	config->writeEntry("Text Color",mTextColor);
	config->writeEntry("Bg Color", mBgColor);
	config->writeEntry("Link Color", mLinkColor);

	config->writeEntry("Interface Preference", mInterfacePreference);

//	config->writeEntry("ContactList Transparency Enabled", mCTransparencyEnabled);
//	config->writeEntry("ContactList Transparency Value", mCTransparencyValue);
//	config->writeEntry("ContactList Transparency Tint Color", mCTransparencyColor);

	config->writeEntry("Show Systemtray", mShowTray);
	config->writeEntry("Stylesheet", mStyleSheet);

	config->sync();
	emit saved();

	if( mTransparancyChanged )
		emit( transparancyChanged() );

	mTransparancyChanged = false;
}

void KopetePrefs::setIconTheme(const QString &value)
{
	mIconTheme = value;
}

void KopetePrefs::setUseEmoticons(bool value)
{
	mUseEmoticons = value;
}

void KopetePrefs::setShowOffline(bool value)
{
	mShowOffline = value;
}

void KopetePrefs::setTreeView(bool value)
{
	mTreeView = value;
}

void KopetePrefs::setSortByGroup(bool value)
{
	mSortByGroup = value;
}

void KopetePrefs::setGreyIdleMetaContacts(bool value)
{
	mGreyIdle = value;
}

void KopetePrefs::setStartDocked(bool value)
{
	mStartDocked = value;
}

void KopetePrefs::setUseQueue(bool value)
{
	mUseQueue = value;
}

void KopetePrefs::setRaiseMsgWindow(bool value)
{
	mRaiseMsgWindow = value;
}

void KopetePrefs::setShowEvents(bool value)
{
	mShowEvents = value;
}

void KopetePrefs::setTrayflashNotify(bool value)
{
	mTrayflashNotify = value;
}

void KopetePrefs::setBalloonNotify(bool value)
{
	mBalloonNotify = value;
}

void KopetePrefs::setSoundIfAway(bool value)
{
	mSoundIfAway = value;
}

void KopetePrefs::setStyleSheet(const QString &value)
{
	if( mAppearanceChanged || mStyleSheet != value )
	{
		mStyleSheet = value;
		mStyleContents = fileContents( mStyleSheet );
		emit( messageAppearanceChanged() );
	}
}

void KopetePrefs::setFontFace( const QFont &value )
{
	mAppearanceChanged = mAppearanceChanged || !(value == mFontFace);
	mFontFace = value;
}

void KopetePrefs::setTextColor( const QColor &value )
{
	mAppearanceChanged = mAppearanceChanged || !(value == mTextColor);
	mTextColor = value;
}

void KopetePrefs::setBgColor( const QColor &value )
{
	mAppearanceChanged = mAppearanceChanged || !(value == mBgColor);
	mBgColor = value;
}

void KopetePrefs::setLinkColor( const QColor &value )
{
	mAppearanceChanged = mAppearanceChanged || !(value == mLinkColor);
	mLinkColor = value;
}

void KopetePrefs::setChatWindowPolicy(int value)
{
	mChatWindowPolicy = value;
}

void KopetePrefs::setInterfacePreference(int value)
{
	mInterfacePreference = value;
}

void KopetePrefs::setTransparencyEnabled(bool value)
{
	mTransparancyChanged =  mTransparancyChanged || !(value == mTransparencyEnabled);
	mTransparencyEnabled = value;
}

void KopetePrefs::setTransparencyColor(const QColor &value)
{
	mTransparancyChanged =  mTransparancyChanged || !(value == mTransparencyColor);
	mTransparencyColor = value;
}

void KopetePrefs::setChatViewBufferSize(const int value)
{
	mChatViewBufferSize = value;
}

void KopetePrefs::setHighlightBackground(const QColor &value)
{
	mAppearanceChanged = mAppearanceChanged || !(value == mHighlightBackground);
	mHighlightBackground = value;
}

void KopetePrefs::setHighlightForeground(const QColor &value)
{
	mAppearanceChanged = mAppearanceChanged || !(value == mHighlightForeground);
	mHighlightForeground = value;
}

void KopetePrefs::setHighlightEnabled(bool value)
{
	mAppearanceChanged = mAppearanceChanged || !(value == mHighlightEnabled);
	mHighlightEnabled = value;
}

void KopetePrefs::setTransparencyValue(int value)
{
	mTransparancyChanged = mTransparancyChanged || !(value == mTransparencyValue);
	mTransparencyValue = value;
}

void KopetePrefs::setBgOverride(bool value)
{
	mAppearanceChanged = mAppearanceChanged || !(value == mBgOverride);
	mBgOverride = value;
}

void KopetePrefs::setShowTray(bool value)
{
	mShowTray = value;
}

QString KopetePrefs::fileContents( const QString &path )
{
 	QString contents;
	QFile file( path );
	if ( file.open( IO_ReadOnly ) )
	{
		QTextStream stream( &file );
		contents = stream.read();
		file.close();
	}

	return contents;
}

#include "kopeteprefs.moc"

// vim: set noet ts=4 sts=4 sw=4:
<commit_msg>Use the proper KDE values for default colors<commit_after>/*
    kopeteprefs.cpp - Kopete Preferences Container-Class

    Copyright (c) 2002      by Stefan Gehn            <sgehn@gmx.net>

    Kopete    (c) 2002-2003 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopeteprefs.h"

#include <qfile.h>
#include <qtextstream.h>

#include <kapplication.h>
#include <kglobalsettings.h>
#include <klocale.h>
#include <qcolor.h>
#include <kconfig.h>
#include <kglobal.h>
#include <kdebug.h>
#include <kstandarddirs.h>
//#include <kopetechatwindow.h> // FIXME: I do not like this dependency; mETz

KopetePrefs *KopetePrefs::s_prefs = 0L;

KopetePrefs *KopetePrefs::prefs()
{
	if( !s_prefs )
		s_prefs = new KopetePrefs;
	return s_prefs;
}

KopetePrefs::KopetePrefs() : QObject( kapp, "KopetePrefs" )
{
	config = KGlobal::config();

	load();
}

KopetePrefs::~KopetePrefs()
{
//	save(); // crashes because KopeteApp is already destructed!
}

void KopetePrefs::load()
{

//	kdDebug(14010) << "KopetePrefs::load()" << endl;
	config->setGroup("Appearance");

	mIconTheme		= config->readEntry("EmoticonTheme", defaultTheme());
	mUseEmoticons		= config->readBoolEntry("Use Emoticons", true);
	mShowOffline		= config->readBoolEntry("ShowOfflineUsers", true);
	mGreyIdle		= config->readBoolEntry("GreyIdleMetaContacts", true);
	mSortByGroup		= config->readBoolEntry("SortByGroup" , true);
	mTreeView		= config->readBoolEntry("TreeView", true);
	mStartDocked		= config->readBoolEntry("StartDocked", false);
	mUseQueue		= config->readBoolEntry("Use Queue", true);
	mRaiseMsgWindow		= config->readBoolEntry("Raise Msg Window", false);
	mShowEvents		= config->readBoolEntry("Show Events in Chat Window", true);
	mTrayflashNotify	= config->readBoolEntry("Trayflash Notification", true);
	mBalloonNotify		= config->readBoolEntry("Balloon Notification", true);
	mSoundIfAway		= config->readBoolEntry("Sound Notification If Away", false);
	mChatWindowPolicy	= config->readNumEntry("Chatwindow Policy", 0);
	mTransparencyEnabled	= config->readBoolEntry("ChatView Transparency Enabled", false);
	mTransparencyValue	= config->readNumEntry("ChatView Transparency Value", 50);

	mTransparencyColor	= config->readColorEntry("ChatView Transparency Tint Color", &Qt::white);
	mChatViewBufferSize	= config->readNumEntry("ChatView BufferSize", 250);

	QColor tmpColor = KGlobalSettings::highlightColor();
	mHighlightBackground	= config->readColorEntry("Highlight Background Color", &tmpColor);
	tmpColor = KGlobalSettings::highlightedTextColor();
	mHighlightForeground	= config->readColorEntry("Highlight Foreground Color", &tmpColor);
	mHighlightEnabled	= config->readBoolEntry("Highlighting Enabled", true);
	mBgOverride		= config->readBoolEntry("ChatView Override Background", true);
	mInterfacePreference	= config->readNumEntry("Interface Preference", 1);
	tmpColor= KGlobalSettings::textColor();
	mTextColor		= config->readColorEntry("Text Color", &tmpColor );
	tmpColor = KGlobalSettings::baseColor();
	mBgColor		= config->readColorEntry("Bg Color", &tmpColor );
	tmpColor = KGlobalSettings::linkColor();
	mLinkColor		= config->readColorEntry("Link Color", &tmpColor );
	mFontFace		= config->readFontEntry("Font Face");

	mShowTray		= config->readBoolEntry( "Show Systemtray", true);
	mStyleSheet     	= config->readEntry("Stylesheet", locate("appdata",QString::fromLatin1("styles/Kopete.xsl") ) );
	mStyleContents		= fileContents( mStyleSheet );

	config->setGroup("Appearance");
	mTransparancyChanged = false;
}

void KopetePrefs::save()
{
//	kdDebug(14010) << "KopetePrefs::save()" << endl;

	config->setGroup ( "Appearance");

	config->writeEntry("EmoticonTheme", mIconTheme);
	config->writeEntry("Use Emoticons", mUseEmoticons);
	config->writeEntry("ShowOfflineUsers", mShowOffline);
	config->writeEntry("GreyIdleMetaContacts", mGreyIdle);
	config->writeEntry("TreeView", mTreeView);
	config->writeEntry("SortByGroup", mSortByGroup);
	config->writeEntry("StartDocked", mStartDocked);
	config->writeEntry("Use Queue", mUseQueue);
	config->writeEntry("Raise Msg Window", mRaiseMsgWindow);
	config->writeEntry("Show Events in Chat Window", mShowEvents);
	config->writeEntry("Trayflash Notification", mTrayflashNotify);
	config->writeEntry("Balloon Notification", mBalloonNotify);
	config->writeEntry("Sound Notification If Away", mSoundIfAway);
	config->writeEntry("Chatwindow Policy", mChatWindowPolicy);
	config->writeEntry("ChatView Transparency Enabled", mTransparencyEnabled);
	config->writeEntry("ChatView Transparency Value", mTransparencyValue);
	config->writeEntry("ChatView Transparency Tint Color", mTransparencyColor);
	config->writeEntry("ChatView Override Background", mBgOverride);
	config->writeEntry("ChatView BufferSize", mChatViewBufferSize);
	config->writeEntry("Highlight Background Color", mHighlightBackground);
	config->writeEntry("Highlight Foreground Color", mHighlightForeground);
	config->writeEntry("Highlighting Enabled", mHighlightEnabled );
	config->writeEntry("Font Face", mFontFace);
	config->writeEntry("Text Color",mTextColor);
	config->writeEntry("Bg Color", mBgColor);
	config->writeEntry("Link Color", mLinkColor);

	config->writeEntry("Interface Preference", mInterfacePreference);

//	config->writeEntry("ContactList Transparency Enabled", mCTransparencyEnabled);
//	config->writeEntry("ContactList Transparency Value", mCTransparencyValue);
//	config->writeEntry("ContactList Transparency Tint Color", mCTransparencyColor);

	config->writeEntry("Show Systemtray", mShowTray);
	config->writeEntry("Stylesheet", mStyleSheet);

	config->sync();
	emit saved();

	if( mTransparancyChanged )
		emit( transparancyChanged() );

	mTransparancyChanged = false;
}

void KopetePrefs::setIconTheme(const QString &value)
{
	mIconTheme = value;
}

void KopetePrefs::setUseEmoticons(bool value)
{
	mUseEmoticons = value;
}

void KopetePrefs::setShowOffline(bool value)
{
	mShowOffline = value;
}

void KopetePrefs::setTreeView(bool value)
{
	mTreeView = value;
}

void KopetePrefs::setSortByGroup(bool value)
{
	mSortByGroup = value;
}

void KopetePrefs::setGreyIdleMetaContacts(bool value)
{
	mGreyIdle = value;
}

void KopetePrefs::setStartDocked(bool value)
{
	mStartDocked = value;
}

void KopetePrefs::setUseQueue(bool value)
{
	mUseQueue = value;
}

void KopetePrefs::setRaiseMsgWindow(bool value)
{
	mRaiseMsgWindow = value;
}

void KopetePrefs::setShowEvents(bool value)
{
	mShowEvents = value;
}

void KopetePrefs::setTrayflashNotify(bool value)
{
	mTrayflashNotify = value;
}

void KopetePrefs::setBalloonNotify(bool value)
{
	mBalloonNotify = value;
}

void KopetePrefs::setSoundIfAway(bool value)
{
	mSoundIfAway = value;
}

void KopetePrefs::setStyleSheet(const QString &value)
{
	if( mAppearanceChanged || mStyleSheet != value )
	{
		mStyleSheet = value;
		mStyleContents = fileContents( mStyleSheet );
		emit( messageAppearanceChanged() );
	}
}

void KopetePrefs::setFontFace( const QFont &value )
{
	mAppearanceChanged = mAppearanceChanged || !(value == mFontFace);
	mFontFace = value;
}

void KopetePrefs::setTextColor( const QColor &value )
{
	mAppearanceChanged = mAppearanceChanged || !(value == mTextColor);
	mTextColor = value;
}

void KopetePrefs::setBgColor( const QColor &value )
{
	mAppearanceChanged = mAppearanceChanged || !(value == mBgColor);
	mBgColor = value;
}

void KopetePrefs::setLinkColor( const QColor &value )
{
	mAppearanceChanged = mAppearanceChanged || !(value == mLinkColor);
	mLinkColor = value;
}

void KopetePrefs::setChatWindowPolicy(int value)
{
	mChatWindowPolicy = value;
}

void KopetePrefs::setInterfacePreference(int value)
{
	mInterfacePreference = value;
}

void KopetePrefs::setTransparencyEnabled(bool value)
{
	mTransparancyChanged =  mTransparancyChanged || !(value == mTransparencyEnabled);
	mTransparencyEnabled = value;
}

void KopetePrefs::setTransparencyColor(const QColor &value)
{
	mTransparancyChanged =  mTransparancyChanged || !(value == mTransparencyColor);
	mTransparencyColor = value;
}

void KopetePrefs::setChatViewBufferSize(const int value)
{
	mChatViewBufferSize = value;
}

void KopetePrefs::setHighlightBackground(const QColor &value)
{
	mAppearanceChanged = mAppearanceChanged || !(value == mHighlightBackground);
	mHighlightBackground = value;
}

void KopetePrefs::setHighlightForeground(const QColor &value)
{
	mAppearanceChanged = mAppearanceChanged || !(value == mHighlightForeground);
	mHighlightForeground = value;
}

void KopetePrefs::setHighlightEnabled(bool value)
{
	mAppearanceChanged = mAppearanceChanged || !(value == mHighlightEnabled);
	mHighlightEnabled = value;
}

void KopetePrefs::setTransparencyValue(int value)
{
	mTransparancyChanged = mTransparancyChanged || !(value == mTransparencyValue);
	mTransparencyValue = value;
}

void KopetePrefs::setBgOverride(bool value)
{
	mAppearanceChanged = mAppearanceChanged || !(value == mBgOverride);
	mBgOverride = value;
}

void KopetePrefs::setShowTray(bool value)
{
	mShowTray = value;
}

QString KopetePrefs::fileContents( const QString &path )
{
 	QString contents;
	QFile file( path );
	if ( file.open( IO_ReadOnly ) )
	{
		QTextStream stream( &file );
		contents = stream.read();
		file.close();
	}

	return contents;
}

#include "kopeteprefs.moc"

// vim: set noet ts=4 sts=4 sw=4:
<|endoftext|>