<commit_before>#include "geocoder.h"

#include <sstream>
#include <deque>
#include <set>
#include <iostream>
#include <algorithm>

using namespace GeoNLP;

Geocoder::Geocoder()
{
}

std::string Geocoder::name_primary(const std::string &dname)
{
  return dname + "/geonlp-primary.sqlite";
}

std::string Geocoder::name_normalized_trie(const std::string &dname)
{
  return dname + "/geonlp-normalized.trie";
}

std::string Geocoder::name_normalized_id(const std::string &dname)
{
  return dname + "/geonlp-normalized-id.kct";
}

Geocoder::Geocoder(const std::string &dbname)
{
  if ( !load(dbname) )
    std::cerr << "Geocoder: error loading " << dbname << std::endl;
}

bool Geocoder::load(const std::string &dbname)
{
  if (dbname == m_database_path && m_database_open) return true;

  // clean before loading anything
  drop();

  bool error = false;
  try
    {
      m_database_path = dbname;
      if ( m_db.connect(name_primary(m_database_path).c_str(),
                        SQLITE_OPEN_READONLY) != SQLITE_OK )
        {
          error = true;
          std::cerr << "Error opening SQLite database\n";
        }

      if ( !error && !check_version() )
        {
          error = true;
        }

      if ( !error &&
           !m_database_norm_id.open(name_normalized_id(m_database_path).c_str(),
                                    kyotocabinet::PolyDB::OREADER | kyotocabinet::PolyDB::ONOLOCK ) )
        {
          error = true;
          std::cerr << "Error opening IDs database\n";
        }

      if ( !error )
        m_trie_norm.load(name_normalized_trie(m_database_path).c_str()); // throws exception on error

      m_database_open = true;
    }
  catch (sqlite3pp::database_error e)
    {
      error = true;
      std::cerr << "Geocoder SQLite exception: " << e.what() << std::endl;
    }
  catch (marisa::Exception e)
    {
      error = true;
      std::cerr << "Geocoder MARISA exception: " << e.what() << std::endl;
    }

  if (error) drop();
  return !error;
}

bool Geocoder::load()
{
  return load( m_database_path );
}

void Geocoder::drop()
{
  m_db.disconnect();
  m_database_norm_id.close();
  m_trie_norm.clear();
  m_database_path = std::string();
  m_database_open = false;
}

bool Geocoder::check_version()
{
  return check_version("2");
}

bool Geocoder::check_version(const char *supported)
{
  // this cannot through exceptions
  try
    {
      sqlite3pp::query qry(m_db, "SELECT value FROM meta WHERE key=\"version\"");

      for (auto v: qry)
	{
	  std::string n;
	  v.getter() >> n;
	  if ( n == supported ) return true;
	  else
	    {
	      std::cerr << "Geocoder: wrong version of the database. Supported: " << supported << " / database version: " << n << std::endl;
	      return false;
	    }
	}
    }
   catch (sqlite3pp::database_error e)
    {
      std::cerr << "Geocoder exception while checking database version: " << e.what() << std::endl;
      return false;
    }

  return false;
}

static std::string v2s(const std::vector<std::string> &v)
{
  std::string s = "{";
  for (auto i: v)
    {
      if (s.length() > 1) s += ", ";
      s += i;
    }
  s += "}";
  return s;
}

bool Geocoder::search(const std::vector<Postal::ParseResult> &parsed_query, std::vector<Geocoder::GeoResult> &result)
{
  if (!m_database_open)
    return false;

  // parse query by libpostal
  std::vector< Postal::Hierarchy > parsed_result;
  Postal::result2hierarchy(parsed_query, parsed_result);

  result.clear();
  m_levels_resolved = 0;

#ifdef GEONLP_PRINT_DEBUG
  std::cout << "Search hierarchies:\n";
#endif
#ifdef GEONLP_PRINT_DEBUG_QUERIES
  std::cout << "\n";
#endif

  try { // catch and process SQLite and other exceptions
    for (const auto &r: parsed_result)
      {
#ifdef GEONLP_PRINT_DEBUG
	for (auto a: r)
	  std::cout << v2s(a) << " / ";
	std::cout << "\n";
#endif

	m_query_count = 0;
        if ( r.size() >= m_levels_resolved ||
             (r.size() == m_levels_resolved && result.size() < m_max_results) )
          search(r, result);
#ifdef GEONLP_PRINT_DEBUG_QUERIES
        else
          std::cout << "Skipping hierarchy since search result already has more levels than provided\n";
#endif
#ifdef GEONLP_PRINT_DEBUG_QUERIES
	std::cout << "\n";
#endif
      }

#ifdef GEONLP_PRINT_DEBUG
    std::cout << "\n";
#endif

    // fill the data
    for (GeoResult &r: result)
      {
	get_name(r.id, r.title, r.address, m_levels_in_title);
	r.type = get_type(r.id);

	sqlite3pp::query qry(m_db, "SELECT latitude, longitude FROM object_primary WHERE id=?");
	qry.bind(1, r.id);
	for (auto v: qry)
	  {
	    // only one entry is expected
	    v.getter() >> r.latitude >> r.longitude;
	    break;
	  }
      }
  }
  catch (sqlite3pp::database_error e)
    {
      std::cerr << "Geocoder exception: " << e.what() << std::endl;
      return false;
    }

  return true;
}

bool Geocoder::search(const Postal::Hierarchy &parsed,
                      std::vector<Geocoder::GeoResult> &result, size_t level,
                      long long int range0, long long int range1)
{
  if ( level >= parsed.size() || (m_max_queries_per_hierarchy>0 && m_query_count > m_max_queries_per_hierarchy) )
    return false;

  m_query_count++;

  std::set<long long int> ids_explored; /// keeps all ids which have been used to search further at this level

  // help structure keeping marisa-found search string with found ids
  struct IntermediateResult
  {
    std::string txt;
    index_id_value id;
    IntermediateResult(const std::string &t, index_id_value i): txt(t), id(i) {}
    bool operator<(const IntermediateResult &A) const
    { return ( txt.length() < A.txt.length() || (txt.length() == A.txt.length() && txt<A.txt) || (txt==A.txt && id<A.id) ); }
  };

  std::deque<IntermediateResult> search_result;
  for (const std::string s: parsed[level])
    {
      marisa::Agent agent;
      agent.set_query(s.c_str());
      while (m_trie_norm.predictive_search(agent))
        {
          std::string val;
          if ( m_database_norm_id.get( make_id_key( agent.key().id() ), &val) )
            {
              index_id_value *idx, *idx1;
              if ( get_id_range(val, (level==0), range0, range1,
                                &idx, &idx1) )
                {
                  for (; idx < idx1; ++idx)
                    {
                      long long int id = *idx;
                      if ( level == 0 || ( id > range0 && id <= range1 ) )
                        {
                          IntermediateResult r( std::string(agent.key().ptr(), agent.key().length()),
                                                id );
                          search_result.push_back(r);
                        }
                      else std::cerr << "Internal error " << __FILE__ << " - " << __LINE__ << "\n";
                    }
                }
            }
          else
            {
              std::cerr << "Internal inconsistency of the databases: TRIE " << agent.key().id() << "\n";
            }
        }
    }

  std::sort(search_result.begin(), search_result.end());

  bool last_level = ( level+1 >= parsed.size() );
  for (const IntermediateResult &branch: search_result)
    {
      long long int id = branch.id;
      long long int last_subobject = id;

      if (ids_explored.count(id) > 0)
        continue; // has been looked into it already

      ids_explored.insert(id);

      // are we interested in this result even if it doesn't have subregions?
      if (!last_level)
        {
          sqlite3pp::query qry(m_db, "SELECT last_subobject FROM hierarchy WHERE prim_id=?");
          qry.bind(1, id);
          for (auto v: qry)
            {
              // only one entry is expected
              v.getter() >> last_subobject;
              break;
            }

          // check if we have results which are better than this one if it
          // does not have any subobjects
          if (m_levels_resolved > level+1 && id >= last_subobject)
            continue; // take the next search_result
        }

      if ( last_level ||
	   last_subobject <= id ||
	   !search(parsed, result, level+1, id, last_subobject) )
        {
	  size_t levels_resolved = level+1;
	  if ( m_levels_resolved < levels_resolved )
            {
	      result.clear();
	      m_levels_resolved = levels_resolved;
            }

	  if (m_levels_resolved == levels_resolved && (m_max_results==0 || result.size() < m_max_results))
            {
	      bool have_already = false;
	      for (const auto &r: result)
		if (r.id == id)
		  {
		    have_already = true;
		    break;
		  }

	      if (!have_already)
                {
		  GeoResult r;
		  r.id = id;
		  r.levels_resolved = levels_resolved;
		  result.push_back(r);
                }
            }
        }
    }

  return !ids_explored.empty();
}

void Geocoder::get_name(long long id, std::string &title, std::string &full, int levels_in_title)
{
  long long int parent;
  std::string name;

  sqlite3pp::query qry(m_db, "SELECT name, parent FROM object_primary WHERE id=?");
  qry.bind(1, id);
  for (auto v: qry)
    {
      // only one entry is expected
      v.getter() >> name >> parent;

      if (!full.empty()) full += ", ";
      full += name;

      if (levels_in_title > 0)
        {
	  if (!title.empty()) title += ", ";
	  title += name;
        }

      get_name(parent, title, full, levels_in_title-1);
      return;
    }
}

std::string Geocoder::get_type(long long id)
{
  std::string name;

  sqlite3pp::query qry(m_db, "SELECT t.name FROM object_primary o JOIN type t ON t.id=o.type_id WHERE o.id=?");
  qry.bind(1, id);

  for (auto v: qry)
    {
      std::string n;
      v.getter() >> n;

      if (!name.empty()) name += ", ";
      name += n;
    }

  return name;
}

bool Geocoder::get_id_range(std::string &v, bool full_range, index_id_value range0, index_id_value range1,
                            index_id_value* *idx0, index_id_value* *idx1)
{
  int sz = get_id_number_of_values(v);
  index_id_value* v0 = (index_id_value*)v.data();
  if (sz == 0)
    return false;

  if (full_range)
    {
      *idx0 = v0;
      *idx1 = v0 + sz;
      return true;
    }

  *idx0 = std::lower_bound(v0, v0 + sz, range0);
  if (*idx0 - v0 >= sz) return false;

  *idx1 = std::upper_bound(v0, v0 + sz, range1);
  if (*idx1 - v0 >= sz && *(v0) > range1 ) return false;

  return true;
}
<commit_msg>small optimization<commit_after>#include "geocoder.h"

#include <sstream>
#include <deque>
#include <set>
#include <iostream>
#include <algorithm>

using namespace GeoNLP;

Geocoder::Geocoder()
{
}

std::string Geocoder::name_primary(const std::string &dname)
{
  return dname + "/geonlp-primary.sqlite";
}

std::string Geocoder::name_normalized_trie(const std::string &dname)
{
  return dname + "/geonlp-normalized.trie";
}

std::string Geocoder::name_normalized_id(const std::string &dname)
{
  return dname + "/geonlp-normalized-id.kct";
}

Geocoder::Geocoder(const std::string &dbname)
{
  if ( !load(dbname) )
    std::cerr << "Geocoder: error loading " << dbname << std::endl;
}

bool Geocoder::load(const std::string &dbname)
{
  if (dbname == m_database_path && m_database_open) return true;

  // clean before loading anything
  drop();

  bool error = false;
  try
    {
      m_database_path = dbname;
      if ( m_db.connect(name_primary(m_database_path).c_str(),
                        SQLITE_OPEN_READONLY) != SQLITE_OK )
        {
          error = true;
          std::cerr << "Error opening SQLite database\n";
        }

      if ( !error && !check_version() )
        {
          error = true;
        }

      if ( !error &&
           !m_database_norm_id.open(name_normalized_id(m_database_path).c_str(),
                                    kyotocabinet::PolyDB::OREADER | kyotocabinet::PolyDB::ONOLOCK ) )
        {
          error = true;
          std::cerr << "Error opening IDs database\n";
        }

      if ( !error )
        m_trie_norm.load(name_normalized_trie(m_database_path).c_str()); // throws exception on error

      m_database_open = true;
    }
  catch (sqlite3pp::database_error e)
    {
      error = true;
      std::cerr << "Geocoder SQLite exception: " << e.what() << std::endl;
    }
  catch (marisa::Exception e)
    {
      error = true;
      std::cerr << "Geocoder MARISA exception: " << e.what() << std::endl;
    }

  if (error) drop();
  return !error;
}

bool Geocoder::load()
{
  return load( m_database_path );
}

void Geocoder::drop()
{
  m_db.disconnect();
  m_database_norm_id.close();
  m_trie_norm.clear();
  m_database_path = std::string();
  m_database_open = false;
}

bool Geocoder::check_version()
{
  return check_version("2");
}

bool Geocoder::check_version(const char *supported)
{
  // this cannot through exceptions
  try
    {
      sqlite3pp::query qry(m_db, "SELECT value FROM meta WHERE key=\"version\"");

      for (auto v: qry)
	{
	  std::string n;
	  v.getter() >> n;
	  if ( n == supported ) return true;
	  else
	    {
	      std::cerr << "Geocoder: wrong version of the database. Supported: " << supported << " / database version: " << n << std::endl;
	      return false;
	    }
	}
    }
   catch (sqlite3pp::database_error e)
    {
      std::cerr << "Geocoder exception while checking database version: " << e.what() << std::endl;
      return false;
    }

  return false;
}

static std::string v2s(const std::vector<std::string> &v)
{
  std::string s = "{";
  for (auto i: v)
    {
      if (s.length() > 1) s += ", ";
      s += i;
    }
  s += "}";
  return s;
}

bool Geocoder::search(const std::vector<Postal::ParseResult> &parsed_query, std::vector<Geocoder::GeoResult> &result)
{
  if (!m_database_open)
    return false;

  // parse query by libpostal
  std::vector< Postal::Hierarchy > parsed_result;
  Postal::result2hierarchy(parsed_query, parsed_result);

  result.clear();
  m_levels_resolved = 0;

#ifdef GEONLP_PRINT_DEBUG
  std::cout << "Search hierarchies:\n";
#endif
#ifdef GEONLP_PRINT_DEBUG_QUERIES
  std::cout << "\n";
#endif

  try { // catch and process SQLite and other exceptions
    for (const auto &r: parsed_result)
      {
#ifdef GEONLP_PRINT_DEBUG
	for (auto a: r)
	  std::cout << v2s(a) << " / ";
	std::cout << "\n";
#endif

	m_query_count = 0;
        if ( r.size() >= m_levels_resolved ||
             (r.size() == m_levels_resolved && result.size() < m_max_results) )
          search(r, result);
#ifdef GEONLP_PRINT_DEBUG_QUERIES
        else
          std::cout << "Skipping hierarchy since search result already has more levels than provided\n";
#endif
#ifdef GEONLP_PRINT_DEBUG_QUERIES
	std::cout << "\n";
#endif
      }

#ifdef GEONLP_PRINT_DEBUG
    std::cout << "\n";
#endif

    // fill the data
    for (GeoResult &r: result)
      {
	get_name(r.id, r.title, r.address, m_levels_in_title);
	r.type = get_type(r.id);

	sqlite3pp::query qry(m_db, "SELECT latitude, longitude FROM object_primary WHERE id=?");
	qry.bind(1, r.id);
	for (auto v: qry)
	  {
	    // only one entry is expected
	    v.getter() >> r.latitude >> r.longitude;
	    break;
	  }
      }
  }
  catch (sqlite3pp::database_error e)
    {
      std::cerr << "Geocoder exception: " << e.what() << std::endl;
      return false;
    }

  return true;
}

bool Geocoder::search(const Postal::Hierarchy &parsed,
                      std::vector<Geocoder::GeoResult> &result, size_t level,
                      long long int range0, long long int range1)
{
  if ( level >= parsed.size() || (m_max_queries_per_hierarchy>0 && m_query_count > m_max_queries_per_hierarchy) )
    return false;

  m_query_count++;

  std::set<long long int> ids_explored; /// keeps all ids which have been used to search further at this level

  // help structure keeping marisa-found search string with found ids
  struct IntermediateResult
  {
    std::string txt;
    index_id_value id;
    IntermediateResult(const std::string &t, index_id_value i): txt(t), id(i) {}
    bool operator<(const IntermediateResult &A) const
    { return ( txt.length() < A.txt.length() || (txt.length() == A.txt.length() && txt<A.txt) || (txt==A.txt && id<A.id) ); }
  };

  std::deque<IntermediateResult> search_result;
  for (const std::string s: parsed[level])
    {
      marisa::Agent agent;
      agent.set_query(s.c_str());
      while (m_trie_norm.predictive_search(agent))
        {
          std::string val;
          if ( m_database_norm_id.get( make_id_key( agent.key().id() ), &val) )
            {
              index_id_value *idx, *idx1;
              if ( get_id_range(val, (level==0), range0, range1,
                                &idx, &idx1) )
                {
                  for (; idx < idx1; ++idx)
                    {
                      long long int id = *idx;
                      IntermediateResult r( std::string(agent.key().ptr(), agent.key().length()),
                                            id );
                      search_result.push_back(r);
                    }
                }
            }
          else
            {
              std::cerr << "Internal inconsistency of the databases: TRIE " << agent.key().id() << "\n";
            }
        }
    }

  std::sort(search_result.begin(), search_result.end());

  bool last_level = ( level+1 >= parsed.size() );
  for (const IntermediateResult &branch: search_result)
    {
      long long int id = branch.id;
      long long int last_subobject = id;

      if (ids_explored.count(id) > 0)
        continue; // has been looked into it already

      ids_explored.insert(id);

      // are we interested in this result even if it doesn't have subregions?
      if (!last_level)
        {
          sqlite3pp::query qry(m_db, "SELECT last_subobject FROM hierarchy WHERE prim_id=?");
          qry.bind(1, id);
          for (auto v: qry)
            {
              // only one entry is expected
              v.getter() >> last_subobject;
              break;
            }

          // check if we have results which are better than this one if it
          // does not have any subobjects
          if (m_levels_resolved > level+1 && id >= last_subobject)
            continue; // take the next search_result
        }

      if ( last_level ||
	   last_subobject <= id ||
	   !search(parsed, result, level+1, id, last_subobject) )
        {
	  size_t levels_resolved = level+1;
	  if ( m_levels_resolved < levels_resolved )
            {
	      result.clear();
	      m_levels_resolved = levels_resolved;
            }

	  if (m_levels_resolved == levels_resolved && (m_max_results==0 || result.size() < m_max_results))
            {
	      bool have_already = false;
	      for (const auto &r: result)
		if (r.id == id)
		  {
		    have_already = true;
		    break;
		  }

	      if (!have_already)
                {
		  GeoResult r;
		  r.id = id;
		  r.levels_resolved = levels_resolved;
		  result.push_back(r);
                }
            }
        }
    }

  return !ids_explored.empty();
}

void Geocoder::get_name(long long id, std::string &title, std::string &full, int levels_in_title)
{
  long long int parent;
  std::string name;

  sqlite3pp::query qry(m_db, "SELECT name, parent FROM object_primary WHERE id=?");
  qry.bind(1, id);
  for (auto v: qry)
    {
      // only one entry is expected
      v.getter() >> name >> parent;

      if (!full.empty()) full += ", ";
      full += name;

      if (levels_in_title > 0)
        {
	  if (!title.empty()) title += ", ";
	  title += name;
        }

      get_name(parent, title, full, levels_in_title-1);
      return;
    }
}

std::string Geocoder::get_type(long long id)
{
  std::string name;

  sqlite3pp::query qry(m_db, "SELECT t.name FROM object_primary o JOIN type t ON t.id=o.type_id WHERE o.id=?");
  qry.bind(1, id);

  for (auto v: qry)
    {
      std::string n;
      v.getter() >> n;

      if (!name.empty()) name += ", ";
      name += n;
    }

  return name;
}

bool Geocoder::get_id_range(std::string &v, bool full_range, index_id_value range0, index_id_value range1,
                            index_id_value* *idx0, index_id_value* *idx1)
{
  int sz = get_id_number_of_values(v);
  index_id_value* v0 = (index_id_value*)v.data();
  if (sz == 0)
    return false;

  if (full_range)
    {
      *idx0 = v0;
      *idx1 = v0 + sz;
      return true;
    }

  *idx0 = std::lower_bound(v0, v0 + sz, range0);
  if (*idx0 - v0 >= sz) return false;

  *idx1 = std::upper_bound(v0, v0 + sz, range1);
  if (*idx1 - v0 >= sz && *(v0) > range1 ) return false;

  return true;
}
<|endoftext|>


<commit_before>/*
    kircmessage.cpp - IRC Client

    Copyright (c) 2003      by Michel Hermier <michel.hermier@wanadoo.fr>

    Kopete    (c) 2003      by the Kopete engineelopers <kopete-engineel@kde.org>

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

#include "kircengine.h"
#include "kircmessage.h"

// FIXME: Remove the following dependencies.
#include "kopetemessage.h"
#include "ksparser.h"

#include <kdebug.h>
#include <kextsock.h>
#include <klocale.h>
#include <kmessagebox.h>

using namespace KIRC;

#ifndef _IRC_STRICTNESS_
QRegExp Message::m_IRCNumericCommand("^\\d{1,3}$");

// TODO: This regexp parsing is no good. It's slower than it needs to be, and
// is not codec-safe since QString requires a codec. NEed to parse this with
// our own parsing class that operates on the raw QCStrings
QRegExp Message::m_IRCCommandType1(
	"^(?::([^ ]+) )?([A-Za-z]+|\\d{1,3})((?: [^ :][^ ]*)*) ?(?: :(.*))?$");
	// Extra end arg space check -------------------------^
#else // _IRC_STRICTNESS_
QRegExp Message::m_IRCNumericCommand("^\\d{3,3}$");

QRegExp Message::m_IRCCommandType1(
	"^(?::([^ ]+) )?([A-Za-z]+|\\d{3,3})((?: [^ :][^ ]*){0,13})(?: :(.*))?$");
QRegExp Message::m_IRCCommandType2(
	"^(?::[[^ ]+) )?([A-Za-z]+|\\d{3,3})((?: [^ :][^ ]*){14,14})(?: (.*))?$");
#endif // _IRC_STRICTNESS_

Message::Message()
	: m_ctcpMessage(0)
{
}

Message::Message(const Message &obj)
	: m_ctcpMessage(0)
{
	m_raw = obj.m_raw;

	m_prefix = obj.m_prefix;
	m_command = obj.m_command;
	m_args = obj.m_args;
	m_suffix = obj.m_suffix;

	m_ctcpRaw = obj.m_ctcpRaw;

	if (obj.m_ctcpMessage)
		m_ctcpMessage = new Message(obj.m_ctcpMessage);
}

Message::Message(const Message *obj)
	: m_ctcpMessage(0)
{
	m_raw = obj->m_raw;

	m_prefix = obj->m_prefix;
	m_command = obj->m_command;
	m_args = obj->m_args;
	m_suffix = obj->m_suffix;

	m_ctcpRaw = obj->m_ctcpRaw;

	if (obj->m_ctcpMessage)
		m_ctcpMessage = new Message(obj->m_ctcpMessage);
}

Message::~Message()
{
	if (m_ctcpMessage)
		delete m_ctcpMessage;
}

void Message::writeRawMessage(Engine *engine, const QTextCodec *codec, const QString &str)
{
	// FIXME: Really handle this
	if (!engine->socket())
	{
		kdDebug(14121) << k_funcinfo << "Not connected while attempting to write:" << str << endl;
		return;
	}

	QString txt = str + QString::fromLatin1("\r\n");

	QCString s(codec->fromUnicode(txt));
        kdDebug(14120) << "Message is " << s.length() << " chars" << endl;
	// FIXME: Should check the amount of data really writen.
	int wrote = engine->socket()->writeBlock(s.data(), s.length());

	kdDebug(14121) << QString::fromLatin1("(%1 bytes) >> %2").arg(wrote).arg(str) << endl;
}

void Message::writeMessage(Engine *engine, const QTextCodec *codec, const QString &message)
{
	writeRawMessage(engine, codec, quote(message));
}

void Message::writeMessage(Engine *engine, const QTextCodec *codec,
	const QString &command, const QStringList &args, const QString &suffix)
{
	QString msg = command;

	if (!args.isEmpty())
		msg += QChar(' ') + args.join(QChar(' ')).stripWhiteSpace(); // some extra check should be done here

	if (!suffix.isNull())
		msg += QString::fromLatin1(" :") + suffix;

	writeMessage(engine, codec, msg);
}

void Message::writeCtcpMessage(Engine *engine, const QTextCodec *codec,
		const QString &command, const QString&to,
		const QString &ctcpMessage)
{
	writeMessage(engine, codec, command, to, QChar(0x01) + ctcpQuote(ctcpMessage) + QChar(0x01));
}

void Message::writeCtcpMessage(Engine *engine, const QTextCodec *codec,
		const QString &command, const QString &to, const QString &suffix,
		const QString &ctcpCommand, const QStringList &ctcpArgs, const QString &ctcpSuffix )
{
	QString ctcpMsg = ctcpCommand;

	if (!ctcpArgs.isEmpty())
		ctcpMsg += QChar(' ') + ctcpArgs.join(QChar(' ')).stripWhiteSpace(); // some extra check should be done here

	if (!ctcpSuffix.isNull())
		ctcpMsg += QString::fromLatin1(" :") + ctcpSuffix;

	writeMessage(engine, codec, command, to, suffix + QChar(0x01) + ctcpQuote(ctcpMsg) + QChar(0x01));
}

Message Message::parse(Engine *engine, const QTextCodec *codec, bool *parseSuccess)
{
	if (parseSuccess)
		*parseSuccess=false;

	if (engine->socket()->canReadLine())
	{
		QCString raw(engine->socket()->bytesAvailable()+1);
		Q_LONG length = engine->socket()->readLine(raw.data(), raw.count());

		if( length > -1 )
		{
			raw.resize( length );
			raw.replace("\r\n",""); //remove the trailling \r\n if any(there must be in fact)

			kdDebug(14121) << "<< " << raw << endl;

			Message msg;
			if(matchForIRCRegExp(raw, codec, msg))
			{
				if(parseSuccess)
					*parseSuccess = true;
			}
			else
			{
				kdDebug(14120) << k_funcinfo << "Unmatched line: \"" << raw << "\"" << endl;
			}

			return msg;
		}
		else
			kdWarning(14121) << k_funcinfo << "Failed to read a line while canReadLine returned true!" << endl;
	}

	return Message();
}

QString Message::quote(const QString &str)
{
	QString tmp = str;
	QChar q('\020');
	tmp.replace(q, q+QString(q));
	tmp.replace(QChar('\r'), q+QString::fromLatin1("r"));
	tmp.replace(QChar('\n'), q+QString::fromLatin1("n"));
	tmp.replace(QChar('\0'), q+QString::fromLatin1("0"));
	return tmp;
}

// FIXME: The unquote system is buggy.
QString Message::unquote(const QString &str)
{
	QString tmp = str;

	char b[3];
	b[0] = 20; b[1] = 20; b[2] = '\0';
	char b2[2];
	b2[0] = (char)20; b2[1] = '\0';

	tmp.replace( b, b2 );
	b[1] = 'r';
	tmp.replace( b, "\r");
	b[1] = 'n';
	tmp.replace( b, "\n");
	b[1] = '0';
	tmp.replace( b, "\0");

	return tmp;
}

QString Message::ctcpQuote(const QString &str)
{
	QString tmp = str;
	tmp.replace( QChar('\\'), QString::fromLatin1("\\\\"));
	tmp.replace( (char)1, QString::fromLatin1("\\1"));
	return tmp;
}

QString Message::ctcpUnquote(const QString &str)
{
	QString tmp = str;
	tmp.replace("\\\\", "\\");
	tmp.replace("\\1", "\1" );
	return tmp;
}

bool Message::matchForIRCRegExp(const QCString &line, const QTextCodec *codec, Message &message)
{
	if(matchForIRCRegExp(m_IRCCommandType1, codec, line, message))
		return true;
#ifdef _IRC_STRICTNESS_
	if(!matchForIRCRegExp(m_IRCCommandType2, codec, line, message))
		return true;
#endif // _IRC_STRICTNESS_
	return false;
}

// FIXME: remove the decodeStrings calls or update them.
// FIXME: avoid the recursive call, it make the ctcp command unquoted twice (wich is wrong, but valid in most of the cases)
bool Message::matchForIRCRegExp(QRegExp &regexp, const QTextCodec *codec, const QCString &line, Message &msg )
{
	if( regexp.exactMatch( codec->toUnicode(line) ) )
	{
		msg.m_raw = line;
		msg.m_prefix  = unquote(regexp.cap(1));
		msg.m_command = unquote(regexp.cap(2));
		msg.m_args = QStringList::split(' ', regexp.cap(3));

		QCString suffix = regexp.cap(4).latin1();
		if (!suffix.isNull() && suffix.length() > 0)
		{
			if (extractCtcpCommand(suffix, msg.m_ctcpRaw, codec))
			{
				msg.m_ctcpMessage = new Message();
				msg.m_ctcpMessage->m_raw = msg.m_ctcpRaw.latin1();

				int space = msg.m_ctcpRaw.find(' ');
				if (!matchForIRCRegExp(msg.m_ctcpMessage->m_raw, codec, *msg.m_ctcpMessage))
				{
					if (space > 0)
						msg.m_ctcpMessage->m_command = msg.m_ctcpRaw.mid(0, space).upper();
					else
						msg.m_ctcpMessage->m_command = msg.m_ctcpRaw.upper();
				}

				if (space > 0)
					msg.m_ctcpMessage->m_ctcpRaw = msg.m_ctcpRaw.mid(space).latin1();
			}

			msg.m_suffix = Kopete::Message::decodeString( KSParser::parse(suffix), codec );
		}
		else
			msg.m_suffix = QString::null;
		return true;
	}
	return false;
}

void Message::decodeAgain( const QTextCodec *codec )
{
	matchForIRCRegExp(m_raw, codec, *this);
}

// FIXME: there are missing parts
QString Message::toString() const
{
	if( !isValid() )
		return QString::null;

	QString msg = m_command;
	for (QStringList::ConstIterator it = m_args.begin(); it != m_args.end(); ++it)
		msg += QChar(' ') + *it;
	if (!m_suffix.isNull())
		msg += QString::fromLatin1(" :") + m_suffix;

	return msg;
}

bool Message::isNumeric() const
{
	return m_IRCNumericCommand.exactMatch(m_command);
}

bool Message::isValid() const
{
//	This could/should be more complex but the message validity is tested durring the parsing
//	So this is enougth as we don't allow the editing the content.
	return !m_command.isEmpty();
}

/* Return true if the given string is a special command string
 * (i.e start and finish with the ascii code \001), and the given
 * string is splited to get the first part of the message and fill the ctcp command.
 * FIXME: The code currently only match for a textual message or a ctcp message not both mixed as it can be (even if very rare).
 */
bool Message::extractCtcpCommand(QCString &message, QString &ctcpline, const QTextCodec *codec)
{
	uint len = message.length();

	if( message[0] == 1 && message[len-1] == 1 )
	{
		ctcpline = ctcpUnquote( unquote( Kopete::Message::decodeString(KSParser::parse(message.mid(1,len-2)), codec) ) );
		message.truncate(0);

		return true;
	}

	return false;
}

void Message::dump() const
{
	kdDebug(14120)	<< "Raw:" << m_raw << endl
			<< "Prefix:" << m_prefix << endl
			<< "Command:" << m_command << endl
			<< "Args:" << m_args << endl
			<< "Suffix:" << m_suffix << endl
			<< "CtcpRaw:" << m_ctcpRaw << endl;
	if(m_ctcpMessage)
	{
		kdDebug(14120) << "Contains CTCP Message:" << endl;
		m_ctcpMessage->dump();
	}
}

#include "kircmessage.moc"
<commit_msg>Make it compile<commit_after>/*
    kircmessage.cpp - IRC Client

    Copyright (c) 2003      by Michel Hermier <michel.hermier@wanadoo.fr>

    Kopete    (c) 2003      by the Kopete engineelopers <kopete-engineel@kde.org>

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

#include "kircengine.h"
#include "kircmessage.h"

// FIXME: Remove the following dependencies.
#include "kopetemessage.h"
#include "ksparser.h"

#include <kdebug.h>
#include <kextsock.h>
#include <klocale.h>
#include <kmessagebox.h>

using namespace KIRC;

#ifndef _IRC_STRICTNESS_
QRegExp Message::m_IRCNumericCommand("^\\d{1,3}$");

// TODO: This regexp parsing is no good. It's slower than it needs to be, and
// is not codec-safe since QString requires a codec. NEed to parse this with
// our own parsing class that operates on the raw QCStrings
QRegExp Message::m_IRCCommandType1(
	"^(?::([^ ]+) )?([A-Za-z]+|\\d{1,3})((?: [^ :][^ ]*)*) ?(?: :(.*))?$");
	// Extra end arg space check -------------------------^
#else // _IRC_STRICTNESS_
QRegExp Message::m_IRCNumericCommand("^\\d{3,3}$");

QRegExp Message::m_IRCCommandType1(
	"^(?::([^ ]+) )?([A-Za-z]+|\\d{3,3})((?: [^ :][^ ]*){0,13})(?: :(.*))?$");
QRegExp Message::m_IRCCommandType2(
	"^(?::[[^ ]+) )?([A-Za-z]+|\\d{3,3})((?: [^ :][^ ]*){14,14})(?: (.*))?$");
#endif // _IRC_STRICTNESS_

Message::Message()
	: m_ctcpMessage(0)
{
}

Message::Message(const Message &obj)
        : QObject(), m_ctcpMessage(0)
{
	m_raw = obj.m_raw;

	m_prefix = obj.m_prefix;
	m_command = obj.m_command;
	m_args = obj.m_args;
	m_suffix = obj.m_suffix;

	m_ctcpRaw = obj.m_ctcpRaw;

	if (obj.m_ctcpMessage)
		m_ctcpMessage = new Message(obj.m_ctcpMessage);
}

Message::Message(const Message *obj)
	: m_ctcpMessage(0)
{
	m_raw = obj->m_raw;

	m_prefix = obj->m_prefix;
	m_command = obj->m_command;
	m_args = obj->m_args;
	m_suffix = obj->m_suffix;

	m_ctcpRaw = obj->m_ctcpRaw;

	if (obj->m_ctcpMessage)
		m_ctcpMessage = new Message(obj->m_ctcpMessage);
}

Message::~Message()
{
	if (m_ctcpMessage)
		delete m_ctcpMessage;
}

void Message::writeRawMessage(Engine *engine, const QTextCodec *codec, const QString &str)
{
	// FIXME: Really handle this
	if (!engine->socket())
	{
		kdDebug(14121) << k_funcinfo << "Not connected while attempting to write:" << str << endl;
		return;
	}

	QString txt = str + QString::fromLatin1("\r\n");

	QCString s(codec->fromUnicode(txt));
        kdDebug(14120) << "Message is " << s.length() << " chars" << endl;
	// FIXME: Should check the amount of data really writen.
	int wrote = engine->socket()->writeBlock(s.data(), s.length());

	kdDebug(14121) << QString::fromLatin1("(%1 bytes) >> %2").arg(wrote).arg(str) << endl;
}

void Message::writeMessage(Engine *engine, const QTextCodec *codec, const QString &message)
{
	writeRawMessage(engine, codec, quote(message));
}

void Message::writeMessage(Engine *engine, const QTextCodec *codec,
	const QString &command, const QStringList &args, const QString &suffix)
{
	QString msg = command;

	if (!args.isEmpty())
		msg += QChar(' ') + args.join(QChar(' ')).stripWhiteSpace(); // some extra check should be done here

	if (!suffix.isNull())
		msg += QString::fromLatin1(" :") + suffix;

	writeMessage(engine, codec, msg);
}

void Message::writeCtcpMessage(Engine *engine, const QTextCodec *codec,
		const QString &command, const QString&to,
		const QString &ctcpMessage)
{
	writeMessage(engine, codec, command, to, QChar(0x01) + ctcpQuote(ctcpMessage) + QChar(0x01));
}

void Message::writeCtcpMessage(Engine *engine, const QTextCodec *codec,
		const QString &command, const QString &to, const QString &suffix,
		const QString &ctcpCommand, const QStringList &ctcpArgs, const QString &ctcpSuffix )
{
	QString ctcpMsg = ctcpCommand;

	if (!ctcpArgs.isEmpty())
		ctcpMsg += QChar(' ') + ctcpArgs.join(QChar(' ')).stripWhiteSpace(); // some extra check should be done here

	if (!ctcpSuffix.isNull())
		ctcpMsg += QString::fromLatin1(" :") + ctcpSuffix;

	writeMessage(engine, codec, command, to, suffix + QChar(0x01) + ctcpQuote(ctcpMsg) + QChar(0x01));
}

Message Message::parse(Engine *engine, const QTextCodec *codec, bool *parseSuccess)
{
	if (parseSuccess)
		*parseSuccess=false;

	if (engine->socket()->canReadLine())
	{
		QCString raw(engine->socket()->bytesAvailable()+1);
		Q_LONG length = engine->socket()->readLine(raw.data(), raw.count());

		if( length > -1 )
		{
			raw.resize( length );
			raw.replace("\r\n",""); //remove the trailling \r\n if any(there must be in fact)

			kdDebug(14121) << "<< " << raw << endl;

			Message msg;
			if(matchForIRCRegExp(raw, codec, msg))
			{
				if(parseSuccess)
					*parseSuccess = true;
			}
			else
			{
				kdDebug(14120) << k_funcinfo << "Unmatched line: \"" << raw << "\"" << endl;
			}

			return msg;
		}
		else
			kdWarning(14121) << k_funcinfo << "Failed to read a line while canReadLine returned true!" << endl;
	}

	return Message();
}

QString Message::quote(const QString &str)
{
	QString tmp = str;
	QChar q('\020');
	tmp.replace(q, q+QString(q));
	tmp.replace(QChar('\r'), q+QString::fromLatin1("r"));
	tmp.replace(QChar('\n'), q+QString::fromLatin1("n"));
	tmp.replace(QChar('\0'), q+QString::fromLatin1("0"));
	return tmp;
}

// FIXME: The unquote system is buggy.
QString Message::unquote(const QString &str)
{
	QString tmp = str;

	char b[3];
	b[0] = 20; b[1] = 20; b[2] = '\0';
	char b2[2];
	b2[0] = (char)20; b2[1] = '\0';

	tmp.replace( b, b2 );
	b[1] = 'r';
	tmp.replace( b, "\r");
	b[1] = 'n';
	tmp.replace( b, "\n");
	b[1] = '0';
	tmp.replace( b, "\0");

	return tmp;
}

QString Message::ctcpQuote(const QString &str)
{
	QString tmp = str;
	tmp.replace( QChar('\\'), QString::fromLatin1("\\\\"));
	tmp.replace( (char)1, QString::fromLatin1("\\1"));
	return tmp;
}

QString Message::ctcpUnquote(const QString &str)
{
	QString tmp = str;
	tmp.replace("\\\\", "\\");
	tmp.replace("\\1", "\1" );
	return tmp;
}

bool Message::matchForIRCRegExp(const QCString &line, const QTextCodec *codec, Message &message)
{
	if(matchForIRCRegExp(m_IRCCommandType1, codec, line, message))
		return true;
#ifdef _IRC_STRICTNESS_
	if(!matchForIRCRegExp(m_IRCCommandType2, codec, line, message))
		return true;
#endif // _IRC_STRICTNESS_
	return false;
}

// FIXME: remove the decodeStrings calls or update them.
// FIXME: avoid the recursive call, it make the ctcp command unquoted twice (wich is wrong, but valid in most of the cases)
bool Message::matchForIRCRegExp(QRegExp &regexp, const QTextCodec *codec, const QCString &line, Message &msg )
{
	if( regexp.exactMatch( codec->toUnicode(line) ) )
	{
		msg.m_raw = line;
		msg.m_prefix  = unquote(regexp.cap(1));
		msg.m_command = unquote(regexp.cap(2));
		msg.m_args = QStringList::split(' ', regexp.cap(3));

		QCString suffix = regexp.cap(4).latin1();
		if (!suffix.isNull() && suffix.length() > 0)
		{
			if (extractCtcpCommand(suffix, msg.m_ctcpRaw, codec))
			{
				msg.m_ctcpMessage = new Message();
				msg.m_ctcpMessage->m_raw = msg.m_ctcpRaw.latin1();

				int space = msg.m_ctcpRaw.find(' ');
				if (!matchForIRCRegExp(msg.m_ctcpMessage->m_raw, codec, *msg.m_ctcpMessage))
				{
					if (space > 0)
						msg.m_ctcpMessage->m_command = msg.m_ctcpRaw.mid(0, space).upper();
					else
						msg.m_ctcpMessage->m_command = msg.m_ctcpRaw.upper();
				}

				if (space > 0)
					msg.m_ctcpMessage->m_ctcpRaw = msg.m_ctcpRaw.mid(space).latin1();
			}

			msg.m_suffix = Kopete::Message::decodeString( KSParser::parse(suffix), codec );
		}
		else
			msg.m_suffix = QString::null;
		return true;
	}
	return false;
}

void Message::decodeAgain( const QTextCodec *codec )
{
	matchForIRCRegExp(m_raw, codec, *this);
}

// FIXME: there are missing parts
QString Message::toString() const
{
	if( !isValid() )
		return QString::null;

	QString msg = m_command;
	for (QStringList::ConstIterator it = m_args.begin(); it != m_args.end(); ++it)
		msg += QChar(' ') + *it;
	if (!m_suffix.isNull())
		msg += QString::fromLatin1(" :") + m_suffix;

	return msg;
}

bool Message::isNumeric() const
{
	return m_IRCNumericCommand.exactMatch(m_command);
}

bool Message::isValid() const
{
//	This could/should be more complex but the message validity is tested durring the parsing
//	So this is enougth as we don't allow the editing the content.
	return !m_command.isEmpty();
}

/* Return true if the given string is a special command string
 * (i.e start and finish with the ascii code \001), and the given
 * string is splited to get the first part of the message and fill the ctcp command.
 * FIXME: The code currently only match for a textual message or a ctcp message not both mixed as it can be (even if very rare).
 */
bool Message::extractCtcpCommand(QCString &message, QString &ctcpline, const QTextCodec *codec)
{
	uint len = message.length();

	if( message[0] == 1 && message[len-1] == 1 )
	{
		ctcpline = ctcpUnquote( unquote( Kopete::Message::decodeString(KSParser::parse(message.mid(1,len-2)), codec) ) );
		message.truncate(0);

		return true;
	}

	return false;
}

void Message::dump() const
{
	kdDebug(14120)	<< "Raw:" << m_raw << endl
			<< "Prefix:" << m_prefix << endl
			<< "Command:" << m_command << endl
			<< "Args:" << m_args << endl
			<< "Suffix:" << m_suffix << endl
			<< "CtcpRaw:" << m_ctcpRaw << endl;
	if(m_ctcpMessage)
	{
		kdDebug(14120) << "Contains CTCP Message:" << endl;
		m_ctcpMessage->dump();
	}
}

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


<commit_before>#include "fixedpoint.h"

#include <cmath>

using namespace tdr;

fix1616 tdr::clamp(fix1616 x, fix1616 a, fix1616 b) {
  return max(a, min(b, x));
}

fix1616 tdr::fix1616::operator+(fix1616 b) const {
	if (b.u > 0 && ((int32_t) CELESTIAL) - b.u < u)
		return { (int32_t) CELESTIAL };
	if (b.u < 0 && ((int32_t) ABYSS) - b.u > u)
		return { ((int32_t) ABYSS) };
	return { u + b.u };
}
fix1616 tdr::fix1616::operator-(fix1616 b) const {
	if (b.u > 0 && -((int32_t) CELESTIAL) + b.u < u)
		return { -(int32_t) CELESTIAL };
	if (b.u < 0 && ((int32_t) ABYSS) + b.u > u)
		return { ((int32_t) ABYSS) };
	return { u - b.u };
}
fix1616 tdr::fix1616::addWrap(fix1616 b) const {
  return { (int64_t) ((uint64_t) u + (uint64_t) b.u) };
}
fix1616 tdr::fix1616::subWrap(fix1616 b) const {
  return { (int64_t) ((uint64_t) u - (uint64_t) b.u) };
}
fix1616 tdr::fix1616::operator-() const {
	if (u == ABYSS) return { CELESTIAL };
  else return { -u };
}
fix1616 tdr::fix1616::operator*(fix1616 b) const {
	int64_t prod = (((int64_t) u) * b.u) >> 16;
	if (prod >= 0x100000000) prod = CELESTIAL;
	if (prod < -((int64_t) 0x100000000)) prod = ((int64_t) ABYSS);
	return { (int32_t) prod };
}
fix1616 tdr::fix1616::operator/(fix1616 b) const {
	int64_t aex = (((int64_t) u) << 16);
	int64_t res = aex / b.u;
	if (res > CELESTIAL) return { CELESTIAL };
	if (res < ABYSS) return { ABYSS };
	return { (int32_t) res };
}

bool tdr::fix1616::operator==(fix1616 b) const {
	return u == b.u;
}

bool tdr::fix1616::operator!=(fix1616 b) const {
	return u != b.u;
}

bool tdr::fix1616::operator<(fix1616 b) const {
	return u < b.u;
}

bool tdr::fix1616::operator>(fix1616 b) const {
	return u > b.u;
}

bool tdr::fix1616::operator>=(fix1616 b) const {
	return u >= b.u;
}

bool tdr::fix1616::operator==(int b) const {
	if (b < -0x8000 || b >= 0x8000) return false;
  return (b << 16) == u;
}

bool tdr::fix1616::operator!=(int b) const {
	if (b < -0x8000 || b >= 0x8000) return true;
  return (b << 16) != u;
}

bool tdr::fix1616::operator<(int b) const {
  if (b < -0x8000) return false;
  if (b >= 0x8000) return true;
  return (b << 16) < u;
}

bool tdr::fix1616::operator>(int b) const {
  if (b < -0x8000) return true;
  if (b >= 0x8000) return false;
  return (b << 16) > u;
}

fix1616 tdr::fix1616::operator+=(fix1616 b) {
  u = ((*this) + b).u;
  return *this;
}

fix1616 tdr::fix1616::operator-=(fix1616 b) {
  u = ((*this) - b).u;
  return *this;
}

fix1616 tdr::fix1616::operator=(int b) {
  if (b >= 0x8000) u = CELESTIAL;
  else if (b < -0x8000) u = ABYSS;
  else u = b << 16;
  return *this;
}

fix1616 tdr::max(fix1616 a, fix1616 b) {
  return (a > b) ? a : b;
}

fix1616 tdr::min(fix1616 a, fix1616 b) {
  return (a < b) ? a : b;
}

// Adapted from:
// http://www.codecodex.com/wiki/Calculate_an_integer_square_root
int32_t tdr::sqrti(int64_t n) {
  if (n < 0) throw "Positive n expected in tdr::sqrti";
  int64_t root = 0;
  int64_t rem = n;
  int64_t place = 0x4000'0000'0000'0000; //' // < this compiles, but
  while (place > rem) place >>= 2; // the commented quote was inserted
  while (place != 0) {             // to avoid throwing C++14-unaware
    if (rem >= root + place) {     // syntax highlighters off
      rem -= root + place;
      root += place << 1;
    }
    root >>= 1;
    place >>= 2;
  }
  return (int32_t) root;
}

bool tdr::isWithin(fix1616 x, fix1616 y, fix1616 r) {
	uint64_t distsq = ((int64_t) x.u) * x.u + ((int64_t) y.u) * y.u;
	uint64_t thresh = ((int64_t) r.u) * r.u;
	return distsq <= thresh;
}

fix1616 tdr::hypotx(fix1616 x, fix1616 y) {
  uint64_t distsq = ((int64_t) x.u) * x.u + ((int64_t) y.u) * y.u;
  return { sqrti(distsq) };
}

fix1616 tdr::multiply1616By230(fix1616 a, int32_t b) {
	int64_t res = ((int64_t) a.u) * b >> 30;
	return { (int32_t) res };
}

#define TAU_TIMES_2TT28 0x6487ED51
#define CORDIC_ITERATIONS 31
// CORDIC K constant in 2.30 format.
#define CORDIC_K 0x26DD3B6A

inline int32_t mul230(int32_t a, int32_t b) {
  int64_t aa = a;
  aa *= b;
  return (int32_t) (aa >> 30);
}

// Generated by this Perl6 expression:
// ((^32).map({"0x"~(2**30*atan(2**-$_)).floor.base(16)})).join(", ")
const int32_t arctangents[] = {
  0x3243F6A8, 0x1DAC6705, 0xFADBAFC, 0x7F56EA6,
  0x3FEAB76, 0x1FFD55B, 0xFFFAAA, 0x7FFF55,
  0x3FFFEA, 0x1FFFFD, 0xFFFFF, 0x7FFFF,
  0x3FFFF, 0x1FFFF, 0xFFFF, 0x7FFF,
  0x3FFF, 0x1FFF, 0xFFF, 0x7FF,
  0x3FF, 0x1FF, 0xFF, 0x7F,
  0x3F, 0x1F, 0xF, 0x8,
  0x4, 0x2, 0x1, 0x0
};

// A list of ratios to intermediate K-values, in 2.30 format.
// Generated by this Perl6 expression:
// my @inv = (0..^32).map({1/sqrt(1+2**(-2*$_))});
// say ([\*] @inv).map({"0x" ~ floor(2**30*$_).base(16)}).join(", ");
const int32_t intermediateK[] = {
  0x40000000, 0x2D413CCD, 0x287A26C5, 0x2744C375,
  0x26F72284, 0x26E3B583, 0x26DED9F5, 0x26DDA30D,
  0x26DD5553, 0x26DD41E4, 0x26DD3D09, 0x26DD3BD2,
  0x26DD3B84, 0x26DD3B71, 0x26DD3B6C
};

// A list of ratios to intermediate K-values to CORDIC_K, in 2.30 format.
// Generated by this Perl6 expression:
// my @inv = (0..^32).map({1/sqrt(1+2**(-2*$_))});
// say ([\*] @inv).map({"0x" ~ floor(2**30*$_/([*] @inv)).base(16)}).join(", ");
const int32_t intermediateKRatio[] = {
  0x69648523, 0x4A861BD3, 0x42A7FAAB, 0x40AA7DCD,
  0x402AA7D5, 0x400AAA7D, 0x4002AAA7, 0x4000AAAA,
  0x40002AAA, 0x40000AAA, 0x400002AA, 0x400000AA,
  0x4000002A, 0x4000000A, 0x40000002
};

// Calculates sine and cosine using CORDIC
// (https://en.wikipedia.org/wiki/CORDIC)
// t = angle in 1/65536 of a turn
// c = reference to where you want cosine to be stored
// s = reference to where you want sine to be stored
// Both of the results will be stored in 2.30 format.
void tdr::sincos(fix1616 t, int32_t& c, int32_t& s) {
	bool inv = t.u > 0x40000000 || t.u < -((int32_t) 0x40000000);
	if (inv) // Plus, minus, that doesn't even matter ~
		t.u = (int32_t) (((uint32_t) t.u) + 0x80000000); // avoid UB
	// Multiply by tau to convert turns into radians (in 34.30 format)
  // No idea why we need to shift right by THIRTY, though.
	int64_t radians = ((((int64_t) t.u) * TAU_TIMES_2TT28) >> 30);
	// vx and vy use 2.30 format
	// (to be able to represent both 1 and -1)
	int32_t vx = CORDIC_K;
	int32_t vy = 0;
  unsigned int i;
	for (i = 0; i < CORDIC_ITERATIONS && radians != 0; ++i) {
		// new vector = [1, -factor; factor, 1] old vector
    int32_t nx, ny;
		if (radians >= 0) {
      nx = vx - (vy >> i);
      ny = (vx >> i) + vy;
    } else {
      nx = vx + (vy >> i);
      ny = -(vx >> i) + vy;
    }
		vx = nx;
		vy = ny;
		radians += (radians < 0) ? arctangents[i] : -arctangents[i];
	}
  if (i < (sizeof(intermediateKRatio) / sizeof(intermediateKRatio[0]))) {
    vx = mul230(vx, intermediateKRatio[i]);
    vy = mul230(vy, intermediateKRatio[i]);
  }
	c = inv ? -vx : vx;
	s = inv ? -vy : vy;
}

// Calculating atan2 using CORDIC
void tdr::rectp(fix1616 c, fix1616 s, fix1616& r, fix1616& t) {
  if (c < C_ZERO) {
    rectp(-c, -s, r, t);
    t.u += ABYSS;
    return;
  }
  int64_t angle = 0;
	// vx and vy use 16.16 format
  int32_t vx = c.u;
  int32_t vy = s.u;
  unsigned int i;
  for (i = 0; i < CORDIC_ITERATIONS && vy != 0; ++i) {
    int32_t nx, ny;
    if (vy <= 0) {
      nx = vx - (vy >> i);
      ny = (vx >> i) + vy;
    } else {
      nx = vx + (vy >> i);
      ny = -(vx >> i) + vy;
    }
		vx = nx;
    angle += (vy > 0) ? arctangents[i] : -arctangents[i];
		vy = ny;
  }
  t.u = (angle << 30) / TAU_TIMES_2TT28;
  if (i < (sizeof(intermediateKRatio) / sizeof(intermediateKRatio[0])))
    r.u = (((int64_t) vx) * intermediateK[i]) >> 30;
  else
    r.u = (((int64_t) vx) * CORDIC_K) >> 30;
}
<commit_msg>Fix warning (it was supposed to be 32-bit, not 64)<commit_after>#include "fixedpoint.h"

#include <cmath>

using namespace tdr;

fix1616 tdr::clamp(fix1616 x, fix1616 a, fix1616 b) {
  return max(a, min(b, x));
}

fix1616 tdr::fix1616::operator+(fix1616 b) const {
	if (b.u > 0 && ((int32_t) CELESTIAL) - b.u < u)
		return { (int32_t) CELESTIAL };
	if (b.u < 0 && ((int32_t) ABYSS) - b.u > u)
		return { ((int32_t) ABYSS) };
	return { u + b.u };
}
fix1616 tdr::fix1616::operator-(fix1616 b) const {
	if (b.u > 0 && -((int32_t) CELESTIAL) + b.u < u)
		return { -(int32_t) CELESTIAL };
	if (b.u < 0 && ((int32_t) ABYSS) + b.u > u)
		return { ((int32_t) ABYSS) };
	return { u - b.u };
}
fix1616 tdr::fix1616::addWrap(fix1616 b) const {
  return { (int32_t) ((uint32_t) u + (uint32_t) b.u) };
}
fix1616 tdr::fix1616::subWrap(fix1616 b) const {
  return { (int32_t) ((uint32_t) u - (uint32_t) b.u) };
}
fix1616 tdr::fix1616::operator-() const {
	if (u == ABYSS) return { CELESTIAL };
  else return { -u };
}
fix1616 tdr::fix1616::operator*(fix1616 b) const {
	int64_t prod = (((int64_t) u) * b.u) >> 16;
	if (prod >= 0x100000000) prod = CELESTIAL;
	if (prod < -((int64_t) 0x100000000)) prod = ((int64_t) ABYSS);
	return { (int32_t) prod };
}
fix1616 tdr::fix1616::operator/(fix1616 b) const {
	int64_t aex = (((int64_t) u) << 16);
	int64_t res = aex / b.u;
	if (res > CELESTIAL) return { CELESTIAL };
	if (res < ABYSS) return { ABYSS };
	return { (int32_t) res };
}

bool tdr::fix1616::operator==(fix1616 b) const {
	return u == b.u;
}

bool tdr::fix1616::operator!=(fix1616 b) const {
	return u != b.u;
}

bool tdr::fix1616::operator<(fix1616 b) const {
	return u < b.u;
}

bool tdr::fix1616::operator>(fix1616 b) const {
	return u > b.u;
}

bool tdr::fix1616::operator>=(fix1616 b) const {
	return u >= b.u;
}

bool tdr::fix1616::operator==(int b) const {
	if (b < -0x8000 || b >= 0x8000) return false;
  return (b << 16) == u;
}

bool tdr::fix1616::operator!=(int b) const {
	if (b < -0x8000 || b >= 0x8000) return true;
  return (b << 16) != u;
}

bool tdr::fix1616::operator<(int b) const {
  if (b < -0x8000) return false;
  if (b >= 0x8000) return true;
  return (b << 16) < u;
}

bool tdr::fix1616::operator>(int b) const {
  if (b < -0x8000) return true;
  if (b >= 0x8000) return false;
  return (b << 16) > u;
}

fix1616 tdr::fix1616::operator+=(fix1616 b) {
  u = ((*this) + b).u;
  return *this;
}

fix1616 tdr::fix1616::operator-=(fix1616 b) {
  u = ((*this) - b).u;
  return *this;
}

fix1616 tdr::fix1616::operator=(int b) {
  if (b >= 0x8000) u = CELESTIAL;
  else if (b < -0x8000) u = ABYSS;
  else u = b << 16;
  return *this;
}

fix1616 tdr::max(fix1616 a, fix1616 b) {
  return (a > b) ? a : b;
}

fix1616 tdr::min(fix1616 a, fix1616 b) {
  return (a < b) ? a : b;
}

// Adapted from:
// http://www.codecodex.com/wiki/Calculate_an_integer_square_root
int32_t tdr::sqrti(int64_t n) {
  if (n < 0) throw "Positive n expected in tdr::sqrti";
  int64_t root = 0;
  int64_t rem = n;
  int64_t place = 0x4000'0000'0000'0000; //' // < this compiles, but
  while (place > rem) place >>= 2; // the commented quote was inserted
  while (place != 0) {             // to avoid throwing C++14-unaware
    if (rem >= root + place) {     // syntax highlighters off
      rem -= root + place;
      root += place << 1;
    }
    root >>= 1;
    place >>= 2;
  }
  return (int32_t) root;
}

bool tdr::isWithin(fix1616 x, fix1616 y, fix1616 r) {
	uint64_t distsq = ((int64_t) x.u) * x.u + ((int64_t) y.u) * y.u;
	uint64_t thresh = ((int64_t) r.u) * r.u;
	return distsq <= thresh;
}

fix1616 tdr::hypotx(fix1616 x, fix1616 y) {
  uint64_t distsq = ((int64_t) x.u) * x.u + ((int64_t) y.u) * y.u;
  return { sqrti(distsq) };
}

fix1616 tdr::multiply1616By230(fix1616 a, int32_t b) {
	int64_t res = ((int64_t) a.u) * b >> 30;
	return { (int32_t) res };
}

#define TAU_TIMES_2TT28 0x6487ED51
#define CORDIC_ITERATIONS 31
// CORDIC K constant in 2.30 format.
#define CORDIC_K 0x26DD3B6A

inline int32_t mul230(int32_t a, int32_t b) {
  int64_t aa = a;
  aa *= b;
  return (int32_t) (aa >> 30);
}

// Generated by this Perl6 expression:
// ((^32).map({"0x"~(2**30*atan(2**-$_)).floor.base(16)})).join(", ")
const int32_t arctangents[] = {
  0x3243F6A8, 0x1DAC6705, 0xFADBAFC, 0x7F56EA6,
  0x3FEAB76, 0x1FFD55B, 0xFFFAAA, 0x7FFF55,
  0x3FFFEA, 0x1FFFFD, 0xFFFFF, 0x7FFFF,
  0x3FFFF, 0x1FFFF, 0xFFFF, 0x7FFF,
  0x3FFF, 0x1FFF, 0xFFF, 0x7FF,
  0x3FF, 0x1FF, 0xFF, 0x7F,
  0x3F, 0x1F, 0xF, 0x8,
  0x4, 0x2, 0x1, 0x0
};

// A list of ratios to intermediate K-values, in 2.30 format.
// Generated by this Perl6 expression:
// my @inv = (0..^32).map({1/sqrt(1+2**(-2*$_))});
// say ([\*] @inv).map({"0x" ~ floor(2**30*$_).base(16)}).join(", ");
const int32_t intermediateK[] = {
  0x40000000, 0x2D413CCD, 0x287A26C5, 0x2744C375,
  0x26F72284, 0x26E3B583, 0x26DED9F5, 0x26DDA30D,
  0x26DD5553, 0x26DD41E4, 0x26DD3D09, 0x26DD3BD2,
  0x26DD3B84, 0x26DD3B71, 0x26DD3B6C
};

// A list of ratios to intermediate K-values to CORDIC_K, in 2.30 format.
// Generated by this Perl6 expression:
// my @inv = (0..^32).map({1/sqrt(1+2**(-2*$_))});
// say ([\*] @inv).map({"0x" ~ floor(2**30*$_/([*] @inv)).base(16)}).join(", ");
const int32_t intermediateKRatio[] = {
  0x69648523, 0x4A861BD3, 0x42A7FAAB, 0x40AA7DCD,
  0x402AA7D5, 0x400AAA7D, 0x4002AAA7, 0x4000AAAA,
  0x40002AAA, 0x40000AAA, 0x400002AA, 0x400000AA,
  0x4000002A, 0x4000000A, 0x40000002
};

// Calculates sine and cosine using CORDIC
// (https://en.wikipedia.org/wiki/CORDIC)
// t = angle in 1/65536 of a turn
// c = reference to where you want cosine to be stored
// s = reference to where you want sine to be stored
// Both of the results will be stored in 2.30 format.
void tdr::sincos(fix1616 t, int32_t& c, int32_t& s) {
	bool inv = t.u > 0x40000000 || t.u < -((int32_t) 0x40000000);
	if (inv) // Plus, minus, that doesn't even matter ~
		t.u = (int32_t) (((uint32_t) t.u) + 0x80000000); // avoid UB
	// Multiply by tau to convert turns into radians (in 34.30 format)
  // No idea why we need to shift right by THIRTY, though.
	int64_t radians = ((((int64_t) t.u) * TAU_TIMES_2TT28) >> 30);
	// vx and vy use 2.30 format
	// (to be able to represent both 1 and -1)
	int32_t vx = CORDIC_K;
	int32_t vy = 0;
  unsigned int i;
	for (i = 0; i < CORDIC_ITERATIONS && radians != 0; ++i) {
		// new vector = [1, -factor; factor, 1] old vector
    int32_t nx, ny;
		if (radians >= 0) {
      nx = vx - (vy >> i);
      ny = (vx >> i) + vy;
    } else {
      nx = vx + (vy >> i);
      ny = -(vx >> i) + vy;
    }
		vx = nx;
		vy = ny;
		radians += (radians < 0) ? arctangents[i] : -arctangents[i];
	}
  if (i < (sizeof(intermediateKRatio) / sizeof(intermediateKRatio[0]))) {
    vx = mul230(vx, intermediateKRatio[i]);
    vy = mul230(vy, intermediateKRatio[i]);
  }
	c = inv ? -vx : vx;
	s = inv ? -vy : vy;
}

// Calculating atan2 using CORDIC
void tdr::rectp(fix1616 c, fix1616 s, fix1616& r, fix1616& t) {
  if (c < C_ZERO) {
    rectp(-c, -s, r, t);
    t.u += ABYSS;
    return;
  }
  int64_t angle = 0;
	// vx and vy use 16.16 format
  int32_t vx = c.u;
  int32_t vy = s.u;
  unsigned int i;
  for (i = 0; i < CORDIC_ITERATIONS && vy != 0; ++i) {
    int32_t nx, ny;
    if (vy <= 0) {
      nx = vx - (vy >> i);
      ny = (vx >> i) + vy;
    } else {
      nx = vx + (vy >> i);
      ny = -(vx >> i) + vy;
    }
		vx = nx;
    angle += (vy > 0) ? arctangents[i] : -arctangents[i];
		vy = ny;
  }
  t.u = (angle << 30) / TAU_TIMES_2TT28;
  if (i < (sizeof(intermediateKRatio) / sizeof(intermediateKRatio[0])))
    r.u = (((int64_t) vx) * intermediateK[i]) >> 30;
  else
    r.u = (((int64_t) vx) * CORDIC_K) >> 30;
}
<|endoftext|>


<commit_before>//
// Copyright (C) 2012
// Alessio Sclocco <a.sclocco@vu.nl>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// 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
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include <vector>
using std::vector;
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
using std::fixed;
#include <iomanip>
using std::setprecision;
#include <cmath>

#include <ArgumentList.hpp>
using isa::utils::ArgumentList;
#include <CLData.hpp>
using isa::OpenCL::CLData;
#include <BeamFormer.hpp>
using LOFAR::RTCP::BeamFormer;
#include <InitializeOpenCL.hpp>
using isa::OpenCL::initializeOpenCL;
#include <Exceptions.hpp>
using isa::Exceptions::OpenCLError;
#include <Observation.hpp>
using AstroData::Observation;

const unsigned int nrPolarizations = 2;

int main(int argc, char *argv[]) {
	unsigned int nrIterations = 0;
	unsigned int clPlatformID = 0;
	unsigned int clDeviceID = 0;
	unsigned int minThreads = 0;
	unsigned int maxThreadsPerBlock = 0;
	unsigned int maxItemsPerThread = 0;
	Observation< float > observation("DedispersionTuning", "float");
	CLData< float > * input = 0;
	CLData< float > * output = 0;
	CLData< float > * weights = 0;

	try {
		ArgumentList args(argc, argv);

		nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
		clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
		clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
		observation.setPadding(args.getSwitchArgument< unsigned int >("-padding"));
		minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
		maxThreadsPerBlock = args.getSwitchArgument< unsigned int >("-max_threads");
		maxItemsPerThread = args.getSwitchArgument< unsigned int >("-max_items");
		observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
		observation.setNrChannels(args.getSwitchArgument< unsigned int >("-channels"));
		observation.setNrStations(args.getSwitchArgument< unsigned int >("-stations"));
		observation.setNrBeams(args.getSwitchArgument< unsigned int >("-beams"));
	} catch ( EmptyCommandLine err ) {
		cerr << argv[0] << " -iterations ... -opencl_platform ... -opencl_device ... -padding ... -min_threads ... -max_threads ... -max_items ... -samples ... -channels ... -stations ... -beams ..." << endl;
		return 1;
	} catch ( exception &err ) {
		cerr << err.what() << endl;
		return 1;
	}

	vector< cl::Platform > *oclPlatforms = new vector< cl::Platform >();
	cl::Context *oclContext = new cl::Context();
	vector< cl::Device > *oclDevices = new vector< cl::Device >();
	vector< vector< cl::CommandQueue > > *oclQueues = new vector< vector< cl::CommandQueue > >();

	initializeOpenCL(clPlatformID, 1, oclPlatforms, oclContext, oclDevices, oclQueues);

	cout << fixed << endl;
	cout << "# nrStations nrBeams nrSamplesPerSecond nrChannels nrSamplesPerBlock beamsBlock GFLOP/s std.dev. time std.dev." << endl << endl;

	input = new CLData< float >("Input", true);
	input->allocateHostData(observation.getNrStations() * observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond() * nrPolarizations * 2);
	input->setCLContext(oclContext);
	input->setCLQueue(&(oclQueues->at(clDeviceID)[0]));
	input->setDeviceReadOnly();
	input->allocateDeviceData();

	output = new CLData< float >("Output", true);
	output->allocateHostData(observation.getNrBeams() * observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond() * nrPolarizations * 2);
	output->setCLContext(oclContext);
	output->setCLQueue(&(oclQueues->at(clDeviceID)[0]));
	output->setDeviceWriteOnly();
	output->allocateDeviceData();

	weights = new CLData< float >("Weights", true);
	weights->allocateHostData(observation.getNrChannels() * observation.getNrStations() * observation.getNrBeams() * 2);
	weights->setCLContext(oclContext);
	weights->setCLQueue(&(oclQueues->at(clDeviceID)[0]));
	weights->setDeviceReadOnly();
	weights->allocateDeviceData();

	// Find the parameters
	vector< unsigned int > samplesPerBlock;
	for ( unsigned int samples = minThreads; samples <= maxThreadsPerBlock; samples += minThreads ) {
		if ( (observation.getNrSamplesPerPaddedSecond() % samples) == 0 ) {
			samplesPerBlock.push_back(samples);
		}
	}
	vector< unsigned int > beamsBlock;
	for ( unsigned int beams = 1; beams <= maxItemsPerThread; beams++ ) {
		if ( (observation.getNrBeams() % beams) == 0 ) {
			beamsBlock.push_back(beams);
		}
	}

	for ( vector< unsigned int >::iterator samples = samplesPerBlock.begin(); samples != samplesPerBlock.end(); samples++ ) {
		for ( vector< unsigned int >::iterator beams = beamsBlock.begin(); beams != beamsBlock.end(); beams++ ) {
			double Acur = 0.0;
			double Aold = 0.0;
			double Vcur = 0.0;
			double Vold = 0.0;
			BeamFormer< float > * beamFormer = new BeamFormer< float >("BeamFormer", "float");

			try {
				beamFormer->bindOpenCL(oclContext, &(oclDevices->at(clDeviceID)), &(oclQueues->at(clDeviceID)[0]));
				beamFormer->setBeamsBlock(*beams);
				beamFormer->setNrSamplesPerBlock(*samples);
				beamFormer->setObservation(&observation);
				beamFormer->setAveragingFactor(1.0f / observation.getNrStations());

				// Warm-up
				(*beamFormer)(input, output, weights);
				beamFormer->getTimer().reset();

				for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
					(*beamFormer)(input, output, weights);

					if ( iteration == 0 ) {
						Acur = beamFormer->getGFLOP() / beamFormer->getTimer().getLastRunTime();
					} else {
						Aold = Acur;
						Vold = Vcur;

						Acur = Aold + (((beamFormer->getGFLOP() / beamFormer->getTimer().getLastRunTime()) - Aold) / (iteration + 1));
						Vcur = Vold + (((beamFormer->getGFLOP() / beamFormer->getTimer().getLastRunTime()) - Aold) * ((beamFormer->getGFLOP() / beamFormer->getTimer().getLastRunTime()) - Acur));
					}
				}
				Vcur = sqrt(Vcur / nrIterations);

				cout << observation.getNrStations() << " " << observation.getNrBeams() << " " << observation.getNrSamplesPerSecond() << " " << observation.getNrChannels() << " " << *samples << " " << *beams << " " << setprecision(3) << Acur << " " << Vcur << " " << setprecision(6) << beamFormer->getTimer().getAverageTime() << " " << beamFormer->getTimer().getStdDev() << endl;
			} catch ( OpenCLError err ) {
				cerr << err.what() << endl;
				continue;
			}
		}
	}

	cout << endl;
	return 0;
}

<commit_msg>Kernel now provides GFLOP/s and GB/s computation.<commit_after>//
// Copyright (C) 2012
// Alessio Sclocco <a.sclocco@vu.nl>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// 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
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include <vector>
using std::vector;
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
using std::fixed;
#include <iomanip>
using std::setprecision;
#include <cmath>

#include <ArgumentList.hpp>
using isa::utils::ArgumentList;
#include <CLData.hpp>
using isa::OpenCL::CLData;
#include <BeamFormer.hpp>
using LOFAR::RTCP::BeamFormer;
#include <InitializeOpenCL.hpp>
using isa::OpenCL::initializeOpenCL;
#include <Exceptions.hpp>
using isa::Exceptions::OpenCLError;
#include <Observation.hpp>
using AstroData::Observation;

const unsigned int nrPolarizations = 2;

int main(int argc, char *argv[]) {
	unsigned int nrIterations = 0;
	unsigned int clPlatformID = 0;
	unsigned int clDeviceID = 0;
	unsigned int minThreads = 0;
	unsigned int maxThreadsPerBlock = 0;
	unsigned int maxItemsPerThread = 0;
	Observation< float > observation("DedispersionTuning", "float");
	CLData< float > * input = 0;
	CLData< float > * output = 0;
	CLData< float > * weights = 0;

	try {
		ArgumentList args(argc, argv);

		nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
		clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
		clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
		observation.setPadding(args.getSwitchArgument< unsigned int >("-padding"));
		minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
		maxThreadsPerBlock = args.getSwitchArgument< unsigned int >("-max_threads");
		maxItemsPerThread = args.getSwitchArgument< unsigned int >("-max_items");
		observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
		observation.setNrChannels(args.getSwitchArgument< unsigned int >("-channels"));
		observation.setNrStations(args.getSwitchArgument< unsigned int >("-stations"));
		observation.setNrBeams(args.getSwitchArgument< unsigned int >("-beams"));
	} catch ( EmptyCommandLine err ) {
		cerr << argv[0] << " -iterations ... -opencl_platform ... -opencl_device ... -padding ... -min_threads ... -max_threads ... -max_items ... -samples ... -channels ... -stations ... -beams ..." << endl;
		return 1;
	} catch ( exception &err ) {
		cerr << err.what() << endl;
		return 1;
	}

	vector< cl::Platform > *oclPlatforms = new vector< cl::Platform >();
	cl::Context *oclContext = new cl::Context();
	vector< cl::Device > *oclDevices = new vector< cl::Device >();
	vector< vector< cl::CommandQueue > > *oclQueues = new vector< vector< cl::CommandQueue > >();

	initializeOpenCL(clPlatformID, 1, oclPlatforms, oclContext, oclDevices, oclQueues);

	cout << fixed << endl;
	cout << "# nrStations nrBeams nrSamplesPerSecond nrChannels nrSamplesPerBlock beamsBlock GFLOP/s std.dev. time std.dev." << endl << endl;

	input = new CLData< float >("Input", true);
	input->allocateHostData(observation.getNrStations() * observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond() * nrPolarizations * 2);
	input->setCLContext(oclContext);
	input->setCLQueue(&(oclQueues->at(clDeviceID)[0]));
	input->setDeviceReadOnly();
	input->allocateDeviceData();

	output = new CLData< float >("Output", true);
	output->allocateHostData(observation.getNrBeams() * observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond() * nrPolarizations * 2);
	output->setCLContext(oclContext);
	output->setCLQueue(&(oclQueues->at(clDeviceID)[0]));
	output->setDeviceWriteOnly();
	output->allocateDeviceData();

	weights = new CLData< float >("Weights", true);
	weights->allocateHostData(observation.getNrChannels() * observation.getNrStations() * observation.getNrBeams() * 2);
	weights->setCLContext(oclContext);
	weights->setCLQueue(&(oclQueues->at(clDeviceID)[0]));
	weights->setDeviceReadOnly();
	weights->allocateDeviceData();

	// Find the parameters
	vector< unsigned int > samplesPerBlock;
	for ( unsigned int samples = minThreads; samples <= maxThreadsPerBlock; samples += minThreads ) {
		if ( (observation.getNrSamplesPerPaddedSecond() % samples) == 0 ) {
			samplesPerBlock.push_back(samples);
		}
	}
	vector< unsigned int > beamsBlock;
	for ( unsigned int beams = 1; beams <= maxItemsPerThread; beams++ ) {
		if ( (observation.getNrBeams() % beams) == 0 ) {
			beamsBlock.push_back(beams);
		}
	}

	for ( vector< unsigned int >::iterator samples = samplesPerBlock.begin(); samples != samplesPerBlock.end(); samples++ ) {
		for ( vector< unsigned int >::iterator beams = beamsBlock.begin(); beams != beamsBlock.end(); beams++ ) {
			double Acur = 0.0;
			double Aold = 0.0;
			double Vcur = 0.0;
			double Vold = 0.0;
			BeamFormer< float > * beamFormer = new BeamFormer< float >("BeamFormer", "float");

			try {
				beamFormer->bindOpenCL(oclContext, &(oclDevices->at(clDeviceID)), &(oclQueues->at(clDeviceID)[0]));
				beamFormer->setBeamsBlock(*beams);
				beamFormer->setNrSamplesPerBlock(*samples);
				beamFormer->setObservation(&observation);
				beamFormer->setAveragingFactor(1.0f / observation.getNrStations());

				// Warm-up
				(*beamFormer)(input, output, weights);
				beamFormer->getTimer().reset();
				beamFormer->resetStats();

				for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
					(*beamFormer)(input, output, weights);
				}

				cout << observation.getNrStations() << " " << observation.getNrBeams() << " " << observation.getNrSamplesPerSecond() << " " << observation.getNrChannels() << " " << *samples << " " << *beams << " " << setprecision(3) << beamFormer->getGFLOPs() << " " << beamFormer->getGFLOPsErr() << " " << setprecision(6) << beamFormer->getTimer().getAverageTime() << " " << beamFormer->getTimer().getStdDev() << endl;
			} catch ( OpenCLError err ) {
				cerr << err.what() << endl;
				continue;
			}
		}
	}

	cout << endl;
	return 0;
}

<|endoftext|>


<commit_before>#include <cstddef>
#include <cstddef>
#include <fstream>
#include <iomanip>

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <ShlObj.h>

#define WIDEIFYIMP(x) L##x
#define WIDEIFY(x) WIDEIFYIMP(x)

#include <queue>

#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;

#include <UWP/UWP.hpp>

#include <UWP/DumperIPC.hpp>

std::uint32_t __stdcall DumperThread(void* DLLHandle)
{
	std::wstring DumpPath = fs::path(UWP::Current::Storage::GetTempStatePath()) / L"DUMP";

	IPC::SetTargetThread(GetCurrentThreadId());

	IPC::PushMessage(L"UWPDumper Build date(%ls : %ls)\n", WIDEIFY(__DATE__), WIDEIFY(__TIME__));
	IPC::PushMessage(L"\t-https://github.com/Wunkolo/UWPDumper\n");
	IPC::PushMessage(L"Publisher:\n\t%s\n", UWP::Current::GetPublisher().c_str());
	IPC::PushMessage(L"Publisher ID:\n\t%s\n", UWP::Current::GetPublisherID().c_str());
	IPC::PushMessage(L"Publisher Path:\n\t%s\n", UWP::Current::Storage::GetPublisherPath().c_str());
	IPC::PushMessage(L"Package Path:\n\t%s\n", UWP::Current::GetPackagePath().c_str());
	IPC::PushMessage(L"Package Name:\n\t%s\n", UWP::Current::GetFullName().c_str());
	IPC::PushMessage(L"Family Name:\n\t%s\n", UWP::Current::GetFamilyName().c_str());

	IPC::PushMessage(L"Dump Path:\n\t%s\n", DumpPath.c_str());

	std::vector<fs::directory_entry> FileList;

	for( auto& Entry : fs::recursive_directory_iterator(".") )
	{
		if( fs::is_regular_file(Entry.path()) )
		{
			FileList.push_back(Entry);
		}
	}

	IPC::PushMessage(L"\tDumping %zu files\n", FileList.size());

	std::size_t i = 0;
	for( const auto& File : FileList )
	{
		const fs::path WritePath = DumpPath + File.path().wstring().substr(1);
		const std::wstring ReadPath = File.path().wstring().substr(1);
		IPC::PushMessage(
			L"%*.*s %*.u bytes %*zu/%zu\n",
			60, 60,
			ReadPath.c_str() + (ReadPath.length() > 60 ? (ReadPath.length() - (60)) : 0),
			15,
			fs::file_size(File),
			20,
			i + 1,
			FileList.size()
		);

		std::error_code ErrorCode;
		fs::create_directories(WritePath.parent_path(), ErrorCode);

		std::ifstream SourceFile(ReadPath, std::ios::binary);
		std::ofstream DestFile(WritePath, std::ios::binary);

		if( SourceFile && DestFile && ErrorCode )
		{
			DestFile << SourceFile.rdbuf();
		}
		else
		{
			IPC::PushMessage(
				L"\tError copying:\n\t\t%s\n\t\tto\n\t\t%s\n",
				File.path().c_str(),
				WritePath.c_str()
			);
		}

		i++;
	}

	IPC::PushMessage(L"Dump complete!\n\tPath:\n\t%s\n", DumpPath.c_str());
	IPC::ClearTargetThread();

	FreeLibraryAndExitThread(reinterpret_cast<HMODULE>(DLLHandle), 0);

	return EXIT_SUCCESS;
}

std::int32_t __stdcall DllMain(HINSTANCE hDLL, std::uint32_t Reason, void* Reserved)
{
	switch( Reason )
	{
	case DLL_PROCESS_ATTACH:
	{
		if( IPC::GetTargetProcess() == GetCurrentProcessId() )
		{
			// We are the target process to be dumped
			CreateThread(
				nullptr,
				0,
				reinterpret_cast<unsigned long(__stdcall*)(void*)>(&DumperThread),
				hDLL,
				0,
				nullptr
			);
		}
	}
	case DLL_PROCESS_DETACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	default:
	{
		return true;
	}
	}

	return false;
}
<commit_msg>Decouple error output for folders<commit_after>#include <cstddef>
#include <cstddef>
#include <fstream>
#include <iomanip>

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <ShlObj.h>

#define WIDEIFYIMP(x) L##x
#define WIDEIFY(x) WIDEIFYIMP(x)

#include <queue>

#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;

#include <UWP/UWP.hpp>

#include <UWP/DumperIPC.hpp>

std::uint32_t __stdcall DumperThread(void* DLLHandle)
{
	std::wstring DumpPath = fs::path(UWP::Current::Storage::GetTempStatePath()) / L"DUMP";

	IPC::SetTargetThread(GetCurrentThreadId());

	IPC::PushMessage(L"UWPDumper Build date(%ls : %ls)\n", WIDEIFY(__DATE__), WIDEIFY(__TIME__));
	IPC::PushMessage(L"\t-https://github.com/Wunkolo/UWPDumper\n");
	IPC::PushMessage(L"Publisher:\n\t%s\n", UWP::Current::GetPublisher().c_str());
	IPC::PushMessage(L"Publisher ID:\n\t%s\n", UWP::Current::GetPublisherID().c_str());
	IPC::PushMessage(L"Publisher Path:\n\t%s\n", UWP::Current::Storage::GetPublisherPath().c_str());
	IPC::PushMessage(L"Package Path:\n\t%s\n", UWP::Current::GetPackagePath().c_str());
	IPC::PushMessage(L"Package Name:\n\t%s\n", UWP::Current::GetFullName().c_str());
	IPC::PushMessage(L"Family Name:\n\t%s\n", UWP::Current::GetFamilyName().c_str());

	IPC::PushMessage(L"Dump Path:\n\t%s\n", DumpPath.c_str());

	std::vector<fs::directory_entry> FileList;

	for( auto& Entry : fs::recursive_directory_iterator(".") )
	{
		if( fs::is_regular_file(Entry.path()) )
		{
			FileList.push_back(Entry);
		}
	}

	IPC::PushMessage(L"\tDumping %zu files\n", FileList.size());

	std::size_t i = 0;
	for( const auto& File : FileList )
	{
		const fs::path WritePath = DumpPath + File.path().wstring().substr(1);
		const std::wstring ReadPath = File.path().wstring().substr(1);
		IPC::PushMessage(
			L"%*.*s %*.u bytes %*zu/%zu\n",
			60, 60,
			ReadPath.c_str() + (ReadPath.length() > 60 ? (ReadPath.length() - (60)) : 0),
			15,
			fs::file_size(File),
			20,
			++i,
			FileList.size()
		);

		std::error_code ErrorCode;
		if( fs::create_directories(WritePath.parent_path(), ErrorCode) )
		{
			IPC::PushMessage(
				L"Error creating dump folder: %s (%s)\n",
				WritePath.c_str(),
				ErrorCode.message().c_str()
			);
			continue;
		}

		std::ifstream SourceFile(ReadPath, std::ios::binary);
		std::ofstream DestFile(WritePath, std::ios::binary);

		if( SourceFile && DestFile )
		{
			DestFile << SourceFile.rdbuf();
		}
		else
		{
			IPC::PushMessage(
				L"Error copying:\n"
				"\t%s\n"
				"\tto\n"
				"\t%s\n",
				File.path().c_str(),
				WritePath.c_str()
			);
		}
	}

	IPC::PushMessage(L"Dump complete!\n\tPath:\n\t%s\n", DumpPath.c_str());
	IPC::ClearTargetThread();

	FreeLibraryAndExitThread(reinterpret_cast<HMODULE>(DLLHandle), 0);

	return EXIT_SUCCESS;
}

std::int32_t __stdcall DllMain(HINSTANCE hDLL, std::uint32_t Reason, void* Reserved)
{
	switch( Reason )
	{
	case DLL_PROCESS_ATTACH:
	{
		if( IPC::GetTargetProcess() == GetCurrentProcessId() )
		{
			// We are the target process to be dumped
			CreateThread(
				nullptr,
				0,
				reinterpret_cast<unsigned long(__stdcall*)(void*)>(&DumperThread),
				hDLL,
				0,
				nullptr
			);
		}
	}
	case DLL_PROCESS_DETACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	default:
	{
		return true;
	}
	}

	return false;
}
<|endoftext|>


<commit_before>// Copyright (c) Andrew Fischer. See LICENSE file for license terms.

#include "common_headers.h"

#include "interpreter.h"
#include "function.h"
#include "type.h"
#include "tagged_value.h"
#include "type.h"

#include "handle.h"

namespace circa {

struct HandleData
{
    int refCount;
    void* value;
    caReleaseFunc release;
};

bool is_handle(caValue* value)
{
    return value->value_type->storageType == sym_StorageTypeHandle;
}

HandleData* as_handle(caValue* handle)
{
    ca_assert(handle->value_type->storageType == sym_StorageTypeHandle);
    return (HandleData*) handle->value_data.ptr;
}

void* handle_get_value(caValue* handle)
{
    HandleData* container = as_handle(handle);
    return container->value;
}

void handle_set(caValue* handle, void* value, caReleaseFunc release)
{
    HandleData* container = as_handle(handle);
    container->value = value;
    container->release = release;
}

void handle_initialize(Type* type, caValue* value)
{
    HandleData* c = (HandleData*) malloc(sizeof(HandleData));
    c->refCount = 1;
    c->value = NULL;
    c->release = NULL;
    value->value_data.ptr = c;
}

void handle_release(caValue* value)
{
    HandleData* container = as_handle(value);
    ca_assert(container != NULL);
    ca_assert(container->refCount > 0);

    container->refCount--;

    // Release data, if this is the last reference.
    if (container->refCount == 0) {

        if (container->release != NULL)
            container->release(value, container->value);

        #if 0
        // Find the type's release function (if any), and call it.
        Value releaseStr;
        set_string(&releaseStr, "release");
        Term* releaseMethod = find_method(NULL, value->value_type, &releaseStr);
        if (releaseMethod != NULL) {
            Stack stack;
            stack_init(&stack, function_contents(releaseMethod));
            caValue* inputSlot = get_input(&stack, 0);

            // Don't copy this value, otherwise we'll get in trouble when the copy
            // needs to be released.
            set_pointer(inputSlot, container->value);

            stack_run(&stack);

            inputSlot = get_input(&stack, 0);
        }
        #endif

        free(container);
    }
}

void handle_copy(Type*, caValue* source, caValue* dest)
{
    as_handle(source)->refCount++;

    set_null(dest);
    make_no_initialize(source->value_type, dest);
    dest->value_data.ptr = source->value_data.ptr;
}

bool handle_equals(caValue* left, caValue* right)
{
    if (!is_handle(right))
        return false;

    return left->value_data.ptr == right->value_data.ptr;
}

int handle_hash(caValue* val)
{
    return (int64_t) as_handle(val)->value;
}

void handle_setup_type(Type* type)
{
    type->storageType = sym_StorageTypeHandle;
    type->initialize = handle_initialize;
    type->copy = handle_copy;
    type->release = handle_release;
    type->equals = handle_equals;
    type->hashFunc = handle_hash;
}

} // namespace circa
<commit_msg>Tiny fix in handle<commit_after>// Copyright (c) Andrew Fischer. See LICENSE file for license terms.

#include "common_headers.h"

#include "interpreter.h"
#include "function.h"
#include "type.h"
#include "tagged_value.h"
#include "type.h"

#include "handle.h"

namespace circa {

struct HandleData
{
    int refCount;
    void* value;
    caReleaseFunc release;
};

bool is_handle(caValue* value)
{
    return value->value_type->storageType == sym_StorageTypeHandle;
}

HandleData* as_handle(caValue* handle)
{
    ca_assert(handle->value_type->storageType == sym_StorageTypeHandle);
    return (HandleData*) handle->value_data.ptr;
}

void* handle_get_value(caValue* handle)
{
    HandleData* container = as_handle(handle);
    return container->value;
}

void handle_set(caValue* handle, void* value, caReleaseFunc release)
{
    if (!is_handle(handle))
        make_no_initialize(TYPES.handle, handle);

    HandleData* container = as_handle(handle);
    container->value = value;
    container->release = release;
}

void handle_initialize(Type* type, caValue* value)
{
    HandleData* c = (HandleData*) malloc(sizeof(HandleData));
    c->refCount = 1;
    c->value = NULL;
    c->release = NULL;
    value->value_data.ptr = c;
}

void handle_release(caValue* value)
{
    HandleData* container = as_handle(value);
    ca_assert(container != NULL);
    ca_assert(container->refCount > 0);

    container->refCount--;

    // Release data, if this is the last reference.
    if (container->refCount == 0) {

        if (container->release != NULL)
            container->release(value, container->value);

        #if 0
        // Find the type's release function (if any), and call it.
        Value releaseStr;
        set_string(&releaseStr, "release");
        Term* releaseMethod = find_method(NULL, value->value_type, &releaseStr);
        if (releaseMethod != NULL) {
            Stack stack;
            stack_init(&stack, function_contents(releaseMethod));
            caValue* inputSlot = get_input(&stack, 0);

            // Don't copy this value, otherwise we'll get in trouble when the copy
            // needs to be released.
            set_pointer(inputSlot, container->value);

            stack_run(&stack);

            inputSlot = get_input(&stack, 0);
        }
        #endif

        free(container);
    }
}

void handle_copy(Type*, caValue* source, caValue* dest)
{
    as_handle(source)->refCount++;

    set_null(dest);
    make_no_initialize(source->value_type, dest);
    dest->value_data.ptr = source->value_data.ptr;
}

bool handle_equals(caValue* left, caValue* right)
{
    if (!is_handle(right))
        return false;

    return left->value_data.ptr == right->value_data.ptr;
}

int handle_hash(caValue* val)
{
    return (int64_t) as_handle(val)->value;
}

void handle_setup_type(Type* type)
{
    type->storageType = sym_StorageTypeHandle;
    type->initialize = handle_initialize;
    type->copy = handle_copy;
    type->release = handle_release;
    type->equals = handle_equals;
    type->hashFunc = handle_hash;
}

} // namespace circa
<|endoftext|>


<commit_before>#include <algorithm>
#include "catch.h"
#include "../Software/NeuralNet.h"
#include "../Software/Backpropagation.h"

const double ERROR_ALLOWANCE = 1.0;

TEST_CASE("Test back propagation", "[backprop]") {
	// Creates a neural network with
	// 1 input, 1 output, 2 hidden layers, 4 neurons per hidden layer,
	// a sigmoid activation function for hidden layers, and a linear activation function on the final layer.
	net::NeuralNet neuralNetwork = net::NeuralNet(1, 1, 2, 4, "sigmoid");
	neuralNetwork.setOutputActivationFunction("simpleLinear");

	std::vector< std::vector<double> > input = { {1}, {2}, {5}, {6} };
	std::vector< std::vector<double> > correctOutput = { {2}, {4}, {10}, {12} };

	// Create backpropagation object with
	// a learning rate of 10%, a momentum term of 0.001, an acceptable error level of 0.1%,
	// and a maximum number of training iterations of 10000
	net::Backpropagation backprop = net::Backpropagation(0.1, 0.001, 0.001, 10000);
	backprop.train(&neuralNetwork, input, correctOutput);

	// Cycle through inputs and print the outputs
	for (std::vector<double> current: input) {
		REQUIRE(fabs(current[0]*2 - neuralNetwork.getOutput(current)[0]) < ERROR_ALLOWANCE);
	}
}
<commit_msg>add saving and loading unit tests<commit_after>#include <algorithm>
#include <fstream>
#include <iostream>
#include <cstdio>
#include "catch.h"
#include "../Software/NeuralNet.h"
#include "../Software/Backpropagation.h"

const static double ERROR_ALLOWANCE = 0.1;
const static double DIFFERENCE_ALLOWANCE = 0.01;
const static char * FILENAME = "backpropfile.txt";

TEST_CASE("Test back propagation", "[backprop]") {
	// Creates a neural network with
	// 1 input, 1 output, 2 hidden layers, 4 neurons per hidden layer,
	// a sigmoid activation function for hidden layers, and a linear activation function on the final layer.
	net::NeuralNet neuralNetwork = net::NeuralNet(1, 1, 2, 4, "sigmoid");
	neuralNetwork.setOutputActivationFunction("simpleLinear");

	std::vector< std::vector<double> > input = { {1}, {2}, {5}, {6} };
	std::vector< std::vector<double> > correctOutput = { {2}, {4}, {10}, {12} };

	// Create backpropagation object with
	// a learning rate of 10%, a momentum term of 0.001, an acceptable error level of 0.1%,
	// and a maximum number of training iterations of 10000
	net::Backpropagation backprop = net::Backpropagation(0.1, 0.001, 0.001, 10000);
	backprop.train(&neuralNetwork, input, correctOutput);

	// Cycle through inputs and print the outputs
	for (std::vector<double> current: input) {
		REQUIRE(fabs(current[0]*2 - neuralNetwork.getOutput(current)[0]) < ERROR_ALLOWANCE);
	}
}

TEST_CASE("Save and load backpropagations through streams", "[backprop]") {
	// Creates a neural network with
	// 1 input, 1 output, 2 hidden layers, 4 neurons per hidden layer,
	// a sigmoid activation function for hidden layers, and a linear activation function on the final layer.
	net::NeuralNet neuralNetwork = net::NeuralNet(1, 1, 2, 4, "sigmoid");
	neuralNetwork.setOutputActivationFunction("simpleLinear");
	net::NeuralNet newNeuralNetwork = net::NeuralNet(1, 1, 2, 4, "sigmoid");
	newNeuralNetwork.setOutputActivationFunction("simpleLinear");

	std::vector< std::vector<double> > input = { {1}, {2}, {5}, {6} };
	std::vector< std::vector<double> > correctOutput = { {2}, {4}, {10}, {12} };

	// Create backpropagation object with
	// a learning rate of 10%, a momentum term of 0.001, an acceptable error level of 0.1%,
	// and a maximum number of training iterations of 10000
	net::Backpropagation backprop = net::Backpropagation(0.1, 0.001, 0.001, 10000);

	// Save
	std::ofstream ostream;
	ostream.open(FILENAME, std::ios::app);
	backprop.store(&ostream); // Store old
	ostream.close();

	// Load
	std::ifstream istream;
	istream.open(FILENAME, std::ifstream::in);
	net::Backpropagation newBackprop = net::Backpropagation(&istream); // load new
	istream.close();
	std::remove(FILENAME);

	// Train with new backprop
	backprop.train(&neuralNetwork, input, correctOutput); // train old
	newBackprop.train(&newNeuralNetwork, input, correctOutput); // train new

	// Test similarity
	for (std::vector<double> current: input) {
		REQUIRE( fabs(newNeuralNetwork.getOutput(current)[0] - neuralNetwork.getOutput(current)[0]) < DIFFERENCE_ALLOWANCE);
	}
}
<|endoftext|>