<commit_before>/*
  Copyright (c) DataStax, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "error_response.hpp"

#include "external.hpp"
#include "logger.hpp"
#include "serialization.hpp"

#include <iomanip>

using namespace datastax;
using namespace datastax::internal;
using namespace datastax::internal::core;

extern "C" {

void cass_error_result_free(const CassErrorResult* error_result) { error_result->dec_ref(); }

CassError cass_error_result_code(const CassErrorResult* error_result) {
  return static_cast<CassError>(CASS_ERROR(CASS_ERROR_SOURCE_SERVER, error_result->code()));
}

CassConsistency cass_error_result_consistency(const CassErrorResult* error_result) {
  return error_result->consistency();
}

cass_int32_t cass_error_result_responses_received(const CassErrorResult* error_result) {
  return error_result->received();
}

cass_int32_t cass_error_result_responses_required(const CassErrorResult* error_result) {
  return error_result->required();
}

cass_int32_t cass_error_result_num_failures(const CassErrorResult* error_result) {
  return error_result->num_failures();
}

cass_bool_t cass_error_result_data_present(const CassErrorResult* error_result) {
  return static_cast<cass_bool_t>(error_result->data_present());
}

CassWriteType cass_error_result_write_type(const CassErrorResult* error_result) {
  return error_result->write_type();
}

CassError cass_error_result_keyspace(const CassErrorResult* error_result, const char** keyspace,
                                     size_t* keyspace_length) {
  if (error_result->code() != CASS_ERROR_SERVER_ALREADY_EXISTS ||
      error_result->code() != CASS_ERROR_SERVER_FUNCTION_FAILURE) {
    return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
  }
  *keyspace = error_result->keyspace().data();
  *keyspace_length = error_result->keyspace().size();
  return CASS_OK;
}

CassError cass_error_result_table(const CassErrorResult* error_result, const char** table,
                                  size_t* table_length) {
  if (error_result->code() != CASS_ERROR_SERVER_ALREADY_EXISTS) {
    return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
  }
  *table = error_result->table().data();
  *table_length = error_result->table().size();
  return CASS_OK;
}

CassError cass_error_result_function(const CassErrorResult* error_result, const char** function,
                                     size_t* function_length) {
  if (error_result->code() != CASS_ERROR_SERVER_FUNCTION_FAILURE) {
    return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
  }
  *function = error_result->function().data();
  *function_length = error_result->function().size();
  return CASS_OK;
}

size_t cass_error_num_arg_types(const CassErrorResult* error_result) {
  return error_result->arg_types().size();
}

CassError cass_error_result_arg_type(const CassErrorResult* error_result, size_t index,
                                     const char** arg_type, size_t* arg_type_length) {
  if (error_result->code() != CASS_ERROR_SERVER_FUNCTION_FAILURE) {
    return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
  }
  if (index > error_result->arg_types().size()) {
    return CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS;
  }
  StringRef arg_type_ref = error_result->arg_types()[index];
  *arg_type = arg_type_ref.data();
  *arg_type_length = arg_type_ref.size();
  return CASS_OK;
}

} // extern "C"

String ErrorResponse::error_message() const {
  OStringStream ss;
  ss << "'" << message().to_string() << "'"
     << " (0x" << std::hex << std::uppercase << std::setw(8) << std::setfill('0')
     << CASS_ERROR(CASS_ERROR_SOURCE_SERVER, code()) << ")";
  return ss.str();
}

bool ErrorResponse::decode(Decoder& decoder) {
  decoder.set_type("error");
  CHECK_RESULT(decoder.decode_int32(code_));
  CHECK_RESULT(decoder.decode_string(&message_));

  switch (code_) {
    case CQL_ERROR_UNAVAILABLE:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_int32(received_));
      break;
    case CQL_ERROR_READ_TIMEOUT:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(received_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_byte(data_present_));
      break;
    case CQL_ERROR_WRITE_TIMEOUT:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(received_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_write_type(write_type_));
      break;
    case CQL_ERROR_READ_FAILURE:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(received_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_failures(failures_, num_failures_));
      CHECK_RESULT(decoder.decode_byte(data_present_));
      break;
    case CQL_ERROR_FUNCTION_FAILURE:
      CHECK_RESULT(decoder.decode_string(&keyspace_));
      CHECK_RESULT(decoder.decode_string(&function_));
      CHECK_RESULT(decoder.decode_stringlist(arg_types_));
      break;
    case CQL_ERROR_WRITE_FAILURE:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(received_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_failures(failures_, num_failures_));
      CHECK_RESULT(decoder.decode_write_type(write_type_));
      break;
    case CQL_ERROR_UNPREPARED:
      CHECK_RESULT(decoder.decode_string(&prepared_id_));
      break;
    case CQL_ERROR_ALREADY_EXISTS:
      CHECK_RESULT(decoder.decode_string(&keyspace_));
      CHECK_RESULT(decoder.decode_string(&table_));
      break;
  }

  decoder.maybe_log_remaining();
  return true;
}

bool check_error_or_invalid_response(const String& prefix, uint8_t expected_opcode,
                                     const Response* response) {
  if (response->opcode() == expected_opcode) {
    return false;
  }

  OStringStream ss;
  if (response->opcode() == CQL_OPCODE_ERROR) {
    ss << prefix << ": Error response "
       << static_cast<const ErrorResponse*>(response)->error_message();
  } else {
    ss << prefix << ": Unexpected opcode " << opcode_to_string(response->opcode());
  }

  LOG_ERROR("%s", ss.str().c_str());

  return true;
}
<commit_msg>CPP-849 Error result doesn't allow access to keyspace, table, and function data<commit_after>/*
  Copyright (c) DataStax, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "error_response.hpp"

#include "external.hpp"
#include "logger.hpp"
#include "serialization.hpp"

#include <iomanip>

using namespace datastax;
using namespace datastax::internal;
using namespace datastax::internal::core;

extern "C" {

void cass_error_result_free(const CassErrorResult* error_result) { error_result->dec_ref(); }

CassError cass_error_result_code(const CassErrorResult* error_result) {
  return static_cast<CassError>(CASS_ERROR(CASS_ERROR_SOURCE_SERVER, error_result->code()));
}

CassConsistency cass_error_result_consistency(const CassErrorResult* error_result) {
  return error_result->consistency();
}

cass_int32_t cass_error_result_responses_received(const CassErrorResult* error_result) {
  return error_result->received();
}

cass_int32_t cass_error_result_responses_required(const CassErrorResult* error_result) {
  return error_result->required();
}

cass_int32_t cass_error_result_num_failures(const CassErrorResult* error_result) {
  return error_result->num_failures();
}

cass_bool_t cass_error_result_data_present(const CassErrorResult* error_result) {
  return static_cast<cass_bool_t>(error_result->data_present());
}

CassWriteType cass_error_result_write_type(const CassErrorResult* error_result) {
  return error_result->write_type();
}

CassError cass_error_result_keyspace(const CassErrorResult* error_result, const char** keyspace,
                                     size_t* keyspace_length) {
  if (error_result->code() != CQL_ERROR_ALREADY_EXISTS &&
      error_result->code() != CQL_ERROR_FUNCTION_FAILURE) {
    return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
  }
  *keyspace = error_result->keyspace().data();
  *keyspace_length = error_result->keyspace().size();
  return CASS_OK;
}

CassError cass_error_result_table(const CassErrorResult* error_result, const char** table,
                                  size_t* table_length) {
  if (error_result->code() != CQL_ERROR_ALREADY_EXISTS) {
    return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
  }
  *table = error_result->table().data();
  *table_length = error_result->table().size();
  return CASS_OK;
}

CassError cass_error_result_function(const CassErrorResult* error_result, const char** function,
                                     size_t* function_length) {
  if (error_result->code() != CQL_ERROR_FUNCTION_FAILURE) {
    return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
  }
  *function = error_result->function().data();
  *function_length = error_result->function().size();
  return CASS_OK;
}

size_t cass_error_num_arg_types(const CassErrorResult* error_result) {
  return error_result->arg_types().size();
}

CassError cass_error_result_arg_type(const CassErrorResult* error_result, size_t index,
                                     const char** arg_type, size_t* arg_type_length) {
  if (error_result->code() != CQL_ERROR_FUNCTION_FAILURE) {
    return CASS_ERROR_LIB_INVALID_ERROR_RESULT_TYPE;
  }
  if (index > error_result->arg_types().size()) {
    return CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS;
  }
  StringRef arg_type_ref = error_result->arg_types()[index];
  *arg_type = arg_type_ref.data();
  *arg_type_length = arg_type_ref.size();
  return CASS_OK;
}

} // extern "C"

String ErrorResponse::error_message() const {
  OStringStream ss;
  ss << "'" << message().to_string() << "'"
     << " (0x" << std::hex << std::uppercase << std::setw(8) << std::setfill('0')
     << CASS_ERROR(CASS_ERROR_SOURCE_SERVER, code()) << ")";
  return ss.str();
}

bool ErrorResponse::decode(Decoder& decoder) {
  decoder.set_type("error");
  CHECK_RESULT(decoder.decode_int32(code_));
  CHECK_RESULT(decoder.decode_string(&message_));

  switch (code_) {
    case CQL_ERROR_UNAVAILABLE:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_int32(received_));
      break;
    case CQL_ERROR_READ_TIMEOUT:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(received_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_byte(data_present_));
      break;
    case CQL_ERROR_WRITE_TIMEOUT:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(received_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_write_type(write_type_));
      break;
    case CQL_ERROR_READ_FAILURE:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(received_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_failures(failures_, num_failures_));
      CHECK_RESULT(decoder.decode_byte(data_present_));
      break;
    case CQL_ERROR_FUNCTION_FAILURE:
      CHECK_RESULT(decoder.decode_string(&keyspace_));
      CHECK_RESULT(decoder.decode_string(&function_));
      CHECK_RESULT(decoder.decode_stringlist(arg_types_));
      break;
    case CQL_ERROR_WRITE_FAILURE:
      CHECK_RESULT(decoder.decode_uint16(cl_));
      CHECK_RESULT(decoder.decode_int32(received_));
      CHECK_RESULT(decoder.decode_int32(required_));
      CHECK_RESULT(decoder.decode_failures(failures_, num_failures_));
      CHECK_RESULT(decoder.decode_write_type(write_type_));
      break;
    case CQL_ERROR_UNPREPARED:
      CHECK_RESULT(decoder.decode_string(&prepared_id_));
      break;
    case CQL_ERROR_ALREADY_EXISTS:
      CHECK_RESULT(decoder.decode_string(&keyspace_));
      CHECK_RESULT(decoder.decode_string(&table_));
      break;
  }

  decoder.maybe_log_remaining();
  return true;
}

bool check_error_or_invalid_response(const String& prefix, uint8_t expected_opcode,
                                     const Response* response) {
  if (response->opcode() == expected_opcode) {
    return false;
  }

  OStringStream ss;
  if (response->opcode() == CQL_OPCODE_ERROR) {
    ss << prefix << ": Error response "
       << static_cast<const ErrorResponse*>(response)->error_message();
  } else {
    ss << prefix << ": Unexpected opcode " << opcode_to_string(response->opcode());
  }

  LOG_ERROR("%s", ss.str().c_str());

  return true;
}
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mylistmodel.h"

#include <QList>
#include <algorithm>
#include <QSettings>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    classes.append(Class());
    Class &c = classes.last();
    c.name = "Example class";

    QSettings set("_Vi","studentchooser");

    int n = set.value("preview/count", 0).toInt();
    for(int i = 0; i < n; ++i) {
        Student s;
        s.name =    set.value(QString("preview/%1/name"   ).arg(i), "???").toString();
        s.present = set.value(QString("preview/%1/present").arg(i), false).toBool() ? Qt::Checked : Qt::Unchecked;
        c.students.append(s);
    }

    lm = new MyListModel(&c.students, this);

    ui->students->setModel(lm);
    ui->attendants->setModel(lm);
    //ui->classes->setModel(lm);

    connect(lm,SIGNAL(dataChanged(QModelIndex,QModelIndex)),this,SLOT(on_attendants_itemChanged(QModelIndex,QModelIndex)));
    on_attendants_itemChanged(QModelIndex(), QModelIndex());
}

MainWindow::~MainWindow()
{
    delete ui;

    QSettings set("_Vi","studentchooser");
    set.setValue("preview/count", lm->rowCount(QModelIndex()));
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        bool present = (Qt::CheckState)lm->data(lm->index(i, 0), Qt::CheckStateRole).toUInt() == Qt::Checked;
        QString name = lm->data(lm->index(i, 0), Qt::DisplayRole).toString();
        set.setValue(QString("preview/%1/name"   ).arg(i), name);
        set.setValue(QString("preview/%1/present").arg(i), present);
    }

}

void MainWindow::on_pushButton_3_clicked()
{
    QModelIndex i = lm->addEntry("New student");
    ui->students->edit(i);
    ui->students->scrollTo(i);
}

void MainWindow::on_pushButton_4_clicked()
{
    foreach (QModelIndex i, ui->students->selectionModel()->selectedRows()) {
        lm->removeRow(i.row());
    }
}

void MainWindow::on_pushButton_5_clicked()
{
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        lm->setData(lm->index(i, 0), QVariant(Qt::Checked), Qt::CheckStateRole);
    }
}

void MainWindow::on_pushButton_6_clicked()
{
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        lm->setData(lm->index(i, 0), QVariant(Qt::Unchecked), Qt::CheckStateRole);
    }
}

void MainWindow::on_attendants_itemChanged(const QModelIndex &ib, const QModelIndex &ie)
{
    (void)ib; (void)ie;// FIXME: ineffectinve O(n*n) update
    int present = 0;
    int absent = 0;
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        if ((Qt::CheckState)lm->data(lm->index(i, 0), Qt::CheckStateRole).toUInt() == Qt::Checked) {
            ++present;
        } else {
            ++absent;
        }
    }
    ui->absenseStats->setText(tr("%1 students present, %2 students absent").arg(present).arg(absent));
}

QList<QString> MainWindow::getShuffledPresentStudents()
{
    QList<QString> presentStudents;
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        if ((Qt::CheckState)lm->data(lm->index(i, 0), Qt::CheckStateRole).toUInt() == Qt::Checked) {
            presentStudents.append(lm->data(lm->index(i, 0), Qt::DisplayRole).toString());
        }
    }

    std::random_shuffle(presentStudents.begin(), presentStudents.end());
    return presentStudents;
}

void MainWindow::doGrouping(QList<QString> s, int groupCount)
{
    int n = s.length();

    ui->result->clear();
    ui->result->setColumnCount(groupCount);
    ui->result->setRowCount(n/groupCount + 1);

    int x = 0;
    int currentColumn = 0;
    int currentRow = 0;
    foreach (QString i, s) {
        QTableWidgetItem *it = new QTableWidgetItem(i);
        ui->result->setItem(currentRow, currentColumn, it);
        ++currentRow;

        // n / groupCount;

        x+=groupCount;
        if (x >= n && currentColumn < groupCount-1) {
            currentRow = 0;
            currentColumn += 1;
            x -= n;
        }
    }
}

void MainWindow::on_pushButton_8_clicked()
{
    QList<QString> s = getShuffledPresentStudents();
    int groupCount = ui->desiredSGcount->text().toInt();
    doGrouping(s, groupCount);
}

void MainWindow::on_pushButton_7_clicked()
{
    QList<QString> s = getShuffledPresentStudents();
    int n = s.length();
    if (n == 0) return;
    int desiredGroupSize = ui->desiredSGsize->text().toInt();

    int groupCountCandidate = n / desiredGroupSize;
    int groupCountRemainder = n % desiredGroupSize;

    if (groupCountRemainder != 0) {
        if (ui->radioPreferIncomplete->isChecked()) {
            ++groupCountCandidate;
        } else
        if (ui->radioBalanced->isChecked()) {
            if (groupCountRemainder - 1 < desiredGroupSize/2) {
                // prefer extended
            } else {
                // prefer incomplete
                ++groupCountCandidate;
            }
        }
    }

    if (groupCountCandidate == 0) ++groupCountCandidate;

    doGrouping(s, groupCountCandidate);
}

void MainWindow::on_pushButton_clicked()
{
    QMessageBox msgBox(this);
    msgBox.setText("Creating classes is not implemented.");
    msgBox.exec();
}

void MainWindow::on_pushButton_2_clicked()
{
    QMessageBox msgBox(this);
    msgBox.setText("Removing classes is not implemented.");
    msgBox.exec();
}

void MainWindow::on_actionExport_to_file_triggered()
{
    QMessageBox msgBox(this);
    msgBox.setText("Exporting data is not implemented.");
    msgBox.exec();
}

void MainWindow::on_actionImport_from_file_triggered()
{
    QMessageBox msgBox(this);
    msgBox.setText("Importing data is not implemented.");
    msgBox.exec();
}
<commit_msg>Add version to initial format<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mylistmodel.h"

#include <QList>
#include <algorithm>
#include <QSettings>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    classes.append(Class());
    Class &c = classes.last();
    c.name = "Example class";

    QSettings set("_Vi","studentchooser");

    int n = set.value("preview/count", 0).toInt();
    for(int i = 0; i < n; ++i) {
        Student s;
        s.name =    set.value(QString("preview/%1/name"   ).arg(i), "???").toString();
        s.present = set.value(QString("preview/%1/present").arg(i), false).toBool() ? Qt::Checked : Qt::Unchecked;
        c.students.append(s);
    }

    lm = new MyListModel(&c.students, this);

    ui->students->setModel(lm);
    ui->attendants->setModel(lm);
    //ui->classes->setModel(lm);

    connect(lm,SIGNAL(dataChanged(QModelIndex,QModelIndex)),this,SLOT(on_attendants_itemChanged(QModelIndex,QModelIndex)));
    on_attendants_itemChanged(QModelIndex(), QModelIndex());
}

MainWindow::~MainWindow()
{
    delete ui;

    QSettings set("_Vi","studentchooser");
    set.setValue("version", 0);
    set.setValue("preview/count", lm->rowCount(QModelIndex()));
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        bool present = (Qt::CheckState)lm->data(lm->index(i, 0), Qt::CheckStateRole).toUInt() == Qt::Checked;
        QString name = lm->data(lm->index(i, 0), Qt::DisplayRole).toString();
        set.setValue(QString("preview/%1/name"   ).arg(i), name);
        set.setValue(QString("preview/%1/present").arg(i), present);
    }

}

void MainWindow::on_pushButton_3_clicked()
{
    QModelIndex i = lm->addEntry("New student");
    ui->students->edit(i);
    ui->students->scrollTo(i);
}

void MainWindow::on_pushButton_4_clicked()
{
    foreach (QModelIndex i, ui->students->selectionModel()->selectedRows()) {
        lm->removeRow(i.row());
    }
}

void MainWindow::on_pushButton_5_clicked()
{
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        lm->setData(lm->index(i, 0), QVariant(Qt::Checked), Qt::CheckStateRole);
    }
}

void MainWindow::on_pushButton_6_clicked()
{
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        lm->setData(lm->index(i, 0), QVariant(Qt::Unchecked), Qt::CheckStateRole);
    }
}

void MainWindow::on_attendants_itemChanged(const QModelIndex &ib, const QModelIndex &ie)
{
    (void)ib; (void)ie;// FIXME: ineffectinve O(n*n) update
    int present = 0;
    int absent = 0;
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        if ((Qt::CheckState)lm->data(lm->index(i, 0), Qt::CheckStateRole).toUInt() == Qt::Checked) {
            ++present;
        } else {
            ++absent;
        }
    }
    ui->absenseStats->setText(tr("%1 students present, %2 students absent").arg(present).arg(absent));
}

QList<QString> MainWindow::getShuffledPresentStudents()
{
    QList<QString> presentStudents;
    for(int i = 0; i < lm->rowCount(QModelIndex()); ++i) {
        if ((Qt::CheckState)lm->data(lm->index(i, 0), Qt::CheckStateRole).toUInt() == Qt::Checked) {
            presentStudents.append(lm->data(lm->index(i, 0), Qt::DisplayRole).toString());
        }
    }

    std::random_shuffle(presentStudents.begin(), presentStudents.end());
    return presentStudents;
}

void MainWindow::doGrouping(QList<QString> s, int groupCount)
{
    int n = s.length();

    ui->result->clear();
    ui->result->setColumnCount(groupCount);
    ui->result->setRowCount(n/groupCount + 1);

    int x = 0;
    int currentColumn = 0;
    int currentRow = 0;
    foreach (QString i, s) {
        QTableWidgetItem *it = new QTableWidgetItem(i);
        ui->result->setItem(currentRow, currentColumn, it);
        ++currentRow;

        // n / groupCount;

        x+=groupCount;
        if (x >= n && currentColumn < groupCount-1) {
            currentRow = 0;
            currentColumn += 1;
            x -= n;
        }
    }
}

void MainWindow::on_pushButton_8_clicked()
{
    QList<QString> s = getShuffledPresentStudents();
    int groupCount = ui->desiredSGcount->text().toInt();
    doGrouping(s, groupCount);
}

void MainWindow::on_pushButton_7_clicked()
{
    QList<QString> s = getShuffledPresentStudents();
    int n = s.length();
    if (n == 0) return;
    int desiredGroupSize = ui->desiredSGsize->text().toInt();

    int groupCountCandidate = n / desiredGroupSize;
    int groupCountRemainder = n % desiredGroupSize;

    if (groupCountRemainder != 0) {
        if (ui->radioPreferIncomplete->isChecked()) {
            ++groupCountCandidate;
        } else
        if (ui->radioBalanced->isChecked()) {
            if (groupCountRemainder - 1 < desiredGroupSize/2) {
                // prefer extended
            } else {
                // prefer incomplete
                ++groupCountCandidate;
            }
        }
    }

    if (groupCountCandidate == 0) ++groupCountCandidate;

    doGrouping(s, groupCountCandidate);
}

void MainWindow::on_pushButton_clicked()
{
    QMessageBox msgBox(this);
    msgBox.setText("Creating classes is not implemented.");
    msgBox.exec();
}

void MainWindow::on_pushButton_2_clicked()
{
    QMessageBox msgBox(this);
    msgBox.setText("Removing classes is not implemented.");
    msgBox.exec();
}

void MainWindow::on_actionExport_to_file_triggered()
{
    QMessageBox msgBox(this);
    msgBox.setText("Exporting data is not implemented.");
    msgBox.exec();
}

void MainWindow::on_actionImport_from_file_triggered()
{
    QMessageBox msgBox(this);
    msgBox.setText("Importing data is not implemented.");
    msgBox.exec();
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <eigen3/Eigen/Dense>

#include "common/visionbuf.h"
#include "common/visionipc.h"
#include "common/swaglog.h"

#include "models/driving.h"
#include "messaging.hpp"
volatile sig_atomic_t do_exit = 0;

static void set_do_exit(int sig) {
  do_exit = 1;
}

// globals
bool run_model;
mat3 cur_transform;
pthread_mutex_t transform_lock;

void* live_thread(void *arg) {
  int err;
  set_thread_name("live");

  SubMaster sm({"liveCalibration"});
  /*
     import numpy as np
     from common.transformations.model import medmodel_frame_from_road_frame
     medmodel_frame_from_ground = medmodel_frame_from_road_frame[:, (0, 1, 3)]
     ground_from_medmodel_frame = np.linalg.inv(medmodel_frame_from_ground)
  */
  Eigen::Matrix<float, 3, 3> ground_from_medmodel_frame;
  ground_from_medmodel_frame <<
    0.00000000e+00, 0.00000000e+00, 1.00000000e+00,
    -1.09890110e-03, 0.00000000e+00, 2.81318681e-01,
    -1.84808520e-20, 9.00738606e-04,-4.28751576e-02;

  Eigen::Matrix<float, 3, 3> eon_intrinsics;
  eon_intrinsics <<
    910.0, 0.0, 582.0,
    0.0, 910.0, 437.0,
    0.0,   0.0,   1.0;

  while (!do_exit) {
    if (sm.update(10) > 0){

      auto extrinsic_matrix = sm["liveCalibration"].getLiveCalibration().getExtrinsicMatrix();
      Eigen::Matrix<float, 3, 4> extrinsic_matrix_eigen;
      for (int i = 0; i < 4*3; i++){
        extrinsic_matrix_eigen(i / 4, i % 4) = extrinsic_matrix[i];
      }

      auto camera_frame_from_road_frame = eon_intrinsics * extrinsic_matrix_eigen;
      Eigen::Matrix<float, 3, 3> camera_frame_from_ground;
      camera_frame_from_ground.col(0) = camera_frame_from_road_frame.col(0);
      camera_frame_from_ground.col(1) = camera_frame_from_road_frame.col(1);
      camera_frame_from_ground.col(2) = camera_frame_from_road_frame.col(3);

      auto warp_matrix = camera_frame_from_ground * ground_from_medmodel_frame;

      pthread_mutex_lock(&transform_lock);
      for (int i=0; i<3*3; i++) {
        cur_transform.v[i] = warp_matrix(i / 3, i % 3);
      }

      run_model = true;
      pthread_mutex_unlock(&transform_lock);
    }
  }
  return NULL;
}

int main(int argc, char **argv) {
  int err;
  set_realtime_priority(51);

  // start calibration thread
  pthread_t live_thread_handle;
  err = pthread_create(&live_thread_handle, NULL, live_thread, NULL);
  assert(err == 0);

  // messaging
  PubMaster pm({"model", "cameraOdometry"});
  SubMaster sm({"pathPlan"});

#ifdef QCOM
  cl_device_type device_type = CL_DEVICE_TYPE_DEFAULT;
#else
  cl_device_type device_type = CL_DEVICE_TYPE_CPU;
#endif

  // cl init
  cl_device_id device_id;
  cl_context context;
  cl_command_queue q;
  {
    cl_uint num_platforms;
    err = clGetPlatformIDs(0, NULL, &num_platforms);
    assert(err == 0);

    cl_platform_id * platform_ids = new cl_platform_id[num_platforms];
    err = clGetPlatformIDs(num_platforms, platform_ids, NULL);
    assert(err == 0);

    LOGD("got %d opencl platform(s)", num_platforms);

    char cBuffer[1024];
    bool opencl_platform_found = false;

    for (size_t i = 0; i < num_platforms; i++){
      err = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_NAME, sizeof(cBuffer), &cBuffer, NULL);
      assert(err == 0);
      LOGD("platform[%zu] CL_PLATFORM_NAME: %s", i, cBuffer);

      cl_uint num_devices;
      err = clGetDeviceIDs(platform_ids[i], device_type, 0, NULL, &num_devices);
      if (err != 0|| !num_devices){
        continue;
      }

      // Get first device
      err = clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL);
      assert(err == 0);

      context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err);
      assert(err == 0);

      q = clCreateCommandQueue(context, device_id, 0, &err);
      assert(err == 0);

      opencl_platform_found = true;
      break;
    }

    delete[] platform_ids;

    if (!opencl_platform_found){
      LOGE("No valid openCL platform found");
      assert(opencl_platform_found);
    }

    LOGD("opencl init complete");
  }

  // init the models
  ModelState model;
  model_init(&model, device_id, context, true);
  LOGW("models loaded, modeld starting");

  // debayering does a 2x downscale
  mat3 yuv_transform = transform_scale_buffer((mat3){{
    1.0, 0.0, 0.0,
    0.0, 1.0, 0.0,
    0.0, 0.0, 1.0,
  }}, 0.5);

  // loop
  VisionStream stream;
  while (!do_exit) {
    VisionStreamBufs buf_info;
    err = visionstream_init(&stream, VISION_STREAM_YUV, true, &buf_info);
    if (err) {
      LOGW("visionstream connect failed");
      usleep(100000);
      continue;
    }
    LOGW("connected with buffer size: %d", buf_info.buf_len);

    // one frame in memory
    cl_mem yuv_cl;
    VisionBuf yuv_ion = visionbuf_allocate_cl(buf_info.buf_len, device_id, context, &yuv_cl);

    double last = 0;
    int desire = -1;
    while (!do_exit) {
      VIPCBuf *buf;
      VIPCBufExtra extra;
      buf = visionstream_get(&stream, &extra);
      if (buf == NULL) {
        LOGW("visionstream get failed");
        visionstream_destroy(&stream);
        break;
      }

      pthread_mutex_lock(&transform_lock);
      mat3 transform = cur_transform;
      const bool run_model_this_iter = run_model;
      pthread_mutex_unlock(&transform_lock);

      if (sm.update(0) > 0){
        // TODO: path planner timeout?
        desire = ((int)sm["pathPlan"].getPathPlan().getDesire()) - 1;
      }

      double mt1 = 0, mt2 = 0;
      if (run_model_this_iter) {
        float vec_desire[DESIRE_LEN] = {0};
        if (desire >= 0 && desire < DESIRE_LEN) {
          vec_desire[desire] = 1.0;
        }

        mat3 model_transform = matmul3(yuv_transform, transform);

        mt1 = millis_since_boot();

        // TODO: don't make copies!
        memcpy(yuv_ion.addr, buf->addr, buf_info.buf_len);

        ModelDataRaw model_buf =
            model_eval_frame(&model, q, yuv_cl, buf_info.width, buf_info.height,
                             model_transform, NULL, vec_desire);
        mt2 = millis_since_boot();

        model_publish(pm, extra.frame_id, model_buf, extra.timestamp_eof);
        posenet_publish(pm, extra.frame_id, model_buf, extra.timestamp_eof);

        LOGD("model process: %.2fms, from last %.2fms", mt2-mt1, mt1-last);
        last = mt1;
      }

    }
    visionbuf_free(&yuv_ion);
  }

  visionstream_destroy(&stream);

  model_free(&model);

  LOG("joining live_thread");
  err = pthread_join(live_thread_handle, NULL);
  assert(err == 0);
  clReleaseCommandQueue(q);
  clReleaseContext(context);

  return 0;
}
<commit_msg>Fix modeld dropping frames if processing takes over 50 ms<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <eigen3/Eigen/Dense>

#include "common/visionbuf.h"
#include "common/visionipc.h"
#include "common/swaglog.h"

#include "models/driving.h"
#include "messaging.hpp"
volatile sig_atomic_t do_exit = 0;

static void set_do_exit(int sig) {
  do_exit = 1;
}

// globals
bool run_model;
mat3 cur_transform;
pthread_mutex_t transform_lock;

void* live_thread(void *arg) {
  int err;
  set_thread_name("live");

  SubMaster sm({"liveCalibration"});
  /*
     import numpy as np
     from common.transformations.model import medmodel_frame_from_road_frame
     medmodel_frame_from_ground = medmodel_frame_from_road_frame[:, (0, 1, 3)]
     ground_from_medmodel_frame = np.linalg.inv(medmodel_frame_from_ground)
  */
  Eigen::Matrix<float, 3, 3> ground_from_medmodel_frame;
  ground_from_medmodel_frame <<
    0.00000000e+00, 0.00000000e+00, 1.00000000e+00,
    -1.09890110e-03, 0.00000000e+00, 2.81318681e-01,
    -1.84808520e-20, 9.00738606e-04,-4.28751576e-02;

  Eigen::Matrix<float, 3, 3> eon_intrinsics;
  eon_intrinsics <<
    910.0, 0.0, 582.0,
    0.0, 910.0, 437.0,
    0.0,   0.0,   1.0;

  while (!do_exit) {
    if (sm.update(10) > 0){

      auto extrinsic_matrix = sm["liveCalibration"].getLiveCalibration().getExtrinsicMatrix();
      Eigen::Matrix<float, 3, 4> extrinsic_matrix_eigen;
      for (int i = 0; i < 4*3; i++){
        extrinsic_matrix_eigen(i / 4, i % 4) = extrinsic_matrix[i];
      }

      auto camera_frame_from_road_frame = eon_intrinsics * extrinsic_matrix_eigen;
      Eigen::Matrix<float, 3, 3> camera_frame_from_ground;
      camera_frame_from_ground.col(0) = camera_frame_from_road_frame.col(0);
      camera_frame_from_ground.col(1) = camera_frame_from_road_frame.col(1);
      camera_frame_from_ground.col(2) = camera_frame_from_road_frame.col(3);

      auto warp_matrix = camera_frame_from_ground * ground_from_medmodel_frame;

      pthread_mutex_lock(&transform_lock);
      for (int i=0; i<3*3; i++) {
        cur_transform.v[i] = warp_matrix(i / 3, i % 3);
      }

      run_model = true;
      pthread_mutex_unlock(&transform_lock);
    }
  }
  return NULL;
}

int main(int argc, char **argv) {
  int err;
  set_realtime_priority(51);

  // start calibration thread
  pthread_t live_thread_handle;
  err = pthread_create(&live_thread_handle, NULL, live_thread, NULL);
  assert(err == 0);

  // messaging
  PubMaster pm({"model", "cameraOdometry"});
  SubMaster sm({"pathPlan"});

#ifdef QCOM
  cl_device_type device_type = CL_DEVICE_TYPE_DEFAULT;
#else
  cl_device_type device_type = CL_DEVICE_TYPE_CPU;
#endif

  // cl init
  cl_device_id device_id;
  cl_context context;
  cl_command_queue q;
  {
    cl_uint num_platforms;
    err = clGetPlatformIDs(0, NULL, &num_platforms);
    assert(err == 0);

    cl_platform_id * platform_ids = new cl_platform_id[num_platforms];
    err = clGetPlatformIDs(num_platforms, platform_ids, NULL);
    assert(err == 0);

    LOGD("got %d opencl platform(s)", num_platforms);

    char cBuffer[1024];
    bool opencl_platform_found = false;

    for (size_t i = 0; i < num_platforms; i++){
      err = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_NAME, sizeof(cBuffer), &cBuffer, NULL);
      assert(err == 0);
      LOGD("platform[%zu] CL_PLATFORM_NAME: %s", i, cBuffer);

      cl_uint num_devices;
      err = clGetDeviceIDs(platform_ids[i], device_type, 0, NULL, &num_devices);
      if (err != 0|| !num_devices){
        continue;
      }

      // Get first device
      err = clGetDeviceIDs(platform_ids[i], device_type, 1, &device_id, NULL);
      assert(err == 0);

      context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err);
      assert(err == 0);

      q = clCreateCommandQueue(context, device_id, 0, &err);
      assert(err == 0);

      opencl_platform_found = true;
      break;
    }

    delete[] platform_ids;

    if (!opencl_platform_found){
      LOGE("No valid openCL platform found");
      assert(opencl_platform_found);
    }

    LOGD("opencl init complete");
  }

  // init the models
  ModelState model;
  model_init(&model, device_id, context, true);
  LOGW("models loaded, modeld starting");

  // debayering does a 2x downscale
  mat3 yuv_transform = transform_scale_buffer((mat3){{
    1.0, 0.0, 0.0,
    0.0, 1.0, 0.0,
    0.0, 0.0, 1.0,
  }}, 0.5);

  // loop
  VisionStream stream;
  while (!do_exit) {
    VisionStreamBufs buf_info;
    err = visionstream_init(&stream, VISION_STREAM_YUV, false, &buf_info);
    if (err) {
      LOGW("visionstream connect failed");
      usleep(100000);
      continue;
    }
    LOGW("connected with buffer size: %d", buf_info.buf_len);

    // one frame in memory
    cl_mem yuv_cl;
    VisionBuf yuv_ion = visionbuf_allocate_cl(buf_info.buf_len, device_id, context, &yuv_cl);

    double last = 0;
    int desire = -1;
    while (!do_exit) {
      VIPCBuf *buf;
      VIPCBufExtra extra;
      buf = visionstream_get(&stream, &extra);
      if (buf == NULL) {
        LOGW("visionstream get failed");
        visionstream_destroy(&stream);
        break;
      }

      pthread_mutex_lock(&transform_lock);
      mat3 transform = cur_transform;
      const bool run_model_this_iter = run_model;
      pthread_mutex_unlock(&transform_lock);

      if (sm.update(0) > 0){
        // TODO: path planner timeout?
        desire = ((int)sm["pathPlan"].getPathPlan().getDesire()) - 1;
      }

      double mt1 = 0, mt2 = 0;
      if (run_model_this_iter) {
        float vec_desire[DESIRE_LEN] = {0};
        if (desire >= 0 && desire < DESIRE_LEN) {
          vec_desire[desire] = 1.0;
        }

        mat3 model_transform = matmul3(yuv_transform, transform);

        mt1 = millis_since_boot();

        // TODO: don't make copies!
        memcpy(yuv_ion.addr, buf->addr, buf_info.buf_len);

        ModelDataRaw model_buf =
            model_eval_frame(&model, q, yuv_cl, buf_info.width, buf_info.height,
                             model_transform, NULL, vec_desire);
        mt2 = millis_since_boot();

        model_publish(pm, extra.frame_id, model_buf, extra.timestamp_eof);
        posenet_publish(pm, extra.frame_id, model_buf, extra.timestamp_eof);

        LOGD("model process: %.2fms, from last %.2fms", mt2-mt1, mt1-last);
        last = mt1;
      }

    }
    visionbuf_free(&yuv_ion);
  }

  visionstream_destroy(&stream);

  model_free(&model);

  LOG("joining live_thread");
  err = pthread_join(live_thread_handle, NULL);
  assert(err == 0);
  clReleaseCommandQueue(q);
  clReleaseContext(context);

  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Allow the RenderWidgetHostViewGtk to be sized even if it isn't a popup.<commit_after><|endoftext|>


<commit_before>/*
 * SuRealPMCB.cc
 *
 * Copyright (C) 2014 OpenCog Foundation
 *
 * Author: William Ma <https://github.com/williampma>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/nlp/types/atom_types.h>
#include <opencog/guile/SchemeSmob.h>

#include "SuRealPMCB.h"

using namespace opencog::nlp;
using namespace opencog;

/**
 * The constructor for the PatternMatcherCallback.
 *
 * @param pAS    the corresponding AtomSpace
 * @param vars   the set of nodes that should be treated as variables
 */
SuRealPMCB::SuRealPMCB(AtomSpace* pAS, std::set<Handle> vars)
    : DefaultPatternMatchCB(pAS), m_vars(vars), m_eval(new SchemeEval(pAS))
{

}

SuRealPMCB::~SuRealPMCB()
{
    delete m_eval;
}

/**
 * Override the variable_match callback.
 *
 * Do the special checking for each variable matches.  Note that variables
 * in SuReal will not just be VariableNode, but any nodes with an actual word
 * (eg. (PredicateNode "runs"), (ConceptNode "dog@1324-12213"), etc).
 *
 * For each variable and its potential solution, the corresponding WordNode
 * will be located.  Then we following the WordNode to find LgWordCset to get
 * the LG dictionary entries.  If the two words have identical LG entries,
 * then the two words matches.  Just one pair of LG entries need to match even
 * if a word has multiple entries.
 *
 * @param hPat    the variable, a node extracted from the original query
 * @param hSoln   the potential mapping
 * @return        false if solution is rejected, true if accepted
 */
bool SuRealPMCB::variable_match(Handle &hPat, Handle &hSoln)
{
    logger().debug("[SuReal] In variable_match, looking at %s", hSoln->toShortString().c_str());

    // reject if the solution is not of the same type
    if (hPat->getType() != hSoln->getType())
        return false;

    // VariableNode can be matched to any VariableNode, similarly for InterpretationNode
    if (hPat->getType() == VARIABLE_NODE || hPat->getType() == INTERPRETATION_NODE)
        return true;

    std::string sPat = _as->getName(hPat);
    std::string sPatWord = sPat.substr(0, sPat.find_first_of('@'));
    std::string sSoln = _as->getName(hSoln);

    // get the WordNode associated with the word (extracted from "word@1234" convention)
    Handle hPatWordNode = _as->getHandle(WORD_NODE, sPatWord);

    // get the corresponding WordInstanceNode for hSoln
    Handle hSolnWordInst = _as->getHandle(WORD_INSTANCE_NODE, sSoln);

    // no WordInstanceNode? reject!
    if (hSolnWordInst == Handle::UNDEFINED)
        return false;

    // get the source connectors for the solution
    std::string scmCode = "(word-inst-get-source-conn " + SchemeSmob::to_string(hSolnWordInst) + ")";
    HandleSeq qTargetConns = m_eval->eval_q(scmCode);

    HandleSeq qOr = _as->getNeighbors(hPatWordNode, false, true, LG_WORD_CSET, false);
    HandleSeq qDisjuncts;

    auto insertHelper = [&](const Handle& h)
    {
        HandleSeq q = _as->getOutgoing(h);
        qDisjuncts.insert(qDisjuncts.end(), q.begin(), q.end());
    };

    std::for_each(qOr.begin(), qOr.end(), insertHelper);

    // for each disjunct, get its outgoing set, and match 1-to-1 with qConns
    auto matchHelper = [&](const Handle& hDisjunct)
    {
        HandleSeq qSourceConns = _as->getOutgoing(hDisjunct);

        if (qSourceConns.size() != qTargetConns.size())
            return false;

        for (uint i = 0; i < qSourceConns.size(); i++)
        {
            scmCode = "(lg-conn-linkable? " + SchemeSmob::to_string(qSourceConns[i]) + " " + SchemeSmob::to_string(qTargetConns[i]) + ")";

            if (m_eval->eval(scmCode) == "#f")
                return false;
        }

        return true;
    };

    return std::any_of(qDisjuncts.begin(), qDisjuncts.end(), matchHelper);
}

/**
 * Override the clause_match callback.
 *
 * Reject a clause match if the matched link is not in a SetLink linked to an
 * InterpretationNode.  The reason of doing it here instead of earlier in
 * link_match() is because it is possible a SetLink is used for other purpose
 * as part of R2L's output.
 *
 * @param pattrn_link_h   the matched clause, extracted from the input SetLink
 * @param grnd_link_h     the corresponding grounding to be checked
 * @return                false if rejected, true if accepted
 */
bool SuRealPMCB::clause_match(Handle &pattrn_link_h, Handle &grnd_link_h)
{
    logger().debug("[SuReal] In clause_match, looking at %s", grnd_link_h->toShortString().c_str());

    HandleSeq qISet = _as->getIncoming(grnd_link_h);

    // keep only SetLink, and check if any of the SetLink has an InterpretationNode as neightbor
    qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& h) { return h->getType() != SET_LINK; }), qISet.end());

    // helper lambda function to check for linkage to an InterpretationNode, given SetLink
    auto hasInterpretation = [this](Handle& h)
    {
        HandleSeq qN = _as->getNeighbors(h, true, false, REFERENCE_LINK, false);
        return std::any_of(qN.begin(), qN.end(), [](Handle& hn) { return hn->getType() == INTERPRETATION_NODE; });
    };

    // reject match (ie. return false) if there is no InterpretationNode
    return std::any_of(qISet.begin(), qISet.end(), hasInterpretation);
}

/**
 * Implement the grounding method.
 *
 * Check all matched clauses to see if they are all within the same SetLink
 * linking to the same InterpretationNode.  If so, store the solution and try
 * to find more.
 *
 * @param var_soln   the variable & links mapping
 * @param pred_soln  the clause mapping
 * @return           always return false to search for more solutions
 */
bool SuRealPMCB::grounding(const std::map<Handle, Handle> &var_soln, const std::map<Handle, Handle> &pred_soln)
{
    logger().debug("[SuReal] grounding a solution");

    // helper to get the InterpretationNode
    auto getInterpretation = [this](const Handle& h)
    {
        HandleSeq qISet = _as->getIncoming(h);
        qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& h) { return h->getType() != SET_LINK; }), qISet.end());

        HandleSeq results;

        for (auto& hSetLink : qISet)
        {
            HandleSeq qN  = _as->getNeighbors(hSetLink, true, false, REFERENCE_LINK, false);
            qN.erase(std::remove_if(qN.begin(), qN.end(), [](Handle& h) { return h->getType() != INTERPRETATION_NODE; }), qN.end());

            results.insert(results.end(), qN.begin(), qN.end());
        }

        return results;
    };

    HandleSeq qItprNode = getInterpretation(pred_soln.begin()->second);
    std::sort(qItprNode.begin(), qItprNode.end());

    // try to find a common InterpretationNode to the solutions
    for (std::map<Handle, Handle>::const_iterator it = ++pred_soln.begin(); it != pred_soln.end(); ++it)
    {
        HandleSeq thisSeq = getInterpretation(it->second);
        std::sort(thisSeq.begin(), thisSeq.end());

        HandleSeq overlapSeq;
        std::set_intersection(qItprNode.begin(), qItprNode.end(), thisSeq.begin(), thisSeq.end(), std::back_inserter(overlapSeq));

        qItprNode = overlapSeq;
    }

    // no common InterpretationNode, ignore this grounding
    if (qItprNode.empty())
        return false;

    // shrink var_soln to only contain solution for the variables
    std::map<Handle, Handle> shrinked_soln;

    for (const auto& kv : var_soln)
    {
        if (m_vars.count(kv.first) == 0)
            continue;

        auto checker = [&](const std::pair<Handle, Handle>& nkv)
        {
            return kv.second == nkv.second;
        };

        // if another variable already map to the same solution, discard this grounding
        // because each variable should map to its own unique solution
        if (std::any_of(shrinked_soln.begin(), shrinked_soln.end(), checker))
            return false;

        shrinked_soln[kv.first] = kv.second;
    }

    // store the solution; all common InterpretationNode are solutions for this
    // grounding, so store the solution for each InterpretationNode
    for (auto n : qItprNode)
    {
        // there could also be multiple solutions for one InterpretationNode,
        // so store them in a vector
        if (m_results.count(n) == 0)
            m_results[n] = std::vector<std::map<Handle, Handle> >();

        m_results[n].push_back(shrinked_soln);
    }

    return false;
}

/**
 * Implement the perform_search method.
 *
 * Similar to DefaultPatternMatcherCB::perform_search, in which we start search
 * by looking at the thinnest clause with constants.  However, since most clauses
 * for SuReal will have 0 constants, most searches will require looking at all
 * the links.  This implementation improves that by looking at links within a
 * SetLink within a ReferenceLink with a InterpretationNode neightbor, thus
 * limiting the search space.
 *
 * @param pPME       pointer to the PatternMatchEngine
 * @param vars       a set of nodes that are variables
 * @param clauses    the clauses for the query
 * @param negations  the negative clauses
 */
void SuRealPMCB::perform_search(PatternMatchEngine* pPME, std::set<Handle>& vars, HandleSeq& clauses, HandleSeq& negations)
{
    size_t bestClauseIndex;
    Handle bestClause, bestSubClause, bestSubNode;

    // find the thinnest clause with constants
    bestSubNode = find_thinnest(clauses, bestSubClause, bestClauseIndex);

    if (bestSubNode != Handle::UNDEFINED && !vars.empty())
    {
        bestClause = clauses[bestClauseIndex];

        logger().debug("[SuReal] Search start node: %s", bestSubNode->toShortString().c_str());
        logger().debug("[SuReal] Start pred is: %s", bestSubClause->toShortString().c_str());

        IncomingSet iset = get_incoming_set(bestSubNode);

        for (auto& l : iset)
        {
            Handle h(l);
            logger().debug("[SuReal] Loop candidate: %s", h->toShortString().c_str());

            if (pPME->do_candidate(bestClause, bestSubClause, h))
                break;
        }

        return;
    }

    // reaching here means no contants, so do some search space reduction here
    bestClause = clauses[0];

    logger().debug("[SuReal] Start pred is: %s", bestClause->toShortString().c_str());

    // helper for checking for InterpretationNode
    auto hasNoInterpretation = [this](Handle& h)
    {
        HandleSeq qISet = _as->getIncoming(h);
        qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& hl) { return hl->getType() != SET_LINK; }), qISet.end());

        auto hasNode = [this](Handle& hl)
        {
            HandleSeq qN = _as->getNeighbors(hl, true, false, REFERENCE_LINK, false);
            return std::any_of(qN.begin(), qN.end(), [](Handle& hn) { return hn->getType() == INTERPRETATION_NODE; });
        };

        return not std::any_of(qISet.begin(), qISet.end(), hasNode);
    };

    // keep only links of the same type as bestClause and have linkage to InterpretationNode
    HandleSeq qCandidate;
    _as->getHandlesByType(std::back_inserter(qCandidate), bestClause->getType());
    qCandidate.erase(std::remove_if(qCandidate.begin(), qCandidate.end(), hasNoInterpretation), qCandidate.end());

    for (auto& c : qCandidate)
    {
        logger().debug("[SuReal] Loop candidate: %s", c->toShortString().c_str());

        if (pPME->do_candidate(bestClause, bestClause, c))
            break;
    }
}

/**
 * Override the find_starter method in DefaultPatternMatchCB.
 *
 * Override find_starter so that it will not treat VariableNode variables,
 * but instead compare against the variable list.
 *
 * @param h       same as DefaultPatternMatchCB::find_starter
 * @param depth   same as DefaultPatternMatchCB::find_starter
 * @param start   same as DefaultPatternMatchCB::find_starter
 * @param width   same as DefaultPatternMatchCB::find_starter
 * @return        same as DefaultPatternMatchCB::find_starter but change
 *                the result if is a variable
 */
Handle SuRealPMCB::find_starter(Handle h, size_t& depth, Handle& start, size_t& width)
{
    Handle rh = DefaultPatternMatchCB::find_starter(h, depth, start, width);

    // if the non-VariableNode is actually a variable
    if (m_vars.count(rh) == 1)
        return Handle::UNDEFINED;

    return rh;
}

<commit_msg>Fixes handling of a disjunct of just one connector<commit_after>/*
 * SuRealPMCB.cc
 *
 * Copyright (C) 2014 OpenCog Foundation
 *
 * Author: William Ma <https://github.com/williampma>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/nlp/types/atom_types.h>
#include <opencog/guile/SchemeSmob.h>

#include "SuRealPMCB.h"

using namespace opencog::nlp;
using namespace opencog;

/**
 * The constructor for the PatternMatcherCallback.
 *
 * @param pAS    the corresponding AtomSpace
 * @param vars   the set of nodes that should be treated as variables
 */
SuRealPMCB::SuRealPMCB(AtomSpace* pAS, std::set<Handle> vars)
    : DefaultPatternMatchCB(pAS), m_vars(vars), m_eval(new SchemeEval(pAS))
{

}

SuRealPMCB::~SuRealPMCB()
{
    delete m_eval;
}

/**
 * Override the variable_match callback.
 *
 * Do the special checking for each variable matches.  Note that variables
 * in SuReal will not just be VariableNode, but any nodes with an actual word
 * (eg. (PredicateNode "runs"), (ConceptNode "dog@1324-12213"), etc).
 *
 * For each variable and its potential solution, the corresponding WordNode
 * will be located.  Then we following the WordNode to find LgWordCset to get
 * the LG dictionary entries.  If the two words have identical LG entries,
 * then the two words matches.  Just one pair of LG entries need to match even
 * if a word has multiple entries.
 *
 * @param hPat    the variable, a node extracted from the original query
 * @param hSoln   the potential mapping
 * @return        false if solution is rejected, true if accepted
 */
bool SuRealPMCB::variable_match(Handle &hPat, Handle &hSoln)
{
    logger().debug("[SuReal] In variable_match, looking at %s", hSoln->toShortString().c_str());

    // reject if the solution is not of the same type
    if (hPat->getType() != hSoln->getType())
        return false;

    // VariableNode can be matched to any VariableNode, similarly for InterpretationNode
    if (hPat->getType() == VARIABLE_NODE || hPat->getType() == INTERPRETATION_NODE)
        return true;

    std::string sPat = _as->getName(hPat);
    std::string sPatWord = sPat.substr(0, sPat.find_first_of('@'));
    std::string sSoln = _as->getName(hSoln);

    // get the WordNode associated with the word (extracted from "word@1234" convention)
    Handle hPatWordNode = _as->getHandle(WORD_NODE, sPatWord);

    // get the corresponding WordInstanceNode for hSoln
    Handle hSolnWordInst = _as->getHandle(WORD_INSTANCE_NODE, sSoln);

    // no WordInstanceNode? reject!
    if (hSolnWordInst == Handle::UNDEFINED)
        return false;

    // get the source connectors for the solution
    std::string scmCode = "(word-inst-get-source-conn " + SchemeSmob::to_string(hSolnWordInst) + ")";
    HandleSeq qTargetConns = m_eval->eval_q(scmCode);

    HandleSeq qOr = _as->getNeighbors(hPatWordNode, false, true, LG_WORD_CSET, false);
    HandleSeq qDisjuncts;

    auto insertHelper = [&](const Handle& h)
    {
        HandleSeq q = _as->getOutgoing(h);
        qDisjuncts.insert(qDisjuncts.end(), q.begin(), q.end());
    };

    std::for_each(qOr.begin(), qOr.end(), insertHelper);

    logger().debug("[SuReal] Looking at %d disjuncts of %s", qDisjuncts.size(), hPat->toShortString().c_str());

    // for each disjunct, get its outgoing set, and match 1-to-1 with qConns
    auto matchHelper = [&](const Handle& hDisjunct)
    {
        HandleSeq qSourceConns;

        // check if hDisjunct is LgAnd or just a lone connector
        if (hDisjunct->getType() == LG_AND)
            qSourceConns = _as->getOutgoing(hDisjunct);
        else
            qSourceConns.push_back(hDisjunct);

        if (qSourceConns.size() != qTargetConns.size())
            return false;

        for (uint i = 0; i < qSourceConns.size(); i++)
        {
            scmCode = "(lg-conn-linkable? " + SchemeSmob::to_string(qSourceConns[i]) + " " + SchemeSmob::to_string(qTargetConns[i]) + ")";

            if (m_eval->eval(scmCode) == "#f")
                return false;
        }

        return true;
    };

    return std::any_of(qDisjuncts.begin(), qDisjuncts.end(), matchHelper);
}

/**
 * Override the clause_match callback.
 *
 * Reject a clause match if the matched link is not in a SetLink linked to an
 * InterpretationNode.  The reason of doing it here instead of earlier in
 * link_match() is because it is possible a SetLink is used for other purpose
 * as part of R2L's output.
 *
 * @param pattrn_link_h   the matched clause, extracted from the input SetLink
 * @param grnd_link_h     the corresponding grounding to be checked
 * @return                false if rejected, true if accepted
 */
bool SuRealPMCB::clause_match(Handle &pattrn_link_h, Handle &grnd_link_h)
{
    logger().debug("[SuReal] In clause_match, looking at %s", grnd_link_h->toShortString().c_str());

    HandleSeq qISet = _as->getIncoming(grnd_link_h);

    // keep only SetLink, and check if any of the SetLink has an InterpretationNode as neightbor
    qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& h) { return h->getType() != SET_LINK; }), qISet.end());

    // helper lambda function to check for linkage to an InterpretationNode, given SetLink
    auto hasInterpretation = [this](Handle& h)
    {
        HandleSeq qN = _as->getNeighbors(h, true, false, REFERENCE_LINK, false);
        return std::any_of(qN.begin(), qN.end(), [](Handle& hn) { return hn->getType() == INTERPRETATION_NODE; });
    };

    // reject match (ie. return false) if there is no InterpretationNode
    return std::any_of(qISet.begin(), qISet.end(), hasInterpretation);
}

/**
 * Implement the grounding method.
 *
 * Check all matched clauses to see if they are all within the same SetLink
 * linking to the same InterpretationNode.  If so, store the solution and try
 * to find more.
 *
 * @param var_soln   the variable & links mapping
 * @param pred_soln  the clause mapping
 * @return           always return false to search for more solutions
 */
bool SuRealPMCB::grounding(const std::map<Handle, Handle> &var_soln, const std::map<Handle, Handle> &pred_soln)
{
    logger().debug("[SuReal] grounding a solution");

    // helper to get the InterpretationNode
    auto getInterpretation = [this](const Handle& h)
    {
        HandleSeq qISet = _as->getIncoming(h);
        qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& h) { return h->getType() != SET_LINK; }), qISet.end());

        HandleSeq results;

        for (auto& hSetLink : qISet)
        {
            HandleSeq qN  = _as->getNeighbors(hSetLink, true, false, REFERENCE_LINK, false);
            qN.erase(std::remove_if(qN.begin(), qN.end(), [](Handle& h) { return h->getType() != INTERPRETATION_NODE; }), qN.end());

            results.insert(results.end(), qN.begin(), qN.end());
        }

        return results;
    };

    HandleSeq qItprNode = getInterpretation(pred_soln.begin()->second);
    std::sort(qItprNode.begin(), qItprNode.end());

    // try to find a common InterpretationNode to the solutions
    for (std::map<Handle, Handle>::const_iterator it = ++pred_soln.begin(); it != pred_soln.end(); ++it)
    {
        HandleSeq thisSeq = getInterpretation(it->second);
        std::sort(thisSeq.begin(), thisSeq.end());

        HandleSeq overlapSeq;
        std::set_intersection(qItprNode.begin(), qItprNode.end(), thisSeq.begin(), thisSeq.end(), std::back_inserter(overlapSeq));

        qItprNode = overlapSeq;
    }

    // no common InterpretationNode, ignore this grounding
    if (qItprNode.empty())
        return false;

    // shrink var_soln to only contain solution for the variables
    std::map<Handle, Handle> shrinked_soln;

    for (const auto& kv : var_soln)
    {
        if (m_vars.count(kv.first) == 0)
            continue;

        auto checker = [&](const std::pair<Handle, Handle>& nkv)
        {
            return kv.second == nkv.second;
        };

        // if another variable already map to the same solution, discard this grounding
        // because each variable should map to its own unique solution
        if (std::any_of(shrinked_soln.begin(), shrinked_soln.end(), checker))
            return false;

        shrinked_soln[kv.first] = kv.second;
    }

    // store the solution; all common InterpretationNode are solutions for this
    // grounding, so store the solution for each InterpretationNode
    for (auto n : qItprNode)
    {
        // there could also be multiple solutions for one InterpretationNode,
        // so store them in a vector
        if (m_results.count(n) == 0)
            m_results[n] = std::vector<std::map<Handle, Handle> >();

        m_results[n].push_back(shrinked_soln);
    }

    return false;
}

/**
 * Implement the perform_search method.
 *
 * Similar to DefaultPatternMatcherCB::perform_search, in which we start search
 * by looking at the thinnest clause with constants.  However, since most clauses
 * for SuReal will have 0 constants, most searches will require looking at all
 * the links.  This implementation improves that by looking at links within a
 * SetLink within a ReferenceLink with a InterpretationNode neightbor, thus
 * limiting the search space.
 *
 * @param pPME       pointer to the PatternMatchEngine
 * @param vars       a set of nodes that are variables
 * @param clauses    the clauses for the query
 * @param negations  the negative clauses
 */
void SuRealPMCB::perform_search(PatternMatchEngine* pPME, std::set<Handle>& vars, HandleSeq& clauses, HandleSeq& negations)
{
    size_t bestClauseIndex;
    Handle bestClause, bestSubClause, bestSubNode;

    // find the thinnest clause with constants
    bestSubNode = find_thinnest(clauses, bestSubClause, bestClauseIndex);

    if (bestSubNode != Handle::UNDEFINED && !vars.empty())
    {
        bestClause = clauses[bestClauseIndex];

        logger().debug("[SuReal] Search start node: %s", bestSubNode->toShortString().c_str());
        logger().debug("[SuReal] Start pred is: %s", bestSubClause->toShortString().c_str());

        IncomingSet iset = get_incoming_set(bestSubNode);

        for (auto& l : iset)
        {
            Handle h(l);
            logger().debug("[SuReal] Loop candidate: %s", h->toShortString().c_str());

            if (pPME->do_candidate(bestClause, bestSubClause, h))
                break;
        }

        return;
    }

    // reaching here means no contants, so do some search space reduction here
    bestClause = clauses[0];

    logger().debug("[SuReal] Start pred is: %s", bestClause->toShortString().c_str());

    // helper for checking for InterpretationNode
    auto hasNoInterpretation = [this](Handle& h)
    {
        HandleSeq qISet = _as->getIncoming(h);
        qISet.erase(std::remove_if(qISet.begin(), qISet.end(), [](Handle& hl) { return hl->getType() != SET_LINK; }), qISet.end());

        auto hasNode = [this](Handle& hl)
        {
            HandleSeq qN = _as->getNeighbors(hl, true, false, REFERENCE_LINK, false);
            return std::any_of(qN.begin(), qN.end(), [](Handle& hn) { return hn->getType() == INTERPRETATION_NODE; });
        };

        return not std::any_of(qISet.begin(), qISet.end(), hasNode);
    };

    // keep only links of the same type as bestClause and have linkage to InterpretationNode
    HandleSeq qCandidate;
    _as->getHandlesByType(std::back_inserter(qCandidate), bestClause->getType());
    qCandidate.erase(std::remove_if(qCandidate.begin(), qCandidate.end(), hasNoInterpretation), qCandidate.end());

    for (auto& c : qCandidate)
    {
        logger().debug("[SuReal] Loop candidate: %s", c->toShortString().c_str());

        if (pPME->do_candidate(bestClause, bestClause, c))
            break;
    }
}

/**
 * Override the find_starter method in DefaultPatternMatchCB.
 *
 * Override find_starter so that it will not treat VariableNode variables,
 * but instead compare against the variable list.
 *
 * @param h       same as DefaultPatternMatchCB::find_starter
 * @param depth   same as DefaultPatternMatchCB::find_starter
 * @param start   same as DefaultPatternMatchCB::find_starter
 * @param width   same as DefaultPatternMatchCB::find_starter
 * @return        same as DefaultPatternMatchCB::find_starter but change
 *                the result if is a variable
 */
Handle SuRealPMCB::find_starter(Handle h, size_t& depth, Handle& start, size_t& width)
{
    Handle rh = DefaultPatternMatchCB::find_starter(h, depth, start, width);

    // if the non-VariableNode is actually a variable
    if (m_vars.count(rh) == 1)
        return Handle::UNDEFINED;

    return rh;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: exc_thrower.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: jl $ $Date: 2001-03-12 13:39:32 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _OSL_INTERLOCK_H_
#include <osl/interlck.h>
#endif
#ifndef _UNO_DISPATCHER_H_
#include <uno/dispatcher.h>
#endif
#ifndef _UNO_MAPPING_HXX_
#include <uno/mapping.hxx>
#endif

#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Exception.hpp>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/uno/XInterface.hpp>

using namespace com::sun::star::uno;
using namespace rtl;

namespace cppu
{

//************************************** generated, slightly modified for unicode revision
class XThrower : public ::com::sun::star::uno::XInterface
{
public:

    // Methods
    virtual void SAL_CALL throwException( const ::com::sun::star::uno::Any& rExc )
        SAL_THROW( (::com::sun::star::uno::Exception) ) = 0;
};

static
const ::com::sun::star::uno::Type& getCppuType( const ::com::sun::star::uno::Reference< ::cppu::XThrower >* )
    SAL_THROW( () )
{
    static ::com::sun::star::uno::Type * pType_cppu_XThrower = 0;

    if ( !pType_cppu_XThrower )
    {
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if ( !pType_cppu_XThrower )
    {
        // Start inline typedescription generation
        typelib_InterfaceTypeDescription * pTD = 0;

        const Type & rSuperType = ::getCppuType( ( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > *)0 );
        typelib_TypeDescriptionReference * pMembers[1] = { 0 };
        OUString aMemberTypeName( RTL_CONSTASCII_USTRINGPARAM("cppu.XThrower::throwException") );
        typelib_typedescriptionreference_new( &pMembers[0],
                                              (typelib_TypeClass)::com::sun::star::uno::TypeClass_INTERFACE_METHOD,
                                              aMemberTypeName.pData );

        OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("cppu.XThrower") );
        typelib_typedescription_newInterface(
            &pTD,
            aTypeName.pData, 0x3313e220, 0xb491, 0xb491, 0x9ede0050, 0x04d7677e,
            rSuperType.getTypeLibType(),
            1,
            pMembers );

        typelib_typedescription_register( (typelib_TypeDescription**)&pTD );
        typelib_typedescriptionreference_release( pMembers[0] );
        typelib_typedescription_release( (typelib_TypeDescription*)pTD );

        static ::com::sun::star::uno::Type aType_cppu_XThrower(
            ::com::sun::star::uno::TypeClass_INTERFACE, aTypeName.pData );
        ::getCppuType( (const ::com::sun::star::uno::Exception*)0 );

        typelib_InterfaceMethodTypeDescription * pMethod = 0;
        {
            typelib_Parameter_Init aParameters[1];
            OUString aParamName( RTL_CONSTASCII_USTRINGPARAM("rExc") );
            aParameters[0].pParamName = aParamName.pData;
            aParameters[0].eTypeClass = (typelib_TypeClass)::com::sun::star::uno::TypeClass_ANY;
            OUString aParamTypeName( RTL_CONSTASCII_USTRINGPARAM("any") );
            aParameters[0].pTypeName = aParamTypeName.pData;
            aParameters[0].bIn = sal_True;
            aParameters[0].bOut = sal_False;
            OUString aExceptionName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.Exception") );
            OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
            typelib_typedescription_newInterfaceMethod( &pMethod,
                3, sal_False,
                aMemberTypeName.pData,
                (typelib_TypeClass)::com::sun::star::uno::TypeClass_VOID, aVoidName.pData,
                1, aParameters,
                1, &aExceptionName.pData );
            typelib_typedescription_register( (typelib_TypeDescription**)&pMethod );
        }
        typelib_typedescription_release( (typelib_TypeDescription*)pMethod );
        // End inline typedescription generation
        pType_cppu_XThrower = &aType_cppu_XThrower;
    }
    }
    return *pType_cppu_XThrower;
}
//**************************************

//==================================================================================================
struct ExceptionThrower : public uno_Interface
{
    oslInterlockedCount         nRef;

    inline ExceptionThrower() SAL_THROW( () );
};
extern "C"
{
//--------------------------------------------------------------------------------------------------
static void SAL_CALL ExceptionThrower_acquire( uno_Interface * pUnoI ) SAL_THROW( () )
{
    osl_incrementInterlockedCount( & SAL_STATIC_CAST( ExceptionThrower *, pUnoI )->nRef );
}
//--------------------------------------------------------------------------------------------------
static void SAL_CALL ExceptionThrower_release( uno_Interface * pUnoI ) SAL_THROW( () )
{
    if (! osl_decrementInterlockedCount( & SAL_STATIC_CAST( ExceptionThrower *, pUnoI )->nRef ))
        delete SAL_STATIC_CAST( ExceptionThrower *, pUnoI );
}
//--------------------------------------------------------------------------------------------------
static void SAL_CALL ExceptionThrower_dispatch(
    uno_Interface * pUnoI, const typelib_TypeDescription * pMemberType,
    void * pReturn, void * pArgs[], uno_Any ** ppException )
    SAL_THROW( () )
{
    OSL_ASSERT( pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD );

    switch (((typelib_InterfaceMemberTypeDescription *)pMemberType)->nPosition)
    {
    case 0: // queryInterace()
    {
        if (::getCppuType( (const Reference< XInterface > *)0 ).equals( *(const Type *)pArgs[0] ))
        {
            const Type & rType = ::getCppuType( (const Reference< XInterface > *)0 );
            typelib_TypeDescription * pTD = 0;
            TYPELIB_DANGER_GET( &pTD, rType.getTypeLibType() );
            uno_any_construct( (uno_Any *)pReturn, &pUnoI, pTD, 0 );
            TYPELIB_DANGER_RELEASE( pTD );
        }
        else if (getCppuType( (const Reference< XThrower > *)0 ).equals( *(const Type *)pArgs[0] ))
        {
            const Type & rType = getCppuType( (const Reference< XThrower > *)0 );
            typelib_TypeDescription * pTD = 0;
            TYPELIB_DANGER_GET( &pTD, rType.getTypeLibType() );
            uno_any_construct( (uno_Any *)pReturn, &pUnoI, pTD, 0 );
            TYPELIB_DANGER_RELEASE( pTD );
        }
        else
        {
            uno_any_construct( (uno_Any *)pReturn, 0, 0, 0 );
        }
        *ppException = 0;
        break;
    }
    case 1: // acquire()
        ExceptionThrower_acquire( pUnoI );
        *ppException = 0;
        break;
    case 2: // release()
        ExceptionThrower_release( pUnoI );
        *ppException = 0;
        break;
    case 3: // throwException()
    {
        OSL_ASSERT( ((uno_Any *)pArgs[0])->pType->eTypeClass == typelib_TypeClass_EXCEPTION );

        uno_type_any_construct(
            *ppException, ((uno_Any *)pArgs[0])->pData, ((uno_Any *)pArgs[0])->pType, 0 );
        break;
    }
    default:
        OSL_ENSURE( sal_False, "### illegal member called!" );
    }
}
} // extern "C"
//__________________________________________________________________________________________________
inline ExceptionThrower::ExceptionThrower() SAL_THROW( () )
    : nRef( 0 )
{
    uno_Interface::acquire = ExceptionThrower_acquire;
    uno_Interface::release = ExceptionThrower_release;
    uno_Interface::pDispatcher = ExceptionThrower_dispatch;
}

//==================================================================================================
void SAL_CALL throwException( const Any & rExc ) SAL_THROW( (Exception) )
{
    if (rExc.getValueTypeClass() == TypeClass_EXCEPTION)
    {
        OUString aExceptionName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.Exception") );
        typelib_TypeDescription * pComp = 0;
        TYPELIB_DANGER_GET( &pComp, rExc.getValueTypeRef() );
        // must be derived from com.sun.star.uno.Exception
        for ( typelib_CompoundTypeDescription * pTD = (typelib_CompoundTypeDescription *)pComp;
              pTD; pTD = pTD->pBaseTypeDescription )
        {
            if (aExceptionName == rtl::OUString(((typelib_TypeDescription *)pTD)->pTypeName))
            {
                Mapping aUno2Cpp( OUString( RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO) ),
                                  OUString( RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME) ) );
                OSL_ENSURE( aUno2Cpp.is(), "### cannot get uno to cpp mapping!" );
                if (aUno2Cpp.is())
                {
                    uno_Interface * pUnoI = new ExceptionThrower();
                    (*pUnoI->acquire)( pUnoI );
                    Reference< XThrower > xThrower;
                    aUno2Cpp.mapInterface(
                        reinterpret_cast< void ** >( &xThrower ),
                        pUnoI, ::cppu::getCppuType( (const Reference< XThrower > *)0 ) );
                    (*pUnoI->release)( pUnoI );

                    if (xThrower.is())
                    {
                        TYPELIB_DANGER_RELEASE( pComp );
                        xThrower->throwException( rExc );
                    }
                }
                break;
            }
        }
        TYPELIB_DANGER_RELEASE( pComp );
    }
    throw RuntimeException(
        OUString( RTL_CONSTASCII_USTRINGPARAM("failed throwing exception generically!") ),
        Reference< XInterface >() );
}

}
<commit_msg>INTEGRATION: CWS unopkg (1.4.90); FILE MERGED 2003/09/30 13:37:59 dbo 1.4.90.2: #112449# 2003/09/26 13:01:38 dbo 1.4.90.1: #112449# added ::cppu::getCaughtException()<commit_after>/*************************************************************************
 *
 *  $RCSfile: exc_thrower.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: vg $ $Date: 2003-10-06 12:55:55 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "osl/diagnose.h"
#include "osl/doublecheckedlocking.h"
#include "osl/mutex.hxx"
#include "uno/dispatcher.hxx"
#include "uno/mapping.hxx"
#include "cppu/XExceptionThrower.hpp"

#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )

using namespace ::rtl;
using namespace ::osl;
using namespace ::cppu;
using namespace ::com::sun::star::uno;

namespace
{

//==============================================================================
struct ExceptionThrower : public uno_Interface, XExceptionThrower
{
    inline ExceptionThrower();

public:
    static ExceptionThrower * get();
    static inline Type const & getCppuType()
    {
        return ::getCppuType(
            reinterpret_cast< Reference< XExceptionThrower > const * >(0) );
    }

    // XInterface
    virtual Any SAL_CALL queryInterface( Type const & type )
        throw (RuntimeException);
    virtual void SAL_CALL acquire() throw ();
    virtual void SAL_CALL release() throw ();

    // XExceptionThrower
    virtual void SAL_CALL throwException( Any const & exc ) throw (Exception);
    virtual void SAL_CALL rethrowException() throw (Exception);
};

extern "C"
{

//------------------------------------------------------------------------------
static void SAL_CALL ExceptionThrower_acquire_release_nop( uno_Interface * )
{
}

//------------------------------------------------------------------------------
static void SAL_CALL ExceptionThrower_dispatch(
    uno_Interface * pUnoI, typelib_TypeDescription const * pMemberType,
    void * pReturn, void * pArgs [], uno_Any ** ppException )
{
    OSL_ASSERT( pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD );

    switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription * >(
                const_cast< typelib_TypeDescription * >( pMemberType ) )->
            nPosition)
    {
    case 0: // queryInterace()
    {
        Type const & rType_demanded =
            *reinterpret_cast< Type const * >( pArgs[ 0 ] );
        if (rType_demanded.equals(
                ::getCppuType( reinterpret_cast<
                               Reference< XInterface > const * >(0) ) ) ||
            rType_demanded.equals( ExceptionThrower::getCppuType() ))
        {
            typelib_TypeDescription * pTD = 0;
            TYPELIB_DANGER_GET( &pTD, rType_demanded.getTypeLibType() );
            uno_any_construct(
                reinterpret_cast< uno_Any * >( pReturn ), &pUnoI, pTD, 0 );
            TYPELIB_DANGER_RELEASE( pTD );
        }
        else
        {
            uno_any_construct(
                reinterpret_cast< uno_Any * >( pReturn ), 0, 0, 0 );
        }
        *ppException = 0;
        break;
    }
    case 1: // acquire()
    case 2: // release()
        *ppException = 0;
        break;
    case 3: // throwException()
    {
        uno_Any * pAny = reinterpret_cast< uno_Any * >( pArgs[ 0 ] );
        OSL_ASSERT( pAny->pType->eTypeClass == typelib_TypeClass_EXCEPTION );
        uno_type_any_construct( *ppException, pAny->pData, pAny->pType, 0 );
        break;
    }
    default:
    {
        OSL_ASSERT( 0 );
        RuntimeException exc(
            OUSTR("not implemented!"), Reference< XInterface >() );
        uno_type_any_construct(
            *ppException, &exc, ::getCppuType( &exc ).getTypeLibType(), 0 );
        break;
    }
    }
}

} // extern "C"

//______________________________________________________________________________
Any ExceptionThrower::queryInterface( Type const & type )
    throw (RuntimeException)
{
    if (type.equals( ::getCppuType( reinterpret_cast<
                                    Reference< XInterface > const * >(0) ) ) ||
        type.equals( ExceptionThrower::getCppuType() ))
    {
        XExceptionThrower * that = static_cast< XExceptionThrower * >( this );
        return Any( &that, type );
    }
    return Any();
}

//______________________________________________________________________________
void ExceptionThrower::acquire() throw ()
{
}
//______________________________________________________________________________
void ExceptionThrower::release() throw ()
{
}

//______________________________________________________________________________
void ExceptionThrower::throwException( Any const & exc ) throw (Exception)
{
    OSL_ENSURE( 0, "unexpected!" );
    throwException( exc );
}

//______________________________________________________________________________
void ExceptionThrower::rethrowException() throw (Exception)
{
    throw;
}

//______________________________________________________________________________
inline ExceptionThrower::ExceptionThrower()
{
    uno_Interface::acquire = ExceptionThrower_acquire_release_nop;
    uno_Interface::release = ExceptionThrower_acquire_release_nop;
    uno_Interface::pDispatcher = ExceptionThrower_dispatch;
}

//______________________________________________________________________________
ExceptionThrower * ExceptionThrower::get()
{
    ExceptionThrower * s_pThrower = 0;
    if (s_pThrower == 0)
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        static ExceptionThrower s_thrower;
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
        s_pThrower = &s_thrower;
    }
    else
    {
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
    }
    return s_pThrower;
}

} // anonymous namespace

namespace cppu
{

//==============================================================================
void SAL_CALL throwException( Any const & exc ) SAL_THROW( (Exception) )
{
    if (exc.getValueTypeClass() != TypeClass_EXCEPTION)
    {
        throw RuntimeException(
            OUSTR("no UNO exception given "
                  "(must be derived from com::sun::star::uno::Exception)!"),
            Reference< XInterface >() );
    }

    Mapping uno2cpp(
        OUSTR(UNO_LB_UNO), OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME) );
    if (! uno2cpp.is())
    {
        throw RuntimeException(
            OUSTR("cannot get binary UNO to C++ mapping!"),
            Reference< XInterface >() );
    }

    Reference< XExceptionThrower > xThrower;
    uno2cpp.mapInterface(
        reinterpret_cast< void ** >( &xThrower ),
        static_cast< uno_Interface * >( ExceptionThrower::get() ),
        ExceptionThrower::getCppuType() );
    OSL_ASSERT( xThrower.is() );
    xThrower->throwException( exc );
}

//==============================================================================
Any SAL_CALL getCaughtException()
{
    Mapping cpp2uno(
        OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME), OUSTR(UNO_LB_UNO) );
    if (! cpp2uno.is())
    {
        throw RuntimeException(
            OUSTR("cannot get C++ to binary UNO mapping!"),
            Reference< XInterface >() );
    }
    Mapping uno2cpp(
        OUSTR(UNO_LB_UNO), OUSTR(CPPU_CURRENT_LANGUAGE_BINDING_NAME) );
    if (! uno2cpp.is())
    {
        throw RuntimeException(
            OUSTR("cannot get binary UNO to C++ mapping!"),
            Reference< XInterface >() );
    }

    typelib_TypeDescription * pTD = 0;
    TYPELIB_DANGER_GET(
        &pTD, ExceptionThrower::getCppuType().getTypeLibType() );

    UnoInterfaceReference unoI;
    cpp2uno.mapInterface(
        reinterpret_cast< void ** >( &unoI.m_pUnoI ),
        static_cast< XExceptionThrower * >( ExceptionThrower::get() ), pTD );
    OSL_ASSERT( unoI.is() );

    typelib_TypeDescription * pMemberTD = 0;
    TYPELIB_DANGER_GET(
        &pMemberTD,
        reinterpret_cast< typelib_InterfaceTypeDescription * >( pTD )->
        ppMembers[ 1 ] /* rethrowException() */ );

    uno_Any exc_mem;
    uno_Any * exc = &exc_mem;
    unoI.dispatch( pMemberTD, 0, 0, &exc );

    TYPELIB_DANGER_RELEASE( pMemberTD );
    TYPELIB_DANGER_RELEASE( pTD );

    if (exc == 0)
    {
        throw RuntimeException(
            OUSTR("rethrowing C++ exception failed!"),
            Reference< XInterface >() );
    }

    Any ret;
    uno_any_destruct( &ret, cpp_release );
    uno_type_any_constructAndConvert(
        &ret, exc->pData, exc->pType, uno2cpp.get() );
    uno_any_destruct( exc, 0 );
    return ret;
}

}
<|endoftext|>


<commit_before><commit_msg>remove accidentally committed debugging spew<commit_after><|endoftext|>