<commit_before>/*
 * Teng -- a general purpose templating engine.
 * Copyright (C) 2004  Seznam.cz, a.s.
 *
 * 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.1 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
 *
 * Seznam.cz, a.s.
 * Naskove 1, Praha 5, 15000, Czech Republic
 * http://www.seznam.cz, mailto:teng@firma.seznam.cz
 *
 *
 * $Id: tengstructs.cc,v 1.4 2007-05-21 15:43:28 vasek Exp $
 *
 * DESCRIPTION
 * Teng data types -- implementation.
 *
 * AUTHORS
 * Vaclav Blazek <blazek@firma.seznam.cz>
 *
 * HISTORY
 * 2003-09-30  (vasek)
 *             Created.
 * 2005-06-21  (roman)
 *             Win32 support.
*/

#include <cstdio>
#include <cstring>
#include <sstream>
#include <iomanip>

#include "tengstructs.h"
#include "tengplatform.h"

namespace Teng {
namespace {

template <typename type_t>
void dispose(type_t *ptr) {ptr->~type_t();}

std::string stringify(IntType_t value) {
    std::ostringstream os;
    os << value;
    return os.str();
}

std::string stringify(double value) {
    // produce at least d.d
    char buffer[64];
    auto len = snprintf(buffer, sizeof(buffer), "%#f", value);

    // remove trialing zeroes
    for (; len > 2; --len) {
        if (buffer[len - 1] == '0')
            if (buffer[len - 2] != '.')
                continue;
        break;
    }

    // done
    return std::string(buffer, len);
}

template <typename where_t, typename type_t>
void replace_item(where_t &&items, const std::string &name, type_t &&value) {
    auto iitem = items.find(name);
    if (iitem != items.end())
        return iitem->second->setValue(value);
    items.emplace_hint(iitem, name, std::make_unique<FragmentValue_t>(value));
}

void unicode_char(std::ostream &o, char ch) {
    o << "\\u00" << std::hex << std::setw(2) << std::setfill('0') << int(ch);
}

void quote_json_string(std::ostream &o, const std::string &value) {
    o << '"';
    for (char ch: value) {
        switch (ch) {
        case 0 ... 8:
        case 11 ... 12:
        case 14 ... 31: unicode_char(o, ch); break;
        case '\n': o << "\\n"; break;
        case '\r': o << "\\r"; break;
        case '\t': o << "\\t"; break;
        case '\\': o << "\\\\"; break;
        case '"': o << "\\\""; break;
        default: o << ch; break;
        }
    }
    o << '"';
}

} // namespace

Fragment_t &FragmentList_t::addFragment() {
    items.push_back(std::make_unique<Fragment_t>());
    return *items.back();
}

void Fragment_t::json(std::ostream &o) const {
    o << '{';
   for (const_iterator i = begin(); i != end(); ++i) {
        if (i != begin()) o << ", ";
        quote_json_string(o, i->first);
        o << " : ";
        i->second->json(o);
    }
    o << '}';
}

void Fragment_t::dump(std::ostream &o) const {
    o << '{';
    for (const_iterator i = begin(); i != end(); ++i) {
        if (i != begin()) o << ", ";
        o << "'" << i->first << "': ";
        i->second->dump(o);
    }
    o << '}';
}

void
Fragment_t::addVariable(const std::string &name, const std::string &value) {
    replace_item(items, name, value);
}

void Fragment_t::addVariable(const std::string &name, IntType_t value) {
    replace_item(items, name, value);
}

void Fragment_t::addVariable(const std::string &name, double value) {
    replace_item(items, name, value);
}

Fragment_t &Fragment_t::addFragment(const std::string &name) {
    return addFragmentList(name).addFragment();
}

FragmentList_t &
Fragment_t::addFragmentList(const std::string &name) {
    auto iitem = items.find(name);
    if (iitem != items.end())
        return iitem->second->ensureFragmentList();
    return items.emplace_hint(
        iitem,
        name,
        std::make_unique<FragmentValue_t>(std::make_unique<FragmentList_t>())
    )->second->ensureFragmentList();
}

void FragmentList_t::json(std::ostream &o) const {
    o << '[';
    for (const_iterator i = begin(); i != end(); ++i) {
        if (i != begin()) o << ", ";
        (*i)->json(o);
    }
    o << ']';
}

void FragmentList_t::dump(std::ostream &o) const {
    o << '[';
    for (const_iterator i = begin(); i != end(); ++i) {
        if (i != begin()) o << ", ";
        (*i)->dump(o);
    }
    o << ']';
}

FragmentValue_t::FragmentValue_t()
    : held_type(type::string), value()
{}

FragmentValue_t::FragmentValue_t(const std::string &value)
    : held_type(type::string), value(value)
{}

FragmentValue_t::FragmentValue_t(IntType_t value)
    : held_type(type::integer), value(stringify(value))
{}

FragmentValue_t::FragmentValue_t(double value)
    : held_type(type::floating), value(stringify(value))
{}

FragmentValue_t::FragmentValue_t(std::unique_ptr<FragmentList_t> fragment_list)
    : held_type(type::fragments), nestedFragments(std::move(fragment_list))
{}

FragmentValue_t::~FragmentValue_t() {
    switch (held_type) {
    case type::fragments: dispose(&nestedFragments); break;
    case type::string: dispose(&value); break;
    case type::integer: dispose(&value); break;
    case type::floating: dispose(&value); break;
    }
}

void FragmentValue_t::setValue(const std::string &new_value) {
    if (held_type == type::fragments) {
        dispose(&nestedFragments);
        new (&value) std::string(new_value);
    } else value = new_value;
    held_type = type::string;
}

void FragmentValue_t::setValue(const IntType_t new_value) {
    if (held_type == type::fragments) {
        dispose(&nestedFragments);
        new (&value) std::string(stringify(new_value));
    } else value = stringify(new_value);;
    held_type = type::integer;
}

void FragmentValue_t::setValue(const double new_value) {
    if (held_type == type::fragments) {
        dispose(&nestedFragments);
        new (&value) std::string(stringify(new_value));
    } else value = stringify(new_value);
    held_type = type::floating;
}

FragmentList_t &FragmentValue_t::ensureFragmentList() {
    if (held_type != type::fragments) {
        dispose(&value);
        new (&nestedFragments)
            std::unique_ptr<FragmentList_t>(new FragmentList_t());
    }
    return *nestedFragments;
}

Fragment_t &FragmentValue_t::addFragment() {
    ensureFragmentList().addFragment();
    return nestedFragments->addFragment();
}

void FragmentValue_t::json(std::ostream &o) const {
    switch (held_type) {
    case type::fragments: nestedFragments->json(o); break;
    case type::string: quote_json_string(o, value); break;
    case type::integer: o << value; break;
    case type::floating: o << value; break;
    }
}

void FragmentValue_t::dump(std::ostream &o) const {
    if (held_type == type::fragments) nestedFragments->dump(o);
    else o << '\'' << value << '\'';
}

} // namespace Teng

<commit_msg>Revert "fix unicode format"<commit_after>/*
 * Teng -- a general purpose templating engine.
 * Copyright (C) 2004  Seznam.cz, a.s.
 *
 * 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.1 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
 *
 * Seznam.cz, a.s.
 * Naskove 1, Praha 5, 15000, Czech Republic
 * http://www.seznam.cz, mailto:teng@firma.seznam.cz
 *
 *
 * $Id: tengstructs.cc,v 1.4 2007-05-21 15:43:28 vasek Exp $
 *
 * DESCRIPTION
 * Teng data types -- implementation.
 *
 * AUTHORS
 * Vaclav Blazek <blazek@firma.seznam.cz>
 *
 * HISTORY
 * 2003-09-30  (vasek)
 *             Created.
 * 2005-06-21  (roman)
 *             Win32 support.
*/

#include <cstdio>
#include <cstring>
#include <sstream>

#include "tengstructs.h"
#include "tengplatform.h"

namespace Teng {
namespace {

template <typename type_t>
void dispose(type_t *ptr) {ptr->~type_t();}

std::string stringify(IntType_t value) {
    std::ostringstream os;
    os << value;
    return os.str();
}

std::string stringify(double value) {
    // produce at least d.d
    char buffer[64];
    auto len = snprintf(buffer, sizeof(buffer), "%#f", value);

    // remove trialing zeroes
    for (; len > 2; --len) {
        if (buffer[len - 1] == '0')
            if (buffer[len - 2] != '.')
                continue;
        break;
    }

    // done
    return std::string(buffer, len);
}

template <typename where_t, typename type_t>
void replace_item(where_t &&items, const std::string &name, type_t &&value) {
    auto iitem = items.find(name);
    if (iitem != items.end())
        return iitem->second->setValue(value);
    items.emplace_hint(iitem, name, std::make_unique<FragmentValue_t>(value));
}

void unicode_char(std::ostream &o, char ch) {
    o << "\\u00" << std::hex << int(ch);
}

void quote_json_string(std::ostream &o, const std::string &value) {
    o << '"';
    for (char ch: value) {
        switch (ch) {
        case 0 ... 8:
        case 11 ... 12:
        case 14 ... 31: unicode_char(o, ch); break;
        case '\n': o << "\\n"; break;
        case '\r': o << "\\r"; break;
        case '\t': o << "\\t"; break;
        case '\\': o << "\\\\"; break;
        case '"': o << "\\\""; break;
        default: o << ch; break;
        }
    }
    o << '"';
}

} // namespace

Fragment_t &FragmentList_t::addFragment() {
    items.push_back(std::make_unique<Fragment_t>());
    return *items.back();
}

void Fragment_t::json(std::ostream &o) const {
    o << '{';
   for (const_iterator i = begin(); i != end(); ++i) {
        if (i != begin()) o << ", ";
        quote_json_string(o, i->first);
        o << " : ";
        i->second->json(o);
    }
    o << '}';
}

void Fragment_t::dump(std::ostream &o) const {
    o << '{';
    for (const_iterator i = begin(); i != end(); ++i) {
        if (i != begin()) o << ", ";
        o << "'" << i->first << "': ";
        i->second->dump(o);
    }
    o << '}';
}

void
Fragment_t::addVariable(const std::string &name, const std::string &value) {
    replace_item(items, name, value);
}

void Fragment_t::addVariable(const std::string &name, IntType_t value) {
    replace_item(items, name, value);
}

void Fragment_t::addVariable(const std::string &name, double value) {
    replace_item(items, name, value);
}

Fragment_t &Fragment_t::addFragment(const std::string &name) {
    return addFragmentList(name).addFragment();
}

FragmentList_t &
Fragment_t::addFragmentList(const std::string &name) {
    auto iitem = items.find(name);
    if (iitem != items.end())
        return iitem->second->ensureFragmentList();
    return items.emplace_hint(
        iitem,
        name,
        std::make_unique<FragmentValue_t>(std::make_unique<FragmentList_t>())
    )->second->ensureFragmentList();
}

void FragmentList_t::json(std::ostream &o) const {
    o << '[';
    for (const_iterator i = begin(); i != end(); ++i) {
        if (i != begin()) o << ", ";
        (*i)->json(o);
    }
    o << ']';
}

void FragmentList_t::dump(std::ostream &o) const {
    o << '[';
    for (const_iterator i = begin(); i != end(); ++i) {
        if (i != begin()) o << ", ";
        (*i)->dump(o);
    }
    o << ']';
}

FragmentValue_t::FragmentValue_t()
    : held_type(type::string), value()
{}

FragmentValue_t::FragmentValue_t(const std::string &value)
    : held_type(type::string), value(value)
{}

FragmentValue_t::FragmentValue_t(IntType_t value)
    : held_type(type::integer), value(stringify(value))
{}

FragmentValue_t::FragmentValue_t(double value)
    : held_type(type::floating), value(stringify(value))
{}

FragmentValue_t::FragmentValue_t(std::unique_ptr<FragmentList_t> fragment_list)
    : held_type(type::fragments), nestedFragments(std::move(fragment_list))
{}

FragmentValue_t::~FragmentValue_t() {
    switch (held_type) {
    case type::fragments: dispose(&nestedFragments); break;
    case type::string: dispose(&value); break;
    case type::integer: dispose(&value); break;
    case type::floating: dispose(&value); break;
    }
}

void FragmentValue_t::setValue(const std::string &new_value) {
    if (held_type == type::fragments) {
        dispose(&nestedFragments);
        new (&value) std::string(new_value);
    } else value = new_value;
    held_type = type::string;
}

void FragmentValue_t::setValue(const IntType_t new_value) {
    if (held_type == type::fragments) {
        dispose(&nestedFragments);
        new (&value) std::string(stringify(new_value));
    } else value = stringify(new_value);;
    held_type = type::integer;
}

void FragmentValue_t::setValue(const double new_value) {
    if (held_type == type::fragments) {
        dispose(&nestedFragments);
        new (&value) std::string(stringify(new_value));
    } else value = stringify(new_value);
    held_type = type::floating;
}

FragmentList_t &FragmentValue_t::ensureFragmentList() {
    if (held_type != type::fragments) {
        dispose(&value);
        new (&nestedFragments)
            std::unique_ptr<FragmentList_t>(new FragmentList_t());
    }
    return *nestedFragments;
}

Fragment_t &FragmentValue_t::addFragment() {
    ensureFragmentList().addFragment();
    return nestedFragments->addFragment();
}

void FragmentValue_t::json(std::ostream &o) const {
    switch (held_type) {
    case type::fragments: nestedFragments->json(o); break;
    case type::string: quote_json_string(o, value); break;
    case type::integer: o << value; break;
    case type::floating: o << value; break;
    }
}

void FragmentValue_t::dump(std::ostream &o) const {
    if (held_type == type::fragments) nestedFragments->dump(o);
    else o << '\'' << value << '\'';
}

} // namespace Teng

<|endoftext|>


<commit_before>// @file irc.cpp
// @brief Implementation of the IRC class, which implements the
//        User, Message and Chat abstract classes.
//

#include <sstream> // std::stringstream
#include "irc.h"

std::deque<std::string> Split(std::string pretext, char delim)
{
  std::deque<std::string> sans_delim;
  std::string tokens;
  std::stringstream sstream(pretext);
  while (std::getline(sstream, tokens, delim))
  {
    sans_delim.push_back(tokens);
  }
  return sans_delim;
}

//----------------------------//
// User Class Implementation. //
//----------------------------//
IRCUser::IRCUser(void)
{
  return;
}

  bool
IRCUser::Equals(User *u)
{
  return true;
}

//-------------------------------//
// Message Class Implementation. //
//-------------------------------//
  std::string
IRCMessage::GetString()
{
  return str;
}

  std::string
IRCMessage::GetFormattedString()
{
  std::string arg;
  for (auto i = argList.begin(); i != argList.end(); ++i)
  {
    arg += *i + " ";
  }
  return command + " " + arg + ":" + str + "\r\n";
}

IRCMessage::IRCMessage(std::string s)
{
  str = "";

  // We don't know if the prefix is actually present.
  int prefixEnd = -1;

  // The prefix is actually present.
  if (s.at(0) == ':')
  {
    // The end is before the first space.
    prefixEnd = s.find_first_of(' ');
    // Save the prefix. (Note: we ca further segment it later.)
    prefix = s.substr(1, prefixEnd - 1);
    if (prefix.find('!') != prefix.npos)
    {
      nickname = prefix.substr(0, prefix.find('!'));
    }
  }

  size_t trailBegin = s.find(" :");

  // Check if there is a trailing message.
  if (trailBegin != s.npos)
  {
    // Save the trail (char after colon to end of string).
    str = s.substr(trailBegin + 2, s.npos);
  }
  // We get a list of the arguments.
  argList = Split(s.substr(prefixEnd + 1, (trailBegin - prefixEnd - 1)), ' ');

  if (!argList.empty())
  {
    command = argList.at(0);
    argList.pop_front();
  }

  // Trim the \r\n
  if (str.length() > 2) {
    str = str.substr(0, str.length() - 2);
  }
}

IRCMessage::IRCMessage()
{
  str = "";
  return;
}

IRCMessage::~IRCMessage()
{
  return;
}

  IRCUser*
IRCMessage::GetUser()
{
  return new IRCUser;
}

  IRCMessage*
IRCMessage::Respond(std::string s)
{
  IRCMessage *m = new IRCMessage();
  m->str = s;
  m->command = "PRIVMSG";
  m->argList = argList;
  return m;
}

  void
IRCMessage::Update(std::string s)
{
  str = s;
}

//----------------------------//
// Chat Class Implementation. //
//----------------------------//

IRCChat::IRCChat(std::string server,
    std::string port,
    std::string nick,
    std::string password)
{
  socket = new Socket(server, port);
  socket->Send("PASS " + password + "\r\n");
  socket->Send("NICK " + nick + "\r\n");
  socket->Send("USER " + nick + " localhost servername :" + nick + "\r\n");
}

IRCChat::~IRCChat(void)
{
  delete socket;
}

  void
IRCChat::Join(std::string channel)
{
  socket->Send("JOIN " + channel + "\r\n");
}

  IRCMessage*
IRCChat::GetMessage()
{
  IRCMessage *m = NULL;
  while (!m)
  {
    m = new IRCMessage(socket->Recv());
    if (m->command == "PING")
    {
      socket->Send("PONG :" + m->str + "\r\n");
      delete m;
    }
  }

#ifdef LOGGING
  std::cout << "COMMAND: " + m->command + "\nARGUMENTS" << std::endl;
  for (auto i = m->argList.begin(); i != m->argList.end(); ++i)
  {
    std::cout << "\t" + *i << std::endl;
  }
  std::cout << "MESSAGE: " + m->str << std::endl;
  std::cout << "NICKNAME: " + m->nickname << std::endl;
  std::cout << "USERNAME: " + m->username << std::endl;
  std::cout << "HOSTNAME: " + m->hostname << std::endl;
  std::cout << "SERVERNAME: " + m->servername << std::endl;
  std::cout << "PREFIX: " + m->prefix << std::endl;
#endif

  return m;
}

  void
IRCChat::SendMessage(Message *m)
{
#ifdef LOGGING
  std::cout << m->GetFormattedString() << std::endl;
#endif
  socket->Send(m->GetFormattedString());
}

<commit_msg>fixed annoying segfault, I think<commit_after>// @file irc.cpp
// @brief Implementation of the IRC class, which implements the
//        User, Message and Chat abstract classes.
//

#include <sstream> // std::stringstream
#include "irc.h"

std::deque<std::string> Split(std::string pretext, char delim)
{
  std::deque<std::string> sans_delim;
  std::string tokens;
  std::stringstream sstream(pretext);
  while (std::getline(sstream, tokens, delim))
  {
    sans_delim.push_back(tokens);
  }
  return sans_delim;
}

//----------------------------//
// User Class Implementation. //
//----------------------------//
IRCUser::IRCUser(void)
{
  return;
}

  bool
IRCUser::Equals(User *u)
{
  return true;
}

//-------------------------------//
// Message Class Implementation. //
//-------------------------------//
  std::string
IRCMessage::GetString()
{
  return str;
}

  std::string
IRCMessage::GetFormattedString()
{
  std::string arg;
  for (auto i = argList.begin(); i != argList.end(); ++i)
  {
    arg += *i + " ";
  }
  return command + " " + arg + ":" + str + "\r\n";
}

IRCMessage::IRCMessage(std::string s)
{
  str = "";

  // We don't know if the prefix is actually present.
  int prefixEnd = -1;

  // The prefix is actually present.
  if (s.at(0) == ':')
  {
    // The end is before the first space.
    prefixEnd = s.find_first_of(' ');
    // Save the prefix. (Note: we ca further segment it later.)
    prefix = s.substr(1, prefixEnd - 1);
    if (prefix.find('!') != prefix.npos)
    {
      nickname = prefix.substr(0, prefix.find('!'));
    }
  }

  size_t trailBegin = s.find(" :");

  // Check if there is a trailing message.
  if (trailBegin != s.npos)
  {
    // Save the trail (char after colon to end of string).
    str = s.substr(trailBegin + 2, s.npos);
  }
  // We get a list of the arguments.
  argList = Split(s.substr(prefixEnd + 1, (trailBegin - prefixEnd - 1)), ' ');

  if (!argList.empty())
  {
    command = argList.at(0);
    argList.pop_front();
  }

  // Trim the \r\n
  if (str.length() > 2) {
    str = str.substr(0, str.length() - 2);
  }
}

IRCMessage::IRCMessage()
{
  str = "";
  return;
}

IRCMessage::~IRCMessage()
{
  return;
}

  IRCUser*
IRCMessage::GetUser()
{
  return new IRCUser;
}

  IRCMessage*
IRCMessage::Respond(std::string s)
{
  IRCMessage *m = new IRCMessage();
  m->str = s;
  m->command = "PRIVMSG";
  m->argList = argList;
  return m;
}

  void
IRCMessage::Update(std::string s)
{
  str = s;
}

//----------------------------//
// Chat Class Implementation. //
//----------------------------//

IRCChat::IRCChat(std::string server,
    std::string port,
    std::string nick,
    std::string password)
{
  socket = new Socket(server, port);
  socket->Send("PASS " + password + "\r\n");
  socket->Send("NICK " + nick + "\r\n");
  socket->Send("USER " + nick + " localhost servername :" + nick + "\r\n");
}

IRCChat::~IRCChat(void)
{
  delete socket;
}

  void
IRCChat::Join(std::string channel)
{
  socket->Send("JOIN " + channel + "\r\n");
}

  IRCMessage*
IRCChat::GetMessage()
{
  IRCMessage *m = NULL;
  while (!m)
  {
    m = new IRCMessage(socket->Recv());
    if (m->command == "PING")
    {
      socket->Send("PONG :" + m->str + "\r\n");
      delete m;
      m = NULL;
    }
  }

#ifdef LOGGING
  std::cout << "COMMAND: " + m->command + "\nARGUMENTS" << std::endl;
  for (auto i = m->argList.begin(); i != m->argList.end(); ++i)
  {
    std::cout << "\t" + *i << std::endl;
  }
  std::cout << "MESSAGE: " + m->str << std::endl;
  std::cout << "NICKNAME: " + m->nickname << std::endl;
  std::cout << "USERNAME: " + m->username << std::endl;
  std::cout << "HOSTNAME: " + m->hostname << std::endl;
  std::cout << "SERVERNAME: " + m->servername << std::endl;
  std::cout << "PREFIX: " + m->prefix << std::endl;
#endif

  return m;
}

  void
IRCChat::SendMessage(Message *m)
{
#ifdef LOGGING
  std::cout << m->GetFormattedString() << std::endl;
#endif
  socket->Send(m->GetFormattedString());
}

<|endoftext|>


<commit_before>#include "fileentry.h"
#include "fileentry_p.h"

#include "file.h"
#include "pluginmanager_p.h"
#include "runextensions.h"

FileEntryData::FileEntryData() :
    engine(Q_NULLPTR)
{
}

FileEntryData::FileEntryData(const FileEntryData &other) :
    QSharedData(other),
    url(other.url),
    engine(createEngine(other.url))
{
}

FileEntryData::~FileEntryData()
{
    destroyEngine(engine);
}

FileEntryData &FileEntryData::operator =(const FileEntryData &other)
{
    url = other.url;
    destroyEngine(engine);
    engine = createEngine(other.url);
    return *this;
}

AbstractDirEngine *FileEntryData::createEngine(const QUrl &url)
{
    AbstractDirEngine *engine = PluginManager::createDirEngine(url);
    if (!engine)
        engine = AbstractDirEngine::emptyEngine();
    return engine;
}

void FileEntryData::destroyEngine(AbstractDirEngine *engine)
{
    if (engine != AbstractDirEngine::emptyEngine())
        delete engine;
}

FileEntry::FileEntry() :
    d(new FileEntryData)
{
    d->engine = AbstractDirEngine::emptyEngine();
}

FileEntry::FileEntry(const QUrl &url) :
    d(new FileEntryData)
{
    d->url = url;
    d->engine = FileEntryData::createEngine(url);
}

FileEntry::FileEntry(const FileEntry &rhs) :
    d(rhs.d)
{
}

FileEntry &FileEntry::operator=(const FileEntry &rhs)
{
    if (this != &rhs)
        d.operator=(rhs.d);
    return *this;
}

FileEntry::~FileEntry()
{
}

QUrl FileEntry::url() const
{
    return d->url;
}

void FileEntry::setUrl(const QUrl &url)
{
    if (d->url == url)
        return;

    if (d->url.scheme() != url.scheme()) {
        FileEntryData::destroyEngine(d->engine);
        d->engine = FileEntryData::createEngine(url);
    }
    d->url = url;
}

ListJob FileEntry::list(QDir::Filters filters, QDir::SortFlags sortFlags)
{
    return d->engine->list(filters, sortFlags);
}

InfoListJob FileEntry::infoList(QDir::Filters filters, QDir::SortFlags sortFlags)
{
    return d->engine->infoList(filters, sortFlags);
}

FileJob FileEntry::mkdir(const QString &fileName)
{
    return d->engine->mkdir(fileName, false);
}

FileJob FileEntry::rmdir(const QString &fileName)
{
    return d->engine->rmdir(fileName, false);
}

FileJob FileEntry::mkpath(const QString &dirPath)
{
    return d->engine->mkdir(dirPath, true);
}

FileJob FileEntry::rmpath(const QString &dirPath)
{
    return d->engine->rmdir(dirPath, true);
}

FileJob FileEntry::touch(const QString &fileName)
{
    typedef void (*func)(QFutureInterface<FileResult> &future, QUrl url);
    func f = [](QFutureInterface<FileResult> &future, QUrl url) {
        File file(url);
        const bool ok = file.open(QIODevice::WriteOnly);
        future.reportResult(ok ? FileResult() : FileResult::Error::Unknown);
    };
    return QtConcurrent::run(f, absoluteUrl(this->url(), fileName));
}

FileJob FileEntry::remove(const QString &fileName)
{
    return d->engine->remove(fileName);
}

/*!
    Renames this file entry to the \a newName.
*/
FileJob FileEntry::rename(const QString &newName)
{
    return d->engine->rename(QString(), newName);
}

/*!
    Renames file or directory at \a oldName to the \a newName.
*/
FileJob FileEntry::rename(const QString &oldName, const QString &newName)
{
    return d->engine->rename(oldName, newName);
}

/*!
    Creates a link named linkName that points to this file.

    \note link can be created only on the same filesystem (if supported) and it
    is not possible to specify url to the other filesystem
*/
FileJob FileEntry::link(const QString &linkPath)
{
    Q_UNUSED(linkPath);
    Q_UNIMPLEMENTED();
    return FileJob();
}

StatJob FileEntry::stat(const QString &fileName)
{
    return d->engine->stat(fileName);
}

FileJob FileEntry::setPermissions(const QString &fileName, QFileDevice::Permissions permissions)
{
    return d->engine->setPermissions(fileName, permissions);
}

static bool doRemove(const FileInfo &info)
{
    if (info.isDir()) {
        static const auto filters = QDir::NoDotAndDotDot
                | QDir::AllEntries
                | QDir::Hidden
                | QDir::System;
        const QUrl url = info.url();
        FileEntry dir(url);
        auto f1 = dir.infoList(filters);
        // TODO: wait for next result
        f1.waitForFinished();
        FileInfoList list = f1.result();
        bool ok = true;

        foreach (const auto &info, list)
            ok &= doRemove(info);

        if (!ok)
            return false;

        auto f = dir.rmdir();
        f.waitForFinished();
        return f.result();
    }

    auto f = FileEntry(info.url()).remove();
    f.waitForFinished();
    return f.result();
}

struct Operation
{
    enum Type { None = 0x0, Mkdir, RmDir, Copy, Remove };

    Operation() : type(None) {}
    Operation(Type type, const QUrl &source, const QUrl &destination = QUrl()) :
        type(type), source(source), destination(destination)
    {}

    Type type;
    QUrl source;
    QUrl destination;
};

enum OperationFlag { None = 0x0, Remove = 0x1, Copy = 0x2 };
Q_DECLARE_FLAGS(OperationFlags, OperationFlag)

static void operationListHelper(const FileInfo &info, const QUrl &destUrl, OperationFlags type, QVector<Operation> &result)
{
    static const auto filters = QDir::NoDotAndDotDot
            | QDir::AllEntries
            | QDir::Hidden
            | QDir::System;

    if (info.isDir()) {
        if (type & OperationFlag::Copy)
            result.append(Operation(Operation::Type::Mkdir, QUrl(), destUrl));

        FileEntry entry2(info.url());
        InfoListJob job2 = entry2.infoList(filters);
        job2.waitForFinished();
        foreach (const FileInfo &info3, job2.result()) {
            const QUrl destUrl2 = FileEntry::absoluteUrl(destUrl, info3.fileName());
            operationListHelper(info3, destUrl2, type, result);
        }

        if (type & OperationFlag::Remove)
            result.append(Operation(Operation::Type::RmDir, info.url()));

    } else {
        if (type & OperationFlag::Copy) {
            result.append(Operation(Operation::Type::Copy, info.url(), destUrl));
        }
        if (type & OperationFlag::Remove)
            result.append(Operation(Operation::Type::Remove, info.url()));
    }
}

static QVector<Operation> operationList(const QUrl &sourceUrl, const QUrl &destUrl, OperationFlags type)
{
    QVector<Operation> result;

    FileEntry entry(sourceUrl);
    StatJob job = entry.stat();
    job.waitForFinished();

    operationListHelper(job.result(), destUrl, type, result);
    return result;
}

FileResult copyFile(const QUrl &sourceUrl, const QUrl &destUrl)
{
    File sourceFile(sourceUrl);
    File destFile(destUrl);
    if (!sourceFile.open(QIODevice::ReadOnly))
        return FileResult::Error::Unknown;
    if (!destFile.open(QIODevice::WriteOnly))
        return FileResult::Error::Unknown;

    while (!sourceFile.atEnd()) {
        sourceFile.waitForReadyRead();
        destFile.write(sourceFile.read(sourceFile.bytesAvailable()));
        destFile.waitForBytesWritten();
    }

    return FileResult();
}

void doWork(QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl, OperationFlags flags)
{
    const auto operations = ::operationList(sourceUrl, destUrl, flags);
    future.setProgressRange(0, operations.count());
    int count = 0;

    foreach (const Operation &op, operations) {
        FileEntry sourceEntry(op.source);
        FileEntry destEntry(op.destination);
        FileResult r;
        switch (op.type) {
        case Operation::Type::RmDir: {
            FileJob job = sourceEntry.rmdir();
            job.waitForFinished();
            r = job.result();
            break;
        } case Operation::Type::Remove: {
            FileJob job  = sourceEntry.remove();
            job.waitForFinished();
            r = job.result();
            break;
        } case Operation::Type::Copy: {
            r = copyFile(op.source, op.destination);
            Q_ASSERT(r);
            break;
        } case Operation::Type::Mkdir: {
            FileJob job = destEntry.mkdir();
            job.waitForFinished();
            r = job.result();
            break;
        } default:
            Q_UNREACHABLE();
            break;
        }

        if (!r) {
            future.reportResult(r);
            return;
        }

        future.setProgressValue(++count);
    }

    future.reportResult(FileResult());
}

FileJob FileEntry::removeRecursively(const QString &fileName)
{
    typedef void (*func)(QFutureInterface<FileResult> &future, QUrl url);
    func f = [](QFutureInterface<FileResult> &future, QUrl url) {
        doWork(future, url, QUrl(), OperationFlag::Remove);
        return;
    };
    return QtConcurrent::run(f, absoluteUrl(url(), fileName));
}

FileJob FileEntry::copy(const QUrl &destUrl)
{
    typedef void (*Handler)(QFutureInterface<FileResult> &, QUrl, QUrl);
    Handler func = [](QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl) {
        doWork(future, sourceUrl, destUrl, OperationFlag::Copy);
    };
    return QtConcurrent::run(func, absoluteUrl(url(), QString()), destUrl);
}

FileJob FileEntry::copy(const QString &fileName, const QUrl &destUrl)
{
    typedef void (*Handler)(QFutureInterface<FileResult> &, QUrl, QUrl);
    Handler func = [](QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl) {
        doWork(future, sourceUrl, destUrl, OperationFlag::Copy);
    };
    return QtConcurrent::run(func, absoluteUrl(url(), fileName), destUrl);
}

FileJob FileEntry::move(const QUrl &destUrl)
{
    typedef void (*Handler)(QFutureInterface<FileResult> &, QUrl, QUrl);
    Handler func = [](QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl) {
        OperationFlags flags(OperationFlag::Copy | OperationFlag::Remove);
        doWork(future, sourceUrl, destUrl, flags);
    };
    return QtConcurrent::run(func, absoluteUrl(url(), QString()), destUrl);
}

FileJob FileEntry::move(const QString &fileName, const QUrl &destUrl)
{
    typedef void (*Handler)(QFutureInterface<FileResult> &, QUrl, QUrl);
    Handler func = [](QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl) {
        OperationFlags flags(OperationFlag::Copy | OperationFlag::Remove);
        doWork(future, sourceUrl, destUrl, flags);
    };
    return QtConcurrent::run(func, absoluteUrl(url(), fileName), destUrl);
}

/*!
    Appends \a relativePath to the \a parentUrl's path and returns new url.
*/
QUrl FileEntry::absoluteUrl(const QUrl &parentUrl, const QString &relativePath)
{
    if (relativePath.isEmpty())
        return parentUrl;
    QUrl result = parentUrl;
    const QString path = QDir::cleanPath(result.path() + "/" + relativePath);
    result.setPath(path);
    return result;
}

AbstractDirEngine *FileEntry::engine() const
{
    return d->engine;
}
<commit_msg>Make copyFile static<commit_after>#include "fileentry.h"
#include "fileentry_p.h"

#include "file.h"
#include "pluginmanager_p.h"
#include "runextensions.h"

FileEntryData::FileEntryData() :
    engine(Q_NULLPTR)
{
}

FileEntryData::FileEntryData(const FileEntryData &other) :
    QSharedData(other),
    url(other.url),
    engine(createEngine(other.url))
{
}

FileEntryData::~FileEntryData()
{
    destroyEngine(engine);
}

FileEntryData &FileEntryData::operator =(const FileEntryData &other)
{
    url = other.url;
    destroyEngine(engine);
    engine = createEngine(other.url);
    return *this;
}

AbstractDirEngine *FileEntryData::createEngine(const QUrl &url)
{
    AbstractDirEngine *engine = PluginManager::createDirEngine(url);
    if (!engine)
        engine = AbstractDirEngine::emptyEngine();
    return engine;
}

void FileEntryData::destroyEngine(AbstractDirEngine *engine)
{
    if (engine != AbstractDirEngine::emptyEngine())
        delete engine;
}

FileEntry::FileEntry() :
    d(new FileEntryData)
{
    d->engine = AbstractDirEngine::emptyEngine();
}

FileEntry::FileEntry(const QUrl &url) :
    d(new FileEntryData)
{
    d->url = url;
    d->engine = FileEntryData::createEngine(url);
}

FileEntry::FileEntry(const FileEntry &rhs) :
    d(rhs.d)
{
}

FileEntry &FileEntry::operator=(const FileEntry &rhs)
{
    if (this != &rhs)
        d.operator=(rhs.d);
    return *this;
}

FileEntry::~FileEntry()
{
}

QUrl FileEntry::url() const
{
    return d->url;
}

void FileEntry::setUrl(const QUrl &url)
{
    if (d->url == url)
        return;

    if (d->url.scheme() != url.scheme()) {
        FileEntryData::destroyEngine(d->engine);
        d->engine = FileEntryData::createEngine(url);
    }
    d->url = url;
}

ListJob FileEntry::list(QDir::Filters filters, QDir::SortFlags sortFlags)
{
    return d->engine->list(filters, sortFlags);
}

InfoListJob FileEntry::infoList(QDir::Filters filters, QDir::SortFlags sortFlags)
{
    return d->engine->infoList(filters, sortFlags);
}

FileJob FileEntry::mkdir(const QString &fileName)
{
    return d->engine->mkdir(fileName, false);
}

FileJob FileEntry::rmdir(const QString &fileName)
{
    return d->engine->rmdir(fileName, false);
}

FileJob FileEntry::mkpath(const QString &dirPath)
{
    return d->engine->mkdir(dirPath, true);
}

FileJob FileEntry::rmpath(const QString &dirPath)
{
    return d->engine->rmdir(dirPath, true);
}

FileJob FileEntry::touch(const QString &fileName)
{
    typedef void (*func)(QFutureInterface<FileResult> &future, QUrl url);
    func f = [](QFutureInterface<FileResult> &future, QUrl url) {
        File file(url);
        const bool ok = file.open(QIODevice::WriteOnly);
        future.reportResult(ok ? FileResult() : FileResult::Error::Unknown);
    };
    return QtConcurrent::run(f, absoluteUrl(this->url(), fileName));
}

FileJob FileEntry::remove(const QString &fileName)
{
    return d->engine->remove(fileName);
}

/*!
    Renames this file entry to the \a newName.
*/
FileJob FileEntry::rename(const QString &newName)
{
    return d->engine->rename(QString(), newName);
}

/*!
    Renames file or directory at \a oldName to the \a newName.
*/
FileJob FileEntry::rename(const QString &oldName, const QString &newName)
{
    return d->engine->rename(oldName, newName);
}

/*!
    Creates a link named linkName that points to this file.

    \note link can be created only on the same filesystem (if supported) and it
    is not possible to specify url to the other filesystem
*/
FileJob FileEntry::link(const QString &linkPath)
{
    Q_UNUSED(linkPath);
    Q_UNIMPLEMENTED();
    return FileJob();
}

StatJob FileEntry::stat(const QString &fileName)
{
    return d->engine->stat(fileName);
}

FileJob FileEntry::setPermissions(const QString &fileName, QFileDevice::Permissions permissions)
{
    return d->engine->setPermissions(fileName, permissions);
}

static bool doRemove(const FileInfo &info)
{
    if (info.isDir()) {
        static const auto filters = QDir::NoDotAndDotDot
                | QDir::AllEntries
                | QDir::Hidden
                | QDir::System;
        const QUrl url = info.url();
        FileEntry dir(url);
        auto f1 = dir.infoList(filters);
        // TODO: wait for next result
        f1.waitForFinished();
        FileInfoList list = f1.result();
        bool ok = true;

        foreach (const auto &info, list)
            ok &= doRemove(info);

        if (!ok)
            return false;

        auto f = dir.rmdir();
        f.waitForFinished();
        return f.result();
    }

    auto f = FileEntry(info.url()).remove();
    f.waitForFinished();
    return f.result();
}

struct Operation
{
    enum Type { None = 0x0, Mkdir, RmDir, Copy, Remove };

    Operation() : type(None) {}
    Operation(Type type, const QUrl &source, const QUrl &destination = QUrl()) :
        type(type), source(source), destination(destination)
    {}

    Type type;
    QUrl source;
    QUrl destination;
};

enum OperationFlag { None = 0x0, Remove = 0x1, Copy = 0x2 };
Q_DECLARE_FLAGS(OperationFlags, OperationFlag)

static void operationListHelper(const FileInfo &info, const QUrl &destUrl, OperationFlags type, QVector<Operation> &result)
{
    static const auto filters = QDir::NoDotAndDotDot
            | QDir::AllEntries
            | QDir::Hidden
            | QDir::System;

    if (info.isDir()) {
        if (type & OperationFlag::Copy)
            result.append(Operation(Operation::Type::Mkdir, QUrl(), destUrl));

        FileEntry entry2(info.url());
        InfoListJob job2 = entry2.infoList(filters);
        job2.waitForFinished();
        foreach (const FileInfo &info3, job2.result()) {
            const QUrl destUrl2 = FileEntry::absoluteUrl(destUrl, info3.fileName());
            operationListHelper(info3, destUrl2, type, result);
        }

        if (type & OperationFlag::Remove)
            result.append(Operation(Operation::Type::RmDir, info.url()));

    } else {
        if (type & OperationFlag::Copy) {
            result.append(Operation(Operation::Type::Copy, info.url(), destUrl));
        }
        if (type & OperationFlag::Remove)
            result.append(Operation(Operation::Type::Remove, info.url()));
    }
}

static QVector<Operation> operationList(const QUrl &sourceUrl, const QUrl &destUrl, OperationFlags type)
{
    QVector<Operation> result;

    FileEntry entry(sourceUrl);
    StatJob job = entry.stat();
    job.waitForFinished();

    operationListHelper(job.result(), destUrl, type, result);
    return result;
}

static FileResult copyFile(const QUrl &sourceUrl, const QUrl &destUrl)
{
    File sourceFile(sourceUrl);
    File destFile(destUrl);
    if (!sourceFile.open(QIODevice::ReadOnly))
        return FileResult::Error::Unknown;
    if (!destFile.open(QIODevice::WriteOnly))
        return FileResult::Error::Unknown;

    while (!sourceFile.atEnd()) {
        sourceFile.waitForReadyRead();
        destFile.write(sourceFile.read(sourceFile.bytesAvailable()));
        destFile.waitForBytesWritten();
    }

    return FileResult();
}

void doWork(QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl, OperationFlags flags)
{
    const auto operations = ::operationList(sourceUrl, destUrl, flags);
    future.setProgressRange(0, operations.count());
    int count = 0;

    foreach (const Operation &op, operations) {
        FileEntry sourceEntry(op.source);
        FileEntry destEntry(op.destination);
        FileResult r;
        switch (op.type) {
        case Operation::Type::RmDir: {
            FileJob job = sourceEntry.rmdir();
            job.waitForFinished();
            r = job.result();
            break;
        } case Operation::Type::Remove: {
            FileJob job  = sourceEntry.remove();
            job.waitForFinished();
            r = job.result();
            break;
        } case Operation::Type::Copy: {
            r = copyFile(op.source, op.destination);
            Q_ASSERT(r);
            break;
        } case Operation::Type::Mkdir: {
            FileJob job = destEntry.mkdir();
            job.waitForFinished();
            r = job.result();
            break;
        } default:
            Q_UNREACHABLE();
            break;
        }

        if (!r) {
            future.reportResult(r);
            return;
        }

        future.setProgressValue(++count);
    }

    future.reportResult(FileResult());
}

FileJob FileEntry::removeRecursively(const QString &fileName)
{
    typedef void (*func)(QFutureInterface<FileResult> &future, QUrl url);
    func f = [](QFutureInterface<FileResult> &future, QUrl url) {
        doWork(future, url, QUrl(), OperationFlag::Remove);
        return;
    };
    return QtConcurrent::run(f, absoluteUrl(url(), fileName));
}

FileJob FileEntry::copy(const QUrl &destUrl)
{
    typedef void (*Handler)(QFutureInterface<FileResult> &, QUrl, QUrl);
    Handler func = [](QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl) {
        doWork(future, sourceUrl, destUrl, OperationFlag::Copy);
    };
    return QtConcurrent::run(func, absoluteUrl(url(), QString()), destUrl);
}

FileJob FileEntry::copy(const QString &fileName, const QUrl &destUrl)
{
    typedef void (*Handler)(QFutureInterface<FileResult> &, QUrl, QUrl);
    Handler func = [](QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl) {
        doWork(future, sourceUrl, destUrl, OperationFlag::Copy);
    };
    return QtConcurrent::run(func, absoluteUrl(url(), fileName), destUrl);
}

FileJob FileEntry::move(const QUrl &destUrl)
{
    typedef void (*Handler)(QFutureInterface<FileResult> &, QUrl, QUrl);
    Handler func = [](QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl) {
        OperationFlags flags(OperationFlag::Copy | OperationFlag::Remove);
        doWork(future, sourceUrl, destUrl, flags);
    };
    return QtConcurrent::run(func, absoluteUrl(url(), QString()), destUrl);
}

FileJob FileEntry::move(const QString &fileName, const QUrl &destUrl)
{
    typedef void (*Handler)(QFutureInterface<FileResult> &, QUrl, QUrl);
    Handler func = [](QFutureInterface<FileResult> &future, QUrl sourceUrl, QUrl destUrl) {
        OperationFlags flags(OperationFlag::Copy | OperationFlag::Remove);
        doWork(future, sourceUrl, destUrl, flags);
    };
    return QtConcurrent::run(func, absoluteUrl(url(), fileName), destUrl);
}

/*!
    Appends \a relativePath to the \a parentUrl's path and returns new url.
*/
QUrl FileEntry::absoluteUrl(const QUrl &parentUrl, const QString &relativePath)
{
    if (relativePath.isEmpty())
        return parentUrl;
    QUrl result = parentUrl;
    const QString path = QDir::cleanPath(result.path() + "/" + relativePath);
    result.setPath(path);
    return result;
}

AbstractDirEngine *FileEntry::engine() const
{
    return d->engine;
}
<|endoftext|>


<commit_before>/*
 * molgetter.h
 *
 *  Created on: Jun 5, 2014
 *      Author: dkoes
 */
#include "molgetter.h"
#include "parse_pdbqt.h"
#include "parsing.h"
#include <openbabel/mol.h>
#include <openbabel/obconversion.h>
#include <boost/archive/binary_iarchive.hpp>
#include "SminaConverter.h"

//setup for reading from fname
void MolGetter::setInputFile(const std::string& fname)
{
	if (fname.size() > 0) //zer if no_lig
	{
		lpath = path(fname);
		if (lpath.extension() == ".pdbqt")
		{
			//built-in pdbqt parsing that respects rotabable bonds in pdbqt
			type = PDBQT;
			pdbqtdone = false;
		}
		else if (infile.open(lpath, ".smina", true)) //smina always gzipped
		{
			type = SMINA;
		}
		else //openbabel
		{
			type = OB;
			//clear in case we had previous vile
			infileopener.clear();
			infileopener.openForInput(conv, fname);
			VINA_CHECK(conv.SetOutFormat("PDBQT"));
		}
	}
}

//initialize model to initm and add next molecule
//return false if no molecule available;
bool MolGetter::readMoleculeIntoModel(model &m)
{
	//reinit the model
	m = initm;
	switch (type)
	{
	case SMINA:
		{
		parsing_struct p;
		context c;
		unsigned torsdof = 0;
		if (!infile)
			return false;
		try
		{
			boost::archive::binary_iarchive serialin(infile,
					boost::archive::no_header | boost::archive::no_tracking);
			serialin >> torsdof;
			serialin >> p;
			serialin >> c;

			non_rigid_parsed nr;
			postprocess_ligand(nr, p, c, torsdof);
			VINA_CHECK(nr.atoms_atoms_bonds.dim() == nr.atoms.size());

			pdbqt_initializer tmp;
			tmp.initialize_from_nrp(nr, c, true);
			tmp.initialize(nr.mobility_matrix());

			if(c.sdftext.valid())
			{
				//set name
				m.set_name(c.sdftext.name);
			}

			m.append(tmp.m);
			return true;
		}
		catch (boost::archive::archive_exception& e)
		{
			return false;
		}
	}
		break;
	case PDBQT:
		{
		if (pdbqtdone)
			return false; //can only read one
		m.append(parse_ligand_pdbqt(lpath));
		pdbqtdone = true;
		return true;
	}
		break;
	case OB:
		{
		OpenBabel::OBMol mol;
		while (conv.Read(&mol)) //will return after first success
		{
			std::string name = mol.GetTitle();
			m.set_name(name);
			try
			{
				parsing_struct p;
				context c;
				unsigned torsdof = SminaConverter::convertParsing(mol, p, c, add_hydrogens);
				non_rigid_parsed nr;
				postprocess_ligand(nr, p, c, torsdof);
				VINA_CHECK(nr.atoms_atoms_bonds.dim() == nr.atoms.size());

				pdbqt_initializer tmp;
				tmp.initialize_from_nrp(nr, c, true);
				tmp.initialize(nr.mobility_matrix());

				m.append(tmp.m);
				return true;
			}
			catch (parse_error& e)
			{
				std::cerr << "\n\nParse error with molecule "
						<< mol.GetTitle() << " in file \""
						<< e.file.string() << "\": " << e.reason
						<< '\n';
				continue;
			}
		}
		return false; //no valid molecules read
	}
		break;
	}
	return false; //shouldn't get here
}
<commit_msg>process only the largest connectd component in a provided ligand<commit_after>/*
 * molgetter.h
 *
 *  Created on: Jun 5, 2014
 *      Author: dkoes
 */
#include "molgetter.h"
#include "parse_pdbqt.h"
#include "parsing.h"
#include <openbabel/mol.h>
#include <openbabel/obconversion.h>
#include <boost/archive/binary_iarchive.hpp>
#include "SminaConverter.h"

//setup for reading from fname
void MolGetter::setInputFile(const std::string& fname)
{
	if (fname.size() > 0) //zer if no_lig
	{
		lpath = path(fname);
		if (lpath.extension() == ".pdbqt")
		{
			//built-in pdbqt parsing that respects rotabable bonds in pdbqt
			type = PDBQT;
			pdbqtdone = false;
		}
		else if (infile.open(lpath, ".smina", true)) //smina always gzipped
		{
			type = SMINA;
		}
		else //openbabel
		{
			type = OB;
			//clear in case we had previous vile
			infileopener.clear();
			infileopener.openForInput(conv, fname);
			VINA_CHECK(conv.SetOutFormat("PDBQT"));
		}
	}
}

//initialize model to initm and add next molecule
//return false if no molecule available;
bool MolGetter::readMoleculeIntoModel(model &m)
{
	//reinit the model
	m = initm;
	switch (type)
	{
	case SMINA:
		{
		parsing_struct p;
		context c;
		unsigned torsdof = 0;
		if (!infile)
			return false;
		try
		{
			boost::archive::binary_iarchive serialin(infile,
					boost::archive::no_header | boost::archive::no_tracking);
			serialin >> torsdof;
			serialin >> p;
			serialin >> c;

			non_rigid_parsed nr;
			postprocess_ligand(nr, p, c, torsdof);
			VINA_CHECK(nr.atoms_atoms_bonds.dim() == nr.atoms.size());

			pdbqt_initializer tmp;
			tmp.initialize_from_nrp(nr, c, true);
			tmp.initialize(nr.mobility_matrix());

			if(c.sdftext.valid())
			{
				//set name
				m.set_name(c.sdftext.name);
			}

			m.append(tmp.m);
			return true;
		}
		catch (boost::archive::archive_exception& e)
		{
			return false;
		}
	}
		break;
	case PDBQT:
		{
		if (pdbqtdone)
			return false; //can only read one
		m.append(parse_ligand_pdbqt(lpath));
		pdbqtdone = true;
		return true;
	}
		break;
	case OB:
		{
		OpenBabel::OBMol mol;
		while (conv.Read(&mol)) //will return after first success
		{
			std::string name = mol.GetTitle();
			mol.StripSalts();
			m.set_name(name);
			try
			{
				parsing_struct p;
				context c;
				unsigned torsdof = SminaConverter::convertParsing(mol, p, c, add_hydrogens);
				non_rigid_parsed nr;
				postprocess_ligand(nr, p, c, torsdof);
				VINA_CHECK(nr.atoms_atoms_bonds.dim() == nr.atoms.size());

				pdbqt_initializer tmp;
				tmp.initialize_from_nrp(nr, c, true);
				tmp.initialize(nr.mobility_matrix());

				m.append(tmp.m);
				return true;
			}
			catch (parse_error& e)
			{
				std::cerr << "\n\nParse error with molecule "
						<< mol.GetTitle() << " in file \""
						<< e.file.string() << "\": " << e.reason
						<< '\n';
				continue;
			}
		}
		return false; //no valid molecules read
	}
		break;
	}
	return false; //shouldn't get here
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_BILINEARFORM_EXT
#define MFEM_BILINEARFORM_EXT

#include "../config/config.hpp"
#include "fespace.hpp"
#include "../general/device.hpp"

namespace mfem
{

class BilinearForm;
class MixedBilinearForm;

/// Class extending the BilinearForm class to support different AssemblyLevels.
/**  FA - Full Assembly
     PA - Partial Assembly
     EA - Element Assembly
     MF - Matrix Free
*/
class BilinearFormExtension : public Operator
{
protected:
   BilinearForm *a; ///< Not owned

public:
   BilinearFormExtension(BilinearForm *form);

   virtual MemoryClass GetMemoryClass() const
   { return Device::GetDeviceMemoryClass(); }

   /// Get the finite element space prolongation matrix
   virtual const Operator *GetProlongation() const;

   /// Get the finite element space restriction matrix
   virtual const Operator *GetRestriction() const;

   /// Assemble at the level given for the BilinearFormExtension subclass
   virtual void Assemble() = 0;

   virtual void AssembleDiagonal(Vector &diag) const
   {
      MFEM_ABORT("AssembleDiagonal not implemented for this assembly level!");
   }

   virtual void FormSystemMatrix(const Array<int> &ess_tdof_list,
                                 OperatorHandle &A) = 0;
   virtual void FormLinearSystem(const Array<int> &ess_tdof_list,
                                 Vector &x, Vector &b,
                                 OperatorHandle &A, Vector &X, Vector &B,
                                 int copy_interior = 0) = 0;
   virtual void Update() = 0;
};

/// Data and methods for partially-assembled bilinear forms
class PABilinearFormExtension : public BilinearFormExtension
{
protected:
   const FiniteElementSpace *trialFes, *testFes; // Not owned
   mutable Vector localX, localY;
   mutable Vector faceIntX, faceIntY;
   mutable Vector faceBdrX, faceBdrY;
   const Operator *elem_restrict; // Not owned
   const Operator *int_face_restrict_lex; // Not owned
   const Operator *bdr_face_restrict_lex; // Not owned

public:
   PABilinearFormExtension(BilinearForm*);

   void Assemble();
   void AssembleDiagonal(Vector &diag) const;
   void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A);
   void FormLinearSystem(const Array<int> &ess_tdof_list,
                         Vector &x, Vector &b,
                         OperatorHandle &A, Vector &X, Vector &B,
                         int copy_interior = 0);
   void Mult(const Vector &x, Vector &y) const;
   void MultTranspose(const Vector &x, Vector &y) const;
   void Update();

protected:
   void SetupRestrictionOperators(const L2FaceValues m);
};

/// Data and methods for element-assembled bilinear forms
class EABilinearFormExtension : public PABilinearFormExtension
{
protected:
   int ne;
   int elemDofs;
   // The element matrices are stored row major
   Vector ea_data;
   int nf_int, nf_bdr;
   int faceDofs;
   Vector ea_data_int, ea_data_ext, ea_data_bdr;
   bool factorize_face_terms;

public:
   EABilinearFormExtension(BilinearForm *form);

   void Assemble();
   void Mult(const Vector &x, Vector &y) const;
   void MultTranspose(const Vector &x, Vector &y) const;
};

/// Data and methods for fully-assembled bilinear forms
class FABilinearFormExtension : public EABilinearFormExtension
{
private:
   SparseMatrix mat;
   /// face_mat handles parallelism for DG face terms.
   SparseMatrix face_mat;
   bool use_face_mat;

public:
   FABilinearFormExtension(BilinearForm *form);

   void Assemble();
   void Mult(const Vector &x, Vector &y) const;
   void MultTranspose(const Vector &x, Vector &y) const;
};

/// Data and methods for matrix-free bilinear forms NOT YET IMPLEMENTED.
class MFBilinearFormExtension : public BilinearFormExtension
{
protected:
   const FiniteElementSpace *trialFes, *testFes; // Not owned
   mutable Vector localX, localY;
   mutable Vector faceIntX, faceIntY;
   mutable Vector faceBdrX, faceBdrY;
   const Operator *elem_restrict; // Not owned
   const Operator *int_face_restrict_lex; // Not owned
   const Operator *bdr_face_restrict_lex; // Not owned

public:
   MFBilinearFormExtension(BilinearForm *form);

   void Assemble();
   void AssembleDiagonal(Vector &diag) const;
   void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A);
   void FormLinearSystem(const Array<int> &ess_tdof_list,
                         Vector &x, Vector &b,
                         OperatorHandle &A, Vector &X, Vector &B,
                         int copy_interior = 0);
   void Mult(const Vector &x, Vector &y) const;
   void MultTranspose(const Vector &x, Vector &y) const;
   void Update();
};

/// Class extending the MixedBilinearForm class to support different AssemblyLevels.
/**  FA - Full Assembly
     PA - Partial Assembly
     EA - Element Assembly
     MF - Matrix Free
*/
class MixedBilinearFormExtension : public Operator
{
protected:
   MixedBilinearForm *a; ///< Not owned

public:
   MixedBilinearFormExtension(MixedBilinearForm *form);

   virtual MemoryClass GetMemoryClass() const
   { return Device::GetMemoryClass(); }

   /// Get the finite element space prolongation matrix
   virtual const Operator *GetProlongation() const;

   /// Get the finite element space restriction matrix
   virtual const Operator *GetRestriction() const;

   /// Get the output finite element space restriction matrix
   virtual const Operator *GetOutputProlongation() const;

   /// Get the output finite element space restriction matrix
   virtual const Operator *GetOutputRestriction() const;

   virtual void Assemble() = 0;
   virtual void FormRectangularSystemOperator(const Array<int> &trial_tdof_list,
                                              const Array<int> &test_tdof_list,
                                              OperatorHandle &A) = 0;
   virtual void FormRectangularLinearSystem(const Array<int> &trial_tdof_list,
                                            const Array<int> &test_tdof_list,
                                            Vector &x, Vector &b,
                                            OperatorHandle &A, Vector &X, Vector &B) = 0;

   virtual void AddMult(const Vector &x, Vector &y, const double c=1.0) const = 0;
   virtual void AddMultTranspose(const Vector &x, Vector &y,
                                 const double c=1.0) const = 0;

   virtual void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const = 0;

   virtual void Update() = 0;
};

/// Data and methods for partially-assembled mixed bilinear forms
class PAMixedBilinearFormExtension : public MixedBilinearFormExtension
{
protected:
   const FiniteElementSpace *trialFes, *testFes; // Not owned
   mutable Vector localTrial, localTest, tempY;
   const Operator *elem_restrict_trial; // Not owned
   const Operator *elem_restrict_test;  // Not owned
private:
   /// Helper function to set up inputs/outputs for Mult or MultTranspose
   void SetupMultInputs(const Operator *elem_restrict_x,
                        const Vector &x, Vector &localX,
                        const Operator *elem_restrict_y,
                        Vector &y, Vector &localY, const double c) const;

public:
   PAMixedBilinearFormExtension(MixedBilinearForm *form);

   /// Partial assembly of all internal integrators
   void Assemble();
   /**
      @brief Setup OperatorHandle A to contain constrained linear operator

      OperatorHandle A contains matrix-free constrained operator formed for RAP
      system where ess_tdof_list are in trial space and eliminated from
      "columns" of A.
   */
   void FormRectangularSystemOperator(const Array<int> &trial_tdof_list,
                                      const Array<int> &test_tdof_list,
                                      OperatorHandle &A);
   /**
      Setup OperatorHandle A to contain constrained linear operator and
      eliminate columns corresponding to essential dofs from system,
      updating RHS B vector with the results.
   */
   void FormRectangularLinearSystem(const Array<int> &trial_tdof_list,
                                    const Array<int> &test_tdof_list,
                                    Vector &x, Vector &b,
                                    OperatorHandle &A, Vector &X, Vector &B);
   /// y = A*x
   void Mult(const Vector &x, Vector &y) const;
   /// y += c*A*x
   void AddMult(const Vector &x, Vector &y, const double c=1.0) const;
   /// y = A^T*x
   void MultTranspose(const Vector &x, Vector &y) const;
   /// y += c*A^T*x
   void AddMultTranspose(const Vector &x, Vector &y, const double c=1.0) const;
   /// Assemble the diagonal of ADA^T for a diagonal vector D.
   void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const;

   /// Update internals for when a new MixedBilinearForm is given to this class
   void Update();
};

}

#endif
<commit_msg>Improve doc.<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_BILINEARFORM_EXT
#define MFEM_BILINEARFORM_EXT

#include "../config/config.hpp"
#include "fespace.hpp"
#include "../general/device.hpp"

namespace mfem
{

class BilinearForm;
class MixedBilinearForm;

/// Class extending the BilinearForm class to support different AssemblyLevels.
/**  FA - Full Assembly
     PA - Partial Assembly
     EA - Element Assembly
     MF - Matrix Free
*/
class BilinearFormExtension : public Operator
{
protected:
   BilinearForm *a; ///< Not owned

public:
   BilinearFormExtension(BilinearForm *form);

   virtual MemoryClass GetMemoryClass() const
   { return Device::GetDeviceMemoryClass(); }

   /// Get the finite element space prolongation matrix
   virtual const Operator *GetProlongation() const;

   /// Get the finite element space restriction matrix
   virtual const Operator *GetRestriction() const;

   /// Assemble at the level given for the BilinearFormExtension subclass
   virtual void Assemble() = 0;

   virtual void AssembleDiagonal(Vector &diag) const
   {
      MFEM_ABORT("AssembleDiagonal not implemented for this assembly level!");
   }

   virtual void FormSystemMatrix(const Array<int> &ess_tdof_list,
                                 OperatorHandle &A) = 0;
   virtual void FormLinearSystem(const Array<int> &ess_tdof_list,
                                 Vector &x, Vector &b,
                                 OperatorHandle &A, Vector &X, Vector &B,
                                 int copy_interior = 0) = 0;
   virtual void Update() = 0;
};

/// Data and methods for partially-assembled bilinear forms
class PABilinearFormExtension : public BilinearFormExtension
{
protected:
   const FiniteElementSpace *trialFes, *testFes; // Not owned
   mutable Vector localX, localY;
   mutable Vector faceIntX, faceIntY;
   mutable Vector faceBdrX, faceBdrY;
   const Operator *elem_restrict; // Not owned
   const Operator *int_face_restrict_lex; // Not owned
   const Operator *bdr_face_restrict_lex; // Not owned

public:
   PABilinearFormExtension(BilinearForm*);

   void Assemble();
   void AssembleDiagonal(Vector &diag) const;
   void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A);
   void FormLinearSystem(const Array<int> &ess_tdof_list,
                         Vector &x, Vector &b,
                         OperatorHandle &A, Vector &X, Vector &B,
                         int copy_interior = 0);
   void Mult(const Vector &x, Vector &y) const;
   void MultTranspose(const Vector &x, Vector &y) const;
   void Update();

protected:
   void SetupRestrictionOperators(const L2FaceValues m);
};

/// Data and methods for element-assembled bilinear forms
class EABilinearFormExtension : public PABilinearFormExtension
{
protected:
   int ne;
   int elemDofs;
   // The element matrices are stored row major
   Vector ea_data;
   int nf_int, nf_bdr;
   int faceDofs;
   Vector ea_data_int, ea_data_ext, ea_data_bdr;
   bool factorize_face_terms;

public:
   EABilinearFormExtension(BilinearForm *form);

   void Assemble();
   void Mult(const Vector &x, Vector &y) const;
   void MultTranspose(const Vector &x, Vector &y) const;
};

/// Data and methods for fully-assembled bilinear forms
class FABilinearFormExtension : public EABilinearFormExtension
{
private:
   SparseMatrix mat;
   /// face_mat handles parallelism for DG face terms.
   SparseMatrix face_mat;
   bool use_face_mat;

public:
   FABilinearFormExtension(BilinearForm *form);

   void Assemble();
   void Mult(const Vector &x, Vector &y) const;
   void MultTranspose(const Vector &x, Vector &y) const;
};

/// Data and methods for matrix-free bilinear forms
class MFBilinearFormExtension : public BilinearFormExtension
{
protected:
   const FiniteElementSpace *trialFes, *testFes; // Not owned
   mutable Vector localX, localY;
   mutable Vector faceIntX, faceIntY;
   mutable Vector faceBdrX, faceBdrY;
   const Operator *elem_restrict; // Not owned
   const Operator *int_face_restrict_lex; // Not owned
   const Operator *bdr_face_restrict_lex; // Not owned

public:
   MFBilinearFormExtension(BilinearForm *form);

   void Assemble();
   void AssembleDiagonal(Vector &diag) const;
   void FormSystemMatrix(const Array<int> &ess_tdof_list, OperatorHandle &A);
   void FormLinearSystem(const Array<int> &ess_tdof_list,
                         Vector &x, Vector &b,
                         OperatorHandle &A, Vector &X, Vector &B,
                         int copy_interior = 0);
   void Mult(const Vector &x, Vector &y) const;
   void MultTranspose(const Vector &x, Vector &y) const;
   void Update();
};

/// Class extending the MixedBilinearForm class to support different AssemblyLevels.
/**  FA - Full Assembly
     PA - Partial Assembly
     EA - Element Assembly
     MF - Matrix Free
*/
class MixedBilinearFormExtension : public Operator
{
protected:
   MixedBilinearForm *a; ///< Not owned

public:
   MixedBilinearFormExtension(MixedBilinearForm *form);

   virtual MemoryClass GetMemoryClass() const
   { return Device::GetMemoryClass(); }

   /// Get the finite element space prolongation matrix
   virtual const Operator *GetProlongation() const;

   /// Get the finite element space restriction matrix
   virtual const Operator *GetRestriction() const;

   /// Get the output finite element space restriction matrix
   virtual const Operator *GetOutputProlongation() const;

   /// Get the output finite element space restriction matrix
   virtual const Operator *GetOutputRestriction() const;

   virtual void Assemble() = 0;
   virtual void FormRectangularSystemOperator(const Array<int> &trial_tdof_list,
                                              const Array<int> &test_tdof_list,
                                              OperatorHandle &A) = 0;
   virtual void FormRectangularLinearSystem(const Array<int> &trial_tdof_list,
                                            const Array<int> &test_tdof_list,
                                            Vector &x, Vector &b,
                                            OperatorHandle &A, Vector &X, Vector &B) = 0;

   virtual void AddMult(const Vector &x, Vector &y, const double c=1.0) const = 0;
   virtual void AddMultTranspose(const Vector &x, Vector &y,
                                 const double c=1.0) const = 0;

   virtual void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const = 0;

   virtual void Update() = 0;
};

/// Data and methods for partially-assembled mixed bilinear forms
class PAMixedBilinearFormExtension : public MixedBilinearFormExtension
{
protected:
   const FiniteElementSpace *trialFes, *testFes; // Not owned
   mutable Vector localTrial, localTest, tempY;
   const Operator *elem_restrict_trial; // Not owned
   const Operator *elem_restrict_test;  // Not owned
private:
   /// Helper function to set up inputs/outputs for Mult or MultTranspose
   void SetupMultInputs(const Operator *elem_restrict_x,
                        const Vector &x, Vector &localX,
                        const Operator *elem_restrict_y,
                        Vector &y, Vector &localY, const double c) const;

public:
   PAMixedBilinearFormExtension(MixedBilinearForm *form);

   /// Partial assembly of all internal integrators
   void Assemble();
   /**
      @brief Setup OperatorHandle A to contain constrained linear operator

      OperatorHandle A contains matrix-free constrained operator formed for RAP
      system where ess_tdof_list are in trial space and eliminated from
      "columns" of A.
   */
   void FormRectangularSystemOperator(const Array<int> &trial_tdof_list,
                                      const Array<int> &test_tdof_list,
                                      OperatorHandle &A);
   /**
      Setup OperatorHandle A to contain constrained linear operator and
      eliminate columns corresponding to essential dofs from system,
      updating RHS B vector with the results.
   */
   void FormRectangularLinearSystem(const Array<int> &trial_tdof_list,
                                    const Array<int> &test_tdof_list,
                                    Vector &x, Vector &b,
                                    OperatorHandle &A, Vector &X, Vector &B);
   /// y = A*x
   void Mult(const Vector &x, Vector &y) const;
   /// y += c*A*x
   void AddMult(const Vector &x, Vector &y, const double c=1.0) const;
   /// y = A^T*x
   void MultTranspose(const Vector &x, Vector &y) const;
   /// y += c*A^T*x
   void AddMultTranspose(const Vector &x, Vector &y, const double c=1.0) const;
   /// Assemble the diagonal of ADA^T for a diagonal vector D.
   void AssembleDiagonal_ADAt(const Vector &D, Vector &diag) const;

   /// Update internals for when a new MixedBilinearForm is given to this class
   void Update();
};

}

#endif
<|endoftext|>


<commit_before>// ffmpeg player output (portaudio)
// part of MusicPlayer, https://github.com/albertz/music-player
// Copyright (c) 2012, Albert Zeyer, www.az2000.de
// All rights reserved.
// This code is under the 2-clause BSD license, see License.txt in the root directory of this project.

#include "ffmpeg.h"
#include "PyUtils.h"

#include <portaudio.h>
#include <boost/bind.hpp>
#include <boost/atomic.hpp>

#ifdef __APPLE__
// PortAudio specific Mac stuff
#include "pa_mac_core.h"
#endif

// For setting the thread priority to realtime on MacOSX.
#ifdef __APPLE__
#include <mach/mach_init.h>
#include <mach/thread_policy.h>
#include <mach/thread_act.h> // the doc says mach/sched.h but that seems outdated...
#include <pthread.h>
#include <mach/mach_error.h>
#include <mach/mach_time.h>
#endif
static void setRealtime(double dutyCicleMs);

/*
The implementation with the PortAudio callback was there first.
For testing, I implemented also the blocking PortAudio interface.
I had some issues which small hiccups in the audio output -
maybe the blocking PortAudio implementation can avoid them better.
For the callback, we need to minimize the locks - or better, avoid
them fully. I'm not sure it is good to depend on thread context
switches in case it is locked. This however needs some heavy redesign.
*/
#define USE_PORTAUDIO_CALLBACK 1

int initPlayerOutput() {
	PaError ret = Pa_Initialize();
	if(ret != paNoError)
		Py_FatalError("PortAudio init failed");
	return 0;
}

void reinitPlayerOutput() {
	if(Pa_Terminate() != paNoError)
		printf("Warning: Pa_Terminate() failed\n");
	initPlayerOutput();
}

template<typename T> struct OutPaSampleFormat{};
template<> struct OutPaSampleFormat<int16_t> {
	static const PaSampleFormat format = paInt16;
};
template<> struct OutPaSampleFormat<float32_t> {
	static const PaSampleFormat format = paFloat32;
};

#define LATENCY_IN_MS 100

struct PlayerObject::OutStream {
	PlayerObject* const player;
	PaStream* stream;
	boost::atomic<bool> needRealtimeReset; // PortAudio callback thread must set itself to realtime
	boost::atomic<bool> setThreadName;

	OutStream(PlayerObject* p) : player(p), stream(NULL), needRealtimeReset(false) {
		mlock(this, sizeof(*this));
	}
	~OutStream() { close(); }

#if USE_PORTAUDIO_CALLBACK
	static int paStreamCallback(
		const void *input, void *output,
		unsigned long frameCount,
		const PaStreamCallbackTimeInfo* timeInfo,
		PaStreamCallbackFlags statusFlags,
		void *userData )
	{
		OutStream* outStream = (OutStream*) userData;
		PlayerObject* player = outStream->player;

		if(outStream->needRealtimeReset.exchange(false))
			setRealtime(1000.0 * frameCount / player->outSamplerate);

		if(outStream->setThreadName.exchange(false))
			setCurThreadName("audio callback");

		if(statusFlags & paOutputUnderflow)
			printf("audio: paOutputUnderflow\n");
		if(statusFlags & paOutputOverflow)
			printf("audio: paOutputOverflow\n");

		// We must not hold the PyGIL here!
		// Also no need to hold the player lock, all is safe!

		player->readOutStream((OUTSAMPLE_t*) output, frameCount * outStream->player->outNumChannels, NULL);
		return paContinue;
	}
#else
	PyThread audioThread;
	void audioThreadProc(PyMutex& threadLock, bool& stopSignal) {
		while(true) {
			{
				PyScopedLock l(threadLock);
				if(stopSignal) return;
			}

			if(needRealtimeReset) {
				needRealtimeReset = false;
				setRealtime();
			}

			OUTSAMPLE_t buffer[48 * 2 * 10]; // 10ms stereo in 48khz
			size_t frameCount = 0;
			{
				PyScopedLock lock(player->lock);
				if(stopSignal) return;
				player->readOutStream(buffer, sizeof(buffer)/sizeof(OUTSAMPLE_t), NULL);
				frameCount = sizeof(buffer)/sizeof(OUTSAMPLE_t) / player->outNumChannels;
			}

			PaError ret = Pa_WriteStream(stream, buffer, frameCount);
			if(ret == paOutputUnderflowed)
				printf("warning: paOutputUnderflowed\n");
			else if(ret != paNoError) {
				printf("Pa_WriteStream error %i (%s)\n", ret, Pa_GetErrorText(ret));
				// sleep half a second to avoid spamming
				for(int i = 0; i < 50; ++i) {
					usleep(10 * 1000);
					PyScopedLock l(threadLock);
					if(stopSignal) return;
				}
			}
		}
	}
#endif

	bool open() {
		if(stream) close();
		assert(stream == NULL);

		// For reference:
		// Mixxx code: http://bazaar.launchpad.net/~mixxxdevelopers/mixxx/trunk/view/head:/mixxx/src/sounddeviceportaudio.cpp

		PaStreamParameters outputParameters;

#if defined(__APPLE__)
		PaMacCoreStreamInfo macInfo;
		PaMacCore_SetupStreamInfo( &macInfo,
			paMacCorePlayNice | paMacCorePro );
		outputParameters.hostApiSpecificStreamInfo = &macInfo;
#elif defined(__LINUX__)
		// TODO: if we have PaAlsa_EnableRealtimeScheduling in portaudio,
		// we can call that to enable RT priority with ALSA.
		// We could check dynamically via dsym.
		outputParameters.hostApiSpecificStreamInfo = NULL;
#else
		outputParameters.hostApiSpecificStreamInfo = NULL;
#endif

		outputParameters.device = Pa_GetDefaultOutputDevice();
		if (outputParameters.device == paNoDevice) {
			PyScopedGIL gil;
			PyErr_SetString(PyExc_RuntimeError, "Pa_GetDefaultOutputDevice didn't returned a device");
			return false;
		}
		outputParameters.channelCount = player->outNumChannels;
		outputParameters.sampleFormat = OutPaSampleFormat<OUTSAMPLE_t>::format;

		//unsigned long bufferSize = (player->outSamplerate * player->outNumChannels / 1000) * LATENCY_IN_MS / 4;
		unsigned long bufferSize = paFramesPerBufferUnspecified; // support any buffer size
		if(bufferSize == paFramesPerBufferUnspecified)
			outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
		else
			outputParameters.suggestedLatency = LATENCY_IN_MS / 1000.0;

		// Note about framesPerBuffer:
		// Earlier, we used (2048 * 5 * OUTSAMPLEBYTELEN) which caused
		// some random more or less rare cracking noises.
		// See here: https://github.com/albertz/music-player/issues/35
		// This doesn't seem to happen with paFramesPerBufferUnspecified.

		PaError ret = Pa_OpenStream(
			&stream,
			NULL, // no input
			&outputParameters,
			player->outSamplerate, // sampleRate
			bufferSize,
			paClipOff | paDitherOff,
#if USE_PORTAUDIO_CALLBACK
			&paStreamCallback,
#else
			NULL,
#endif
			this //void *userData
			);

		if(ret != paNoError) {
			{
				PyScopedGIL gil;
				PyErr_Format(PyExc_RuntimeError, "Pa_OpenStream failed: (err %i) %s", ret, Pa_GetErrorText(ret));
			}
			if(stream)
				close();
			return false;
		}

		needRealtimeReset = true;
		setThreadName = true;
		Pa_StartStream(stream);

#if !USE_PORTAUDIO_CALLBACK
		audioThread.func = boost::bind(&OutStream::audioThreadProc, this, _1, _2);
		audioThread.start();
#endif
		return true;
	}

	void close() {
		if(this->stream == NULL) return;
		// we expect that we have the player lock here.
		// reset fader.
		player->fader.change(0,0);
		// we must release the player lock so that any thread-join can be done.
		PaStream* stream = NULL;
		std::swap(stream, this->stream);
		PyScopedUnlock unlock(player->lock);
#if !USE_PORTAUDIO_CALLBACK
		audioThread.stop();
#endif
		Pa_CloseStream(stream);
	}

	bool isOpen() const { return stream != NULL; }

};

int PlayerObject::setPlaying(bool playing) {
	PlayerObject* player = this;
	bool oldplayingstate = player->playing;

	if(oldplayingstate != playing)
		outOfSync = true;

	PyScopedGIL gil;
	{
		PyScopedGIUnlock gunlock;

		player->workerThread.start(); // if not running yet, start
		if(!player->outStream.get())
			player->outStream.reset(new OutStream(this));
		assert(player->outStream.get() != NULL);

		if(soundcardOutputEnabled) {
			if(playing && !player->outStream->isOpen()) {
				if(!player->outStream->open())
					playing = false;
			}
		}

		if(soundcardOutputEnabled && player->outStream.get() && player->outStream->isOpen() && oldplayingstate != playing)
			fader.change(playing ? 1 : -1, outSamplerate);
		player->playing = playing;
	}

	if(!PyErr_Occurred() && player->dict) {
		Py_INCREF(player->dict);
		PyObject* onPlayingStateChange = PyDict_GetItemString(player->dict, "onPlayingStateChange");
		if(onPlayingStateChange && onPlayingStateChange != Py_None) {
			Py_INCREF(onPlayingStateChange);

			PyObject* kwargs = PyDict_New();
			assert(kwargs);
			PyDict_SetItemString_retain(kwargs, "oldState", PyBool_FromLong(oldplayingstate));
			PyDict_SetItemString_retain(kwargs, "newState", PyBool_FromLong(playing));

			PyObject* retObj = PyEval_CallObjectWithKeywords(onPlayingStateChange, NULL, kwargs);
			Py_XDECREF(retObj);

			// errors are not fatal from the callback, so handle it now and go on
			if(PyErr_Occurred())
				PyErr_Print();

			Py_DECREF(kwargs);
			Py_DECREF(onPlayingStateChange);
		}
		Py_DECREF(player->dict);
	}

	return PyErr_Occurred() ? -1 : 0;
}

void PlayerObject::resetPlaying() {
	if(this->playing)
		this->setPlaying(false);
	if(this->outStream.get() != NULL)
		this->outStream.reset();
	reinitPlayerOutput();
}

#ifdef __APPLE__
// https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html
// Also, from Google Native Client, osx/nacl_thread_nice.c has some related code.
// Or, from Google Chrome, platform_thread_mac.mm. http://src.chromium.org/svn/trunk/src/base/threading/platform_thread_mac.mm
void setRealtime(double dutyCicleMs) {
	kern_return_t ret;
	thread_port_t threadport = pthread_mach_thread_np(pthread_self());

	thread_extended_policy_data_t policy;
	policy.timeshare = 0;
	ret = thread_policy_set(threadport,
							THREAD_EXTENDED_POLICY,
							(thread_policy_t)&policy,
							THREAD_EXTENDED_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_EXTENDED_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}

	thread_precedence_policy_data_t precedence;
	precedence.importance = 63;
	ret = thread_policy_set(threadport,
							THREAD_PRECEDENCE_POLICY,
							(thread_policy_t)&precedence,
							THREAD_PRECEDENCE_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_PRECEDENCE_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}

	// Get the conversion factor from milliseconds to absolute time
	// which is what the time-constraints call needs.
	mach_timebase_info_data_t tb_info;
	mach_timebase_info(&tb_info);
	double timeFact = ((double)tb_info.denom / (double)tb_info.numer) * 1000000;

	thread_time_constraint_policy_data_t ttcpolicy;
	// in Chrome: period = 2.9ms ~= 128 frames @44.1KHz, comp = 0.75 * period, constr = 0.85 * period.
	ttcpolicy.period = dutyCicleMs * timeFact;
	ttcpolicy.computation = dutyCicleMs * 0.75 * timeFact;
	ttcpolicy.constraint = dutyCicleMs * 0.85 * timeFact;
	ttcpolicy.preemptible = 0;

	ret = thread_policy_set(threadport,
							THREAD_TIME_CONSTRAINT_POLICY,
							(thread_policy_t)&ttcpolicy,
							THREAD_TIME_CONSTRAINT_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_TIME_CONSTRAINT_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}
}
#else
void setRealtime(double dutyCicleMs) {} // not implemented yet
#endif

<commit_msg>comments<commit_after>// ffmpeg player output (portaudio)
// part of MusicPlayer, https://github.com/albertz/music-player
// Copyright (c) 2012, Albert Zeyer, www.az2000.de
// All rights reserved.
// This code is under the 2-clause BSD license, see License.txt in the root directory of this project.

#include "ffmpeg.h"
#include "PyUtils.h"

#include <portaudio.h>
#include <boost/bind.hpp>
#include <boost/atomic.hpp>

#ifdef __APPLE__
// PortAudio specific Mac stuff
#include "pa_mac_core.h"
#endif

// For setting the thread priority to realtime on MacOSX.
#ifdef __APPLE__
#include <mach/mach_init.h>
#include <mach/thread_policy.h>
#include <mach/thread_act.h> // the doc says mach/sched.h but that seems outdated...
#include <pthread.h>
#include <mach/mach_error.h>
#include <mach/mach_time.h>
#endif
static void setRealtime(double dutyCicleMs);

/*
The implementation with the PortAudio callback was there first.
For testing, I implemented also the blocking PortAudio interface.
I had some issues which small hiccups in the audio output -
maybe the blocking PortAudio implementation can avoid them better.
For the callback, we need to minimize the locks - or better, avoid
them fully. I'm not sure it is good to depend on thread context
switches in case it is locked. This however needs some heavy redesign.
*/
#define USE_PORTAUDIO_CALLBACK 1

int initPlayerOutput() {
	PaError ret = Pa_Initialize();
	if(ret != paNoError)
		Py_FatalError("PortAudio init failed");
	return 0;
}

void reinitPlayerOutput() {
	if(Pa_Terminate() != paNoError)
		printf("Warning: Pa_Terminate() failed\n");
	initPlayerOutput();
}

template<typename T> struct OutPaSampleFormat{};
template<> struct OutPaSampleFormat<int16_t> {
	static const PaSampleFormat format = paInt16;
};
template<> struct OutPaSampleFormat<float32_t> {
	static const PaSampleFormat format = paFloat32;
};

#define LATENCY_IN_MS 100

struct PlayerObject::OutStream {
	PlayerObject* const player;
	PaStream* stream;
	boost::atomic<bool> needRealtimeReset; // PortAudio callback thread must set itself to realtime
	boost::atomic<bool> setThreadName;

	OutStream(PlayerObject* p) : player(p), stream(NULL), needRealtimeReset(false) {
		mlock(this, sizeof(*this));
	}
	~OutStream() { close(); }

#if USE_PORTAUDIO_CALLBACK
	static int paStreamCallback(
		const void *input, void *output,
		unsigned long frameCount,
		const PaStreamCallbackTimeInfo* timeInfo,
		PaStreamCallbackFlags statusFlags,
		void *userData )
	{
		OutStream* outStream = (OutStream*) userData;
		PlayerObject* player = outStream->player;

		if(outStream->needRealtimeReset.exchange(false))
			setRealtime(1000.0 * frameCount / player->outSamplerate);

		if(outStream->setThreadName.exchange(false))
			setCurThreadName("audio callback");

		if(statusFlags & paOutputUnderflow)
			printf("audio: paOutputUnderflow\n");
		if(statusFlags & paOutputOverflow)
			printf("audio: paOutputOverflow\n");

		// We must not hold the PyGIL here!
		// Also no need to hold the player lock, all is safe!

		player->readOutStream((OUTSAMPLE_t*) output, frameCount * outStream->player->outNumChannels, NULL);
		return paContinue;
	}
#else
	PyThread audioThread;
	void audioThreadProc(PyMutex& threadLock, bool& stopSignal) {
		while(true) {
			{
				PyScopedLock l(threadLock);
				if(stopSignal) return;
			}

			if(needRealtimeReset) {
				needRealtimeReset = false;
				setRealtime();
			}

			OUTSAMPLE_t buffer[48 * 2 * 10]; // 10ms stereo in 48khz
			size_t frameCount = 0;
			{
				PyScopedLock lock(player->lock);
				if(stopSignal) return;
				player->readOutStream(buffer, sizeof(buffer)/sizeof(OUTSAMPLE_t), NULL);
				frameCount = sizeof(buffer)/sizeof(OUTSAMPLE_t) / player->outNumChannels;
			}

			PaError ret = Pa_WriteStream(stream, buffer, frameCount);
			if(ret == paOutputUnderflowed)
				printf("warning: paOutputUnderflowed\n");
			else if(ret != paNoError) {
				printf("Pa_WriteStream error %i (%s)\n", ret, Pa_GetErrorText(ret));
				// sleep half a second to avoid spamming
				for(int i = 0; i < 50; ++i) {
					usleep(10 * 1000);
					PyScopedLock l(threadLock);
					if(stopSignal) return;
				}
			}
		}
	}
#endif

	bool open() {
		if(stream) close();
		assert(stream == NULL);

		// For reference:
		// Mixxx code: http://bazaar.launchpad.net/~mixxxdevelopers/mixxx/trunk/view/head:/mixxx/src/sounddeviceportaudio.cpp

		PaStreamParameters outputParameters;

#if defined(__APPLE__)
		PaMacCoreStreamInfo macInfo;
		PaMacCore_SetupStreamInfo( &macInfo,
			paMacCorePlayNice | paMacCorePro );
		outputParameters.hostApiSpecificStreamInfo = &macInfo;
#elif defined(__LINUX__)
		// TODO: if we have PaAlsa_EnableRealtimeScheduling in portaudio,
		// we can call that to enable RT priority with ALSA.
		// We could check dynamically via dsym.
		outputParameters.hostApiSpecificStreamInfo = NULL;
#else
		outputParameters.hostApiSpecificStreamInfo = NULL;
#endif

		outputParameters.device = Pa_GetDefaultOutputDevice();
		if (outputParameters.device == paNoDevice) {
			PyScopedGIL gil;
			PyErr_SetString(PyExc_RuntimeError, "Pa_GetDefaultOutputDevice didn't returned a device");
			return false;
		}
		outputParameters.channelCount = player->outNumChannels;
		outputParameters.sampleFormat = OutPaSampleFormat<OUTSAMPLE_t>::format;

		//unsigned long bufferSize = (player->outSamplerate * player->outNumChannels / 1000) * LATENCY_IN_MS / 4;
		unsigned long bufferSize = paFramesPerBufferUnspecified; // support any buffer size
		if(bufferSize == paFramesPerBufferUnspecified)
			outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
		else
			outputParameters.suggestedLatency = LATENCY_IN_MS / 1000.0;

		// Note about framesPerBuffer:
		// Earlier, we used (2048 * 5 * OUTSAMPLEBYTELEN) which caused
		// some random more or less rare cracking noises.
		// See here: https://github.com/albertz/music-player/issues/35
		// This doesn't seem to happen with paFramesPerBufferUnspecified.

		PaError ret = Pa_OpenStream(
			&stream,
			NULL, // no input
			&outputParameters,
			player->outSamplerate, // sampleRate
			bufferSize,
			paClipOff | paDitherOff,
#if USE_PORTAUDIO_CALLBACK
			&paStreamCallback,
#else
			NULL,
#endif
			this //void *userData
			);

		if(ret != paNoError) {
			{
				PyScopedGIL gil;
				PyErr_Format(PyExc_RuntimeError, "Pa_OpenStream failed: (err %i) %s", ret, Pa_GetErrorText(ret));
			}
			if(stream)
				close();
			return false;
		}

		needRealtimeReset = true;
		setThreadName = true;
		Pa_StartStream(stream);

#if !USE_PORTAUDIO_CALLBACK
		audioThread.func = boost::bind(&OutStream::audioThreadProc, this, _1, _2);
		audioThread.start();
#endif
		return true;
	}

	void close() {
		if(this->stream == NULL) return;
		// we expect that we have the player lock here.
		// reset fader.
		player->fader.change(0,0);
		// we must release the player lock so that any thread-join can be done.
		PaStream* stream = NULL;
		std::swap(stream, this->stream);
		PyScopedUnlock unlock(player->lock);
#if !USE_PORTAUDIO_CALLBACK
		audioThread.stop();
#endif
		Pa_CloseStream(stream);
	}

	bool isOpen() const { return stream != NULL; }

};

int PlayerObject::setPlaying(bool playing) {
	PlayerObject* player = this;
	bool oldplayingstate = player->playing;

	if(oldplayingstate != playing)
		outOfSync = true;

	PyScopedGIL gil;
	{
		PyScopedGIUnlock gunlock;

		player->workerThread.start(); // if not running yet, start
		if(!player->outStream.get())
			player->outStream.reset(new OutStream(this));
		assert(player->outStream.get() != NULL);

		if(soundcardOutputEnabled) {
			if(playing && !player->outStream->isOpen()) {
				if(!player->outStream->open())
					playing = false;
			}
		}

		if(soundcardOutputEnabled && player->outStream.get() && player->outStream->isOpen() && oldplayingstate != playing)
			fader.change(playing ? 1 : -1, outSamplerate);
		player->playing = playing;
	}

	if(!PyErr_Occurred() && player->dict) {
		Py_INCREF(player->dict);
		PyObject* onPlayingStateChange = PyDict_GetItemString(player->dict, "onPlayingStateChange");
		if(onPlayingStateChange && onPlayingStateChange != Py_None) {
			Py_INCREF(onPlayingStateChange);

			PyObject* kwargs = PyDict_New();
			assert(kwargs);
			PyDict_SetItemString_retain(kwargs, "oldState", PyBool_FromLong(oldplayingstate));
			PyDict_SetItemString_retain(kwargs, "newState", PyBool_FromLong(playing));

			PyObject* retObj = PyEval_CallObjectWithKeywords(onPlayingStateChange, NULL, kwargs);
			Py_XDECREF(retObj);

			// errors are not fatal from the callback, so handle it now and go on
			if(PyErr_Occurred())
				PyErr_Print();

			Py_DECREF(kwargs);
			Py_DECREF(onPlayingStateChange);
		}
		Py_DECREF(player->dict);
	}

	return PyErr_Occurred() ? -1 : 0;
}

void PlayerObject::resetPlaying() {
	if(this->playing)
		this->setPlaying(false);
	if(this->outStream.get() != NULL)
		this->outStream.reset();
	reinitPlayerOutput();
}

#ifdef __APPLE__
// https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html
// Also, from Google Native Client, osx/nacl_thread_nice.c has some related code.
// Or, from Google Chrome, platform_thread_mac.mm. http://src.chromium.org/svn/trunk/src/base/threading/platform_thread_mac.mm
void setRealtime(double dutyCicleMs) {
	kern_return_t ret;
	thread_port_t threadport = pthread_mach_thread_np(pthread_self());

	thread_extended_policy_data_t policy;
	policy.timeshare = 0;
	ret = thread_policy_set(threadport,
							THREAD_EXTENDED_POLICY,
							(thread_policy_t)&policy,
							THREAD_EXTENDED_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_EXTENDED_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}

	thread_precedence_policy_data_t precedence;
	precedence.importance = 63;
	ret = thread_policy_set(threadport,
							THREAD_PRECEDENCE_POLICY,
							(thread_policy_t)&precedence,
							THREAD_PRECEDENCE_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_PRECEDENCE_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}

	// Get the conversion factor from milliseconds to absolute time
	// which is what the time-constraints call needs.
	mach_timebase_info_data_t tb_info;
	mach_timebase_info(&tb_info);
	double timeFact = ((double)tb_info.denom / (double)tb_info.numer) * 1000000;

	// In Chrome: period = 2.9ms ~= 128 frames @44.1KHz, comp = 0.75 * period, constr = 0.85 * period.
	// Also read: http://lists.apple.com/archives/coreaudio-api/2009/Jun/msg00059.html
	// Or: http://web.archiveorange.com/archive/v/q7bubBVFSGH286ErO0zz
	thread_time_constraint_policy_data_t ttcpolicy;
	ttcpolicy.period = dutyCicleMs * timeFact;
	ttcpolicy.computation = dutyCicleMs * 0.75 * timeFact;
	ttcpolicy.constraint = dutyCicleMs * 0.85 * timeFact;
	ttcpolicy.preemptible = 0;

	ret = thread_policy_set(threadport,
							THREAD_TIME_CONSTRAINT_POLICY,
							(thread_policy_t)&ttcpolicy,
							THREAD_TIME_CONSTRAINT_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_TIME_CONSTRAINT_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}
}
#else
void setRealtime(double dutyCicleMs) {} // not implemented yet
#endif

<|endoftext|>