<commit_before>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *   - Laura Schlimmer <laura@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <eventql/eventql.h>
#include <eventql/util/stdtypes.h>
#include <eventql/util/application.h>
#include <eventql/util/cli/flagparser.h>
#include <eventql/util/csv/BinaryCSVOutputStream.h>
#include <eventql/util/http/httpclient.h>
#include <eventql/util/json/jsonoutputstream.h>
#include "eventql/util/thread/FixedSizeThreadPool.h"
#include "eventql/util/util/SimpleRateLimit.h"
#include <eventql/util/mysql/MySQL.h>
#include <eventql/util/mysql/MySQLConnection.h>

using namespace eventql;

struct UploadShard {
  Buffer data;
  size_t nrows;
};

void run(const cli::FlagParser& flags) {
  auto source_table = flags.getString("source_table");
  auto destination_table = flags.getString("destination_table");
  auto shard_size = flags.getInt("shard_size");
  auto num_upload_threads = flags.getInt("upload_threads");
  auto mysql_addr = flags.getString("mysql");
  auto host = flags.getString("host");
  auto port = flags.getInt("port");
  auto db = flags.getString("database");

  logInfo("mysql2evql", "Connecting to MySQL Server...");

  util::mysql::mysqlInit();
  auto mysql_conn = util::mysql::MySQLConnection::openConnection(URI(mysql_addr));

  logInfo(
      "mysql2evql",
      "Analyzing the input table. This might take a few minutes...");

  auto schema = mysql_conn->getTableSchema(source_table);
  logDebug("mysql2evql", "Table Schema:\n$0", schema->toString());
  Vector<String> column_names;
  for (const auto& field : schema->fields()) {
    column_names.emplace_back(field.name);
  }

  /* status line */
  std::atomic<size_t> num_rows_uploaded(0);
  util::SimpleRateLimitedFn status_line(kMicrosPerSecond, [&] () {
    logInfo(
        "mysql2evql",
        "Uploading... $0 rows",
        num_rows_uploaded.load());
  });

  /* start upload threads */
  http::HTTPMessage::HeaderList auth_headers;
  if (flags.isSet("auth_token")) {
    auth_headers.emplace_back(
        "Authorization",
        StringUtil::format("Token $0", flags.getString("auth_token")));
  //} else if (!cfg_.getPassword().isEmpty()) {
  //  auth_headers.emplace_back(
  //      "Authorization",
  //      StringUtil::format("Basic $0",
  //          util::Base64::encode(
  //              cfg_.getUser() + ":" + cfg_.getPassword().get())));
  }

  bool upload_done = false;
  thread::Queue<UploadShard> upload_queue(1);
  Vector<std::thread> upload_threads(num_upload_threads);
  for (size_t i = 0; i < num_upload_threads; ++i) {
    upload_threads[i] = std::thread([&] {
      while (!upload_done) {
        auto shard = upload_queue.interruptiblePop();
        if (shard.isEmpty()) {
          continue;
        }

       logDebug(
          "mysql2evql",
          "Uploading batch; target=$0:$1 size=$2MB",
          host,
          port,
          shard.get().data.size() / 1000000.0);

        try {
          auto insert_uri = StringUtil::format(
              "http://$0:$1/api/v1/tables/insert",
              host,
              port);

          http::HTTPClient http_client;
          auto upload_res = http_client.executeRequest(
              http::HTTPRequest::mkPost(
                  insert_uri,
                  "[" + shard.get().data.toString() + "]",
                  auth_headers));

          if (upload_res.statusCode() != 201) {
            logError(
                "mysql2evql", "[FATAL ERROR]: HTTP Status Code $0 $1",
                upload_res.statusCode(),
                upload_res.body().toString());
            RAISE(kRuntimeError, upload_res.body().toString());
          }

          num_rows_uploaded += shard.get().nrows;
          status_line.runMaybe();
        } catch (const std::exception& e) {
          logError("mysql2evql", e, "error while uploading table data");
        }
      }
    });
  }

  /* fetch rows from mysql */
  UploadShard shard;
  shard.nrows = 0;
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&shard.data));

  String where_expr;
  if (flags.isSet("filter")) {
    where_expr = "WHERE " + flags.getString("filter");
  }

  auto get_rows_qry = StringUtil::format(
      "SELECT * FROM `$0` $1;",
     source_table,
     where_expr);

  mysql_conn->executeQuery(
      get_rows_qry,
      [&] (const Vector<String>& column_values) -> bool {
    ++shard.nrows;

    if (shard.nrows > 1) {
      json.addComma();
    }

    json.beginObject();
    json.addObjectEntry("database");
    json.addString(db);
    json.addComma();
    json.addObjectEntry("table");
    json.addString(destination_table);
    json.addComma();
    json.addObjectEntry("data");
    json.beginObject();

    for (size_t i = 0; i < column_names.size() && i < column_values.size(); ++i) {
      if (i > 0 ){
        json.addComma();
      }

      json.addObjectEntry(column_names[i]);
      json.addString(column_values[i]);
    }

    json.endObject();
    json.endObject();

    if (shard.nrows == shard_size) {
      upload_queue.insert(shard, true);
      shard.data.clear();
      shard.nrows = 0;
    }

    status_line.runMaybe();
    return true;
  });

  if (shard.nrows > 0) {
    upload_queue.insert(shard, true);
  }

  upload_queue.waitUntilEmpty();
  upload_done = true;
  upload_queue.wakeup();
  for (auto& t : upload_threads) {
    t.join();
  }

  status_line.runForce();
  logInfo("mysql2evql", "Upload finished successfully :)");
}

int main(int argc, const char** argv) {
  Application::init();
  Application::logToStderr("mysql2evql");

  cli::FlagParser flags;

  flags.defineFlag(
      "loglevel",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.defineFlag(
      "source_table",
      cli::FlagParser::T_STRING,
      true,
      "t",
      NULL,
      "table name",
      "<name>");

  flags.defineFlag(
      "destination_table",
      cli::FlagParser::T_STRING,
      true,
      "t",
      NULL,
      "table name",
      "<name>");

  flags.defineFlag(
      "host",
      cli::FlagParser::T_STRING,
      true,
      "h",
      NULL,
      "eventql server hostname",
      "<host>");

  flags.defineFlag(
      "port",
      cli::FlagParser::T_INTEGER,
      true,
      "p",
      NULL,
      "eventql server port",
      "<port>");

  flags.defineFlag(
      "database",
      cli::FlagParser::T_STRING,
      true,
      "db",
      "",
      "eventql database",
      "<database>");

  flags.defineFlag(
      "auth_token",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "auth token",
      "<token>");

  flags.defineFlag(
      "mysql",
      cli::FlagParser::T_STRING,
      true,
      "x",
      "mysql://localhost:3306/mydb?user=root",
      "MySQL connection string",
      "<url>");

  flags.defineFlag(
      "filter",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "boolean sql expression",
      "<sql_expr>");

  flags.defineFlag(
      "shard_size",
      cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "128",
      "shard size",
      "<num>");

  flags.defineFlag(
      "upload_threads",
      cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8",
      "concurrent uploads",
      "<num>");

  try {
    flags.parseArgv(argc, argv);
  } catch (const StandardException& e) {
    logError("mysql2evql", "$0", e.what());
    auto stdout_os = OutputStream::getStdout();
    flags.printUsage(stdout_os.get());
    return 0;
  }

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  try {
    run(flags);
    return 0;
  } catch (const StandardException& e) {
    return 1;
  }
}
<commit_msg>proper return code<commit_after>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *   - Laura Schlimmer <laura@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <eventql/eventql.h>
#include <eventql/util/stdtypes.h>
#include <eventql/util/application.h>
#include <eventql/util/cli/flagparser.h>
#include <eventql/util/csv/BinaryCSVOutputStream.h>
#include <eventql/util/http/httpclient.h>
#include <eventql/util/json/jsonoutputstream.h>
#include "eventql/util/thread/FixedSizeThreadPool.h"
#include "eventql/util/util/SimpleRateLimit.h"
#include <eventql/util/mysql/MySQL.h>
#include <eventql/util/mysql/MySQLConnection.h>

using namespace eventql;

struct UploadShard {
  Buffer data;
  size_t nrows;
};

bool run(const cli::FlagParser& flags) {
  auto source_table = flags.getString("source_table");
  auto destination_table = flags.getString("destination_table");
  auto shard_size = flags.getInt("shard_size");
  auto num_upload_threads = flags.getInt("upload_threads");
  auto mysql_addr = flags.getString("mysql");
  auto host = flags.getString("host");
  auto port = flags.getInt("port");
  auto db = flags.getString("database");

  logInfo("mysql2evql", "Connecting to MySQL Server...");

  util::mysql::mysqlInit();
  auto mysql_conn = util::mysql::MySQLConnection::openConnection(URI(mysql_addr));

  logInfo(
      "mysql2evql",
      "Analyzing the input table. This might take a few minutes...");

  auto schema = mysql_conn->getTableSchema(source_table);
  logDebug("mysql2evql", "Table Schema:\n$0", schema->toString());
  Vector<String> column_names;
  for (const auto& field : schema->fields()) {
    column_names.emplace_back(field.name);
  }

  /* status line */
  std::atomic<size_t> num_rows_uploaded(0);
  util::SimpleRateLimitedFn status_line(kMicrosPerSecond, [&] () {
    logInfo(
        "mysql2evql",
        "Uploading... $0 rows",
        num_rows_uploaded.load());
  });

  /* start upload threads */
  http::HTTPMessage::HeaderList auth_headers;
  if (flags.isSet("auth_token")) {
    auth_headers.emplace_back(
        "Authorization",
        StringUtil::format("Token $0", flags.getString("auth_token")));
  //} else if (!cfg_.getPassword().isEmpty()) {
  //  auth_headers.emplace_back(
  //      "Authorization",
  //      StringUtil::format("Basic $0",
  //          util::Base64::encode(
  //              cfg_.getUser() + ":" + cfg_.getPassword().get())));
  }

  bool upload_done = false;
  bool upload_error = false;
  thread::Queue<UploadShard> upload_queue(1);
  Vector<std::thread> upload_threads(num_upload_threads);
  for (size_t i = 0; i < num_upload_threads; ++i) {
    upload_threads[i] = std::thread([&] {
      while (!upload_done) {
        auto shard = upload_queue.interruptiblePop();
        if (shard.isEmpty()) {
          continue;
        }

       logDebug(
          "mysql2evql",
          "Uploading batch; target=$0:$1 size=$2MB",
          host,
          port,
          shard.get().data.size() / 1000000.0);

        try {
          auto insert_uri = StringUtil::format(
              "http://$0:$1/api/v1/tables/insert",
              host,
              port);

          http::HTTPClient http_client;
          auto upload_res = http_client.executeRequest(
              http::HTTPRequest::mkPost(
                  insert_uri,
                  "[" + shard.get().data.toString() + "]",
                  auth_headers));

          if (upload_res.statusCode() != 201) {
            logError(
                "mysql2evql", "[FATAL ERROR]: HTTP Status Code $0 $1",
                upload_res.statusCode(),
                upload_res.body().toString());
            RAISE(kRuntimeError, upload_res.body().toString());
          }

          num_rows_uploaded += shard.get().nrows;
          status_line.runMaybe();
        } catch (const std::exception& e) {
          upload_error = true;
          logError("mysql2evql", e, "error while uploading table data");
        }
      }
    });
  }

  /* fetch rows from mysql */
  UploadShard shard;
  shard.nrows = 0;
  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&shard.data));

  String where_expr;
  if (flags.isSet("filter")) {
    where_expr = "WHERE " + flags.getString("filter");
  }

  auto get_rows_qry = StringUtil::format(
      "SELECT * FROM `$0` $1;",
     source_table,
     where_expr);

  mysql_conn->executeQuery(
      get_rows_qry,
      [&] (const Vector<String>& column_values) -> bool {
    ++shard.nrows;

    if (shard.nrows > 1) {
      json.addComma();
    }

    json.beginObject();
    json.addObjectEntry("database");
    json.addString(db);
    json.addComma();
    json.addObjectEntry("table");
    json.addString(destination_table);
    json.addComma();
    json.addObjectEntry("data");
    json.beginObject();

    for (size_t i = 0; i < column_names.size() && i < column_values.size(); ++i) {
      if (i > 0 ){
        json.addComma();
      }

      json.addObjectEntry(column_names[i]);
      json.addString(column_values[i]);
    }

    json.endObject();
    json.endObject();

    if (shard.nrows == shard_size) {
      upload_queue.insert(shard, true);
      shard.data.clear();
      shard.nrows = 0;
    }

    status_line.runMaybe();
    return true;
  });

  if (shard.nrows > 0) {
    upload_queue.insert(shard, true);
  }

  upload_queue.waitUntilEmpty();
  upload_done = true;
  upload_queue.wakeup();
  for (auto& t : upload_threads) {
    t.join();
  }

  status_line.runForce();

  if (upload_error) {
    logInfo("mysql2evql", "Upload finished with errors");
    return false;
  } else {
    logInfo("mysql2evql", "Upload finished successfully :)");
    return true;
  }
}

int main(int argc, const char** argv) {
  Application::init();
  Application::logToStderr("mysql2evql");

  cli::FlagParser flags;

  flags.defineFlag(
      "loglevel",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.defineFlag(
      "source_table",
      cli::FlagParser::T_STRING,
      true,
      "t",
      NULL,
      "table name",
      "<name>");

  flags.defineFlag(
      "destination_table",
      cli::FlagParser::T_STRING,
      true,
      "t",
      NULL,
      "table name",
      "<name>");

  flags.defineFlag(
      "host",
      cli::FlagParser::T_STRING,
      true,
      "h",
      NULL,
      "eventql server hostname",
      "<host>");

  flags.defineFlag(
      "port",
      cli::FlagParser::T_INTEGER,
      true,
      "p",
      NULL,
      "eventql server port",
      "<port>");

  flags.defineFlag(
      "database",
      cli::FlagParser::T_STRING,
      true,
      "db",
      "",
      "eventql database",
      "<database>");

  flags.defineFlag(
      "auth_token",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "auth token",
      "<token>");

  flags.defineFlag(
      "mysql",
      cli::FlagParser::T_STRING,
      true,
      "x",
      "mysql://localhost:3306/mydb?user=root",
      "MySQL connection string",
      "<url>");

  flags.defineFlag(
      "filter",
      cli::FlagParser::T_STRING,
      false,
      NULL,
      NULL,
      "boolean sql expression",
      "<sql_expr>");

  flags.defineFlag(
      "shard_size",
      cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "128",
      "shard size",
      "<num>");

  flags.defineFlag(
      "upload_threads",
      cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "8",
      "concurrent uploads",
      "<num>");

  try {
    flags.parseArgv(argc, argv);
  } catch (const StandardException& e) {
    logError("mysql2evql", "$0", e.what());
    auto stdout_os = OutputStream::getStdout();
    flags.printUsage(stdout_os.get());
    return 0;
  }

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  try {
    if (run(flags)) {
      return 0;
    } else {
      return 1;
    }
  } catch (const StandardException& e) {
    logFatal("mysql2evql", "$0", e.what());
    return 1;
  }
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"

namespace libtorrent
{
	boost::shared_ptr<file> file_pool::open_file(void* st, std::string const& p
		, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(p);
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::shared_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if (((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr.unique());
				e.file_ptr->close();
				if (!e.file_ptr->open(p, m, ec))
				{
					m_files.erase(i);
					return boost::shared_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
				if (m_low_prio_io)
				{
					FILE_IO_PRIORITY_HINT_INFO priorityHint;
					priorityHint.PriorityHint = IoPriorityHintLow;
					result = SetFileInformationByHandle(e.file_ptr->native_handle(),
						FileIoPriorityHintInfo, &priorityHint, sizeof(PriorityHint));
				}
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		if (!e.file_ptr->open(p, m, ec))
			return boost::shared_ptr<file>();
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(p, e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;
		m_files.erase(i);
	}

	void file_pool::release(std::string const& p)
	{
		mutex::scoped_lock l(m_mutex);

		file_set::iterator i = m_files.find(p);
		if (i != m_files.end()) m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		mutex::scoped_lock l(m_mutex);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}
<commit_msg>fixed windows unit tests<commit_after>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"

namespace libtorrent
{
	boost::shared_ptr<file> file_pool::open_file(void* st, std::string const& p
		, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(p);
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::shared_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if (((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr.unique());
				e.file_ptr->close();
				if (!e.file_ptr->open(p, m, ec))
				{
					m_files.erase(i);
					return boost::shared_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
// file prio is supported on vista and up
#if _WIN32_WINNT >= 0x0600
				if (m_low_prio_io)
				{
					FILE_IO_PRIORITY_HINT_INFO priorityHint;
					priorityHint.PriorityHint = IoPriorityHintLow;
					result = SetFileInformationByHandle(e.file_ptr->native_handle(),
						FileIoPriorityHintInfo, &priorityHint, sizeof(PriorityHint));
				}
#endif
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		if (!e.file_ptr->open(p, m, ec))
			return boost::shared_ptr<file>();
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(p, e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;
		m_files.erase(i);
	}

	void file_pool::release(std::string const& p)
	{
		mutex::scoped_lock l(m_mutex);

		file_set::iterator i = m_files.find(p);
		if (i != m_files.end()) m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		mutex::scoped_lock l(m_mutex);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}
<|endoftext|>


<commit_before>/// \file src/fmm_method.cc
/// \brief Implementation of FMM Method

#include "include/fmm_method.h"

namespace dashmm {

void FMM::generate(SourceNode &curr, const ExpansionRef expand) const {
  int n_digits = expand.accuracy();
  curr.set_expansion(expand.get_new_expansion(curr.center(), n_digits));
  ExpansionRef currexp = curr.expansion();
  SourceRef sources = curr.parts();
  double scale = 1.0 / curr.size();
  currexp.S_to_M(curr.center(), sources, scale);
}

void FMM::aggregate(SourceNode &curr, const ExpansionRef expand) const {
  int n_digits = expand.accuracy();
  curr.set_expansion(expand.get_new_expansion(curr.center(), n_digits));
  ExpansionRef currexp = curr.expansion();

  for (size_t i = 0; i < 8; ++i) {
    SourceNode kid = curr.child(i);
    if (kid.is_valid()) {
      ExpansionRef kexp = kid.expansion();
      currexp.M_to_M(kexp, i, kid.size());
    }
  }
}

void FMM::inherit(TargetNode &curr, const ExpansionRef expand,
                  size_t which_child) const {
  int n_digits = expand.accuracy();
  curr.set_expansion(expand.get_new_expansion(curr.center(), n_digits));
  ExpansionRef currexp = curr.expansion();

  if (curr.parent().is_valid()) {
    ExpansionRef pexp = curr.parent().expansion();
    currexp.L_to_L(pexp, which_child, curr.size());
  } else {
    curr.set_expansion(expand.get_new_expansion(curr.center(), n_digits));
  }
}

void FMM::process(TargetNode &curr, std::vector<SourceNode> &consider,
                  bool curr_is_leaf) const {
  ExpansionRef currexp = curr.expansion();
  double scale = 1.0 / curr.size();
  TargetRef targets = curr.parts();
  Index t_index = curr.index();

  if (curr_is_leaf) {
    for (auto S = consider.begin(); S != consider.end(); ++S) {
      if (S->level() < curr.level()) {
        if (well_sep_test_asymmetric(t_index, S->index())) {
          SourceRef sources = S->parts();
          currexp.S_to_L(curr.center(), sources, scale);
        } else {
          SourceRef sources = S->parts();
          ExpansionRef expand = S->expansion();
          expand.S_to_T(sources, targets);
        }
      } else {
        if (well_sep_test(S->index(), curr.index())) {
          ExpansionRef expand = S->expansion();
          double s_size = S->size();
          Index s_index = S->index();
          currexp.M_to_L(expand, s_index, s_size, t_index);
        } else {
          proc_coll_recur(curr, *S);
        }
      }
    }

    currexp.L_to_T(targets, scale);
  } else {
    std::vector<SourceNode> newcons{};

    for (auto S = consider.begin(); S != consider.end(); ++S) {
      if (S->level() < curr.level()) {
        if (well_sep_test_asymmetric(t_index, S->index())) {
          SourceRef sources = S->parts();
          currexp.S_to_L(curr.center(), sources, scale);
        } else {
          // a 1; add it to newcons
          newcons.push_back(*S);
        }
      } else {
        if (well_sep_test(S->index(), curr.index())) {
          ExpansionRef expand = S->expansion();
          double s_size = S->size();
          Index s_index = S->index();
          currexp.M_to_L(expand, s_index, s_size, t_index);
        } else {
          bool S_is_leaf = true;
          for (size_t i = 0; i < 8; ++i) {
            SourceNode child = S->child(i);
            if (child.is_valid()) {
              newcons.push_back(child);
              S_is_leaf = false;
            }
          }

          if (S_is_leaf)
            newcons.push_back(*S);
        }
      }
    }

    consider = std::move(newcons);
  }

}

bool FMM::refine_test(bool same_sources_and_targets, const TargetNode &curr,
                      const std::vector<SourceNode> &consider) const {
  if (same_sources_and_targets) {
    return true;
  }

  for (auto i = consider.begin(); i != consider.end(); ++i) {
    if (i->level() == curr.level()) {
      if (!well_sep_test(i->index(), curr.index()) && !i->is_leaf()) {
        return true;
      }
    }
  }

  return false;
}

bool FMM::well_sep_test_asymmetric(Index smaller, Index larger) const {
  int delta = smaller.level() - larger.level();
  int shift = (1 << delta) - 1;
  Index l_mod{larger.x() << delta, larger.y() << delta,
              larger.z() << delta, smaller.level()};
  Index l_mod_top{l_mod.x() + shift, l_mod.y() + shift, l_mod.z() + shift,
                  l_mod.level()};

  //in the asymmetric case, we need to check both sides of the larger box
  // to make sure there is a gap of one of the smaller boxes
  if (abs(smaller.x() - l_mod.x()) > 1
       && abs(smaller.x() - l_mod_top.x()) > 1) return true;
  if (abs(smaller.y() - l_mod.y()) > 1
       && abs(smaller.y() - l_mod_top.y()) > 1) return true;
  if (abs(smaller.z() - l_mod.z()) > 1
       && abs(smaller.z() - l_mod_top.z()) > 1) return true;
  return false;
}

bool FMM::well_sep_test(Index source, Index target) const {
  //When the nodes are the same level, we just need to have at least one
  // index that is different by +/- 2 or more.
  if (abs(source.x() - target.x()) > 1) return true;
  if (abs(source.y() - target.y()) > 1) return true;
  if (abs(source.z() - target.z()) > 1) return true;
  return false;
}

void FMM::proc_coll_recur(TargetNode &T, SourceNode &S) const {
  if (well_sep_test_asymmetric(S.index(), T.index())) {
    ExpansionRef expand = S.expansion();
    TargetRef targets = T.parts();
    double scale = 1.0 / T.size();
    expand.M_to_T(targets, scale);
  } else {
    if (S.is_leaf()) {
      ExpansionRef expand = S.expansion();
      TargetRef targets = T.parts();
      SourceRef sources = S.parts();
      expand.S_to_T(sources, targets);
    } else {
      for (size_t i = 0; i < 8; ++i) {
        SourceNode child = S.child(i);
        if (child.is_valid())
          proc_coll_recur(T, child);
      }
    }
  }
}

} // namespace dashmm
<commit_msg>fix typo that passes a wrong scaling factor to M_to_T<commit_after>/// \file src/fmm_method.cc
/// \brief Implementation of FMM Method

#include "include/fmm_method.h"

namespace dashmm {

void FMM::generate(SourceNode &curr, const ExpansionRef expand) const {
  int n_digits = expand.accuracy();
  curr.set_expansion(expand.get_new_expansion(curr.center(), n_digits));
  ExpansionRef currexp = curr.expansion();
  SourceRef sources = curr.parts();
  double scale = 1.0 / curr.size();
  currexp.S_to_M(curr.center(), sources, scale);
}

void FMM::aggregate(SourceNode &curr, const ExpansionRef expand) const {
  int n_digits = expand.accuracy();
  curr.set_expansion(expand.get_new_expansion(curr.center(), n_digits));
  ExpansionRef currexp = curr.expansion();

  for (size_t i = 0; i < 8; ++i) {
    SourceNode kid = curr.child(i);
    if (kid.is_valid()) {
      ExpansionRef kexp = kid.expansion();
      currexp.M_to_M(kexp, i, kid.size());
    }
  }
}

void FMM::inherit(TargetNode &curr, const ExpansionRef expand,
                  size_t which_child) const {
  int n_digits = expand.accuracy();
  curr.set_expansion(expand.get_new_expansion(curr.center(), n_digits));
  ExpansionRef currexp = curr.expansion();

  if (curr.parent().is_valid()) {
    ExpansionRef pexp = curr.parent().expansion();
    currexp.L_to_L(pexp, which_child, curr.size());
  } else {
    curr.set_expansion(expand.get_new_expansion(curr.center(), n_digits));
  }
}

void FMM::process(TargetNode &curr, std::vector<SourceNode> &consider,
                  bool curr_is_leaf) const {
  ExpansionRef currexp = curr.expansion();
  double scale = 1.0 / curr.size();
  TargetRef targets = curr.parts();
  Index t_index = curr.index();

  if (curr_is_leaf) {
    for (auto S = consider.begin(); S != consider.end(); ++S) {
      if (S->level() < curr.level()) {
        if (well_sep_test_asymmetric(t_index, S->index())) {
          SourceRef sources = S->parts();
          currexp.S_to_L(curr.center(), sources, scale);
        } else {
          SourceRef sources = S->parts();
          ExpansionRef expand = S->expansion();
          expand.S_to_T(sources, targets);
        }
      } else {
        if (well_sep_test(S->index(), curr.index())) {
          ExpansionRef expand = S->expansion();
          double s_size = S->size();
          Index s_index = S->index();
          currexp.M_to_L(expand, s_index, s_size, t_index);
        } else {
          proc_coll_recur(curr, *S);
        }
      }
    }

    currexp.L_to_T(targets, scale);
  } else {
    std::vector<SourceNode> newcons{};

    for (auto S = consider.begin(); S != consider.end(); ++S) {
      if (S->level() < curr.level()) {
        if (well_sep_test_asymmetric(t_index, S->index())) {
          SourceRef sources = S->parts();
          currexp.S_to_L(curr.center(), sources, scale);
        } else {
          // a 1; add it to newcons
          newcons.push_back(*S);
        }
      } else {
        if (well_sep_test(S->index(), curr.index())) {
          ExpansionRef expand = S->expansion();
          double s_size = S->size();
          Index s_index = S->index();
          currexp.M_to_L(expand, s_index, s_size, t_index);
        } else {
          bool S_is_leaf = true;
          for (size_t i = 0; i < 8; ++i) {
            SourceNode child = S->child(i);
            if (child.is_valid()) {
              newcons.push_back(child);
              S_is_leaf = false;
            }
          }

          if (S_is_leaf)
            newcons.push_back(*S);
        }
      }
    }

    consider = std::move(newcons);
  }

}

bool FMM::refine_test(bool same_sources_and_targets, const TargetNode &curr,
                      const std::vector<SourceNode> &consider) const {
  if (same_sources_and_targets) {
    return true;
  }

  for (auto i = consider.begin(); i != consider.end(); ++i) {
    if (i->level() == curr.level()) {
      if (!well_sep_test(i->index(), curr.index()) && !i->is_leaf()) {
        return true;
      }
    }
  }

  return false;
}

bool FMM::well_sep_test_asymmetric(Index smaller, Index larger) const {
  int delta = smaller.level() - larger.level();
  int shift = (1 << delta) - 1;
  Index l_mod{larger.x() << delta, larger.y() << delta,
              larger.z() << delta, smaller.level()};
  Index l_mod_top{l_mod.x() + shift, l_mod.y() + shift, l_mod.z() + shift,
                  l_mod.level()};

  //in the asymmetric case, we need to check both sides of the larger box
  // to make sure there is a gap of one of the smaller boxes
  if (abs(smaller.x() - l_mod.x()) > 1
       && abs(smaller.x() - l_mod_top.x()) > 1) return true;
  if (abs(smaller.y() - l_mod.y()) > 1
       && abs(smaller.y() - l_mod_top.y()) > 1) return true;
  if (abs(smaller.z() - l_mod.z()) > 1
       && abs(smaller.z() - l_mod_top.z()) > 1) return true;
  return false;
}

bool FMM::well_sep_test(Index source, Index target) const {
  //When the nodes are the same level, we just need to have at least one
  // index that is different by +/- 2 or more.
  if (abs(source.x() - target.x()) > 1) return true;
  if (abs(source.y() - target.y()) > 1) return true;
  if (abs(source.z() - target.z()) > 1) return true;
  return false;
}

void FMM::proc_coll_recur(TargetNode &T, SourceNode &S) const {
  if (well_sep_test_asymmetric(S.index(), T.index())) {
    ExpansionRef expand = S.expansion();
    TargetRef targets = T.parts();
    double scale = 1.0 / S.size();
    expand.M_to_T(targets, scale);
  } else {
    if (S.is_leaf()) {
      ExpansionRef expand = S.expansion();
      TargetRef targets = T.parts();
      SourceRef sources = S.parts();
      expand.S_to_T(sources, targets);
    } else {
      for (size_t i = 0; i < 8; ++i) {
        SourceNode child = S.child(i);
        if (child.is_valid())
          proc_coll_recur(T, child);
      }
    }
  }
}

} // namespace dashmm
<|endoftext|>


<commit_before>/*
 * Copyright © 2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file opt_rebalance_tree.cpp
 *
 * Rebalances a reduction expression tree.
 *
 * For reduction operations (e.g., x + y + z + w) we generate an expression
 * tree like
 *
 *        +
 *       / \
 *      +   w
 *     / \
 *    +   z
 *   / \
 *  x   y
 *
 * which we can rebalance into
 *
 *       +
 *      / \
 *     /   \
 *    +     +
 *   / \   / \
 *  x   y z   w
 *
 * to get a better instruction scheduling.
 *
 * See "Tree Rebalancing in Optimal Editor Time and Space" by Quentin F. Stout
 * and Bette L. Warren.
 *
 * Also see http://penguin.ewu.edu/~trolfe/DSWpaper/ for a very readable
 * explanation of the of the tree_to_vine() (rightward rotation) and
 * vine_to_tree() (leftward rotation) algorithms.
 */

#include "ir.h"
#include "ir_visitor.h"
#include "ir_rvalue_visitor.h"
#include "ir_optimization.h"
#include "main/macros.h" /* for MAX2 */

/* The DSW algorithm generates a degenerate tree (really, a linked list) in
 * tree_to_vine(). We'd rather not leave a binary expression with only one
 * operand, so trivial modifications (the ternary operators below) are needed
 * to ensure that we only rotate around the ir_expression nodes of the tree.
 */
static unsigned
tree_to_vine(ir_expression *root)
{
   unsigned size = 0;
   ir_rvalue *vine_tail = root;
   ir_rvalue *remainder = root->operands[1];

   while (remainder != NULL) {
      ir_expression *remainder_temp = remainder->as_expression();
      ir_expression *remainder_left = remainder_temp ?
         remainder_temp->operands[0]->as_expression() : NULL;

      if (remainder_left == NULL) {
         /* move vine_tail down one */
         vine_tail = remainder;
         remainder = remainder->as_expression() ?
            ((ir_expression *)remainder)->operands[1] : NULL;
         size++;
      } else {
         /* rotate */
         ir_expression *tempptr = remainder_left;
         ((ir_expression *)remainder)->operands[0] = tempptr->operands[1];
         tempptr->operands[1] = remainder;
         remainder = tempptr;
         ((ir_expression *)vine_tail)->operands[1] = tempptr;
      }
   }

   return size;
}

static void
compression(ir_expression *root, unsigned count)
{
   ir_expression *scanner = root;

   for (unsigned i = 0; i < count; i++) {
      ir_expression *child = (ir_expression *)scanner->operands[1];
      scanner->operands[1] = child->operands[1];
      scanner = (ir_expression *)scanner->operands[1];
      child->operands[1] = scanner->operands[0];
      scanner->operands[0] = child;
   }
}

static void
vine_to_tree(ir_expression *root, unsigned size)
{
   int n = size - 1;
   for (int m = n / 2; m > 0; m = n / 2) {
      compression(root, m);
      n -= m + 1;
   }
}

namespace {

class ir_rebalance_visitor : public ir_rvalue_enter_visitor {
public:
   ir_rebalance_visitor()
   {
      progress = false;
   }

   void handle_rvalue(ir_rvalue **rvalue);

   bool progress;
};

struct is_reduction_data {
   ir_expression_operation operation;
   const glsl_type *type;
   unsigned num_expr;
   bool is_reduction;
   bool contains_constant;
};

} /* anonymous namespace */

static bool
is_reduction_operation(ir_expression_operation operation)
{
   switch (operation) {
   case ir_binop_add:
   case ir_binop_mul:
   case ir_binop_bit_and:
   case ir_binop_bit_xor:
   case ir_binop_bit_or:
   case ir_binop_logic_and:
   case ir_binop_logic_xor:
   case ir_binop_logic_or:
   case ir_binop_min:
   case ir_binop_max:
      return true;
   default:
      return false;
   }
}

/* Note that this function does not attempt to recognize that reduction trees
 * are already balanced.
 *
 * We return false from this function for a number of reasons other than an
 * expression tree not being a mathematical reduction. Namely,
 *
 *    - if the tree contains multiple constants that we may be able to combine.
 *    - if the tree contains matrices:
 *       - they might contain vec4's with many constant components that we can
 *         simplify after splitting.
 *       - applying the matrix chain ordering optimization is more than just
 *         balancing an expression tree.
 *    - if the tree contains operations on multiple types.
 *    - if the tree contains ir_dereference_{array,record}, since foo[a+b] + c
 *      would trick the visiting pass.
 */
static void
is_reduction(ir_instruction *ir, void *data)
{
   struct is_reduction_data *ird = (struct is_reduction_data *)data;
   if (!ird->is_reduction)
      return;

   /* We don't want to balance a tree that contains multiple constants, since
    * we'll be able to constant fold them if they're not in separate subtrees.
    */
   if (ir->as_constant()) {
      if (ird->contains_constant) {
         ird->is_reduction = false;
      }
      ird->contains_constant = true;
      return;
   }

   /* Array/record dereferences have subtrees that are not part of the expr
    * tree we're balancing. Skip trees containing them.
    */
   if (ir->ir_type == ir_type_dereference_array ||
       ir->ir_type == ir_type_dereference_record) {
      ird->is_reduction = false;
      return;
   }

   ir_expression *expr = ir->as_expression();
   if (!expr)
      return;

   /* Non-constant matrices might still contain constant vec4 that we can
    * constant fold once split up. Handling matrices will need some more
    * work.
    */
   if (expr->type->is_matrix() ||
       expr->operands[0]->type->is_matrix() ||
       (expr->operands[1] && expr->operands[1]->type->is_matrix())) {
      ird->is_reduction = false;
      return;
   }

   if (ird->type != NULL && ird->type != expr->type) {
      ird->is_reduction = false;
      return;
   }
   ird->type = expr->type;

   ird->num_expr++;
   if (is_reduction_operation(expr->operation)) {
      if (ird->operation != 0 && ird->operation != expr->operation)
         ird->is_reduction = false;
      ird->operation = expr->operation;
   } else {
      ird->is_reduction = false;
   }
}

static ir_rvalue *
handle_expression(ir_expression *expr)
{
   struct is_reduction_data ird;
   ird.operation = (ir_expression_operation)0;
   ird.type = NULL;
   ird.num_expr = 0;
   ird.is_reduction = true;
   ird.contains_constant = false;

   visit_tree(expr, is_reduction, (void *)&ird);

   if (ird.is_reduction && ird.num_expr > 2) {
      ir_constant z = ir_constant(0.0f);
      ir_expression pseudo_root = ir_expression(ir_binop_add, &z, expr);

      unsigned size = tree_to_vine(&pseudo_root);
      vine_to_tree(&pseudo_root, size);

      expr = (ir_expression *)pseudo_root.operands[1];
   }
   return expr;
}

static void
update_types(ir_instruction *ir, void *)
{
   ir_expression *expr = ir->as_expression();
   if (!expr)
      return;

   const glsl_type *const new_type =
      glsl_type::get_instance(expr->type->base_type,
                              MAX2(expr->operands[0]->type->components(),
                                   expr->operands[1]->type->components()),
                              1);
   assert(new_type != glsl_type::error_type);
   expr->type = new_type;
}

void
ir_rebalance_visitor::handle_rvalue(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return;

   ir_expression *expr = (*rvalue)->as_expression();
   if (!expr || !is_reduction_operation(expr->operation))
      return;

   ir_rvalue *new_rvalue = handle_expression(expr);

   /* If we failed to rebalance the tree (e.g., because it wasn't a reduction,
    * or some other set of cases) new_rvalue will point to the same root as
    * before.
    *
    * Similarly, if the tree rooted at *rvalue was a reduction and was already
    * balanced, the algorithm will rearrange the tree but will ultimately
    * return an identical tree, so this check will handle that as well and
    * will not set progress = true.
    */
   if (new_rvalue == *rvalue)
      return;

   visit_tree(new_rvalue, NULL, NULL, update_types);

   *rvalue = new_rvalue;
   this->progress = true;
}

bool
do_rebalance_tree(exec_list *instructions)
{
   ir_rebalance_visitor v;

   v.run(instructions);

   return v.progress;
}
<commit_msg>glsl: Make the tree rebalancer use vector_elements, not components().<commit_after>/*
 * Copyright © 2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file opt_rebalance_tree.cpp
 *
 * Rebalances a reduction expression tree.
 *
 * For reduction operations (e.g., x + y + z + w) we generate an expression
 * tree like
 *
 *        +
 *       / \
 *      +   w
 *     / \
 *    +   z
 *   / \
 *  x   y
 *
 * which we can rebalance into
 *
 *       +
 *      / \
 *     /   \
 *    +     +
 *   / \   / \
 *  x   y z   w
 *
 * to get a better instruction scheduling.
 *
 * See "Tree Rebalancing in Optimal Editor Time and Space" by Quentin F. Stout
 * and Bette L. Warren.
 *
 * Also see http://penguin.ewu.edu/~trolfe/DSWpaper/ for a very readable
 * explanation of the of the tree_to_vine() (rightward rotation) and
 * vine_to_tree() (leftward rotation) algorithms.
 */

#include "ir.h"
#include "ir_visitor.h"
#include "ir_rvalue_visitor.h"
#include "ir_optimization.h"
#include "main/macros.h" /* for MAX2 */

/* The DSW algorithm generates a degenerate tree (really, a linked list) in
 * tree_to_vine(). We'd rather not leave a binary expression with only one
 * operand, so trivial modifications (the ternary operators below) are needed
 * to ensure that we only rotate around the ir_expression nodes of the tree.
 */
static unsigned
tree_to_vine(ir_expression *root)
{
   unsigned size = 0;
   ir_rvalue *vine_tail = root;
   ir_rvalue *remainder = root->operands[1];

   while (remainder != NULL) {
      ir_expression *remainder_temp = remainder->as_expression();
      ir_expression *remainder_left = remainder_temp ?
         remainder_temp->operands[0]->as_expression() : NULL;

      if (remainder_left == NULL) {
         /* move vine_tail down one */
         vine_tail = remainder;
         remainder = remainder->as_expression() ?
            ((ir_expression *)remainder)->operands[1] : NULL;
         size++;
      } else {
         /* rotate */
         ir_expression *tempptr = remainder_left;
         ((ir_expression *)remainder)->operands[0] = tempptr->operands[1];
         tempptr->operands[1] = remainder;
         remainder = tempptr;
         ((ir_expression *)vine_tail)->operands[1] = tempptr;
      }
   }

   return size;
}

static void
compression(ir_expression *root, unsigned count)
{
   ir_expression *scanner = root;

   for (unsigned i = 0; i < count; i++) {
      ir_expression *child = (ir_expression *)scanner->operands[1];
      scanner->operands[1] = child->operands[1];
      scanner = (ir_expression *)scanner->operands[1];
      child->operands[1] = scanner->operands[0];
      scanner->operands[0] = child;
   }
}

static void
vine_to_tree(ir_expression *root, unsigned size)
{
   int n = size - 1;
   for (int m = n / 2; m > 0; m = n / 2) {
      compression(root, m);
      n -= m + 1;
   }
}

namespace {

class ir_rebalance_visitor : public ir_rvalue_enter_visitor {
public:
   ir_rebalance_visitor()
   {
      progress = false;
   }

   void handle_rvalue(ir_rvalue **rvalue);

   bool progress;
};

struct is_reduction_data {
   ir_expression_operation operation;
   const glsl_type *type;
   unsigned num_expr;
   bool is_reduction;
   bool contains_constant;
};

} /* anonymous namespace */

static bool
is_reduction_operation(ir_expression_operation operation)
{
   switch (operation) {
   case ir_binop_add:
   case ir_binop_mul:
   case ir_binop_bit_and:
   case ir_binop_bit_xor:
   case ir_binop_bit_or:
   case ir_binop_logic_and:
   case ir_binop_logic_xor:
   case ir_binop_logic_or:
   case ir_binop_min:
   case ir_binop_max:
      return true;
   default:
      return false;
   }
}

/* Note that this function does not attempt to recognize that reduction trees
 * are already balanced.
 *
 * We return false from this function for a number of reasons other than an
 * expression tree not being a mathematical reduction. Namely,
 *
 *    - if the tree contains multiple constants that we may be able to combine.
 *    - if the tree contains matrices:
 *       - they might contain vec4's with many constant components that we can
 *         simplify after splitting.
 *       - applying the matrix chain ordering optimization is more than just
 *         balancing an expression tree.
 *    - if the tree contains operations on multiple types.
 *    - if the tree contains ir_dereference_{array,record}, since foo[a+b] + c
 *      would trick the visiting pass.
 */
static void
is_reduction(ir_instruction *ir, void *data)
{
   struct is_reduction_data *ird = (struct is_reduction_data *)data;
   if (!ird->is_reduction)
      return;

   /* We don't want to balance a tree that contains multiple constants, since
    * we'll be able to constant fold them if they're not in separate subtrees.
    */
   if (ir->as_constant()) {
      if (ird->contains_constant) {
         ird->is_reduction = false;
      }
      ird->contains_constant = true;
      return;
   }

   /* Array/record dereferences have subtrees that are not part of the expr
    * tree we're balancing. Skip trees containing them.
    */
   if (ir->ir_type == ir_type_dereference_array ||
       ir->ir_type == ir_type_dereference_record) {
      ird->is_reduction = false;
      return;
   }

   ir_expression *expr = ir->as_expression();
   if (!expr)
      return;

   /* Non-constant matrices might still contain constant vec4 that we can
    * constant fold once split up. Handling matrices will need some more
    * work.
    */
   if (expr->type->is_matrix() ||
       expr->operands[0]->type->is_matrix() ||
       (expr->operands[1] && expr->operands[1]->type->is_matrix())) {
      ird->is_reduction = false;
      return;
   }

   if (ird->type != NULL && ird->type != expr->type) {
      ird->is_reduction = false;
      return;
   }
   ird->type = expr->type;

   ird->num_expr++;
   if (is_reduction_operation(expr->operation)) {
      if (ird->operation != 0 && ird->operation != expr->operation)
         ird->is_reduction = false;
      ird->operation = expr->operation;
   } else {
      ird->is_reduction = false;
   }
}

static ir_rvalue *
handle_expression(ir_expression *expr)
{
   struct is_reduction_data ird;
   ird.operation = (ir_expression_operation)0;
   ird.type = NULL;
   ird.num_expr = 0;
   ird.is_reduction = true;
   ird.contains_constant = false;

   visit_tree(expr, is_reduction, (void *)&ird);

   if (ird.is_reduction && ird.num_expr > 2) {
      ir_constant z = ir_constant(0.0f);
      ir_expression pseudo_root = ir_expression(ir_binop_add, &z, expr);

      unsigned size = tree_to_vine(&pseudo_root);
      vine_to_tree(&pseudo_root, size);

      expr = (ir_expression *)pseudo_root.operands[1];
   }
   return expr;
}

static void
update_types(ir_instruction *ir, void *)
{
   ir_expression *expr = ir->as_expression();
   if (!expr)
      return;

   const glsl_type *const new_type =
      glsl_type::get_instance(expr->type->base_type,
                              MAX2(expr->operands[0]->type->vector_elements,
                                   expr->operands[1]->type->vector_elements),
                              1);
   assert(new_type != glsl_type::error_type);
   expr->type = new_type;
}

void
ir_rebalance_visitor::handle_rvalue(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return;

   ir_expression *expr = (*rvalue)->as_expression();
   if (!expr || !is_reduction_operation(expr->operation))
      return;

   ir_rvalue *new_rvalue = handle_expression(expr);

   /* If we failed to rebalance the tree (e.g., because it wasn't a reduction,
    * or some other set of cases) new_rvalue will point to the same root as
    * before.
    *
    * Similarly, if the tree rooted at *rvalue was a reduction and was already
    * balanced, the algorithm will rearrange the tree but will ultimately
    * return an identical tree, so this check will handle that as well and
    * will not set progress = true.
    */
   if (new_rvalue == *rvalue)
      return;

   visit_tree(new_rvalue, NULL, NULL, update_types);

   *rvalue = new_rvalue;
   this->progress = true;
}

bool
do_rebalance_tree(exec_list *instructions)
{
   ir_rebalance_visitor v;

   v.run(instructions);

   return v.progress;
}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "FilterHighpass.h"
#include "Filterfill.h"
#include "Pixel8.h"
#include "Bitmap.h"

#include <iostream>
#include <sstream>

using namespace std;

namespace avg {

FilterHighpass::FilterHighpass()
{
}

FilterHighpass::~FilterHighpass()
{
}

BitmapPtr FilterHighpass::apply(BitmapPtr pBmpSrc)
{
    assert(pBmpSrc->getPixelFormat() == I8);
    BitmapPtr pBmpDest = BitmapPtr(new Bitmap(pBmpSrc->getSize(), I8,
            pBmpSrc->getName()));
    int SrcStride = pBmpSrc->getStride();
    int DestStride = pBmpDest->getStride();
    unsigned char * pSrcLine = pBmpSrc->getPixels()+3*SrcStride;
    unsigned char * pDestLine = pBmpDest->getPixels()+3*DestStride;
    IntPoint size = pBmpDest->getSize();
    for (int y = 3; y<size.y-3; ++y) {
        unsigned char * pSrcPixel = pSrcLine+3;
        unsigned char * pDstPixel = pDestLine;
        *pDstPixel++ = 128;
        *pDstPixel++ = 128;
        *pDstPixel++ = 128;
        for (int x = 3; x < size.x-3; ++x) {
            // Convolution Matrix is
            // -1  0  0   0  -1
            //  0 -1  0  -1   0
            //  0  0  8   0   0
            //  0 -1  0  -1   0
            // -1  0  0   0  -1
            // Actually, it's 7x7, but you get the idea.
            *pDstPixel =
                128 - int(*(pSrcPixel-2*SrcStride-2) + *(pSrcPixel-2*SrcStride+2) +
                *(pSrcPixel-SrcStride-1) + *(pSrcPixel-1*SrcStride+1) +
                *(pSrcPixel+SrcStride-1) + *(pSrcPixel+1*SrcStride+1) +
                *(pSrcPixel+2*SrcStride-2) + *(pSrcPixel+2*SrcStride+2))/16 +
                *(pSrcPixel)*3/4;
            *pDstPixel -= int(*(pSrcPixel-3*SrcStride-3) + *(pSrcPixel-3*SrcStride+3) +
                *(pSrcPixel+3*SrcStride-3) + *(pSrcPixel+3*SrcStride+3))/16;
/*
            unsigned char *pSrc = pSrcPixel-3*SrcStride-3;
            int Dest = *pSrc;
            pSrc += 6;
            Dest += *pSrc;
            pSrc += SrcStride-5;
            Dest += *pSrc;
            pSrc += 4;
            Dest += *pSrc;
            pSrc += 4*SrcStride-4;
            Dest += *pSrc;
            pSrc += 4;
            Dest += *pSrc;
            pSrc += SrcStride-5;
            Dest += *pSrc;
            pSrc += 6;
            Dest += *pSrc;
            Dest /= 8;
            *pDstPixel = 128+(*pSrcPixel)-Dest;
*/
/*
            unsigned char *pSrc = pSrcPixel-3*SrcStride;
            int Dest = *pSrc;
            pSrc += SrcStride;
            Dest += *pSrc;
            pSrc += SrcStride;
            Dest += *pSrc;
            pSrc += SrcStride-3;
            Dest += *pSrc++;
            Dest += *pSrc++;
            Dest += *pSrc++;
            pSrc++;
            Dest += *pSrc++;
            Dest += *pSrc++;
            Dest += *pSrc;
            pSrc += SrcStride-3;
            Dest += *pSrc;
            pSrc += SrcStride;
            Dest += *pSrc;
            pSrc += SrcStride;
            Dest += *pSrc;
            Dest /= 16;
            *pDstPixel = 128-Dest+*(pSrcPixel)*3/4;
*/
/*
            *pDstPixel =
                128 - int(*(pSrcPixel-3*SrcStride) +
                        *(pSrcPixel-2*SrcStride) +
                        *(pSrcPixel-SrcStride) +
                        *(pSrcPixel-3) + *(pSrcPixel-2) + *(pSrcPixel-1) +
                        *(pSrcPixel+3) + *(pSrcPixel+2) + *(pSrcPixel+1) +
                        *(pSrcPixel+1*SrcStride) +
                        *(pSrcPixel+2*SrcStride) +
                        *(pSrcPixel+3*SrcStride))/16 +
                *(pSrcPixel)*3/4;
*/
            ++pSrcPixel;
            ++pDstPixel;
        }
        *pDstPixel++ = 128;
        *pDstPixel++ = 128;
        *pDstPixel++ = 128;
        pSrcLine += SrcStride;
        pDestLine += DestStride;
    }
    // Set top and bottom borders.
    memset(pBmpDest->getPixels(), 128, DestStride*3);
    memset(pBmpDest->getPixels()+DestStride*(size.y-3), 128, DestStride*3);
    return pBmpDest;
}

}
<commit_msg>Partial overflow bugfix in FilterHighpass.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "FilterHighpass.h"
#include "Filterfill.h"
#include "Pixel8.h"
#include "Bitmap.h"

#include <iostream>
#include <sstream>

using namespace std;

namespace avg {

FilterHighpass::FilterHighpass()
{
}

FilterHighpass::~FilterHighpass()
{
}

BitmapPtr FilterHighpass::apply(BitmapPtr pBmpSrc)
{
    assert(pBmpSrc->getPixelFormat() == I8);
    BitmapPtr pBmpDest = BitmapPtr(new Bitmap(pBmpSrc->getSize(), I8,
            pBmpSrc->getName()));
    int SrcStride = pBmpSrc->getStride();
    int DestStride = pBmpDest->getStride();
    unsigned char * pSrcLine = pBmpSrc->getPixels()+3*SrcStride;
    unsigned char * pDestLine = pBmpDest->getPixels()+3*DestStride;
    IntPoint size = pBmpDest->getSize();
    for (int y = 3; y<size.y-3; ++y) {
        unsigned char * pSrcPixel = pSrcLine+3;
        unsigned char * pDstPixel = pDestLine;
        *pDstPixel++ = 128;
        *pDstPixel++ = 128;
        *pDstPixel++ = 128;
        for (int x = 3; x < size.x-3; ++x) {
            // Convolution Matrix is
            // -1  0  0   0  -1
            //  0 -1  0  -1   0
            //  0  0  8   0   0
            //  0 -1  0  -1   0
            // -1  0  0   0  -1
            // Actually, it's 7x7, but you get the idea.
            *pDstPixel = 128 - int(*(pSrcPixel-3*SrcStride-3) + *(pSrcPixel-3*SrcStride+3) +
                *(pSrcPixel+3*SrcStride-3) + *(pSrcPixel+3*SrcStride+3))/16;
            *pDstPixel +=
                - int(*(pSrcPixel-2*SrcStride-2) + *(pSrcPixel-2*SrcStride+2) +
                      *(pSrcPixel-SrcStride-1) + *(pSrcPixel-1*SrcStride+1) +
                      *(pSrcPixel+SrcStride-1) + *(pSrcPixel+1*SrcStride+1) +
                      *(pSrcPixel+2*SrcStride-2) + *(pSrcPixel+2*SrcStride+2))/16
                + *(pSrcPixel)*3/4;
/*
            unsigned char *pSrc = pSrcPixel-3*SrcStride-3;
            int Dest = *pSrc;
            pSrc += 6;
            Dest += *pSrc;
            pSrc += SrcStride-5;
            Dest += *pSrc;
            pSrc += 4;
            Dest += *pSrc;
            pSrc += 4*SrcStride-4;
            Dest += *pSrc;
            pSrc += 4;
            Dest += *pSrc;
            pSrc += SrcStride-5;
            Dest += *pSrc;
            pSrc += 6;
            Dest += *pSrc;
            Dest /= 8;
            *pDstPixel = 128+(*pSrcPixel)-Dest;
*/
/*
            unsigned char *pSrc = pSrcPixel-3*SrcStride;
            int Dest = *pSrc;
            pSrc += SrcStride;
            Dest += *pSrc;
            pSrc += SrcStride;
            Dest += *pSrc;
            pSrc += SrcStride-3;
            Dest += *pSrc++;
            Dest += *pSrc++;
            Dest += *pSrc++;
            pSrc++;
            Dest += *pSrc++;
            Dest += *pSrc++;
            Dest += *pSrc;
            pSrc += SrcStride-3;
            Dest += *pSrc;
            pSrc += SrcStride;
            Dest += *pSrc;
            pSrc += SrcStride;
            Dest += *pSrc;
            Dest /= 16;
            *pDstPixel = 128-Dest+*(pSrcPixel)*3/4;
*/
/*
            *pDstPixel =
                128 - int(*(pSrcPixel-3*SrcStride) +
                        *(pSrcPixel-2*SrcStride) +
                        *(pSrcPixel-SrcStride) +
                        *(pSrcPixel-3) + *(pSrcPixel-2) + *(pSrcPixel-1) +
                        *(pSrcPixel+3) + *(pSrcPixel+2) + *(pSrcPixel+1) +
                        *(pSrcPixel+1*SrcStride) +
                        *(pSrcPixel+2*SrcStride) +
                        *(pSrcPixel+3*SrcStride))/16 +
                *(pSrcPixel)*3/4;
*/
            ++pSrcPixel;
            ++pDstPixel;
        }
        *pDstPixel++ = 128;
        *pDstPixel++ = 128;
        *pDstPixel++ = 128;
        pSrcLine += SrcStride;
        pDestLine += DestStride;
    }
    // Set top and bottom borders.
    memset(pBmpDest->getPixels(), 128, DestStride*3);
    memset(pBmpDest->getPixels()+DestStride*(size.y-3), 128, DestStride*3);
    return pBmpDest;
}

}
<|endoftext|>


<commit_before>/*
 * Copyright © 2008, 2009 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */
#include <cstdlib>
#include <cstdio>
#include <getopt.h>

#include "ast.h"
#include "glsl_parser_extras.h"
#include "glsl_parser.h"
#include "ir_optimization.h"
#include "ir_print_visitor.h"
#include "program.h"
#include "loop_analysis.h"

extern "C" struct gl_shader *
_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type);

extern "C" void
_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
                       struct gl_shader *sh);

/* Copied from shader_api.c for the stand-alone compiler.
 */
void
_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
                       struct gl_shader *sh)
{
   *ptr = sh;
}

struct gl_shader *
_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
{
   struct gl_shader *shader;

   (void) ctx;

   assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
   shader = talloc_zero(NULL, struct gl_shader);
   if (shader) {
      shader->Type = type;
      shader->Name = name;
      shader->RefCount = 1;
   }
   return shader;
}

static void
initialize_context(struct gl_context *ctx, gl_api api)
{
   memset(ctx, 0, sizeof(*ctx));

   ctx->API = api;

   ctx->Extensions.ARB_draw_buffers = GL_TRUE;
   ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
   ctx->Extensions.EXT_texture_array = GL_TRUE;
   ctx->Extensions.NV_texture_rectangle = GL_TRUE;

   /* 1.10 minimums. */
   ctx->Const.MaxLights = 8;
   ctx->Const.MaxClipPlanes = 8;
   ctx->Const.MaxTextureUnits = 2;

   /* More than the 1.10 minimum to appease parser tests taken from
    * apps that (hopefully) already checked the number of coords.
    */
   ctx->Const.MaxTextureCoordUnits = 4;

   ctx->Const.VertexProgram.MaxAttribs = 16;
   ctx->Const.VertexProgram.MaxUniformComponents = 512;
   ctx->Const.MaxVarying = 8;
   ctx->Const.MaxVertexTextureImageUnits = 0;
   ctx->Const.MaxCombinedTextureImageUnits = 2;
   ctx->Const.MaxTextureImageUnits = 2;
   ctx->Const.FragmentProgram.MaxUniformComponents = 64;

   ctx->Const.MaxDrawBuffers = 2;

   ctx->Driver.NewShader = _mesa_new_shader;
}

/* Returned string will have 'ctx' as its talloc owner. */
static char *
load_text_file(void *ctx, const char *file_name)
{
	char *text = NULL;
	size_t size;
	size_t total_read = 0;
	FILE *fp = fopen(file_name, "rb");

	if (!fp) {
		return NULL;
	}

	fseek(fp, 0L, SEEK_END);
	size = ftell(fp);
	fseek(fp, 0L, SEEK_SET);

	text = (char *) talloc_size(ctx, size + 1);
	if (text != NULL) {
		do {
			size_t bytes = fread(text + total_read,
					     1, size - total_read, fp);
			if (bytes < size - total_read) {
				free(text);
				text = NULL;
				break;
			}

			if (bytes == 0) {
				break;
			}

			total_read += bytes;
		} while (total_read < size);

		text[total_read] = '\0';
	}

	fclose(fp);

	return text;
}

int glsl_es = 0;
int dump_ast = 0;
int dump_hir = 0;
int dump_lir = 0;
int do_link = 0;

const struct option compiler_opts[] = {
   { "glsl-es",  0, &glsl_es,  1 },
   { "dump-ast", 0, &dump_ast, 1 },
   { "dump-hir", 0, &dump_hir, 1 },
   { "dump-lir", 0, &dump_lir, 1 },
   { "link",     0, &do_link,  1 },
   { NULL, 0, NULL, 0 }
};

/**
 * \brief Print proper usage and exit with failure.
 */
void
usage_fail(const char *name)
{

   const char *header =
      "usage: %s [options] <file.vert | file.geom | file.frag>\n"
      "\n"
      "Possible options are:\n";
   printf(header, name, name);
   for (const struct option *o = compiler_opts; o->name != 0; ++o) {
      printf("    --%s\n", o->name);
   }
   exit(EXIT_FAILURE);
}

void
compile_shader(struct gl_context *ctx, struct gl_shader *shader)
{
   struct _mesa_glsl_parse_state *state =
      new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);

   const char *source = shader->Source;
   state->error = preprocess(state, &source, &state->info_log,
			     state->extensions, ctx->API);

   if (!state->error) {
      _mesa_glsl_lexer_ctor(state, source);
      _mesa_glsl_parse(state);
      _mesa_glsl_lexer_dtor(state);
   }

   if (dump_ast) {
      foreach_list_const(n, &state->translation_unit) {
	 ast_node *ast = exec_node_data(ast_node, n, link);
	 ast->print();
      }
      printf("\n\n");
   }

   shader->ir = new(shader) exec_list;
   if (!state->error && !state->translation_unit.is_empty())
      _mesa_ast_to_hir(shader->ir, state);

   /* Print out the unoptimized IR. */
   if (!state->error && dump_hir) {
      validate_ir_tree(shader->ir);
      _mesa_print_ir(shader->ir, state);
   }

   /* Optimization passes */
   if (!state->error && !shader->ir->is_empty()) {
      bool progress;
      do {
	 progress = do_common_optimization(shader->ir, false, 32);
      } while (progress);

      validate_ir_tree(shader->ir);
   }

   /* Print out the resulting IR */
   if (!state->error && dump_lir) {
      _mesa_print_ir(shader->ir, state);
   }

   shader->symbols = state->symbols;
   shader->CompileStatus = !state->error;
   shader->Version = state->language_version;
   memcpy(shader->builtins_to_link, state->builtins_to_link,
	  sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
   shader->num_builtins_to_link = state->num_builtins_to_link;

   if (shader->InfoLog)
      talloc_free(shader->InfoLog);

   shader->InfoLog = state->info_log;

   /* Retain any live IR, but trash the rest. */
   reparent_ir(shader->ir, shader);

   talloc_free(state);

   return;
}

int
main(int argc, char **argv)
{
   int status = EXIT_SUCCESS;
   struct gl_context local_ctx;
   struct gl_context *ctx = &local_ctx;

   int c;
   int idx = 0;
   while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1)
      /* empty */ ;

   if (argc <= optind)
      usage_fail(argv[0]);

   initialize_context(ctx, (glsl_es) ? API_OPENGLES2 : API_OPENGL);

   struct gl_shader_program *whole_program;

   whole_program = talloc_zero (NULL, struct gl_shader_program);
   assert(whole_program != NULL);

   for (/* empty */; argc > optind; optind++) {
      whole_program->Shaders = (struct gl_shader **)
	 talloc_realloc(whole_program, whole_program->Shaders,
			struct gl_shader *, whole_program->NumShaders + 1);
      assert(whole_program->Shaders != NULL);

      struct gl_shader *shader = talloc_zero(whole_program, gl_shader);

      whole_program->Shaders[whole_program->NumShaders] = shader;
      whole_program->NumShaders++;

      const unsigned len = strlen(argv[optind]);
      if (len < 6)
	 usage_fail(argv[0]);

      const char *const ext = & argv[optind][len - 5];
      if (strncmp(".vert", ext, 5) == 0)
	 shader->Type = GL_VERTEX_SHADER;
      else if (strncmp(".geom", ext, 5) == 0)
	 shader->Type = GL_GEOMETRY_SHADER;
      else if (strncmp(".frag", ext, 5) == 0)
	 shader->Type = GL_FRAGMENT_SHADER;
      else
	 usage_fail(argv[0]);

      shader->Source = load_text_file(whole_program, argv[optind]);
      if (shader->Source == NULL) {
	 printf("File \"%s\" does not exist.\n", argv[optind]);
	 exit(EXIT_FAILURE);
      }

      compile_shader(ctx, shader);

      if (!shader->CompileStatus) {
	 printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog);
	 status = EXIT_FAILURE;
	 break;
      }
   }

   if ((status == EXIT_SUCCESS) && do_link)  {
      link_shaders(ctx, whole_program);
      status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE;

      if (strlen(whole_program->InfoLog) > 0)
	 printf("Info log for linking:\n%s\n", whole_program->InfoLog);
   }

   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++)
      talloc_free(whole_program->_LinkedShaders[i]);

   talloc_free(whole_program);
   _mesa_glsl_release_types();
   _mesa_glsl_release_functions();

   return status;
}
<commit_msg>glsl: fix implicit int to bool warning<commit_after>/*
 * Copyright © 2008, 2009 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */
#include <cstdlib>
#include <cstdio>
#include <getopt.h>

#include "ast.h"
#include "glsl_parser_extras.h"
#include "glsl_parser.h"
#include "ir_optimization.h"
#include "ir_print_visitor.h"
#include "program.h"
#include "loop_analysis.h"

extern "C" struct gl_shader *
_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type);

extern "C" void
_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
                       struct gl_shader *sh);

/* Copied from shader_api.c for the stand-alone compiler.
 */
void
_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
                       struct gl_shader *sh)
{
   *ptr = sh;
}

struct gl_shader *
_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
{
   struct gl_shader *shader;

   (void) ctx;

   assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
   shader = talloc_zero(NULL, struct gl_shader);
   if (shader) {
      shader->Type = type;
      shader->Name = name;
      shader->RefCount = 1;
   }
   return shader;
}

static void
initialize_context(struct gl_context *ctx, gl_api api)
{
   memset(ctx, 0, sizeof(*ctx));

   ctx->API = api;

   ctx->Extensions.ARB_draw_buffers = GL_TRUE;
   ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
   ctx->Extensions.EXT_texture_array = GL_TRUE;
   ctx->Extensions.NV_texture_rectangle = GL_TRUE;

   /* 1.10 minimums. */
   ctx->Const.MaxLights = 8;
   ctx->Const.MaxClipPlanes = 8;
   ctx->Const.MaxTextureUnits = 2;

   /* More than the 1.10 minimum to appease parser tests taken from
    * apps that (hopefully) already checked the number of coords.
    */
   ctx->Const.MaxTextureCoordUnits = 4;

   ctx->Const.VertexProgram.MaxAttribs = 16;
   ctx->Const.VertexProgram.MaxUniformComponents = 512;
   ctx->Const.MaxVarying = 8;
   ctx->Const.MaxVertexTextureImageUnits = 0;
   ctx->Const.MaxCombinedTextureImageUnits = 2;
   ctx->Const.MaxTextureImageUnits = 2;
   ctx->Const.FragmentProgram.MaxUniformComponents = 64;

   ctx->Const.MaxDrawBuffers = 2;

   ctx->Driver.NewShader = _mesa_new_shader;
}

/* Returned string will have 'ctx' as its talloc owner. */
static char *
load_text_file(void *ctx, const char *file_name)
{
	char *text = NULL;
	size_t size;
	size_t total_read = 0;
	FILE *fp = fopen(file_name, "rb");

	if (!fp) {
		return NULL;
	}

	fseek(fp, 0L, SEEK_END);
	size = ftell(fp);
	fseek(fp, 0L, SEEK_SET);

	text = (char *) talloc_size(ctx, size + 1);
	if (text != NULL) {
		do {
			size_t bytes = fread(text + total_read,
					     1, size - total_read, fp);
			if (bytes < size - total_read) {
				free(text);
				text = NULL;
				break;
			}

			if (bytes == 0) {
				break;
			}

			total_read += bytes;
		} while (total_read < size);

		text[total_read] = '\0';
	}

	fclose(fp);

	return text;
}

int glsl_es = 0;
int dump_ast = 0;
int dump_hir = 0;
int dump_lir = 0;
int do_link = 0;

const struct option compiler_opts[] = {
   { "glsl-es",  0, &glsl_es,  1 },
   { "dump-ast", 0, &dump_ast, 1 },
   { "dump-hir", 0, &dump_hir, 1 },
   { "dump-lir", 0, &dump_lir, 1 },
   { "link",     0, &do_link,  1 },
   { NULL, 0, NULL, 0 }
};

/**
 * \brief Print proper usage and exit with failure.
 */
void
usage_fail(const char *name)
{

   const char *header =
      "usage: %s [options] <file.vert | file.geom | file.frag>\n"
      "\n"
      "Possible options are:\n";
   printf(header, name, name);
   for (const struct option *o = compiler_opts; o->name != 0; ++o) {
      printf("    --%s\n", o->name);
   }
   exit(EXIT_FAILURE);
}

void
compile_shader(struct gl_context *ctx, struct gl_shader *shader)
{
   struct _mesa_glsl_parse_state *state =
      new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);

   const char *source = shader->Source;
   state->error = preprocess(state, &source, &state->info_log,
			     state->extensions, ctx->API) != 0;

   if (!state->error) {
      _mesa_glsl_lexer_ctor(state, source);
      _mesa_glsl_parse(state);
      _mesa_glsl_lexer_dtor(state);
   }

   if (dump_ast) {
      foreach_list_const(n, &state->translation_unit) {
	 ast_node *ast = exec_node_data(ast_node, n, link);
	 ast->print();
      }
      printf("\n\n");
   }

   shader->ir = new(shader) exec_list;
   if (!state->error && !state->translation_unit.is_empty())
      _mesa_ast_to_hir(shader->ir, state);

   /* Print out the unoptimized IR. */
   if (!state->error && dump_hir) {
      validate_ir_tree(shader->ir);
      _mesa_print_ir(shader->ir, state);
   }

   /* Optimization passes */
   if (!state->error && !shader->ir->is_empty()) {
      bool progress;
      do {
	 progress = do_common_optimization(shader->ir, false, 32);
      } while (progress);

      validate_ir_tree(shader->ir);
   }

   /* Print out the resulting IR */
   if (!state->error && dump_lir) {
      _mesa_print_ir(shader->ir, state);
   }

   shader->symbols = state->symbols;
   shader->CompileStatus = !state->error;
   shader->Version = state->language_version;
   memcpy(shader->builtins_to_link, state->builtins_to_link,
	  sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
   shader->num_builtins_to_link = state->num_builtins_to_link;

   if (shader->InfoLog)
      talloc_free(shader->InfoLog);

   shader->InfoLog = state->info_log;

   /* Retain any live IR, but trash the rest. */
   reparent_ir(shader->ir, shader);

   talloc_free(state);

   return;
}

int
main(int argc, char **argv)
{
   int status = EXIT_SUCCESS;
   struct gl_context local_ctx;
   struct gl_context *ctx = &local_ctx;

   int c;
   int idx = 0;
   while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1)
      /* empty */ ;

   if (argc <= optind)
      usage_fail(argv[0]);

   initialize_context(ctx, (glsl_es) ? API_OPENGLES2 : API_OPENGL);

   struct gl_shader_program *whole_program;

   whole_program = talloc_zero (NULL, struct gl_shader_program);
   assert(whole_program != NULL);

   for (/* empty */; argc > optind; optind++) {
      whole_program->Shaders = (struct gl_shader **)
	 talloc_realloc(whole_program, whole_program->Shaders,
			struct gl_shader *, whole_program->NumShaders + 1);
      assert(whole_program->Shaders != NULL);

      struct gl_shader *shader = talloc_zero(whole_program, gl_shader);

      whole_program->Shaders[whole_program->NumShaders] = shader;
      whole_program->NumShaders++;

      const unsigned len = strlen(argv[optind]);
      if (len < 6)
	 usage_fail(argv[0]);

      const char *const ext = & argv[optind][len - 5];
      if (strncmp(".vert", ext, 5) == 0)
	 shader->Type = GL_VERTEX_SHADER;
      else if (strncmp(".geom", ext, 5) == 0)
	 shader->Type = GL_GEOMETRY_SHADER;
      else if (strncmp(".frag", ext, 5) == 0)
	 shader->Type = GL_FRAGMENT_SHADER;
      else
	 usage_fail(argv[0]);

      shader->Source = load_text_file(whole_program, argv[optind]);
      if (shader->Source == NULL) {
	 printf("File \"%s\" does not exist.\n", argv[optind]);
	 exit(EXIT_FAILURE);
      }

      compile_shader(ctx, shader);

      if (!shader->CompileStatus) {
	 printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog);
	 status = EXIT_FAILURE;
	 break;
      }
   }

   if ((status == EXIT_SUCCESS) && do_link)  {
      link_shaders(ctx, whole_program);
      status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE;

      if (strlen(whole_program->InfoLog) > 0)
	 printf("Info log for linking:\n%s\n", whole_program->InfoLog);
   }

   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++)
      talloc_free(whole_program->_LinkedShaders[i]);

   talloc_free(whole_program);
   _mesa_glsl_release_types();
   _mesa_glsl_release_functions();

   return status;
}
<|endoftext|>


<commit_before>// Check that we transparently fallback to llvm-gcc for i386 kexts, we don't
// support the ABI they use (yet).

// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -fapple-kext -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK < %t %s

// CHECK: cc1plus"
// CHECK: "-fapple-kext"

// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -mkernel -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-MKERNEL < %t %s

// CHECK-MKERNEL: cc1plus"
// CHECK-MKERNEL: "-mkernel"

// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -Wno-self-assign -Wc++11-extensions -Wno-microsoft -Wmicrosoft -Wvla \
// RUN:   -faltivec -mthumb -mcpu=G4 -mlongcall -mno-longcall -msoft-float \
// RUN:   -fapple-kext -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED < %t %s

// CHECK-UNSUPPORTED: cc1plus"
// CHECK-UNSUPPORTED-NOT: "-Wno-self-assign"
// CHECK-UNSUPPORTED-NOT: "-Wc++11-extensions"
// CHECK-UNSUPPORTED-NOT: "-Wno-microsoft"
// CHECK-UNSUPPORTED-NOT: "-Wmicrosoft"
// CHECK-UNSUPPORTED-NOT: "-Wvla"
// CHECK-UNSUPPORTED-NOT: "-faltivec"
// CHECK-UNSUPPORTED-NOT: "-mthumb"
// CHECK-UNSUPPORTED-NOT: "-mlongcall"
// CHECK-UNSUPPORTED: "-mno-longcall"
// CHECK-UNSUPPORTED: "-msoft-float"

// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -Wconstant-logical-operand -save-temps \
// RUN:   -fapple-kext -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED2 < %t %s

// CHECK-UNSUPPORTED2: cc1plus"
// CHECK-UNSUPPORTED2-NOT: "-Wconstant-logical-operand"

// Check that --serialize-diagnostics does not cause an "argument unused" error.
// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -Werror -Wall -Wno-comment -fapple-kext \
// RUN:   --serialize-diagnostics %t.dia -c %s
<commit_msg>Don't actually execute gcc during testing.<commit_after>// Check that we transparently fallback to llvm-gcc for i386 kexts, we don't
// support the ABI they use (yet).

// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -fapple-kext -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK < %t %s

// CHECK: cc1plus"
// CHECK: "-fapple-kext"

// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -mkernel -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-MKERNEL < %t %s

// CHECK-MKERNEL: cc1plus"
// CHECK-MKERNEL: "-mkernel"

// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -Wno-self-assign -Wc++11-extensions -Wno-microsoft -Wmicrosoft -Wvla \
// RUN:   -faltivec -mthumb -mcpu=G4 -mlongcall -mno-longcall -msoft-float \
// RUN:   -fapple-kext -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED < %t %s

// CHECK-UNSUPPORTED: cc1plus"
// CHECK-UNSUPPORTED-NOT: "-Wno-self-assign"
// CHECK-UNSUPPORTED-NOT: "-Wc++11-extensions"
// CHECK-UNSUPPORTED-NOT: "-Wno-microsoft"
// CHECK-UNSUPPORTED-NOT: "-Wmicrosoft"
// CHECK-UNSUPPORTED-NOT: "-Wvla"
// CHECK-UNSUPPORTED-NOT: "-faltivec"
// CHECK-UNSUPPORTED-NOT: "-mthumb"
// CHECK-UNSUPPORTED-NOT: "-mlongcall"
// CHECK-UNSUPPORTED: "-mno-longcall"
// CHECK-UNSUPPORTED: "-msoft-float"

// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -Wconstant-logical-operand -save-temps \
// RUN:   -fapple-kext -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-UNSUPPORTED2 < %t %s

// CHECK-UNSUPPORTED2: cc1plus"
// CHECK-UNSUPPORTED2-NOT: "-Wconstant-logical-operand"

// Check that --serialize-diagnostics does not cause an "argument unused" error.
// RUN: %clang -target i386-apple-darwin10 \
// RUN:   -Werror -Wall -Wno-comment -fapple-kext -### \
// RUN:   --serialize-diagnostics %t.dia -c %s 2>&1 | \
// RUN:   FileCheck --check-prefix=CHECK-UNUSED %s

// CHECK-UNUSED-NOT: argument unused
// CHECK-UNUSED: cc1plus
<|endoftext|>


<commit_before>#include "ieventdispatcher.h"

#include "iconnection.h"

#include <cstdio>

#define IEVENTDISPATCHER_DEBUG

using namespace std;

IEventDispatcher::~IEventDispatcher()
{
    map<FileDescriptor, IConnection*>::iterator it = m_connections.begin();
    for ( ; it != m_connections.end(); it = m_connections.begin() ) {
        it->second->setEventDispatcher(0);
    }
}

bool IEventDispatcher::addConnection(IConnection *conn)
{
    pair<map<FileDescriptor, IConnection*>::iterator, bool> insertResult;
    insertResult = m_connections.insert(make_pair(conn->fileDescriptor(), conn));
    return insertResult.second;
}

bool IEventDispatcher::removeConnection(IConnection *conn)
{
    return m_connections.erase(conn->fileDescriptor());
}

void IEventDispatcher::notifyConnectionForReading(FileDescriptor fd)
{
    std::map<int, IConnection *>::iterator it = m_connections.find(fd);
    if (it != m_connections.end()) {
        it->second->notifyRead();
    } else {
#ifdef IEVENTDISPATCHER_DEBUG
        // while interesting for debugging, this is not an error if a connection was in the epoll
        // set and disconnected in its notifyRead() or notifyWrite() implementation
        printf("IEventDispatcher::notifyRead(): unhandled file descriptor %d.\n", fd);
#endif
    }
}

void IEventDispatcher::notifyConnectionForWriting(FileDescriptor fd)
{
    std::map<int, IConnection *>::iterator it = m_connections.find(fd);
    if (it != m_connections.end()) {
        it->second->notifyRead();
    } else {
#ifdef IEVENTDISPATCHER_DEBUG
        // while interesting for debugging, this is not an error if a connection was in the epoll
        // set and disconnected in its notifyRead() or notifyWrite() implementation
        printf("IEventDispatcher::notifyWrite(): unhandled file descriptor %d.\n", fd);
#endif
    }
}
<commit_msg>In notifyConnectionForWriting(), call notifyWrite(), not notifyRead().<commit_after>#include "ieventdispatcher.h"

#include "iconnection.h"

#include <cstdio>

#define IEVENTDISPATCHER_DEBUG

using namespace std;

IEventDispatcher::~IEventDispatcher()
{
    map<FileDescriptor, IConnection*>::iterator it = m_connections.begin();
    for ( ; it != m_connections.end(); it = m_connections.begin() ) {
        it->second->setEventDispatcher(0);
    }
}

bool IEventDispatcher::addConnection(IConnection *conn)
{
    pair<map<FileDescriptor, IConnection*>::iterator, bool> insertResult;
    insertResult = m_connections.insert(make_pair(conn->fileDescriptor(), conn));
    return insertResult.second;
}

bool IEventDispatcher::removeConnection(IConnection *conn)
{
    return m_connections.erase(conn->fileDescriptor());
}

void IEventDispatcher::notifyConnectionForReading(FileDescriptor fd)
{
    std::map<int, IConnection *>::iterator it = m_connections.find(fd);
    if (it != m_connections.end()) {
        it->second->notifyRead();
    } else {
#ifdef IEVENTDISPATCHER_DEBUG
        // while interesting for debugging, this is not an error if a connection was in the epoll
        // set and disconnected in its notifyRead() or notifyWrite() implementation
        printf("IEventDispatcher::notifyRead(): unhandled file descriptor %d.\n", fd);
#endif
    }
}

void IEventDispatcher::notifyConnectionForWriting(FileDescriptor fd)
{
    std::map<int, IConnection *>::iterator it = m_connections.find(fd);
    if (it != m_connections.end()) {
        it->second->notifyWrite();
    } else {
#ifdef IEVENTDISPATCHER_DEBUG
        // while interesting for debugging, this is not an error if a connection was in the epoll
        // set and disconnected in its notifyRead() or notifyWrite() implementation
        printf("IEventDispatcher::notifyWrite(): unhandled file descriptor %d.\n", fd);
#endif
    }
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2010 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef STREAM_HELPER_HXX_INCLUDED
#define STREAM_HELPER_HXX_INCLUDED

#include "internal/types.hxx"

class IStream;

class BufferStream : public StreamInterface
{
public:
    BufferStream(IStream *str);
    ~BufferStream();
    unsigned long sread (unsigned char *vuf, unsigned long size);
    long stell ();
    long sseek (unsigned long offset, int origin);
private:
    IStream *stream;
};

class FileStream : public StreamInterface
{
public:
    FileStream(const char *filename);
    ~FileStream();
    unsigned long sread (unsigned char *buf, unsigned long size);
    long stell ();
    long sseek (unsigned long offset, int origin);
private:
    FILE *file;
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>WaE: C4099: type name first seen using struct now using class<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2010 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef STREAM_HELPER_HXX_INCLUDED
#define STREAM_HELPER_HXX_INCLUDED

#include "internal/types.hxx"

struct IStream;

class BufferStream : public StreamInterface
{
public:
    BufferStream(IStream *str);
    ~BufferStream();
    unsigned long sread (unsigned char *vuf, unsigned long size);
    long stell ();
    long sseek (unsigned long offset, int origin);
private:
    IStream *stream;
};

class FileStream : public StreamInterface
{
public:
    FileStream(const char *filename);
    ~FileStream();
    unsigned long sread (unsigned char *buf, unsigned long size);
    long stell ();
    long sseek (unsigned long offset, int origin);
private:
    FILE *file;
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>