<commit_before>/*
 * collection.hpp
 *
 *  Copyright (c) 2015 Masatoshi Hanai
 *
 *  This software is released under MIT License.
 *  See LICENSE.
 *
 */
#ifndef SCALESIM_COM_MPI_COLLECTION_HPP_
#define SCALESIM_COM_MPI_COLLECTION_HPP_

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include "scalesim/simulation/sim_obj.hpp"
#include "scalesim/util.hpp"

namespace scalesim {

template<class App>
class mpi_collection {
 private:
  mpi_collection(const mpi_collection&);
  void operator=(const mpi_collection&);
 public:
  mpi_collection(): wait_(false){};
  virtual ~mpi_collection(){};
 private:
  const boost::mpi::communicator* com_world_;
  bool wait_;
  bool* wait_barrier_;

  bool* wait_shuffle_ev_; ev_vec<App>* shuffle_ev_buf_;
  ev_vec<App>* shuffle_ev_ret_; parti_ptr shuffle_parti_;

  bool* wait_shuffle_what_if_;
  std::vector<boost::shared_ptr<const what_if<App> > >* shuffle_wi_buf_;
  std::vector<boost::shared_ptr<const what_if<App> > >* shuffle_wi_ret_;

  bool* wait_reduce_; long reduce_buf_; long* reduce_ret_;

 public:
  void init(const boost::mpi::communicator* comm_world) {
    com_world_ = comm_world;
  };

  void check_collection();

  void wait_barrier(bool& wait_barrier);

  void wait_shuffle_event(bool& wait, ev_vec<App>& ret,
                          ev_vec<App>& events, const parti_ptr& parti);

  void wait_shuffle_what_if(bool& wait_shuffle,
                     std::vector<boost::shared_ptr<const what_if<App> > >& ret,
                     std::vector<boost::shared_ptr<const what_if<App> > >& objs,
                     const parti_ptr& parti);

  void wait_reduce_sum(bool& wait_reduce, long& ret, const long val);

 private:
  void shuffle_event();
  void shuffle_what_if();
};

template<class App>
void mpi_collection<App>::check_collection() {
  if (wait_) {
    if (wait_barrier_ && *wait_barrier_) {
      com_world_->barrier();
      *wait_barrier_ = false;
      wait_barrier_ = NULL;
      wait_ = false;
    } else if (wait_shuffle_ev_ && *wait_shuffle_ev_) {
      shuffle_event();
      *wait_shuffle_ev_ = false;
      wait_shuffle_ev_ = NULL;
      wait_ = false;
    } else if (wait_shuffle_what_if_ && *wait_shuffle_what_if_) {
      shuffle_what_if();
      *wait_shuffle_what_if_ = false;
      wait_shuffle_what_if_ = NULL;
      wait_ = false;
    } else if (wait_reduce_ && *wait_reduce_) {
      *reduce_ret_
          = boost::mpi::all_reduce(*com_world_, reduce_buf_, std::plus<long>());
      *wait_reduce_ = false;
      wait_reduce_ = NULL;
      wait_ = false;
    }
  }
}

template<class App>
void mpi_collection<App>::wait_barrier(bool& wait_barrier) {
  wait_ = true;
  wait_barrier = true;
  wait_barrier_ = &wait_barrier;
}

template<class App>
void mpi_collection<App>::wait_shuffle_event(bool& wait_shuffle,
                                             ev_vec<App>& ret,
                                             ev_vec<App>& events,
                                             const parti_ptr& parti) {
  shuffle_ev_buf_ = &events;
  shuffle_ev_ret_ = &ret;
  shuffle_parti_ = parti;
  wait_ = true;
  wait_shuffle = true;
  wait_shuffle_ev_ = &wait_shuffle;
};

template<class App>
void mpi_collection<App>::wait_shuffle_what_if(bool& wait_shuffle,
                     std::vector<boost::shared_ptr<const what_if<App> > >& ret,
                     std::vector<boost::shared_ptr<const what_if<App> > >& objs,
                     const parti_ptr& parti) {
  shuffle_wi_buf_ = &objs;
  shuffle_wi_ret_ = &ret;
  shuffle_parti_ = parti;
  wait_ = true;
  wait_shuffle = true;
  wait_shuffle_what_if_ = &wait_shuffle;
}

template<class App>
void mpi_collection<App>::wait_reduce_sum(bool& wait_reduce,
                                          long& ret, const long val) {
  reduce_buf_ = val;
  reduce_ret_ = &ret;
  wait_ = true;
  wait_reduce = true;
  wait_reduce_ = &wait_reduce;
}

template<class App>
void mpi_collection<App>::shuffle_event() {
  /* calculate  maximum size of buffers */
  std::vector<int> msg_num_to_rank(com_world_->size(), 0);
  for (auto it = shuffle_ev_buf_->begin(); it != shuffle_ev_buf_->end(); ++it) {
    int target_rank = (*shuffle_parti_)[(*it)->destination()];
    ++msg_num_to_rank[target_rank];
  }
  int max_buf_size
      = *std::max_element(msg_num_to_rank.begin(), msg_num_to_rank.end());
  max_buf_size
      = boost::mpi::all_reduce(*com_world_, max_buf_size,
                               boost::mpi::maximum<int>());

  /* make events vectors, where events for rank i are in out_bufs[i] */
  std::vector<event<App> > out_bufs(com_world_->size()*max_buf_size,
                                    event<App>());
  std::vector<int> index(com_world_->size(), 0);
  for (auto it = shuffle_ev_buf_->begin(); it != shuffle_ev_buf_->end(); ++it) {
    int target_rank = (*shuffle_parti_)[(*it)->destination()];
    out_bufs[target_rank*max_buf_size + index[target_rank] ] = **it;
    ++index[target_rank];
  }

  /* shuffle events */
  std::vector<event<App> > in_bufs(com_world_->size()*max_buf_size,
                                   event<App>());
  boost::mpi::all_to_all(*com_world_, out_bufs, max_buf_size, in_bufs);

  /* insert in_bufs to ret */
  for (int rank = 0; rank < com_world_->size(); ++rank) {
    for (int i = 0; i < max_buf_size; ++i) {
      if (in_bufs[rank*max_buf_size + i].id() == -1) break;
      shuffle_ev_ret_->push_back(
          boost::make_shared<event<App> >(event<App>(in_bufs[rank*max_buf_size + i])));
    }
  }
}

template<class App>
void mpi_collection<App>::shuffle_what_if() {
  /* calculate  maximum size of buffers */
  std::vector<int> msg_num_to_rank(com_world_->size(), 0);
  for (auto it = shuffle_wi_buf_->begin(); it != shuffle_wi_buf_->end(); ++it) {
    int target_rank = (*shuffle_parti_)[(*it)->lp_id_];
    ++msg_num_to_rank[target_rank];
  }
  int max_buf_size
      = *std::max_element(msg_num_to_rank.begin(), msg_num_to_rank.end());
  max_buf_size
      = boost::mpi::all_reduce(*com_world_, max_buf_size,
                               boost::mpi::maximum<int>());

  /* make events vectors, where events for rank i are in out_bufs[i] */
  std::vector<what_if<App> > out_bufs(com_world_->size()*max_buf_size,
                                    what_if<App>());
  std::vector<int> index(com_world_->size(), 0);
  for (auto it = shuffle_wi_buf_->begin();it != shuffle_wi_buf_->end(); ++it) {
    int target_rank = (*shuffle_parti_)[(*it)->lp_id_];
    out_bufs[target_rank*max_buf_size + index[target_rank] ] = **it;
    ++index[target_rank];
  }

  /* shuffle events */
  std::vector<what_if<App> > in_bufs(com_world_->size()*max_buf_size,
                                     what_if<App>());
  boost::mpi::all_to_all(*com_world_, out_bufs, max_buf_size, in_bufs);

  /* insert in_bufs to ret */
  for (int rank = 0; rank < com_world_->size(); ++rank) {
    for (int i = 0; i < max_buf_size; ++i) {
      if (in_bufs[rank*max_buf_size + i].lp_id_ == -1) break;
      shuffle_wi_ret_->push_back(
          boost::make_shared<what_if<App> >(what_if<App>(in_bufs[rank + i])));
    }
  }
};

} /* namespace scalesim */

#endif /* SCALESIM_COM_MPI_COLLECTION_HPP_ */
<commit_msg>Fix bug of init pointer<commit_after>/*
 * collection.hpp
 *
 *  Copyright (c) 2015 Masatoshi Hanai
 *
 *  This software is released under MIT License.
 *  See LICENSE.
 *
 */
#ifndef SCALESIM_COM_MPI_COLLECTION_HPP_
#define SCALESIM_COM_MPI_COLLECTION_HPP_

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include "scalesim/simulation/sim_obj.hpp"
#include "scalesim/util.hpp"

namespace scalesim {

template<class App>
class mpi_collection {
 private:
  mpi_collection(const mpi_collection&);
  void operator=(const mpi_collection&);
 public:
  mpi_collection(): wait_(false), wait_barrier_(NULL), wait_shuffle_ev_(NULL),
                    wait_shuffle_what_if_(NULL), wait_reduce_(NULL), reduce_ret_(NULL){};
  virtual ~mpi_collection(){};
 private:
  const boost::mpi::communicator* com_world_;
  bool wait_;
  bool* wait_barrier_;

  bool* wait_shuffle_ev_; ev_vec<App>* shuffle_ev_buf_;
  ev_vec<App>* shuffle_ev_ret_; parti_ptr shuffle_parti_;

  bool* wait_shuffle_what_if_;
  std::vector<boost::shared_ptr<const what_if<App> > >* shuffle_wi_buf_;
  std::vector<boost::shared_ptr<const what_if<App> > >* shuffle_wi_ret_;

  bool* wait_reduce_; long reduce_buf_; long* reduce_ret_;

 public:
  void init(const boost::mpi::communicator* comm_world) {
    com_world_ = comm_world;
  };

  void check_collection();

  void wait_barrier(bool& wait_barrier);

  void wait_shuffle_event(bool& wait, ev_vec<App>& ret,
                          ev_vec<App>& events, const parti_ptr& parti);

  void wait_shuffle_what_if(bool& wait_shuffle,
                     std::vector<boost::shared_ptr<const what_if<App> > >& ret,
                     std::vector<boost::shared_ptr<const what_if<App> > >& objs,
                     const parti_ptr& parti);

  void wait_reduce_sum(bool& wait_reduce, long& ret, const long val);

 private:
  void shuffle_event();
  void shuffle_what_if();
};

template<class App>
void mpi_collection<App>::check_collection() {
  if (wait_) {
    if (wait_barrier_ && *wait_barrier_) {
      com_world_->barrier();
      *wait_barrier_ = false;
      wait_barrier_ = NULL;
      wait_ = false;
    } else if (wait_shuffle_ev_ && *wait_shuffle_ev_) {
      shuffle_event();
      *wait_shuffle_ev_ = false;
      wait_shuffle_ev_ = NULL;
      wait_ = false;
    } else if (wait_shuffle_what_if_ && *wait_shuffle_what_if_) {
      shuffle_what_if();
      *wait_shuffle_what_if_ = false;
      wait_shuffle_what_if_ = NULL;
      wait_ = false;
    } else if (wait_reduce_ && *wait_reduce_) {
      *reduce_ret_
          = boost::mpi::all_reduce(*com_world_, reduce_buf_, std::plus<long>());
      *wait_reduce_ = false;
      wait_reduce_ = NULL;
      wait_ = false;
    }
  }
}

template<class App>
void mpi_collection<App>::wait_barrier(bool& wait_barrier) {
  wait_ = true;
  wait_barrier = true;
  wait_barrier_ = &wait_barrier;
}

template<class App>
void mpi_collection<App>::wait_shuffle_event(bool& wait_shuffle,
                                             ev_vec<App>& ret,
                                             ev_vec<App>& events,
                                             const parti_ptr& parti) {
  shuffle_ev_buf_ = &events;
  shuffle_ev_ret_ = &ret;
  shuffle_parti_ = parti;
  wait_ = true;
  wait_shuffle = true;
  wait_shuffle_ev_ = &wait_shuffle;
};

template<class App>
void mpi_collection<App>::wait_shuffle_what_if(bool& wait_shuffle,
                     std::vector<boost::shared_ptr<const what_if<App> > >& ret,
                     std::vector<boost::shared_ptr<const what_if<App> > >& objs,
                     const parti_ptr& parti) {
  shuffle_wi_buf_ = &objs;
  shuffle_wi_ret_ = &ret;
  shuffle_parti_ = parti;
  wait_ = true;
  wait_shuffle = true;
  wait_shuffle_what_if_ = &wait_shuffle;
}

template<class App>
void mpi_collection<App>::wait_reduce_sum(bool& wait_reduce,
                                          long& ret, const long val) {
  reduce_buf_ = val;
  reduce_ret_ = &ret;
  wait_ = true;
  wait_reduce = true;
  wait_reduce_ = &wait_reduce;
}

template<class App>
void mpi_collection<App>::shuffle_event() {
  /* calculate  maximum size of buffers */
  std::vector<int> msg_num_to_rank(com_world_->size(), 0);
  for (auto it = shuffle_ev_buf_->begin(); it != shuffle_ev_buf_->end(); ++it) {
    int target_rank = (*shuffle_parti_)[(*it)->destination()];
    ++msg_num_to_rank[target_rank];
  }
  int max_buf_size
      = *std::max_element(msg_num_to_rank.begin(), msg_num_to_rank.end());
  max_buf_size
      = boost::mpi::all_reduce(*com_world_, max_buf_size,
                               boost::mpi::maximum<int>());

  /* make events vectors, where events for rank i are in out_bufs[i] */
  std::vector<event<App> > out_bufs(com_world_->size()*max_buf_size,
                                    event<App>());
  std::vector<int> index(com_world_->size(), 0);
  for (auto it = shuffle_ev_buf_->begin(); it != shuffle_ev_buf_->end(); ++it) {
    int target_rank = (*shuffle_parti_)[(*it)->destination()];
    out_bufs[target_rank*max_buf_size + index[target_rank] ] = **it;
    ++index[target_rank];
  }

  /* shuffle events */
  std::vector<event<App> > in_bufs(com_world_->size()*max_buf_size,
                                   event<App>());
  boost::mpi::all_to_all(*com_world_, out_bufs, max_buf_size, in_bufs);

  /* insert in_bufs to ret */
  for (int rank = 0; rank < com_world_->size(); ++rank) {
    for (int i = 0; i < max_buf_size; ++i) {
      if (in_bufs[rank*max_buf_size + i].id() == -1) break;
      shuffle_ev_ret_->push_back(
          boost::make_shared<event<App> >(event<App>(in_bufs[rank*max_buf_size + i])));
    }
  }
}

template<class App>
void mpi_collection<App>::shuffle_what_if() {
  /* calculate  maximum size of buffers */
  std::vector<int> msg_num_to_rank(com_world_->size(), 0);
  for (auto it = shuffle_wi_buf_->begin(); it != shuffle_wi_buf_->end(); ++it) {
    int target_rank = (*shuffle_parti_)[(*it)->lp_id_];
    ++msg_num_to_rank[target_rank];
  }
  int max_buf_size
      = *std::max_element(msg_num_to_rank.begin(), msg_num_to_rank.end());
  max_buf_size
      = boost::mpi::all_reduce(*com_world_, max_buf_size,
                               boost::mpi::maximum<int>());

  /* make events vectors, where events for rank i are in out_bufs[i] */
  std::vector<what_if<App> > out_bufs(com_world_->size()*max_buf_size,
                                    what_if<App>());
  std::vector<int> index(com_world_->size(), 0);
  for (auto it = shuffle_wi_buf_->begin();it != shuffle_wi_buf_->end(); ++it) {
    int target_rank = (*shuffle_parti_)[(*it)->lp_id_];
    out_bufs[target_rank*max_buf_size + index[target_rank] ] = **it;
    ++index[target_rank];
  }

  /* shuffle events */
  std::vector<what_if<App> > in_bufs(com_world_->size()*max_buf_size,
                                     what_if<App>());
  boost::mpi::all_to_all(*com_world_, out_bufs, max_buf_size, in_bufs);

  /* insert in_bufs to ret */
  for (int rank = 0; rank < com_world_->size(); ++rank) {
    for (int i = 0; i < max_buf_size; ++i) {
      if (in_bufs[rank*max_buf_size + i].lp_id_ == -1) break;
      shuffle_wi_ret_->push_back(
          boost::make_shared<what_if<App> >(what_if<App>(in_bufs[rank + i])));
    }
  }
};

} /* namespace scalesim */

#endif /* SCALESIM_COM_MPI_COLLECTION_HPP_ */
<|endoftext|>


<commit_before>//=============================================================================
// ■ resources.cpp
//-----------------------------------------------------------------------------
//   处理资源的加载与释放等。
//=============================================================================

#include "global.hpp"

namespace Res {

	Texture* tex_unit[16];

	Texture::Texture(char* file, GLuint index, GLuint sh) {
		glGenTextures(1, &this->texture);
		glActiveTexture(GL_TEXTURE0 + index);
		glBindTexture(GL_TEXTURE_2D, this->texture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		char* uniform_name = new char[16];
		sprintf(uniform_name, "colortex%d", index);
		log("Texture %s is loaded from %s", uniform_name, file);
		//glUniform1i(glGetUniformLocation(sh, (GLchar*) uniform_name), 0);
		xefree(uniform_name);

		unsigned char* image = SOIL_load_image(file, &width, &height, 0, SOIL_LOAD_RGBA);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
		glGenerateMipmap(GL_TEXTURE_2D);

		SOIL_free_image_data(image);
		glBindTexture(GL_TEXTURE_2D, 0);

		tex_unit[index] = this;
	}
}
<commit_msg>改为NEAREST<commit_after>//=============================================================================
// ■ resources.cpp
//-----------------------------------------------------------------------------
//   处理资源的加载与释放等。
//=============================================================================

#include "global.hpp"

namespace Res {

	Texture* tex_unit[16];

	Texture::Texture(char* file, GLuint index, GLuint sh) {
		glGenTextures(1, &this->texture);
		glActiveTexture(GL_TEXTURE0 + index);
		glBindTexture(GL_TEXTURE_2D, this->texture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

		char* uniform_name = new char[16];
		sprintf(uniform_name, "colortex%d", index);
		log("Texture %s is loaded from %s", uniform_name, file);
		//glUniform1i(glGetUniformLocation(sh, (GLchar*) uniform_name), 0);
		xefree(uniform_name);

		unsigned char* image = SOIL_load_image(file, &width, &height, 0, SOIL_LOAD_RGBA);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
		glGenerateMipmap(GL_TEXTURE_2D);

		SOIL_free_image_data(image);
		glBindTexture(GL_TEXTURE_2D, 0);

		tex_unit[index] = this;
	}
}
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (people-users@projects.maemo.org)
**
** This file is part of contactsd.
**
** If you have questions regarding the use of this file, please contact
** Nokia at people-users@projects.maemo.org.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "test-telepathy-plugin.h"

#include <QMap>
#include <QPair>

#include <QtTracker/Tracker>
#include <QtTracker/ontologies/nco.h>
#include <QtTracker/ontologies/nie.h>
#include <qcontactfilters.h>
#include <qtcontacts.h>

#include <TelepathyQt4/PendingReady>

#include <telepathy-glib/svc-account-manager.h>
#include <telepathy-glib/svc-account.h>

#define ACCOUNT_PATH TP_ACCOUNT_OBJECT_PATH_BASE "fakecm/fakeproto/fakeaccount"
#define BUS_NAME "org.maemo.Contactsd.UnitTest"

TestExpectation::TestExpectation():flags(All),
    presence(TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN)
{
}

void TestExpectation::verify(QContact &contact) const
{
    QCOMPARE(contact.details<QContactOnlineAccount>().count(), 1);
    QCOMPARE(contact.details<QContactPresence>().count(), 1);
    QCOMPARE(contact.detail<QContactOnlineAccount>().accountUri(), accountUri);
    QCOMPARE(contact.detail<QContactOnlineAccount>().value("AccountPath"), QString(ACCOUNT_PATH));

    if (flags & Alias) {
        QString actualAlias = contact.detail<QContactDisplayLabel>().label();
        QCOMPARE(actualAlias, alias);
    }

    if (flags & Presence) {
        QContactPresence::PresenceState actualPresence = contact.detail<QContactPresence>().presenceState();
        switch (presence) {
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_AVAILABLE:
            QCOMPARE(actualPresence, QContactPresence::PresenceAvailable);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_BUSY:
            QCOMPARE(actualPresence, QContactPresence::PresenceBusy);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_AWAY:
            QCOMPARE(actualPresence, QContactPresence::PresenceAway);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_OFFLINE:
            QCOMPARE(actualPresence, QContactPresence::PresenceOffline);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN:
            QCOMPARE(actualPresence, QContactPresence::PresenceUnknown);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_ERROR:
            break;
        }
    }

    if (flags & Avatar) {
        QString avatarFileName = contact.detail<QContactAvatar>().imageUrl().path();
        if (avatarData.isEmpty()) {
            QVERIFY(avatarFileName.isEmpty());
        } else {
            QFile file(avatarFileName);
            QCOMPARE(file.readAll(), avatarData);
        }
    }

    if (flags & Authorization) {
        QContactPresence presence = contact.detail<QContactPresence>();
        QCOMPARE(presence.value("AuthStatusFrom"), subscriptionState);
        QCOMPARE(presence.value("AuthStatusTo"), publishState);
    }
}

TestTelepathyPlugin::TestTelepathyPlugin(QObject *parent) : Test(parent), mContactManager(0)
{
}

void TestTelepathyPlugin::initTestCase()
{
    initTestCaseImpl();

    g_type_init();
    g_set_prgname("test-telepathy-plugin");
    tp_debug_set_flags("all");
    dbus_g_bus_get(DBUS_BUS_STARTER, 0);

    /* Create a QContactManager and track added/changed contacts */
    mContactManager = new QContactManager(QLatin1String("tracker"));
    connect(mContactManager,
            SIGNAL(contactsAdded(const QList<QContactLocalId>&)),
            SLOT(contactsAdded(const QList<QContactLocalId>&)));
    connect(mContactManager,
            SIGNAL(contactsChanged(const QList<QContactLocalId>&)),
            SLOT(contactsChanged(const QList<QContactLocalId>&)));

    /* Create a fake Connection */
    mConnService = TP_BASE_CONNECTION(g_object_new(
            TP_TESTS_TYPE_CONTACTS_CONNECTION,
            "account", "fakeaccount",
            "protocol", "fakeproto",
            NULL));
    QVERIFY(mConnService != 0);
    QVERIFY(tp_base_connection_register(mConnService, "fakecm", NULL, NULL, NULL));
    TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles(
        mConnService, TP_HANDLE_TYPE_CONTACT);
    mConnService->self_handle = tp_handle_ensure(serviceRepo,
        "fakeaccountid", NULL, NULL);
    tp_base_connection_change_status(mConnService,
        TP_CONNECTION_STATUS_CONNECTED,
        TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED);
    mListManager = tp_tests_contacts_connection_get_contact_list_manager(
        TP_TESTS_CONTACTS_CONNECTION(mConnService));

    /* Request the UnitTest bus name, so the AM knows we are ready to go */
    TpDBusDaemon *dbus = tp_dbus_daemon_dup(NULL);
    QVERIFY(tp_dbus_daemon_request_name(dbus, BUS_NAME, FALSE, NULL));
    g_object_unref (dbus);
}

void TestTelepathyPlugin::testBasicUpdates()
{
    /* Create a new contact "alice" */
    TpHandleRepoIface *serviceRepo =
        tp_base_connection_get_handles(mConnService, TP_HANDLE_TYPE_CONTACT);
    TpHandle handle = tp_handle_ensure(serviceRepo, "alice", NULL, NULL);
    QVERIFY(handle != 0);

    /* Set alias to "Alice" */
    const char *alias = "Alice";
    tp_tests_contacts_connection_change_aliases(
        TP_TESTS_CONTACTS_CONNECTION (mConnService),
        1, &handle, &alias);

    /* Add Alice in the ContactList */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "wait", NULL);

    TestExpectation e;
    e.event = TestExpectation::Added;
    e.accountUri = QString("alice");
    e.alias = QString("Alice");
    e.presence = TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN;
    e.subscriptionState = "Requested";
    e.publishState = "No";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    /* Change the presence of Alice to busy */
    TpTestsContactsConnectionPresenceStatusIndex presence =
        TP_TESTS_CONTACTS_CONNECTION_STATUS_BUSY;
    const gchar *message = "Making coffee";
    tp_tests_contacts_connection_change_presences(
        TP_TESTS_CONTACTS_CONNECTION (mConnService),
        1, &handle, &presence, &message);

    e.event = TestExpectation::Changed;
    e.presence = presence;
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

#if 0
    /* Change the avatar of Alice */
    const gchar avatarData[] = "fake-avatar-data";
    const gchar avatarToken[] = "fake-avatar-token";
    const gchar avatarMimeType[] = "fake-avatar-mime-type";
    GArray *array = g_array_new(FALSE, FALSE, sizeof(gchar));
    g_array_append_vals (array, avatarData, strlen(avatarData));
    tp_tests_contacts_connection_change_avatar_data(
        TP_TESTS_CONTACTS_CONNECTION (mConnService),
        handle, array, avatarMimeType, avatarToken);

    e.avatarData = QByteArray(avatarData);
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);
#endif

    qDebug() << "All expectations passed";
}

void TestTelepathyPlugin::testAuthorization()
{
    /* Create a new contact "romeo" */
    TpHandleRepoIface *serviceRepo =
        tp_base_connection_get_handles(mConnService, TP_HANDLE_TYPE_CONTACT);
    TpHandle handle = tp_handle_ensure(serviceRepo, "romeo", NULL, NULL);
    QVERIFY(handle != 0);

    /* Add Bob in the ContactList, the request will be ignored */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "wait", NULL);

    TestExpectation e;
    e.flags = TestExpectation::Authorization;
    e.event = TestExpectation::Added;
    e.accountUri = QString("romeo");
    e.subscriptionState = "Requested";
    e.publishState = "No";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    /* Ask again for subscription, say "please" this time so it gets accepted */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "please", NULL);

    e.event = TestExpectation::Changed;
    e.subscriptionState = "Yes";
    e.publishState = "Requested";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    handle = tp_handle_ensure(serviceRepo, "juliette", NULL, NULL);
    QVERIFY(handle != 0);

    /* Add Bob in the ContactList, the request will be ignored */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "wait", NULL);

    e.event = TestExpectation::Added;
    e.accountUri = QString("juliette");
    e.subscriptionState = "Requested";
    e.publishState = "No";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    /* Ask again for subscription, but this time it will be rejected */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "no", NULL);

    e.event = TestExpectation::Changed;
    e.subscriptionState = "No";
    e.publishState = "No";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);
}

void TestTelepathyPlugin::testSelfContact()
{
    QContactLocalId selfId = mContactManager->selfContactId();
    QContact contact = mContactManager->contact(selfId);
    qDebug() << contact;

    TestExpectation e;
    e.flags = TestExpectation::Presence;
    e.accountUri = QString("fake@account.org");
    e.presence = TP_TESTS_CONTACTS_CONNECTION_STATUS_AVAILABLE;
    e.verify(contact);
}

void TestTelepathyPlugin::testSetOffline()
{
    tp_base_connection_change_status(mConnService,
        TP_CONNECTION_STATUS_DISCONNECTED,
        TP_CONNECTION_STATUS_REASON_REQUESTED);

    TestExpectation e;
    e.flags = TestExpectation::Presence;
    e.event = TestExpectation::Changed;
    e.presence = TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN;
    e.accountUri = QString("romeo");
    mExpectations.append(e);
    e.accountUri = QString("alice");
    mExpectations.append(e);
    e.accountUri = QString("juliette");
    mExpectations.append(e);

    QCOMPARE(mLoop->exec(), 0);
}

void TestTelepathyPlugin::verify(TestExpectation::Event event,
    const QList<QContactLocalId> &contactIds)
{
    Q_FOREACH (QContactLocalId localId, contactIds) {
        QContactLocalId SelfContactId = 0x7FFFFFFF;
        if (localId == SelfContactId)
            continue;

        QContact contact = mContactManager->contact(localId);
        qDebug() << contact;

        if (mExpectations.isEmpty()) {
            mLoop->exit(0);
        }
        QVERIFY(!mExpectations.isEmpty());

        const TestExpectation &e = mExpectations.takeFirst();

        /* If we took the last expectation, quit the mainloop after a short
         * timeout. This is to make sure we don't get extra unwanted signals */
        if (mExpectations.isEmpty()) {
            QTimer::singleShot(500, mLoop, SLOT(quit()));
        }

        QCOMPARE(e.event, event);

        e.verify(contact);
    }
}

void TestTelepathyPlugin::contactsAdded(const QList<QContactLocalId>& contactIds)
{
    qDebug() << "Got contactsAdded";
    verify(TestExpectation::Added, contactIds);
}

void TestTelepathyPlugin::contactsChanged(const QList<QContactLocalId>& contactIds)
{
    qDebug() << "Got contactsChanged";
    verify(TestExpectation::Changed, contactIds);
}

void TestTelepathyPlugin::cleanupTestCase()
{
    tp_base_connection_change_status(mConnService,
        TP_CONNECTION_STATUS_DISCONNECTED,
        TP_CONNECTION_STATUS_REASON_REQUESTED);

    g_object_unref(mConnService);

    delete mContactManager;

    cleanupTestCaseImpl();
}

void TestTelepathyPlugin::init()
{
    initImpl();
}

void TestTelepathyPlugin::cleanup()
{
    cleanupImpl();
}

QTEST_MAIN(TestTelepathyPlugin)
<commit_msg>enable avatar unit test<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (people-users@projects.maemo.org)
**
** This file is part of contactsd.
**
** If you have questions regarding the use of this file, please contact
** Nokia at people-users@projects.maemo.org.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "test-telepathy-plugin.h"

#include <QMap>
#include <QPair>

#include <QtTracker/Tracker>
#include <QtTracker/ontologies/nco.h>
#include <QtTracker/ontologies/nie.h>
#include <qcontactfilters.h>
#include <qtcontacts.h>

#include <TelepathyQt4/PendingReady>

#include <telepathy-glib/svc-account-manager.h>
#include <telepathy-glib/svc-account.h>

#define ACCOUNT_PATH TP_ACCOUNT_OBJECT_PATH_BASE "fakecm/fakeproto/fakeaccount"
#define BUS_NAME "org.maemo.Contactsd.UnitTest"

TestExpectation::TestExpectation():flags(All),
    presence(TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN)
{
}

void TestExpectation::verify(QContact &contact) const
{
    QCOMPARE(contact.details<QContactOnlineAccount>().count(), 1);
    QCOMPARE(contact.details<QContactPresence>().count(), 1);
    QCOMPARE(contact.detail<QContactOnlineAccount>().accountUri(), accountUri);
    QCOMPARE(contact.detail<QContactOnlineAccount>().value("AccountPath"), QString(ACCOUNT_PATH));

    if (flags & Alias) {
        QString actualAlias = contact.detail<QContactDisplayLabel>().label();
        QCOMPARE(actualAlias, alias);
    }

    if (flags & Presence) {
        QContactPresence::PresenceState actualPresence = contact.detail<QContactPresence>().presenceState();
        switch (presence) {
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_AVAILABLE:
            QCOMPARE(actualPresence, QContactPresence::PresenceAvailable);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_BUSY:
            QCOMPARE(actualPresence, QContactPresence::PresenceBusy);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_AWAY:
            QCOMPARE(actualPresence, QContactPresence::PresenceAway);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_OFFLINE:
            QCOMPARE(actualPresence, QContactPresence::PresenceOffline);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN:
            QCOMPARE(actualPresence, QContactPresence::PresenceUnknown);
            break;
        case TP_TESTS_CONTACTS_CONNECTION_STATUS_ERROR:
            break;
        }
    }

    if (flags & Avatar) {
        QString avatarFileName = contact.detail<QContactAvatar>().imageUrl().path();
        if (avatarData.isEmpty()) {
            QVERIFY(avatarFileName.isEmpty());
        } else {
            QFile file(avatarFileName);
            file.open(QIODevice::ReadOnly);
            QCOMPARE(file.readAll(), avatarData);
            file.close();
        }
    }

    if (flags & Authorization) {
        QContactPresence presence = contact.detail<QContactPresence>();
        QCOMPARE(presence.value("AuthStatusFrom"), subscriptionState);
        QCOMPARE(presence.value("AuthStatusTo"), publishState);
    }
}

TestTelepathyPlugin::TestTelepathyPlugin(QObject *parent) : Test(parent), mContactManager(0)
{
}

void TestTelepathyPlugin::initTestCase()
{
    initTestCaseImpl();

    g_type_init();
    g_set_prgname("test-telepathy-plugin");
    tp_debug_set_flags("all");
    dbus_g_bus_get(DBUS_BUS_STARTER, 0);

    /* Create a QContactManager and track added/changed contacts */
    mContactManager = new QContactManager(QLatin1String("tracker"));
    connect(mContactManager,
            SIGNAL(contactsAdded(const QList<QContactLocalId>&)),
            SLOT(contactsAdded(const QList<QContactLocalId>&)));
    connect(mContactManager,
            SIGNAL(contactsChanged(const QList<QContactLocalId>&)),
            SLOT(contactsChanged(const QList<QContactLocalId>&)));

    /* Create a fake Connection */
    mConnService = TP_BASE_CONNECTION(g_object_new(
            TP_TESTS_TYPE_CONTACTS_CONNECTION,
            "account", "fakeaccount",
            "protocol", "fakeproto",
            NULL));
    QVERIFY(mConnService != 0);
    QVERIFY(tp_base_connection_register(mConnService, "fakecm", NULL, NULL, NULL));
    TpHandleRepoIface *serviceRepo = tp_base_connection_get_handles(
        mConnService, TP_HANDLE_TYPE_CONTACT);
    mConnService->self_handle = tp_handle_ensure(serviceRepo,
        "fakeaccountid", NULL, NULL);
    tp_base_connection_change_status(mConnService,
        TP_CONNECTION_STATUS_CONNECTED,
        TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED);
    mListManager = tp_tests_contacts_connection_get_contact_list_manager(
        TP_TESTS_CONTACTS_CONNECTION(mConnService));

    /* Request the UnitTest bus name, so the AM knows we are ready to go */
    TpDBusDaemon *dbus = tp_dbus_daemon_dup(NULL);
    QVERIFY(tp_dbus_daemon_request_name(dbus, BUS_NAME, FALSE, NULL));
    g_object_unref (dbus);
}

void TestTelepathyPlugin::testBasicUpdates()
{
    /* Create a new contact "alice" */
    TpHandleRepoIface *serviceRepo =
        tp_base_connection_get_handles(mConnService, TP_HANDLE_TYPE_CONTACT);
    TpHandle handle = tp_handle_ensure(serviceRepo, "alice", NULL, NULL);
    QVERIFY(handle != 0);

    /* Set alias to "Alice" */
    const char *alias = "Alice";
    tp_tests_contacts_connection_change_aliases(
        TP_TESTS_CONTACTS_CONNECTION (mConnService),
        1, &handle, &alias);

    /* Add Alice in the ContactList */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "wait", NULL);

    TestExpectation e;
    e.event = TestExpectation::Added;
    e.accountUri = QString("alice");
    e.alias = QString("Alice");
    e.presence = TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN;
    e.subscriptionState = "Requested";
    e.publishState = "No";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    /* Change the presence of Alice to busy */
    TpTestsContactsConnectionPresenceStatusIndex presence =
        TP_TESTS_CONTACTS_CONNECTION_STATUS_BUSY;
    const gchar *message = "Making coffee";
    tp_tests_contacts_connection_change_presences(
        TP_TESTS_CONTACTS_CONNECTION (mConnService),
        1, &handle, &presence, &message);

    e.event = TestExpectation::Changed;
    e.presence = presence;
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    /* Change the avatar of Alice */
    const gchar avatarData[] = "fake-avatar-data";
    const gchar avatarToken[] = "fake-avatar-token";
    const gchar avatarMimeType[] = "fake-avatar-mime-type";
    GArray *array = g_array_new(FALSE, FALSE, sizeof(gchar));
    g_array_append_vals (array, avatarData, strlen(avatarData));
    tp_tests_contacts_connection_change_avatar_data(
        TP_TESTS_CONTACTS_CONNECTION (mConnService),
        handle, array, avatarMimeType, avatarToken);

    e.avatarData = QByteArray(avatarData);
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    qDebug() << "All expectations passed";
}

void TestTelepathyPlugin::testAuthorization()
{
    /* Create a new contact "romeo" */
    TpHandleRepoIface *serviceRepo =
        tp_base_connection_get_handles(mConnService, TP_HANDLE_TYPE_CONTACT);
    TpHandle handle = tp_handle_ensure(serviceRepo, "romeo", NULL, NULL);
    QVERIFY(handle != 0);

    /* Add Bob in the ContactList, the request will be ignored */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "wait", NULL);

    TestExpectation e;
    e.flags = TestExpectation::Authorization;
    e.event = TestExpectation::Added;
    e.accountUri = QString("romeo");
    e.subscriptionState = "Requested";
    e.publishState = "No";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    /* Ask again for subscription, say "please" this time so it gets accepted */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "please", NULL);

    e.event = TestExpectation::Changed;
    e.subscriptionState = "Yes";
    e.publishState = "Requested";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    handle = tp_handle_ensure(serviceRepo, "juliette", NULL, NULL);
    QVERIFY(handle != 0);

    /* Add Bob in the ContactList, the request will be ignored */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "wait", NULL);

    e.event = TestExpectation::Added;
    e.accountUri = QString("juliette");
    e.subscriptionState = "Requested";
    e.publishState = "No";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);

    /* Ask again for subscription, but this time it will be rejected */
    test_contact_list_manager_add_to_list(mListManager, NULL,
        TEST_CONTACT_LIST_SUBSCRIBE, handle, "no", NULL);

    e.event = TestExpectation::Changed;
    e.subscriptionState = "No";
    e.publishState = "No";
    mExpectations.append(e);

    /* Wait for the scenario to happen */
    QCOMPARE(mLoop->exec(), 0);
}

void TestTelepathyPlugin::testSelfContact()
{
    QContactLocalId selfId = mContactManager->selfContactId();
    QContact contact = mContactManager->contact(selfId);
    qDebug() << contact;

    TestExpectation e;
    e.flags = TestExpectation::Presence;
    e.accountUri = QString("fake@account.org");
    e.presence = TP_TESTS_CONTACTS_CONNECTION_STATUS_AVAILABLE;
    e.verify(contact);
}

void TestTelepathyPlugin::testSetOffline()
{
    tp_base_connection_change_status(mConnService,
        TP_CONNECTION_STATUS_DISCONNECTED,
        TP_CONNECTION_STATUS_REASON_REQUESTED);

    TestExpectation e;
    e.flags = TestExpectation::Presence;
    e.event = TestExpectation::Changed;
    e.presence = TP_TESTS_CONTACTS_CONNECTION_STATUS_UNKNOWN;
    e.accountUri = QString("romeo");
    mExpectations.append(e);
    e.accountUri = QString("alice");
    mExpectations.append(e);
    e.accountUri = QString("juliette");
    mExpectations.append(e);

    QCOMPARE(mLoop->exec(), 0);
}

void TestTelepathyPlugin::verify(TestExpectation::Event event,
    const QList<QContactLocalId> &contactIds)
{
    Q_FOREACH (QContactLocalId localId, contactIds) {
        QContactLocalId SelfContactId = 0x7FFFFFFF;
        if (localId == SelfContactId)
            continue;

        QContact contact = mContactManager->contact(localId);
        qDebug() << contact;

        if (mExpectations.isEmpty()) {
            mLoop->exit(0);
        }
        QVERIFY(!mExpectations.isEmpty());

        const TestExpectation &e = mExpectations.takeFirst();

        /* If we took the last expectation, quit the mainloop after a short
         * timeout. This is to make sure we don't get extra unwanted signals */
        if (mExpectations.isEmpty()) {
            QTimer::singleShot(500, mLoop, SLOT(quit()));
        }

        QCOMPARE(e.event, event);

        e.verify(contact);
    }
}

void TestTelepathyPlugin::contactsAdded(const QList<QContactLocalId>& contactIds)
{
    qDebug() << "Got contactsAdded";
    verify(TestExpectation::Added, contactIds);
}

void TestTelepathyPlugin::contactsChanged(const QList<QContactLocalId>& contactIds)
{
    qDebug() << "Got contactsChanged";
    verify(TestExpectation::Changed, contactIds);
}

void TestTelepathyPlugin::cleanupTestCase()
{
    tp_base_connection_change_status(mConnService,
        TP_CONNECTION_STATUS_DISCONNECTED,
        TP_CONNECTION_STATUS_REASON_REQUESTED);

    g_object_unref(mConnService);

    delete mContactManager;

    cleanupTestCaseImpl();
}

void TestTelepathyPlugin::init()
{
    initImpl();
}

void TestTelepathyPlugin::cleanup()
{
    cleanupImpl();
}

QTEST_MAIN(TestTelepathyPlugin)
<|endoftext|>


<commit_before>/// @file
/// @brief 任意の何かから value_type を"生成"する make_value さん群

#pragma once

#include "type.hxx"

namespace usagi::json::picojson
{
  /// @brief ECMA-262 Boolean( in ) 互換変換
  static inline auto to_bool( const value_type& in )
  {
    if ( in.is< boolean_type >() )
      return in.get< boolean_type >();

    if ( in.is< number_type >() )
    {
      const auto v = in.get< number_type >();
      // ECMA-262 NaN: Boolean( 0/0 ) -> false
      // ECMA-262 +Inf: Boolean( +1/0 ) -> true
      // ECMA-262 -Inf: Boolean( -1/0 ) -> true
      return not std::isnan( v ) and v != 0;
    }

    if ( in.is< string_type >() )
    {
      const auto& v = in.get< string_type >();
      // ECMA-262 empty-string: Boolean( "" ) -> false
      return not v.empty();
    }

    // ECMA-262 object: Boolean( {} ) -> true
    // ECMA-262 array: Boolean( [] ) -> true
    // ECMA-262 null: Boolean( null ) -> false
    return in.is< array_type >() or in.is< object_type >();
  }

  /// @brief to_bool した結果を value_type で得る syntax sugar
  static inline auto to_bool_value( const value_type& in )
  { return value_type( to_bool( in ) ); }
}<commit_msg>update<commit_after>/// @file
/// @brief 任意の何かから value_type を"生成"する make_value さん群

#pragma once

#include "type.hxx"

namespace usagi::json::picojson
{
  static inline auto to_bool( const boolean_type in ) { return in; }

  /// @note ECMA-262 NaN: Boolean( 0/0 ) -> false
  /// @note ECMA-262 +Inf: Boolean( +1/0 ) -> true
  /// @note ECMA-262 -Inf: Boolean( -1/0 ) -> true
  static inline auto to_bool( const number_type in )
  {
    return not std::isnan( in ) and in != 0;
  }

  /// @note ECMA-262 empty-string: Boolean( "" ) -> false
  static inline auto to_bool( const string_type& in )
  {
    return not in.empty();
  }

  /// @note: ECMA-262 array: Boolean( [] ) -> true
  static inline auto to_bool( const array_type& )
  { return true; }

  /// @note: ECMA-262 object: Boolean( {} ) -> true
  static inline auto to_bool( const object_type& )
  { return true; }

  /// @note: ECMA-262 null: Boolean( null ) -> false
  static inline auto to_bool( const null_type& = null_type() )
  { return false; }

  /// @brief ECMA-262 Boolean( in ) 互換変換
  static inline auto to_bool( const value_type& in )
  {
    if ( in.is< boolean_type >() )
      return to_bool( in.get< boolean_type >() );

    if ( in.is< number_type >() )
      return to_bool( in.get< number_type >() );

    if ( in.is< string_type >() )
      return to_bool( in.get< string_type >() );

    if ( in.is< array_type >() )
      return to_bool( in.get< array_type >() );

    if ( in.is< object_type >() )
      return to_bool( in.get< object_type >() );

    if ( in.is< null_type >() )
      return to_bool();

    return false;
  }

  /// @brief to_bool した結果を value_type で得る syntax sugar
  static inline auto to_bool_value( const value_type& in )
  { return value_type( to_bool( in ) ); }
}<|endoftext|>


<commit_before>//============================================================================
// vSMC/include/vsmc/utility/aligned_memory.hpp
//----------------------------------------------------------------------------
//                         vSMC: Scalable Monte Carlo
//----------------------------------------------------------------------------
// Copyright (c) 2013-2015, Yan Zhou
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
//   Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//============================================================================

#ifndef VSMC_UTILITY_ALIGNED_MEMORY
#define VSMC_UTILITY_ALIGNED_MEMORY

#include <vsmc/internal/config.hpp>
#include <vsmc/internal/assert.hpp>

#include <cstddef>
#include <cstdlib>
#include <memory>
#include <new>
#include <type_traits>
#include <vector>

#if VSMC_HAS_POSIX
#include <stdlib.h>
#elif defined(VSMC_MSVC)
#include <malloc.h>
#endif

#if VSMC_HAS_TBB_MALLOC
#include <tbb/scalable_allocator.h>
#endif

#if VSMC_HAS_MKL
#include <mkl_service.h>
#endif

/// \brief Default AlignedMemory type
/// \ingroup Config
#ifndef VSMC_ALIGNED_MEMORY_TYPE
#if VSMC_HAS_TBB_MALLOC
#define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemoryTBB
#elif VSMC_HAS_MKL
#define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemoryMKL
#elif VSMC_HAS_POSIX || defined(VSMC_MSVC)
#define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemorySYS
#else
#define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemorySTD
#endif
#endif

#define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(Alignment)     \
    VSMC_STATIC_ASSERT(                                                       \
        (Alignment != 0 && (Alignment & (Alignment - 1)) == 0),               \
        "**AlignedAllocator** USED WITH Alignment NOT A POWER OF TWO")

#define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(Alignemnt)      \
    VSMC_STATIC_ASSERT((Alignment >= sizeof(void *)),                         \
        "**AlginedAllocator** USED WITH Alignment LESS THAN sizeof(void *)")

#define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY                             \
    VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(Alignment);        \
    VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(Alignment);

#define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(alignment)    \
    VSMC_RUNTIME_ASSERT(                                                      \
        (alignment != 0 && (alignment & (alignment - 1)) == 0),               \
        "**aligned_malloc** USED WITH ALIGNMENT NOT A POWER OF TWO")

#define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(alignemnt)     \
    VSMC_RUNTIME_ASSERT((alignment >= sizeof(void *)),                        \
        "**aligned_malloc** USED WITH ALIGNMENT LESS THAN sizeof(void *)")

#define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY                            \
    VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(alignment);       \
    VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(alignment);

namespace vsmc
{

/// \brief Aligned memory using `std::malloc` and `std::free`
/// \ingroup AlignedMemory
///
/// \details
/// Memory allocated through this class is aligned but some bytes might be
/// wasted in each allocation.
class AlignedMemorySTD
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *orig_ptr = std::malloc(n + alignment + sizeof(void *));
        if (orig_ptr == nullptr)
            throw std::bad_alloc();

        uintptr_t address = reinterpret_cast<uintptr_t>(orig_ptr);
        uintptr_t offset = alignment - (address + sizeof(void *)) % alignment;
        void *ptr =
            reinterpret_cast<void *>(address + offset + sizeof(void *));
        void **orig = reinterpret_cast<void **>(address + offset);
        *orig = orig_ptr;

        return ptr;
    }

    static void aligned_free(void *ptr)
    {
        std::free(*reinterpret_cast<void **>(
                      reinterpret_cast<uintptr_t>(ptr) - sizeof(void *)));
    }
}; // class AlignedMemmorySTD

#if VSMC_HAS_POSIX

/// \brief Aligned memory using native system aligned memory allocation
/// \ingroup AlignedMemory
///
/// \details
/// This class use `posix_memalign` and `free` on POSIX systems (Mac OS X,
/// Linux, etc.) and `_aligned_malloc` and `_aligned_free` on Windows.
class AlignedMemorySYS
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *ptr;
        if (posix_memalign(&ptr, alignment, n) != 0)
            throw std::bad_alloc();

        return ptr;
    }

    static void aligned_free(void *ptr) { free(ptr); }
}; // class AlignedMallocSYS

#elif defined(VSMC_MSVC)

class AlignedMemorySYS
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *ptr = _aligned_malloc(n, alignment);
        if (ptr == nullptr)
            throw std::bad_alloc();

        return ptr;
    }

    static void aligned_free(void *ptr) { _aligned_free(ptr); }
}; // class AlignedMemorySYS

#endif // VSMC_HAS_POSIX

#if VSMC_HAS_TBB_MALLOC

/// \brief Aligned memory using Intel TBB `scalable_aligned_malloc` and
/// `scalable_aligned_free`.
/// \ingroup AlignedMemory
class AlignedMemoryTBB
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *ptr = scalable_aligned_malloc(n, alignment);
        if (ptr == nullptr)
            throw std::bad_alloc();

        return ptr;
    }

    static void aligned_free(void *ptr) { scalable_aligned_free(ptr); }
}; // class AlignedMemoryTBB

#endif // VSMC_HAS_TBB_MALLOC

#if VSMC_HAS_MKL

/// \brief Aligned memory using Intel MKL `mkl_malloc` and `mkl_free`
/// \ingroup AlignedMemory
class AlignedMemoryMKL
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *ptr = mkl_malloc(n, static_cast<int>(alignment));
        if (ptr == nullptr)
            throw std::bad_alloc();

        return ptr;
    }

    static void aligned_free(void *ptr) { mkl_free(ptr); }
}; // class AlignedMemoryMKL

#endif // VSMC_HAS_MKL

/// \brief Default AlignedMemory type
/// \ingroup AlignedMemory
typedef VSMC_ALIGNED_MEMORY_TYPE AlignedMemory;

/// \brief Aligned allocator
/// \ingroup AlignedMemory
///
/// \tparam T The value type
/// \tparam Alignment The alignment requirement of memory, must be a power of
/// two and no less than `sizeof(void *)`.
/// \tparam Memory The memory management class. Must provides two member
/// functions, `aligned_malloc` and `aligned_free`. The member function
/// `aligned_malloc` shall behave similar to `std::malloc` but take an
/// additional arguments for alignment. The member function `aligned_free`
/// shall behave just like `std::free`.
template <typename T, std::size_t Alignment = 32,
    typename Memory = AlignedMemory>
class AlignedAllocator : public std::allocator<T>
{
    public:
    typedef typename std::allocator<T>::size_type size_type;
    typedef typename std::allocator<T>::pointer pointer;

    template <typename U>
    class rebind
    {
        public:
        typedef AlignedAllocator<U, Alignment> other;
    }; // class rebind

    AlignedAllocator() { VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY; }

    AlignedAllocator(const AlignedAllocator<T, Alignment, Memory> &other)
        : std::allocator<T>(other)
    {
        VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY;
    }

    template <typename U>
    AlignedAllocator(const AlignedAllocator<U, Alignment, Memory> &other)
        : std::allocator<T>(static_cast<std::allocator<U>>(other))
    {
        VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY;
    }

    AlignedAllocator<T, Alignment, Memory> &operator=(
        const AlignedAllocator<T, Alignment, Memory> &) = default;

    AlignedAllocator(AlignedAllocator<T, Alignment, Memory> &&other)
        : std::allocator<T>(std::move(other))
    {
        VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY;
    }

    template <typename U>
    AlignedAllocator(AlignedAllocator<U, Alignment, Memory> &&other)
        : std::allocator<T>(static_cast<std::allocator<U>>(std::move(other)))
    {
        VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY;
    }

    AlignedAllocator<T, Alignment, Memory> &operator=(
        AlignedAllocator<T, Alignment, Memory> &&) = default;

    ~AlignedAllocator() {}

    pointer allocate(size_type n, const void * = nullptr)
    {
        if (n == 0)
            return nullptr;

        return static_cast<pointer>(
            memory_.aligned_malloc(sizeof(T) * n, Alignment));
    }

    void deallocate(pointer ptr, size_type)
    {
        if (ptr != nullptr)
            memory_.aligned_free(ptr);
    }

    private:
    Memory memory_;
}; // class AlignedAllocator

/// \brief AlignedAllocator for scalar type and `std::allocator` for others
/// \ingroup AlignedMemory
template <typename T>
using Allocator = typename std::conditional<std::is_scalar<T>::value,
    AlignedAllocator<T>, std::allocator<T>>::type;

/// \brief Vector type using AlignedAllocator
/// \ingroup AlignedMemory
template <typename T>
using AlignedVector = std::vector<T, AlignedAllocator<T>>;

/// \brief AlignedVector for scalar type and `std::vector` for others
/// \ingroup AlignedMemory
template <typename T>
using Vector = typename std::conditional<std::is_scalar<T>::value,
    std::vector<T, AlignedAllocator<T>>, std::vector<T>>::type;

} // namespace vsmc

#endif // VSMC_UTILITY_ALIGNED_MEMORY
<commit_msg>default alignment configurable<commit_after>//============================================================================
// vSMC/include/vsmc/utility/aligned_memory.hpp
//----------------------------------------------------------------------------
//                         vSMC: Scalable Monte Carlo
//----------------------------------------------------------------------------
// Copyright (c) 2013-2015, Yan Zhou
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
//
//   Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//============================================================================

#ifndef VSMC_UTILITY_ALIGNED_MEMORY
#define VSMC_UTILITY_ALIGNED_MEMORY

#include <vsmc/internal/config.hpp>
#include <vsmc/internal/assert.hpp>

#include <cstddef>
#include <cstdlib>
#include <memory>
#include <new>
#include <type_traits>
#include <vector>

#if VSMC_HAS_POSIX
#include <stdlib.h>
#elif defined(VSMC_MSVC)
#include <malloc.h>
#endif

#if VSMC_HAS_TBB_MALLOC
#include <tbb/scalable_allocator.h>
#endif

#if VSMC_HAS_MKL
#include <mkl_service.h>
#endif

/// \brief Default AlignedMemory type
/// \ingroup Config
#ifndef VSMC_ALIGNED_MEMORY_TYPE
#if VSMC_HAS_TBB_MALLOC
#define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemoryTBB
#elif VSMC_HAS_MKL
#define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemoryMKL
#elif VSMC_HAS_POSIX || defined(VSMC_MSVC)
#define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemorySYS
#else
#define VSMC_ALIGNED_MEMORY_TYPE ::vsmc::AlignedMemorySTD
#endif
#endif

/// \brief Defualt alignment
/// \ingroup Config
#ifndef VSMC_ALIGNMENT
#define VSMC_ALIGNMENT 32
#endif

#define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(Alignment)     \
    VSMC_STATIC_ASSERT(                                                       \
        (Alignment != 0 && (Alignment & (Alignment - 1)) == 0),               \
        "**AlignedAllocator** USED WITH Alignment NOT A POWER OF TWO")

#define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(Alignemnt)      \
    VSMC_STATIC_ASSERT((Alignment >= sizeof(void *)),                         \
        "**AlginedAllocator** USED WITH Alignment LESS THAN sizeof(void *)")

#define VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY                             \
    VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(Alignment);        \
    VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(Alignment);

#define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(alignment)    \
    VSMC_RUNTIME_ASSERT(                                                      \
        (alignment != 0 && (alignment & (alignment - 1)) == 0),               \
        "**aligned_malloc** USED WITH ALIGNMENT NOT A POWER OF TWO")

#define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(alignemnt)     \
    VSMC_RUNTIME_ASSERT((alignment >= sizeof(void *)),                        \
        "**aligned_malloc** USED WITH ALIGNMENT LESS THAN sizeof(void *)")

#define VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY                            \
    VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_POWER_OF_TWO(alignment);       \
    VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY_SIZEOF_VOID(alignment);

namespace vsmc
{

/// \brief Aligned memory using `std::malloc` and `std::free`
/// \ingroup AlignedMemory
///
/// \details
/// Memory allocated through this class is aligned but some bytes might be
/// wasted in each allocation.
class AlignedMemorySTD
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *orig_ptr = std::malloc(n + alignment + sizeof(void *));
        if (orig_ptr == nullptr)
            throw std::bad_alloc();

        uintptr_t address = reinterpret_cast<uintptr_t>(orig_ptr);
        uintptr_t offset = alignment - (address + sizeof(void *)) % alignment;
        void *ptr =
            reinterpret_cast<void *>(address + offset + sizeof(void *));
        void **orig = reinterpret_cast<void **>(address + offset);
        *orig = orig_ptr;

        return ptr;
    }

    static void aligned_free(void *ptr)
    {
        std::free(*reinterpret_cast<void **>(
                      reinterpret_cast<uintptr_t>(ptr) - sizeof(void *)));
    }
}; // class AlignedMemmorySTD

#if VSMC_HAS_POSIX

/// \brief Aligned memory using native system aligned memory allocation
/// \ingroup AlignedMemory
///
/// \details
/// This class use `posix_memalign` and `free` on POSIX systems (Mac OS X,
/// Linux, etc.) and `_aligned_malloc` and `_aligned_free` on Windows.
class AlignedMemorySYS
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *ptr;
        if (posix_memalign(&ptr, alignment, n) != 0)
            throw std::bad_alloc();

        return ptr;
    }

    static void aligned_free(void *ptr) { free(ptr); }
}; // class AlignedMallocSYS

#elif defined(VSMC_MSVC)

class AlignedMemorySYS
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *ptr = _aligned_malloc(n, alignment);
        if (ptr == nullptr)
            throw std::bad_alloc();

        return ptr;
    }

    static void aligned_free(void *ptr) { _aligned_free(ptr); }
}; // class AlignedMemorySYS

#endif // VSMC_HAS_POSIX

#if VSMC_HAS_TBB_MALLOC

/// \brief Aligned memory using Intel TBB `scalable_aligned_malloc` and
/// `scalable_aligned_free`.
/// \ingroup AlignedMemory
class AlignedMemoryTBB
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *ptr = scalable_aligned_malloc(n, alignment);
        if (ptr == nullptr)
            throw std::bad_alloc();

        return ptr;
    }

    static void aligned_free(void *ptr) { scalable_aligned_free(ptr); }
}; // class AlignedMemoryTBB

#endif // VSMC_HAS_TBB_MALLOC

#if VSMC_HAS_MKL

/// \brief Aligned memory using Intel MKL `mkl_malloc` and `mkl_free`
/// \ingroup AlignedMemory
class AlignedMemoryMKL
{
    public:
    static void *aligned_malloc(std::size_t n, std::size_t alignment)
    {
        VSMC_RUNTIME_ASSERT_UTILITY_ALIGNED_MEMORY;

        if (n == 0)
            return nullptr;

        void *ptr = mkl_malloc(n, static_cast<int>(alignment));
        if (ptr == nullptr)
            throw std::bad_alloc();

        return ptr;
    }

    static void aligned_free(void *ptr) { mkl_free(ptr); }
}; // class AlignedMemoryMKL

#endif // VSMC_HAS_MKL

/// \brief Default AlignedMemory type
/// \ingroup AlignedMemory
typedef VSMC_ALIGNED_MEMORY_TYPE AlignedMemory;

/// \brief Aligned allocator
/// \ingroup AlignedMemory
///
/// \tparam T The value type
/// \tparam Alignment The alignment requirement of memory, must be a power of
/// two and no less than `sizeof(void *)`.
/// \tparam Memory The memory management class. Must provides two member
/// functions, `aligned_malloc` and `aligned_free`. The member function
/// `aligned_malloc` shall behave similar to `std::malloc` but take an
/// additional arguments for alignment. The member function `aligned_free`
/// shall behave just like `std::free`.
template <typename T, std::size_t Alignment = VSMC_ALIGNMENT,
    typename Memory = AlignedMemory>
class AlignedAllocator : public std::allocator<T>
{
    public:
    typedef typename std::allocator<T>::size_type size_type;
    typedef typename std::allocator<T>::pointer pointer;

    template <typename U>
    class rebind
    {
        public:
        typedef AlignedAllocator<U, Alignment> other;
    }; // class rebind

    AlignedAllocator() { VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY; }

    AlignedAllocator(const AlignedAllocator<T, Alignment, Memory> &other)
        : std::allocator<T>(other)
    {
        VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY;
    }

    template <typename U>
    AlignedAllocator(const AlignedAllocator<U, Alignment, Memory> &other)
        : std::allocator<T>(static_cast<std::allocator<U>>(other))
    {
        VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY;
    }

    AlignedAllocator<T, Alignment, Memory> &operator=(
        const AlignedAllocator<T, Alignment, Memory> &) = default;

    AlignedAllocator(AlignedAllocator<T, Alignment, Memory> &&other)
        : std::allocator<T>(std::move(other))
    {
        VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY;
    }

    template <typename U>
    AlignedAllocator(AlignedAllocator<U, Alignment, Memory> &&other)
        : std::allocator<T>(static_cast<std::allocator<U>>(std::move(other)))
    {
        VSMC_STATIC_ASSERT_UTILITY_ALIGNED_MEMORY;
    }

    AlignedAllocator<T, Alignment, Memory> &operator=(
        AlignedAllocator<T, Alignment, Memory> &&) = default;

    ~AlignedAllocator() {}

    pointer allocate(size_type n, const void * = nullptr)
    {
        if (n == 0)
            return nullptr;

        return static_cast<pointer>(
            memory_.aligned_malloc(sizeof(T) * n, Alignment));
    }

    void deallocate(pointer ptr, size_type)
    {
        if (ptr != nullptr)
            memory_.aligned_free(ptr);
    }

    private:
    Memory memory_;
}; // class AlignedAllocator

/// \brief AlignedAllocator for scalar type and `std::allocator` for others
/// \ingroup AlignedMemory
template <typename T>
using Allocator = typename std::conditional<std::is_scalar<T>::value,
    AlignedAllocator<T>, std::allocator<T>>::type;

/// \brief Vector type using AlignedAllocator
/// \ingroup AlignedMemory
template <typename T>
using AlignedVector = std::vector<T, AlignedAllocator<T>>;

/// \brief AlignedVector for scalar type and `std::vector` for others
/// \ingroup AlignedMemory
template <typename T>
using Vector = typename std::conditional<std::is_scalar<T>::value,
    std::vector<T, AlignedAllocator<T>>, std::vector<T>>::type;

} // namespace vsmc

#endif // VSMC_UTILITY_ALIGNED_MEMORY
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief A error listener reacting to mismatches of the grammar defined in `YAML.g4`
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

// -- Imports ------------------------------------------------------------------

#include <iostream>

#include "error_listener.hpp"

// -- Class --------------------------------------------------------------------

/**
 * @brief This constructor creates a new error listener using the given arguments.
 *
 * @param errorSource This text stores an identifier, usually the filename, that identifies the source of an error.
 */
ErrorListener::ErrorListener (string const & errorSource)
{
	source = errorSource;
}

/**
 * @brief This method will be called if the parsing process fails.
 *
 * @param recognizer This parameter stores the current recognizer used to
 *                   parse the input.
 * @param offendingSymbol This token caused the failure of the parsing
 *                        process.
 * @param line This number specifies the line where the parsing process
 *             failed.
 * @param charPositionInLine This number specifies the character position in
 *                           `line`, where the parsing process failed.
 * @param message This text describes the parsing failure.
 * @param error This parameter stores the exception caused by the parsing
 *              failure.
 */
void ErrorListener::syntaxError (Recognizer * recognizer __attribute__ ((unused)), Token * offendingSymbol __attribute__ ((unused)),
				 size_t line, size_t charPositionInLine, const std::string & message,
				 std::exception_ptr error __attribute__ ((unused)))
{
	using std::to_string;
	errorMessage += "\n" + source + ":" + to_string (line) + ":" + to_string (charPositionInLine) + ": " + message;
}

/**
 * @brief This method returns the last error message saved by the error listener.
 *
 * @return A string containing an error message produced by the parser
 */
char const * ErrorListener::message ()
{
	return errorMessage.c_str ();
}
<commit_msg>Yan LR: Include erroneous input in error message<commit_after>/**
 * @file
 *
 * @brief A error listener reacting to mismatches of the grammar defined in `YAML.g4`
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

// -- Imports ------------------------------------------------------------------

#include <iostream>

#include "error_listener.hpp"

using std::to_string;

using antlr4::CommonTokenStream;

// -- Functions ----------------------------------------------------------------

namespace
{
/**
 * @brief This function returns a Clang-like error message for a given error.
 *
 * @param recognizer This parameter stores the current recognizer used to
 *                   parse the input.
 * @param offendingSymbol This token caused the failure of the parsing
 *                        process.
 * @param line This number specifies the line where the parsing process
 *             failed.
 * @param charPositionInLine This number specifies the character position in
 *                           `line`, where the parsing process failed.
 * @param prefix This variable stores as prefix that this function prepends
 *               to every line of the visualized error message.
 */
string visualizeError (Recognizer * recognizer, Token * offendingSymbol, size_t const line, size_t const charPositionInLine,
		       string const & prefix)
{
	CommonTokenStream * tokens = dynamic_cast<CommonTokenStream *> (recognizer->getInputStream ());
	string input = tokens->getTokenSource ()->getInputStream ()->toString ();

	string::size_type start = 0;
	string::size_type end = 0;
	for (size_t currentLine = 1; currentLine <= line; currentLine++)
	{
		size_t offset = (end == 0 ? 0 : 1);
		start = end + offset;
		end = input.find ("\n", end + offset);
	}

	string errorLine = input.substr (start, end - start);

	errorLine = prefix + errorLine + "\n" + prefix + string (charPositionInLine - 1, ' ');
	start = offendingSymbol->getStartIndex ();
	end = offendingSymbol->getStopIndex ();
	for (size_t current = start; current <= end; current++)
	{
		errorLine += "^";
	}

	return errorLine;
}
}

// -- Class --------------------------------------------------------------------

/**
 * @brief This constructor creates a new error listener using the given arguments.
 *
 * @param errorSource This text stores an identifier, usually the filename, that identifies the source of an error.
 */
ErrorListener::ErrorListener (string const & errorSource)
{
	source = errorSource;
}

/**
 * @brief This method will be called if the parsing process fails.
 *
 * @param recognizer This parameter stores the current recognizer used to
 *                   parse the input.
 * @param offendingSymbol This token caused the failure of the parsing
 *                        process.
 * @param line This number specifies the line where the parsing process
 *             failed.
 * @param charPositionInLine This number specifies the character position in
 *                           `line`, where the parsing process failed.
 * @param message This text describes the parsing failure.
 * @param error This parameter stores the exception caused by the parsing
 *              failure.
 */
void ErrorListener::syntaxError (Recognizer * recognizer, Token * offendingSymbol, size_t line, size_t charPositionInLine,
				 const std::string & message, std::exception_ptr error __attribute__ ((unused)))
{
	auto location = source + ":" + to_string (line) + ":" + to_string (charPositionInLine) + ": ";
	auto indent = string (location.length (), ' ');
	errorMessage += "\n" + location + message + "\n";
	errorMessage += visualizeError (recognizer, offendingSymbol, line, charPositionInLine, indent);
}

/**
 * @brief This method returns the last error message saved by the error listener.
 *
 * @return A string containing an error message produced by the parser
 */
char const * ErrorListener::message ()
{
	return errorMessage.c_str ();
}
<|endoftext|>