<commit_before>#include <unistd.h>

#include <process.hpp>

#include <iostream>
#include <climits>
#include <cstdlib>
#include <stdexcept>

#include <glog/logging.h>

#include <boost/lexical_cast.hpp>

#include "fatal.hpp"
#include "master_detector.hpp"
#include "messages.hpp"

using namespace nexus;
using namespace nexus::internal;

using boost::lexical_cast;

MasterDetector::MasterDetector(const string &_servers, const string &_znode,
			       const PID &_pid, bool _contend)
  : servers(_servers), znode(_znode), pid(_pid), contend(_contend)
{
  zk = new ZooKeeper(servers, 10000, this);
}

MasterDetector::~MasterDetector()
{
  if (zk != NULL)
    delete zk;
}

void MasterDetector::process(ZooKeeper *zk, int type, int state,
			     const string &path)
{
  int ret;
  string result;

  static const string delimiter = "/";

  if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_SESSION_EVENT)) {
    // Create directory path znodes as necessary.
    size_t index = znode.find(delimiter, 0);
    while (index < string::npos) {
      index = znode.find(delimiter, index+1);
      string prefix = znode.substr(0, index);
      ret = zk->create(prefix, "", ZOO_OPEN_ACL_UNSAFE, // ZOO_CREATOR_ALL_ACL, // needs authentication
		       0, &result);
      if (ret != ZOK && ret != ZNODEEXISTS)
	fatal("failed to create ZooKeeper znode! (%s)", zk->error(ret));
    }

    // Wierdness in ZooKeeper timing, let's check that everything is created.
    ret = zk->get(znode, false, &result, NULL);

    if (ret != ZOK)
      fatal("ZooKeeper not responding correctly (%s). "
	    "Make sure ZooKeeper is running on: %s",
	    zk->error(ret), servers.c_str());

    if (contend) {
      // We use the contend with the pid given in constructor.
      ret = zk->create(znode, pid, ZOO_CREATOR_ALL_ACL,
		       ZOO_SEQUENCE | ZOO_EPHEMERAL, &result);

      if (ret != ZOK)
	fatal("ZooKeeper not responding correctly (%s). "
	      "Make sure ZooKeeper is running on: %s",
	      zk->error(ret), servers.c_str());

      setMySeq(result);
      LOG(INFO) << "Created ephemeral/sequence:" << getMySeq();

      const string &s =
	Tuple<Process>::tupleToString(Tuple<Process>::pack<GOT_MASTER_SEQ>(getMySeq()));
      Process::post(pid, GOT_MASTER_SEQ, s.data(), s.size());
    }

    detectMaster();
  } else if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_CHILD_EVENT)) {
    detectMaster();
  } else {
    LOG(INFO) << "Unimplemented watch event: (state is "
	      << state << " and type is " << type << ")";
  }
}

void MasterDetector::detectMaster()
{
  vector<string> results;

  int ret = zk->getChildren(znode, true, &results);

  if (ret != ZOK)
    LOG(ERROR) << "failed to get masters: " << zk->error(ret);
  else
    LOG(INFO) << "found " << results.size() << " registered masters";

  string masterSeq;
  long min = LONG_MAX;
  foreach (const string &result, results) {
    int i = lexical_cast<int>(result);
    if (i < min) {
      min = i;
      masterSeq = result;
    }
  }

  // No master present (lost or possibly hasn't come up yet).
  if (masterSeq.empty()) {
    const string &s =
      Tuple<Process>::tupleToString(Tuple<Process>::pack<NO_MASTER_DETECTED>());
    Process::post(pid, NO_MASTER_DETECTED, s.data(), s.size());
  } else if (masterSeq != currentMasterSeq) {
    currentMasterSeq = masterSeq;
    currentMasterPID = lookupMasterPID(masterSeq);

    // While trying to get the master PID, master might have crashed,
    // so PID might be empty.
    if (currentMasterPID == PID()) {
      const string &s =
	Tuple<Process>::tupleToString(Tuple<Process>::pack<NO_MASTER_DETECTED>());
      Process::post(pid, NO_MASTER_DETECTED, s.data(), s.size());
    } else {
      const string &s =
	Tuple<Process>::tupleToString(Tuple<Process>::pack<NEW_MASTER_DETECTED>(currentMasterSeq, currentMasterPID));
      Process::post(pid, NEW_MASTER_DETECTED, s.data(), s.size());
    }
  }
}

PID MasterDetector::lookupMasterPID(const string &seq) const
{
  CHECK(!seq.empty());

  int ret;
  string result;

  ret = zk->get(znode + seq, false, &result, NULL);

  if (ret != ZOK)
    LOG(ERROR) << "failed to fetch new master pid: " << zk->error(ret);
  else
    LOG(INFO) << "got new master pid: " << result;

  // TODO(benh): Automatic cast!
  return make_pid(result.c_str());
}

string MasterDetector::getCurrentMasterSeq() const {
  return currentMasterSeq;
}

PID MasterDetector::getCurrentMasterPID() const {
  return currentMasterPID;
}
<commit_msg>Another ACL changed to make our ZooKeeper implementation work (we don't do authentication yet, maybe Twitter has other code that does that?<commit_after>#include <unistd.h>

#include <process.hpp>

#include <iostream>
#include <climits>
#include <cstdlib>
#include <stdexcept>

#include <glog/logging.h>

#include <boost/lexical_cast.hpp>

#include "fatal.hpp"
#include "master_detector.hpp"
#include "messages.hpp"

using namespace nexus;
using namespace nexus::internal;

using boost::lexical_cast;

MasterDetector::MasterDetector(const string &_servers, const string &_znode,
			       const PID &_pid, bool _contend)
  : servers(_servers), znode(_znode), pid(_pid), contend(_contend)
{
  zk = new ZooKeeper(servers, 10000, this);
}

MasterDetector::~MasterDetector()
{
  if (zk != NULL)
    delete zk;
}

void MasterDetector::process(ZooKeeper *zk, int type, int state,
			     const string &path)
{
  int ret;
  string result;

  static const string delimiter = "/";

  if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_SESSION_EVENT)) {
    // Create directory path znodes as necessary.
    size_t index = znode.find(delimiter, 0);
    while (index < string::npos) {
      index = znode.find(delimiter, index+1);
      string prefix = znode.substr(0, index);
      ret = zk->create(prefix, "", ZOO_OPEN_ACL_UNSAFE, // ZOO_CREATOR_ALL_ACL, // needs authentication
		       0, &result);
      if (ret != ZOK && ret != ZNODEEXISTS)
	fatal("failed to create ZooKeeper znode! (%s)", zk->error(ret));
    }

    // Wierdness in ZooKeeper timing, let's check that everything is created.
    ret = zk->get(znode, false, &result, NULL);

    if (ret != ZOK)
      fatal("ZooKeeper not responding correctly (%s). "
	    "Make sure ZooKeeper is running on: %s",
	    zk->error(ret), servers.c_str());

    if (contend) {
      // We use the contend with the pid given in constructor.
      ret = zk->create(znode, pid, ZOO_OPEN_ACL_UNSAFE, // ZOO_CREATOR_ALL_ACL, // needs authentication
		       ZOO_SEQUENCE | ZOO_EPHEMERAL, &result);

      if (ret != ZOK)
	fatal("ZooKeeper not responding correctly (%s). "
	      "Make sure ZooKeeper is running on: %s",
	      zk->error(ret), servers.c_str());

      setMySeq(result);
      LOG(INFO) << "Created ephemeral/sequence:" << getMySeq();

      const string &s =
	Tuple<Process>::tupleToString(Tuple<Process>::pack<GOT_MASTER_SEQ>(getMySeq()));
      Process::post(pid, GOT_MASTER_SEQ, s.data(), s.size());
    }

    detectMaster();
  } else if ((state == ZOO_CONNECTED_STATE) && (type == ZOO_CHILD_EVENT)) {
    detectMaster();
  } else {
    LOG(INFO) << "Unimplemented watch event: (state is "
	      << state << " and type is " << type << ")";
  }
}

void MasterDetector::detectMaster()
{
  vector<string> results;

  int ret = zk->getChildren(znode, true, &results);

  if (ret != ZOK)
    LOG(ERROR) << "failed to get masters: " << zk->error(ret);
  else
    LOG(INFO) << "found " << results.size() << " registered masters";

  string masterSeq;
  long min = LONG_MAX;
  foreach (const string &result, results) {
    int i = lexical_cast<int>(result);
    if (i < min) {
      min = i;
      masterSeq = result;
    }
  }

  // No master present (lost or possibly hasn't come up yet).
  if (masterSeq.empty()) {
    const string &s =
      Tuple<Process>::tupleToString(Tuple<Process>::pack<NO_MASTER_DETECTED>());
    Process::post(pid, NO_MASTER_DETECTED, s.data(), s.size());
  } else if (masterSeq != currentMasterSeq) {
    currentMasterSeq = masterSeq;
    currentMasterPID = lookupMasterPID(masterSeq);

    // While trying to get the master PID, master might have crashed,
    // so PID might be empty.
    if (currentMasterPID == PID()) {
      const string &s =
	Tuple<Process>::tupleToString(Tuple<Process>::pack<NO_MASTER_DETECTED>());
      Process::post(pid, NO_MASTER_DETECTED, s.data(), s.size());
    } else {
      const string &s =
	Tuple<Process>::tupleToString(Tuple<Process>::pack<NEW_MASTER_DETECTED>(currentMasterSeq, currentMasterPID));
      Process::post(pid, NEW_MASTER_DETECTED, s.data(), s.size());
    }
  }
}

PID MasterDetector::lookupMasterPID(const string &seq) const
{
  CHECK(!seq.empty());

  int ret;
  string result;

  ret = zk->get(znode + seq, false, &result, NULL);

  if (ret != ZOK)
    LOG(ERROR) << "failed to fetch new master pid: " << zk->error(ret);
  else
    LOG(INFO) << "got new master pid: " << result;

  // TODO(benh): Automatic cast!
  return make_pid(result.c_str());
}

string MasterDetector::getCurrentMasterSeq() const {
  return currentMasterSeq;
}

PID MasterDetector::getCurrentMasterPID() const {
  return currentMasterPID;
}
<|endoftext|>


<commit_before><commit_msg>Roxie -selftest coring<commit_after><|endoftext|>


<commit_before><commit_msg>Fixed random() issues on Windows.<commit_after><|endoftext|>


<commit_before><commit_msg>Allow XUnknown in comparisons.<commit_after><|endoftext|>


<commit_before><commit_msg>Changed to server.write<commit_after><|endoftext|>


<commit_before><commit_msg>learn how to create heap by initialize using new keyword and delete heap using delete<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * 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;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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
 * OWNER 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.
 *
 * Authors: Andreas Hansson
 */

#include "base/chunk_generator.hh"
#include "mem/port_proxy.hh"

void
PortProxy::blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd) const
{
    Request req;

    for (ChunkGenerator gen(addr, size, _port.peerBlockSize());
         !gen.done(); gen.next()) {
        req.setPhys(gen.addr(), gen.size(), 0, Request::funcMasterId);
        Packet pkt(&req, cmd);
		if (addr > 1073741824 && addr < 2.0*1073741824 ) pkt.threadID = 1;
		else if (addr > 2.0*1073741824 && addr < 3.0*1073741824 ) pkt.threadID = 2;
		else if (addr > 3.0*1073741824 && addr < 4000000000.0 ) pkt.threadID = 3;
		else pkt.threadID = 0;
        pkt.dataStatic(p);
        _port.sendFunctional(&pkt);
        p += gen.size();
    }
}

void
PortProxy::memsetBlob(Addr addr, uint8_t v, int size) const
{
    // quick and dirty...
    uint8_t *buf = new uint8_t[size];

    std::memset(buf, v, size);
    blobHelper(addr, buf, size, MemCmd::WriteReq);

    delete [] buf;
}
<commit_msg>stop using default constructor<commit_after>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * 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;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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
 * OWNER 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.
 *
 * Authors: Andreas Hansson
 */

#include "base/chunk_generator.hh"
#include "mem/port_proxy.hh"

void
PortProxy::blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd) const
{
    Request req;

    for (ChunkGenerator gen(addr, size, _port.peerBlockSize());
         !gen.done(); gen.next()) {
        req.setPhys(gen.addr(), gen.size(), 0, Request::funcMasterId);
        Packet pkt(&req, cmd, 0, 0, 0);
		if (addr > 1073741824 && addr < 2.0*1073741824 ) pkt.threadID = 1;
		else if (addr > 2.0*1073741824 && addr < 3.0*1073741824 ) pkt.threadID = 2;
		else if (addr > 3.0*1073741824 && addr < 4000000000.0 ) pkt.threadID = 3;
		else pkt.threadID = 0;
        pkt.dataStatic(p);
        _port.sendFunctional(&pkt);
        p += gen.size();
    }
}

void
PortProxy::memsetBlob(Addr addr, uint8_t v, int size) const
{
    // quick and dirty...
    uint8_t *buf = new uint8_t[size];

    std::memset(buf, v, size);
    blobHelper(addr, buf, size, MemCmd::WriteReq);

    delete [] buf;
}
<|endoftext|>


<commit_before>/**
 * @file profile.cpp
 * @author Sean Massung
 */

#include <iostream>
#include <vector>
#include <unordered_set>
#include <string>
#include "cpptoml.h"
#include "util/shim.h"
#include "util/filesystem.h"
#include "analyzers/analyzer.h"
#include "analyzers/tokenizers/icu_tokenizer.h"
#include "analyzers/filters/all.h"
#include "analyzers/ngram/ngram_word_analyzer.h"
#include "corpus/document.h"
#include "sequence/crf/crf.h"
#include "sequence/crf/tagger.h"
#include "sequence/io/ptb_parser.h"
#include "sequence/sequence.h"

using namespace meta;

/**
 * Prints help for this executable.
 * @param prog The name of the current executable
 * @return the exit code for this program
 */
int print_usage(const std::string& prog)
{
    std::cerr << std::endl;
    std::cerr << "Usage: " << prog << " config.toml file.txt [OPTION]"
              << std::endl;
    std::cerr << "where [OPTION] is one or more of:" << std::endl;
    std::cerr << "\t--stem\tperform stemming on each word" << std::endl;
    std::cerr << "\t--stop\tremove stopwords" << std::endl;
    std::cerr << "\t--pos\tannotate words with POS tags" << std::endl;
    std::cerr << "\t--pos-replace\treplace words with their POS tags"
              << std::endl;
    std::cerr << "\t--freq-unigram\tsort and count unigram words" << std::endl;
    std::cerr << "\t--freq-bigram\tsort and count bigram words" << std::endl;
    std::cerr << "\t--freq-trigram\tsort and count trigram words" << std::endl;
    std::cerr << "\t--all\trun all options" << std::endl;
    std::cerr << std::endl;
    return 1;
}

/**
 * @param file The filename to modify
 * @return the base filename without an extension
 */
std::string no_ext(const std::string& file)
{
    auto idx = file.find_last_of('.');
    return file.substr(0, idx);
}

/**
 * @param stream Token stream to read from
 * @param in_name Input filename
 * @param out_name Output filename
 */
template <class Stream>
void write_file(Stream& stream, const std::string& in_name,
                const std::string& out_name)
{
    std::ofstream outfile{out_name};
    stream->set_content(filesystem::file_text(in_name));
    while (*stream)
    {
        auto next = stream->next();
        if (next == "<s>" || next == " ")
            continue;
        else if (next == "</s>")
            outfile << std::endl;
        else
            outfile << next << " ";
    }
}

/**
 * Performs stemming on a text file.
 * @param file The input file
 * @param config Configuration settings
 */
void stem(const std::string& file, const cpptoml::toml_group& config)
{
    std::cout << "Running stemming algorithm" << std::endl;

    using namespace meta::analyzers;
    std::unique_ptr<token_stream> stream
        = make_unique<tokenizers::icu_tokenizer>();
    stream = make_unique<filters::lowercase_filter>(std::move(stream));
    stream = make_unique<filters::porter2_stemmer>(std::move(stream));
    stream = make_unique<filters::empty_sentence_filter>(std::move(stream));

    auto out_name = no_ext(file) + ".stems.txt";
    write_file(stream, file, out_name);
    std::cout << " -> file saved as " << out_name << std::endl;
}

/**
 * Performs stopword removal on a text file.
 * @param file The input file
 * @param config Configuration settings
 */
void stop(const std::string& file, const cpptoml::toml_group& config)
{
    std::cout << "Running stopword removal" << std::endl;

    using namespace meta::analyzers;
    auto stopwords = config.get_as<std::string>("stop-words");
    std::unique_ptr<token_stream> stream
        = make_unique<tokenizers::icu_tokenizer>();
    stream = make_unique<filters::lowercase_filter>(std::move(stream));
    stream = make_unique<filters::list_filter>(std::move(stream), *stopwords);
    stream = make_unique<filters::empty_sentence_filter>(std::move(stream));

    auto out_name = no_ext(file) + ".stops.txt";
    write_file(stream, file, out_name);
    std::cout << " -> file saved as " << out_name << std::endl;
}

/**
 * Performs part-of-speech tagging on a text file.
 * @param file The input file
 * @param config Configuration settings
 * @param replace Whether or not to replace words with their POS tags
 */
void pos(const std::string& file, const cpptoml::toml_group& config,
         bool replace)
{
    std::cout << "Running POS-tagging with replace = " << std::boolalpha
              << replace << std::endl;

    using namespace meta::sequence;

    // load POS-tagging model
    auto crf_group = config.get_group("crf");
    auto prefix = crf_group->get_as<std::string>("prefix");
    crf crf_model{*prefix};
    const sequence_analyzer analyzer = default_pos_analyzer(*prefix);
    auto tagger = crf_model.make_tagger();

    // read file into a sequence
    std::unique_ptr<analyzers::token_stream> stream
        = make_unique<analyzers::tokenizers::icu_tokenizer>();
    stream->set_content(filesystem::file_text(file));
    meta::sequence::sequence seq;
    while (*stream)
    {
        auto token = stream->next();
        if (token == " ")
            continue;
        seq.add_observation({symbol_t{token}, tag_t{"[UNK]"}});
    }

    // annotate sequence with POS tags
    analyzer.analyze(seq);
    tagger.tag(seq);

    // write output to file
    auto out_name = no_ext(file)
                    + (replace ? ".pos-replace.txt" : ".pos-tagged.txt");
    std::ofstream outfile{out_name};
    for (auto& obs : seq)
    {
        if (obs.symbol() == symbol_t{"<s>"})
            continue;
        if (obs.symbol() == symbol_t{"</s>"})
        {
            outfile << std::endl;
            continue;
        }
        if (replace)
            outfile << analyzer.tag(obs.label()) << " ";
        else
            outfile << obs.symbol() << "_" << analyzer.tag(obs.label()) << " ";
    }

    std::cout << " -> file saved as " << out_name << std::endl;
}

/**
 * Performs frequency analysis on a text file.
 * @param file The input file
 * @param config Configuration settings
 * @param n The n-gram value to use in tokenization
 */
void freq(const std::string& file, const cpptoml::toml_group& config,
          uint16_t n)
{
    std::cout << "Running frequency analysis on " << n << "-grams" << std::endl;

    std::unique_ptr<analyzers::token_stream> stream
        = make_unique<analyzers::tokenizers::icu_tokenizer>();
    analyzers::ngram_word_analyzer ana{n, std::move(stream)};

    corpus::document doc;
    doc.content(filesystem::file_text(file));
    ana.tokenize(doc);

    using pair_t = std::pair<std::string, double>;
    std::vector<pair_t> sorted(doc.counts().begin(), doc.counts().end());
    std::sort(sorted.begin(), sorted.end(), [](const pair_t& a, const pair_t& b)
              {
        return a.second > b.second;
    });

    auto out_name = no_ext(file) + ".freq." + std::to_string(n) + ".txt";
    std::ofstream outfile{out_name};
    for (auto& token : sorted)
        outfile << token.first << " " << token.second << std::endl;

    std::cout << " -> file saved as " << out_name << std::endl;
}

int main(int argc, char* argv[])
{
    if (argc < 4)
        return print_usage(argv[0]);

    auto config = cpptoml::parse_file(argv[1]);
    std::string file = argv[2];
    std::unordered_set<std::string> args{argv + 3, argv + argc};
    bool all = args.find("--all") != args.end();

    if (all || args.find("--stem") != args.end())
        stem(file, config);
    if (all || args.find("--stop") != args.end())
        stop(file, config);
    if (all || args.find("--pos") != args.end())
        pos(file, config, false);
    if (all || args.find("--pos-replace") != args.end())
        pos(file, config, true);
    if (all || args.find("--freq-unigram") != args.end())
        freq(file, config, 1);
    if (all || args.find("--freq-bigram") != args.end())
        freq(file, config, 2);
    if (all || args.find("--freq-trigram") != args.end())
        freq(file, config, 3);
}
<commit_msg>Update profile to latest cpptoml library.<commit_after>/**
 * @file profile.cpp
 * @author Sean Massung
 */

#include <iostream>
#include <vector>
#include <unordered_set>
#include <string>
#include "cpptoml.h"
#include "util/shim.h"
#include "util/filesystem.h"
#include "analyzers/analyzer.h"
#include "analyzers/tokenizers/icu_tokenizer.h"
#include "analyzers/filters/all.h"
#include "analyzers/ngram/ngram_word_analyzer.h"
#include "corpus/document.h"
#include "sequence/crf/crf.h"
#include "sequence/crf/tagger.h"
#include "sequence/io/ptb_parser.h"
#include "sequence/sequence.h"

using namespace meta;

/**
 * Prints help for this executable.
 * @param prog The name of the current executable
 * @return the exit code for this program
 */
int print_usage(const std::string& prog)
{
    std::cerr << std::endl;
    std::cerr << "Usage: " << prog << " config.toml file.txt [OPTION]"
              << std::endl;
    std::cerr << "where [OPTION] is one or more of:" << std::endl;
    std::cerr << "\t--stem\tperform stemming on each word" << std::endl;
    std::cerr << "\t--stop\tremove stopwords" << std::endl;
    std::cerr << "\t--pos\tannotate words with POS tags" << std::endl;
    std::cerr << "\t--pos-replace\treplace words with their POS tags"
              << std::endl;
    std::cerr << "\t--freq-unigram\tsort and count unigram words" << std::endl;
    std::cerr << "\t--freq-bigram\tsort and count bigram words" << std::endl;
    std::cerr << "\t--freq-trigram\tsort and count trigram words" << std::endl;
    std::cerr << "\t--all\trun all options" << std::endl;
    std::cerr << std::endl;
    return 1;
}

/**
 * @param file The filename to modify
 * @return the base filename without an extension
 */
std::string no_ext(const std::string& file)
{
    auto idx = file.find_last_of('.');
    return file.substr(0, idx);
}

/**
 * @param stream Token stream to read from
 * @param in_name Input filename
 * @param out_name Output filename
 */
template <class Stream>
void write_file(Stream& stream, const std::string& in_name,
                const std::string& out_name)
{
    std::ofstream outfile{out_name};
    stream->set_content(filesystem::file_text(in_name));
    while (*stream)
    {
        auto next = stream->next();
        if (next == "<s>" || next == " ")
            continue;
        else if (next == "</s>")
            outfile << std::endl;
        else
            outfile << next << " ";
    }
}

/**
 * Performs stemming on a text file.
 * @param file The input file
 * @param config Configuration settings
 */
void stem(const std::string& file, const cpptoml::table&)
{
    std::cout << "Running stemming algorithm" << std::endl;

    using namespace meta::analyzers;
    std::unique_ptr<token_stream> stream
        = make_unique<tokenizers::icu_tokenizer>();
    stream = make_unique<filters::lowercase_filter>(std::move(stream));
    stream = make_unique<filters::porter2_stemmer>(std::move(stream));
    stream = make_unique<filters::empty_sentence_filter>(std::move(stream));

    auto out_name = no_ext(file) + ".stems.txt";
    write_file(stream, file, out_name);
    std::cout << " -> file saved as " << out_name << std::endl;
}

/**
 * Performs stopword removal on a text file.
 * @param file The input file
 * @param config Configuration settings
 */
void stop(const std::string& file, const cpptoml::table& config)
{
    std::cout << "Running stopword removal" << std::endl;

    using namespace meta::analyzers;
    auto stopwords = config.get_as<std::string>("stop-words");
    std::unique_ptr<token_stream> stream
        = make_unique<tokenizers::icu_tokenizer>();
    stream = make_unique<filters::lowercase_filter>(std::move(stream));
    stream = make_unique<filters::list_filter>(std::move(stream), *stopwords);
    stream = make_unique<filters::empty_sentence_filter>(std::move(stream));

    auto out_name = no_ext(file) + ".stops.txt";
    write_file(stream, file, out_name);
    std::cout << " -> file saved as " << out_name << std::endl;
}

/**
 * Performs part-of-speech tagging on a text file.
 * @param file The input file
 * @param config Configuration settings
 * @param replace Whether or not to replace words with their POS tags
 */
void pos(const std::string& file, const cpptoml::table& config,
         bool replace)
{
    std::cout << "Running POS-tagging with replace = " << std::boolalpha
              << replace << std::endl;

    using namespace meta::sequence;

    // load POS-tagging model
    auto crf_group = config.get_table("crf");
    auto prefix = crf_group->get_as<std::string>("prefix");
    crf crf_model{*prefix};
    const sequence_analyzer analyzer = default_pos_analyzer();
    auto tagger = crf_model.make_tagger();

    // read file into a sequence
    std::unique_ptr<analyzers::token_stream> stream
        = make_unique<analyzers::tokenizers::icu_tokenizer>();
    stream->set_content(filesystem::file_text(file));
    meta::sequence::sequence seq;
    while (*stream)
    {
        auto token = stream->next();
        if (token == " ")
            continue;
        seq.add_observation({symbol_t{token}, tag_t{"[UNK]"}});
    }

    // annotate sequence with POS tags
    analyzer.analyze(seq);
    tagger.tag(seq);

    // write output to file
    auto out_name = no_ext(file)
                    + (replace ? ".pos-replace.txt" : ".pos-tagged.txt");
    std::ofstream outfile{out_name};
    for (auto& obs : seq)
    {
        if (obs.symbol() == symbol_t{"<s>"})
            continue;
        if (obs.symbol() == symbol_t{"</s>"})
        {
            outfile << std::endl;
            continue;
        }
        if (replace)
            outfile << analyzer.tag(obs.label()) << " ";
        else
            outfile << obs.symbol() << "_" << analyzer.tag(obs.label()) << " ";
    }

    std::cout << " -> file saved as " << out_name << std::endl;
}

/**
 * Performs frequency analysis on a text file.
 * @param file The input file
 * @param config Configuration settings
 * @param n The n-gram value to use in tokenization
 */
void freq(const std::string& file, const cpptoml::table&,
          uint16_t n)
{
    std::cout << "Running frequency analysis on " << n << "-grams" << std::endl;

    std::unique_ptr<analyzers::token_stream> stream
        = make_unique<analyzers::tokenizers::icu_tokenizer>();
    analyzers::ngram_word_analyzer ana{n, std::move(stream)};

    corpus::document doc;
    doc.content(filesystem::file_text(file));
    ana.tokenize(doc);

    using pair_t = std::pair<std::string, double>;
    std::vector<pair_t> sorted(doc.counts().begin(), doc.counts().end());
    std::sort(sorted.begin(), sorted.end(), [](const pair_t& a, const pair_t& b)
              {
        return a.second > b.second;
    });

    auto out_name = no_ext(file) + ".freq." + std::to_string(n) + ".txt";
    std::ofstream outfile{out_name};
    for (auto& token : sorted)
        outfile << token.first << " " << token.second << std::endl;

    std::cout << " -> file saved as " << out_name << std::endl;
}

int main(int argc, char* argv[])
{
    if (argc < 4)
        return print_usage(argv[0]);

    auto config = cpptoml::parse_file(argv[1]);
    std::string file = argv[2];
    std::unordered_set<std::string> args{argv + 3, argv + argc};
    bool all = args.find("--all") != args.end();

    if (all || args.find("--stem") != args.end())
        stem(file, config);
    if (all || args.find("--stop") != args.end())
        stop(file, config);
    if (all || args.find("--pos") != args.end())
        pos(file, config, false);
    if (all || args.find("--pos-replace") != args.end())
        pos(file, config, true);
    if (all || args.find("--freq-unigram") != args.end())
        freq(file, config, 1);
    if (all || args.find("--freq-bigram") != args.end())
        freq(file, config, 2);
    if (all || args.find("--freq-trigram") != args.end())
        freq(file, config, 3);
}
<|endoftext|>


<commit_before><commit_msg>Fix wrong wallet balance after spend<commit_after><|endoftext|>


<commit_before>//
// Copyright (c) 2015-2016 CNRS
// Copyright (c) 2015 Wandercraft, 86 rue de Paris 91400 Orsay, France.
//
// This file is part of Pinocchio
// Pinocchio is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// Pinocchio is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// Pinocchio If not, see
// <http://www.gnu.org/licenses/>.

#ifndef __se3_model_hpp__
#define __se3_model_hpp__

#include "pinocchio/spatial/fwd.hpp"
#include "pinocchio/spatial/se3.hpp"
#include "pinocchio/spatial/force.hpp"
#include "pinocchio/spatial/motion.hpp"
#include "pinocchio/spatial/inertia.hpp"
#include "pinocchio/multibody/joint/joint-variant.hpp"
#include <iostream>

EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(se3::SE3)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(se3::Inertia)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(se3::Force)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(se3::Motion)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Matrix<double,6,Eigen::Dynamic>)

namespace se3
{
  class Model;
  class Data;

  class Model
  {
  public:
    typedef std::size_t Index;

    int nq;                               // Dimension of the configuration representation
    int nv;                               // Dimension of the velocity vector space
    int nbody;                            // Number of bodies (= number of joints + 1)
    int nFixBody;                         // Number of fixed-bodies (= number of fixed-joints)

    std::vector<Inertia> inertias;        // Spatial inertias of the body  in the supporting joint frame
    std::vector<SE3> jointPlacements;     // Placement (SE3) of the input of joint  in parent joint output

    JointModelVector joints;              // Model of joint
    std::vector<Index> parents;           // Joint parent of joint , denoted
 (li==parents[i])
    std::vector<std::string> names;       // Name of joint
    std::vector<std::string> bodyNames;   // Name of the body attached to the output of joint
    std::vector<bool> hasVisual;          // True iff body  has a visual mesh.

    std::vector<SE3> fix_lmpMi;           // Fixed-body relative placement (wrt last moving parent)
    std::vector<Model::Index> fix_lastMovingParent; // Fixed-body index of the last moving parent
    std::vector<bool> fix_hasVisual;      // True iff fixed-body  has a visual mesh.
    std::vector<std::string> fix_bodyNames;// Name of fixed-joint

    Motion gravity;                       // Spatial gravity
    static const Eigen::Vector3d gravity981; // Default 3D gravity (=(0,0,-9.81))

    Model()
      : nq(0)
      , nv(0)
      , nbody(1)
      , nFixBody(0)
      , inertias(1)
      , jointPlacements(1)
      , joints(1)
      , parents(1)
      , names(1)
      , bodyNames(1)
      , hasVisual(1)
      , gravity( gravity981,Eigen::Vector3d::Zero() )
    {
      names[0]     = "universe";     // Should be "universe joint (trivial)"
      bodyNames[0] = "universe";
    }
    ~Model() {} // std::cout << "Destroy model" << std::endl; }
    template<typename D>
    Index addBody(  Index parent,const JointModelBase<D> & j,const SE3 & placement,
		                const Inertia & Y,
                    const std::string & jointName = "", const std::string & bodyName = "",
                    bool visual = false);
    template<typename D>
    Index addBody(  Index parent,const JointModelBase<D> & j,const SE3 & placement,
                    const Inertia & Y,
                    const Eigen::VectorXd & effort, const Eigen::VectorXd & velocity,
                    const Eigen::VectorXd & lowPos, const Eigen::VectorXd & upPos,
                    const std::string & jointName = "", const std::string & bodyName = "",
                    bool visual = false);
    Index addFixedBody( Index fix_lastMovingParent,
                        const SE3 & placementFromLastMoving,
                        const std::string &jointName = "",
                        bool visual=false);
    void mergeFixedBody(Index parent, const SE3 & placement, const Inertia & Y);
    Index getBodyId( const std::string & name ) const;
    bool existBodyName( const std::string & name ) const;
    const std::string& getBodyName( Index index ) const;
    Index getJointId( const std::string & name ) const;
    bool existJointName( const std::string & name ) const;
    const std::string& getJointName( Index index ) const;
  };

  class Data
  {
  public:
    typedef Eigen::Matrix<double,6,Eigen::Dynamic> Matrix6x;
    typedef Eigen::Matrix<double,3,Eigen::Dynamic> Matrix3x;

  public:
    const Model& model;
    JointDataVector joints;
    std::vector<Motion> a;                // Body acceleration
    std::vector<Motion> v;                // Body velocity
    std::vector<Force> f;                 // Body force
    std::vector<SE3> oMi;                 // Body absolute placement (wrt world)
    std::vector<SE3> liMi;                // Body relative placement (wrt parent)
    Eigen::VectorXd tau;                  // Joint forces
    Eigen::VectorXd nle;                  // Non linear effects

    std::vector<Inertia> Ycrb;            // Inertia of the sub-tree composit rigid body
    Eigen::MatrixXd M;                    // Joint Inertia

    std::vector<Matrix6x> Fcrb;           // Spatial forces set, used in CRBA

    std::vector<int> lastChild;  // Index of the last child (for CRBA)
    std::vector<int> nvSubtree;           // Dimension of the subtree motion space (for CRBA)

    Eigen::MatrixXd U;                    // Joint Inertia square root (upper triangle)
    Eigen::VectorXd D;                    // Diagonal of UDUT inertia decomposition
    Eigen::VectorXd tmp;                  // Temporary of size NV used in Cholesky
    std::vector<int> parents_fromRow;     // First previous non-zero row in M (used in Cholesky)
    std::vector<int> nvSubtree_fromRow;   //

    Matrix6x J;                    // Jacobian of joint placement
    std::vector<SE3> iMf;                 // Body placement wrt to algorithm end effector.

    std::vector<Eigen::Vector3d> com;     // Subtree com position.
    std::vector<Eigen::Vector3d> vcom;    // Subtree com velocity.
    std::vector<Eigen::Vector3d> acom;    // Subtree com acceleration.
    std::vector<double> mass;             // Subtree total mass.
    Matrix3x Jcom; // Jacobian of center of mass.

    Eigen::VectorXd effortLimit;          // Joint max effort
    Eigen::VectorXd velocityLimit;        // Joint max velocity

    Eigen::VectorXd lowerPositionLimit;   // limit for joint lower position
    Eigen::VectorXd upperPositionLimit;   // limit for joint upper position

    double kinetic_energy; // kinetic energy of the model
    double potential_energy; // potential energy of the model

    Data( const Model& ref );

  private:
    void computeLastChild(const Model& model);
    void computeParents_fromRow(const Model& model);

  };

} // namespace se3

/* --- Details -------------------------------------------------------------- */
/* --- Details -------------------------------------------------------------- */
/* --- Details -------------------------------------------------------------- */
#include "pinocchio/multibody/model.hxx"

#endif // ifndef __se3_model_hpp__
<commit_msg>[C++] Add typedef and std::vector specialization in data struct<commit_after>//
// Copyright (c) 2015-2016 CNRS
// Copyright (c) 2015 Wandercraft, 86 rue de Paris 91400 Orsay, France.
//
// This file is part of Pinocchio
// Pinocchio is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// Pinocchio is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// Pinocchio If not, see
// <http://www.gnu.org/licenses/>.

#ifndef __se3_model_hpp__
#define __se3_model_hpp__

#include "pinocchio/spatial/fwd.hpp"
#include "pinocchio/spatial/se3.hpp"
#include "pinocchio/spatial/force.hpp"
#include "pinocchio/spatial/motion.hpp"
#include "pinocchio/spatial/inertia.hpp"
#include "pinocchio/multibody/joint/joint-variant.hpp"
#include <iostream>

EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(se3::SE3)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(se3::Inertia)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(se3::Force)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(se3::Motion)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Matrix<double,6,Eigen::Dynamic>)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(se3::SE3::Vector3)

namespace se3
{
  class Model;
  class Data;

  class Model
  {
  public:
    typedef std::size_t Index;

    int nq;                               // Dimension of the configuration representation
    int nv;                               // Dimension of the velocity vector space
    int nbody;                            // Number of bodies (= number of joints + 1)
    int nFixBody;                         // Number of fixed-bodies (= number of fixed-joints)

    std::vector<Inertia> inertias;        // Spatial inertias of the body  in the supporting joint frame
    std::vector<SE3> jointPlacements;     // Placement (SE3) of the input of joint  in parent joint output

    JointModelVector joints;              // Model of joint
    std::vector<Index> parents;           // Joint parent of joint , denoted
 (li==parents[i])
    std::vector<std::string> names;       // Name of joint
    std::vector<std::string> bodyNames;   // Name of the body attached to the output of joint
    std::vector<bool> hasVisual;          // True iff body  has a visual mesh.

    std::vector<SE3> fix_lmpMi;           // Fixed-body relative placement (wrt last moving parent)
    std::vector<Model::Index> fix_lastMovingParent; // Fixed-body index of the last moving parent
    std::vector<bool> fix_hasVisual;      // True iff fixed-body  has a visual mesh.
    std::vector<std::string> fix_bodyNames;// Name of fixed-joint

    Motion gravity;                       // Spatial gravity
    static const Eigen::Vector3d gravity981; // Default 3D gravity (=(0,0,-9.81))

    Model()
      : nq(0)
      , nv(0)
      , nbody(1)
      , nFixBody(0)
      , inertias(1)
      , jointPlacements(1)
      , joints(1)
      , parents(1)
      , names(1)
      , bodyNames(1)
      , hasVisual(1)
      , gravity( gravity981,Eigen::Vector3d::Zero() )
    {
      names[0]     = "universe";     // Should be "universe joint (trivial)"
      bodyNames[0] = "universe";
    }
    ~Model() {} // std::cout << "Destroy model" << std::endl; }
    template<typename D>
    Index addBody(  Index parent,const JointModelBase<D> & j,const SE3 & placement,
		                const Inertia & Y,
                    const std::string & jointName = "", const std::string & bodyName = "",
                    bool visual = false);
    template<typename D>
    Index addBody(  Index parent,const JointModelBase<D> & j,const SE3 & placement,
                    const Inertia & Y,
                    const Eigen::VectorXd & effort, const Eigen::VectorXd & velocity,
                    const Eigen::VectorXd & lowPos, const Eigen::VectorXd & upPos,
                    const std::string & jointName = "", const std::string & bodyName = "",
                    bool visual = false);
    Index addFixedBody( Index fix_lastMovingParent,
                        const SE3 & placementFromLastMoving,
                        const std::string &jointName = "",
                        bool visual=false);
    void mergeFixedBody(Index parent, const SE3 & placement, const Inertia & Y);
    Index getBodyId( const std::string & name ) const;
    bool existBodyName( const std::string & name ) const;
    const std::string& getBodyName( Index index ) const;
    Index getJointId( const std::string & name ) const;
    bool existJointName( const std::string & name ) const;
    const std::string& getJointName( Index index ) const;
  };

  class Data
  {
  public:
    typedef Eigen::Matrix<double,6,Eigen::Dynamic> Matrix6x;
    typedef Eigen::Matrix<double,3,Eigen::Dynamic> Matrix3x;
    typedef SE3::Vector3 Vector3;

  public:
    const Model& model;
    JointDataVector joints;
    std::vector<Motion> a;                // Body acceleration
    std::vector<Motion> v;                // Body velocity
    std::vector<Force> f;                 // Body force
    std::vector<SE3> oMi;                 // Body absolute placement (wrt world)
    std::vector<SE3> liMi;                // Body relative placement (wrt parent)
    Eigen::VectorXd tau;                  // Joint forces
    Eigen::VectorXd nle;                  // Non linear effects

    std::vector<Inertia> Ycrb;            // Inertia of the sub-tree composit rigid body
    Eigen::MatrixXd M;                    // Joint Inertia

    std::vector<Matrix6x> Fcrb;           // Spatial forces set, used in CRBA

    std::vector<int> lastChild;  // Index of the last child (for CRBA)
    std::vector<int> nvSubtree;           // Dimension of the subtree motion space (for CRBA)

    Eigen::MatrixXd U;                    // Joint Inertia square root (upper triangle)
    Eigen::VectorXd D;                    // Diagonal of UDUT inertia decomposition
    Eigen::VectorXd tmp;                  // Temporary of size NV used in Cholesky
    std::vector<int> parents_fromRow;     // First previous non-zero row in M (used in Cholesky)
    std::vector<int> nvSubtree_fromRow;   //

    Matrix6x J;                    // Jacobian of joint placement
    std::vector<SE3> iMf;                 // Body placement wrt to algorithm end effector.

    std::vector<Eigen::Vector3d> com;     // Subtree com position.
    std::vector<Eigen::Vector3d> vcom;    // Subtree com velocity.
    std::vector<Eigen::Vector3d> acom;    // Subtree com acceleration.
    std::vector<double> mass;             // Subtree total mass.
    Matrix3x Jcom; // Jacobian of center of mass.

    Eigen::VectorXd effortLimit;          // Joint max effort
    Eigen::VectorXd velocityLimit;        // Joint max velocity

    Eigen::VectorXd lowerPositionLimit;   // limit for joint lower position
    Eigen::VectorXd upperPositionLimit;   // limit for joint upper position

    double kinetic_energy; // kinetic energy of the model
    double potential_energy; // potential energy of the model

    Data( const Model& ref );

  private:
    void computeLastChild(const Model& model);
    void computeParents_fromRow(const Model& model);

  };

} // namespace se3

/* --- Details -------------------------------------------------------------- */
/* --- Details -------------------------------------------------------------- */
/* --- Details -------------------------------------------------------------- */
#include "pinocchio/multibody/model.hxx"

#endif // ifndef __se3_model_hpp__
<|endoftext|>


<commit_before>
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

#ifndef REALM_OS_OBJECT_ACCESSOR_HPP
#define REALM_OS_OBJECT_ACCESSOR_HPP

#include "object.hpp"

#include "feature_checks.hpp"
#include "list.hpp"
#include "object_schema.hpp"
#include "object_store.hpp"
#include "results.hpp"
#include "schema.hpp"
#include "util/format.hpp"

#include <realm/link_view.hpp>
#include <realm/util/assert.hpp>
#include <realm/table_view.hpp>

#if REALM_HAVE_SYNC_STABLE_IDS
#include <realm/sync/object.hpp>
#endif // REALM_HAVE_SYNC_STABLE_IDS

#include <string>

namespace realm {
template <typename ValueType, typename ContextType>
void Object::set_property_value(ContextType& ctx, StringData prop_name, ValueType value, bool try_update)
{
    verify_attached();
    m_realm->verify_in_write();
    auto& property = property_for_name(prop_name);

    // Modifying primary keys is allowed in migrations to make it possible to
    // add a new primary key to a type (or change the property type), but it
    // is otherwise considered the immutable identity of the row
    if (property.is_primary && !m_realm->is_in_migration())
        throw std::logic_error("Cannot modify primary key after creation");

    set_property_value_impl(ctx, property, value, try_update);
}

template <typename ValueType, typename ContextType>
ValueType Object::get_property_value(ContextType& ctx, StringData prop_name)
{
    return get_property_value_impl<ValueType>(ctx, property_for_name(prop_name));
}

template <typename ValueType, typename ContextType>
void Object::set_property_value_impl(ContextType& ctx, const Property &property,
                                     ValueType value, bool try_update, bool is_default)
{
    ctx.will_change(*this, property);

    auto& table = *m_row.get_table();
    size_t col = property.table_column;
    size_t row = m_row.get_index();
    if (is_nullable(property.type) && ctx.is_null(value)) {
        if (property.type == PropertyType::Object) {
            if (!is_default)
                table.nullify_link(col, row);
        }
        else {
            table.set_null(col, row, is_default);
        }

        ctx.did_change();
        return;
    }

    if (is_array(property.type)) {
        REALM_ASSERT(property.type == PropertyType::Object);

        List list(m_realm, m_row.get_linklist(col));
        list.remove_all();
        if (!ctx.is_null(value)) {
            ContextType child_ctx(ctx, property);
            ctx.enumerate_list(value, [&](auto&& element) {
                list.add(child_ctx, element, try_update);
            });
        }
        ctx.did_change();
        return;
    }

    switch (property.type & ~PropertyType::Flags) {
        case PropertyType::Bool:
            table.set(col, row, ctx.template unbox<bool>(value), is_default);
            break;
        case PropertyType::Int:
            table.set(col, row, ctx.template unbox<int64_t>(value), is_default);
            break;
        case PropertyType::Float:
            table.set(col, row, ctx.template unbox<float>(value), is_default);
            break;
        case PropertyType::Double:
            table.set(col, row, ctx.template unbox<double>(value), is_default);
            break;
        case PropertyType::String:
            table.set(col, row, ctx.template unbox<StringData>(value), is_default);
            break;
        case PropertyType::Data:
            table.set(col, row, ctx.template unbox<BinaryData>(value), is_default);
            break;
        case PropertyType::Any:
            throw std::logic_error("not supported");
        case PropertyType::Date:
            table.set(col, row, ctx.template unbox<Timestamp>(value), is_default);
            break;
        case PropertyType::Object: {
            ContextType child_ctx(ctx, property);
            auto link = child_ctx.template unbox<RowExpr>(value, true, try_update);
            table.set_link(col, row, link.get_index(), is_default);
            break;
        }
        case PropertyType::LinkingObjects:
            throw ReadOnlyPropertyException(m_object_schema->name, property.name);
        default:
            REALM_COMPILER_HINT_UNREACHABLE();
    }
    ctx.did_change();
}

template <typename ValueType, typename ContextType>
ValueType Object::get_property_value_impl(ContextType& ctx, const Property &property)
{
    verify_attached();

    size_t column = property.table_column;
    if (is_nullable(property.type) && m_row.is_null(column)) {
        return ctx.null_value();
    }

    if (is_array(property.type) && property.type != PropertyType::LinkingObjects) {
        REALM_ASSERT(property.type == PropertyType::Object);
        return ctx.box(List(m_realm, m_row.get_linklist(column)));
    }

    switch (property.type & ~PropertyType::Flags) {
        case PropertyType::Bool:   return ctx.box(m_row.get_bool(column));
        case PropertyType::Int:    return ctx.box(m_row.get_int(column));
        case PropertyType::Float:  return ctx.box(m_row.get_float(column));
        case PropertyType::Double: return ctx.box(m_row.get_double(column));
        case PropertyType::String: return ctx.box(m_row.get_string(column));
        case PropertyType::Data:   return ctx.box(m_row.get_binary(column));
        case PropertyType::Date:   return ctx.box(m_row.get_timestamp(column));
        case PropertyType::Any:    return ctx.box(m_row.get_mixed(column));
        case PropertyType::Object: {
            auto linkObjectSchema = m_realm->schema().find(property.object_type);
            TableRef table = ObjectStore::table_for_object_type(m_realm->read_group(), property.object_type);
            return ctx.box(Object(m_realm, *linkObjectSchema, table->get(m_row.get_link(column))));
        }
        case PropertyType::LinkingObjects: {
            auto target_object_schema = m_realm->schema().find(property.object_type);
            auto link_property = target_object_schema->property_for_name(property.link_origin_property_name);
            TableRef table = ObjectStore::table_for_object_type(m_realm->read_group(), target_object_schema->name);
            auto tv = m_row.get_table()->get_backlink_view(m_row.get_index(), table.get(), link_property->table_column);
            return ctx.box(Results(m_realm, std::move(tv)));
        }
        default: REALM_UNREACHABLE();
    }
}

template<typename ValueType, typename ContextType>
Object Object::create(ContextType& ctx, std::shared_ptr<Realm> const& realm,
                      StringData object_type, ValueType value,
                      bool try_update, Row* out_row)
{
    auto object_schema = realm->schema().find(object_type);
    REALM_ASSERT(object_schema != realm->schema().end());
    return create(ctx, realm, *object_schema, value, try_update, out_row);
}

template<typename ValueType, typename ContextType>
Object Object::create(ContextType& ctx, std::shared_ptr<Realm> const& realm,
                      ObjectSchema const& object_schema, ValueType value,
                      bool try_update, Row* out_row)
{
    realm->verify_in_write();

    // get or create our accessor
    bool created = false;

    // try to get existing row if updating
    size_t row_index = realm::not_found;
    TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name);

    bool skip_primary = true;
    if (auto primary_prop = object_schema.primary_key_property()) {
        // search for existing object based on primary key type
        auto primary_value = ctx.value_for_property(value, primary_prop->name,
                                                    primary_prop - &object_schema.persisted_properties[0]);
        if (!primary_value)
            primary_value = ctx.default_value_for_property(object_schema, primary_prop->name);
        if (!primary_value) {
            if (!is_nullable(primary_prop->type))
                throw MissingPropertyValueException(object_schema.name, primary_prop->name);
            primary_value = ctx.null_value();
        }
        row_index = get_for_primary_key_impl(ctx, *table, *primary_prop, *primary_value);

        if (row_index == realm::not_found) {
            created = true;
            if (primary_prop->type == PropertyType::Int) {
#if REALM_HAVE_SYNC_STABLE_IDS
                row_index = sync::create_object_with_primary_key(realm->read_group(), *table, ctx.template unbox<util::Optional<int64_t>>(*primary_value));
#else
                row_index = table->add_empty_row();
                if (ctx.is_null(*primary_value))
                    table->set_null_unique(primary_prop->table_column, row_index);
                else
                    table->set_unique(primary_prop->table_column, row_index, ctx.template unbox<int64_t>(*primary_value));
#endif // REALM_HAVE_SYNC_STABLE_IDS
            }
            else if (primary_prop->type == PropertyType::String) {
                auto value = ctx.template unbox<StringData>(*primary_value);
#if REALM_HAVE_SYNC_STABLE_IDS
                row_index = sync::create_object_with_primary_key(realm->read_group(), *table, value);
#else
                row_index = table->add_empty_row();
                table->set_unique(primary_prop->table_column, row_index, value);
#endif // REALM_HAVE_SYNC_STABLE_IDS
            }
            else {
                REALM_TERMINATE("Unsupported primary key type.");
            }
        }
        else if (!try_update) {
            if (realm->is_in_migration()) {
                // Creating objects with duplicate primary keys is allowed in migrations
                // as long as there are no duplicates at the end, as adding an entirely
                // new column which is the PK will inherently result in duplicates at first
                row_index = table->add_empty_row();
                created = true;
                skip_primary = false;
            }
            else {
                throw std::logic_error(util::format("Attempting to create an object of type '%1' with an existing primary key value '%2'.",
                                                    object_schema.name, ctx.print(*primary_value)));
            }
        }
    }
    else {
#if REALM_HAVE_SYNC_STABLE_IDS
        row_index = sync::create_object(realm->read_group(), *table);
#else
        row_index = table->add_empty_row();
#endif // REALM_HAVE_SYNC_STABLE_IDS
        created = true;
    }

    // populate
    Object object(realm, object_schema, table->get(row_index));
    if (out_row)
        *out_row = object.row();
    for (size_t i = 0; i < object_schema.persisted_properties.size(); ++i) {
        auto& prop = object_schema.persisted_properties[i];
        if (skip_primary && prop.is_primary)
            continue;

        auto v = ctx.value_for_property(value, prop.name, i);
        if (!created && !v)
            continue;

        bool is_default = false;
        if (!v) {
            v = ctx.default_value_for_property(object_schema, prop.name);
            is_default = true;
        }
        if ((!v || ctx.is_null(*v)) && !is_nullable(prop.type) && !is_array(prop.type)) {
            if (prop.is_primary || !ctx.allow_missing(value))
                throw MissingPropertyValueException(object_schema.name, prop.name);
        }
        if (v)
            object.set_property_value_impl(ctx, prop, *v, try_update, is_default);
    }
    return object;
}

template<typename ValueType, typename ContextType>
Object Object::get_for_primary_key(ContextType& ctx, std::shared_ptr<Realm> const& realm,
                      StringData object_type, ValueType primary_value)
{
    auto object_schema = realm->schema().find(object_type);
    REALM_ASSERT(object_schema != realm->schema().end());
    return get_for_primary_key(ctx, realm, *object_schema, primary_value);
}

template<typename ValueType, typename ContextType>
Object Object::get_for_primary_key(ContextType& ctx, std::shared_ptr<Realm> const& realm,
                                   const ObjectSchema &object_schema,
                                   ValueType primary_value)
{
    auto primary_prop = object_schema.primary_key_property();
    if (!primary_prop) {
        throw MissingPrimaryKeyException(object_schema.name);
    }

    auto table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name);
    if (!table)
        return Object(realm, object_schema, RowExpr());
    auto row_index = get_for_primary_key_impl(ctx, *table, *primary_prop, primary_value);

    return Object(realm, object_schema, row_index == realm::not_found ? Row() : Row(table->get(row_index)));
}

template<typename ValueType, typename ContextType>
size_t Object::get_for_primary_key_impl(ContextType& ctx, Table const& table,
                                        const Property &primary_prop,
                                        ValueType primary_value) {
    bool is_null = ctx.is_null(primary_value);
    if (is_null && !is_nullable(primary_prop.type))
        throw std::logic_error("Invalid null value for non-nullable primary key.");
    if (primary_prop.type == PropertyType::String) {
        return table.find_first(primary_prop.table_column,
                                ctx.template unbox<StringData>(primary_value));
    }
    if (is_nullable(primary_prop.type))
        return table.find_first(primary_prop.table_column,
                                ctx.template unbox<util::Optional<int64_t>>(primary_value));
    return table.find_first(primary_prop.table_column,
                            ctx.template unbox<int64_t>(primary_value));
}

} // namespace realm

#endif // REALM_OS_OBJECT_ACCESSOR_HPP
<commit_msg>Move a check for LinkingObjects to the right spot<commit_after>
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

#ifndef REALM_OS_OBJECT_ACCESSOR_HPP
#define REALM_OS_OBJECT_ACCESSOR_HPP

#include "object.hpp"

#include "feature_checks.hpp"
#include "list.hpp"
#include "object_schema.hpp"
#include "object_store.hpp"
#include "results.hpp"
#include "schema.hpp"
#include "util/format.hpp"

#include <realm/link_view.hpp>
#include <realm/util/assert.hpp>
#include <realm/table_view.hpp>

#if REALM_HAVE_SYNC_STABLE_IDS
#include <realm/sync/object.hpp>
#endif // REALM_HAVE_SYNC_STABLE_IDS

#include <string>

namespace realm {
template <typename ValueType, typename ContextType>
void Object::set_property_value(ContextType& ctx, StringData prop_name, ValueType value, bool try_update)
{
    verify_attached();
    m_realm->verify_in_write();
    auto& property = property_for_name(prop_name);

    // Modifying primary keys is allowed in migrations to make it possible to
    // add a new primary key to a type (or change the property type), but it
    // is otherwise considered the immutable identity of the row
    if (property.is_primary && !m_realm->is_in_migration())
        throw std::logic_error("Cannot modify primary key after creation");

    set_property_value_impl(ctx, property, value, try_update);
}

template <typename ValueType, typename ContextType>
ValueType Object::get_property_value(ContextType& ctx, StringData prop_name)
{
    return get_property_value_impl<ValueType>(ctx, property_for_name(prop_name));
}

template <typename ValueType, typename ContextType>
void Object::set_property_value_impl(ContextType& ctx, const Property &property,
                                     ValueType value, bool try_update, bool is_default)
{
    ctx.will_change(*this, property);

    auto& table = *m_row.get_table();
    size_t col = property.table_column;
    size_t row = m_row.get_index();
    if (is_nullable(property.type) && ctx.is_null(value)) {
        if (property.type == PropertyType::Object) {
            if (!is_default)
                table.nullify_link(col, row);
        }
        else {
            table.set_null(col, row, is_default);
        }

        ctx.did_change();
        return;
    }

    if (is_array(property.type)) {
        if (property.type == PropertyType::LinkingObjects)
            throw ReadOnlyPropertyException(m_object_schema->name, property.name);
        REALM_ASSERT(property.type == PropertyType::Object);

        List list(m_realm, m_row.get_linklist(col));
        list.remove_all();
        if (!ctx.is_null(value)) {
            ContextType child_ctx(ctx, property);
            ctx.enumerate_list(value, [&](auto&& element) {
                list.add(child_ctx, element, try_update);
            });
        }
        ctx.did_change();
        return;
    }

    switch (property.type & ~PropertyType::Flags) {
        case PropertyType::Bool:
            table.set(col, row, ctx.template unbox<bool>(value), is_default);
            break;
        case PropertyType::Int:
            table.set(col, row, ctx.template unbox<int64_t>(value), is_default);
            break;
        case PropertyType::Float:
            table.set(col, row, ctx.template unbox<float>(value), is_default);
            break;
        case PropertyType::Double:
            table.set(col, row, ctx.template unbox<double>(value), is_default);
            break;
        case PropertyType::String:
            table.set(col, row, ctx.template unbox<StringData>(value), is_default);
            break;
        case PropertyType::Data:
            table.set(col, row, ctx.template unbox<BinaryData>(value), is_default);
            break;
        case PropertyType::Any:
            throw std::logic_error("not supported");
        case PropertyType::Date:
            table.set(col, row, ctx.template unbox<Timestamp>(value), is_default);
            break;
        case PropertyType::Object: {
            ContextType child_ctx(ctx, property);
            auto link = child_ctx.template unbox<RowExpr>(value, true, try_update);
            table.set_link(col, row, link.get_index(), is_default);
            break;
        }
        default:
            REALM_COMPILER_HINT_UNREACHABLE();
    }
    ctx.did_change();
}

template <typename ValueType, typename ContextType>
ValueType Object::get_property_value_impl(ContextType& ctx, const Property &property)
{
    verify_attached();

    size_t column = property.table_column;
    if (is_nullable(property.type) && m_row.is_null(column)) {
        return ctx.null_value();
    }

    if (is_array(property.type) && property.type != PropertyType::LinkingObjects) {
        REALM_ASSERT(property.type == PropertyType::Object);
        return ctx.box(List(m_realm, m_row.get_linklist(column)));
    }

    switch (property.type & ~PropertyType::Flags) {
        case PropertyType::Bool:   return ctx.box(m_row.get_bool(column));
        case PropertyType::Int:    return ctx.box(m_row.get_int(column));
        case PropertyType::Float:  return ctx.box(m_row.get_float(column));
        case PropertyType::Double: return ctx.box(m_row.get_double(column));
        case PropertyType::String: return ctx.box(m_row.get_string(column));
        case PropertyType::Data:   return ctx.box(m_row.get_binary(column));
        case PropertyType::Date:   return ctx.box(m_row.get_timestamp(column));
        case PropertyType::Any:    return ctx.box(m_row.get_mixed(column));
        case PropertyType::Object: {
            auto linkObjectSchema = m_realm->schema().find(property.object_type);
            TableRef table = ObjectStore::table_for_object_type(m_realm->read_group(), property.object_type);
            return ctx.box(Object(m_realm, *linkObjectSchema, table->get(m_row.get_link(column))));
        }
        case PropertyType::LinkingObjects: {
            auto target_object_schema = m_realm->schema().find(property.object_type);
            auto link_property = target_object_schema->property_for_name(property.link_origin_property_name);
            TableRef table = ObjectStore::table_for_object_type(m_realm->read_group(), target_object_schema->name);
            auto tv = m_row.get_table()->get_backlink_view(m_row.get_index(), table.get(), link_property->table_column);
            return ctx.box(Results(m_realm, std::move(tv)));
        }
        default: REALM_UNREACHABLE();
    }
}

template<typename ValueType, typename ContextType>
Object Object::create(ContextType& ctx, std::shared_ptr<Realm> const& realm,
                      StringData object_type, ValueType value,
                      bool try_update, Row* out_row)
{
    auto object_schema = realm->schema().find(object_type);
    REALM_ASSERT(object_schema != realm->schema().end());
    return create(ctx, realm, *object_schema, value, try_update, out_row);
}

template<typename ValueType, typename ContextType>
Object Object::create(ContextType& ctx, std::shared_ptr<Realm> const& realm,
                      ObjectSchema const& object_schema, ValueType value,
                      bool try_update, Row* out_row)
{
    realm->verify_in_write();

    // get or create our accessor
    bool created = false;

    // try to get existing row if updating
    size_t row_index = realm::not_found;
    TableRef table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name);

    bool skip_primary = true;
    if (auto primary_prop = object_schema.primary_key_property()) {
        // search for existing object based on primary key type
        auto primary_value = ctx.value_for_property(value, primary_prop->name,
                                                    primary_prop - &object_schema.persisted_properties[0]);
        if (!primary_value)
            primary_value = ctx.default_value_for_property(object_schema, primary_prop->name);
        if (!primary_value) {
            if (!is_nullable(primary_prop->type))
                throw MissingPropertyValueException(object_schema.name, primary_prop->name);
            primary_value = ctx.null_value();
        }
        row_index = get_for_primary_key_impl(ctx, *table, *primary_prop, *primary_value);

        if (row_index == realm::not_found) {
            created = true;
            if (primary_prop->type == PropertyType::Int) {
#if REALM_HAVE_SYNC_STABLE_IDS
                row_index = sync::create_object_with_primary_key(realm->read_group(), *table, ctx.template unbox<util::Optional<int64_t>>(*primary_value));
#else
                row_index = table->add_empty_row();
                if (ctx.is_null(*primary_value))
                    table->set_null_unique(primary_prop->table_column, row_index);
                else
                    table->set_unique(primary_prop->table_column, row_index, ctx.template unbox<int64_t>(*primary_value));
#endif // REALM_HAVE_SYNC_STABLE_IDS
            }
            else if (primary_prop->type == PropertyType::String) {
                auto value = ctx.template unbox<StringData>(*primary_value);
#if REALM_HAVE_SYNC_STABLE_IDS
                row_index = sync::create_object_with_primary_key(realm->read_group(), *table, value);
#else
                row_index = table->add_empty_row();
                table->set_unique(primary_prop->table_column, row_index, value);
#endif // REALM_HAVE_SYNC_STABLE_IDS
            }
            else {
                REALM_TERMINATE("Unsupported primary key type.");
            }
        }
        else if (!try_update) {
            if (realm->is_in_migration()) {
                // Creating objects with duplicate primary keys is allowed in migrations
                // as long as there are no duplicates at the end, as adding an entirely
                // new column which is the PK will inherently result in duplicates at first
                row_index = table->add_empty_row();
                created = true;
                skip_primary = false;
            }
            else {
                throw std::logic_error(util::format("Attempting to create an object of type '%1' with an existing primary key value '%2'.",
                                                    object_schema.name, ctx.print(*primary_value)));
            }
        }
    }
    else {
#if REALM_HAVE_SYNC_STABLE_IDS
        row_index = sync::create_object(realm->read_group(), *table);
#else
        row_index = table->add_empty_row();
#endif // REALM_HAVE_SYNC_STABLE_IDS
        created = true;
    }

    // populate
    Object object(realm, object_schema, table->get(row_index));
    if (out_row)
        *out_row = object.row();
    for (size_t i = 0; i < object_schema.persisted_properties.size(); ++i) {
        auto& prop = object_schema.persisted_properties[i];
        if (skip_primary && prop.is_primary)
            continue;

        auto v = ctx.value_for_property(value, prop.name, i);
        if (!created && !v)
            continue;

        bool is_default = false;
        if (!v) {
            v = ctx.default_value_for_property(object_schema, prop.name);
            is_default = true;
        }
        if ((!v || ctx.is_null(*v)) && !is_nullable(prop.type) && !is_array(prop.type)) {
            if (prop.is_primary || !ctx.allow_missing(value))
                throw MissingPropertyValueException(object_schema.name, prop.name);
        }
        if (v)
            object.set_property_value_impl(ctx, prop, *v, try_update, is_default);
    }
    return object;
}

template<typename ValueType, typename ContextType>
Object Object::get_for_primary_key(ContextType& ctx, std::shared_ptr<Realm> const& realm,
                      StringData object_type, ValueType primary_value)
{
    auto object_schema = realm->schema().find(object_type);
    REALM_ASSERT(object_schema != realm->schema().end());
    return get_for_primary_key(ctx, realm, *object_schema, primary_value);
}

template<typename ValueType, typename ContextType>
Object Object::get_for_primary_key(ContextType& ctx, std::shared_ptr<Realm> const& realm,
                                   const ObjectSchema &object_schema,
                                   ValueType primary_value)
{
    auto primary_prop = object_schema.primary_key_property();
    if (!primary_prop) {
        throw MissingPrimaryKeyException(object_schema.name);
    }

    auto table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name);
    if (!table)
        return Object(realm, object_schema, RowExpr());
    auto row_index = get_for_primary_key_impl(ctx, *table, *primary_prop, primary_value);

    return Object(realm, object_schema, row_index == realm::not_found ? Row() : Row(table->get(row_index)));
}

template<typename ValueType, typename ContextType>
size_t Object::get_for_primary_key_impl(ContextType& ctx, Table const& table,
                                        const Property &primary_prop,
                                        ValueType primary_value) {
    bool is_null = ctx.is_null(primary_value);
    if (is_null && !is_nullable(primary_prop.type))
        throw std::logic_error("Invalid null value for non-nullable primary key.");
    if (primary_prop.type == PropertyType::String) {
        return table.find_first(primary_prop.table_column,
                                ctx.template unbox<StringData>(primary_value));
    }
    if (is_nullable(primary_prop.type))
        return table.find_first(primary_prop.table_column,
                                ctx.template unbox<util::Optional<int64_t>>(primary_value));
    return table.find_first(primary_prop.table_column,
                            ctx.template unbox<int64_t>(primary_value));
}

} // namespace realm

#endif // REALM_OS_OBJECT_ACCESSOR_HPP
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <set>
#include <qitype/genericobject.hpp>
#include <qimessaging/transportserver.hpp>
#include <qimessaging/serviceinfo.hpp>
#include <qitype/objecttypebuilder.hpp>
#include "server.hpp"
#include "objectregistrar.hpp"
#include "serverresult.hpp"
#include "transportserver_p.hpp"
#include <qi/os.hpp>
#include <boost/thread/mutex.hpp>
#include "servicedirectoryclient.hpp"

namespace qi {

  ObjectRegistrar::ObjectRegistrar(ServiceDirectoryClient *sdClient)
    : Server()
    , _dying(false)
    , _sdClient(sdClient)
  {
  }

  ObjectRegistrar::~ObjectRegistrar()
  {
    _dying = true;
  }

  void serviceReady(qi::Future<void> fut, qi::Promise<unsigned int> result, unsigned int idx) {
    if (fut.hasError()) {
      result.setError(fut.error());
      return;
    }
    result.setValue(idx);
  }

  void ObjectRegistrar::onFutureFinished(qi::Future<unsigned int> fut, long id, qi::Promise<unsigned int> result)
  {
    if (fut.hasError()) {
      result.setError(fut.error());
      return;
    }
    qi::ServiceInfo              si;
    RegisterServiceMap::iterator it;

    {
      boost::mutex::scoped_lock sl(_registerServiceRequestMutex);
      it = _registerServiceRequest.find(id);
      if (it != _registerServiceRequest.end())
        si = it->second.second;
      if (fut.hasError()) {
        _registerServiceRequest.erase(id);
        result.setError(fut.error());
        return;
      }
    }
    unsigned int idx = fut.value();
    si.setServiceId(idx);
    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundService bs;
      bs.id          = idx;
      bs.object      = it->second.first;
      bs.serviceInfo = si;
      bs.name        = si.name();
      BoundServiceMap::iterator it;
      it = _services.find(idx);
      if (it != _services.end()) {
        qiLogError("qi.server") << "A service is already registered with that id:" << idx;
        result.setError("Service already registered.");
        return;
      }
      _services[idx] = bs;
      //todo register the object on the server (find a better way)
      Server::addObject(idx, bs.object);
    }

    // ack the Service directory to tell that we are ready
    //TODO: async handle.
    qi::Future<void> fut2 = _sdClient->serviceReady(idx);
    fut2.connect(boost::bind(&serviceReady, _1, result, idx));

    {
      boost::mutex::scoped_lock sl(_serviceNameToIndexMutex);
      _serviceNameToIndex[si.name()] = idx;
    }
    {
      boost::mutex::scoped_lock sl(_registerServiceRequestMutex);
      _registerServiceRequest.erase(it);
    }

  }

  qi::Future<unsigned int> ObjectRegistrar::registerService(const std::string &name, qi::ObjectPtr obj)
  {
    if (Server::endpoints().empty()) {
      qiLogError("qimessaging.Server") << "Could not register service: " << name << " because the current server has not endpoint";
      return qi::Future<unsigned int>();
    }
    qi::ServiceInfo si;
    si.setName(name);
    si.setProcessId(qi::os::getpid());
    si.setMachineId(qi::os::getMachineId());
    si.setEndpoints(Server::endpoints());

    long id = ++_registerServiceRequestIndex;
    {
      boost::mutex::scoped_lock sl(_registerServiceRequestMutex);
      _registerServiceRequest[id] = std::make_pair(obj, si);
    }

    qi::Promise<unsigned int> prom;
    qi::Future<unsigned int>  future;
    future = _sdClient->registerService(si);
    future.connect(boost::bind<void>(&ObjectRegistrar::onFutureFinished, this, _1, id, prom));

    return prom.future();
  };

  qi::Future<void> ObjectRegistrar::unregisterService(unsigned int idx)
  {
    qi::Future<void> future = _sdClient->unregisterService(idx);

    std::string name;
    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundServiceMap::iterator it = _services.find(idx);
      if (it != _services.end()) {
        name = it->second.name;
        if (!it->second.object.unique())
        {
          qiLogInfo("qimessaging.Server") << "Some references to service #" << idx
                                          << " are still held!";
        }
        _services.erase(it);
      } else {
        qiLogVerbose("qimessaging.Server") << "Can't find name associated to id:" << idx;
      }
      Server::removeObject(idx);
    }
    if (!name.empty())
    {
      boost::mutex::scoped_lock sl(_serviceNameToIndexMutex);
      ServiceNameToIndexMap::iterator it = _serviceNameToIndex.find(name);
      if (it != _serviceNameToIndex.end())
        _serviceNameToIndex.erase(it);
      else
        qiLogVerbose("qimessaging.Server") << "Can't find idx associated to name :" << name;
    }
    return future;
  }

  std::vector<qi::ServiceInfo> ObjectRegistrar::registeredServices() {
    std::vector<qi::ServiceInfo> ssi;
    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundServiceMap::iterator it = _services.begin();
      for (; it != _services.end(); ++it) {
        //drop 0 => it's the server itself.
        if (it->first == 0)
          continue;
        ssi.push_back(it->second.serviceInfo);
      }
    }
    return ssi;
  }

  //return 0 on error (0 is the server which have no name)
  unsigned int ObjectRegistrar::objectId(const std::string &name)
  {
    {
      boost::mutex::scoped_lock sl(_serviceNameToIndexMutex);
      ServiceNameToIndexMap::iterator it;
      it = _serviceNameToIndex.find(name);
      if (it != _serviceNameToIndex.end())
        return it->second;
    }
    return 0;
  }

  qi::ServiceInfo ObjectRegistrar::registeredService(const std::string &service) {
    unsigned int serviceId = objectId(service);

    if (!serviceId)
      return qi::ServiceInfo();

    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundServiceMap::iterator it = _services.find(serviceId);
      if (it != _services.end())
        return it->second.serviceInfo;
    }
    return qi::ServiceInfo();
  }

  qi::ObjectPtr ObjectRegistrar::registeredServiceObject(const std::string &service) {
    unsigned int serviceId = objectId(service);
    if (!serviceId)
      return qi::ObjectPtr();

    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundServiceMap::iterator it = _services.find(serviceId);
      if (it != _services.end())
        return it->second.object;
    }
    return ObjectPtr();
  }

}
<commit_msg>Change verbosity level<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <set>
#include <qitype/genericobject.hpp>
#include <qimessaging/transportserver.hpp>
#include <qimessaging/serviceinfo.hpp>
#include <qitype/objecttypebuilder.hpp>
#include "server.hpp"
#include "objectregistrar.hpp"
#include "serverresult.hpp"
#include "transportserver_p.hpp"
#include <qi/os.hpp>
#include <boost/thread/mutex.hpp>
#include "servicedirectoryclient.hpp"

namespace qi {

  ObjectRegistrar::ObjectRegistrar(ServiceDirectoryClient *sdClient)
    : Server()
    , _dying(false)
    , _sdClient(sdClient)
  {
  }

  ObjectRegistrar::~ObjectRegistrar()
  {
    _dying = true;
  }

  void serviceReady(qi::Future<void> fut, qi::Promise<unsigned int> result, unsigned int idx) {
    if (fut.hasError()) {
      result.setError(fut.error());
      return;
    }
    result.setValue(idx);
  }

  void ObjectRegistrar::onFutureFinished(qi::Future<unsigned int> fut, long id, qi::Promise<unsigned int> result)
  {
    if (fut.hasError()) {
      result.setError(fut.error());
      return;
    }
    qi::ServiceInfo              si;
    RegisterServiceMap::iterator it;

    {
      boost::mutex::scoped_lock sl(_registerServiceRequestMutex);
      it = _registerServiceRequest.find(id);
      if (it != _registerServiceRequest.end())
        si = it->second.second;
      if (fut.hasError()) {
        _registerServiceRequest.erase(id);
        result.setError(fut.error());
        return;
      }
    }
    unsigned int idx = fut.value();
    si.setServiceId(idx);
    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundService bs;
      bs.id          = idx;
      bs.object      = it->second.first;
      bs.serviceInfo = si;
      bs.name        = si.name();
      BoundServiceMap::iterator it;
      it = _services.find(idx);
      if (it != _services.end()) {
        qiLogError("qi.server") << "A service is already registered with that id:" << idx;
        result.setError("Service already registered.");
        return;
      }
      _services[idx] = bs;
      //todo register the object on the server (find a better way)
      Server::addObject(idx, bs.object);
    }

    // ack the Service directory to tell that we are ready
    //TODO: async handle.
    qi::Future<void> fut2 = _sdClient->serviceReady(idx);
    fut2.connect(boost::bind(&serviceReady, _1, result, idx));

    {
      boost::mutex::scoped_lock sl(_serviceNameToIndexMutex);
      _serviceNameToIndex[si.name()] = idx;
    }
    {
      boost::mutex::scoped_lock sl(_registerServiceRequestMutex);
      _registerServiceRequest.erase(it);
    }

  }

  qi::Future<unsigned int> ObjectRegistrar::registerService(const std::string &name, qi::ObjectPtr obj)
  {
    if (Server::endpoints().empty()) {
      qiLogError("qimessaging.Server") << "Could not register service: " << name << " because the current server has not endpoint";
      return qi::Future<unsigned int>();
    }
    qi::ServiceInfo si;
    si.setName(name);
    si.setProcessId(qi::os::getpid());
    si.setMachineId(qi::os::getMachineId());
    si.setEndpoints(Server::endpoints());

    long id = ++_registerServiceRequestIndex;
    {
      boost::mutex::scoped_lock sl(_registerServiceRequestMutex);
      _registerServiceRequest[id] = std::make_pair(obj, si);
    }

    qi::Promise<unsigned int> prom;
    qi::Future<unsigned int>  future;
    future = _sdClient->registerService(si);
    future.connect(boost::bind<void>(&ObjectRegistrar::onFutureFinished, this, _1, id, prom));

    return prom.future();
  };

  qi::Future<void> ObjectRegistrar::unregisterService(unsigned int idx)
  {
    qi::Future<void> future = _sdClient->unregisterService(idx);

    std::string name;
    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundServiceMap::iterator it = _services.find(idx);
      if (it != _services.end()) {
        name = it->second.name;
        if (!it->second.object.unique())
        {
          qiLogVerbose("qimessaging.Server") << "Some references to service #" << idx
                                             << " are still held!";
        }
        _services.erase(it);
      } else {
        qiLogVerbose("qimessaging.Server") << "Can't find name associated to id:" << idx;
      }
      Server::removeObject(idx);
    }
    if (!name.empty())
    {
      boost::mutex::scoped_lock sl(_serviceNameToIndexMutex);
      ServiceNameToIndexMap::iterator it = _serviceNameToIndex.find(name);
      if (it != _serviceNameToIndex.end())
        _serviceNameToIndex.erase(it);
      else
        qiLogVerbose("qimessaging.Server") << "Can't find idx associated to name :" << name;
    }
    return future;
  }

  std::vector<qi::ServiceInfo> ObjectRegistrar::registeredServices() {
    std::vector<qi::ServiceInfo> ssi;
    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundServiceMap::iterator it = _services.begin();
      for (; it != _services.end(); ++it) {
        //drop 0 => it's the server itself.
        if (it->first == 0)
          continue;
        ssi.push_back(it->second.serviceInfo);
      }
    }
    return ssi;
  }

  //return 0 on error (0 is the server which have no name)
  unsigned int ObjectRegistrar::objectId(const std::string &name)
  {
    {
      boost::mutex::scoped_lock sl(_serviceNameToIndexMutex);
      ServiceNameToIndexMap::iterator it;
      it = _serviceNameToIndex.find(name);
      if (it != _serviceNameToIndex.end())
        return it->second;
    }
    return 0;
  }

  qi::ServiceInfo ObjectRegistrar::registeredService(const std::string &service) {
    unsigned int serviceId = objectId(service);

    if (!serviceId)
      return qi::ServiceInfo();

    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundServiceMap::iterator it = _services.find(serviceId);
      if (it != _services.end())
        return it->second.serviceInfo;
    }
    return qi::ServiceInfo();
  }

  qi::ObjectPtr ObjectRegistrar::registeredServiceObject(const std::string &service) {
    unsigned int serviceId = objectId(service);
    if (!serviceId)
      return qi::ObjectPtr();

    {
      boost::mutex::scoped_lock sl(_servicesMutex);
      BoundServiceMap::iterator it = _services.find(serviceId);
      if (it != _services.end())
        return it->second.object;
    }
    return ObjectPtr();
  }

}
<|endoftext|>