<commit_before>/******************************************************************************

  This source file is part of the MoleQueue project.

  Copyright 2012 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "message.h"

#include "connection.h"
#include "messageidmanager_p.h"

#include <qjsonarray.h>
#include <qjsondocument.h>

#include <QtCore/QDebug>
#include <QtCore/QStringList>

namespace MoleQueue {

// Dummy value returned by *Ref() functions called with invalid types.
QJsonValue dummyValue(QJsonValue::Null);

Message::Message(Connection *conn, EndpointIdType endpoint_)
  : m_type(Invalid),
    m_errorCode(0),
    m_connection(conn),
    m_endpoint(endpoint_)
{
}

Message::Message(Message::MessageType type_, Connection *conn,
                 EndpointIdType endpoint_)
  : m_type(type_),
    m_errorCode(0),
    m_connection(conn),
    m_endpoint(endpoint_)
{
}

Message::Message(const QJsonObject &rawJson, Connection *conn,
                 EndpointIdType endpoint_)
  : m_type(Raw),
    m_errorCode(0),
    m_rawJson(rawJson),
    m_connection(conn),
    m_endpoint(endpoint_)
{
}

Message::Message(const Message &other)
  : m_type(other.m_type),
    m_method(other.m_method),
    m_id(other.m_id),
    m_params(other.m_params),
    m_result(other.m_result),
    m_errorCode(other.m_errorCode),
    m_errorMessage(other.m_errorMessage),
    m_errorData(other.m_errorData),
    m_rawJson(other.m_rawJson),
    m_connection(other.m_connection),
    m_endpoint(other.m_endpoint)
{
}

Message& Message::operator=(const Message &other)
{
  m_type = other.m_type;
  m_method = other.m_method;
  m_id = other.m_id;
  m_params = other.m_params;
  m_result = other.m_result;
  m_errorCode = other.m_errorCode;
  m_errorMessage = other.m_errorMessage;
  m_errorData = other.m_errorData;
  m_rawJson = other.m_rawJson;
  m_connection = other.m_connection;
  m_endpoint = other.m_endpoint;
  return *this;
}

Message::MessageType Message::type() const
{
  return m_type;
}

QString Message::method() const
{
  if (!checkType(Q_FUNC_INFO, Request | Notification | Response | Error))
    return QString();

  return m_method;
}

void Message::setMethod(const QString &m)
{
  if (!checkType(Q_FUNC_INFO, Request | Notification | Response | Error))
    return;

  m_method = m;
}

QJsonValue Message::params() const
{
  if (!checkType(Q_FUNC_INFO, Request | Notification))
    return QJsonValue();

  return m_params;
}

QJsonValue& Message::paramsRef()
{
  if (!checkType(Q_FUNC_INFO, Request | Notification))
    return dummyValue;

  return m_params;
}

void Message::setParams(const QJsonArray &p)
{
  if (!checkType(Q_FUNC_INFO, Request | Notification))
    return;

  m_params = p;
}

void Message::setParams(const QJsonObject &p)
{
  if (!checkType(Q_FUNC_INFO, Request | Notification))
    return;

  m_params = p;
}

QJsonValue Message::result() const
{
  if (!checkType(Q_FUNC_INFO, Response))
    return QJsonValue();

  return m_result;
}

QJsonValue& Message::resultRef()
{
  if (!checkType(Q_FUNC_INFO, Response))
    return dummyValue;

  return m_result;
}

void Message::setResult(const QJsonValue &r)
{
  if (!checkType(Q_FUNC_INFO, Response))
    return;

  m_result = r;
}

int Message::errorCode() const
{
  if (!checkType(Q_FUNC_INFO, Error))
    return 0;

  return m_errorCode;
}

void Message::setErrorCode(int e)
{
  if (!checkType(Q_FUNC_INFO, Error))
    return;

  m_errorCode = e;
}

QString Message::errorMessage() const
{
  if (!checkType(Q_FUNC_INFO, Error))
    return QString();

  return m_errorMessage;
}

void Message::setErrorMessage(const QString &e)
{
  if (!checkType(Q_FUNC_INFO,Error))
    return;

  m_errorMessage = e;
}

QJsonValue Message::errorData() const
{
  if (!checkType(Q_FUNC_INFO, Error))
    return QJsonValue();

  return m_errorData;
}

QJsonValue& Message::errorDataRef()
{
  if (!checkType(Q_FUNC_INFO, Error))
    return dummyValue;

  return m_errorData;
}

void Message::setErrorData(const QJsonValue &e)
{
  if (!checkType(Q_FUNC_INFO, Error))
    return;

  m_errorData = e;
}

MessageIdType Message::id() const
{
  if (!checkType(Q_FUNC_INFO, Request | Response | Error))
    return MessageIdType();

  return m_id;
}

void Message::setId(const MessageIdType &i)
{
  if (!checkType(Q_FUNC_INFO, Request | Response | Error))
    return;

  m_id = i;
}

Connection* Message::connection() const
{
  return m_connection;
}

void Message::setConnection(Connection* c)
{
  m_connection = c;
}

EndpointIdType Message::endpoint() const
{
  return m_endpoint;
}

void Message::setEndpoint(const EndpointIdType &e)
{
  m_endpoint = e;
}

QJsonObject Message::toJsonObject() const
{
  QJsonObject obj;

  switch (m_type) {
  case MoleQueue::Message::Request:
    obj.insert("jsonrpc", QLatin1String("2.0"));
    obj.insert("method", m_method);
    if ((m_params.isObject() && !m_params.toObject().isEmpty()) ||
        (m_params.isArray() && !m_params.toArray().isEmpty())) {
      obj.insert("params", m_params);
    }
    obj.insert("id", m_id);
    break;
  case MoleQueue::Message::Notification:
    obj.insert("jsonrpc", QLatin1String("2.0"));
    obj.insert("method", m_method);
    if ((m_params.isObject() && !m_params.toObject().isEmpty()) ||
        (m_params.isArray() && !m_params.toArray().isEmpty())) {
      obj.insert("params", m_params);
    }
    break;
  case MoleQueue::Message::Response:
    obj.insert("jsonrpc", QLatin1String("2.0"));
    obj.insert("result", m_result);
    obj.insert("id", m_id);
    break;
  case MoleQueue::Message::Error: {
    QJsonObject errorObject;
    errorObject.insert("code", m_errorCode);
    errorObject.insert("message", m_errorMessage);
    if (!m_errorData.isNull())
      errorObject.insert("data", m_errorData);

    obj.insert("jsonrpc", QLatin1String("2.0"));
    obj.insert("error", errorObject);
    obj.insert("id", m_id);
    }
    break;
  case MoleQueue::Message::Raw:
    obj = m_rawJson;
    break;
  case MoleQueue::Message::Invalid:
    qWarning() << "Cannot convert invalid message to a JSON object.";
    break;
  }
  return obj;
}

PacketType Message::toJson() const
{
  QJsonDocument doc(toJsonObject());
  return PacketType(doc.toJson());
}

bool Message::send()
{
  if (m_type == Invalid || !m_connection || !m_connection->isOpen())
    return false;

  if (m_type == Request)
    m_id = MessageIdManager::registerMethod(m_method);

  return m_connection->send(toJson(), m_endpoint);
}

Message Message::generateResponse() const
{
  if (!checkType(Q_FUNC_INFO, Request))
    return Message();

  Message resp(Response, m_connection, m_endpoint);
  resp.m_method     = m_method;
  resp.m_id         = m_id;
  return resp;
}

Message Message::generateErrorResponse() const
{
  if (!checkType(Q_FUNC_INFO, Request | Raw | Invalid))
    return Message();

  Message resp(Error, m_connection, m_endpoint);
  resp.m_method     = m_method;
  resp.m_id         = m_id;
  return resp;
}

bool Message::parse()
{
  Message message;
  return parse(message);
}

bool Message::parse(Message &errorMessage_)
{
  // Can only parse Raw types -- return true if this message is already parsed
  // or invalid.
  if (m_type != Raw)
    return true;

  QJsonObject json = m_rawJson;

  // Validate the message
  QStringList errors;

  // jsonrpc must equal "2.0"
  if (!json.contains("jsonrpc"))
    errors << "jsonrpc key missing.";
  if (!json.value("jsonrpc").isString())
    errors << "jsonrpc key must be a string.";
  if (json.value("jsonrpc").toString() != "2.0") {
    errors << QString("Unrecognized jsonrpc string: %1")
              .arg(json.value("jsonrpc").toString());
  }

  // Must have either id or method
  if (!json.contains("id") && !json.contains("method"))
    errors << "Missing both id and method.";

  // If method is present, it must be a string.
  QString method_;
  if (json.contains("method")) {
    if (!json.value("method").isString())
      errors << "method must be a string.";
    else
      method_ = json.value("method").toString();
  }
  else {
    // Lookup method for response/error.
    method_ = MessageIdManager::lookupMethod(json.value("id"));
  }

  // If any errors have occurred, prep the response:
  if (!errors.empty()) {
    errors.prepend("Invalid request:");
    QJsonObject errorDataObject;
    errorDataObject.insert("description", errors.join(" "));
    errorDataObject.insert("request", json);
    errorMessage_ = generateErrorResponse();
    errorMessage_.setErrorCode(-32600);
    errorMessage_.setErrorMessage("Invalid request");
    errorMessage_.setErrorData(errorDataObject);
    return false;
  }

  // Results, errors, and notifications cannot return errors. Parse them
  // as best we can and return true.
  if (json.contains("result")) {
    interpretResponse(json, method_);
    return true;
  }
  else if (json.contains("error")) {
    interpretError(json, method_);
    return true;
  }
  else if (!json.contains("id")) {
    interpretNotification(json);
    return true;
  }

  // Assume anything else is a request.
  return interpretRequest(json, errorMessage_);
}

inline
bool Message::checkType(const char *method_, MessageTypes validTypes) const
{
  if (m_type & validTypes)
    return true;

  qWarning() << "Invalid message type in call.\n"
             << "  Method:" << method_ << "\n"
             << "  Valid types:" << validTypes << "\n"
             << "  Actual type:" << m_type;
  return false;
}

bool Message::interpretRequest(const QJsonObject &json, Message &errorMessage_)
{
  QStringList errors;

  // method must exist and be a string.
  if (!json.value("method").isString())
    errors << "method is not a string.";

  // id must be present.
  if (!json.contains("id"))
    errors << "id missing.";

  // params is optional, but must be structured if present.
  if (json.contains("params") &&
      !json.value("params").isArray() &&
      !json.value("params").isObject()) {
    errors << "params must be structured if present.";
  }

  if (!errors.empty()) {
    errors.prepend("Invalid request:");
    QJsonObject errorDataObject;
    errorDataObject.insert("description", errors.join(" "));
    errorDataObject.insert("request", json);
    errorMessage_ = generateErrorResponse();
    errorMessage_.setErrorCode(-32600);
    errorMessage_.setErrorMessage("Invalid request");
    errorMessage_.setErrorData(errorDataObject);
    return false;
  }

  m_type = Request;
  m_method = json.value("method").toString();
  if (json.contains("params"))
    m_params = json.value("params");
  else
    m_params = QJsonValue();
  m_id = MessageIdType(json.value("id"));
  return true;
}

void Message::interpretNotification(const QJsonObject &json)
{
  m_type = Notification;
  m_method = json.value("method").toString();
  if (json.contains("params"))
    m_params = json.value("params");
  else
    m_params = QJsonValue();
  m_id = MessageIdType();
  return;
}

void Message::interpretResponse(const QJsonObject &json, const QString &method_)
{
  m_type = Response;
  m_method = method_;
  m_result = json.value("result");
  m_id = json.value("id");
  return;
}

void Message::interpretError(const QJsonObject &json, const QString &method_)
{
  m_type = Error;
  m_method = method_;
  m_id = json.value("id");

  // We cannot send an error reply if we receive a malformated error message.
  // If this happens, generate a server error (-32000) with the original error
  // member as the error data (there must be an error member defined for this
  // function to be called)
  QStringList errors;
  QJsonValue errorValue = json.value("error");
  if (!errorValue.isObject()) {
    errors << "error must be an object.";
  }
  else {
    QJsonObject errorObject = errorValue.toObject();

    // error.code validation
    if (!errorObject.contains("code")) {
      errors << "error.code missing.";
    }
    else {
      // Check that error.code is integral. There is no QJsonValue.isInt()
      // method, only isDouble, so the test is more complicated than it should
      // be...
      if (!errorObject.value("code").isDouble()) {
        errors << "error.code is not numeric.";
      }
      else {
        double code = errorObject.value("code").toDouble();
        if (qAbs(code - static_cast<double>(static_cast<int>(code))) > 1e-5)
          errors << "error.code is not integral.";
        else
          m_errorCode = static_cast<int>(code);
      }
    }

    // error.message validation
    if (!errorObject.contains("message")) {
      errors << "error.message missing.";
    }
    else {
      if (!errorObject.value("message").isString())
        errors << "error.message is not a string.";
      else
        m_errorMessage = errorObject.value("message").toString();
    }

    if (errorObject.contains("data"))
      m_errorData = errorObject.value("data");
  }

  // If any errors occured, reset the error members to a server error.
  if (!errors.empty()) {
    m_errorCode = -32000;
    m_errorMessage = "Server error";

    QJsonObject errorDataObject;
    errors.prepend("Malformed error response:");
    errorDataObject.insert("description", errors.join(" "));
    errorDataObject.insert("origMessage", errorValue);
    m_errorData = errorDataObject;
  }
}

} // namespace MoleQueue
<commit_msg>Eliminate unnecessary copy in Message::parse.<commit_after>/******************************************************************************

  This source file is part of the MoleQueue project.

  Copyright 2012 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "message.h"

#include "connection.h"
#include "messageidmanager_p.h"

#include <qjsonarray.h>
#include <qjsondocument.h>

#include <QtCore/QDebug>
#include <QtCore/QStringList>

namespace MoleQueue {

// Dummy value returned by *Ref() functions called with invalid types.
QJsonValue dummyValue(QJsonValue::Null);

Message::Message(Connection *conn, EndpointIdType endpoint_)
  : m_type(Invalid),
    m_errorCode(0),
    m_connection(conn),
    m_endpoint(endpoint_)
{
}

Message::Message(Message::MessageType type_, Connection *conn,
                 EndpointIdType endpoint_)
  : m_type(type_),
    m_errorCode(0),
    m_connection(conn),
    m_endpoint(endpoint_)
{
}

Message::Message(const QJsonObject &rawJson, Connection *conn,
                 EndpointIdType endpoint_)
  : m_type(Raw),
    m_errorCode(0),
    m_rawJson(rawJson),
    m_connection(conn),
    m_endpoint(endpoint_)
{
}

Message::Message(const Message &other)
  : m_type(other.m_type),
    m_method(other.m_method),
    m_id(other.m_id),
    m_params(other.m_params),
    m_result(other.m_result),
    m_errorCode(other.m_errorCode),
    m_errorMessage(other.m_errorMessage),
    m_errorData(other.m_errorData),
    m_rawJson(other.m_rawJson),
    m_connection(other.m_connection),
    m_endpoint(other.m_endpoint)
{
}

Message& Message::operator=(const Message &other)
{
  m_type = other.m_type;
  m_method = other.m_method;
  m_id = other.m_id;
  m_params = other.m_params;
  m_result = other.m_result;
  m_errorCode = other.m_errorCode;
  m_errorMessage = other.m_errorMessage;
  m_errorData = other.m_errorData;
  m_rawJson = other.m_rawJson;
  m_connection = other.m_connection;
  m_endpoint = other.m_endpoint;
  return *this;
}

Message::MessageType Message::type() const
{
  return m_type;
}

QString Message::method() const
{
  if (!checkType(Q_FUNC_INFO, Request | Notification | Response | Error))
    return QString();

  return m_method;
}

void Message::setMethod(const QString &m)
{
  if (!checkType(Q_FUNC_INFO, Request | Notification | Response | Error))
    return;

  m_method = m;
}

QJsonValue Message::params() const
{
  if (!checkType(Q_FUNC_INFO, Request | Notification))
    return QJsonValue();

  return m_params;
}

QJsonValue& Message::paramsRef()
{
  if (!checkType(Q_FUNC_INFO, Request | Notification))
    return dummyValue;

  return m_params;
}

void Message::setParams(const QJsonArray &p)
{
  if (!checkType(Q_FUNC_INFO, Request | Notification))
    return;

  m_params = p;
}

void Message::setParams(const QJsonObject &p)
{
  if (!checkType(Q_FUNC_INFO, Request | Notification))
    return;

  m_params = p;
}

QJsonValue Message::result() const
{
  if (!checkType(Q_FUNC_INFO, Response))
    return QJsonValue();

  return m_result;
}

QJsonValue& Message::resultRef()
{
  if (!checkType(Q_FUNC_INFO, Response))
    return dummyValue;

  return m_result;
}

void Message::setResult(const QJsonValue &r)
{
  if (!checkType(Q_FUNC_INFO, Response))
    return;

  m_result = r;
}

int Message::errorCode() const
{
  if (!checkType(Q_FUNC_INFO, Error))
    return 0;

  return m_errorCode;
}

void Message::setErrorCode(int e)
{
  if (!checkType(Q_FUNC_INFO, Error))
    return;

  m_errorCode = e;
}

QString Message::errorMessage() const
{
  if (!checkType(Q_FUNC_INFO, Error))
    return QString();

  return m_errorMessage;
}

void Message::setErrorMessage(const QString &e)
{
  if (!checkType(Q_FUNC_INFO,Error))
    return;

  m_errorMessage = e;
}

QJsonValue Message::errorData() const
{
  if (!checkType(Q_FUNC_INFO, Error))
    return QJsonValue();

  return m_errorData;
}

QJsonValue& Message::errorDataRef()
{
  if (!checkType(Q_FUNC_INFO, Error))
    return dummyValue;

  return m_errorData;
}

void Message::setErrorData(const QJsonValue &e)
{
  if (!checkType(Q_FUNC_INFO, Error))
    return;

  m_errorData = e;
}

MessageIdType Message::id() const
{
  if (!checkType(Q_FUNC_INFO, Request | Response | Error))
    return MessageIdType();

  return m_id;
}

void Message::setId(const MessageIdType &i)
{
  if (!checkType(Q_FUNC_INFO, Request | Response | Error))
    return;

  m_id = i;
}

Connection* Message::connection() const
{
  return m_connection;
}

void Message::setConnection(Connection* c)
{
  m_connection = c;
}

EndpointIdType Message::endpoint() const
{
  return m_endpoint;
}

void Message::setEndpoint(const EndpointIdType &e)
{
  m_endpoint = e;
}

QJsonObject Message::toJsonObject() const
{
  QJsonObject obj;

  switch (m_type) {
  case MoleQueue::Message::Request:
    obj.insert("jsonrpc", QLatin1String("2.0"));
    obj.insert("method", m_method);
    if ((m_params.isObject() && !m_params.toObject().isEmpty()) ||
        (m_params.isArray() && !m_params.toArray().isEmpty())) {
      obj.insert("params", m_params);
    }
    obj.insert("id", m_id);
    break;
  case MoleQueue::Message::Notification:
    obj.insert("jsonrpc", QLatin1String("2.0"));
    obj.insert("method", m_method);
    if ((m_params.isObject() && !m_params.toObject().isEmpty()) ||
        (m_params.isArray() && !m_params.toArray().isEmpty())) {
      obj.insert("params", m_params);
    }
    break;
  case MoleQueue::Message::Response:
    obj.insert("jsonrpc", QLatin1String("2.0"));
    obj.insert("result", m_result);
    obj.insert("id", m_id);
    break;
  case MoleQueue::Message::Error: {
    QJsonObject errorObject;
    errorObject.insert("code", m_errorCode);
    errorObject.insert("message", m_errorMessage);
    if (!m_errorData.isNull())
      errorObject.insert("data", m_errorData);

    obj.insert("jsonrpc", QLatin1String("2.0"));
    obj.insert("error", errorObject);
    obj.insert("id", m_id);
    }
    break;
  case MoleQueue::Message::Raw:
    obj = m_rawJson;
    break;
  case MoleQueue::Message::Invalid:
    qWarning() << "Cannot convert invalid message to a JSON object.";
    break;
  }
  return obj;
}

PacketType Message::toJson() const
{
  QJsonDocument doc(toJsonObject());
  return PacketType(doc.toJson());
}

bool Message::send()
{
  if (m_type == Invalid || !m_connection || !m_connection->isOpen())
    return false;

  if (m_type == Request)
    m_id = MessageIdManager::registerMethod(m_method);

  return m_connection->send(toJson(), m_endpoint);
}

Message Message::generateResponse() const
{
  if (!checkType(Q_FUNC_INFO, Request))
    return Message();

  Message resp(Response, m_connection, m_endpoint);
  resp.m_method     = m_method;
  resp.m_id         = m_id;
  return resp;
}

Message Message::generateErrorResponse() const
{
  if (!checkType(Q_FUNC_INFO, Request | Raw | Invalid))
    return Message();

  Message resp(Error, m_connection, m_endpoint);
  resp.m_method     = m_method;
  resp.m_id         = m_id;
  return resp;
}

bool Message::parse()
{
  Message message;
  return parse(message);
}

bool Message::parse(Message &errorMessage_)
{
  // Can only parse Raw types -- return true if this message is already parsed
  // or invalid.
  if (m_type != Raw)
    return true;

  // Validate the message
  QStringList errors;

  // jsonrpc must equal "2.0"
  if (!m_rawJson.contains("jsonrpc"))
    errors << "jsonrpc key missing.";
  if (!m_rawJson.value("jsonrpc").isString())
    errors << "jsonrpc key must be a string.";
  if (m_rawJson.value("jsonrpc").toString() != "2.0") {
    errors << QString("Unrecognized jsonrpc string: %1")
              .arg(m_rawJson.value("jsonrpc").toString());
  }

  // Must have either id or method
  if (!m_rawJson.contains("id") && !m_rawJson.contains("method"))
    errors << "Missing both id and method.";

  // If method is present, it must be a string.
  QString method_;
  if (m_rawJson.contains("method")) {
    if (!m_rawJson.value("method").isString())
      errors << "method must be a string.";
    else
      method_ = m_rawJson.value("method").toString();
  }
  else {
    // Lookup method for response/error.
    method_ = MessageIdManager::lookupMethod(m_rawJson.value("id"));
  }

  // If any errors have occurred, prep the response:
  if (!errors.empty()) {
    errors.prepend("Invalid request:");
    QJsonObject errorDataObject;
    errorDataObject.insert("description", errors.join(" "));
    errorDataObject.insert("request", m_rawJson);
    errorMessage_ = generateErrorResponse();
    errorMessage_.setErrorCode(-32600);
    errorMessage_.setErrorMessage("Invalid request");
    errorMessage_.setErrorData(errorDataObject);
    return false;
  }

  // Results, errors, and notifications cannot return errors. Parse them
  // as best we can and return true.
  if (m_rawJson.contains("result")) {
    interpretResponse(m_rawJson, method_);
    return true;
  }
  else if (m_rawJson.contains("error")) {
    interpretError(m_rawJson, method_);
    return true;
  }
  else if (!m_rawJson.contains("id")) {
    interpretNotification(m_rawJson);
    return true;
  }

  // Assume anything else is a request.
  return interpretRequest(m_rawJson, errorMessage_);
}

inline
bool Message::checkType(const char *method_, MessageTypes validTypes) const
{
  if (m_type & validTypes)
    return true;

  qWarning() << "Invalid message type in call.\n"
             << "  Method:" << method_ << "\n"
             << "  Valid types:" << validTypes << "\n"
             << "  Actual type:" << m_type;
  return false;
}

bool Message::interpretRequest(const QJsonObject &json, Message &errorMessage_)
{
  QStringList errors;

  // method must exist and be a string.
  if (!json.value("method").isString())
    errors << "method is not a string.";

  // id must be present.
  if (!json.contains("id"))
    errors << "id missing.";

  // params is optional, but must be structured if present.
  if (json.contains("params") &&
      !json.value("params").isArray() &&
      !json.value("params").isObject()) {
    errors << "params must be structured if present.";
  }

  if (!errors.empty()) {
    errors.prepend("Invalid request:");
    QJsonObject errorDataObject;
    errorDataObject.insert("description", errors.join(" "));
    errorDataObject.insert("request", json);
    errorMessage_ = generateErrorResponse();
    errorMessage_.setErrorCode(-32600);
    errorMessage_.setErrorMessage("Invalid request");
    errorMessage_.setErrorData(errorDataObject);
    return false;
  }

  m_type = Request;
  m_method = json.value("method").toString();
  if (json.contains("params"))
    m_params = json.value("params");
  else
    m_params = QJsonValue();
  m_id = MessageIdType(json.value("id"));
  return true;
}

void Message::interpretNotification(const QJsonObject &json)
{
  m_type = Notification;
  m_method = json.value("method").toString();
  if (json.contains("params"))
    m_params = json.value("params");
  else
    m_params = QJsonValue();
  m_id = MessageIdType();
  return;
}

void Message::interpretResponse(const QJsonObject &json, const QString &method_)
{
  m_type = Response;
  m_method = method_;
  m_result = json.value("result");
  m_id = json.value("id");
  return;
}

void Message::interpretError(const QJsonObject &json, const QString &method_)
{
  m_type = Error;
  m_method = method_;
  m_id = json.value("id");

  // We cannot send an error reply if we receive a malformated error message.
  // If this happens, generate a server error (-32000) with the original error
  // member as the error data (there must be an error member defined for this
  // function to be called)
  QStringList errors;
  QJsonValue errorValue = json.value("error");
  if (!errorValue.isObject()) {
    errors << "error must be an object.";
  }
  else {
    QJsonObject errorObject = errorValue.toObject();

    // error.code validation
    if (!errorObject.contains("code")) {
      errors << "error.code missing.";
    }
    else {
      // Check that error.code is integral. There is no QJsonValue.isInt()
      // method, only isDouble, so the test is more complicated than it should
      // be...
      if (!errorObject.value("code").isDouble()) {
        errors << "error.code is not numeric.";
      }
      else {
        double code = errorObject.value("code").toDouble();
        if (qAbs(code - static_cast<double>(static_cast<int>(code))) > 1e-5)
          errors << "error.code is not integral.";
        else
          m_errorCode = static_cast<int>(code);
      }
    }

    // error.message validation
    if (!errorObject.contains("message")) {
      errors << "error.message missing.";
    }
    else {
      if (!errorObject.value("message").isString())
        errors << "error.message is not a string.";
      else
        m_errorMessage = errorObject.value("message").toString();
    }

    if (errorObject.contains("data"))
      m_errorData = errorObject.value("data");
  }

  // If any errors occured, reset the error members to a server error.
  if (!errors.empty()) {
    m_errorCode = -32000;
    m_errorMessage = "Server error";

    QJsonObject errorDataObject;
    errors.prepend("Malformed error response:");
    errorDataObject.insert("description", errors.join(" "));
    errorDataObject.insert("origMessage", errorValue);
    m_errorData = errorDataObject;
  }
}

} // namespace MoleQueue
<|endoftext|>


<commit_before>#include <algorithm>
#include <cassert>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <functional>
#include <iostream>
#include <memory>
#include <random>
#include <string>

#include "chainerx/array.h"
#include "chainerx/array_index.h"
#include "chainerx/backprop_mode.h"
#include "chainerx/backward.h"
#include "chainerx/device_id.h"
#include "chainerx/dtype.h"
#include "chainerx/routines/creation.h"
#include "chainerx/routines/linalg.h"
#include "chainerx/routines/manipulation.h"
#include "chainerx/routines/math.h"
#include "chainerx/shape.h"
#include "chainerx/slice.h"
#include "mnist.h"

chainerx::Array GetRandomArray(std::mt19937& gen, std::normal_distribution<float>& dist, const chainerx::Shape& shape) {
    int64_t n = shape.GetTotalSize();
    std::shared_ptr<float> data{new float[n], std::default_delete<float[]>{}};
    std::generate_n(data.get(), n, [&dist, &gen]() { return dist(gen); });
    return chainerx::FromContiguousHostData(
            shape, chainerx::TypeToDtype<float>, static_cast<std::shared_ptr<void>>(data), chainerx::GetDefaultDevice());
}

class Model {
public:
    Model(int64_t n_in, int64_t n_hidden, int64_t n_out, int64_t n_layers)
        : n_in_{n_in}, n_hidden_{n_hidden}, n_out_{n_out}, n_layers_{n_layers} {};

    chainerx::Array operator()(const chainerx::Array& x) {
        chainerx::Array h = x;
        for (int64_t i = 0; i < n_layers_; ++i) {
            h = chainerx::Dot(h, params_[i * 2]) + params_[i * 2 + 1];
            if (i != n_layers_ - 1) {
                h = chainerx::Maximum(0, h);
            }
        }
        return h;
    }

    const std::vector<chainerx::Array>& params() { return params_; }

    void Initialize(std::mt19937& gen, std::normal_distribution<float>& dist) {
        params_.clear();

        for (int64_t i = 0; i < n_layers_; ++i) {
            int64_t n_in = i == 0 ? n_in_ : n_hidden_;
            int64_t n_out = i == n_layers_ - 1 ? n_out_ : n_hidden_;
            params_.emplace_back(GetRandomArray(gen, dist, {n_in, n_out}));
            params_.emplace_back(chainerx::Zeros({n_out}, chainerx::TypeToDtype<float>));
        }

        for (const chainerx::Array& param : params_) {
            param.RequireGrad();
        }
    }

private:
    int64_t n_in_;
    int64_t n_hidden_;
    int64_t n_out_;
    int64_t n_layers_;
    std::vector<chainerx::Array> params_;
};

chainerx::Array SoftmaxCrossEntropy(const chainerx::Array& y, const chainerx::Array& t, bool normalize = true) {
    chainerx::Array score = chainerx::LogSoftmax(y, 1);
    chainerx::Array mask =
            (t.At({chainerx::Slice{}, chainerx::NewAxis{}}) == chainerx::Arange(score.shape()[1], t.dtype())).AsType(score.dtype());
    if (normalize) {
        return -(score * mask).Sum() / y.shape()[0];
    }
    return -(score * mask).Sum();
}

void RunWithDefaultDevice(int64_t epochs, int64_t batch_size, int64_t n_hidden, int64_t n_layers, float lr, const std::string& mnist_root) {
    // Read the MNIST dataset.
    chainerx::Array train_x = ReadMnistImages(mnist_root + "train-images-idx3-ubyte");
    chainerx::Array train_t = ReadMnistLabels(mnist_root + "train-labels-idx1-ubyte");
    chainerx::Array test_x = ReadMnistImages(mnist_root + "t10k-images-idx3-ubyte");
    chainerx::Array test_t = ReadMnistLabels(mnist_root + "t10k-labels-idx1-ubyte");

    train_x = train_x.AsType(chainerx::Dtype::kFloat32) / 255.f;
    train_t = train_t.AsType(chainerx::Dtype::kInt32);
    test_x = test_x.AsType(chainerx::Dtype::kFloat32) / 255.f;
    test_t = test_t.AsType(chainerx::Dtype::kInt32);

    int64_t n_train = train_x.shape().front();
    int64_t n_test = test_x.shape().front();
    chainerx::Array train_indices = chainerx::Arange(n_train, chainerx::Dtype::kInt64);

    // Initialize the model with random parameters.
    Model model{train_x.shape()[1], n_hidden, 10, n_layers};
    std::random_device rd{};
    std::mt19937 gen{rd()};
    std::normal_distribution<float> dist{0.f, 0.05f};
    model.Initialize(gen, dist);

    auto start = std::chrono::high_resolution_clock::now();

    for (int64_t epoch = 0; epoch < epochs; ++epoch) {
        // The underlying data of the indices' Array is contiguous so we can use std::shuffle to randomize the order.
        assert(train_indices.IsContiguous());
        std::shuffle(
                reinterpret_cast<int64_t*>(train_indices.raw_data()), reinterpret_cast<int64_t*>(train_indices.raw_data()) + n_train, gen);
        for (int64_t i = 0; i < n_train; i += batch_size) {
            chainerx::Array indices = train_indices.At({chainerx::Slice{i, i + batch_size}});
            chainerx::Array x = train_x.Take(indices, 0);
            chainerx::Array t = train_t.Take(indices, 0);

            chainerx::Backward(SoftmaxCrossEntropy(model(x), t));

            // Vanilla SGD.
            for (const chainerx::Array& param : model.params()) {
                chainerx::Array p = param.AsGradStopped();
                p -= param.GetGrad()->AsGradStopped() * lr;
                param.ClearGrad();
            }
        }

        // Evaluate.
        {
            chainerx::NoBackpropModeScope scope{};

            chainerx::Array loss = chainerx::Zeros({}, chainerx::Dtype::kFloat32);
            chainerx::Array acc = chainerx::Zeros({}, chainerx::Dtype::kFloat32);

            for (int64_t i = 0; i < n_test; i += batch_size) {
                std::vector<chainerx::ArrayIndex> indices{chainerx::Slice{i, i + batch_size}};
                chainerx::Array x = test_x.At(indices);
                chainerx::Array t = test_t.At(indices);
                chainerx::Array y = model(x);
                loss += SoftmaxCrossEntropy(y, t, false);
                acc += (y.ArgMax(1).AsType(t.dtype()) == t).Sum().AsType(acc.dtype());
            }

            std::cout << "epoch: " << epoch << " loss=" << chainerx::AsScalar(loss / n_test)
                      << " accuracy=" << chainerx::AsScalar(acc / n_test)
                      << " elapsed_time=" << std::chrono::duration<double>{std::chrono::high_resolution_clock::now() - start}.count()
                      << std::endl;
        }
    }
}

int main(int argc, char** argv) {
    int64_t epochs{20};
    int64_t batch_size{100};
    int64_t n_hidden{1000};
    int64_t n_layers{3};
    float lr{0.01};
    std::string device_name{"native"};
    std::string mnist_root{"./"};

    for (int i = 1; i < argc; i += 2) {
        std::string arg = argv[i];
        if (arg == "--epoch") {
            epochs = std::atoi(argv[i + 1]);
        } else if (arg == "--batchsize") {
            batch_size = std::atoi(argv[i + 1]);
        } else if (arg == "--unit") {
            n_hidden = std::atoi(argv[i + 1]);
        } else if (arg == "--layer") {
            n_layers = std::atoi(argv[i + 1]);
        } else if (arg == "--lr") {
            lr = std::atof(argv[i + 1]);
        } else if (arg == "--device") {
            device_name = argv[i + 1];
        } else if (arg == "--data") {
            mnist_root = argv[i + 1];
        } else {
            throw std::runtime_error("Unknown argument: " + arg);
        }
    }

    if (mnist_root.back() != '/') {
        mnist_root += "/";
    }

    chainerx::Context ctx{};
    chainerx::SetDefaultContext(&ctx);
    chainerx::Device& device = ctx.GetDevice(device_name);
    chainerx::SetDefaultDevice(&device);

    std::cout << "Epochs: " << epochs << std::endl;
    std::cout << "Minibatch size: " << batch_size << std::endl;
    std::cout << "Hidden neurons: " << n_hidden << std::endl;
    std::cout << "Layers: " << n_layers << std::endl;
    std::cout << "Learning rate: " << lr << std::endl;
    std::cout << "Device: " << device.name() << std::endl;
    std::cout << "MNIST root: " << mnist_root << std::endl;

    RunWithDefaultDevice(epochs, batch_size, n_hidden, n_layers, lr, mnist_root);
}
<commit_msg>Simplify function name<commit_after>#include <algorithm>
#include <cassert>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <functional>
#include <iostream>
#include <memory>
#include <random>
#include <string>

#include "chainerx/array.h"
#include "chainerx/array_index.h"
#include "chainerx/backprop_mode.h"
#include "chainerx/backward.h"
#include "chainerx/device_id.h"
#include "chainerx/dtype.h"
#include "chainerx/routines/creation.h"
#include "chainerx/routines/linalg.h"
#include "chainerx/routines/manipulation.h"
#include "chainerx/routines/math.h"
#include "chainerx/shape.h"
#include "chainerx/slice.h"
#include "mnist.h"

chainerx::Array GetRandomArray(std::mt19937& gen, std::normal_distribution<float>& dist, const chainerx::Shape& shape) {
    int64_t n = shape.GetTotalSize();
    std::shared_ptr<float> data{new float[n], std::default_delete<float[]>{}};
    std::generate_n(data.get(), n, [&dist, &gen]() { return dist(gen); });
    return chainerx::FromContiguousHostData(
            shape, chainerx::TypeToDtype<float>, static_cast<std::shared_ptr<void>>(data), chainerx::GetDefaultDevice());
}

class Model {
public:
    Model(int64_t n_in, int64_t n_hidden, int64_t n_out, int64_t n_layers)
        : n_in_{n_in}, n_hidden_{n_hidden}, n_out_{n_out}, n_layers_{n_layers} {};

    chainerx::Array operator()(const chainerx::Array& x) {
        chainerx::Array h = x;
        for (int64_t i = 0; i < n_layers_; ++i) {
            h = chainerx::Dot(h, params_[i * 2]) + params_[i * 2 + 1];
            if (i != n_layers_ - 1) {
                h = chainerx::Maximum(0, h);
            }
        }
        return h;
    }

    const std::vector<chainerx::Array>& params() { return params_; }

    void Initialize(std::mt19937& gen, std::normal_distribution<float>& dist) {
        params_.clear();

        for (int64_t i = 0; i < n_layers_; ++i) {
            int64_t n_in = i == 0 ? n_in_ : n_hidden_;
            int64_t n_out = i == n_layers_ - 1 ? n_out_ : n_hidden_;
            params_.emplace_back(GetRandomArray(gen, dist, {n_in, n_out}));
            params_.emplace_back(chainerx::Zeros({n_out}, chainerx::TypeToDtype<float>));
        }

        for (const chainerx::Array& param : params_) {
            param.RequireGrad();
        }
    }

private:
    int64_t n_in_;
    int64_t n_hidden_;
    int64_t n_out_;
    int64_t n_layers_;
    std::vector<chainerx::Array> params_;
};

chainerx::Array SoftmaxCrossEntropy(const chainerx::Array& y, const chainerx::Array& t, bool normalize = true) {
    chainerx::Array score = chainerx::LogSoftmax(y, 1);
    chainerx::Array mask =
            (t.At({chainerx::Slice{}, chainerx::NewAxis{}}) == chainerx::Arange(score.shape()[1], t.dtype())).AsType(score.dtype());
    if (normalize) {
        return -(score * mask).Sum() / y.shape()[0];
    }
    return -(score * mask).Sum();
}

void Run(int64_t epochs, int64_t batch_size, int64_t n_hidden, int64_t n_layers, float lr, const std::string& mnist_root) {
    // Read the MNIST dataset.
    chainerx::Array train_x = ReadMnistImages(mnist_root + "train-images-idx3-ubyte");
    chainerx::Array train_t = ReadMnistLabels(mnist_root + "train-labels-idx1-ubyte");
    chainerx::Array test_x = ReadMnistImages(mnist_root + "t10k-images-idx3-ubyte");
    chainerx::Array test_t = ReadMnistLabels(mnist_root + "t10k-labels-idx1-ubyte");

    train_x = train_x.AsType(chainerx::Dtype::kFloat32) / 255.f;
    train_t = train_t.AsType(chainerx::Dtype::kInt32);
    test_x = test_x.AsType(chainerx::Dtype::kFloat32) / 255.f;
    test_t = test_t.AsType(chainerx::Dtype::kInt32);

    int64_t n_train = train_x.shape().front();
    int64_t n_test = test_x.shape().front();
    chainerx::Array train_indices = chainerx::Arange(n_train, chainerx::Dtype::kInt64);

    // Initialize the model with random parameters.
    Model model{train_x.shape()[1], n_hidden, 10, n_layers};
    std::random_device rd{};
    std::mt19937 gen{rd()};
    std::normal_distribution<float> dist{0.f, 0.05f};
    model.Initialize(gen, dist);

    auto start = std::chrono::high_resolution_clock::now();

    for (int64_t epoch = 0; epoch < epochs; ++epoch) {
        // The underlying data of the indices' Array is contiguous so we can use std::shuffle to randomize the order.
        assert(train_indices.IsContiguous());
        std::shuffle(
                reinterpret_cast<int64_t*>(train_indices.raw_data()), reinterpret_cast<int64_t*>(train_indices.raw_data()) + n_train, gen);
        for (int64_t i = 0; i < n_train; i += batch_size) {
            chainerx::Array indices = train_indices.At({chainerx::Slice{i, i + batch_size}});
            chainerx::Array x = train_x.Take(indices, 0);
            chainerx::Array t = train_t.Take(indices, 0);

            chainerx::Backward(SoftmaxCrossEntropy(model(x), t));

            // Vanilla SGD.
            for (const chainerx::Array& param : model.params()) {
                chainerx::Array p = param.AsGradStopped();
                p -= param.GetGrad()->AsGradStopped() * lr;
                param.ClearGrad();
            }
        }

        // Evaluate.
        {
            chainerx::NoBackpropModeScope scope{};

            chainerx::Array loss = chainerx::Zeros({}, chainerx::Dtype::kFloat32);
            chainerx::Array acc = chainerx::Zeros({}, chainerx::Dtype::kFloat32);

            for (int64_t i = 0; i < n_test; i += batch_size) {
                std::vector<chainerx::ArrayIndex> indices{chainerx::Slice{i, i + batch_size}};
                chainerx::Array x = test_x.At(indices);
                chainerx::Array t = test_t.At(indices);
                chainerx::Array y = model(x);
                loss += SoftmaxCrossEntropy(y, t, false);
                acc += (y.ArgMax(1).AsType(t.dtype()) == t).Sum().AsType(acc.dtype());
            }

            std::cout << "epoch: " << epoch << " loss=" << chainerx::AsScalar(loss / n_test)
                      << " accuracy=" << chainerx::AsScalar(acc / n_test)
                      << " elapsed_time=" << std::chrono::duration<double>{std::chrono::high_resolution_clock::now() - start}.count()
                      << std::endl;
        }
    }
}

int main(int argc, char** argv) {
    int64_t epochs{20};
    int64_t batch_size{100};
    int64_t n_hidden{1000};
    int64_t n_layers{3};
    float lr{0.01};
    std::string device_name{"native"};
    std::string mnist_root{"./"};

    for (int i = 1; i < argc; i += 2) {
        std::string arg = argv[i];
        if (arg == "--epoch") {
            epochs = std::atoi(argv[i + 1]);
        } else if (arg == "--batchsize") {
            batch_size = std::atoi(argv[i + 1]);
        } else if (arg == "--unit") {
            n_hidden = std::atoi(argv[i + 1]);
        } else if (arg == "--layer") {
            n_layers = std::atoi(argv[i + 1]);
        } else if (arg == "--lr") {
            lr = std::atof(argv[i + 1]);
        } else if (arg == "--device") {
            device_name = argv[i + 1];
        } else if (arg == "--data") {
            mnist_root = argv[i + 1];
        } else {
            throw std::runtime_error("Unknown argument: " + arg);
        }
    }

    if (mnist_root.back() != '/') {
        mnist_root += "/";
    }

    chainerx::Context ctx{};
    chainerx::SetDefaultContext(&ctx);
    chainerx::Device& device = ctx.GetDevice(device_name);
    chainerx::SetDefaultDevice(&device);

    std::cout << "Epochs: " << epochs << std::endl;
    std::cout << "Minibatch size: " << batch_size << std::endl;
    std::cout << "Hidden neurons: " << n_hidden << std::endl;
    std::cout << "Layers: " << n_layers << std::endl;
    std::cout << "Learning rate: " << lr << std::endl;
    std::cout << "Device: " << device.name() << std::endl;
    std::cout << "MNIST root: " << mnist_root << std::endl;

    Run(epochs, batch_size, n_hidden, n_layers, lr, mnist_root);
}
<|endoftext|>


<commit_before>//
//   Copyright 2013 Pixar
//
//   Licensed under the Apache License, Version 2.0 (the "Apache License")
//   with the following modification; you may not use this file except in
//   compliance with the Apache License and the following modification to it:
//   Section 6. Trademarks. is deleted and replaced with:
//
//   6. Trademarks. This License does not grant permission to use the trade
//      names, trademarks, service marks, or product names of the Licensor
//      and its affiliates, except as required to comply with Section 4(c) of
//      the License and to reproduce the content of the NOTICE file.
//
//   You may obtain a copy of the Apache License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the Apache License with the above modification is
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//   KIND, either express or implied. See the Apache License for the specific
//   language governing permissions and limitations under the Apache License.
//

#define HBR_ADAPTIVE
#include "../far/meshFactory.h"

#include "refiner.h"

#include "../osd/vertex.h"

#include <iostream>
#include <sstream>

using namespace std;
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {

//------------------------------------------------------------------------------
// The simplest constructor, only point positions and polygonal
// mesh topology

OsdUtilRefiner::OsdUtilRefiner():
    _adaptive(false),
    _mesh(NULL),
    _farMesh(NULL),
    _patchParamTable(NULL),
    _firstVertexOffset(0),
    _numRefinedVerts(0),
    _numUniformQuads(0),
    _numPatches(0),
    _isRefined(false)
{
}

bool
OsdUtilRefiner::Initialize(
       const OsdUtilSubdivTopology &topology,
       bool adaptive,
       string *errorMessage)
{

    if (not topology.IsValid(errorMessage)) {
        return false;
    }

    _mesh = new OsdUtilMesh<OsdVertex>();

    if (not _mesh->Initialize(topology, errorMessage)) {
        return false;
    }

    const OsdUtilSubdivTopology &t = _mesh->GetTopology();

    if (adaptive) {
        FarMeshFactory<OsdVertex> adaptiveMeshFactory(
            _mesh->GetHbrMesh(), t.refinementLevel, true);

        _farMesh = adaptiveMeshFactory.Create();

    } else {
        // XXX:gelder
        // Had problems with patchArrayVector in patchTables not working
        // unless firstLevel is passed as 1 here.  Bug in refiner?
        FarMeshFactory<OsdVertex> uniformMeshFactory(
            _mesh->GetHbrMesh(), t.refinementLevel, false, /*firstLevel*/1);

        _farMesh = uniformMeshFactory.Create();
    }

    //
    // Now that we've created table driven subdivision data structures
    // needed for refinement,  grab and cache specific values for
    // later fast lookup.
    //

    // Subdivision tables describe the addition steps with coefficients
    // needed to perform subdivision
    const FarSubdivisionTables* ftable =
        _farMesh->GetSubdivisionTables();

    // Find quads array at given level
    const FarPatchTables * ptables = _farMesh->GetPatchTables();
    const FarPatchTables::PatchArrayVector & parrays =
        ptables->GetPatchArrayVector();

    if (t.refinementLevel > (int)parrays.size()) {
        if (errorMessage) {
            stringstream ss;
            ss << "Invalid size of patch array " << t.refinementLevel << " " <<
                (int)parrays.size();
            *errorMessage = ss.str();
        }
        return false;
    }

    // parrays doesn't contain base mesh, so it starts with level==1
    const FarPatchTables::PatchArray & parray = parrays[t.refinementLevel-1];

    _patchParamTable = &(ptables->GetPatchParamTable());

    // Global index of the first point in this array
    _firstVertexOffset =  ftable->GetFirstVertexOffset(t.refinementLevel);

    // Global index of the first face (patch) in this array
    _firstPatchOffset =  parray.GetPatchIndex();

    _numRefinedVerts = (int) ftable->GetNumVertices(t.refinementLevel);

    if (adaptive) {
        _numPatches = (int) parray.GetNumPatches();
    } else {
        _numUniformQuads = (int) parray.GetNumPatches();
    }

    _isRefined = true;

    return true;
}

bool
OsdUtilRefiner::GetRefinedQuads(
    vector<int>* quads,
    string *errorMessage) const
{
    if (!_isRefined) {
        if (errorMessage) {
            *errorMessage = "GetQuads: Mesh has not been refined.";
        }
        return false;
    }

    if (_adaptive) {
        if (errorMessage) {
            *errorMessage = "GetQuads: only supports uniform subdivision.";
        }
        return false;
    }

    if (!quads || (_numUniformQuads == 0)) {
        return false;
    }

    quads->resize(_numUniformQuads * 4);

    const FarPatchTables * ptables = _farMesh->GetPatchTables();
    const unsigned int *quadIndices =
        ptables->GetFaceVertices(_mesh->GetTopology().refinementLevel);

    for (int i=0; i<_numUniformQuads*4; ++i) {
        (*quads)[i] = quadIndices[i] - _firstVertexOffset;
    }

    return true;
}

// Inverse of OpenSubdiv::FarPatchParam::BitField::Normalize
static void
_InverseNormalize(OpenSubdiv::FarPatchParam::BitField bf, float& u, float& v)
{
    float frac = bf.GetParamFraction();
    float pu = (float) bf.GetU() * frac;
    float pv = (float) bf.GetV() * frac;

    u = u * frac + pu;
    v = v * frac + pv;
}

// Inverse of OpenSubdiv::FarPatchParam::BitField::Rotate
static void
_InverseRotate(OpenSubdiv::FarPatchParam::BitField bf, float& u, float& v)
{
    switch (bf.GetRotation()) {
         case 0 : break;
         case 1 : { float tmp=u; u=1.0f-v; v=tmp; } break;
         case 2 : { u=1.0f-u; v=1.0f-v; } break;
         case 3 : { float tmp=v; v=1.0f-u; u=tmp; } break;
    }
}

bool
OsdUtilRefiner::GetRefinedPtexUvs(vector<float>* subfaceUvs,
                                    vector<int>* ptexIndices,
                                    string *errorMessage) const
{
    if (!_isRefined) {
        if (errorMessage) {
            *errorMessage = "GetRefinedPtexUvs: Mesh has not been refined.";
        }
        return false;
    }

    if (_adaptive) {
        if (errorMessage) {
            *errorMessage = "GetRefinedPtexUvs: only supports uniform subdivision.";
        }
        return false;
    }

    subfaceUvs->resize(_numUniformQuads * 4);
    vector<float>::iterator uvIt = subfaceUvs->begin();

    ptexIndices->resize(_numUniformQuads);
    vector<int>::iterator idIt = ptexIndices->begin();

    const FarPatchTables * ptables = _farMesh->GetPatchTables();
    const FarPatchTables::PatchArrayVector & parrays =
        ptables->GetPatchArrayVector();
    int refinementLevel = _mesh->GetTopology().refinementLevel;

    if (refinementLevel > (int)parrays.size()) {
        if (errorMessage)
            *errorMessage = "Invalid size of patch array";
    }
    const FarPatchTables::PatchArray & parray = parrays[refinementLevel-1];

    const FarPatchTables::PatchParamTable& paramTable =
        ptables->GetPatchParamTable();

    for (int refinedIndex = 0; refinedIndex < _numUniformQuads;
         ++refinedIndex) {

        const OpenSubdiv::FarPatchParam& param =
            paramTable[parray.GetPatchIndex() + refinedIndex];
        OpenSubdiv::FarPatchParam::BitField bf = param.bitField;

        float u0 = 0;
        float v0 = 0;
        _InverseRotate(bf, u0, v0);
        _InverseNormalize(bf, u0, v0);

        float u1 = 1;
        float v1 = 1;
        _InverseRotate(bf, u1, v1);
        _InverseNormalize(bf, u1, v1);

        *idIt++ = param.faceIndex;
        *uvIt++ = u0;
        *uvIt++ = v0;
        *uvIt++ = u1;
        *uvIt++ = v1;
    }

    return true;
}

OsdUtilRefiner::~OsdUtilRefiner() {

    if (_mesh)
        delete _mesh;

    if (_farMesh)
        delete _farMesh;
}

const std::string &
OsdUtilRefiner::GetName()
{
    if (_mesh) {
        return _mesh->GetName();
    } else {
        static std::string bogus("bogus");
        return bogus;
    }
}

OpenSubdiv::HbrMesh<OpenSubdiv::OsdVertex>*
OsdUtilRefiner::GetHbrMesh()
{
    if (_mesh) {
        return _mesh->GetHbrMesh();
    } else {
        return NULL;
    }
}

}  // end namespace OPENSUBDIV_VERSION
}  // end namespace OpenSubdiv
<commit_msg>Fix OsdUtilRefiner incorrect "Invalid size of patch array" error reporting.<commit_after>//
//   Copyright 2013 Pixar
//
//   Licensed under the Apache License, Version 2.0 (the "Apache License")
//   with the following modification; you may not use this file except in
//   compliance with the Apache License and the following modification to it:
//   Section 6. Trademarks. is deleted and replaced with:
//
//   6. Trademarks. This License does not grant permission to use the trade
//      names, trademarks, service marks, or product names of the Licensor
//      and its affiliates, except as required to comply with Section 4(c) of
//      the License and to reproduce the content of the NOTICE file.
//
//   You may obtain a copy of the Apache License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the Apache License with the above modification is
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//   KIND, either express or implied. See the Apache License for the specific
//   language governing permissions and limitations under the Apache License.
//

#define HBR_ADAPTIVE
#include "../far/meshFactory.h"

#include "refiner.h"

#include "../osd/vertex.h"

#include <iostream>
#include <sstream>

using namespace std;
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {

//------------------------------------------------------------------------------
// The simplest constructor, only point positions and polygonal
// mesh topology

OsdUtilRefiner::OsdUtilRefiner():
    _adaptive(false),
    _mesh(NULL),
    _farMesh(NULL),
    _patchParamTable(NULL),
    _firstVertexOffset(0),
    _numRefinedVerts(0),
    _numUniformQuads(0),
    _numPatches(0),
    _isRefined(false)
{
}

bool
OsdUtilRefiner::Initialize(
       const OsdUtilSubdivTopology &topology,
       bool adaptive,
       string *errorMessage)
{

    if (not topology.IsValid(errorMessage)) {
        return false;
    }

    _mesh = new OsdUtilMesh<OsdVertex>();

    if (not _mesh->Initialize(topology, errorMessage)) {
        return false;
    }

    const OsdUtilSubdivTopology &t = _mesh->GetTopology();

    if (adaptive) {
        FarMeshFactory<OsdVertex> adaptiveMeshFactory(
            _mesh->GetHbrMesh(), t.refinementLevel, true);

        _farMesh = adaptiveMeshFactory.Create();

    } else {
        // XXX:gelder
        // Had problems with patchArrayVector in patchTables not working
        // unless firstLevel is passed as 1 here.  Bug in refiner?
        FarMeshFactory<OsdVertex> uniformMeshFactory(
            _mesh->GetHbrMesh(), t.refinementLevel, false, /*firstLevel*/1);

        _farMesh = uniformMeshFactory.Create();
    }

    //
    // Now that we've created table driven subdivision data structures
    // needed for refinement,  grab and cache specific values for
    // later fast lookup.
    //

    // Subdivision tables describe the addition steps with coefficients
    // needed to perform subdivision
    const FarSubdivisionTables* ftable =
        _farMesh->GetSubdivisionTables();

    // Find quads array at given level
    const FarPatchTables * ptables = _farMesh->GetPatchTables();
    const FarPatchTables::PatchArrayVector & parrays =
        ptables->GetPatchArrayVector();

    if ((not adaptive) and (t.refinementLevel > (int)parrays.size())) {
        if (errorMessage) {
            stringstream ss;
            ss << "Invalid size of patch array " << t.refinementLevel << " " <<
                (int)parrays.size();
            *errorMessage = ss.str();
        }
        return false;
    }

    // parrays doesn't contain base mesh, so it starts with level==1
    const FarPatchTables::PatchArray & parray = parrays[t.refinementLevel-1];

    _patchParamTable = &(ptables->GetPatchParamTable());

    // Global index of the first point in this array
    _firstVertexOffset =  ftable->GetFirstVertexOffset(t.refinementLevel);

    // Global index of the first face (patch) in this array
    _firstPatchOffset =  parray.GetPatchIndex();

    _numRefinedVerts = (int) ftable->GetNumVertices(t.refinementLevel);

    if (adaptive) {
        _numPatches = (int) parray.GetNumPatches();
    } else {
        _numUniformQuads = (int) parray.GetNumPatches();
    }

    _isRefined = true;

    return true;
}

bool
OsdUtilRefiner::GetRefinedQuads(
    vector<int>* quads,
    string *errorMessage) const
{
    if (!_isRefined) {
        if (errorMessage) {
            *errorMessage = "GetQuads: Mesh has not been refined.";
        }
        return false;
    }

    if (_adaptive) {
        if (errorMessage) {
            *errorMessage = "GetQuads: only supports uniform subdivision.";
        }
        return false;
    }

    if (!quads || (_numUniformQuads == 0)) {
        return false;
    }

    quads->resize(_numUniformQuads * 4);

    const FarPatchTables * ptables = _farMesh->GetPatchTables();
    const unsigned int *quadIndices =
        ptables->GetFaceVertices(_mesh->GetTopology().refinementLevel);

    for (int i=0; i<_numUniformQuads*4; ++i) {
        (*quads)[i] = quadIndices[i] - _firstVertexOffset;
    }

    return true;
}

// Inverse of OpenSubdiv::FarPatchParam::BitField::Normalize
static void
_InverseNormalize(OpenSubdiv::FarPatchParam::BitField bf, float& u, float& v)
{
    float frac = bf.GetParamFraction();
    float pu = (float) bf.GetU() * frac;
    float pv = (float) bf.GetV() * frac;

    u = u * frac + pu;
    v = v * frac + pv;
}

// Inverse of OpenSubdiv::FarPatchParam::BitField::Rotate
static void
_InverseRotate(OpenSubdiv::FarPatchParam::BitField bf, float& u, float& v)
{
    switch (bf.GetRotation()) {
         case 0 : break;
         case 1 : { float tmp=u; u=1.0f-v; v=tmp; } break;
         case 2 : { u=1.0f-u; v=1.0f-v; } break;
         case 3 : { float tmp=v; v=1.0f-u; u=tmp; } break;
    }
}

bool
OsdUtilRefiner::GetRefinedPtexUvs(vector<float>* subfaceUvs,
                                    vector<int>* ptexIndices,
                                    string *errorMessage) const
{
    if (!_isRefined) {
        if (errorMessage) {
            *errorMessage = "GetRefinedPtexUvs: Mesh has not been refined.";
        }
        return false;
    }

    if (_adaptive) {
        if (errorMessage) {
            *errorMessage = "GetRefinedPtexUvs: only supports uniform subdivision.";
        }
        return false;
    }

    subfaceUvs->resize(_numUniformQuads * 4);
    vector<float>::iterator uvIt = subfaceUvs->begin();

    ptexIndices->resize(_numUniformQuads);
    vector<int>::iterator idIt = ptexIndices->begin();

    const FarPatchTables * ptables = _farMesh->GetPatchTables();
    const FarPatchTables::PatchArrayVector & parrays =
        ptables->GetPatchArrayVector();
    int refinementLevel = _mesh->GetTopology().refinementLevel;

    if (refinementLevel > (int)parrays.size()) {
        if (errorMessage)
            *errorMessage = "Invalid size of patch array";
    }
    const FarPatchTables::PatchArray & parray = parrays[refinementLevel-1];

    const FarPatchTables::PatchParamTable& paramTable =
        ptables->GetPatchParamTable();

    for (int refinedIndex = 0; refinedIndex < _numUniformQuads;
         ++refinedIndex) {

        const OpenSubdiv::FarPatchParam& param =
            paramTable[parray.GetPatchIndex() + refinedIndex];
        OpenSubdiv::FarPatchParam::BitField bf = param.bitField;

        float u0 = 0;
        float v0 = 0;
        _InverseRotate(bf, u0, v0);
        _InverseNormalize(bf, u0, v0);

        float u1 = 1;
        float v1 = 1;
        _InverseRotate(bf, u1, v1);
        _InverseNormalize(bf, u1, v1);

        *idIt++ = param.faceIndex;
        *uvIt++ = u0;
        *uvIt++ = v0;
        *uvIt++ = u1;
        *uvIt++ = v1;
    }

    return true;
}

OsdUtilRefiner::~OsdUtilRefiner() {

    if (_mesh)
        delete _mesh;

    if (_farMesh)
        delete _farMesh;
}

const std::string &
OsdUtilRefiner::GetName()
{
    if (_mesh) {
        return _mesh->GetName();
    } else {
        static std::string bogus("bogus");
        return bogus;
    }
}

OpenSubdiv::HbrMesh<OpenSubdiv::OsdVertex>*
OsdUtilRefiner::GetHbrMesh()
{
    if (_mesh) {
        return _mesh->GetHbrMesh();
    } else {
        return NULL;
    }
}

}  // end namespace OPENSUBDIV_VERSION
}  // end namespace OpenSubdiv
<|endoftext|>


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

// Implementation of class LinearForm

#include "fem.hpp"

namespace mfem
{

LinearForm::LinearForm(FiniteElementSpace *f, LinearForm *lf)
   : Vector(f->GetVSize())
{
   // Linear forms are stored on the device
   UseDevice(true);

   fes = f;
   ext = nullptr;
   extern_lfs = 1;

   // Copy the pointers to the integrators
   domain_integs = lf->domain_integs;

   domain_delta_integs = lf->domain_delta_integs;

   boundary_integs = lf->boundary_integs;

   boundary_face_integs = lf->boundary_face_integs;
   boundary_face_integs_marker = lf->boundary_face_integs_marker;
}

void LinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi)
{
   DeltaLFIntegrator *maybe_delta =
      dynamic_cast<DeltaLFIntegrator *>(lfi);
   if (!maybe_delta || !maybe_delta->IsDelta())
   {
      domain_integs.Append(lfi);
   }
   else
   {
      domain_delta_integs.Append(maybe_delta);
   }
   domain_integs_marker.Append(NULL);
}

void LinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi,
                                     Array<int> &elem_marker)
{
   DeltaLFIntegrator *maybe_delta =
      dynamic_cast<DeltaLFIntegrator *>(lfi);
   if (!maybe_delta || !maybe_delta->IsDelta())
   {
      domain_integs.Append(lfi);
   }
   else
   {
      domain_delta_integs.Append(maybe_delta);
   }
   domain_integs_marker.Append(&elem_marker);
}

void LinearForm::AddBoundaryIntegrator (LinearFormIntegrator * lfi)
{
   boundary_integs.Append (lfi);
   boundary_integs_marker.Append(NULL); // NULL -> all attributes are active
}

void LinearForm::AddBoundaryIntegrator (LinearFormIntegrator * lfi,
                                        Array<int> &bdr_attr_marker)
{
   boundary_integs.Append (lfi);
   boundary_integs_marker.Append(&bdr_attr_marker);
}

void LinearForm::AddBdrFaceIntegrator (LinearFormIntegrator * lfi)
{
   boundary_face_integs.Append(lfi);
   // NULL -> all attributes are active
   boundary_face_integs_marker.Append(NULL);
}

void LinearForm::AddBdrFaceIntegrator(LinearFormIntegrator *lfi,
                                      Array<int> &bdr_attr_marker)
{
   boundary_face_integs.Append(lfi);
   boundary_face_integs_marker.Append(&bdr_attr_marker);
}

void LinearForm::AddInteriorFaceIntegrator(LinearFormIntegrator *lfi)
{
   interior_face_integs.Append(lfi);
}

bool LinearForm::SupportsDevice()
{
   // return false for NURBS meshs, so we don’t convert it to non-NURBS
   // through Assemble, AssembleDevice, GetGeometricFactors and EnsureNodes
   if (fes->GetMesh()->NURBSext != nullptr) { return false; }

   // scan domain integrator to verify that all can use device assembly
   if (domain_integs.Size() > 0)
   {
      for (int k = 0; k < domain_integs.Size(); k++)
      {
         if (!domain_integs[k]->SupportsDevice()) { return false; }
      }
   }

   // boundary, delta and face integrators are not supported yet
   if (GetBLFI()->Size() > 0 || GetFLFI()->Size() > 0 ||
       GetDLFI_Delta()->Size() > 0 || GetIFLFI()->Size() > 0) { return false; }

   const Mesh &mesh = *fes->GetMesh();

   // no support for elements with varying polynomial orders
   if (fes->IsVariableOrder()) { return false; }

   // no support for 1D and embedded meshes
   const int mesh_dim = mesh.Dimension();
   if (mesh_dim == 1 || mesh_dim != mesh.SpaceDimension()) { return false; }

   // tensor-product finite element space only
   if (!UsesTensorBasis(*fes)) { return false; }

   return true;
}

void LinearForm::Assemble(bool use_device)
{
   Array<int> vdofs;
   ElementTransformation *eltrans;
   DofTransformation *doftrans;
   Vector elemvect;

   if (!ext && use_device && SupportsDevice())
   {
      ext = new LinearFormExtension(this);
   }

   Vector::operator=(0.0);

   // The above operation is executed on device because of UseDevice().
   // The first use of AddElementVector() below will move it back to host
   // because both 'vdofs' and 'elemvect' are on host.

   if (ext) { return ext->Assemble(); }

   if (domain_integs.Size())
   {
      for (int k = 0; k < domain_integs.Size(); k++)
      {
         if (domain_integs_marker[k] != NULL)
         {
            MFEM_VERIFY(domain_integs_marker[k]->Size() ==
                        (fes->GetMesh()->attributes.Size() ?
                         fes->GetMesh()->attributes.Max() : 0),
                        "invalid element marker for domain linear form "
                        "integrator #" << k << ", counting from zero");
         }
      }

      for (int i = 0; i < fes -> GetNE(); i++)
      {
         int elem_attr = fes->GetMesh()->GetAttribute(i);
         for (int k = 0; k < domain_integs.Size(); k++)
         {
            const Array<int> * const markers = domain_integs_marker[k];
            if ( markers == NULL || (*markers)[elem_attr-1] == 1 )
            {
               doftrans = fes -> GetElementVDofs (i, vdofs);
               eltrans = fes -> GetElementTransformation (i);
               domain_integs[k]->AssembleRHSElementVect(*fes->GetFE(i),
                                                        *eltrans, elemvect);
               if (doftrans)
               {
                  doftrans->TransformDual(elemvect);
               }
               AddElementVector (vdofs, elemvect);
            }
         }
      }
   }
   AssembleDelta();

   if (boundary_integs.Size())
   {
      Mesh *mesh = fes->GetMesh();

      // Which boundary attributes need to be processed?
      Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
                                 mesh->bdr_attributes.Max() : 0);
      bdr_attr_marker = 0;
      for (int k = 0; k < boundary_integs.Size(); k++)
      {
         if (boundary_integs_marker[k] == NULL)
         {
            bdr_attr_marker = 1;
            break;
         }
         Array<int> &bdr_marker = *boundary_integs_marker[k];
         MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
                     "invalid boundary marker for boundary integrator #"
                     << k << ", counting from zero");
         for (int i = 0; i < bdr_attr_marker.Size(); i++)
         {
            bdr_attr_marker[i] |= bdr_marker[i];
         }
      }

      for (int i = 0; i < fes -> GetNBE(); i++)
      {
         const int bdr_attr = mesh->GetBdrAttribute(i);
         if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
         doftrans = fes -> GetBdrElementVDofs (i, vdofs);
         eltrans = fes -> GetBdrElementTransformation (i);
         for (int k=0; k < boundary_integs.Size(); k++)
         {
            if (boundary_integs_marker[k] &&
                (*boundary_integs_marker[k])[bdr_attr-1] == 0) { continue; }

            boundary_integs[k]->AssembleRHSElementVect(*fes->GetBE(i),
                                                       *eltrans, elemvect);

            if (doftrans)
            {
               doftrans->TransformDual(elemvect);
            }
            AddElementVector (vdofs, elemvect);
         }
      }
   }
   if (boundary_face_integs.Size())
   {
      FaceElementTransformations *tr;
      Mesh *mesh = fes->GetMesh();

      // Which boundary attributes need to be processed?
      Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
                                 mesh->bdr_attributes.Max() : 0);
      bdr_attr_marker = 0;
      for (int k = 0; k < boundary_face_integs.Size(); k++)
      {
         if (boundary_face_integs_marker[k] == NULL)
         {
            bdr_attr_marker = 1;
            break;
         }
         Array<int> &bdr_marker = *boundary_face_integs_marker[k];
         MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
                     "invalid boundary marker for boundary face integrator #"
                     << k << ", counting from zero");
         for (int i = 0; i < bdr_attr_marker.Size(); i++)
         {
            bdr_attr_marker[i] |= bdr_marker[i];
         }
      }

      for (int i = 0; i < mesh->GetNBE(); i++)
      {
         const int bdr_attr = mesh->GetBdrAttribute(i);
         if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }

         tr = mesh->GetBdrFaceTransformations(i);
         if (tr != NULL)
         {
            fes -> GetElementVDofs (tr -> Elem1No, vdofs);
            for (int k = 0; k < boundary_face_integs.Size(); k++)
            {
               if (boundary_face_integs_marker[k] &&
                   (*boundary_face_integs_marker[k])[bdr_attr-1] == 0)
               { continue; }

               boundary_face_integs[k]->
               AssembleRHSElementVect(*fes->GetFE(tr->Elem1No),
                                      *tr, elemvect);
               AddElementVector (vdofs, elemvect);
            }
         }
      }
   }

   if (interior_face_integs.Size())
   {
      Mesh *mesh = fes->GetMesh();

      for (int k = 0; k < interior_face_integs.Size(); k++)
      {
         for (int i = 0; i < mesh->GetNumFaces(); i++)
         {
            FaceElementTransformations *tr = NULL;
            tr = mesh->GetInteriorFaceTransformations (i);
            if (tr != NULL)
            {
               fes -> GetElementVDofs (tr -> Elem1No, vdofs);
               Array<int> vdofs2;
               fes -> GetElementVDofs (tr -> Elem2No, vdofs2);
               vdofs.Append(vdofs2);
               interior_face_integs[k]->
               AssembleRHSElementVect(*fes->GetFE(tr->Elem1No),
                                      *fes->GetFE(tr->Elem2No),
                                      *tr, elemvect);
               AddElementVector (vdofs, elemvect);
            }
         }
      }
   }
}

void LinearForm::Update()
{
   SetSize(fes->GetVSize()); ResetDeltaLocations();
   if (ext) { ext->Update(); }
}

void LinearForm::Update(FiniteElementSpace *f, Vector &v, int v_offset)
{
   MFEM_ASSERT(v.Size() >= v_offset + f->GetVSize(), "");
   fes = f;
   v.UseDevice(true);
   this->Vector::MakeRef(v, v_offset, fes->GetVSize());
   ResetDeltaLocations();
   if (ext) { ext->Update(); }
}

void LinearForm::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
{
   Update(f, v, v_offset);
}

void LinearForm::AssembleDelta()
{
   if (domain_delta_integs.Size() == 0) { return; }

   if (!HaveDeltaLocations())
   {
      int sdim = fes->GetMesh()->SpaceDimension();
      Vector center;
      DenseMatrix centers(sdim, domain_delta_integs.Size());
      for (int i = 0; i < centers.Width(); i++)
      {
         centers.GetColumnReference(i, center);
         domain_delta_integs[i]->GetDeltaCenter(center);
         MFEM_VERIFY(center.Size() == sdim,
                     "Point dim " << center.Size() <<
                     " does not match space dim " << sdim);
      }
      fes->GetMesh()->FindPoints(centers, domain_delta_integs_elem_id,
                                 domain_delta_integs_ip);
   }

   Array<int> vdofs;
   Vector elemvect;
   for (int i = 0; i < domain_delta_integs.Size(); i++)
   {
      int elem_id = domain_delta_integs_elem_id[i];
      // The delta center may be outside of this sub-domain, or
      // (Par)Mesh::FindPoints() failed to find this point:
      if (elem_id < 0) { continue; }

      const IntegrationPoint &ip = domain_delta_integs_ip[i];
      ElementTransformation &Trans = *fes->GetElementTransformation(elem_id);
      Trans.SetIntPoint(&ip);

      fes->GetElementVDofs(elem_id, vdofs);
      domain_delta_integs[i]->AssembleDeltaElementVect(*fes->GetFE(elem_id),
                                                       Trans, elemvect);
      AddElementVector(vdofs, elemvect);
   }
}

LinearForm & LinearForm::operator=(double value)
{
   Vector::operator=(value);
   return *this;
}

LinearForm & LinearForm::operator=(const Vector &v)
{
   MFEM_ASSERT(fes && v.Size() == fes->GetVSize(), "");
   Vector::operator=(v);
   return *this;
}

LinearForm::~LinearForm()
{
   if (!extern_lfs)
   {
      int k;
      for (k=0; k < domain_delta_integs.Size(); k++)
      { delete domain_delta_integs[k]; }
      for (k=0; k < domain_integs.Size(); k++) { delete domain_integs[k]; }
      for (k=0; k < boundary_integs.Size(); k++) { delete boundary_integs[k]; }
      for (k=0; k < boundary_face_integs.Size(); k++)
      { delete boundary_face_integs[k]; }
      for (k=0; k < interior_face_integs.Size(); k++)
      { delete interior_face_integs[k]; }
   }

   delete ext;
}

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

// Implementation of class LinearForm

#include "fem.hpp"

namespace mfem
{

LinearForm::LinearForm(FiniteElementSpace *f, LinearForm *lf)
   : Vector(f->GetVSize())
{
   // Linear forms are stored on the device
   UseDevice(true);

   fes = f;
   ext = nullptr;
   extern_lfs = 1;

   // Copy the pointers to the integrators
   domain_integs = lf->domain_integs;

   domain_delta_integs = lf->domain_delta_integs;

   boundary_integs = lf->boundary_integs;

   boundary_face_integs = lf->boundary_face_integs;
   boundary_face_integs_marker = lf->boundary_face_integs_marker;
}

void LinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi)
{
   DeltaLFIntegrator *maybe_delta =
      dynamic_cast<DeltaLFIntegrator *>(lfi);
   if (!maybe_delta || !maybe_delta->IsDelta())
   {
      domain_integs.Append(lfi);
   }
   else
   {
      domain_delta_integs.Append(maybe_delta);
   }
   domain_integs_marker.Append(NULL);
}

void LinearForm::AddDomainIntegrator(LinearFormIntegrator *lfi,
                                     Array<int> &elem_marker)
{
   DeltaLFIntegrator *maybe_delta =
      dynamic_cast<DeltaLFIntegrator *>(lfi);
   if (!maybe_delta || !maybe_delta->IsDelta())
   {
      domain_integs.Append(lfi);
   }
   else
   {
      domain_delta_integs.Append(maybe_delta);
   }
   domain_integs_marker.Append(&elem_marker);
}

void LinearForm::AddBoundaryIntegrator (LinearFormIntegrator * lfi)
{
   boundary_integs.Append (lfi);
   boundary_integs_marker.Append(NULL); // NULL -> all attributes are active
}

void LinearForm::AddBoundaryIntegrator (LinearFormIntegrator * lfi,
                                        Array<int> &bdr_attr_marker)
{
   boundary_integs.Append (lfi);
   boundary_integs_marker.Append(&bdr_attr_marker);
}

void LinearForm::AddBdrFaceIntegrator (LinearFormIntegrator * lfi)
{
   boundary_face_integs.Append(lfi);
   // NULL -> all attributes are active
   boundary_face_integs_marker.Append(NULL);
}

void LinearForm::AddBdrFaceIntegrator(LinearFormIntegrator *lfi,
                                      Array<int> &bdr_attr_marker)
{
   boundary_face_integs.Append(lfi);
   boundary_face_integs_marker.Append(&bdr_attr_marker);
}

void LinearForm::AddInteriorFaceIntegrator(LinearFormIntegrator *lfi)
{
   interior_face_integs.Append(lfi);
}

bool LinearForm::SupportsDevice()
{
   // return false for NURBS meshs, so we don’t convert it to non-NURBS
   // through Assemble, AssembleDevice, GetGeometricFactors and EnsureNodes
   if (fes->GetMesh()->NURBSext != nullptr) { return false; }

   // scan domain integrator to verify that all can use device assembly
   if (domain_integs.Size() > 0)
   {
      for (int k = 0; k < domain_integs.Size(); k++)
      {
         if (!domain_integs[k]->SupportsDevice()) { return false; }
      }
   }

   // boundary, delta and face integrators are not supported yet
   if (GetBLFI()->Size() > 0 || GetFLFI()->Size() > 0 ||
       GetDLFI_Delta()->Size() > 0 || GetIFLFI()->Size() > 0) { return false; }

   const Mesh &mesh = *fes->GetMesh();

   // no support for elements with varying polynomial orders
   if (fes->IsVariableOrder()) { return false; }

   // no support for 1D and embedded meshes
   const int mesh_dim = mesh.Dimension();
   if (mesh_dim == 1 || mesh_dim != mesh.SpaceDimension()) { return false; }

   // tensor-product finite element space only
   if (!UsesTensorBasis(*fes)) { return false; }

   return true;
}

void LinearForm::Assemble(bool use_device)
{
   Array<int> vdofs;
   ElementTransformation *eltrans;
   DofTransformation *doftrans;
   Vector elemvect;

   if (!ext && use_device && SupportsDevice())
   {
      ext = new LinearFormExtension(this);
   }

   Vector::operator=(0.0);

   // The above operation is executed on device because of UseDevice().
   // The first use of AddElementVector() below will move it back to host
   // because both 'vdofs' and 'elemvect' are on host.

   if (ext) { return ext->Assemble(); }

   if (domain_integs.Size())
   {
      for (int k = 0; k < domain_integs.Size(); k++)
      {
         if (domain_integs_marker[k] != NULL)
         {
            MFEM_VERIFY(domain_integs_marker[k]->Size() ==
                        (fes->GetMesh()->attributes.Size() ?
                         fes->GetMesh()->attributes.Max() : 0),
                        "invalid element marker for domain linear form "
                        "integrator #" << k << ", counting from zero");
         }
      }

      for (int i = 0; i < fes -> GetNE(); i++)
      {
         int elem_attr = fes->GetMesh()->GetAttribute(i);
         for (int k = 0; k < domain_integs.Size(); k++)
         {
            const Array<int> * const markers = domain_integs_marker[k];
            if ( markers == NULL || (*markers)[elem_attr-1] == 1 )
            {
               doftrans = fes -> GetElementVDofs (i, vdofs);
               eltrans = fes -> GetElementTransformation (i);
               domain_integs[k]->AssembleRHSElementVect(*fes->GetFE(i),
                                                        *eltrans, elemvect);
               if (doftrans)
               {
                  doftrans->TransformDual(elemvect);
               }
               AddElementVector (vdofs, elemvect);
            }
         }
      }
   }
   AssembleDelta();

   if (boundary_integs.Size())
   {
      Mesh *mesh = fes->GetMesh();

      // Which boundary attributes need to be processed?
      Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
                                 mesh->bdr_attributes.Max() : 0);
      bdr_attr_marker = 0;
      for (int k = 0; k < boundary_integs.Size(); k++)
      {
         if (boundary_integs_marker[k] == NULL)
         {
            bdr_attr_marker = 1;
            break;
         }
         Array<int> &bdr_marker = *boundary_integs_marker[k];
         MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
                     "invalid boundary marker for boundary integrator #"
                     << k << ", counting from zero");
         for (int i = 0; i < bdr_attr_marker.Size(); i++)
         {
            bdr_attr_marker[i] |= bdr_marker[i];
         }
      }

      for (int i = 0; i < fes -> GetNBE(); i++)
      {
         const int bdr_attr = mesh->GetBdrAttribute(i);
         if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
         doftrans = fes -> GetBdrElementVDofs (i, vdofs);
         eltrans = fes -> GetBdrElementTransformation (i);
         for (int k=0; k < boundary_integs.Size(); k++)
         {
            if (boundary_integs_marker[k] &&
                (*boundary_integs_marker[k])[bdr_attr-1] == 0) { continue; }

            boundary_integs[k]->AssembleRHSElementVect(*fes->GetBE(i),
                                                       *eltrans, elemvect);

            if (doftrans)
            {
               doftrans->TransformDual(elemvect);
            }
            AddElementVector (vdofs, elemvect);
         }
      }
   }
   if (boundary_face_integs.Size())
   {
      FaceElementTransformations *tr;
      Mesh *mesh = fes->GetMesh();

      // Which boundary attributes need to be processed?
      Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
                                 mesh->bdr_attributes.Max() : 0);
      bdr_attr_marker = 0;
      for (int k = 0; k < boundary_face_integs.Size(); k++)
      {
         if (boundary_face_integs_marker[k] == NULL)
         {
            bdr_attr_marker = 1;
            break;
         }
         Array<int> &bdr_marker = *boundary_face_integs_marker[k];
         MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
                     "invalid boundary marker for boundary face integrator #"
                     << k << ", counting from zero");
         for (int i = 0; i < bdr_attr_marker.Size(); i++)
         {
            bdr_attr_marker[i] |= bdr_marker[i];
         }
      }

      for (int i = 0; i < mesh->GetNBE(); i++)
      {
         const int bdr_attr = mesh->GetBdrAttribute(i);
         if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }

         tr = mesh->GetBdrFaceTransformations(i);
         if (tr != NULL)
         {
            fes -> GetElementVDofs (tr -> Elem1No, vdofs);
            for (int k = 0; k < boundary_face_integs.Size(); k++)
            {
               if (boundary_face_integs_marker[k] &&
                   (*boundary_face_integs_marker[k])[bdr_attr-1] == 0)
               { continue; }

               boundary_face_integs[k]->
               AssembleRHSElementVect(*fes->GetFE(tr->Elem1No),
                                      *tr, elemvect);
               AddElementVector (vdofs, elemvect);
            }
         }
      }
   }

   if (interior_face_integs.Size())
   {
      Mesh *mesh = fes->GetMesh();

      for (int k = 0; k < interior_face_integs.Size(); k++)
      {
         for (int i = 0; i < mesh->GetNumFaces(); i++)
         {
            FaceElementTransformations *tr = NULL;
            tr = mesh->GetInteriorFaceTransformations (i);
            if (tr != NULL)
            {
               fes -> GetElementVDofs (tr -> Elem1No, vdofs);
               Array<int> vdofs2;
               fes -> GetElementVDofs (tr -> Elem2No, vdofs2);
               vdofs.Append(vdofs2);
               interior_face_integs[k]->
               AssembleRHSElementVect(*fes->GetFE(tr->Elem1No),
                                      *fes->GetFE(tr->Elem2No),
                                      *tr, elemvect);
               AddElementVector (vdofs, elemvect);
            }
         }
      }
   }
}

void LinearForm::Update()
{
   SetSize(fes->GetVSize()); ResetDeltaLocations();
   if (ext) { ext->Update(); }
}

void LinearForm::Update(FiniteElementSpace *f, Vector &v, int v_offset)
{
   MFEM_ASSERT(v.Size() >= v_offset + f->GetVSize(), "");
   fes = f;
   v.UseDevice(true);
   this->Vector::MakeRef(v, v_offset, fes->GetVSize());
   ResetDeltaLocations();
   if (ext) { ext->Update(); }
}

void LinearForm::MakeRef(FiniteElementSpace *f, Vector &v, int v_offset)
{
   Update(f, v, v_offset);
}

void LinearForm::AssembleDelta()
{
   if (domain_delta_integs.Size() == 0) { return; }

   if (!HaveDeltaLocations())
   {
      int sdim = fes->GetMesh()->SpaceDimension();
      Vector center;
      DenseMatrix centers(sdim, domain_delta_integs.Size());
      for (int i = 0; i < centers.Width(); i++)
      {
         centers.GetColumnReference(i, center);
         domain_delta_integs[i]->GetDeltaCenter(center);
         MFEM_VERIFY(center.Size() == sdim,
                     "Point dim " << center.Size() <<
                     " does not match space dim " << sdim);
      }
      fes->GetMesh()->FindPoints(centers, domain_delta_integs_elem_id,
                                 domain_delta_integs_ip);
   }

   Array<int> vdofs;
   Vector elemvect;
   for (int i = 0; i < domain_delta_integs.Size(); i++)
   {
      int elem_id = domain_delta_integs_elem_id[i];
      // The delta center may be outside of this sub-domain, or
      // (Par)Mesh::FindPoints() failed to find this point:
      if (elem_id < 0) { continue; }

      const IntegrationPoint &ip = domain_delta_integs_ip[i];
      ElementTransformation &Trans = *fes->GetElementTransformation(elem_id);
      Trans.SetIntPoint(&ip);

      fes->GetElementVDofs(elem_id, vdofs);
      domain_delta_integs[i]->AssembleDeltaElementVect(*fes->GetFE(elem_id),
                                                       Trans, elemvect);
      AddElementVector(vdofs, elemvect);
   }
}

LinearForm & LinearForm::operator=(double value)
{
   Vector::operator=(value);
   return *this;
}

LinearForm & LinearForm::operator=(const Vector &v)
{
   MFEM_ASSERT(fes && v.Size() == fes->GetVSize(), "");
   Vector::operator=(v);
   return *this;
}

LinearForm::~LinearForm()
{
   if (!extern_lfs)
   {
      int k;
      for (k=0; k < domain_delta_integs.Size(); k++)
      { delete domain_delta_integs[k]; }
      for (k=0; k < domain_integs.Size(); k++) { delete domain_integs[k]; }
      for (k=0; k < boundary_integs.Size(); k++) { delete boundary_integs[k]; }
      for (k=0; k < boundary_face_integs.Size(); k++)
      { delete boundary_face_integs[k]; }
      for (k=0; k < interior_face_integs.Size(); k++)
      { delete interior_face_integs[k]; }
   }

   delete ext;
}

}
<|endoftext|>


<commit_before>#include "stdafx.h"

App app;

std::string g_type;

static float CalcRadius(const Mesh* m)
{
	const Block& b = m->GetRawDatas();
	float maxSq = 0;
	for (auto& it : b.vertices) {
		float sq = lengthSq(it.xyz);
		maxSq = std::max(maxSq, sq);
	}
	return sqrt(maxSq);
}

App::App()
{
	mesh = nullptr;
}

void App::Draw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glDepthMask(GL_FALSE);
	glDepthFunc(GL_ALWAYS);
	waterSurface.Draw();
	glDepthMask(GL_TRUE);
	glDepthFunc(GL_GEQUAL);

	fontMan.Render();

	matrixMan.Set(MatrixMan::WORLD, Mat());
	matrixMan.Set(MatrixMan::VIEW, devCamera.CalcViewMatrix());

	ivec2 scrSize = systemMetrics.GetScreenSize();

	float dist = devCamera.GetDistance();

	float f = dist * 1000;
	float n = dist / 1000;
	float aspect = (float)scrSize.x / scrSize.y;
#ifdef GL_TRUE
	Mat proj = Mat((float)1 / tanf(45 * (float)M_PI / 180 * 0.5f) / aspect, 0, 0, 0,
		0, (float)1 / tanf(45 * (float)M_PI / 180 * 0.5f), 0, 0,
		0, 0, -(f + n) / (f - n), 1,
		0, 0, (n * f) * 2 / (f - n), 0);
#else
	Mat proj = Mat((float)1 / tanf(45 * (float)M_PI / 180 * 0.5f) / aspect, 0, 0, 0,
		0, (float)1 / tanf(45 * (float)M_PI / 180 * 0.5f), 0, 0,
		0, 0, f / (f - n), 1,
		0, 0, -(n * f) / (f - n), 0);
#endif
	matrixMan.Set(MatrixMan::PROJ, proj);

	MeshXAnimResult r;
	mesh->CalcAnimation(0, GetTime(), r);
	mesh->Draw(r, Mat());
	mesh->Draw(r, translate(0, radius * 1.5f, 0) * q2m(Quat(Vec3(0, 0, 1), GetTime() * M_PI)));
	mesh->Draw(r, translate(radius * 2, 0, 0) * q2m(Quat(Vec3(0, 1, 0), GetTime() * M_PI)));
	meshRenderer.Flush();
}

void App::Init()
{
    ivec2 scrSize = systemMetrics.GetScreenSize();
    glViewport(0, 0, scrSize.x, scrSize.y);

	glClearColor(0.0f, 0.2f, 0.5f, 1.0f);
	glEnable(GL_DEPTH_TEST);
	glClearDepthf(0);

	meshRenderer.Create();
	waterSurface.Init();
	fontMan.Init();
	LoadMesh("jiji.x");
}

void App::LoadMesh(const char* fileName)
{
	SAFE_DELETE(mesh);
	mesh = new MeshX(fileName);
	radius = CalcRadius(mesh);
	float scale = std::max(0.00001f, radius);
	devCamera.SetDistance(scale * 3);

	g_type = "mesh";
}

void App::OnTap(float x, float y)
{
	waterSurface.CreateRipple(Vec2(x, y));
}

void App::Destroy()
{
	SAFE_DELETE(mesh);
	texMan.Destroy();
	shaderMan.Destroy();
	waterSurface.Destroy();
	fontMan.Destroy();
	meshRenderer.Destroy();
}

void App::Update()
{
	waterSurface.Update();
	fps.Update();
	fontMan.DrawString(Vec2(20, 20), 20, SPrintf("FPS: %f", fps.Get()));
}
<commit_msg>remove warnings<commit_after>#include "stdafx.h"

App app;

std::string g_type;

static float CalcRadius(const Mesh* m)
{
	const Block& b = m->GetRawDatas();
	float maxSq = 0;
	for (auto& it : b.vertices) {
		float sq = lengthSq(it.xyz);
		maxSq = std::max(maxSq, sq);
	}
	return sqrt(maxSq);
}

App::App()
{
	mesh = nullptr;
}

void App::Draw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glDepthMask(GL_FALSE);
	glDepthFunc(GL_ALWAYS);
	waterSurface.Draw();
	glDepthMask(GL_TRUE);
	glDepthFunc(GL_GEQUAL);

	fontMan.Render();

	matrixMan.Set(MatrixMan::WORLD, Mat());
	matrixMan.Set(MatrixMan::VIEW, devCamera.CalcViewMatrix());

	ivec2 scrSize = systemMetrics.GetScreenSize();

	float dist = devCamera.GetDistance();

	float f = dist * 1000;
	float n = dist / 1000;
	float aspect = (float)scrSize.x / scrSize.y;
#ifdef GL_TRUE
	Mat proj = Mat((float)1 / tanf(45 * (float)M_PI / 180 * 0.5f) / aspect, 0, 0, 0,
		0, (float)1 / tanf(45 * (float)M_PI / 180 * 0.5f), 0, 0,
		0, 0, -(f + n) / (f - n), 1,
		0, 0, (n * f) * 2 / (f - n), 0);
#else
	Mat proj = Mat((float)1 / tanf(45 * (float)M_PI / 180 * 0.5f) / aspect, 0, 0, 0,
		0, (float)1 / tanf(45 * (float)M_PI / 180 * 0.5f), 0, 0,
		0, 0, f / (f - n), 1,
		0, 0, -(n * f) / (f - n), 0);
#endif
	matrixMan.Set(MatrixMan::PROJ, proj);

	MeshXAnimResult r;
	mesh->CalcAnimation(0, GetTime(), r);
	mesh->Draw(r, Mat());
	mesh->Draw(r, translate(0, radius * 1.5f, 0) * q2m(Quat(Vec3(0, 0, 1.0f), (float)(GetTime() * M_PI))));
	mesh->Draw(r, translate(radius * 2.0f, 0, 0) * q2m(Quat(Vec3(0, 1.0f, 0), (float)(GetTime() * M_PI))));
	meshRenderer.Flush();
}

void App::Init()
{
    ivec2 scrSize = systemMetrics.GetScreenSize();
    glViewport(0, 0, scrSize.x, scrSize.y);

	glClearColor(0.0f, 0.2f, 0.5f, 1.0f);
	glEnable(GL_DEPTH_TEST);
	glClearDepthf(0);

	meshRenderer.Create();
	waterSurface.Init();
	fontMan.Init();
	LoadMesh("jiji.x");
}

void App::LoadMesh(const char* fileName)
{
	SAFE_DELETE(mesh);
	mesh = new MeshX(fileName);
	radius = CalcRadius(mesh);
	float scale = std::max(0.00001f, radius);
	devCamera.SetDistance(scale * 3);

	g_type = "mesh";
}

void App::OnTap(float x, float y)
{
	waterSurface.CreateRipple(Vec2(x, y));
}

void App::Destroy()
{
	SAFE_DELETE(mesh);
	texMan.Destroy();
	shaderMan.Destroy();
	waterSurface.Destroy();
	fontMan.Destroy();
	meshRenderer.Destroy();
}

void App::Update()
{
	waterSurface.Update();
	fps.Update();
	fontMan.DrawString(Vec2(20, 20), 20, SPrintf("FPS: %f", fps.Get()));
}
<|endoftext|>


<commit_before><commit_msg>Fix wrong include to fix the CromeOS build.<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: i_attribute.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2004-07-12 15:13:51 $
 *
 *  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 <precomp.h>
#include <ary/idl/i_attribute.hxx>
#include <ary/idl/ik_attribute.hxx>

// NOT FULLY DECLARED SERVICES
#include <ary/idl/ihost_ce.hxx>
#include <sci_impl.hxx>

namespace ary
{
namespace idl
{

Attribute::Attribute( const String &      i_sName,
                      Ce_id               i_nService,
                      Ce_id               i_nModule,
                      Type_id             i_nType,
                      bool                i_bReadonly,
                      bool                i_bBound )
    :   sName(i_sName),
        nOwner(i_nService),
        nNameRoom(i_nModule),
        nType(i_nType),
        aGetExceptions(),
        aSetExceptions(),
        bReadonly(i_bReadonly),
        bBound(i_bBound)
{
}

Attribute::~Attribute()
{
}

void
Attribute::do_Visit_CeHost( CeHost & o_rHost ) const
{
    o_rHost.Do_Attribute(*this);
}

RCid
Attribute::inq_ClassId() const
{
    return class_id;
}

const String &
Attribute::inq_LocalName() const
{
    return sName;
}

Ce_id
Attribute::inq_NameRoom() const
{
    return nNameRoom;
}

Ce_id
Attribute::inq_Owner() const
{
    return nOwner;
}

E_SightLevel
Attribute::inq_SightLevel() const
{
    return sl_Member;
}

namespace ifc_attribute
{

inline const Attribute &
attribute_cast( const CodeEntity &  i_ce )
{
    csv_assert( i_ce.ClassId() == Attribute::class_id );
    return static_cast< const Attribute& >(i_ce);
}

bool
attr::HasAnyStereotype( const CodeEntity & i_ce )
{
    const Attribute & rAttr = attribute_cast(i_ce);
    return rAttr.bReadonly OR rAttr.bBound;
}

bool
attr::IsReadOnly( const CodeEntity & i_ce )
{
    return attribute_cast(i_ce).bReadonly;
}

bool
attr::IsBound( const CodeEntity & i_ce )
{
    return attribute_cast(i_ce).bBound;
}

Type_id
attr::Type( const CodeEntity & i_ce )
{
    return attribute_cast(i_ce).nType;
}

void
attr::Get_GetExceptions( Dyn_TypeIterator &  o_result,
                         const CodeEntity &  i_ce )
{
    o_result
        = new SCI_Vector<Type_id>( attribute_cast(i_ce).aGetExceptions );
}

void
attr::Get_SetExceptions( Dyn_TypeIterator &  o_result,
                         const CodeEntity &  i_ce )
{
    o_result
        = new SCI_Vector<Type_id>( attribute_cast(i_ce).aSetExceptions );
}

} // namespace ifc_attribute

}   //  namespace   idl
}   //  namespace   ary
<commit_msg>INTEGRATION: CWS ooo19126 (1.2.24); FILE MERGED 2005/09/05 13:09:54 rt 1.2.24.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: i_attribute.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 16:39:58 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

#include <precomp.h>
#include <ary/idl/i_attribute.hxx>
#include <ary/idl/ik_attribute.hxx>

// NOT FULLY DECLARED SERVICES
#include <ary/idl/ihost_ce.hxx>
#include <sci_impl.hxx>

namespace ary
{
namespace idl
{

Attribute::Attribute( const String &      i_sName,
                      Ce_id               i_nService,
                      Ce_id               i_nModule,
                      Type_id             i_nType,
                      bool                i_bReadonly,
                      bool                i_bBound )
    :   sName(i_sName),
        nOwner(i_nService),
        nNameRoom(i_nModule),
        nType(i_nType),
        aGetExceptions(),
        aSetExceptions(),
        bReadonly(i_bReadonly),
        bBound(i_bBound)
{
}

Attribute::~Attribute()
{
}

void
Attribute::do_Visit_CeHost( CeHost & o_rHost ) const
{
    o_rHost.Do_Attribute(*this);
}

RCid
Attribute::inq_ClassId() const
{
    return class_id;
}

const String &
Attribute::inq_LocalName() const
{
    return sName;
}

Ce_id
Attribute::inq_NameRoom() const
{
    return nNameRoom;
}

Ce_id
Attribute::inq_Owner() const
{
    return nOwner;
}

E_SightLevel
Attribute::inq_SightLevel() const
{
    return sl_Member;
}

namespace ifc_attribute
{

inline const Attribute &
attribute_cast( const CodeEntity &  i_ce )
{
    csv_assert( i_ce.ClassId() == Attribute::class_id );
    return static_cast< const Attribute& >(i_ce);
}

bool
attr::HasAnyStereotype( const CodeEntity & i_ce )
{
    const Attribute & rAttr = attribute_cast(i_ce);
    return rAttr.bReadonly OR rAttr.bBound;
}

bool
attr::IsReadOnly( const CodeEntity & i_ce )
{
    return attribute_cast(i_ce).bReadonly;
}

bool
attr::IsBound( const CodeEntity & i_ce )
{
    return attribute_cast(i_ce).bBound;
}

Type_id
attr::Type( const CodeEntity & i_ce )
{
    return attribute_cast(i_ce).nType;
}

void
attr::Get_GetExceptions( Dyn_TypeIterator &  o_result,
                         const CodeEntity &  i_ce )
{
    o_result
        = new SCI_Vector<Type_id>( attribute_cast(i_ce).aGetExceptions );
}

void
attr::Get_SetExceptions( Dyn_TypeIterator &  o_result,
                         const CodeEntity &  i_ce )
{
    o_result
        = new SCI_Vector<Type_id>( attribute_cast(i_ce).aSetExceptions );
}

} // namespace ifc_attribute

}   //  namespace   idl
}   //  namespace   ary
<|endoftext|>