<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/websockets/websocket_handshake.h"

#include <algorithm>
#include <vector>

#include "base/md5.h"
#include "base/rand_util.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"

namespace net {

const int WebSocketHandshake::kWebSocketPort = 80;
const int WebSocketHandshake::kSecureWebSocketPort = 443;

WebSocketHandshake::WebSocketHandshake(
    const GURL& url,
    const std::string& origin,
    const std::string& location,
    const std::string& protocol)
    : url_(url),
      origin_(origin),
      location_(location),
      protocol_(protocol),
      mode_(MODE_INCOMPLETE) {
}

WebSocketHandshake::~WebSocketHandshake() {
}

bool WebSocketHandshake::is_secure() const {
  return url_.SchemeIs("wss");
}

std::string WebSocketHandshake::CreateClientHandshakeMessage() {
  if (!parameter_.get()) {
    parameter_.reset(new Parameter);
    parameter_->GenerateKeys();
  }
  std::string msg;

  // WebSocket protocol 4.1 Opening handshake.

  msg = "GET ";
  msg += GetResourceName();
  msg += " HTTP/1.1\r\n";

  std::vector<std::string> fields;

  fields.push_back("Upgrade: WebSocket");
  fields.push_back("Connection: Upgrade");

  fields.push_back("Host: " + GetHostFieldValue());

  fields.push_back("Origin: " + GetOriginFieldValue());

  if (!protocol_.empty())
    fields.push_back("Sec-WebSocket-Protocol: " + protocol_);

  // TODO(ukai): Add cookie if necessary.

  fields.push_back("Sec-WebSocket-Key1: " + parameter_->GetSecWebSocketKey1());
  fields.push_back("Sec-WebSocket-Key2: " + parameter_->GetSecWebSocketKey2());

  std::random_shuffle(fields.begin(), fields.end());

  for (size_t i = 0; i < fields.size(); i++) {
    msg += fields[i] + "\r\n";
  }
  msg += "\r\n";

  msg.append(parameter_->GetKey3());
  return msg;
}

int WebSocketHandshake::ReadServerHandshake(const char* data, size_t len) {
  mode_ = MODE_INCOMPLETE;
  int eoh = HttpUtil::LocateEndOfHeaders(data, len);
  if (eoh < 0)
    return -1;

  scoped_refptr<HttpResponseHeaders> headers(
      new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(data, eoh)));

  if (headers->response_code() != 101) {
    mode_ = MODE_FAILED;
    DLOG(INFO) << "Bad response code: " << headers->response_code();
    return eoh;
  }
  mode_ = MODE_NORMAL;
  if (!ProcessHeaders(*headers) || !CheckResponseHeaders()) {
    DLOG(INFO) << "Process Headers failed: "
               << std::string(data, eoh);
    mode_ = MODE_FAILED;
    return eoh;
  }
  if (len < static_cast<size_t>(eoh + Parameter::kExpectedResponseSize)) {
    mode_ = MODE_INCOMPLETE;
    return -1;
  }
  uint8 expected[Parameter::kExpectedResponseSize];
  parameter_->GetExpectedResponse(expected);
  if (memcmp(&data[eoh], expected, Parameter::kExpectedResponseSize)) {
    mode_ = MODE_FAILED;
    return eoh + Parameter::kExpectedResponseSize;
  }
  mode_ = MODE_CONNECTED;
  return eoh + Parameter::kExpectedResponseSize;
}

std::string WebSocketHandshake::GetResourceName() const {
  std::string resource_name = url_.path();
  if (url_.has_query()) {
    resource_name += "?";
    resource_name += url_.query();
  }
  return resource_name;
}

std::string WebSocketHandshake::GetHostFieldValue() const {
  // url_.host() is expected to be encoded in punnycode here.
  std::string host = StringToLowerASCII(url_.host());
  if (url_.has_port()) {
    bool secure = is_secure();
    int port = url_.EffectiveIntPort();
    if ((!secure &&
         port != kWebSocketPort && port != url_parse::PORT_UNSPECIFIED) ||
        (secure &&
         port != kSecureWebSocketPort && port != url_parse::PORT_UNSPECIFIED)) {
      host += ":";
      host += IntToString(port);
    }
  }
  return host;
}

std::string WebSocketHandshake::GetOriginFieldValue() const {
  // It's OK to lowercase the origin as the Origin header does not contain
  // the path or query portions, as per
  // http://tools.ietf.org/html/draft-abarth-origin-00.
  //
  // TODO(satorux): Should we trim the port portion here if it's 80 for
  // http:// or 443 for https:// ? Or can we assume it's done by the
  // client of the library?
  return StringToLowerASCII(origin_);
}

/* static */
bool WebSocketHandshake::GetSingleHeader(const HttpResponseHeaders& headers,
                                         const std::string& name,
                                         std::string* value) {
  std::string first_value;
  void* iter = NULL;
  if (!headers.EnumerateHeader(&iter, name, &first_value))
    return false;

  // Checks no more |name| found in |headers|.
  // Second call of EnumerateHeader() must return false.
  std::string second_value;
  if (headers.EnumerateHeader(&iter, name, &second_value))
    return false;
  *value = first_value;
  return true;
}

bool WebSocketHandshake::ProcessHeaders(const HttpResponseHeaders& headers) {
  std::string value;
  if (!GetSingleHeader(headers, "upgrade", &value) ||
      value != "WebSocket")
    return false;

  if (!GetSingleHeader(headers, "connection", &value) ||
      !LowerCaseEqualsASCII(value, "upgrade"))
    return false;

  if (!GetSingleHeader(headers, "sec-websocket-origin", &ws_origin_))
    return false;

  if (!GetSingleHeader(headers, "sec-websocket-location", &ws_location_))
    return false;

  // If |protocol_| is not specified by client, we don't care if there's
  // protocol field or not as specified in the spec.
  if (!protocol_.empty()
      && !GetSingleHeader(headers, "sec-websocket-protocol", &ws_protocol_))
    return false;
  return true;
}

bool WebSocketHandshake::CheckResponseHeaders() const {
  DCHECK(mode_ == MODE_NORMAL);
  if (!LowerCaseEqualsASCII(origin_, ws_origin_.c_str()))
    return false;
  if (location_ != ws_location_)
    return false;
  if (!protocol_.empty() && protocol_ != ws_protocol_)
    return false;
  return true;
}

namespace {

// unsigned int version of base::RandInt().
// we can't use base::RandInt(), because max would be negative if it is
// represented as int, so DCHECK(min <= max) fails.
uint32 RandUint32(uint32 min, uint32 max) {
  DCHECK(min <= max);

  uint64 range = static_cast<int64>(max) - min + 1;
  uint64 number = base::RandUint64();
  // TODO(ukai): fix to be uniform.
  // the distribution of the result of modulo will be biased.
  uint32 result = min + static_cast<uint32>(number % range);
  DCHECK(result >= min && result <= max);
  return result;
}

}

uint32 (*WebSocketHandshake::Parameter::rand_)(uint32 min, uint32 max) =
    RandUint32;
uint8 randomCharacterInSecWebSocketKey[0x2F - 0x20 + 0x7E - 0x39];

WebSocketHandshake::Parameter::Parameter()
    : number_1_(0), number_2_(0) {
  if (randomCharacterInSecWebSocketKey[0] == '\0') {
    int i = 0;
    for (int ch = 0x21; ch <= 0x2F; ch++, i++)
      randomCharacterInSecWebSocketKey[i] = ch;
    for (int ch = 0x3A; ch <= 0x7E; ch++, i++)
      randomCharacterInSecWebSocketKey[i] = ch;
  }
}

WebSocketHandshake::Parameter::~Parameter() {}

void WebSocketHandshake::Parameter::GenerateKeys() {
  GenerateSecWebSocketKey(&number_1_, &key_1_);
  GenerateSecWebSocketKey(&number_2_, &key_2_);
  GenerateKey3();
}

static void SetChallengeNumber(uint8* buf, uint32 number) {
  uint8* p = buf + 3;
  for (int i = 0; i < 4; i++) {
    *p = (uint8)(number & 0xFF);
    --p;
    number >>= 8;
  }
}

void WebSocketHandshake::Parameter::GetExpectedResponse(uint8 *expected) const {
  uint8 challenge[kExpectedResponseSize];
  SetChallengeNumber(&challenge[0], number_1_);
  SetChallengeNumber(&challenge[4], number_2_);
  memcpy(&challenge[8], key_3_.data(), kKey3Size);
  MD5Digest digest;
  MD5Sum(challenge, kExpectedResponseSize, &digest);
  memcpy(expected, digest.a, kExpectedResponseSize);
}

/* static */
void WebSocketHandshake::Parameter::SetRandomNumberGenerator(
    uint32 (*rand)(uint32 min, uint32 max)) {
  rand_ = rand;
}

void WebSocketHandshake::Parameter::GenerateSecWebSocketKey(
    uint32* number, std::string* key) {
  uint32 space = rand_(1, 12);
  uint32 max = 4294967295U / space;
  *number = rand_(0, max);
  uint32 product = *number * space;

  std::string s = StringPrintf("%010u", product);
  for (uint32 i = 0; i < space; i++) {
    int pos = rand_(1, s.length() - 1);
    s = s.substr(0, pos) + " " + s.substr(pos);
  }
  int n = rand_(1, 12);
  for (int i = 0; i < n; i++) {
    int pos = rand_(0, s.length());
    int chpos = rand_(0, sizeof(randomCharacterInSecWebSocketKey) - 1);
    s = s.substr(0, pos).append(1, randomCharacterInSecWebSocketKey[chpos]) +
        s.substr(pos);
  }
  *key = s;
}

void WebSocketHandshake::Parameter::GenerateKey3() {
  key_3_.clear();
  for (int i = 0; i < 8; i++) {
    key_3_.append(1, rand_(0, 255));
  }
}

}  // namespace net
<commit_msg>Fix websocket key generation algorithm.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/websockets/websocket_handshake.h"

#include <algorithm>
#include <vector>

#include "base/md5.h"
#include "base/rand_util.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"

namespace net {

const int WebSocketHandshake::kWebSocketPort = 80;
const int WebSocketHandshake::kSecureWebSocketPort = 443;

WebSocketHandshake::WebSocketHandshake(
    const GURL& url,
    const std::string& origin,
    const std::string& location,
    const std::string& protocol)
    : url_(url),
      origin_(origin),
      location_(location),
      protocol_(protocol),
      mode_(MODE_INCOMPLETE) {
}

WebSocketHandshake::~WebSocketHandshake() {
}

bool WebSocketHandshake::is_secure() const {
  return url_.SchemeIs("wss");
}

std::string WebSocketHandshake::CreateClientHandshakeMessage() {
  if (!parameter_.get()) {
    parameter_.reset(new Parameter);
    parameter_->GenerateKeys();
  }
  std::string msg;

  // WebSocket protocol 4.1 Opening handshake.

  msg = "GET ";
  msg += GetResourceName();
  msg += " HTTP/1.1\r\n";

  std::vector<std::string> fields;

  fields.push_back("Upgrade: WebSocket");
  fields.push_back("Connection: Upgrade");

  fields.push_back("Host: " + GetHostFieldValue());

  fields.push_back("Origin: " + GetOriginFieldValue());

  if (!protocol_.empty())
    fields.push_back("Sec-WebSocket-Protocol: " + protocol_);

  // TODO(ukai): Add cookie if necessary.

  fields.push_back("Sec-WebSocket-Key1: " + parameter_->GetSecWebSocketKey1());
  fields.push_back("Sec-WebSocket-Key2: " + parameter_->GetSecWebSocketKey2());

  std::random_shuffle(fields.begin(), fields.end());

  for (size_t i = 0; i < fields.size(); i++) {
    msg += fields[i] + "\r\n";
  }
  msg += "\r\n";

  msg.append(parameter_->GetKey3());
  return msg;
}

int WebSocketHandshake::ReadServerHandshake(const char* data, size_t len) {
  mode_ = MODE_INCOMPLETE;
  int eoh = HttpUtil::LocateEndOfHeaders(data, len);
  if (eoh < 0)
    return -1;

  scoped_refptr<HttpResponseHeaders> headers(
      new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(data, eoh)));

  if (headers->response_code() != 101) {
    mode_ = MODE_FAILED;
    DLOG(INFO) << "Bad response code: " << headers->response_code();
    return eoh;
  }
  mode_ = MODE_NORMAL;
  if (!ProcessHeaders(*headers) || !CheckResponseHeaders()) {
    DLOG(INFO) << "Process Headers failed: "
               << std::string(data, eoh);
    mode_ = MODE_FAILED;
    return eoh;
  }
  if (len < static_cast<size_t>(eoh + Parameter::kExpectedResponseSize)) {
    mode_ = MODE_INCOMPLETE;
    return -1;
  }
  uint8 expected[Parameter::kExpectedResponseSize];
  parameter_->GetExpectedResponse(expected);
  if (memcmp(&data[eoh], expected, Parameter::kExpectedResponseSize)) {
    mode_ = MODE_FAILED;
    return eoh + Parameter::kExpectedResponseSize;
  }
  mode_ = MODE_CONNECTED;
  return eoh + Parameter::kExpectedResponseSize;
}

std::string WebSocketHandshake::GetResourceName() const {
  std::string resource_name = url_.path();
  if (url_.has_query()) {
    resource_name += "?";
    resource_name += url_.query();
  }
  return resource_name;
}

std::string WebSocketHandshake::GetHostFieldValue() const {
  // url_.host() is expected to be encoded in punnycode here.
  std::string host = StringToLowerASCII(url_.host());
  if (url_.has_port()) {
    bool secure = is_secure();
    int port = url_.EffectiveIntPort();
    if ((!secure &&
         port != kWebSocketPort && port != url_parse::PORT_UNSPECIFIED) ||
        (secure &&
         port != kSecureWebSocketPort && port != url_parse::PORT_UNSPECIFIED)) {
      host += ":";
      host += IntToString(port);
    }
  }
  return host;
}

std::string WebSocketHandshake::GetOriginFieldValue() const {
  // It's OK to lowercase the origin as the Origin header does not contain
  // the path or query portions, as per
  // http://tools.ietf.org/html/draft-abarth-origin-00.
  //
  // TODO(satorux): Should we trim the port portion here if it's 80 for
  // http:// or 443 for https:// ? Or can we assume it's done by the
  // client of the library?
  return StringToLowerASCII(origin_);
}

/* static */
bool WebSocketHandshake::GetSingleHeader(const HttpResponseHeaders& headers,
                                         const std::string& name,
                                         std::string* value) {
  std::string first_value;
  void* iter = NULL;
  if (!headers.EnumerateHeader(&iter, name, &first_value))
    return false;

  // Checks no more |name| found in |headers|.
  // Second call of EnumerateHeader() must return false.
  std::string second_value;
  if (headers.EnumerateHeader(&iter, name, &second_value))
    return false;
  *value = first_value;
  return true;
}

bool WebSocketHandshake::ProcessHeaders(const HttpResponseHeaders& headers) {
  std::string value;
  if (!GetSingleHeader(headers, "upgrade", &value) ||
      value != "WebSocket")
    return false;

  if (!GetSingleHeader(headers, "connection", &value) ||
      !LowerCaseEqualsASCII(value, "upgrade"))
    return false;

  if (!GetSingleHeader(headers, "sec-websocket-origin", &ws_origin_))
    return false;

  if (!GetSingleHeader(headers, "sec-websocket-location", &ws_location_))
    return false;

  // If |protocol_| is not specified by client, we don't care if there's
  // protocol field or not as specified in the spec.
  if (!protocol_.empty()
      && !GetSingleHeader(headers, "sec-websocket-protocol", &ws_protocol_))
    return false;
  return true;
}

bool WebSocketHandshake::CheckResponseHeaders() const {
  DCHECK(mode_ == MODE_NORMAL);
  if (!LowerCaseEqualsASCII(origin_, ws_origin_.c_str()))
    return false;
  if (location_ != ws_location_)
    return false;
  if (!protocol_.empty() && protocol_ != ws_protocol_)
    return false;
  return true;
}

namespace {

// unsigned int version of base::RandInt().
// we can't use base::RandInt(), because max would be negative if it is
// represented as int, so DCHECK(min <= max) fails.
uint32 RandUint32(uint32 min, uint32 max) {
  DCHECK(min <= max);

  uint64 range = static_cast<int64>(max) - min + 1;
  uint64 number = base::RandUint64();
  // TODO(ukai): fix to be uniform.
  // the distribution of the result of modulo will be biased.
  uint32 result = min + static_cast<uint32>(number % range);
  DCHECK(result >= min && result <= max);
  return result;
}

}

uint32 (*WebSocketHandshake::Parameter::rand_)(uint32 min, uint32 max) =
    RandUint32;
uint8 randomCharacterInSecWebSocketKey[0x2F - 0x20 + 0x7E - 0x39];

WebSocketHandshake::Parameter::Parameter()
    : number_1_(0), number_2_(0) {
  if (randomCharacterInSecWebSocketKey[0] == '\0') {
    int i = 0;
    for (int ch = 0x21; ch <= 0x2F; ch++, i++)
      randomCharacterInSecWebSocketKey[i] = ch;
    for (int ch = 0x3A; ch <= 0x7E; ch++, i++)
      randomCharacterInSecWebSocketKey[i] = ch;
  }
}

WebSocketHandshake::Parameter::~Parameter() {}

void WebSocketHandshake::Parameter::GenerateKeys() {
  GenerateSecWebSocketKey(&number_1_, &key_1_);
  GenerateSecWebSocketKey(&number_2_, &key_2_);
  GenerateKey3();
}

static void SetChallengeNumber(uint8* buf, uint32 number) {
  uint8* p = buf + 3;
  for (int i = 0; i < 4; i++) {
    *p = (uint8)(number & 0xFF);
    --p;
    number >>= 8;
  }
}

void WebSocketHandshake::Parameter::GetExpectedResponse(uint8 *expected) const {
  uint8 challenge[kExpectedResponseSize];
  SetChallengeNumber(&challenge[0], number_1_);
  SetChallengeNumber(&challenge[4], number_2_);
  memcpy(&challenge[8], key_3_.data(), kKey3Size);
  MD5Digest digest;
  MD5Sum(challenge, kExpectedResponseSize, &digest);
  memcpy(expected, digest.a, kExpectedResponseSize);
}

/* static */
void WebSocketHandshake::Parameter::SetRandomNumberGenerator(
    uint32 (*rand)(uint32 min, uint32 max)) {
  rand_ = rand;
}

void WebSocketHandshake::Parameter::GenerateSecWebSocketKey(
    uint32* number, std::string* key) {
  uint32 space = rand_(1, 12);
  uint32 max = 4294967295U / space;
  *number = rand_(0, max);
  uint32 product = *number * space;

  std::string s = StringPrintf("%u", product);
  int n = rand_(1, 12);
  for (int i = 0; i < n; i++) {
    int pos = rand_(0, s.length());
    int chpos = rand_(0, sizeof(randomCharacterInSecWebSocketKey) - 1);
    s = s.substr(0, pos).append(1, randomCharacterInSecWebSocketKey[chpos]) +
        s.substr(pos);
  }
  for (uint32 i = 0; i < space; i++) {
    int pos = rand_(1, s.length() - 1);
    s = s.substr(0, pos) + " " + s.substr(pos);
  }
  *key = s;
}

void WebSocketHandshake::Parameter::GenerateKey3() {
  key_3_.clear();
  for (int i = 0; i < 8; i++) {
    key_3_.append(1, rand_(0, 255));
  }
}

}  // namespace net
<|endoftext|>


<commit_before>/*
  This file is part of the kblog library.

  Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
  Copyright (c) 2006-2007 Christian Weilbach <christian_weilbach@web.de>
  Copyright (c) 2007-2008 Mike Arthur <mike@mikearthur.co.uk>

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

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include "movabletype.h"
#include "movabletype_p.h"
#include "blogpost.h"

#include <kxmlrpcclient/client.h>

#include <KDebug>
#include <KLocale>
#include <KDateTime>

#include <QtCore/QStringList>

using namespace KBlog;

MovableType::MovableType( const KUrl &server, QObject *parent )
  : MetaWeblog( server, *new MovableTypePrivate, parent )
{
  kDebug() << "MovableType()";
}

MovableType::MovableType( const KUrl &server, MovableTypePrivate &dd,
                        QObject *parent )
  : MetaWeblog( server, dd, parent )
{
  kDebug() << "MovableType()";
}

MovableType::~MovableType()
{
  kDebug() << "~MovableType()";
}

QString MovableType::interfaceName() const
{
  return QLatin1String( "Movable Type" );
}

void MovableType::listRecentPosts( int number )
{
    Q_D( MovableType );
    kDebug() << "Fetching List of Posts...";
    QList<QVariant> args( d->defaultArgs( blogId() ) );
    args << QVariant( number );
    d->mXmlRpcClient->call(
      "metaWeblog.getRecentPosts", args,
      this, SLOT(slotListRecentPosts(const QList<QVariant>&,const QVariant&)),
      this, SLOT(slotError(int,const QString&,const QVariant&)),
      QVariant( number ) );
}

void MovableType::listTrackBackPings( KBlog::BlogPost *post )
{
  Q_D( MovableType );
  kDebug() << "List trackback pings...";
  QList<QVariant> args;
  args << QVariant( post->postId() );
  unsigned int i = d->mCallCounter++;
  d->mCallMap[ i ] = post;
  d->mXmlRpcClient->call(
    "mt.getTracebackPings", args,
    this, SLOT(slotListTrackbackPings(const QList<QVariant>&,const QVariant&)),
    this, SLOT(slotError(int,const QString&,const QVariant&)),
    QVariant( i ) );
}

MovableTypePrivate::MovableTypePrivate()
{
}

MovableTypePrivate::~MovableTypePrivate()
{
  kDebug() << "~MovableTypePrivate()";
}

QList<QVariant> MovableTypePrivate::defaultArgs( const QString &id )
{
  Q_Q( MovableType );
  QList<QVariant> args;
  if( !id.isEmpty() ) {
    args << QVariant( id );
  }
  args << QVariant( q->username() )
       << QVariant( q->password() );
  return args;
}

bool MovableTypePrivate::readPostFromMap( BlogPost *post, const QMap<QString, QVariant> &postInfo )
{

  // FIXME: integrate error handling
  kDebug() << "readPostFromMap()";
  if ( !post ) {
    return false;
  }
  QStringList mapkeys = postInfo.keys();
  kDebug() << endl << "Keys:" << mapkeys.join( ", " );
  kDebug() << endl;

  KDateTime dt =
    KDateTime( postInfo["dateCreated"].toDateTime(), KDateTime::UTC );
  if ( dt.isValid() && !dt.isNull() ) {
    post->setCreationDateTime( dt );
  }

  dt =
    KDateTime( postInfo["lastModified"].toDateTime(), KDateTime::UTC );
  if ( dt.isValid() && !dt.isNull() ) {
    post->setModificationDateTime( dt );
  }

  post->setPostId( postInfo["postid"].toString() );

  QString title( postInfo["title"].toString() );
  QString description( postInfo["description"].toString() );
  QStringList categories( postInfo["categories"].toStringList() );
  //TODO 2 new keys are:
  // String mt_convert_breaks, the value for the convert_breaks field
  // String mt_text_more, the value for the additional entry text
  post->setTitle( title );
  post->setContent( description );
  post->setCommentAllowed( (bool)postInfo["mt_allow_comments"].toInt() );
  post->setTrackBackAllowed( (bool)postInfo["mt_allow_pings"].toInt() );
  post->setSummary( postInfo["mt_excerpt"].toString() );
  post->setTags( postInfo["mt_keywords"].toStringList() );
  post->setLink( postInfo["link"].toString() );
  post->setPermaLink( postInfo["permaLink"].toString() );

  if ( !categories.isEmpty() ){
    kDebug() << "Categories:" << categories;
    post->setCategories( categories );
  }
  return true;
}

void MovableTypePrivate::slotListTrackBackPings(
    const QList<QVariant> &result, const QVariant &id )
{
  Q_Q( MovableType );
  kDebug() << "slotTrackbackPings()";
  BlogPost *post = mCallMap[ id.toInt() ];
  mCallMap.remove( id.toInt() );
  QList<QMap<QString,QString> > trackBackList;
  if ( result[0].type() != QVariant::List ) {
    kError() << "Could not fetch list of trackback pings out of the"
                 << "result from the server.";
    emit q->error( MovableType::ParsingError,
                   i18n( "Could not fetch list of trackback pings out of the "
                         "result from the server." ) );
    return;
  }
  const QList<QVariant> trackBackReceived = result[0].toList();
  QList<QVariant>::ConstIterator it = trackBackReceived.begin();
  QList<QVariant>::ConstIterator end = trackBackReceived.end();
  for ( ; it != end; ++it ) {
    QMap<QString,QString> tping;
    kDebug() << "MIDDLE:" << ( *it ).typeName();
    const QMap<QString, QVariant> trackBackInfo = ( *it ).toMap();
    tping[ "title" ] = trackBackInfo[ "pingTitle"].toString();
    tping[ "url" ] = trackBackInfo[ "pingURL"].toString();
    tping[ "ip" ] = trackBackInfo[ "pingIP"].toString();
    trackBackList << tping;
  }
  kDebug() << "Emitting listedTrackBackPings()";
  emit q->listedTrackBackPings( post, trackBackList );
}

bool MovableTypePrivate::readArgsFromPost( QList<QVariant> *args, const BlogPost &post )
{
  //TODO 3 new keys are:
  // String mt_convert_breaks, the value for the convert_breaks field
  // String mt_text_more, the value for the additional entry text
  // array mt_tb_ping_urls, the list of TrackBack ping URLs for this entry
  if ( !args ) {
    return false;
  }
  QMap<QString, QVariant> map;
  map["categories"] = post.categories();
  map["description"] = post.content();
  map["title"] = post.title();
  map["dateCreated"] = post.creationDateTime().toUtc().dateTime();
  map["mt_allow_comments"] = (int)post.isCommentAllowed();
  map["mt_allow_pings"] = (int)post.isTrackBackAllowed();
  map["mt_excerpt"] = post.summary();
  map["mt_keywords"] = post.tags().join(",");
  //map["mt_tb_ping_urls"] check for that, i think this should only be done on the server.
  *args << map;
  *args << QVariant( !post.isPrivate() );
  return true;
}

#include "movabletype.moc"
<commit_msg>Fix a stupid typo.<commit_after>/*
  This file is part of the kblog library.

  Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
  Copyright (c) 2006-2007 Christian Weilbach <christian_weilbach@web.de>
  Copyright (c) 2007-2008 Mike Arthur <mike@mikearthur.co.uk>

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

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include "movabletype.h"
#include "movabletype_p.h"
#include "blogpost.h"

#include <kxmlrpcclient/client.h>

#include <KDebug>
#include <KLocale>
#include <KDateTime>

#include <QtCore/QStringList>

using namespace KBlog;

MovableType::MovableType( const KUrl &server, QObject *parent )
  : MetaWeblog( server, *new MovableTypePrivate, parent )
{
  kDebug() << "MovableType()";
}

MovableType::MovableType( const KUrl &server, MovableTypePrivate &dd,
                        QObject *parent )
  : MetaWeblog( server, dd, parent )
{
  kDebug() << "MovableType()";
}

MovableType::~MovableType()
{
  kDebug() << "~MovableType()";
}

QString MovableType::interfaceName() const
{
  return QLatin1String( "Movable Type" );
}

void MovableType::listRecentPosts( int number )
{
    Q_D( MovableType );
    kDebug() << "Fetching List of Posts...";
    QList<QVariant> args( d->defaultArgs( blogId() ) );
    args << QVariant( number );
    d->mXmlRpcClient->call(
      "metaWeblog.getRecentPosts", args,
      this, SLOT(slotListRecentPosts(const QList<QVariant>&,const QVariant&)),
      this, SLOT(slotError(int,const QString&,const QVariant&)),
      QVariant( number ) );
}

void MovableType::listTrackBackPings( KBlog::BlogPost *post )
{
  Q_D( MovableType );
  kDebug() << "List trackback pings...";
  QList<QVariant> args;
  args << QVariant( post->postId() );
  unsigned int i = d->mCallCounter++;
  d->mCallMap[ i ] = post;
  d->mXmlRpcClient->call(
    "mt.getTrackbackPings", args,
    this, SLOT(slotListTrackbackPings(const QList<QVariant>&,const QVariant&)),
    this, SLOT(slotError(int,const QString&,const QVariant&)),
    QVariant( i ) );
}

MovableTypePrivate::MovableTypePrivate()
{
}

MovableTypePrivate::~MovableTypePrivate()
{
  kDebug() << "~MovableTypePrivate()";
}

QList<QVariant> MovableTypePrivate::defaultArgs( const QString &id )
{
  Q_Q( MovableType );
  QList<QVariant> args;
  if( !id.isEmpty() ) {
    args << QVariant( id );
  }
  args << QVariant( q->username() )
       << QVariant( q->password() );
  return args;
}

bool MovableTypePrivate::readPostFromMap( BlogPost *post, const QMap<QString, QVariant> &postInfo )
{

  // FIXME: integrate error handling
  kDebug() << "readPostFromMap()";
  if ( !post ) {
    return false;
  }
  QStringList mapkeys = postInfo.keys();
  kDebug() << endl << "Keys:" << mapkeys.join( ", " );
  kDebug() << endl;

  KDateTime dt =
    KDateTime( postInfo["dateCreated"].toDateTime(), KDateTime::UTC );
  if ( dt.isValid() && !dt.isNull() ) {
    post->setCreationDateTime( dt );
  }

  dt =
    KDateTime( postInfo["lastModified"].toDateTime(), KDateTime::UTC );
  if ( dt.isValid() && !dt.isNull() ) {
    post->setModificationDateTime( dt );
  }

  post->setPostId( postInfo["postid"].toString() );

  QString title( postInfo["title"].toString() );
  QString description( postInfo["description"].toString() );
  QStringList categories( postInfo["categories"].toStringList() );
  //TODO 2 new keys are:
  // String mt_convert_breaks, the value for the convert_breaks field
  // String mt_text_more, the value for the additional entry text
  post->setTitle( title );
  post->setContent( description );
  post->setCommentAllowed( (bool)postInfo["mt_allow_comments"].toInt() );
  post->setTrackBackAllowed( (bool)postInfo["mt_allow_pings"].toInt() );
  post->setSummary( postInfo["mt_excerpt"].toString() );
  post->setTags( postInfo["mt_keywords"].toStringList() );
  post->setLink( postInfo["link"].toString() );
  post->setPermaLink( postInfo["permaLink"].toString() );

  if ( !categories.isEmpty() ){
    kDebug() << "Categories:" << categories;
    post->setCategories( categories );
  }
  return true;
}

void MovableTypePrivate::slotListTrackBackPings(
    const QList<QVariant> &result, const QVariant &id )
{
  Q_Q( MovableType );
  kDebug() << "slotTrackbackPings()";
  BlogPost *post = mCallMap[ id.toInt() ];
  mCallMap.remove( id.toInt() );
  QList<QMap<QString,QString> > trackBackList;
  if ( result[0].type() != QVariant::List ) {
    kError() << "Could not fetch list of trackback pings out of the"
                 << "result from the server.";
    emit q->error( MovableType::ParsingError,
                   i18n( "Could not fetch list of trackback pings out of the "
                         "result from the server." ) );
    return;
  }
  const QList<QVariant> trackBackReceived = result[0].toList();
  QList<QVariant>::ConstIterator it = trackBackReceived.begin();
  QList<QVariant>::ConstIterator end = trackBackReceived.end();
  for ( ; it != end; ++it ) {
    QMap<QString,QString> tping;
    kDebug() << "MIDDLE:" << ( *it ).typeName();
    const QMap<QString, QVariant> trackBackInfo = ( *it ).toMap();
    tping[ "title" ] = trackBackInfo[ "pingTitle"].toString();
    tping[ "url" ] = trackBackInfo[ "pingURL"].toString();
    tping[ "ip" ] = trackBackInfo[ "pingIP"].toString();
    trackBackList << tping;
  }
  kDebug() << "Emitting listedTrackBackPings()";
  emit q->listedTrackBackPings( post, trackBackList );
}

bool MovableTypePrivate::readArgsFromPost( QList<QVariant> *args, const BlogPost &post )
{
  //TODO 3 new keys are:
  // String mt_convert_breaks, the value for the convert_breaks field
  // String mt_text_more, the value for the additional entry text
  // array mt_tb_ping_urls, the list of TrackBack ping URLs for this entry
  if ( !args ) {
    return false;
  }
  QMap<QString, QVariant> map;
  map["categories"] = post.categories();
  map["description"] = post.content();
  map["title"] = post.title();
  map["dateCreated"] = post.creationDateTime().toUtc().dateTime();
  map["mt_allow_comments"] = (int)post.isCommentAllowed();
  map["mt_allow_pings"] = (int)post.isTrackBackAllowed();
  map["mt_excerpt"] = post.summary();
  map["mt_keywords"] = post.tags().join(",");
  //map["mt_tb_ping_urls"] check for that, i think this should only be done on the server.
  *args << map;
  *args << QVariant( !post.isPrivate() );
  return true;
}

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


<commit_before>#include <ffigen/generate/generator/function_map_generator.hpp>
#include <ffigen/utility/logger.hpp>
#include <ffigen/utility/exceptions.hpp>
#include <ffigen/utility/error_codes.hpp>
#include <iostream>

namespace ffigen
{
    using namespace utility::logs;

    //! converts
    //!
    //! int my_function(params...)
    //!
    //! to
    //!
    //! _library.my_function = [_library.int, [params...]];
    void function_map_generator::operator()(std::ostream & os) const
    {
        debug() << "function_map_generator::operator(): generating function" << std::endl;

        if (entity.is_variadic()) {
            throw fatal_error(std::string("Variadic functions not supported yet (trying to generate '")
                + entity.name() + "'", error_codes::UNSUPPORTED);
        }

        os << "_library." << entity.name() << " = [";
        os << entity.return_type().ffi_reference();
        os << ", [";

        bool is_first = true;
        for (code_entity const& parameter : entity.argument_types())
        {
            if (is_first)
            {
                is_first = false;
            }
            else
            {
                os << ", ";
            }
            os << parameter.ffi_reference();
        }

        os << "]];";
        newline(os);

        os << "_library._functions.push(_library." << entity.name() << ");";
        newline(os);
        newline(os);

        debug() << "function_map_generator::operator(): finished generating function" << std::endl;
    }
}

// TODO: there are special keywords generated by node-ffi-generator. if a type is named after it, we have to skip mapping it.
//       special keywords are 'exports', 'module', 'require', '_library', ...
<commit_msg>Do not throw fatal error if variadic function found, just ignore.<commit_after>#include <ffigen/generate/generator/function_map_generator.hpp>
#include <ffigen/utility/logger.hpp>
#include <ffigen/utility/exceptions.hpp>
#include <ffigen/utility/error_codes.hpp>
#include <iostream>

namespace ffigen
{
    using namespace utility::logs;

    //! converts
    //!
    //! int my_function(params...)
    //!
    //! to
    //!
    //! _library.my_function = [_library.int, [params...]];
    void function_map_generator::operator()(std::ostream & os) const
    {
        debug() << "function_map_generator::operator(): generating function" << std::endl;

        if (entity.is_variadic()) {
            error() << "Variadic functions not supported yet (trying to generate'"
                    << entity.name() << "')";
            return;
        }

        os << "_library." << entity.name() << " = [";
        os << entity.return_type().ffi_reference();
        os << ", [";

        bool is_first = true;
        for (code_entity const& parameter : entity.argument_types())
        {
            if (is_first)
            {
                is_first = false;
            }
            else
            {
                os << ", ";
            }
            os << parameter.ffi_reference();
        }

        os << "]];";
        newline(os);

        os << "_library._functions.push(_library." << entity.name() << ");";
        newline(os);
        newline(os);

        debug() << "function_map_generator::operator(): finished generating function" << std::endl;
    }
}

// TODO: there are special keywords generated by node-ffi-generator. if a type is named after it, we have to skip mapping it.
//       special keywords are 'exports', 'module', 'require', '_library', ...
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#define EIGEN_USE_THREADS

#include "main.h"
#include <iostream>
#include <Eigen/CXX11/Tensor>

using Eigen::Tensor;

static void test_multithread_elementwise()
{
  Tensor<float, 3> in1(2,3,7);
  Tensor<float, 3> in2(2,3,7);
  Tensor<float, 3> out(2,3,7);

  in1.setRandom();
  in2.setRandom();

  Eigen::ThreadPoolDevice thread_pool_device(internal::random<int>(3, 11));
  out.device(thread_pool_device) = in1 + in2 * 3.14f;

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
      }
    }
  }
}

static void test_multithread_compound_assignment()
{
  Tensor<float, 3> in1(2,3,7);
  Tensor<float, 3> in2(2,3,7);
  Tensor<float, 3> out(2,3,7);

  in1.setRandom();
  in2.setRandom();

  Eigen::ThreadPoolDevice thread_pool_device(internal::random<int>(3, 11));
  out.device(thread_pool_device) = in1;
  out.device(thread_pool_device) += in2 * 3.14f;

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
      }
    }
  }
}

template<int DataLayout>
static void test_multithread_contraction()
{
  Tensor<float, 4, DataLayout> t_left(30, 50, 37, 31);
  Tensor<float, 5, DataLayout> t_right(37, 31, 70, 2, 10);
  Tensor<float, 5, DataLayout> t_result(30, 50, 70, 2, 10);

  t_left.setRandom();
  t_right.setRandom();

  // this contraction should be equivalent to a single matrix multiplication
  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(3, 1)}});

  typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
  MapXf m_left(t_left.data(), 1500, 1147);
  MapXf m_right(t_right.data(), 1147, 1400);
  Matrix<float, Dynamic, Dynamic, DataLayout> m_result(1500, 1400);

  Eigen::ThreadPoolDevice thread_pool_device(4);

  // compute results by separate methods
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  m_result = m_left * m_right;

 for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    VERIFY(&t_result.data()[i] != &m_result.data()[i]);
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }
}

template<int DataLayout>
static void test_contraction_corner_cases()
{
  Tensor<float, 2, DataLayout> t_left(32, 500);
  Tensor<float, 2, DataLayout> t_right(32, 28*28);
  Tensor<float, 2, DataLayout> t_result(500, 28*28);

  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result = t_result.constant(NAN);

  // this contraction should be equivalent to a single matrix multiplication
  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 1> dims{{DimPair(0, 0)}};

  typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
  MapXf m_left(t_left.data(), 32, 500);
  MapXf m_right(t_right.data(), 32, 28*28);
  Matrix<float, Dynamic, Dynamic, DataLayout> m_result(500, 28*28);

  Eigen::ThreadPoolDevice thread_pool_device(12);

  // compute results by separate methods
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  m_result = m_left.transpose() * m_right;

  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!isnan(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected at index " << i << " : " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 1);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_result.resize (1, 28*28);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 1);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!isnan(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 500);
  t_right.resize(32, 4);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result.resize (500, 4);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 500);
  new(&m_right) MapXf(t_right.data(), 32, 4);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!isnan(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 1);
  t_right.resize(32, 4);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result.resize (1, 4);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 1);
  new(&m_right) MapXf(t_right.data(), 32, 4);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!isnan(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }
}

template<int DataLayout>
static void test_multithread_contraction_agrees_with_singlethread() {
  int contract_size = internal::random<int>(1, 5000);

  Tensor<float, 3, DataLayout> left(internal::random<int>(1, 80),
                                    contract_size,
                                    internal::random<int>(1, 100));

  Tensor<float, 4, DataLayout> right(internal::random<int>(1, 25),
                                     internal::random<int>(1, 37),
                                     contract_size,
                                     internal::random<int>(1, 51));

  left.setRandom();
  right.setRandom();

  // add constants to shift values away from 0 for more precision
  left += left.constant(1.5f);
  right += right.constant(1.5f);

  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 1> dims({{DimPair(1, 2)}});

  Eigen::ThreadPoolDevice thread_pool_device(internal::random<int>(2, 11));

  Tensor<float, 5, DataLayout> st_result;
  st_result = left.contract(right, dims);

  Tensor<float, 5, DataLayout> tp_result(st_result.dimensions());
  tp_result.device(thread_pool_device) = left.contract(right, dims);

  VERIFY(dimensions_match(st_result.dimensions(), tp_result.dimensions()));
  for (ptrdiff_t i = 0; i < st_result.size(); i++) {
    // if both of the values are very small, then do nothing (because the test will fail
    // due to numerical precision issues when values are small)
    if (fabs(st_result.data()[i] - tp_result.data()[i]) >= 1e-4) {
      VERIFY_IS_APPROX(st_result.data()[i], tp_result.data()[i]);
    }
  }
}

static void test_memcpy() {

  for (int i = 0; i < 5; ++i) {
    const int num_threads = internal::random<int>(3, 11);
    Eigen::ThreadPoolDevice thread_pool_device(num_threads);

    const int size = internal::random<int>(13, 7632);
    Tensor<float, 1> t1(size);
    t1.setRandom();
    std::vector<float> result(size);
    thread_pool_device.memcpy(&result[0], t1.data(), size*sizeof(float));
    for (int i = 0; i < size; i++) {
      VERIFY_IS_EQUAL(t1(i), result[i]);
    }
  }
}

static void test_multithread_random()
{
  Eigen::ThreadPoolDevice device(2);
  Tensor<float, 1> t(1 << 20);
  t.device(device) = t.random<Eigen::internal::NormalRandomGenerator<float>>();
}

void test_cxx11_tensor_thread_pool()
{
  CALL_SUBTEST(test_multithread_elementwise());
  CALL_SUBTEST(test_multithread_compound_assignment());

  CALL_SUBTEST(test_multithread_contraction<ColMajor>());
  CALL_SUBTEST(test_multithread_contraction<RowMajor>());

  CALL_SUBTEST(test_multithread_contraction_agrees_with_singlethread<ColMajor>());
  CALL_SUBTEST(test_multithread_contraction_agrees_with_singlethread<RowMajor>());

  // Exercise various cases that have been problematic in the past.
  CALL_SUBTEST(test_contraction_corner_cases<ColMajor>());
  CALL_SUBTEST(test_contraction_corner_cases<RowMajor>());

  CALL_SUBTEST(test_memcpy());

  CALL_SUBTEST(test_multithread_random());
}
<commit_msg>Fix clang compilation<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#define EIGEN_USE_THREADS

#include "main.h"
#include <iostream>
#include <Eigen/CXX11/Tensor>

using Eigen::Tensor;
using std::isnan;

static void test_multithread_elementwise()
{
  Tensor<float, 3> in1(2,3,7);
  Tensor<float, 3> in2(2,3,7);
  Tensor<float, 3> out(2,3,7);

  in1.setRandom();
  in2.setRandom();

  Eigen::ThreadPoolDevice thread_pool_device(internal::random<int>(3, 11));
  out.device(thread_pool_device) = in1 + in2 * 3.14f;

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
      }
    }
  }
}

static void test_multithread_compound_assignment()
{
  Tensor<float, 3> in1(2,3,7);
  Tensor<float, 3> in2(2,3,7);
  Tensor<float, 3> out(2,3,7);

  in1.setRandom();
  in2.setRandom();

  Eigen::ThreadPoolDevice thread_pool_device(internal::random<int>(3, 11));
  out.device(thread_pool_device) = in1;
  out.device(thread_pool_device) += in2 * 3.14f;

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 3; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
      }
    }
  }
}

template<int DataLayout>
static void test_multithread_contraction()
{
  Tensor<float, 4, DataLayout> t_left(30, 50, 37, 31);
  Tensor<float, 5, DataLayout> t_right(37, 31, 70, 2, 10);
  Tensor<float, 5, DataLayout> t_result(30, 50, 70, 2, 10);

  t_left.setRandom();
  t_right.setRandom();

  // this contraction should be equivalent to a single matrix multiplication
  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(3, 1)}});

  typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
  MapXf m_left(t_left.data(), 1500, 1147);
  MapXf m_right(t_right.data(), 1147, 1400);
  Matrix<float, Dynamic, Dynamic, DataLayout> m_result(1500, 1400);

  Eigen::ThreadPoolDevice thread_pool_device(4);

  // compute results by separate methods
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  m_result = m_left * m_right;

 for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    VERIFY(&t_result.data()[i] != &m_result.data()[i]);
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }
}

template<int DataLayout>
static void test_contraction_corner_cases()
{
  Tensor<float, 2, DataLayout> t_left(32, 500);
  Tensor<float, 2, DataLayout> t_right(32, 28*28);
  Tensor<float, 2, DataLayout> t_result(500, 28*28);

  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result = t_result.constant(NAN);

  // this contraction should be equivalent to a single matrix multiplication
  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 1> dims{{DimPair(0, 0)}};

  typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
  MapXf m_left(t_left.data(), 32, 500);
  MapXf m_right(t_right.data(), 32, 28*28);
  Matrix<float, Dynamic, Dynamic, DataLayout> m_result(500, 28*28);

  Eigen::ThreadPoolDevice thread_pool_device(12);

  // compute results by separate methods
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  m_result = m_left.transpose() * m_right;

  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!isnan(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected at index " << i << " : " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 1);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_result.resize (1, 28*28);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 1);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!isnan(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 500);
  t_right.resize(32, 4);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result.resize (500, 4);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 500);
  new(&m_right) MapXf(t_right.data(), 32, 4);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!isnan(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }

  t_left.resize(32, 1);
  t_right.resize(32, 4);
  t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
  t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
  t_result.resize (1, 4);
  t_result = t_result.constant(NAN);
  t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
  new(&m_left) MapXf(t_left.data(), 32, 1);
  new(&m_right) MapXf(t_right.data(), 32, 4);
  m_result = m_left.transpose() * m_right;
  for (ptrdiff_t i = 0; i < t_result.size(); i++) {
    assert(!isnan(t_result.data()[i]));
    if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
      std::cout << "mismatch detected: " << t_result.data()[i] << " vs " <<  m_result.data()[i] << std::endl;
      assert(false);
    }
  }
}

template<int DataLayout>
static void test_multithread_contraction_agrees_with_singlethread() {
  int contract_size = internal::random<int>(1, 5000);

  Tensor<float, 3, DataLayout> left(internal::random<int>(1, 80),
                                    contract_size,
                                    internal::random<int>(1, 100));

  Tensor<float, 4, DataLayout> right(internal::random<int>(1, 25),
                                     internal::random<int>(1, 37),
                                     contract_size,
                                     internal::random<int>(1, 51));

  left.setRandom();
  right.setRandom();

  // add constants to shift values away from 0 for more precision
  left += left.constant(1.5f);
  right += right.constant(1.5f);

  typedef Tensor<float, 1>::DimensionPair DimPair;
  Eigen::array<DimPair, 1> dims({{DimPair(1, 2)}});

  Eigen::ThreadPoolDevice thread_pool_device(internal::random<int>(2, 11));

  Tensor<float, 5, DataLayout> st_result;
  st_result = left.contract(right, dims);

  Tensor<float, 5, DataLayout> tp_result(st_result.dimensions());
  tp_result.device(thread_pool_device) = left.contract(right, dims);

  VERIFY(dimensions_match(st_result.dimensions(), tp_result.dimensions()));
  for (ptrdiff_t i = 0; i < st_result.size(); i++) {
    // if both of the values are very small, then do nothing (because the test will fail
    // due to numerical precision issues when values are small)
    if (fabs(st_result.data()[i] - tp_result.data()[i]) >= 1e-4) {
      VERIFY_IS_APPROX(st_result.data()[i], tp_result.data()[i]);
    }
  }
}

static void test_memcpy() {

  for (int i = 0; i < 5; ++i) {
    const int num_threads = internal::random<int>(3, 11);
    Eigen::ThreadPoolDevice thread_pool_device(num_threads);

    const int size = internal::random<int>(13, 7632);
    Tensor<float, 1> t1(size);
    t1.setRandom();
    std::vector<float> result(size);
    thread_pool_device.memcpy(&result[0], t1.data(), size*sizeof(float));
    for (int i = 0; i < size; i++) {
      VERIFY_IS_EQUAL(t1(i), result[i]);
    }
  }
}

static void test_multithread_random()
{
  Eigen::ThreadPoolDevice device(2);
  Tensor<float, 1> t(1 << 20);
  t.device(device) = t.random<Eigen::internal::NormalRandomGenerator<float>>();
}

void test_cxx11_tensor_thread_pool()
{
  CALL_SUBTEST(test_multithread_elementwise());
  CALL_SUBTEST(test_multithread_compound_assignment());

  CALL_SUBTEST(test_multithread_contraction<ColMajor>());
  CALL_SUBTEST(test_multithread_contraction<RowMajor>());

  CALL_SUBTEST(test_multithread_contraction_agrees_with_singlethread<ColMajor>());
  CALL_SUBTEST(test_multithread_contraction_agrees_with_singlethread<RowMajor>());

  // Exercise various cases that have been problematic in the past.
  CALL_SUBTEST(test_contraction_corner_cases<ColMajor>());
  CALL_SUBTEST(test_contraction_corner_cases<RowMajor>());

  CALL_SUBTEST(test_memcpy());

  CALL_SUBTEST(test_multithread_random());
}
<|endoftext|>


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

#include "reformpriorities.h"
#include <tuple>

namespace RfrmPri {
  // namespace to hold everything related to the
  // "priority of reforms" CDMP. Note that KBase has no access.

  using namespace std;

  using KBase::KMatrix;
  using KBase::PRNG;
  using KBase::VUI;
  using KBase::printVUI;

  // -------------------------------------------------
  // function definitions

  // return the list of the most self-interested position of each actor,
  // with the CP last.
  // As a side-affect, set each actor's min/max permutation values so as to
  // compute normalized utilities later.
  vector<VUI> scanPositions(const RPModel * rpm) {
    unsigned int numA = rpm->numAct;
    unsigned int numRefItem = rpm->numItm;
    assert(numRefItem == rpm->numCat);

    printf("There are %u actors and %u reform items \n", numA, numRefItem);

    cout << "Computing positions ... " << endl;
    vector<VUI> positions; // list of all positions
    VUI pstn;
    // build the first permutation: 1,2,3,...
    for (unsigned int i = 0; i < numRefItem; i++) {
      pstn.push_back(i);
    }
    positions.push_back(pstn);
    while (next_permutation(pstn.begin(), pstn.end())) {
      positions.push_back(pstn);
    }
    const unsigned int numPos = positions.size();
    cout << "For " << numRefItem << " reform items there are " << numPos << " positions" << endl;

    // -------------------------------------------------
    // The next section sets up actor utilities.
    // First, we compute the unnormalized, raw utilities. The 'utilActorPos' checks
    // to see if pvMin/pvMax have been set, and returns the raw scores if not.
    // Then we scan across rows to find that actor's pvMin/pvMax, and record that
    // so utilActorPos can use it in the future. Finally, we normalize the rows and
    // display the normalized utility matrix.
    cout << "Computing utilities of positions ... " << endl;
    cout << "Effective gov costs:" << endl;
    (rpm->govCost).mPrintf("%.3f ");
    cout << endl;
    auto ruFn = [positions, rpm](unsigned int ai, unsigned int pj) {
      auto pstn = positions[pj];
      double uip = rpm->utilActorPos(ai, pstn);
      return uip;
    };
    auto rawUij = KMatrix::map(ruFn, numA, numPos); // rows are actors, columns are all possible positions
    for (unsigned int i = 0; i < numA; i++) {
      double pvMin = rawUij(i, 0);
      double pvMax = rawUij(i, 0);
      for (unsigned int j = 0; j < numPos; j++) {
        double rij = rawUij(i, j);
        if (rij < pvMin) {
          pvMin = rij;
        }
        if (rij > pvMax) {
          pvMax = rij;
        }
      }
      assert(0 <= pvMin);
      assert(pvMin < pvMax);
      auto ai = ((RPActor*)(rpm->actrs[i]));
      ai->posValMin = pvMin;
      ai->posValMax = pvMax;
    }
    KMatrix uij = KBase::rescaleRows(rawUij, 0.0, 1.0); // von Neumann utility scale

    cout << "Complete (normalized) utility matrix of all possible positions (rows) versus actors (columns)" << endl << flush;
    for (unsigned int pj = 0; pj < numPos; pj++) {
      printf("%3u  ", pj);
      auto pstn = positions[pj];
      printVUI(pstn);
      printf("  ");
      for (unsigned int ai = 0; ai < numA; ai++) {
        double uap = uij(ai, pj);
        printf("%6.4f, ", uap);
      }
      cout << endl << flush;
    }

    // -------------------------------------------------
    // The next section determines the most self-interested positions for each actor,
    // as well as the 'central position' over all possible reform priorities
    // (which 'office seeking politicans' would adopt IF proportional voting).
    cout << endl << "Computing best position for each actor" << endl;
    vector<VUI> bestAP; // list of each actor's best position (followed by CP)
    for (unsigned int ai = 0; ai < numA; ai++) {
      unsigned int bestJ = 0;
      double bestV = 0;
      for (unsigned int pj = 0; pj < numPos; pj++) {
        if (bestV < uij(ai, pj)) {
          bestJ = pj;
          bestV = uij(ai, pj);
        }
      }
      printf("Best for %02u is ", ai);
      printVUI(positions[bestJ]);
      cout << endl;
      bestAP.push_back(positions[bestJ]);
    }

    cout << "Computing zeta ... " << endl;
    KMatrix aCap = KMatrix(1, numA);
    for (unsigned int i = 0; i < numA; i++) {
      auto ri = ((const RPActor *)(rpm->actrs[i]));
      aCap(0, i) = ri->sCap;
    }
    KMatrix zeta = aCap * uij;
    assert((1 == zeta.numR()) && (numPos == zeta.numC()));

    cout << "Sorting positions from most to least net support ..." << endl << flush;

    auto betterPR = [](tuple<unsigned int, double, VUI> pr1,
      tuple<unsigned int, double, VUI> pr2) {
      double v1 = get<1>(pr1);
      double v2 = get<1>(pr2);
      bool better = (v1 > v2);
      return better;
    };

    auto pairs = vector<tuple<unsigned int, double, VUI>>();
    for (unsigned int i = 0; i < numPos; i++) {
      auto pri = tuple<unsigned int, double, VUI>(i, zeta(0, i), positions[i]);
      pairs.push_back(pri);
    }

    sort(pairs.begin(), pairs.end(), betterPR);

    const unsigned int maxDisplayed = 720; // factorial(6)
    unsigned int  numPr = (pairs.size() < maxDisplayed) ? pairs.size() : maxDisplayed;

    cout << "Displaying highest " << numPr << endl << flush;
    for (unsigned int i = 0; i < numPr; i++) {
      auto pri = pairs[i];
      unsigned int ni = get<0>(pri);
      double zi = get<1>(pri);
      VUI pi = get<2>(pri);

      printf(" %3u: %4u  %.2f  ", i, ni, zi);
      printVUI(pi);
      cout << endl << flush;
    }

    VUI bestPerm = get<2>(pairs[0]);

    bestAP.push_back(bestPerm);
    return bestAP;
  }

} // end of namespace

int main(int ac, char **av) {
  using KBase::ReportingLevel;
  using KBase::PRNG;
  using KBase::MtchPstn;
  using KBase::dSeed;
  using RfrmPri::RPModel;
  using RfrmPri::RPState;
  using RfrmPri::RPActor;
  using RfrmPri::printPerm;

  auto sTime = KBase::displayProgramStart(RfrmPri::appName, RfrmPri::appVersion);
  uint64_t seed = dSeed; // arbitrary;
  bool siP = true;
  bool cpP = false;
  bool runP = true;
  unsigned int sNum = 1;
  bool xmlP = false;
  string inputXML = "";

  auto showHelp = [ sNum]() {
    printf("\n");
    printf("Usage: specify one or more of these options\n");
    printf("\n");
    printf("--cp              start all actors from the central position \n");
    printf("--si              start each actor from their most self-interested position \n");
    printf("                  If neither si nor cp are specified, it will use si. \n");
    printf("                  If both si and cp are specified, it will use second specified. \n");
    printf("--help            print this message and exit \n");
    printf("--seed <n>        set a 64bit seed \n");
    printf("                  0 means truly random \n");
    printf("                  default: %020llu \n", dSeed);
    printf("--sNum <n>        choose a scenario number \n");
    printf("                  default: %u \n", sNum);
    printf("--xml <f>         read XML scenario from a given file \n");
    printf("\n");
    printf("For example, rpdemo --si  --xml rpdata.xml, would read the file rpdata.xml \n");
    printf("and start all actors from self-interested positions.\n");
    printf("\n");
    printf("If both scenario number and XML file are specified, it will use only the XML.\n");
    printf("\n");
    printf("If neither scenario number nor XML file are specified, \n");
    printf("it will run a hard-coded example, as if --sNum 1 had been specified.\n");
    printf("\n");
  };

  // a list of <keyword, description, λ-fn>
  // might be enough to do this - except for the arguments to options.
  if (ac > 1) {
    for (int i = 1; i < ac; i++) {
      if (strcmp(av[i], "--seed") == 0) {
        i++;
        seed = std::stoull(av[i]);
      }
      else if (strcmp(av[i], "--sNum") == 0) {
        i++;
        sNum = atoi(av[i]);
      }
      else if (strcmp(av[i], "--xml") == 0) {
        xmlP = true;
        i++;
        inputXML = av[i];
      }
      else if (strcmp(av[i], "--si") == 0) {
        cpP = false;
        siP = true;
      }
      else if (strcmp(av[i], "--cp") == 0) {
        siP = false;
        cpP = true;
      }
      else if (strcmp(av[i], "--help") == 0) {
        runP = false;
      }
      else {
        runP = false;
        printf("Unrecognized argument: %s\n", av[i]);
      }
    }
  }

  if (!runP) {
    showHelp();
    return 0;
  }

  PRNG * rng = new PRNG();
  if (0 == seed) {
    seed = rng->setSeed(seed); // 0 == get a random number
  }
  printf("Using PRNG seed:  %020llu \n", seed);
  printf("Same seed in hex:   0x%016llX \n", seed);
  // Unix correctly prints all digits with lu, lX, llu, and llX.
  // Windows only prints part, with lu, lX, llu, and llX.

  auto rpm = new RPModel(rng);
  if (xmlP) {
    rpm->readXML(inputXML);
    cout << "done reading XML" << endl << flush;
  }
  else {
    switch (sNum) {
    case 0:
      rpm->initScen(sNum);
      break;
    case 1:
      rpm->initScen(sNum);
      break;

    case 2:
    case 20:
    case 21:
    case 22:
    case 23:
      rpm->initScen(sNum);
      break;

    case 3:
    case 30:
    case 31:
    case 32:
    case 33:
      rpm->initScen(sNum);
      break;

    default:
      cout << "Unrecognized scenario number " << sNum << endl << flush;
      assert(false);
      break;
    }
  }

  unsigned int numA = rpm->numAct; // the actors are as yet unnamed
  unsigned int numR = rpm->numItm;
  //unsigned int numC = rpm->numCat;

  auto rps0 = new RPState(rpm);
  rpm->addState(rps0);

  auto pstns = RfrmPri::scanPositions(rpm);
  KBase::VUI bestPerm = pstns[numA];
  assert(numR == bestPerm.size());

  // Either start them all at the CP or have each to choose an initial position which
  // maximizes their direct utility, regardless of expected utility.
  for (unsigned int i = 0; i < numA; i++) {
    auto pi = new  MtchPstn();
    pi->numCat = numR;
    pi->numItm = numR;
    if (cpP) {
      pi->match = bestPerm;
    }
    if (siP) {
      pi->match = pstns[i];
    }
    rps0->addPstn(pi);
  }
  assert(numA == rps0->pstns.size());

  rps0->step = [rps0]() {
    return rps0->stepSUSN();
  };
  unsigned int maxIter = 100;
  rpm->stop = [maxIter, rpm](unsigned int iter, const KBase::State * s) {
    bool doneP = iter > maxIter;
    if (doneP) {
      printf("Max iteration limit of %u exceeded \n", maxIter);
    }
    auto s2 = ((const RPState *)(rpm->history[iter]));
    for (unsigned int i = 0; i < iter; i++) {
      auto s1 = ((const RPState *)(rpm->history[i]));
      if (RPModel::equivStates(s1, s2)) {
        doneP = true;
        printf("State number %u matched state number %u \n", iter, i);
      }
    }

    return doneP;
  };

  rps0->setUENdx();
  rpm->run();

  // we already displayed each state as it was processed,
  // so there is no need to show it again
  //rpm->showHist();

  delete rpm; // and actors, and states
  rpm = nullptr;
  rps0 = nullptr;

  delete rng;
  rng = nullptr;

  KBase::displayProgramEnd(sTime);

  return 0;
}

// --------------------------------------------
// Copyright KAPSARC. Open source MIT License.
// --------------------------------------------
<commit_msg>show actor weights<commit_after>// --------------------------------------------
// Copyright KAPSARC. Open source MIT License.
// --------------------------------------------
// The MIT License (MIT)
//
// Copyright (c) 2015 King Abdullah Petroleum Studies and Research Center
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
// the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// -------------------------------------------------
// Define the functions and methods unique to the Priority case.
// -------------------------------------------------

#include "reformpriorities.h"
#include <tuple>

namespace RfrmPri {
  // namespace to hold everything related to the
  // "priority of reforms" CDMP. Note that KBase has no access.

  using namespace std;

  using KBase::KMatrix;
  using KBase::PRNG;
  using KBase::VUI;
  using KBase::printVUI;

  // -------------------------------------------------
  // function definitions

  // return the list of the most self-interested position of each actor,
  // with the CP last.
  // As a side-affect, set each actor's min/max permutation values so as to
  // compute normalized utilities later.
  vector<VUI> scanPositions(const RPModel * rpm) {
    unsigned int numA = rpm->numAct;
    unsigned int numRefItem = rpm->numItm;
    assert(numRefItem == rpm->numCat);

    printf("There are %u actors and %u reform items \n", numA, numRefItem);

    cout << "Computing positions ... " << endl;
    vector<VUI> positions; // list of all positions
    VUI pstn;
    // build the first permutation: 1,2,3,...
    for (unsigned int i = 0; i < numRefItem; i++) {
      pstn.push_back(i);
    }
    positions.push_back(pstn);
    while (next_permutation(pstn.begin(), pstn.end())) {
      positions.push_back(pstn);
    }
    const unsigned int numPos = positions.size();
    cout << "For " << numRefItem << " reform items there are " << numPos << " positions" << endl;

    // -------------------------------------------------
    // The next section sets up actor utilities.
    // First, we compute the unnormalized, raw utilities. The 'utilActorPos' checks
    // to see if pvMin/pvMax have been set, and returns the raw scores if not.
    // Then we scan across rows to find that actor's pvMin/pvMax, and record that
    // so utilActorPos can use it in the future. Finally, we normalize the rows and
    // display the normalized utility matrix.
    cout << "Computing utilities of positions ... " << endl;
    cout << "Effective gov costs:" << endl;
    (rpm->govCost).mPrintf("%.3f ");
    cout << endl;
    auto ruFn = [positions, rpm](unsigned int ai, unsigned int pj) {
      auto pstn = positions[pj];
      double uip = rpm->utilActorPos(ai, pstn);
      return uip;
    };
    auto rawUij = KMatrix::map(ruFn, numA, numPos); // rows are actors, columns are all possible positions
    for (unsigned int i = 0; i < numA; i++) {
      double pvMin = rawUij(i, 0);
      double pvMax = rawUij(i, 0);
      for (unsigned int j = 0; j < numPos; j++) {
        double rij = rawUij(i, j);
        if (rij < pvMin) {
          pvMin = rij;
        }
        if (rij > pvMax) {
          pvMax = rij;
        }
      }
      assert(0 <= pvMin);
      assert(pvMin < pvMax);
      auto ai = ((RPActor*)(rpm->actrs[i]));
      ai->posValMin = pvMin;
      ai->posValMax = pvMax;
    }
    KMatrix uij = KBase::rescaleRows(rawUij, 0.0, 1.0); // von Neumann utility scale

    cout << "Complete (normalized) utility matrix of all possible positions (rows) versus actors (columns)" << endl << flush;
    for (unsigned int pj = 0; pj < numPos; pj++) {
      printf("%3u  ", pj);
      auto pstn = positions[pj];
      printVUI(pstn);
      printf("  ");
      for (unsigned int ai = 0; ai < numA; ai++) {
        double uap = uij(ai, pj);
        printf("%6.4f, ", uap);
      }
      cout << endl << flush;
    }

    // -------------------------------------------------
    // The next section determines the most self-interested positions for each actor,
    // as well as the 'central position' over all possible reform priorities
    // (which 'office seeking politicans' would adopt IF proportional voting).
    cout << endl << "Computing best position for each actor" << endl;
    vector<VUI> bestAP; // list of each actor's best position (followed by CP)
    for (unsigned int ai = 0; ai < numA; ai++) {
      unsigned int bestJ = 0;
      double bestV = 0;
      for (unsigned int pj = 0; pj < numPos; pj++) {
        if (bestV < uij(ai, pj)) {
          bestJ = pj;
          bestV = uij(ai, pj);
        }
      }
      printf("Best for %02u is ", ai);
      printVUI(positions[bestJ]);
      cout << endl;
      bestAP.push_back(positions[bestJ]);
    }

    KMatrix aCap = KMatrix(1, numA);
    for (unsigned int i = 0; i < numA; i++) {
      auto ri = ((const RPActor *)(rpm->actrs[i]));
      aCap(0, i) = ri->sCap;
    }
    cout << "Actor capabilities: " << endl;
    aCap.mPrintf(" %.2f ");
    cout << endl;

    cout << "Computing zeta ... " << endl;
    KMatrix zeta = aCap * uij;
    assert((1 == zeta.numR()) && (numPos == zeta.numC()));

    cout << "Sorting positions from most to least net support ..." << endl << flush;

    auto betterPR = [](tuple<unsigned int, double, VUI> pr1,
      tuple<unsigned int, double, VUI> pr2) {
      double v1 = get<1>(pr1);
      double v2 = get<1>(pr2);
      bool better = (v1 > v2);
      return better;
    };

    auto pairs = vector<tuple<unsigned int, double, VUI>>();
    for (unsigned int i = 0; i < numPos; i++) {
      auto pri = tuple<unsigned int, double, VUI>(i, zeta(0, i), positions[i]);
      pairs.push_back(pri);
    }

    sort(pairs.begin(), pairs.end(), betterPR);

    const unsigned int maxDisplayed = 720; // factorial(6)
    unsigned int  numPr = (pairs.size() < maxDisplayed) ? pairs.size() : maxDisplayed;

    cout << "Displaying highest " << numPr << endl << flush;
    for (unsigned int i = 0; i < numPr; i++) {
      auto pri = pairs[i];
      unsigned int ni = get<0>(pri);
      double zi = get<1>(pri);
      VUI pi = get<2>(pri);

      printf(" %3u: %4u  %.2f  ", i, ni, zi);
      printVUI(pi);
      cout << endl << flush;
    }

    VUI bestPerm = get<2>(pairs[0]);

    bestAP.push_back(bestPerm);
    return bestAP;
  }

} // end of namespace

int main(int ac, char **av) {
  using KBase::ReportingLevel;
  using KBase::PRNG;
  using KBase::MtchPstn;
  using KBase::dSeed;
  using RfrmPri::RPModel;
  using RfrmPri::RPState;
  using RfrmPri::RPActor;
  using RfrmPri::printPerm;

  auto sTime = KBase::displayProgramStart(RfrmPri::appName, RfrmPri::appVersion);
  uint64_t seed = dSeed; // arbitrary;
  bool siP = true;
  bool cpP = false;
  bool runP = true;
  unsigned int sNum = 1;
  bool xmlP = false;
  string inputXML = "";

  auto showHelp = [ sNum]() {
    printf("\n");
    printf("Usage: specify one or more of these options\n");
    printf("\n");
    printf("--cp              start all actors from the central position \n");
    printf("--si              start each actor from their most self-interested position \n");
    printf("                  If neither si nor cp are specified, it will use si. \n");
    printf("                  If both si and cp are specified, it will use second specified. \n");
    printf("--help            print this message and exit \n");
    printf("--seed <n>        set a 64bit seed \n");
    printf("                  0 means truly random \n");
    printf("                  default: %020llu \n", dSeed);
    printf("--sNum <n>        choose a scenario number \n");
    printf("                  default: %u \n", sNum);
    printf("--xml <f>         read XML scenario from a given file \n");
    printf("\n");
    printf("For example, rpdemo --si  --xml rpdata.xml, would read the file rpdata.xml \n");
    printf("and start all actors from self-interested positions.\n");
    printf("\n");
    printf("If both scenario number and XML file are specified, it will use only the XML.\n");
    printf("\n");
    printf("If neither scenario number nor XML file are specified, \n");
    printf("it will run a hard-coded example, as if --sNum 1 had been specified.\n");
    printf("\n");
  };

  // a list of <keyword, description, λ-fn>
  // might be enough to do this - except for the arguments to options.
  if (ac > 1) {
    for (int i = 1; i < ac; i++) {
      if (strcmp(av[i], "--seed") == 0) {
        i++;
        seed = std::stoull(av[i]);
      }
      else if (strcmp(av[i], "--sNum") == 0) {
        i++;
        sNum = atoi(av[i]);
      }
      else if (strcmp(av[i], "--xml") == 0) {
        xmlP = true;
        i++;
        inputXML = av[i];
      }
      else if (strcmp(av[i], "--si") == 0) {
        cpP = false;
        siP = true;
      }
      else if (strcmp(av[i], "--cp") == 0) {
        siP = false;
        cpP = true;
      }
      else if (strcmp(av[i], "--help") == 0) {
        runP = false;
      }
      else {
        runP = false;
        printf("Unrecognized argument: %s\n", av[i]);
      }
    }
  }

  if (!runP) {
    showHelp();
    return 0;
  }

  PRNG * rng = new PRNG();
  if (0 == seed) {
    seed = rng->setSeed(seed); // 0 == get a random number
  }
  printf("Using PRNG seed:  %020llu \n", seed);
  printf("Same seed in hex:   0x%016llX \n", seed);
  // Unix correctly prints all digits with lu, lX, llu, and llX.
  // Windows only prints part, with lu, lX, llu, and llX.

  auto rpm = new RPModel(rng);
  if (xmlP) {
    rpm->readXML(inputXML);
    cout << "done reading XML" << endl << flush;
  }
  else {
    switch (sNum) {
    case 0:
      rpm->initScen(sNum);
      break;
    case 1:
      rpm->initScen(sNum);
      break;

    case 2:
    case 20:
    case 21:
    case 22:
    case 23:
      rpm->initScen(sNum);
      break;

    case 3:
    case 30:
    case 31:
    case 32:
    case 33:
      rpm->initScen(sNum);
      break;

    default:
      cout << "Unrecognized scenario number " << sNum << endl << flush;
      assert(false);
      break;
    }
  }

  unsigned int numA = rpm->numAct; // the actors are as yet unnamed
  unsigned int numR = rpm->numItm;
  //unsigned int numC = rpm->numCat;

  auto rps0 = new RPState(rpm);
  rpm->addState(rps0);

  auto pstns = RfrmPri::scanPositions(rpm);
  KBase::VUI bestPerm = pstns[numA];
  assert(numR == bestPerm.size());

  // Either start them all at the CP or have each to choose an initial position which
  // maximizes their direct utility, regardless of expected utility.
  for (unsigned int i = 0; i < numA; i++) {
    auto pi = new  MtchPstn();
    pi->numCat = numR;
    pi->numItm = numR;
    if (cpP) {
      pi->match = bestPerm;
    }
    if (siP) {
      pi->match = pstns[i];
    }
    rps0->addPstn(pi);
  }
  assert(numA == rps0->pstns.size());

  rps0->step = [rps0]() {
    return rps0->stepSUSN();
  };
  unsigned int maxIter = 100;
  rpm->stop = [maxIter, rpm](unsigned int iter, const KBase::State * s) {
    bool doneP = iter > maxIter;
    if (doneP) {
      printf("Max iteration limit of %u exceeded \n", maxIter);
    }
    auto s2 = ((const RPState *)(rpm->history[iter]));
    for (unsigned int i = 0; i < iter; i++) {
      auto s1 = ((const RPState *)(rpm->history[i]));
      if (RPModel::equivStates(s1, s2)) {
        doneP = true;
        printf("State number %u matched state number %u \n", iter, i);
      }
    }

    return doneP;
  };

  rps0->setUENdx();
  rpm->run();

  // we already displayed each state as it was processed,
  // so there is no need to show it again
  //rpm->showHist();

  delete rpm; // and actors, and states
  rpm = nullptr;
  rps0 = nullptr;

  delete rng;
  rng = nullptr;

  KBase::displayProgramEnd(sTime);

  return 0;
}

// --------------------------------------------
// Copyright KAPSARC. Open source MIT License.
// --------------------------------------------
<|endoftext|>


<commit_before><commit_msg>Use range-based for loops<commit_after><|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/operation/valid/SweeplineNestedRingTester.h>
#include <geos/operation/valid/IsValidOp.h>
#include <geos/index/sweepline/SweepLineInterval.h>
#include <geos/index/sweepline/SweepLineIndex.h>
#include <geos/algorithm/CGAlgorithms.h>
#include <geos/geom/LinearRing.h>

#include <cassert>

using namespace geos::algorithm;
using namespace geos::index::sweepline;
using namespace geos::geom;

namespace geos {
namespace operation { // geos.operation
namespace valid { // geos.operation.valid

SweeplineNestedRingTester::OverlapAction::OverlapAction(SweeplineNestedRingTester *p)
{
	isNonNested=true;
	parent=p;
}

void
SweeplineNestedRingTester::OverlapAction::overlap(SweepLineInterval *s0, SweepLineInterval *s1)
{
	LinearRing *innerRing=(LinearRing*) s0->getItem();
	LinearRing *searchRing=(LinearRing*) s1->getItem();
	if (innerRing==searchRing) return;
	if (parent->isInside(innerRing, searchRing))
		isNonNested=false;
};

bool
SweeplineNestedRingTester::isNonNested()
{
	buildIndex();
	OverlapAction *action=new OverlapAction(this);
	sweepLine->computeOverlaps(action);
	return action->isNonNested;
}

void
SweeplineNestedRingTester::buildIndex()
{
	sweepLine=new SweepLineIndex();
	for(unsigned int i=0, n=rings.size(); i<n; i++) {
		LinearRing *ring=rings[i];
		const Envelope *env=ring->getEnvelopeInternal();
		SweepLineInterval *sweepInt=new SweepLineInterval(env->getMinX(),env->getMaxX(),ring);
		sweepLine->add(sweepInt);
	}
}

bool
SweeplineNestedRingTester::isInside(LinearRing *innerRing,LinearRing *searchRing)
{
	CoordinateSequence *innerRingPts=innerRing->getCoordinates();
	CoordinateSequence *searchRingPts=searchRing->getCoordinates();

	if (!innerRing->getEnvelopeInternal()->intersects(searchRing->getEnvelopeInternal()))
		return false;
	const Coordinate *innerRingPt=IsValidOp::findPtNotNode(innerRingPts, searchRing, graph);

	// Unable to find a ring point not a node of the search ring
	assert(innerRingPt!=NULL);

	bool isInside=CGAlgorithms::isPointInRing(*innerRingPt,searchRingPts);
	if (isInside) {
		/*
		 * innerRingPt is const just because the input
		 * CoordinateSequence is const. If the input
		 * Polygon survives lifetime of this object
		 * we are safe.
		 */
		nestedPt=const_cast<Coordinate *>(innerRingPt);
		return true;
	}
	return false;
}

} // namespace geos.operation.valid
} // namespace geos.operation
} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.16  2006/03/21 10:01:30  strk
 * indexSweepline.h header split
 *
 **********************************************************************/

<commit_msg>Removed redundant semicolon reported by g++ -pedantic.<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2005-2006 Refractions Research Inc.
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/operation/valid/SweeplineNestedRingTester.h>
#include <geos/operation/valid/IsValidOp.h>
#include <geos/index/sweepline/SweepLineInterval.h>
#include <geos/index/sweepline/SweepLineIndex.h>
#include <geos/algorithm/CGAlgorithms.h>
#include <geos/geom/LinearRing.h>

#include <cassert>

using namespace geos::algorithm;
using namespace geos::index::sweepline;
using namespace geos::geom;

namespace geos {
namespace operation { // geos.operation
namespace valid { // geos.operation.valid

SweeplineNestedRingTester::OverlapAction::OverlapAction(SweeplineNestedRingTester *p)
{
	isNonNested=true;
	parent=p;
}

void
SweeplineNestedRingTester::OverlapAction::overlap(SweepLineInterval *s0, SweepLineInterval *s1)
{
	LinearRing *innerRing=(LinearRing*) s0->getItem();
	LinearRing *searchRing=(LinearRing*) s1->getItem();
	if (innerRing==searchRing) return;
	if (parent->isInside(innerRing, searchRing))
		isNonNested=false;
}

bool
SweeplineNestedRingTester::isNonNested()
{
	buildIndex();
	OverlapAction *action=new OverlapAction(this);
	sweepLine->computeOverlaps(action);
	return action->isNonNested;
}

void
SweeplineNestedRingTester::buildIndex()
{
	sweepLine=new SweepLineIndex();
	for(unsigned int i=0, n=rings.size(); i<n; i++) {
		LinearRing *ring=rings[i];
		const Envelope *env=ring->getEnvelopeInternal();
		SweepLineInterval *sweepInt=new SweepLineInterval(env->getMinX(),env->getMaxX(),ring);
		sweepLine->add(sweepInt);
	}
}

bool
SweeplineNestedRingTester::isInside(LinearRing *innerRing,LinearRing *searchRing)
{
	CoordinateSequence *innerRingPts=innerRing->getCoordinates();
	CoordinateSequence *searchRingPts=searchRing->getCoordinates();

	if (!innerRing->getEnvelopeInternal()->intersects(searchRing->getEnvelopeInternal()))
		return false;
	const Coordinate *innerRingPt=IsValidOp::findPtNotNode(innerRingPts, searchRing, graph);

	// Unable to find a ring point not a node of the search ring
	assert(innerRingPt!=NULL);

	bool isInside=CGAlgorithms::isPointInRing(*innerRingPt,searchRingPts);
	if (isInside) {
		/*
		 * innerRingPt is const just because the input
		 * CoordinateSequence is const. If the input
		 * Polygon survives lifetime of this object
		 * we are safe.
		 */
		nestedPt=const_cast<Coordinate *>(innerRingPt);
		return true;
	}
	return false;
}

} // namespace geos.operation.valid
} // namespace geos.operation
} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.17  2006/04/09 04:09:43  mloskot
 * Removed redundant semicolon reported by g++ -pedantic.
 *
 * Revision 1.16  2006/03/21 10:01:30  strk
 * indexSweepline.h header split
 *
 **********************************************************************/

<|endoftext|>


<commit_before>#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>

BOOST_AUTO_TEST_CASE(Test){}
<commit_msg>Removing empty, useless test<commit_after>#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>

<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS pchfix02 (1.58.2); FILE MERGED 2006/09/01 17:51:46 kaib 1.58.2.1: #i68856# Added header markers and pch files<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: swlinguconfig.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2007-09-27 11:29:01 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

// #107253#
#ifndef _SWLINGUCONFIG_HXX
#include <swlinguconfig.hxx>
#endif

#ifndef _SVTOOLS_LINGUCFG_HXX_
#include <svtools/lingucfg.hxx>
#endif

using namespace ::com::sun::star;

// init static member
static SvtLinguConfig* mpImplLinguConfig = 0L;
static sal_uInt32 mnImplUseCount = 0L;

void ImplCreateOnDemand()
{
    if(!mpImplLinguConfig && mnImplUseCount)
    {
        mpImplLinguConfig = new SvtLinguConfig();
    }
}

SwLinguConfig::SwLinguConfig()
{
    mnImplUseCount++;
}

SwLinguConfig::~SwLinguConfig()
{
    mnImplUseCount--;

    if(!mnImplUseCount && mpImplLinguConfig)
    {
        delete mpImplLinguConfig;
        mpImplLinguConfig = 0L;
    }
}

sal_Bool SwLinguConfig::SetProperty(const rtl::OUString &rPropertyName, const uno::Any &rValue)
{
    ImplCreateOnDemand();
    return mpImplLinguConfig->SetProperty(rPropertyName, rValue);
}

sal_Bool SwLinguConfig::GetOptions(SvtLinguOptions &rOptions) const
{
    ImplCreateOnDemand();
    return mpImplLinguConfig->GetOptions(rOptions);
}

uno::Any SwLinguConfig::GetProperty(const rtl::OUString &rPropertyName) const
{
    ImplCreateOnDemand();
    return mpImplLinguConfig->GetProperty(rPropertyName);
}

// eof
<commit_msg>INTEGRATION: CWS changefileheader (1.5.242); FILE MERGED 2008/04/01 15:58:27 thb 1.5.242.3: #i85898# Stripping all external header guards 2008/04/01 12:55:04 thb 1.5.242.2: #i85898# Stripping all external header guards 2008/03/31 16:56:41 rt 1.5.242.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: swlinguconfig.cxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

// #107253#
#include <swlinguconfig.hxx>
#include <svtools/lingucfg.hxx>

using namespace ::com::sun::star;

// init static member
static SvtLinguConfig* mpImplLinguConfig = 0L;
static sal_uInt32 mnImplUseCount = 0L;

void ImplCreateOnDemand()
{
    if(!mpImplLinguConfig && mnImplUseCount)
    {
        mpImplLinguConfig = new SvtLinguConfig();
    }
}

SwLinguConfig::SwLinguConfig()
{
    mnImplUseCount++;
}

SwLinguConfig::~SwLinguConfig()
{
    mnImplUseCount--;

    if(!mnImplUseCount && mpImplLinguConfig)
    {
        delete mpImplLinguConfig;
        mpImplLinguConfig = 0L;
    }
}

sal_Bool SwLinguConfig::SetProperty(const rtl::OUString &rPropertyName, const uno::Any &rValue)
{
    ImplCreateOnDemand();
    return mpImplLinguConfig->SetProperty(rPropertyName, rValue);
}

sal_Bool SwLinguConfig::GetOptions(SvtLinguOptions &rOptions) const
{
    ImplCreateOnDemand();
    return mpImplLinguConfig->GetOptions(rOptions);
}

uno::Any SwLinguConfig::GetProperty(const rtl::OUString &rPropertyName) const
{
    ImplCreateOnDemand();
    return mpImplLinguConfig->GetProperty(rPropertyName);
}

// eof
<|endoftext|>