<commit_before>#include "dsa_common.h"

#include "node_state.h"

#include "core/session.h"

#include "message/request/invoke_request_message.h"
#include "message/request/set_request_message.h"
#include "stream/responder/outgoing_invoke_stream.h"
#include "stream/responder/outgoing_list_stream.h"
#include "stream/responder/outgoing_set_stream.h"
#include "stream/responder/outgoing_subscribe_stream.h"

namespace dsa {

NodeStateWaitingCache::NodeStateWaitingCache() = default;
NodeStateWaitingCache::~NodeStateWaitingCache() = default;

NodeState::NodeState(NodeStateOwner &owner, ref_<NodeState> &&parent)
    : _owner(owner),
      _parent(std::move(parent)),
      _merged_subscribe_options(QosLevel::_0, -1) {}
NodeState::~NodeState() = default;

ref_<NodeState> NodeState::get_child(const string_ &name, bool create) {
  // find existing node
  auto result = _children.find(name);
  if (result != _children.end()) {
    return result->second;
  } else if (create) {
    auto child = new NodeStateChild(_owner, get_ref(), name);
    child->_path = _path.get_child_path(name);
    _children[name] = child;
    return child->get_ref();
  }
  // not found, return a nullptr
  return ref_<NodeState>();
}
ref_<NodeState> NodeState::create_child(const Path &path,
                                        NodeState &last_modeled_state,
                                        bool allows_runtime_change) {
  const string_ &name = path.current_name();

  // find existing node
  auto result = _children.find(name);
  if (result != _children.end()) {
    if (path.is_last()) {
      return result->second;
    }
    // let child state decide
    if (result->second->_model != nullptr) {
      if (!allows_runtime_change &&
          result->second->_model->allows_runtime_child_change()) {
        allows_runtime_change = true;
      }
      return result->second->create_child(path.next(), *result->second,
                                          allows_runtime_change);
    } else {
      return result->second->create_child(path.next(), last_modeled_state,
                                          allows_runtime_change);
    }
  }
  if (allows_runtime_change) {
    // create new node
    ref_<NodeState> new_state = ref_<NodeState>(
        static_cast<NodeState *>(new NodeStateChild(_owner, get_ref(), name)));
    _children[name] = new_state;
    if (path.is_last()) {
      new_state->_path = path;
      if (_model_status == MODEL_UNKNOWN) {
        new_state->set_model(last_modeled_state._model->on_demand_create_child(
            path.move_pos(last_modeled_state._path.current_pos() + 1)));
      } else if (_model_status == MODEL_CONNECTED) {
        new_state->set_model(_model->on_demand_create_child(path));
      } else {
        new_state->_model_status = _model_status;
      }
      return new_state;
    }
    return _children[name]->create_child(path.next(), last_modeled_state, true);
  }
  // not found, return a nullptr
  return ref_<NodeState>();
}

ref_<NodeState> NodeState::find_child(const Path &path) {
  const string_ &name = path.current_name();

  auto result = _children.find(name);
  if (result != _children.end()) {
    if (path.is_last()) {
      return result->second;
    }

    return result->second->find_child(path.next());
  }
  return ref_<NodeState>();
}

void NodeState::remove_child(const string_ &name) { _children.erase(name); }

void NodeState::set_model(ModelRef &&model) {
  if (model == nullptr) {
    _model.reset();
    _model_status = MODEL_INVALID;
  } else if (model->_strand == nullptr) {  // Other Invalid Models
    _model.reset();
    if (model == NodeModelBase::WAITING) {
      _model_status = MODEL_WAITING;
      if (_waiting_cache == nullptr) {
        _waiting_cache.reset(new NodeStateWaitingCache());
      }
    } else if (model == NodeModelBase::UNAVAILABLE) {
      _model_status = MODEL_UNAVAILABLE;
    } else {
      _model_status = MODEL_INVALID;
    }
  } else {
    _model = std::move(model);
    _model->_state = get_ref();
    _model_status = MODEL_CONNECTED;
    _model->initialize();

    // send all waiting streams

    // subscribe streams
    if (!_merged_subscribe_options.is_invalid()) {
      _model->subscribe(_merged_subscribe_options);
      if (_model->_cached_value != nullptr) {
        for (auto &subscribe_stream : _subscription_streams) {
          subscribe_stream.first->send_subscribe_response(
              copy_ref_(_model->_cached_value));
        }
      }
    }
    // list streams
    for (auto &list_stream : _list_streams) {
      _model->list(*list_stream.first);
    }
    // invoke and set streams
    if (_waiting_cache != nullptr) {
      for (auto &invoke_stream : _waiting_cache->invokes) {
        _model->invoke(std::move(invoke_stream), _parent);
      }
      for (auto &set_stream : _waiting_cache->sets) {
        _model->set(std::move(set_stream));
      }
      _waiting_cache.reset();
    }
  }
}
bool NodeState::periodic_check(size_t ts) {
  for (auto it = _children.begin(); it != _children.end();) {
    if (it->second->periodic_check(ts)) {
      it = _children.erase(it);
    } else {
      it++;
    }
  }

  if (_subscription_streams.empty() && _list_streams.empty() &&
      _children.empty() &&
      // check if model is still in use
      (_model == nullptr || _model->periodic_check(ts))) {
    destroy();
    return true;
  }
  return false;
}

void NodeState::new_subscribe_response(SubscribeResponseMessageCRef &&message) {
  for (auto &it : _subscription_streams) {
    it.first->send_subscribe_response(copy_ref_(message));
  }
}

void NodeState::check_subscribe_options() {
  SubscribeOptions new_options(QosLevel::_0, -1);
  for (auto &stream : _subscription_streams) {
    new_options.mergeFrom(stream.first->subscribe_options());
  }
  if (new_options != _merged_subscribe_options) {
    _merged_subscribe_options = new_options;
    if (_model != nullptr) {
      if (new_options.is_invalid()) {
        _model->unsubscribe();
      } else {
        // update options only
        _model->subscribe(new_options);
      }
    }
  }
}

void NodeState::subscribe(ref_<BaseOutgoingSubscribeStream> &&stream) {
  auto p = stream.get();
  _subscription_streams[p] = std::move(stream);
  if (_model != nullptr && _model->_cached_value != nullptr) {
    p->send_subscribe_response(copy_ref_(_model->_cached_value));
  }
  if (_merged_subscribe_options.mergeFrom(p->subscribe_options())) {
    if (_model_status == MODEL_CONNECTED) {
      _model->subscribe(_merged_subscribe_options);
    }
    // TODO update model;
  }
  p->on_subscribe_option_change([
    this, keep_ref = get_ref()
  ](BaseOutgoingSubscribeStream & stream, const SubscribeOptions &old_options) {
    if (stream.is_destroyed()) {
      _subscription_streams.erase(&stream);
      if (_subscription_streams.empty() ||
          _merged_subscribe_options.needUpdateOnRemoval(
              stream.subscribe_options())) {
        check_subscribe_options();
      }
    } else {
      if (_merged_subscribe_options.needUpdateOnChange(
              old_options, stream.subscribe_options())) {
        check_subscribe_options();
      }
    }
  });
}

void NodeState::update_list_value(const string_ &key,
                                  const VarBytesRef &value) {
  for (auto &it : _list_streams) {
    it.first->update_list_value(key, value);
  }
}

void NodeState::update_list_status(MessageStatus status){
  for (auto &it : _list_streams) {
    it.first->update_list_status(status);
  }
}
void NodeState::update_list_refreshed(){
  for (auto &it : _list_streams) {
    it.first->update_list_refreshed();
  }
}
void NodeState::update_list_pub_path(const string_ &path){
  for (auto &it : _list_streams) {
    it.first->update_list_pub_path(path);
  }
}

void NodeState::list(ref_<BaseOutgoingListStream> &&stream) {
  auto p = stream.get();
  _list_streams[p] = std::move(stream);
  p->on_list_close([ this, keep_ref = get_ref() ](BaseOutgoingListStream & s) {
    _list_streams.erase(&s);
    if (_list_streams.empty() && _model != nullptr) {
      _model->unlist();
    }
  });
  if (_model != nullptr) {
    _model->list(*p);
  }
}

void NodeState::invoke(ref_<OutgoingInvokeStream> &&stream) {
  if (_model != nullptr) {
    _model->invoke(std::move(stream), _parent);
  } else if (_model_status == MODEL_WAITING) {
    _waiting_cache->invokes.emplace_back(std::move(stream));
  } else {
    auto response = make_ref_<InvokeResponseMessage>();
    if (_model_status == MODEL_UNAVAILABLE) {
      response->set_status(MessageStatus::DISCONNECTED);
    } else {
      response->set_status(MessageStatus::NOT_SUPPORTED);
    }
    stream->send_response(std::move(response));
  }
}
void NodeState::set(ref_<OutgoingSetStream> &&stream) {
  if (_model != nullptr) {
    _model->set(std::move(stream));
  } else if (_model_status == MODEL_WAITING) {
    _waiting_cache->sets.emplace_back(std::move(stream));
  } else {
    auto response = make_ref_<SetResponseMessage>();
    if (_model_status == MODEL_UNAVAILABLE) {
      response->set_status(MessageStatus::DISCONNECTED);
    } else {
      response->set_status(MessageStatus::NOT_SUPPORTED);
    }
    stream->send_response(std::move(response));
  }
}

void NodeState::destroy_impl() {
  if (_model != nullptr) {
    _model->destroy();
    _model.reset();
    _model_status = MODEL_UNKNOWN;
  }

  _subscription_streams.clear();
  _list_streams.clear();
  for (auto it = _children.begin(); it != _children.end(); ++it)
    it->second->destroy();
  _children.clear();
  if (_waiting_cache != nullptr) {
    _waiting_cache->invokes.clear();
    _waiting_cache->sets.clear();
    _waiting_cache.reset(nullptr);
  }

  if (!_path.is_invalid()) {
    _owner.remove_state(_path.full_str());
  }
  _parent.reset();
  // TODO: ali ask
  //  if(_parent != nullptr) {
  //    _parent->destroy();
  //    _parent.reset();
  //  }
}

NodeStateChild::NodeStateChild(NodeStateOwner &owner, ref_<NodeState> &&parent,
                               const string_ &name)
    : NodeState(owner, std::move(parent)), name(name) {}

NodeStateRoot::NodeStateRoot(NodeStateOwner &owner, ModelRef &&model)
    : NodeState(owner, ref_<NodeState>()) {
  _path = Path("");
  set_model(std::move(model));
};

}  // namespace dsa
<commit_msg>fix children node's path in dynamic child creation<commit_after>#include "dsa_common.h"

#include "node_state.h"

#include "core/session.h"

#include "message/request/invoke_request_message.h"
#include "message/request/set_request_message.h"
#include "stream/responder/outgoing_invoke_stream.h"
#include "stream/responder/outgoing_list_stream.h"
#include "stream/responder/outgoing_set_stream.h"
#include "stream/responder/outgoing_subscribe_stream.h"

namespace dsa {

NodeStateWaitingCache::NodeStateWaitingCache() = default;
NodeStateWaitingCache::~NodeStateWaitingCache() = default;

NodeState::NodeState(NodeStateOwner &owner, ref_<NodeState> &&parent)
    : _owner(owner),
      _parent(std::move(parent)),
      _merged_subscribe_options(QosLevel::_0, -1) {}
NodeState::~NodeState() = default;

ref_<NodeState> NodeState::get_child(const string_ &name, bool create) {
  // find existing node
  auto result = _children.find(name);
  if (result != _children.end()) {
    return result->second;
  } else if (create) {
    auto child = new NodeStateChild(_owner, get_ref(), name);
    child->_path = _path.get_child_path(name);
    _children[name] = child;
    return child->get_ref();
  }
  // not found, return a nullptr
  return ref_<NodeState>();
}
ref_<NodeState> NodeState::create_child(const Path &path,
                                        NodeState &last_modeled_state,
                                        bool allows_runtime_change) {
  const string_ &name = path.current_name();

  // find existing node
  auto result = _children.find(name);
  if (result != _children.end()) {
    if (path.is_last()) {
      return result->second;
    }
    // let child state decide
    if (result->second->_model != nullptr) {
      if (!allows_runtime_change &&
          result->second->_model->allows_runtime_child_change()) {
        allows_runtime_change = true;
      }
      return result->second->create_child(path.next(), *result->second,
                                          allows_runtime_change);
    } else {
      return result->second->create_child(path.next(), last_modeled_state,
                                          allows_runtime_change);
    }
  }
  if (allows_runtime_change) {
    // create new node
    ref_<NodeState> new_state = ref_<NodeState>(
        static_cast<NodeState *>(new NodeStateChild(_owner, get_ref(), name)));
    _children[name] = new_state;
    if (path.is_last()) {
      new_state->_path = path;
      if (_model_status == MODEL_UNKNOWN) {
        new_state->set_model(last_modeled_state._model->on_demand_create_child(
            // use offset name from the create state's path
            path.move_pos(last_modeled_state._path.data()->names.size())));
      } else if (_model_status == MODEL_CONNECTED) {
        new_state->set_model(_model->on_demand_create_child(path));
      } else {
        new_state->_model_status = _model_status;
      }
      return new_state;
    }
    return _children[name]->create_child(path.next(), last_modeled_state, true);
  }
  // not found, return a nullptr
  return ref_<NodeState>();
}

ref_<NodeState> NodeState::find_child(const Path &path) {
  const string_ &name = path.current_name();

  auto result = _children.find(name);
  if (result != _children.end()) {
    if (path.is_last()) {
      return result->second;
    }

    return result->second->find_child(path.next());
  }
  return ref_<NodeState>();
}

void NodeState::remove_child(const string_ &name) { _children.erase(name); }

void NodeState::set_model(ModelRef &&model) {
  if (model == nullptr) {
    _model.reset();
    _model_status = MODEL_INVALID;
  } else if (model->_strand == nullptr) {  // Other Invalid Models
    _model.reset();
    if (model == NodeModelBase::WAITING) {
      _model_status = MODEL_WAITING;
      if (_waiting_cache == nullptr) {
        _waiting_cache.reset(new NodeStateWaitingCache());
      }
    } else if (model == NodeModelBase::UNAVAILABLE) {
      _model_status = MODEL_UNAVAILABLE;
    } else {
      _model_status = MODEL_INVALID;
    }
  } else {
    _model = std::move(model);
    _model->_state = get_ref();
    _model_status = MODEL_CONNECTED;
    _model->initialize();

    // send all waiting streams

    // subscribe streams
    if (!_merged_subscribe_options.is_invalid()) {
      _model->subscribe(_merged_subscribe_options);
      if (_model->_cached_value != nullptr) {
        for (auto &subscribe_stream : _subscription_streams) {
          subscribe_stream.first->send_subscribe_response(
              copy_ref_(_model->_cached_value));
        }
      }
    }
    // list streams
    for (auto &list_stream : _list_streams) {
      _model->list(*list_stream.first);
    }
    // invoke and set streams
    if (_waiting_cache != nullptr) {
      for (auto &invoke_stream : _waiting_cache->invokes) {
        _model->invoke(std::move(invoke_stream), _parent);
      }
      for (auto &set_stream : _waiting_cache->sets) {
        _model->set(std::move(set_stream));
      }
      _waiting_cache.reset();
    }
  }
}
bool NodeState::periodic_check(size_t ts) {
  for (auto it = _children.begin(); it != _children.end();) {
    if (it->second->periodic_check(ts)) {
      it = _children.erase(it);
    } else {
      it++;
    }
  }

  if (_subscription_streams.empty() && _list_streams.empty() &&
      _children.empty() &&
      // check if model is still in use
      (_model == nullptr || _model->periodic_check(ts))) {
    destroy();
    return true;
  }
  return false;
}

void NodeState::new_subscribe_response(SubscribeResponseMessageCRef &&message) {
  for (auto &it : _subscription_streams) {
    it.first->send_subscribe_response(copy_ref_(message));
  }
}

void NodeState::check_subscribe_options() {
  SubscribeOptions new_options(QosLevel::_0, -1);
  for (auto &stream : _subscription_streams) {
    new_options.mergeFrom(stream.first->subscribe_options());
  }
  if (new_options != _merged_subscribe_options) {
    _merged_subscribe_options = new_options;
    if (_model != nullptr) {
      if (new_options.is_invalid()) {
        _model->unsubscribe();
      } else {
        // update options only
        _model->subscribe(new_options);
      }
    }
  }
}

void NodeState::subscribe(ref_<BaseOutgoingSubscribeStream> &&stream) {
  auto p = stream.get();
  _subscription_streams[p] = std::move(stream);
  if (_model != nullptr && _model->_cached_value != nullptr) {
    p->send_subscribe_response(copy_ref_(_model->_cached_value));
  }
  if (_merged_subscribe_options.mergeFrom(p->subscribe_options())) {
    if (_model_status == MODEL_CONNECTED) {
      _model->subscribe(_merged_subscribe_options);
    }
    // TODO update model;
  }
  p->on_subscribe_option_change([
    this, keep_ref = get_ref()
  ](BaseOutgoingSubscribeStream & stream, const SubscribeOptions &old_options) {
    if (stream.is_destroyed()) {
      _subscription_streams.erase(&stream);
      if (_subscription_streams.empty() ||
          _merged_subscribe_options.needUpdateOnRemoval(
              stream.subscribe_options())) {
        check_subscribe_options();
      }
    } else {
      if (_merged_subscribe_options.needUpdateOnChange(
              old_options, stream.subscribe_options())) {
        check_subscribe_options();
      }
    }
  });
}

void NodeState::update_list_value(const string_ &key,
                                  const VarBytesRef &value) {
  for (auto &it : _list_streams) {
    it.first->update_list_value(key, value);
  }
}

void NodeState::update_list_status(MessageStatus status) {
  for (auto &it : _list_streams) {
    it.first->update_list_status(status);
  }
}
void NodeState::update_list_refreshed() {
  for (auto &it : _list_streams) {
    it.first->update_list_refreshed();
  }
}
void NodeState::update_list_pub_path(const string_ &path) {
  for (auto &it : _list_streams) {
    it.first->update_list_pub_path(path);
  }
}

void NodeState::list(ref_<BaseOutgoingListStream> &&stream) {
  auto p = stream.get();
  _list_streams[p] = std::move(stream);
  p->on_list_close([ this, keep_ref = get_ref() ](BaseOutgoingListStream & s) {
    _list_streams.erase(&s);
    if (_list_streams.empty() && _model != nullptr) {
      _model->unlist();
    }
  });
  if (_model != nullptr) {
    _model->list(*p);
  }
}

void NodeState::invoke(ref_<OutgoingInvokeStream> &&stream) {
  if (_model != nullptr) {
    _model->invoke(std::move(stream), _parent);
  } else if (_model_status == MODEL_WAITING) {
    _waiting_cache->invokes.emplace_back(std::move(stream));
  } else {
    auto response = make_ref_<InvokeResponseMessage>();
    if (_model_status == MODEL_UNAVAILABLE) {
      response->set_status(MessageStatus::DISCONNECTED);
    } else {
      response->set_status(MessageStatus::NOT_SUPPORTED);
    }
    stream->send_response(std::move(response));
  }
}
void NodeState::set(ref_<OutgoingSetStream> &&stream) {
  if (_model != nullptr) {
    _model->set(std::move(stream));
  } else if (_model_status == MODEL_WAITING) {
    _waiting_cache->sets.emplace_back(std::move(stream));
  } else {
    auto response = make_ref_<SetResponseMessage>();
    if (_model_status == MODEL_UNAVAILABLE) {
      response->set_status(MessageStatus::DISCONNECTED);
    } else {
      response->set_status(MessageStatus::NOT_SUPPORTED);
    }
    stream->send_response(std::move(response));
  }
}

void NodeState::destroy_impl() {
  if (_model != nullptr) {
    _model->destroy();
    _model.reset();
    _model_status = MODEL_UNKNOWN;
  }

  _subscription_streams.clear();
  _list_streams.clear();
  for (auto it = _children.begin(); it != _children.end(); ++it)
    it->second->destroy();
  _children.clear();
  if (_waiting_cache != nullptr) {
    _waiting_cache->invokes.clear();
    _waiting_cache->sets.clear();
    _waiting_cache.reset(nullptr);
  }

  if (!_path.is_invalid()) {
    _owner.remove_state(_path.full_str());
  }
  _parent.reset();
  // TODO: ali ask
  //  if(_parent != nullptr) {
  //    _parent->destroy();
  //    _parent.reset();
  //  }
}

NodeStateChild::NodeStateChild(NodeStateOwner &owner, ref_<NodeState> &&parent,
                               const string_ &name)
    : NodeState(owner, std::move(parent)), name(name) {}

NodeStateRoot::NodeStateRoot(NodeStateOwner &owner, ModelRef &&model)
    : NodeState(owner, ref_<NodeState>()) {
  _path = Path("");
  set_model(std::move(model));
};

}  // namespace dsa
<|endoftext|>


<commit_before>#include "treeview.h"

#include <QDir>
#include <QHeaderView>
#include <QKeyEvent>
#include <QProcess>
#include <QStandardPaths>

namespace NeovimQt {
TreeView::TreeView(NeovimConnector *nvim, QWidget *parent)
    : QTreeView(parent), m_nvim(nvim) {
  model = new QFileSystemModel(this);

  setModel(model);

  header()->hide();
  // FIXME: MAGIC NUMBER!!
  for (int i = 1; i < 5; i++) {
    hideColumn(i);
  }

  connect(m_nvim, &NeovimConnector::ready, this, &TreeView::connector_ready_cb);
}

void TreeView::connector_ready_cb() {
  setDirectory(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));

  connect(this, &TreeView::doubleClicked, this, &TreeView::open);

  connect(m_nvim->neovimObject(), &NeovimApi1::neovimNotification, this,
          &TreeView::handleNeovimNotification);

  m_nvim->neovimObject()->vim_subscribe("Dir");
  m_nvim->neovimObject()->vim_subscribe("TreeView");
}

void TreeView::open(const QModelIndex &index) {
  QFileInfo info = model->fileInfo(index);
  if (info.isFile() and info.isReadable()) {
    QVariantList args;
    args << info.filePath();
    m_nvim->neovimObject()->vim_call_function("GuiDrop", args);
  }
  focusNextChild();
}

void TreeView::setDirectory(const QString &dir, bool notify) {
  if (QDir(dir).exists()) {
    QDir::setCurrent(dir);
    model->setRootPath(dir);
    setRootIndex(model->index(dir));
    if (notify) {
      m_nvim->neovimObject()->vim_change_directory(
          QByteArray::fromStdString(dir.toStdString()));
    }
  }
}

void TreeView::handleNeovimNotification(const QByteArray &name,
                                        const QVariantList &args) {
  if (name == "Dir" and args.size() >= 0) {
    setDirectory(m_nvim->decode(args.at(0).toByteArray()), false);
  } else if (name == "TreeView") {
    QByteArray action = args.at(0).toByteArray();
    if (action == "Toggle" and args.size() == 1) {
      if (isVisible())
        hide();
      else
        show();
    } else if (action == "ShowHide" and args.size() == 2) {
      args.at(1).toBool() ? show() : hide();
    }
  }
}

}  // namespace NeovimQt
<commit_msg>Treeview : call the initialization if the connector is already ready<commit_after>#include "treeview.h"

#include <QDir>
#include <QHeaderView>
#include <QKeyEvent>
#include <QProcess>
#include <QStandardPaths>

namespace NeovimQt {
TreeView::TreeView(NeovimConnector *nvim, QWidget *parent)
    : QTreeView(parent), m_nvim(nvim) {
  model = new QFileSystemModel(this);

  setModel(model);

  header()->hide();
  // FIXME: MAGIC NUMBER!!
  for (int i = 1; i < 5; i++) {
    hideColumn(i);
  }

  if (m_nvim->isReady()) {
    connector_ready_cb();
  }
  connect(m_nvim, &NeovimConnector::ready, this, &TreeView::connector_ready_cb);
}

void TreeView::connector_ready_cb() {
  setDirectory(QStandardPaths::writableLocation(QStandardPaths::HomeLocation));

  connect(this, &TreeView::doubleClicked, this, &TreeView::open);

  connect(m_nvim->neovimObject(), &NeovimApi1::neovimNotification, this,
          &TreeView::handleNeovimNotification);

  m_nvim->neovimObject()->vim_subscribe("Dir");
  m_nvim->neovimObject()->vim_subscribe("TreeView");
}

void TreeView::open(const QModelIndex &index) {
  QFileInfo info = model->fileInfo(index);
  if (info.isFile() and info.isReadable()) {
    QVariantList args;
    args << info.filePath();
    m_nvim->neovimObject()->vim_call_function("GuiDrop", args);
  }
  focusNextChild();
}

void TreeView::setDirectory(const QString &dir, bool notify) {
  if (QDir(dir).exists()) {
    QDir::setCurrent(dir);
    model->setRootPath(dir);
    setRootIndex(model->index(dir));
    if (notify) {
      m_nvim->neovimObject()->vim_change_directory(
          QByteArray::fromStdString(dir.toStdString()));
    }
  }
}

void TreeView::handleNeovimNotification(const QByteArray &name,
                                        const QVariantList &args) {
  if (name == "Dir" and args.size() >= 0) {
    setDirectory(m_nvim->decode(args.at(0).toByteArray()), false);
  } else if (name == "TreeView") {
    QByteArray action = args.at(0).toByteArray();
    if (action == "Toggle" and args.size() == 1) {
      if (isVisible())
        hide();
      else
        show();
    } else if (action == "ShowHide" and args.size() == 2) {
      args.at(1).toBool() ? show() : hide();
    }
  }
}

}  // namespace NeovimQt
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This code glues the RLZ library DLL with Chrome. It allows Chrome to work
// with or without the DLL being present. If the DLL is not present the
// functions do nothing and just return false.

#include "chrome/browser/rlz/rlz.h"

#include <process.h>
#include <windows.h>

#include <algorithm>

#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/synchronization/lock.h"
#include "base/task.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/env_vars.h"
#include "chrome/installer/util/google_update_settings.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_registrar.h"
#include "content/common/notification_service.h"

namespace {

// The maximum length of an access points RLZ in wide chars.
const DWORD kMaxRlzLength = 64;

enum {
  ACCESS_VALUES_STALE,      // Possibly new values available.
  ACCESS_VALUES_FRESH       // The cached values are current.
};

// Tracks if we have tried and succeeded sending the ping. This helps us
// decide if we need to refresh the some cached strings.
volatile int access_values_state = ACCESS_VALUES_STALE;
base::Lock rlz_lock;

bool SendFinancialPing(const std::wstring& brand, const std::wstring& lang,
                       const std::wstring& referral, bool exclude_id) {
  rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX,
                                   rlz_lib::CHROME_HOME_PAGE,
                                   rlz_lib::NO_ACCESS_POINT};
  std::string brand_ascii(WideToASCII(brand));
  std::string lang_ascii(WideToASCII(lang));
  std::string referral_ascii(WideToASCII(referral));

  return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome",
                                    brand_ascii.c_str(), referral_ascii.c_str(),
                                    lang_ascii.c_str(), exclude_id, NULL, true);
}

// This class leverages the AutocompleteEditModel notification to know when
// the user first interacted with the omnibox and set a global accordingly.
class OmniBoxUsageObserver : public NotificationObserver {
 public:
  OmniBoxUsageObserver() {
    registrar_.Add(this, NotificationType::OMNIBOX_OPENED_URL,
                   NotificationService::AllSources());
    // If instant is enabled we'll start searching as soon as the user starts
    // typing in the omnibox (which triggers INSTANT_CONTROLLER_UPDATED).
    registrar_.Add(this, NotificationType::INSTANT_CONTROLLER_UPDATED,
                   NotificationService::AllSources());
    omnibox_used_ = false;
    DCHECK(!instance_);
    instance_ = this;
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    // Needs to be evaluated. See http://crbug.com/62328.
    base::ThreadRestrictions::ScopedAllowIO allow_io;

    // Try to record event now, else set the flag to try later when we
    // attempt the ping.
    if (!RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                        rlz_lib::CHROME_OMNIBOX,
                                        rlz_lib::FIRST_SEARCH))
      omnibox_used_ = true;
    delete this;
  }

  static bool used() {
    return omnibox_used_;
  }

  // Deletes the single instance of OmniBoxUsageObserver.
  static void DeleteInstance() {
    delete instance_;
  }

 private:
  // Dtor is private so the object cannot be created on the stack.
  ~OmniBoxUsageObserver() {
    instance_ = NULL;
  }

  static bool omnibox_used_;

  // There should only be one instance created at a time, and instance_ points
  // to that instance.
  // NOTE: this is only non-null for the amount of time it is needed. Once the
  // instance_ is no longer needed (or Chrome is exiting), this is null.
  static OmniBoxUsageObserver* instance_;

  NotificationRegistrar registrar_;
};

bool OmniBoxUsageObserver::omnibox_used_ = false;
OmniBoxUsageObserver* OmniBoxUsageObserver::instance_ = NULL;

// This task is run in the file thread, so to not block it for a long time
// we use a throwaway thread to do the blocking url request.
class DailyPingTask : public Task {
 public:
  virtual ~DailyPingTask() {
  }
  virtual void Run() {
    // We use a transient thread because we have no guarantees about
    // how long the RLZ lib can block us.
    _beginthread(PingNow, 0, NULL);
  }

 private:
  // Causes a ping to the server using WinInet.
  static void _cdecl PingNow(void*) {
    // Needs to be evaluated. See http://crbug.com/62328.
    base::ThreadRestrictions::ScopedAllowIO allow_io;

    std::wstring lang;
    GoogleUpdateSettings::GetLanguage(&lang);
    if (lang.empty())
      lang = L"en";
    std::wstring brand;
    GoogleUpdateSettings::GetBrand(&brand);
    std::wstring referral;
    GoogleUpdateSettings::GetReferral(&referral);
    if (SendFinancialPing(brand, lang, referral, is_organic(brand))) {
      base::AutoLock lock(rlz_lock);
      access_values_state = ACCESS_VALUES_STALE;
      GoogleUpdateSettings::ClearReferral();
    }
  }

  // Organic brands all start with GG, such as GGCM.
  static bool is_organic(const std::wstring& brand) {
    return (brand.size() < 2) ? false : (brand.substr(0, 2) == L"GG");
  }
};

// Performs late RLZ initialization and RLZ event recording for chrome.
// This task needs to run on the UI thread.
class DelayedInitTask : public Task {
 public:
  explicit DelayedInitTask(bool first_run)
      : first_run_(first_run) {
  }
  virtual ~DelayedInitTask() {
  }
  virtual void Run() {
    // For non-interactive tests we don't do the rest of the initialization
    // because sometimes the very act of loading the dll causes QEMU to crash.
    if (::GetEnvironmentVariableW(ASCIIToWide(env_vars::kHeadless).c_str(),
                                  NULL, 0)) {
      return;
    }
    // For organic brandcodes do not use rlz at all. Empty brandcode usually
    // means a chromium install. This is ok.
    std::wstring brand;
    if (!GoogleUpdateSettings::GetBrand(&brand) || brand.empty() ||
        GoogleUpdateSettings::IsOrganic(brand))
      return;

    // Do the initial event recording if is the first run or if we have an
    // empty rlz which means we haven't got a chance to do it.
    std::wstring omnibox_rlz;
    RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &omnibox_rlz);

    if (first_run_ || omnibox_rlz.empty()) {
      // Record the installation of chrome.
      RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                     rlz_lib::CHROME_OMNIBOX,
                                     rlz_lib::INSTALL);
      RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                     rlz_lib::CHROME_HOME_PAGE,
                                     rlz_lib::INSTALL);
      // Record if google is the initial search provider.
      if (IsGoogleDefaultSearch()) {
        RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                       rlz_lib::CHROME_OMNIBOX,
                                       rlz_lib::SET_TO_GOOGLE);
      }
    }
    // Record first user interaction with the omnibox. We call this all the
    // time but the rlz lib should ingore all but the first one.
    if (OmniBoxUsageObserver::used()) {
      RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                     rlz_lib::CHROME_OMNIBOX,
                                     rlz_lib::FIRST_SEARCH);
    }
    // Schedule the daily RLZ ping.
    MessageLoop::current()->PostTask(FROM_HERE, new DailyPingTask());
  }

 private:
  bool IsGoogleDefaultSearch() {
    if (!g_browser_process)
      return false;
    FilePath user_data_dir;
    if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
      return false;
    ProfileManager* profile_manager = g_browser_process->profile_manager();
    Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
    if (!profile)
      return false;
    const TemplateURL* url_template =
        profile->GetTemplateURLModel()->GetDefaultSearchProvider();
    if (!url_template)
      return false;
    const TemplateURLRef* urlref = url_template->url();
    if (!urlref)
      return false;
    return urlref->HasGoogleBaseURLs();
  }

  bool first_run_;
  DISALLOW_IMPLICIT_CONSTRUCTORS(DelayedInitTask);
};

}  // namespace

bool RLZTracker::InitRlzDelayed(bool first_run, int delay) {
  // Maximum and minimum delay we would allow to be set through master
  // preferences. Somewhat arbitrary, may need to be adjusted in future.
  const int kMaxDelay = 200 * 1000;
  const int kMinDelay = 20 * 1000;

  delay *= 1000;
  delay = (delay < kMinDelay) ? kMinDelay : delay;
  delay = (delay > kMaxDelay) ? kMaxDelay : delay;

  if (!OmniBoxUsageObserver::used())
    new OmniBoxUsageObserver();

  // Schedule the delayed init items.
  BrowserThread::PostDelayedTask(
      BrowserThread::FILE, FROM_HERE, new DelayedInitTask(first_run), delay);
  return true;
}

bool RLZTracker::RecordProductEvent(rlz_lib::Product product,
                                    rlz_lib::AccessPoint point,
                                    rlz_lib::Event event_id) {
  return rlz_lib::RecordProductEvent(product, point, event_id);
}

bool RLZTracker::ClearAllProductEvents(rlz_lib::Product product) {
  return rlz_lib::ClearAllProductEvents(product);
}

// We implement caching of the answer of get_access_point() if the request
// is for CHROME_OMNIBOX. If we had a successful ping, then we update the
// cached value.

bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point,
                                   std::wstring* rlz) {
  static std::wstring cached_ommibox_rlz;
  if (rlz_lib::CHROME_OMNIBOX == point) {
    base::AutoLock lock(rlz_lock);
    if (access_values_state == ACCESS_VALUES_FRESH) {
      *rlz = cached_ommibox_rlz;
      return true;
    }
  }

  // Make sure we don't access disk outside of the file context.
  // In such case we repost the task on the right thread and return error.
  if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
    // Caching of access points is now only implemented for the CHROME_OMNIBOX.
    // Thus it is not possible to call this function on another thread for
    // other access points until proper caching for these has been implemented
    // and the code that calls this function can handle synchronous fetching
    // of the access point.
    DCHECK_EQ(rlz_lib::CHROME_OMNIBOX, point);

    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        NewRunnableFunction(&RLZTracker::GetAccessPointRlz,
                            point, &cached_ommibox_rlz));
      rlz->erase();
      return false;
  }

  char str_rlz[kMaxRlzLength + 1];
  if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength, NULL))
    return false;
  *rlz = ASCIIToWide(std::string(str_rlz));
  if (rlz_lib::CHROME_OMNIBOX == point) {
    base::AutoLock lock(rlz_lock);
    cached_ommibox_rlz.assign(*rlz);
    access_values_state = ACCESS_VALUES_FRESH;
  }
  return true;
}

// static
void RLZTracker::CleanupRlz() {
  OmniBoxUsageObserver::DeleteInstance();
}
<commit_msg>Allows distributions to send a finanacial ping immediately after a first search is performed, even if a financial ping has already been sent for the install event.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This code glues the RLZ library DLL with Chrome. It allows Chrome to work
// with or without the DLL being present. If the DLL is not present the
// functions do nothing and just return false.

#include "chrome/browser/rlz/rlz.h"

#include <process.h>
#include <windows.h>

#include <algorithm>

#include "base/file_path.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/synchronization/lock.h"
#include "base/task.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/env_vars.h"
#include "chrome/installer/util/google_update_settings.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_registrar.h"
#include "content/common/notification_service.h"

namespace {

// The maximum length of an access points RLZ in wide chars.
const DWORD kMaxRlzLength = 64;

enum {
  ACCESS_VALUES_STALE,      // Possibly new values available.
  ACCESS_VALUES_FRESH       // The cached values are current.
};

// Tracks if we have tried and succeeded sending the ping. This helps us
// decide if we need to refresh the some cached strings.
volatile int access_values_state = ACCESS_VALUES_STALE;
base::Lock rlz_lock;

bool SendFinancialPing(const std::wstring& brand, const std::wstring& lang,
                       const std::wstring& referral, bool exclude_id) {
  rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX,
                                   rlz_lib::CHROME_HOME_PAGE,
                                   rlz_lib::NO_ACCESS_POINT};
  std::string brand_ascii(WideToASCII(brand));
  std::string lang_ascii(WideToASCII(lang));
  std::string referral_ascii(WideToASCII(referral));

  return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome",
                                    brand_ascii.c_str(), referral_ascii.c_str(),
                                    lang_ascii.c_str(), exclude_id, NULL, true);
}

// This class leverages the AutocompleteEditModel notification to know when
// the user first interacted with the omnibox and set a global accordingly.
class OmniBoxUsageObserver : public NotificationObserver {
 public:
  OmniBoxUsageObserver(bool first_run, bool send_ping_immediately)
    : first_run_(first_run),
      send_ping_immediately_(send_ping_immediately) {
    registrar_.Add(this, NotificationType::OMNIBOX_OPENED_URL,
                   NotificationService::AllSources());
    // If instant is enabled we'll start searching as soon as the user starts
    // typing in the omnibox (which triggers INSTANT_CONTROLLER_UPDATED).
    registrar_.Add(this, NotificationType::INSTANT_CONTROLLER_UPDATED,
                   NotificationService::AllSources());
    omnibox_used_ = false;
    DCHECK(!instance_);
    instance_ = this;
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details);

  static bool used() {
    return omnibox_used_;
  }

  // Deletes the single instance of OmniBoxUsageObserver.
  static void DeleteInstance() {
    delete instance_;
  }

 private:
  // Dtor is private so the object cannot be created on the stack.
  ~OmniBoxUsageObserver() {
    instance_ = NULL;
  }

  static bool omnibox_used_;

  // There should only be one instance created at a time, and instance_ points
  // to that instance.
  // NOTE: this is only non-null for the amount of time it is needed. Once the
  // instance_ is no longer needed (or Chrome is exiting), this is null.
  static OmniBoxUsageObserver* instance_;

  NotificationRegistrar registrar_;
  bool first_run_;
  bool send_ping_immediately_;
};

bool OmniBoxUsageObserver::omnibox_used_ = false;
OmniBoxUsageObserver* OmniBoxUsageObserver::instance_ = NULL;

// This task is run in the file thread, so to not block it for a long time
// we use a throwaway thread to do the blocking url request.
class DailyPingTask : public Task {
 public:
  virtual ~DailyPingTask() {
  }
  virtual void Run() {
    // We use a transient thread because we have no guarantees about
    // how long the RLZ lib can block us.
    _beginthread(PingNow, 0, NULL);
  }

 private:
  // Causes a ping to the server using WinInet.
  static void _cdecl PingNow(void*) {
    // Needs to be evaluated. See http://crbug.com/62328.
    base::ThreadRestrictions::ScopedAllowIO allow_io;

    std::wstring lang;
    GoogleUpdateSettings::GetLanguage(&lang);
    if (lang.empty())
      lang = L"en";
    std::wstring brand;
    GoogleUpdateSettings::GetBrand(&brand);
    std::wstring referral;
    GoogleUpdateSettings::GetReferral(&referral);
    if (SendFinancialPing(brand, lang, referral, is_organic(brand))) {
      base::AutoLock lock(rlz_lock);
      access_values_state = ACCESS_VALUES_STALE;
      GoogleUpdateSettings::ClearReferral();
    }
  }

  // Organic brands all start with GG, such as GGCM.
  static bool is_organic(const std::wstring& brand) {
    return (brand.size() < 2) ? false : (brand.substr(0, 2) == L"GG");
  }
};

// Performs late RLZ initialization and RLZ event recording for chrome.
// This task needs to run on the UI thread.
class DelayedInitTask : public Task {
 public:
  explicit DelayedInitTask(bool first_run)
      : first_run_(first_run) {
  }
  virtual ~DelayedInitTask() {
  }
  virtual void Run() {
    // For non-interactive tests we don't do the rest of the initialization
    // because sometimes the very act of loading the dll causes QEMU to crash.
    if (::GetEnvironmentVariableW(ASCIIToWide(env_vars::kHeadless).c_str(),
                                  NULL, 0)) {
      return;
    }
    // For organic brandcodes do not use rlz at all. Empty brandcode usually
    // means a chromium install. This is ok.
    std::wstring brand;
    if (!GoogleUpdateSettings::GetBrand(&brand) || brand.empty() ||
        GoogleUpdateSettings::IsOrganic(brand))
      return;

    // Do the initial event recording if is the first run or if we have an
    // empty rlz which means we haven't got a chance to do it.
    std::wstring omnibox_rlz;
    RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &omnibox_rlz);

    if ((first_run_ || omnibox_rlz.empty()) && !already_ran_) {
      already_ran_ = true;

      // Record the installation of chrome.
      RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                     rlz_lib::CHROME_OMNIBOX,
                                     rlz_lib::INSTALL);
      RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                     rlz_lib::CHROME_HOME_PAGE,
                                     rlz_lib::INSTALL);
      // Record if google is the initial search provider.
      if (IsGoogleDefaultSearch()) {
        RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                       rlz_lib::CHROME_OMNIBOX,
                                       rlz_lib::SET_TO_GOOGLE);
      }
    }
    // Record first user interaction with the omnibox. We call this all the
    // time but the rlz lib should ingore all but the first one.
    if (OmniBoxUsageObserver::used()) {
      RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                     rlz_lib::CHROME_OMNIBOX,
                                     rlz_lib::FIRST_SEARCH);
    }
    // Schedule the daily RLZ ping.
    MessageLoop::current()->PostTask(FROM_HERE, new DailyPingTask());
  }

 private:
  bool IsGoogleDefaultSearch() {
    if (!g_browser_process)
      return false;
    FilePath user_data_dir;
    if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
      return false;
    ProfileManager* profile_manager = g_browser_process->profile_manager();
    Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
    if (!profile)
      return false;
    const TemplateURL* url_template =
        profile->GetTemplateURLModel()->GetDefaultSearchProvider();
    if (!url_template)
      return false;
    const TemplateURLRef* urlref = url_template->url();
    if (!urlref)
      return false;
    return urlref->HasGoogleBaseURLs();
  }

  // Flag that remembers if the delayed task already ran or not.  This is
  // needed only in the first_run case, since we don't want to record the
  // set-to-google event more than once.  We need to worry about this event
  // (and not the others) because it is not a stateful RLZ event.
  static bool already_ran_;

  bool first_run_;
  DISALLOW_IMPLICIT_CONSTRUCTORS(DelayedInitTask);
};

bool DelayedInitTask::already_ran_ = false;

void OmniBoxUsageObserver::Observe(NotificationType type,
                                   const NotificationSource& source,
                                   const NotificationDetails& details) {
  // Needs to be evaluated. See http://crbug.com/62328.
  base::ThreadRestrictions::ScopedAllowIO allow_io;

  // Try to record event now, else set the flag to try later when we
  // attempt the ping.
  if (!RLZTracker::RecordProductEvent(rlz_lib::CHROME,
                                      rlz_lib::CHROME_OMNIBOX,
                                      rlz_lib::FIRST_SEARCH))
    omnibox_used_ = true;
  else if (send_ping_immediately_) {
    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE, new DelayedInitTask(first_run_));
  }

  delete this;
}

}  // namespace

bool RLZTracker::InitRlzDelayed(bool first_run, int delay) {
  // A negative delay means that a financial ping should be sent immediately
  // after a first search is recorded, without waiting for the next restart
  // of chrome.  However, we only want this behaviour on first run.
  bool send_ping_immediately = false;
  if (delay < 0) {
    send_ping_immediately = true;
    delay = -delay;
  }

  // Maximum and minimum delay we would allow to be set through master
  // preferences. Somewhat arbitrary, may need to be adjusted in future.
  const int kMaxDelay = 200 * 1000;
  const int kMinDelay = 20 * 1000;

  delay *= 1000;
  delay = (delay < kMinDelay) ? kMinDelay : delay;
  delay = (delay > kMaxDelay) ? kMaxDelay : delay;

  if (!OmniBoxUsageObserver::used())
    new OmniBoxUsageObserver(first_run, send_ping_immediately);

  // Schedule the delayed init items.
  BrowserThread::PostDelayedTask(
      BrowserThread::FILE, FROM_HERE, new DelayedInitTask(first_run), delay);
  return true;
}

bool RLZTracker::RecordProductEvent(rlz_lib::Product product,
                                    rlz_lib::AccessPoint point,
                                    rlz_lib::Event event_id) {
  return rlz_lib::RecordProductEvent(product, point, event_id);
}

bool RLZTracker::ClearAllProductEvents(rlz_lib::Product product) {
  return rlz_lib::ClearAllProductEvents(product);
}

// We implement caching of the answer of get_access_point() if the request
// is for CHROME_OMNIBOX. If we had a successful ping, then we update the
// cached value.

bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point,
                                   std::wstring* rlz) {
  static std::wstring cached_ommibox_rlz;
  if (rlz_lib::CHROME_OMNIBOX == point) {
    base::AutoLock lock(rlz_lock);
    if (access_values_state == ACCESS_VALUES_FRESH) {
      *rlz = cached_ommibox_rlz;
      return true;
    }
  }

  // Make sure we don't access disk outside of the file context.
  // In such case we repost the task on the right thread and return error.
  if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
    // Caching of access points is now only implemented for the CHROME_OMNIBOX.
    // Thus it is not possible to call this function on another thread for
    // other access points until proper caching for these has been implemented
    // and the code that calls this function can handle synchronous fetching
    // of the access point.
    DCHECK_EQ(rlz_lib::CHROME_OMNIBOX, point);

    BrowserThread::PostTask(
        BrowserThread::FILE, FROM_HERE,
        NewRunnableFunction(&RLZTracker::GetAccessPointRlz,
                            point, &cached_ommibox_rlz));
      rlz->erase();
      return false;
  }

  char str_rlz[kMaxRlzLength + 1];
  if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength, NULL))
    return false;
  *rlz = ASCIIToWide(std::string(str_rlz));
  if (rlz_lib::CHROME_OMNIBOX == point) {
    base::AutoLock lock(rlz_lock);
    cached_ommibox_rlz.assign(*rlz);
    access_values_state = ACCESS_VALUES_FRESH;
  }
  return true;
}

// static
void RLZTracker::CleanupRlz() {
  OmniBoxUsageObserver::DeleteInstance();
}
<|endoftext|>


<commit_before>#include "opentelemetry/context/runtime_context.h"
#include "opentelemetry/context/context.h"

#include <gtest/gtest.h>

using namespace opentelemetry;

// Tests that GetCurrent returns the current context
TEST(RuntimeContextTest, GetCurrent)
{
  std::map<std::string, context::ContextValue> map_test = {{"test_key", (int64_t)123}};
  context::Context test_context                         = context::Context(map_test);
  auto old_context = context::RuntimeContext::Attach(test_context);
  EXPECT_EQ(context::RuntimeContext::GetCurrent(), test_context);
}

// Tests that detach resets the context to the previous context
TEST(RuntimeContextTest, Detach)
{
  std::map<std::string, context::ContextValue> map_test = {{"test_key", (int64_t)123}};
  context::Context test_context                         = context::Context(map_test);
  context::Context foo_context                          = context::Context(map_test);

  auto test_context_token = context::RuntimeContext::Attach(test_context);
  auto foo_context_token  = context::RuntimeContext::Attach(foo_context);

  foo_context_token.reset();
  EXPECT_EQ(context::RuntimeContext::GetCurrent(), test_context);
  test_context_token.reset();
}

// Tests that detach returns false when the wrong context is provided
TEST(RuntimeContextTest, DetachWrongContext)
{
  std::map<std::string, context::ContextValue> map_test = {{"test_key", (int64_t)123}};
  context::Context test_context                         = context::Context(map_test);
  auto test_context_token = context::RuntimeContext::Attach(test_context);
  EXPECT_TRUE(context::RuntimeContext::Detach(*test_context_token));
  EXPECT_FALSE(context::RuntimeContext::Detach(*test_context_token));
}

// Tests that the ThreadLocalContext can handle three attached contexts
TEST(RuntimeContextTest, ThreeAttachDetach)
{
  std::map<std::string, context::ContextValue> map_test = {{"test_key", (int64_t)123}};
  context::Context test_context                         = context::Context(map_test);
  context::Context foo_context                          = context::Context(map_test);
  context::Context other_context                        = context::Context(map_test);
  auto test_context_token  = context::RuntimeContext::Attach(test_context);
  auto foo_context_token   = context::RuntimeContext::Attach(foo_context);
  auto other_context_token = context::RuntimeContext::Attach(other_context);

  EXPECT_TRUE(context::RuntimeContext::Detach(*other_context_token));
  EXPECT_TRUE(context::RuntimeContext::Detach(*foo_context_token));
  EXPECT_TRUE(context::RuntimeContext::Detach(*test_context_token));
}

// Tests that SetValue returns a context with the passed in data and the
// RuntimeContext data when a context is not passed into the
// RuntimeContext::SetValue method.
TEST(RuntimeContextTest, SetValueRuntimeContext)
{
  context::Context foo_context  = context::Context("foo_key", (int64_t)596);
  auto old_context_token        = context::RuntimeContext::Attach(foo_context);
  context::Context test_context = context::RuntimeContext::SetValue("test_key", (int64_t)123);
  EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("test_key")), 123);
  EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("foo_key")), 596);
}

// Tests that SetValue returns a context with the passed in data and the
// passed in context data when a context* is passed into the
// RuntimeContext::SetValue method.
TEST(RuntimeContextTest, SetValueOtherContext)
{
  context::Context foo_context = context::Context("foo_key", (int64_t)596);
  context::Context test_context =
      context::RuntimeContext::SetValue("test_key", (int64_t)123, &foo_context);
  EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("test_key")), 123);
  EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("foo_key")), 596);
}

// Tests that SetValue returns the ContextValue associated with the
// passed in string and the current Runtime Context
TEST(RuntimeContextTest, GetValueRuntimeContext)
{
  context::Context foo_context = context::Context("foo_key", (int64_t)596);
  auto old_context_token       = context::RuntimeContext::Attach(foo_context);
  EXPECT_EQ(nostd::get<int64_t>(context::RuntimeContext::GetValue("foo_key")), 596);
}

// Tests that SetValue returns the ContextValue associated with the
// passed in string and the passed in context
TEST(RuntimeContextTest, GetValueOtherContext)
{
  context::Context foo_context = context::Context("foo_key", (int64_t)596);
  EXPECT_EQ(nostd::get<int64_t>(context::RuntimeContext::GetValue("foo_key", &foo_context)), 596);
}

// Test that any possible order of context detaching doesn't mess up the stack.
TEST(RuntimeContextTest, DetachOutOfOrder)
{
  std::vector<size_t> indices;
  indices.push_back(0);
  indices.push_back(1);
  indices.push_back(2);
  indices.push_back(3);

  std::vector<context::Context> contexts;
  for (auto i : indices)
  {
    contexts.push_back(context::Context("index", i));
  }

  do
  {
    std::vector<nostd::unique_ptr<context::Token>> tokens;

    for (auto &c : contexts)
    {
      tokens.push_back(context::RuntimeContext::Attach(c));
    }

    for (size_t i : indices)
    {
      auto token = std::move(tokens.at(i));
      context::RuntimeContext::Detach(*token);
    }

    EXPECT_EQ(context::RuntimeContext::GetCurrent(), context::Context());

  } while (std::next_permutation(indices.begin(), indices.end()));
}
<commit_msg>Fix 32bit build error (#641)<commit_after>#include "opentelemetry/context/runtime_context.h"
#include "opentelemetry/context/context.h"

#include <gtest/gtest.h>

using namespace opentelemetry;

// Tests that GetCurrent returns the current context
TEST(RuntimeContextTest, GetCurrent)
{
  std::map<std::string, context::ContextValue> map_test = {{"test_key", (int64_t)123}};
  context::Context test_context                         = context::Context(map_test);
  auto old_context = context::RuntimeContext::Attach(test_context);
  EXPECT_EQ(context::RuntimeContext::GetCurrent(), test_context);
}

// Tests that detach resets the context to the previous context
TEST(RuntimeContextTest, Detach)
{
  std::map<std::string, context::ContextValue> map_test = {{"test_key", (int64_t)123}};
  context::Context test_context                         = context::Context(map_test);
  context::Context foo_context                          = context::Context(map_test);

  auto test_context_token = context::RuntimeContext::Attach(test_context);
  auto foo_context_token  = context::RuntimeContext::Attach(foo_context);

  foo_context_token.reset();
  EXPECT_EQ(context::RuntimeContext::GetCurrent(), test_context);
  test_context_token.reset();
}

// Tests that detach returns false when the wrong context is provided
TEST(RuntimeContextTest, DetachWrongContext)
{
  std::map<std::string, context::ContextValue> map_test = {{"test_key", (int64_t)123}};
  context::Context test_context                         = context::Context(map_test);
  auto test_context_token = context::RuntimeContext::Attach(test_context);
  EXPECT_TRUE(context::RuntimeContext::Detach(*test_context_token));
  EXPECT_FALSE(context::RuntimeContext::Detach(*test_context_token));
}

// Tests that the ThreadLocalContext can handle three attached contexts
TEST(RuntimeContextTest, ThreeAttachDetach)
{
  std::map<std::string, context::ContextValue> map_test = {{"test_key", (int64_t)123}};
  context::Context test_context                         = context::Context(map_test);
  context::Context foo_context                          = context::Context(map_test);
  context::Context other_context                        = context::Context(map_test);
  auto test_context_token  = context::RuntimeContext::Attach(test_context);
  auto foo_context_token   = context::RuntimeContext::Attach(foo_context);
  auto other_context_token = context::RuntimeContext::Attach(other_context);

  EXPECT_TRUE(context::RuntimeContext::Detach(*other_context_token));
  EXPECT_TRUE(context::RuntimeContext::Detach(*foo_context_token));
  EXPECT_TRUE(context::RuntimeContext::Detach(*test_context_token));
}

// Tests that SetValue returns a context with the passed in data and the
// RuntimeContext data when a context is not passed into the
// RuntimeContext::SetValue method.
TEST(RuntimeContextTest, SetValueRuntimeContext)
{
  context::Context foo_context  = context::Context("foo_key", (int64_t)596);
  auto old_context_token        = context::RuntimeContext::Attach(foo_context);
  context::Context test_context = context::RuntimeContext::SetValue("test_key", (int64_t)123);
  EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("test_key")), 123);
  EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("foo_key")), 596);
}

// Tests that SetValue returns a context with the passed in data and the
// passed in context data when a context* is passed into the
// RuntimeContext::SetValue method.
TEST(RuntimeContextTest, SetValueOtherContext)
{
  context::Context foo_context = context::Context("foo_key", (int64_t)596);
  context::Context test_context =
      context::RuntimeContext::SetValue("test_key", (int64_t)123, &foo_context);
  EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("test_key")), 123);
  EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("foo_key")), 596);
}

// Tests that SetValue returns the ContextValue associated with the
// passed in string and the current Runtime Context
TEST(RuntimeContextTest, GetValueRuntimeContext)
{
  context::Context foo_context = context::Context("foo_key", (int64_t)596);
  auto old_context_token       = context::RuntimeContext::Attach(foo_context);
  EXPECT_EQ(nostd::get<int64_t>(context::RuntimeContext::GetValue("foo_key")), 596);
}

// Tests that SetValue returns the ContextValue associated with the
// passed in string and the passed in context
TEST(RuntimeContextTest, GetValueOtherContext)
{
  context::Context foo_context = context::Context("foo_key", (int64_t)596);
  EXPECT_EQ(nostd::get<int64_t>(context::RuntimeContext::GetValue("foo_key", &foo_context)), 596);
}

// Test that any possible order of context detaching doesn't mess up the stack.
TEST(RuntimeContextTest, DetachOutOfOrder)
{
  std::vector<size_t> indices;
  indices.push_back(0);
  indices.push_back(1);
  indices.push_back(2);
  indices.push_back(3);

  std::vector<context::Context> contexts;
  for (auto i : indices)
  {
    contexts.push_back(context::Context("index", (int64_t)i));
  }

  do
  {
    std::vector<nostd::unique_ptr<context::Token>> tokens;

    for (auto &c : contexts)
    {
      tokens.push_back(context::RuntimeContext::Attach(c));
    }

    for (size_t i : indices)
    {
      auto token = std::move(tokens.at(i));
      context::RuntimeContext::Detach(*token);
    }

    EXPECT_EQ(context::RuntimeContext::GetCurrent(), context::Context());

  } while (std::next_permutation(indices.begin(), indices.end()));
}
<|endoftext|>


<commit_before>AliAnalysisTask *AddTaskTender(Bool_t useV0=kFALSE,
                               Bool_t useTPC=kTRUE,
                               Bool_t useTOF=kTRUE,
                               Bool_t useTRD=kTRUE,
                               Bool_t usePID=kTRUE,
                               Bool_t useVTX=kTRUE,
                               Bool_t useT0=kTRUE,
                               Bool_t useEmc=kFALSE,
			       Bool_t usePtFix=kFALSE)
{
  if (!(useV0 | useTPC | useTOF | useTRD | usePID | useVTX | useEmc)) {
     ::Error("AddTaskTender", "No supply added to tender, so tender not created");
     return 0;
  }
  //get the current analysis manager
  Bool_t checkEvtSelection = useV0;
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskTender", "No analysis manager found.");
    return 0;
  }
  // currently don't accept AOD input
  if (!mgr->GetInputEventHandler()->InheritsFrom(AliESDInputHandler::Class())) {
    ::Error("AddTask_tender_Tender","The analysis tender only works with ESD input!");
    return 0;
  }

  //========= Add tender to the ANALYSIS manager and set default storage =====
  AliTender *tender=new AliTender("AnalysisTender");
  tender->SetCheckEventSelection(checkEvtSelection);
  tender->SetDefaultCDBStorage("raw://");
  mgr->AddTask(tender);
  if (checkEvtSelection) {
    if (mgr->GetTasks()->First() != (TObject*)tender ) {
      TString firstName(mgr->GetTasks()->First()->GetName());
      Bool_t isSecond=(mgr->GetTasks()->At(1) == (TObject*)tender);
      if (! (firstName=="PIDResponseTask" && isSecond )){
        Fatal("AddTaskTender","When setting the tender to check the event selection, it has to be the first wagon, or the first after the PID Response!");
        return NULL;
      }
    }
  }

  //========= Attach VZERO supply ======

  if (useV0) {
     AliVZEROTenderSupply *vzeroSupply=new AliVZEROTenderSupply("VZEROtender");
     vzeroSupply->SetDebug(kFALSE);
     tender->AddSupply(vzeroSupply);
  }

  //========= Attach TPC supply ======
  if (useTPC) {
     AliTPCTenderSupply *tpcSupply=new AliTPCTenderSupply("TPCtender");
     tpcSupply->SetDebugLevel(2);
     //tpcSupply->SetMip(50.);
     tender->AddSupply(tpcSupply);
  }

  //========= Attach track 1/pt correction supply ======
  if (usePtFix) {
     AliTrackFixTenderSupply *trfixSupply=new AliTrackFixTenderSupply("PTInvFix");
     //trfixSupply->SetDebugLevel(2);
     tender->AddSupply(trfixSupply);
  }

  //========= Attach T0 supply ======
  if (useT0) {
    AliT0TenderSupply *t0Tender = new AliT0TenderSupply("T0tender");
    t0Tender ->SetPass4LHC11aCorrection(kTRUE);
    tender->AddSupply(t0Tender);
  }

  //========= Attach TOF supply ======
  if (useTOF) {
    AliTOFTenderSupply *tofTender = new AliTOFTenderSupply("TOFtender");
    tender->AddSupply(tofTender);
 }

  //========= Attach TRD supply ======
  if (useTRD) {
    AliTRDTenderSupply *trdSupply=new AliTRDTenderSupply("TRDtender");
    trdSupply->SetLoadReferencesFromCDB();
    // Mask Bad chambers
    trdSupply->AddBadChamber(265);      // low drift
    trdSupply->AddBadChamber(50);
    trdSupply->AddBadChamber(524);      // low drift
    trdSupply->AddBadChamber(32);       // intermediate gain
    trdSupply->AddBadChamber(15);
    trdSupply->AddBadChamber(231);      // low gain
    trdSupply->AddBadChamber(273);      // intermediate gain
    trdSupply->AddBadChamber(532);
    trdSupply->AddBadChamber(5);        // low drift
    trdSupply->AddBadChamber(227);
    trdSupply->AddBadChamber(287);      // low drift
    trdSupply->AddBadChamber(212);      // intermediate gain
    trdSupply->AddBadChamber(228);      // low gain
    trdSupply->AddBadChamber(52);       // low gain
    trdSupply->AddBadChamber(169);      // low drift
    trdSupply->AddBadChamber(236);      // low drift

    trdSupply->SetPIDmethod(AliTRDTenderSupply::k1DLQpid);
    trdSupply->SetNormalizationFactor(1./7.603);
    tender->AddSupply(trdSupply);
  }

  //========= Attach PID supply ======
  if (usePID) {
    tender->AddSupply(new AliPIDTenderSupply("PIDtender"));
  }

  //========= Attach Primary Vertex supply ======
  if (useVTX) {
    tender->AddSupply(new AliVtxTenderSupply("PriVtxtender"));
  }

  //========= Attach EMCAL supply ======
  if (useEmc) {
    AliEMCALTenderSupply *emcSupply = new AliEMCALTenderSupply("EmcTender");
    emcSupply->SetDefaults();
    tender->AddSupply(emcSupply);
  }

  //================================================
  //              data containers
  //================================================

    //            define output containers, please use 'username'_'somename'
  AliAnalysisDataContainer *coutput1 =
      mgr->CreateContainer("tender_event", AliESDEvent::Class(),
                           AliAnalysisManager::kExchangeContainer,"default_tender");

  //           connect containers
  mgr->ConnectInput  (tender,  0, mgr->GetCommonInputContainer() );
  mgr->ConnectOutput (tender,  1, coutput1);

  return tender;
}
<commit_msg>Added missing check for T0 and PtFix supplies<commit_after>AliAnalysisTask *AddTaskTender(Bool_t useV0=kFALSE,
                               Bool_t useTPC=kTRUE,
                               Bool_t useTOF=kTRUE,
                               Bool_t useTRD=kTRUE,
                               Bool_t usePID=kTRUE,
                               Bool_t useVTX=kTRUE,
                               Bool_t useT0=kTRUE,
                               Bool_t useEmc=kFALSE,
                               Bool_t usePtFix=kFALSE)
{
  if (!(useV0 | useTPC | useTOF | useTRD | usePID | useVTX | | useT0 | useEmc | usePtFix)) {
     ::Error("AddTaskTender", "No supply added to tender, so tender not created");
     return 0;
  }
  //get the current analysis manager
  Bool_t checkEvtSelection = useV0;
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskTender", "No analysis manager found.");
    return 0;
  }
  // currently don't accept AOD input
  if (!mgr->GetInputEventHandler()->InheritsFrom(AliESDInputHandler::Class())) {
    ::Error("AddTask_tender_Tender","The analysis tender only works with ESD input!");
    return 0;
  }

  //========= Add tender to the ANALYSIS manager and set default storage =====
  AliTender *tender=new AliTender("AnalysisTender");
  tender->SetCheckEventSelection(checkEvtSelection);
  tender->SetDefaultCDBStorage("raw://");
  mgr->AddTask(tender);
  if (checkEvtSelection) {
    if (mgr->GetTasks()->First() != (TObject*)tender ) {
      TString firstName(mgr->GetTasks()->First()->GetName());
      Bool_t isSecond=(mgr->GetTasks()->At(1) == (TObject*)tender);
      if (! (firstName=="PIDResponseTask" && isSecond )){
        Fatal("AddTaskTender","When setting the tender to check the event selection, it has to be the first wagon, or the first after the PID Response!");
        return NULL;
      }
    }
  }

  //========= Attach VZERO supply ======

  if (useV0) {
     AliVZEROTenderSupply *vzeroSupply=new AliVZEROTenderSupply("VZEROtender");
     vzeroSupply->SetDebug(kFALSE);
     tender->AddSupply(vzeroSupply);
  }

  //========= Attach TPC supply ======
  if (useTPC) {
     AliTPCTenderSupply *tpcSupply=new AliTPCTenderSupply("TPCtender");
     tpcSupply->SetDebugLevel(2);
     //tpcSupply->SetMip(50.);
     tender->AddSupply(tpcSupply);
  }

  //========= Attach track 1/pt correction supply ======
  if (usePtFix) {
     AliTrackFixTenderSupply *trfixSupply=new AliTrackFixTenderSupply("PTInvFix");
     //trfixSupply->SetDebugLevel(2);
     tender->AddSupply(trfixSupply);
  }

  //========= Attach T0 supply ======
  if (useT0) {
    AliT0TenderSupply *t0Tender = new AliT0TenderSupply("T0tender");
    t0Tender ->SetPass4LHC11aCorrection(kTRUE);
    tender->AddSupply(t0Tender);
  }

  //========= Attach TOF supply ======
  if (useTOF) {
    AliTOFTenderSupply *tofTender = new AliTOFTenderSupply("TOFtender");
    tender->AddSupply(tofTender);
 }

  //========= Attach TRD supply ======
  if (useTRD) {
    AliTRDTenderSupply *trdSupply=new AliTRDTenderSupply("TRDtender");
    trdSupply->SetLoadReferencesFromCDB();
    // Mask Bad chambers
    trdSupply->AddBadChamber(265);      // low drift
    trdSupply->AddBadChamber(50);
    trdSupply->AddBadChamber(524);      // low drift
    trdSupply->AddBadChamber(32);       // intermediate gain
    trdSupply->AddBadChamber(15);
    trdSupply->AddBadChamber(231);      // low gain
    trdSupply->AddBadChamber(273);      // intermediate gain
    trdSupply->AddBadChamber(532);
    trdSupply->AddBadChamber(5);        // low drift
    trdSupply->AddBadChamber(227);
    trdSupply->AddBadChamber(287);      // low drift
    trdSupply->AddBadChamber(212);      // intermediate gain
    trdSupply->AddBadChamber(228);      // low gain
    trdSupply->AddBadChamber(52);       // low gain
    trdSupply->AddBadChamber(169);      // low drift
    trdSupply->AddBadChamber(236);      // low drift

    trdSupply->SetPIDmethod(AliTRDTenderSupply::k1DLQpid);
    trdSupply->SetNormalizationFactor(1./7.603);
    tender->AddSupply(trdSupply);
  }

  //========= Attach PID supply ======
  if (usePID) {
    tender->AddSupply(new AliPIDTenderSupply("PIDtender"));
  }

  //========= Attach Primary Vertex supply ======
  if (useVTX) {
    tender->AddSupply(new AliVtxTenderSupply("PriVtxtender"));
  }

  //========= Attach EMCAL supply ======
  if (useEmc) {
    AliEMCALTenderSupply *emcSupply = new AliEMCALTenderSupply("EmcTender");
    emcSupply->SetDefaults();
    tender->AddSupply(emcSupply);
  }

  //================================================
  //              data containers
  //================================================

    //            define output containers, please use 'username'_'somename'
  AliAnalysisDataContainer *coutput1 =
      mgr->CreateContainer("tender_event", AliESDEvent::Class(),
                           AliAnalysisManager::kExchangeContainer,"default_tender");

  //           connect containers
  mgr->ConnectInput  (tender,  0, mgr->GetCommonInputContainer() );
  mgr->ConnectOutput (tender,  1, coutput1);

  return tender;
}
<|endoftext|>


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

/*
VULKAN_SAMPLE_SHORT_DESCRIPTION
Use a texel buffer to draw a magenta triangle
*/

#include <util_init.hpp>
#include <assert.h>
#include <string.h>
#include <cstdlib>

/* For this sample, we'll start with GLSL so the shader function is plain */
/* and then use the glslang GLSLtoSPV utility to convert it to SPIR-V for */
/* the driver.  We do this for clarity rather than using pre-compiled     */
/* SPIR-V                                                                 */

static const char *vertShaderText =
    "#version 400\n"
    "#extension GL_ARB_separate_shader_objects : enable\n"
    "#extension GL_ARB_shading_language_420pack : enable\n"
    "layout (binding = 0) uniform samplerBuffer texels;\n"
    "layout (location = 0) out vec4 outColor;\n"
    "vec2 vertices[3];\n"
    "float r;\n"
    "float g;\n"
    "float b;\n"
    "out gl_PerVertex { \n"
    "    vec4 gl_Position;\n"
    "};\n"
    "void main() {\n"
    "    r = texelFetch(texels, 0).r;\n"
    "    g = texelFetch(texels, 1).r;\n"
    "    b = texelFetch(texels, 2).r;\n"
    "    outColor = vec4(r, g, b, 1.0);\n"
    "    vertices[0] = vec2(-1.0, -1.0);\n"
    "    vertices[1] = vec2( 1.0, -1.0);\n"
    "    vertices[2] = vec2( 0.0,  1.0);\n"
    "    gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n"
    "}\n";

static const char *fragShaderText =
    "#version 400\n"
    "#extension GL_ARB_separate_shader_objects : enable\n"
    "#extension GL_ARB_shading_language_420pack : enable\n"
    "layout (location = 0) in vec4 color;\n"
    "layout (location = 0) out vec4 outColor;\n"
    "void main() {\n"
    "   outColor = color;\n"
    "}\n";

int main(int argc, char *argv[]) {
    VkResult U_ASSERT_ONLY res;
    bool U_ASSERT_ONLY pass;
    struct sample_info info = {};
    char sample_title[] = "Texel Buffer Sample";
    float texels[] = {1.0, 0.0, 1.0};
    const bool depthPresent = false;
    const bool vertexPresent = false;

    process_command_line_args(info, argc, argv);
    init_global_layer_properties(info);
    init_instance_extension_names(info);
    init_device_extension_names(info);
    init_instance(info, sample_title);
    init_enumerate_device(info);

    if (info.gpu_props.limits.maxTexelBufferElements < 4) {
        std::cout << "maxTexelBufferElements too small\n";
        exit(-1);
    }

    VkFormatProperties props;
    vkGetPhysicalDeviceFormatProperties(info.gpus[0], VK_FORMAT_R32_SFLOAT,
                                        &props);
    if (!(props.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) {
        std::cout << "R32_SFLOAT format unsupported for texel buffer\n";
        exit(-1);
    }

    init_window_size(info, 500, 500);
    init_connection(info);
    init_window(info);
    init_swapchain_extension(info);
    init_device(info);
    init_command_pool(info);
    init_command_buffer(info);
    execute_begin_command_buffer(info);
    init_device_queue(info);
    init_swap_chain(info);

    VkBufferCreateInfo buf_info = {};
    buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    buf_info.pNext = NULL;
    buf_info.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
    buf_info.size = sizeof(texels);
    buf_info.queueFamilyIndexCount = 0;
    buf_info.pQueueFamilyIndices = NULL;
    buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    buf_info.flags = 0;
    VkBuffer texelBuf;
    res = vkCreateBuffer(info.device, &buf_info, NULL, &texelBuf);
    assert(res == VK_SUCCESS);

    VkMemoryRequirements mem_reqs;
    vkGetBufferMemoryRequirements(info.device, texelBuf, &mem_reqs);

    VkMemoryAllocateInfo alloc_info = {};
    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    alloc_info.pNext = NULL;
    alloc_info.memoryTypeIndex = 0;

    alloc_info.allocationSize = mem_reqs.size;
    pass = memory_type_from_properties(info, mem_reqs.memoryTypeBits,
                                       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
                                       &alloc_info.memoryTypeIndex);
    assert(pass);

    VkDeviceMemory texelMem;
    res = vkAllocateMemory(info.device, &alloc_info, NULL, &texelMem);
    assert(res == VK_SUCCESS);

    uint8_t *pData;
    res = vkMapMemory(info.device, texelMem, 0, mem_reqs.size, 0,
                      (void **)&pData);
    assert(res == VK_SUCCESS);

    memcpy(pData, &texels, sizeof(texels));

    vkUnmapMemory(info.device, texelMem);

    res = vkBindBufferMemory(info.device, texelBuf, texelMem, 0);
    assert(res == VK_SUCCESS);

    VkBufferView texel_view;
    VkBufferViewCreateInfo view_info = {};
    view_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
    view_info.pNext = NULL;
    view_info.buffer = texelBuf;
    view_info.format = VK_FORMAT_R32_SFLOAT;
    view_info.offset = 0;
    view_info.range = sizeof(texels);
    vkCreateBufferView(info.device, &view_info, NULL, &texel_view);

    VkDescriptorBufferInfo texel_buffer_info = {};
    texel_buffer_info.buffer = texelBuf;
    texel_buffer_info.offset = 0;
    texel_buffer_info.range = sizeof(texels);

    // init_descriptor_and_pipeline_layouts(info, false);
    VkDescriptorSetLayoutBinding layout_bindings[1];
    layout_bindings[0].binding = 0;
    layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
    layout_bindings[0].descriptorCount = 1;
    layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
    layout_bindings[0].pImmutableSamplers = NULL;

    /* Next take layout bindings and use them to create a descriptor set layout
     */
    VkDescriptorSetLayoutCreateInfo descriptor_layout = {};
    descriptor_layout.sType =
        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
    descriptor_layout.pNext = NULL;
    descriptor_layout.bindingCount = 1;
    descriptor_layout.pBindings = layout_bindings;

    info.desc_layout.resize(NUM_DESCRIPTOR_SETS);
    res = vkCreateDescriptorSetLayout(info.device, &descriptor_layout, NULL,
                                      info.desc_layout.data());
    assert(res == VK_SUCCESS);

    /* Now use the descriptor layout to create a pipeline layout */
    VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {};
    pPipelineLayoutCreateInfo.sType =
        VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
    pPipelineLayoutCreateInfo.pNext = NULL;
    pPipelineLayoutCreateInfo.pushConstantRangeCount = 0;
    pPipelineLayoutCreateInfo.pPushConstantRanges = NULL;
    pPipelineLayoutCreateInfo.setLayoutCount = NUM_DESCRIPTOR_SETS;
    pPipelineLayoutCreateInfo.pSetLayouts = info.desc_layout.data();

    res = vkCreatePipelineLayout(info.device, &pPipelineLayoutCreateInfo, NULL,
                                 &info.pipeline_layout);
    assert(res == VK_SUCCESS);

    init_renderpass(info, depthPresent);
    init_shaders(info, vertShaderText, fragShaderText);
    init_framebuffers(info, depthPresent);

    VkDescriptorPoolSize type_count[1];
    type_count[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
    type_count[0].descriptorCount = 1;

    VkDescriptorPoolCreateInfo descriptor_pool = {};
    descriptor_pool.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
    descriptor_pool.pNext = NULL;
    descriptor_pool.maxSets = 1;
    descriptor_pool.poolSizeCount = 1;
    descriptor_pool.pPoolSizes = type_count;

    res = vkCreateDescriptorPool(info.device, &descriptor_pool, NULL,
                                 &info.desc_pool);
    assert(res == VK_SUCCESS);

    VkDescriptorSetAllocateInfo desc_alloc_info[1];
    desc_alloc_info[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
    desc_alloc_info[0].pNext = NULL;
    desc_alloc_info[0].descriptorPool = info.desc_pool;
    desc_alloc_info[0].descriptorSetCount = NUM_DESCRIPTOR_SETS;
    desc_alloc_info[0].pSetLayouts = info.desc_layout.data();

    /* Allocate descriptor set with UNIFORM_BUFFER_DYNAMIC */
    info.desc_set.resize(NUM_DESCRIPTOR_SETS);
    res = vkAllocateDescriptorSets(info.device, desc_alloc_info,
                                   info.desc_set.data());
    assert(res == VK_SUCCESS);

    VkWriteDescriptorSet writes[1];

    writes[0] = {};
    writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    writes[0].dstSet = info.desc_set[0];
    writes[0].dstBinding = 0;
    writes[0].descriptorCount = 1;
    writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
    writes[0].pBufferInfo = &texel_buffer_info;
    writes[0].pTexelBufferView = &texel_view;
    writes[0].dstArrayElement = 0;

    vkUpdateDescriptorSets(info.device, 1, writes, 0, NULL);

    init_pipeline_cache(info);
    init_pipeline(info, depthPresent, vertexPresent);

    /* VULKAN_KEY_START */

    VkClearValue clear_values[2];
    clear_values[0].color.float32[0] = 0.2f;
    clear_values[0].color.float32[1] = 0.2f;
    clear_values[0].color.float32[2] = 0.2f;
    clear_values[0].color.float32[3] = 0.2f;
    clear_values[1].depthStencil.depth = 1.0f;
    clear_values[1].depthStencil.stencil = 0;

    VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo;
    presentCompleteSemaphoreCreateInfo.sType =
        VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
    presentCompleteSemaphoreCreateInfo.pNext = NULL;
    presentCompleteSemaphoreCreateInfo.flags = 0;

    res = vkCreateSemaphore(info.device, &presentCompleteSemaphoreCreateInfo,
                            NULL, &info.presentCompleteSemaphore);
    assert(res == VK_SUCCESS);

    // Get the index of the next available swapchain image:
    res = vkAcquireNextImageKHR(info.device, info.swap_chain, UINT64_MAX,
                                info.presentCompleteSemaphore, NULL,
                                &info.current_buffer);
    // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR
    // return codes
    assert(res == VK_SUCCESS);

    VkRenderPassBeginInfo rp_begin;
    rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    rp_begin.pNext = NULL;
    rp_begin.renderPass = info.render_pass;
    rp_begin.framebuffer = info.framebuffers[info.current_buffer];
    rp_begin.renderArea.offset.x = 0;
    rp_begin.renderArea.offset.y = 0;
    rp_begin.renderArea.extent.width = info.width;
    rp_begin.renderArea.extent.height = info.height;
    rp_begin.clearValueCount = 2;
    rp_begin.pClearValues = clear_values;

    vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);

    vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline);

    vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
                            info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS,
                            info.desc_set.data(), 0, NULL);

    init_viewports(info);
    init_scissors(info);

    vkCmdDraw(info.cmd, 3, 1, 0, 0);

    vkCmdEndRenderPass(info.cmd);

    execute_pre_present_barrier(info);

    res = vkEndCommandBuffer(info.cmd);
    const VkCommandBuffer cmd_bufs[] = {info.cmd};

    VkFenceCreateInfo fenceInfo;
    VkFence drawFence;
    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
    fenceInfo.pNext = NULL;
    fenceInfo.flags = 0;
    vkCreateFence(info.device, &fenceInfo, NULL, &drawFence);

    execute_queue_cmdbuf(info, cmd_bufs, drawFence);

    do {
        res =
            vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT);
    } while (res == VK_TIMEOUT);
    assert(res == VK_SUCCESS);

    execute_present_image(info);

    wait_seconds(1);
    /* VULKAN_KEY_END */
    if (info.save_images)
        write_ppm(info, "texelbuffer");

    vkDestroySemaphore(info.device, info.presentCompleteSemaphore, NULL);
    vkDestroyBufferView(info.device, texel_view, NULL);
    vkDestroyBuffer(info.device, texelBuf, NULL);
    vkFreeMemory(info.device, texelMem, NULL);
    destroy_pipeline(info);
    destroy_pipeline_cache(info);
    destroy_descriptor_pool(info);
    destroy_framebuffers(info);
    destroy_shaders(info);
    destroy_renderpass(info);
    destroy_descriptor_and_pipeline_layouts(info);
    destroy_swap_chain(info);
    destroy_command_buffer(info);
    destroy_command_pool(info);
    destroy_device(info);
    destroy_window(info);
    destroy_instance(info);
    return 0;
}
<commit_msg>Destroy fence in texelbuffer sample<commit_after>/*
 * Vulkan Samples
 *
 * Copyright (C) 2015-2016 Valve Corporation
 * Copyright (C) 2015-2016 LunarG, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/*
VULKAN_SAMPLE_SHORT_DESCRIPTION
Use a texel buffer to draw a magenta triangle
*/

#include <util_init.hpp>
#include <assert.h>
#include <string.h>
#include <cstdlib>

/* For this sample, we'll start with GLSL so the shader function is plain */
/* and then use the glslang GLSLtoSPV utility to convert it to SPIR-V for */
/* the driver.  We do this for clarity rather than using pre-compiled     */
/* SPIR-V                                                                 */

static const char *vertShaderText =
    "#version 400\n"
    "#extension GL_ARB_separate_shader_objects : enable\n"
    "#extension GL_ARB_shading_language_420pack : enable\n"
    "layout (binding = 0) uniform samplerBuffer texels;\n"
    "layout (location = 0) out vec4 outColor;\n"
    "vec2 vertices[3];\n"
    "float r;\n"
    "float g;\n"
    "float b;\n"
    "out gl_PerVertex { \n"
    "    vec4 gl_Position;\n"
    "};\n"
    "void main() {\n"
    "    r = texelFetch(texels, 0).r;\n"
    "    g = texelFetch(texels, 1).r;\n"
    "    b = texelFetch(texels, 2).r;\n"
    "    outColor = vec4(r, g, b, 1.0);\n"
    "    vertices[0] = vec2(-1.0, -1.0);\n"
    "    vertices[1] = vec2( 1.0, -1.0);\n"
    "    vertices[2] = vec2( 0.0,  1.0);\n"
    "    gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n"
    "}\n";

static const char *fragShaderText =
    "#version 400\n"
    "#extension GL_ARB_separate_shader_objects : enable\n"
    "#extension GL_ARB_shading_language_420pack : enable\n"
    "layout (location = 0) in vec4 color;\n"
    "layout (location = 0) out vec4 outColor;\n"
    "void main() {\n"
    "   outColor = color;\n"
    "}\n";

int main(int argc, char *argv[]) {
    VkResult U_ASSERT_ONLY res;
    bool U_ASSERT_ONLY pass;
    struct sample_info info = {};
    char sample_title[] = "Texel Buffer Sample";
    float texels[] = {1.0, 0.0, 1.0};
    const bool depthPresent = false;
    const bool vertexPresent = false;

    process_command_line_args(info, argc, argv);
    init_global_layer_properties(info);
    init_instance_extension_names(info);
    init_device_extension_names(info);
    init_instance(info, sample_title);
    init_enumerate_device(info);

    if (info.gpu_props.limits.maxTexelBufferElements < 4) {
        std::cout << "maxTexelBufferElements too small\n";
        exit(-1);
    }

    VkFormatProperties props;
    vkGetPhysicalDeviceFormatProperties(info.gpus[0], VK_FORMAT_R32_SFLOAT,
                                        &props);
    if (!(props.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) {
        std::cout << "R32_SFLOAT format unsupported for texel buffer\n";
        exit(-1);
    }

    init_window_size(info, 500, 500);
    init_connection(info);
    init_window(info);
    init_swapchain_extension(info);
    init_device(info);
    init_command_pool(info);
    init_command_buffer(info);
    execute_begin_command_buffer(info);
    init_device_queue(info);
    init_swap_chain(info);

    VkBufferCreateInfo buf_info = {};
    buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    buf_info.pNext = NULL;
    buf_info.usage = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
    buf_info.size = sizeof(texels);
    buf_info.queueFamilyIndexCount = 0;
    buf_info.pQueueFamilyIndices = NULL;
    buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    buf_info.flags = 0;
    VkBuffer texelBuf;
    res = vkCreateBuffer(info.device, &buf_info, NULL, &texelBuf);
    assert(res == VK_SUCCESS);

    VkMemoryRequirements mem_reqs;
    vkGetBufferMemoryRequirements(info.device, texelBuf, &mem_reqs);

    VkMemoryAllocateInfo alloc_info = {};
    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    alloc_info.pNext = NULL;
    alloc_info.memoryTypeIndex = 0;

    alloc_info.allocationSize = mem_reqs.size;
    pass = memory_type_from_properties(info, mem_reqs.memoryTypeBits,
                                       VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
                                       &alloc_info.memoryTypeIndex);
    assert(pass);

    VkDeviceMemory texelMem;
    res = vkAllocateMemory(info.device, &alloc_info, NULL, &texelMem);
    assert(res == VK_SUCCESS);

    uint8_t *pData;
    res = vkMapMemory(info.device, texelMem, 0, mem_reqs.size, 0,
                      (void **)&pData);
    assert(res == VK_SUCCESS);

    memcpy(pData, &texels, sizeof(texels));

    vkUnmapMemory(info.device, texelMem);

    res = vkBindBufferMemory(info.device, texelBuf, texelMem, 0);
    assert(res == VK_SUCCESS);

    VkBufferView texel_view;
    VkBufferViewCreateInfo view_info = {};
    view_info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
    view_info.pNext = NULL;
    view_info.buffer = texelBuf;
    view_info.format = VK_FORMAT_R32_SFLOAT;
    view_info.offset = 0;
    view_info.range = sizeof(texels);
    vkCreateBufferView(info.device, &view_info, NULL, &texel_view);

    VkDescriptorBufferInfo texel_buffer_info = {};
    texel_buffer_info.buffer = texelBuf;
    texel_buffer_info.offset = 0;
    texel_buffer_info.range = sizeof(texels);

    // init_descriptor_and_pipeline_layouts(info, false);
    VkDescriptorSetLayoutBinding layout_bindings[1];
    layout_bindings[0].binding = 0;
    layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
    layout_bindings[0].descriptorCount = 1;
    layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
    layout_bindings[0].pImmutableSamplers = NULL;

    /* Next take layout bindings and use them to create a descriptor set layout
     */
    VkDescriptorSetLayoutCreateInfo descriptor_layout = {};
    descriptor_layout.sType =
        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
    descriptor_layout.pNext = NULL;
    descriptor_layout.bindingCount = 1;
    descriptor_layout.pBindings = layout_bindings;

    info.desc_layout.resize(NUM_DESCRIPTOR_SETS);
    res = vkCreateDescriptorSetLayout(info.device, &descriptor_layout, NULL,
                                      info.desc_layout.data());
    assert(res == VK_SUCCESS);

    /* Now use the descriptor layout to create a pipeline layout */
    VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {};
    pPipelineLayoutCreateInfo.sType =
        VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
    pPipelineLayoutCreateInfo.pNext = NULL;
    pPipelineLayoutCreateInfo.pushConstantRangeCount = 0;
    pPipelineLayoutCreateInfo.pPushConstantRanges = NULL;
    pPipelineLayoutCreateInfo.setLayoutCount = NUM_DESCRIPTOR_SETS;
    pPipelineLayoutCreateInfo.pSetLayouts = info.desc_layout.data();

    res = vkCreatePipelineLayout(info.device, &pPipelineLayoutCreateInfo, NULL,
                                 &info.pipeline_layout);
    assert(res == VK_SUCCESS);

    init_renderpass(info, depthPresent);
    init_shaders(info, vertShaderText, fragShaderText);
    init_framebuffers(info, depthPresent);

    VkDescriptorPoolSize type_count[1];
    type_count[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
    type_count[0].descriptorCount = 1;

    VkDescriptorPoolCreateInfo descriptor_pool = {};
    descriptor_pool.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
    descriptor_pool.pNext = NULL;
    descriptor_pool.maxSets = 1;
    descriptor_pool.poolSizeCount = 1;
    descriptor_pool.pPoolSizes = type_count;

    res = vkCreateDescriptorPool(info.device, &descriptor_pool, NULL,
                                 &info.desc_pool);
    assert(res == VK_SUCCESS);

    VkDescriptorSetAllocateInfo desc_alloc_info[1];
    desc_alloc_info[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
    desc_alloc_info[0].pNext = NULL;
    desc_alloc_info[0].descriptorPool = info.desc_pool;
    desc_alloc_info[0].descriptorSetCount = NUM_DESCRIPTOR_SETS;
    desc_alloc_info[0].pSetLayouts = info.desc_layout.data();

    /* Allocate descriptor set with UNIFORM_BUFFER_DYNAMIC */
    info.desc_set.resize(NUM_DESCRIPTOR_SETS);
    res = vkAllocateDescriptorSets(info.device, desc_alloc_info,
                                   info.desc_set.data());
    assert(res == VK_SUCCESS);

    VkWriteDescriptorSet writes[1];

    writes[0] = {};
    writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
    writes[0].dstSet = info.desc_set[0];
    writes[0].dstBinding = 0;
    writes[0].descriptorCount = 1;
    writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
    writes[0].pBufferInfo = &texel_buffer_info;
    writes[0].pTexelBufferView = &texel_view;
    writes[0].dstArrayElement = 0;

    vkUpdateDescriptorSets(info.device, 1, writes, 0, NULL);

    init_pipeline_cache(info);
    init_pipeline(info, depthPresent, vertexPresent);

    /* VULKAN_KEY_START */

    VkClearValue clear_values[2];
    clear_values[0].color.float32[0] = 0.2f;
    clear_values[0].color.float32[1] = 0.2f;
    clear_values[0].color.float32[2] = 0.2f;
    clear_values[0].color.float32[3] = 0.2f;
    clear_values[1].depthStencil.depth = 1.0f;
    clear_values[1].depthStencil.stencil = 0;

    VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo;
    presentCompleteSemaphoreCreateInfo.sType =
        VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
    presentCompleteSemaphoreCreateInfo.pNext = NULL;
    presentCompleteSemaphoreCreateInfo.flags = 0;

    res = vkCreateSemaphore(info.device, &presentCompleteSemaphoreCreateInfo,
                            NULL, &info.presentCompleteSemaphore);
    assert(res == VK_SUCCESS);

    // Get the index of the next available swapchain image:
    res = vkAcquireNextImageKHR(info.device, info.swap_chain, UINT64_MAX,
                                info.presentCompleteSemaphore, NULL,
                                &info.current_buffer);
    // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR
    // return codes
    assert(res == VK_SUCCESS);

    VkRenderPassBeginInfo rp_begin;
    rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    rp_begin.pNext = NULL;
    rp_begin.renderPass = info.render_pass;
    rp_begin.framebuffer = info.framebuffers[info.current_buffer];
    rp_begin.renderArea.offset.x = 0;
    rp_begin.renderArea.offset.y = 0;
    rp_begin.renderArea.extent.width = info.width;
    rp_begin.renderArea.extent.height = info.height;
    rp_begin.clearValueCount = 2;
    rp_begin.pClearValues = clear_values;

    vkCmdBeginRenderPass(info.cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);

    vkCmdBindPipeline(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, info.pipeline);

    vkCmdBindDescriptorSets(info.cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
                            info.pipeline_layout, 0, NUM_DESCRIPTOR_SETS,
                            info.desc_set.data(), 0, NULL);

    init_viewports(info);
    init_scissors(info);

    vkCmdDraw(info.cmd, 3, 1, 0, 0);

    vkCmdEndRenderPass(info.cmd);

    execute_pre_present_barrier(info);

    res = vkEndCommandBuffer(info.cmd);
    const VkCommandBuffer cmd_bufs[] = {info.cmd};

    VkFenceCreateInfo fenceInfo;
    VkFence drawFence;
    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
    fenceInfo.pNext = NULL;
    fenceInfo.flags = 0;
    vkCreateFence(info.device, &fenceInfo, NULL, &drawFence);

    execute_queue_cmdbuf(info, cmd_bufs, drawFence);

    do {
        res =
            vkWaitForFences(info.device, 1, &drawFence, VK_TRUE, FENCE_TIMEOUT);
    } while (res == VK_TIMEOUT);
    assert(res == VK_SUCCESS);
    vkDestroyFence(info.device, drawFence, NULL);

    execute_present_image(info);

    wait_seconds(1);
    /* VULKAN_KEY_END */
    if (info.save_images)
        write_ppm(info, "texelbuffer");

    vkDestroySemaphore(info.device, info.presentCompleteSemaphore, NULL);
    vkDestroyBufferView(info.device, texel_view, NULL);
    vkDestroyBuffer(info.device, texelBuf, NULL);
    vkFreeMemory(info.device, texelMem, NULL);
    destroy_pipeline(info);
    destroy_pipeline_cache(info);
    destroy_descriptor_pool(info);
    destroy_framebuffers(info);
    destroy_shaders(info);
    destroy_renderpass(info);
    destroy_descriptor_and_pipeline_layouts(info);
    destroy_swap_chain(info);
    destroy_command_buffer(info);
    destroy_command_pool(info);
    destroy_device(info);
    destroy_window(info);
    destroy_instance(info);
    return 0;
}
<|endoftext|>