<commit_before>/*
 *
 * Copyright 2016, Google Inc.
 * 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.
 *     * Neither the name of Google Inc. 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.
 *
 */

// Generates Objective C gRPC service interface out of Protobuf IDL.

#include <memory>

#include "src/compiler/config.h"
#include "src/compiler/c_generator.h"
#include "src/compiler/c_generator_helpers.h"
#include "src/compiler/cpp_generator_helpers.h"
#include "src/compiler/cpp_generator.h"

namespace grpc_c_generator {

using std::map;

class ProtoBufCMethod : public grpc_cpp_generator::Method {
public:
  ProtoBufCMethod(const grpc::protobuf::MethodDescriptor *method)
    : method_(method) { }

  grpc::string name() const { return method_->name(); }

  grpc::string input_type_name() const {
    return method_->input_type()->name();
  }

  grpc::string output_type_name() const {
    return method_->output_type()->name();
  }

  bool NoStreaming() const {
    return !method_->client_streaming() && !method_->server_streaming();
  }

  bool ClientOnlyStreaming() const {
    return method_->client_streaming() && !method_->server_streaming();
  }

  bool ServerOnlyStreaming() const {
    return !method_->client_streaming() && method_->server_streaming();
  }

  bool BidiStreaming() const {
    return method_->client_streaming() && method_->server_streaming();
  }

  grpc::string GetLeadingComments() const {
    return GetCComments(method_, true);
  }

  grpc::string GetTrailingComments() const {
    return GetCComments(method_, false);
  }

private:
  const grpc::protobuf::MethodDescriptor *method_;
};

class ProtoBufCService : public grpc_cpp_generator::Service {
public:
  ProtoBufCService(const grpc::protobuf::ServiceDescriptor *service)
    : service_(service) { }

  grpc::string name() const { return service_->name(); }

  int method_count() const { return service_->method_count(); };

  std::unique_ptr<const grpc_cpp_generator::Method> method(int i) const {
    return std::unique_ptr<const grpc_cpp_generator::Method>(new ProtoBufCMethod(service_->method(i)));
  };

  grpc::string GetLeadingComments() const {
    return GetCComments(service_, true);
  }

  grpc::string GetTrailingComments() const {
    return GetCComments(service_, false);
  }

private:
  const grpc::protobuf::ServiceDescriptor *service_;
};

class ProtoBufCPrinter : public grpc_cpp_generator::Printer {
public:
  ProtoBufCPrinter(grpc::string *str)
    : output_stream_(str), printer_(&output_stream_, '$') { }

  void Print(const std::map<grpc::string, grpc::string> &vars,
             const char *string_template) {
    printer_.Print(vars, string_template);
  }

  void Print(const char *string) { printer_.Print(string); }

  void Indent() { printer_.Indent(); }

  void Outdent() { printer_.Outdent(); }

private:
  grpc::protobuf::io::StringOutputStream output_stream_;
  grpc::protobuf::io::Printer printer_;
};

class ProtoBufCFile : public grpc_cpp_generator::File {
public:
  ProtoBufCFile(const grpc::protobuf::FileDescriptor *file) : file_(file) { }

  grpc::string filename() const { return file_->name(); }

  grpc::string filename_without_ext() const {
    return grpc_generator::StripProto(filename());
  }

  grpc::string message_header_ext() const { return ".pbc.h"; }

  grpc::string service_header_ext() const { return ".grpc.pbc.h"; }

  grpc::string package() const { return file_->package(); }

  std::vector<grpc::string> package_parts() const {
    return grpc_generator::tokenize(package(), ".");
  }

  grpc::string additional_headers() const { return ""; }

  int service_count() const { return file_->service_count(); };

  std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
    return std::unique_ptr<const grpc_cpp_generator::Service>(new ProtoBufCService(file_->service(i)));
  }

  std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(grpc::string *str) const {
    return std::unique_ptr<grpc_cpp_generator::Printer>(new ProtoBufCPrinter(str));
  }

  grpc::string GetLeadingComments() const {
    return GetCComments(file_, true);
  }

  grpc::string GetTrailingComments() const {
    return GetCComments(file_, false);
  }

private:
  const grpc::protobuf::FileDescriptor *file_;
};

} // namespace grpc_c_generator

class CGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
public:
  CGrpcGenerator() {}
  virtual ~CGrpcGenerator() {}

  virtual bool Generate(const grpc::protobuf::FileDescriptor *file,
                        const ::grpc::string &parameter,
                        grpc::protobuf::compiler::GeneratorContext *context,
                        ::grpc::string *error) const {

    if (file->service_count() == 0) {
      // No services.  Do nothing.
      return true;
    }

    grpc::string file_name = grpc_generator::StripProto(file->name());

    // TODO(yifeit): Add c_prefix option in protobuf, and update descriptor
    //::grpc::string prefix = file->options().c_prefix();
    grpc::string prefix = "";

    if (file->options().cc_generic_services()) {
      *error =
        "C grpc proto compiler plugin does not work with generic "
        "services. To generate cpp grpc APIs, please set \""
        "cc_generic_service = false\".";
      return false;
    }

    grpc_cpp_generator::Parameters generator_parameters;
    generator_parameters.use_system_headers = true;

    grpc_c_generator::ProtoBufCFile pbfile(file);

    if (!parameter.empty()) {
      std::vector<grpc::string> parameters_list =
        grpc_generator::tokenize(parameter, ",");
      for (auto parameter_string = parameters_list.begin();
           parameter_string != parameters_list.end();
           parameter_string++) {
        std::vector<grpc::string> param =
          grpc_generator::tokenize(*parameter_string, "=");
        if (param[0] == "services_namespace") {
          generator_parameters.services_namespace = param[1];
        } else if (param[0] == "use_system_headers") {
          if (param[1] == "true") {
            generator_parameters.use_system_headers = true;
          } else if (param[1] == "false") {
            generator_parameters.use_system_headers = false;
          } else {
            *error = grpc::string("Invalid parameter: ") + *parameter_string;
            return false;
          }
        } else if (param[0] == "grpc_search_path") {
          generator_parameters.grpc_search_path = param[1];
        } else {
          *error = grpc::string("Unknown parameter: ") + *parameter_string;
          return false;
        }
      }
    }

    grpc::string header_code =
      grpc_c_generator::GetHeaderPrologue(&pbfile, generator_parameters) +
      grpc_c_generator::GetHeaderIncludes(&pbfile, generator_parameters) +
      grpc_c_generator::GetHeaderServices(&pbfile, generator_parameters) +
      grpc_c_generator::GetHeaderEpilogue(&pbfile, generator_parameters);
    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> header_output(
      context->Open(file_name + ".grpc.pbc.h"));
    grpc::protobuf::io::CodedOutputStream header_coded_out(
      header_output.get());
    header_coded_out.WriteRaw(header_code.data(), header_code.size());

    grpc::string source_code =
      grpc_c_generator::GetSourcePrologue(&pbfile, generator_parameters) +
      grpc_c_generator::GetSourceIncludes(&pbfile, generator_parameters) +
      grpc_c_generator::GetSourceServices(&pbfile, generator_parameters) +
      grpc_c_generator::GetSourceEpilogue(&pbfile, generator_parameters);
    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> source_output(
      context->Open(file_name + ".grpc.pbc.c"));
    grpc::protobuf::io::CodedOutputStream source_coded_out(
      source_output.get());
    source_coded_out.WriteRaw(source_code.data(), source_code.size());

    return true;
  }

private:
  // Insert the given code into the given file at the given insertion point.
  void Insert(grpc::protobuf::compiler::GeneratorContext *context,
              const grpc::string &filename, const grpc::string &insertion_point,
              const grpc::string &code) const {
    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
      context->OpenForInsert(filename, insertion_point));
    grpc::protobuf::io::CodedOutputStream coded_out(output.get());
    coded_out.WriteRaw(code.data(), code.size());
  }
};

int main(int argc, char *argv[]) {
  CGrpcGenerator generator;
  return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
}
<commit_msg>prepare to include nanopb<commit_after>/*
 *
 * Copyright 2016, Google Inc.
 * 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.
 *     * Neither the name of Google Inc. 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.
 *
 */

// Generates Objective C gRPC service interface out of Protobuf IDL.

#include <memory>

#include "src/compiler/config.h"
#include "src/compiler/c_generator.h"
#include "src/compiler/c_generator_helpers.h"
#include "src/compiler/cpp_generator_helpers.h"
#include "src/compiler/cpp_generator.h"

namespace grpc_c_generator {

using std::map;

class ProtoBufCMethod : public grpc_cpp_generator::Method {
public:
  ProtoBufCMethod(const grpc::protobuf::MethodDescriptor *method)
    : method_(method) { }

  grpc::string name() const { return method_->name(); }

  grpc::string input_type_name() const {
    return method_->input_type()->name();
  }

  grpc::string output_type_name() const {
    return method_->output_type()->name();
  }

  bool NoStreaming() const {
    return !method_->client_streaming() && !method_->server_streaming();
  }

  bool ClientOnlyStreaming() const {
    return method_->client_streaming() && !method_->server_streaming();
  }

  bool ServerOnlyStreaming() const {
    return !method_->client_streaming() && method_->server_streaming();
  }

  bool BidiStreaming() const {
    return method_->client_streaming() && method_->server_streaming();
  }

  grpc::string GetLeadingComments() const {
    return GetCComments(method_, true);
  }

  grpc::string GetTrailingComments() const {
    return GetCComments(method_, false);
  }

private:
  const grpc::protobuf::MethodDescriptor *method_;
};

class ProtoBufCService : public grpc_cpp_generator::Service {
public:
  ProtoBufCService(const grpc::protobuf::ServiceDescriptor *service)
    : service_(service) { }

  grpc::string name() const { return service_->name(); }

  int method_count() const { return service_->method_count(); };

  std::unique_ptr<const grpc_cpp_generator::Method> method(int i) const {
    return std::unique_ptr<const grpc_cpp_generator::Method>(new ProtoBufCMethod(service_->method(i)));
  };

  grpc::string GetLeadingComments() const {
    return GetCComments(service_, true);
  }

  grpc::string GetTrailingComments() const {
    return GetCComments(service_, false);
  }

private:
  const grpc::protobuf::ServiceDescriptor *service_;
};

class ProtoBufCPrinter : public grpc_cpp_generator::Printer {
public:
  ProtoBufCPrinter(grpc::string *str)
    : output_stream_(str), printer_(&output_stream_, '$') { }

  void Print(const std::map<grpc::string, grpc::string> &vars,
             const char *string_template) {
    printer_.Print(vars, string_template);
  }

  void Print(const char *string) { printer_.Print(string); }

  void Indent() { printer_.Indent(); }

  void Outdent() { printer_.Outdent(); }

private:
  grpc::protobuf::io::StringOutputStream output_stream_;
  grpc::protobuf::io::Printer printer_;
};

class ProtoBufCFile : public grpc_cpp_generator::File {
public:
  ProtoBufCFile(const grpc::protobuf::FileDescriptor *file) : file_(file) { }

  grpc::string filename() const { return file_->name(); }

  grpc::string filename_without_ext() const {
    return grpc_generator::StripProto(filename());
  }

  // TODO(yifeit): We're relying on Nanopb right now. After rolling out our own Protobuf-C impl, we should
  // use a different extension e.g. ".pbc.h"
  grpc::string message_header_ext() const { return ".pb.h"; }

  grpc::string service_header_ext() const { return ".grpc.pbc.h"; }

  grpc::string package() const { return file_->package(); }

  std::vector<grpc::string> package_parts() const {
    return grpc_generator::tokenize(package(), ".");
  }

  grpc::string additional_headers() const { return ""; }

  int service_count() const { return file_->service_count(); };

  std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
    return std::unique_ptr<const grpc_cpp_generator::Service>(new ProtoBufCService(file_->service(i)));
  }

  std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(grpc::string *str) const {
    return std::unique_ptr<grpc_cpp_generator::Printer>(new ProtoBufCPrinter(str));
  }

  grpc::string GetLeadingComments() const {
    return GetCComments(file_, true);
  }

  grpc::string GetTrailingComments() const {
    return GetCComments(file_, false);
  }

private:
  const grpc::protobuf::FileDescriptor *file_;
};

} // namespace grpc_c_generator

class CGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
public:
  CGrpcGenerator() {}
  virtual ~CGrpcGenerator() {}

  virtual bool Generate(const grpc::protobuf::FileDescriptor *file,
                        const ::grpc::string &parameter,
                        grpc::protobuf::compiler::GeneratorContext *context,
                        ::grpc::string *error) const {

    if (file->service_count() == 0) {
      // No services.  Do nothing.
      return true;
    }

    grpc::string file_name = grpc_generator::StripProto(file->name());

    // TODO(yifeit): Add c_prefix option in protobuf, and update descriptor
    //::grpc::string prefix = file->options().c_prefix();
    grpc::string prefix = "";

    if (file->options().cc_generic_services()) {
      *error =
        "C grpc proto compiler plugin does not work with generic "
        "services. To generate cpp grpc APIs, please set \""
        "cc_generic_service = false\".";
      return false;
    }

    grpc_cpp_generator::Parameters generator_parameters;
    generator_parameters.use_system_headers = true;

    grpc_c_generator::ProtoBufCFile pbfile(file);

    if (!parameter.empty()) {
      std::vector<grpc::string> parameters_list =
        grpc_generator::tokenize(parameter, ",");
      for (auto parameter_string = parameters_list.begin();
           parameter_string != parameters_list.end();
           parameter_string++) {
        std::vector<grpc::string> param =
          grpc_generator::tokenize(*parameter_string, "=");
        if (param[0] == "services_namespace") {
          generator_parameters.services_namespace = param[1];
        } else if (param[0] == "use_system_headers") {
          if (param[1] == "true") {
            generator_parameters.use_system_headers = true;
          } else if (param[1] == "false") {
            generator_parameters.use_system_headers = false;
          } else {
            *error = grpc::string("Invalid parameter: ") + *parameter_string;
            return false;
          }
        } else if (param[0] == "grpc_search_path") {
          generator_parameters.grpc_search_path = param[1];
        } else {
          *error = grpc::string("Unknown parameter: ") + *parameter_string;
          return false;
        }
      }
    }

    grpc::string header_code =
      grpc_c_generator::GetHeaderPrologue(&pbfile, generator_parameters) +
      grpc_c_generator::GetHeaderIncludes(&pbfile, generator_parameters) +
      grpc_c_generator::GetHeaderServices(&pbfile, generator_parameters) +
      grpc_c_generator::GetHeaderEpilogue(&pbfile, generator_parameters);
    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> header_output(
      context->Open(file_name + ".grpc.pbc.h"));
    grpc::protobuf::io::CodedOutputStream header_coded_out(
      header_output.get());
    header_coded_out.WriteRaw(header_code.data(), header_code.size());

    grpc::string source_code =
      grpc_c_generator::GetSourcePrologue(&pbfile, generator_parameters) +
      grpc_c_generator::GetSourceIncludes(&pbfile, generator_parameters) +
      grpc_c_generator::GetSourceServices(&pbfile, generator_parameters) +
      grpc_c_generator::GetSourceEpilogue(&pbfile, generator_parameters);
    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> source_output(
      context->Open(file_name + ".grpc.pbc.c"));
    grpc::protobuf::io::CodedOutputStream source_coded_out(
      source_output.get());
    source_coded_out.WriteRaw(source_code.data(), source_code.size());

    return true;
  }

private:
  // Insert the given code into the given file at the given insertion point.
  void Insert(grpc::protobuf::compiler::GeneratorContext *context,
              const grpc::string &filename, const grpc::string &insertion_point,
              const grpc::string &code) const {
    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
      context->OpenForInsert(filename, insertion_point));
    grpc::protobuf::io::CodedOutputStream coded_out(output.get());
    coded_out.WriteRaw(code.data(), code.size());
  }
};

int main(int argc, char *argv[]) {
  CGrpcGenerator generator;
  return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
}
<|endoftext|>


<commit_before>
#include <iostream>
#include "io/binary_parser.h"
#include "dstruct/factor_graph/factor_graph.h"
#include "dstruct/factor_graph/factor.h"

template <class OBJTOSORT>
class idsorter : public std::binary_function<OBJTOSORT, OBJTOSORT, bool>{
public:
  inline bool operator()(const OBJTOSORT & left, const OBJTOSORT & right){
    return left.id < right.id;
  }
};

dd::InferenceResult::InferenceResult(long _nvars, long _nweights):
  assignments_free(new VariableValue[_nvars]),
  assignments_evid(new VariableValue[_nvars]),
  agg_means(new double[_nvars]),
  agg_nsamples(new double[_nvars]),
  weight_values(new double [_nweights]),
  weights_isfixed(new bool [_nweights]),
  nweights(_nweights),
  nvars(_nvars){}

void dd::InferenceResult::init(Variable * variables, Weight * const weights){

  ntallies = 0;
  for(long t=0;t<nvars;t++){
    const Variable & variable = variables[t];
    assignments_free[variable.id] = variable.assignment_free;
    assignments_evid[variable.id] = variable.assignment_evid;
    agg_means[variable.id] = 0.0;
    agg_nsamples[variable.id] = 0.0;
    if(variable.domain_type == DTYPE_MULTINOMIAL){
      //variable.n_start_i_tally = ntallies;
      ntallies += variable.upper_bound - variable.lower_bound + 1;
    }
  }

  multinomial_tallies = new int[ntallies];
  for(long i=0;i<ntallies;i++){
    multinomial_tallies[i] = 0;
  }

  for(long t=0;t<nweights;t++){
    const Weight & weight = weights[t];
    weight_values[weight.id] = weight.weight;
    weights_isfixed[weight.id] = weight.isfixed;
  }
}

bool dd::FactorGraph::is_usable(){
  return this->loading_finalized && this->safety_check_passed;
}

dd::FactorGraph::FactorGraph(long _n_var, long _n_factor, long _n_weight, long _n_edge) :
  variables(new Variable[_n_var]),
  factors(new Factor[_n_factor]),
  weights(new Weight[_n_weight]),
  n_var(_n_var), n_factor(_n_factor), n_weight(_n_weight),
  infrs(new InferenceResult(_n_var, _n_weight)),
  n_edge(_n_edge),
  factor_ids(new long[_n_edge]),
  factors_dups(new CompactFactor[_n_edge]),
  vifs(new VariableInFactor[_n_edge]),
  factors_dups_weightids(new int[_n_edge])
{
  this->loading_finalized = false;
  this->safety_check_passed = false;
  c_nvar = 0;
  c_nfactor = 0;
  c_nweight = 0;
  n_evid = 0;
  n_query = 0;
}

void dd::FactorGraph::copy_from(const FactorGraph * const p_other_fg){
  // copy each member from the given graph
  memcpy(variables, p_other_fg->variables, sizeof(Variable)*n_var);
  memcpy(factors, p_other_fg->factors, sizeof(Factor)*n_factor);
  memcpy(weights, p_other_fg->weights, sizeof(Weight)*n_weight);
  memcpy(factor_ids, p_other_fg->factor_ids, sizeof(long)*n_edge);
  memcpy(vifs, p_other_fg->vifs, sizeof(VariableInFactor)*n_edge);

  memcpy(factors_dups, p_other_fg->factors_dups, sizeof(CompactFactor)*n_edge);
  memcpy(factors_dups_weightids, p_other_fg->factors_dups_weightids, sizeof(int)*n_edge);

  c_nvar = p_other_fg->c_nvar;
  c_nfactor = p_other_fg->c_nfactor;
  c_nweight = p_other_fg->c_nweight;
  c_edge = p_other_fg->c_edge;
  loading_finalized = p_other_fg->loading_finalized;
  safety_check_passed = p_other_fg->safety_check_passed;

  infrs->init(variables, weights);
  infrs->ntallies = p_other_fg->infrs->ntallies;
  infrs->multinomial_tallies = new int[p_other_fg->infrs->ntallies];
  for(long i=0;i<infrs->ntallies;i++){
    infrs->multinomial_tallies[i] = p_other_fg->infrs->multinomial_tallies[i];
  }
}

long dd::FactorGraph::get_weightid(const VariableValue *assignments, const CompactFactor& fs, long vid, long proposal) {
  /**
   * The weight ids are aligned in a continuous region according
   * to the numerical order of variable values.
   * Say for two variables v1, v2, v3, with cardinality d. The numerical value is
   * v1 * d^2 + v2 * d + v3.
   */
  long weight_offset = 0;
  // for each variable in the factor
  for (long i = fs.n_start_i_vif; i < fs.n_start_i_vif + fs.n_variables; i++) {
    const VariableInFactor & vif = vifs[i];
    if (vif.vid == vid) {
      weight_offset = weight_offset * (variables[vif.vid].upper_bound+1) + proposal;
    } else {
      weight_offset = weight_offset * (variables[vif.vid].upper_bound+1) + assignments[vif.vid];
    }
  }
  long base_offset = &fs - factors_dups; // note c++ will auto scale by sizeof(CompactFactor)
  return *(factors_dups_weightids + base_offset) + weight_offset;
}

void dd::FactorGraph::update_weight(const Variable & variable){
  // corresponding factors and weights in a continous region
  CompactFactor * const fs = factors_dups + variable.n_start_i_factors;
  const int * const ws = factors_dups_weightids + variable.n_start_i_factors;
  // for each factor
  for(long i=0;i<variable.n_factors;i++){
    // boolean variable
    if (variable.domain_type == DTYPE_BOOLEAN) {
      // only update weight when it is not fixed
      if(infrs->weights_isfixed[ws[i]] == false){
        if(fs[i].func_id != 20){
          // stochastic gradient ascent
          // increment weight with stepsize * gradient of weight
          // gradient of weight = E[f|D] - E[f], where D is evidence variables,
          // f is the factor function, E[] is expectation. Expectation is calculated
          // using a sample of the variable.
          infrs->weight_values[ws[i]] +=
            stepsize * (this->template potential<false>(fs[i]) - this->template potential<true>(fs[i]));
        }else{

          const int & dimension = vifs[fs[i].n_start_i_vif].dimension;

          const long & cvid = vifs[fs[i].n_start_i_vif].vid;
          const long & wid = ws[i];
          const long & bvid = vifs[fs[i].n_start_i_vif+1].vid;

          const long assignments_evid_bvid = infrs->assignments_evid[bvid];
          const long assignments_free_bvid = infrs->assignments_free[bvid];

          if(assignments_evid_bvid != assignments_free_bvid){
            for(int j=0;j<dimension;j++){
              infrs->weight_values[wid + j] +=
                  stepsize * (assignments_evid_bvid * infrs->assignments_evid[cvid+j]
                    - assignments_free_bvid * infrs->assignments_free[cvid+j]);
            }
          }
        }
      }
    } else if (variable.domain_type == DTYPE_MULTINOMIAL) {
      // two weights need to be updated
      // sample with evidence fixed, I0, with variable assignment d0
      // sample without evidence unfixed, I1, with variable assigment d1
      // gradient of wd0 = f(I0) - I(d0==d1)f(I1)
      // gradient of wd1 = I(d0==d1)f(I0) - f(I1)
      if(fs[i].func_id != 20){
        long wid1 = get_weightid(infrs->assignments_evid, fs[i], -1, -1);
        long wid2 = get_weightid(infrs->assignments_free, fs[i], -1, -1);
        int equal = infrs->assignments_evid[variable.id] == infrs->assignments_free[variable.id];

        if(infrs->weights_isfixed[wid1] == false){
          infrs->weight_values[wid1] +=
            stepsize * (this->template potential<false>(fs[i]) - equal * this->template potential<true>(fs[i]));
        }

        if(infrs->weights_isfixed[wid2] == false){
          infrs->weight_values[wid2] +=
            stepsize * (equal * this->template potential<false>(fs[i]) - this->template potential<true>(fs[i]));
        }
      }else{

        const int & dimension = vifs[fs[i].n_start_i_vif].dimension;
        const long & cvid = vifs[fs[i].n_start_i_vif].vid;
        const long & bvid = vifs[fs[i].n_start_i_vif+1].vid;

        const long assignments_evid_bvid = infrs->assignments_evid[bvid];
        const long assignments_free_bvid = infrs->assignments_free[bvid];

        if(assignments_evid_bvid != assignments_free_bvid){

          // udpate the weight for assignments_evid_bvid
          long wid = ws[i] + dimension * assignments_evid_bvid;
          for(int j=0;j<dimension;j++){
            infrs->weight_values[wid + j] +=
                stepsize * (infrs->assignments_evid[cvid+j]);
          }

          // update the wight for assignments_free_bvid
          wid = ws[i] + dimension * assignments_free_bvid;
          for(int j=0;j<dimension;j++){
            infrs->weight_values[wid + j] +=
                stepsize * (-infrs->assignments_evid[cvid+j]);
          }

        }

      }
    }
  }
}

void dd::FactorGraph::load(const CmdParser & cmd){

  // get factor graph file names from command line arguments
  std::string weight_file = cmd.weight_file->getValue();
  std::string variable_file = cmd.variable_file->getValue();
  std::string factor_file = cmd.factor_file->getValue();
  std::string edge_file = cmd.edge_file->getValue();

  std::string filename_edges = edge_file;
  std::string filename_factors = factor_file;
  std::string filename_variables = variable_file;
  std::string filename_weights = weight_file;

  // load variables
  long long n_loaded = read_variables(filename_variables, *this);
  assert(n_loaded == n_var);
  std::cout << "LOADED VARIABLES: #" << n_loaded << std::endl;
  std::cout << "         N_QUERY: #" << n_query << std::endl;
  std::cout << "         N_EVID : #" << n_evid << std::endl;

  // load factors
  n_loaded = read_factors(filename_factors, *this);
  assert(n_loaded == n_factor);
  std::cout << "LOADED FACTORS: #" << n_loaded << std::endl;

  // load weights
  n_loaded = read_weights(filename_weights, *this);
  assert(n_loaded == n_weight);
  std::cout << "LOADED WEIGHTS: #" << n_loaded << std::endl;

  // sort the above components
  // NOTE This is very important, as read_edges assume variables,
  // factors and weights are ordered so that their id is the index
  // where they are stored in the array
  this->finalize_loading();

  // load edges
  n_loaded = read_edges(edge_file, *this);
  std::cout << "LOADED EDGES: #" << n_loaded << std::endl;

  // construct edge-based store
  this->safety_check();

  assert(this->is_usable() == true);

}

void dd::FactorGraph::finalize_loading(){
  // sort variables, factors, and weights by id
  std::sort(&variables[0], &variables[n_var], idsorter<Variable>());
  std::sort(&factors[0], &factors[n_factor], idsorter<Factor>());
  std::sort(&weights[0], &weights[n_weight], idsorter<Weight>());
  this->loading_finalized = true;
  infrs->init(variables, weights);
}

void dd::FactorGraph::safety_check(){
  // number of edges
  c_edge = 0;
  // put variables into the edge-based variable array vifs
  for(long i=0;i<n_factor;i++){
    Factor & factor = factors[i];
    factor.n_start_i_vif = c_edge;
    for(const VariableInFactor & vif : factor.tmp_variables){
      vifs[c_edge] = vif;
      c_edge ++;
    }
  }

  c_edge = 0;
  long ntallies = 0;
  // for each variable, put the factors into factor_dups
  for(long i=0;i<n_var;i++){
    Variable & variable = variables[i];
    variable.n_factors = variable.tmp_factor_ids.size();  // no edge count any more

    variable.n_start_i_factors = c_edge;
    if(variable.domain_type == DTYPE_MULTINOMIAL){
      variable.n_start_i_tally = ntallies;
      ntallies += variable.upper_bound - variable.lower_bound + 1;
    }
    for(const long & fid : variable.tmp_factor_ids){
      factor_ids[c_edge] = fid;
      factors_dups[c_edge].id = factors[fid].id;
      factors_dups[c_edge].func_id = factors[fid].func_id;
      factors_dups[c_edge].n_variables = factors[fid].n_variables;
      factors_dups[c_edge].n_start_i_vif = factors[fid].n_start_i_vif;
      factors_dups_weightids[c_edge] = factors[fid].weight_id;
      c_edge ++;
    }
  }

  // check whether variables, factors, and weights are stored
  // in the order of their id
  long s = n_var;
  for(long i=0;i<s;i++){
    assert(this->variables[i].id == i);
  }
  s = n_factor;
  for(long i=0;i<s;i++){
    assert(this->factors[i].id == i);
  }
  s = n_weight;
  for(long i=0;i<s;i++){
    assert(this->weights[i].id == i);
  }
  std::cout << "FACTOR GRAPH: Safety Checking Passed..." << std::endl;
  this->safety_check_passed = true;
}

<commit_msg>fix potential multinomial weight update problem<commit_after>
#include <iostream>
#include "io/binary_parser.h"
#include "dstruct/factor_graph/factor_graph.h"
#include "dstruct/factor_graph/factor.h"

template <class OBJTOSORT>
class idsorter : public std::binary_function<OBJTOSORT, OBJTOSORT, bool>{
public:
  inline bool operator()(const OBJTOSORT & left, const OBJTOSORT & right){
    return left.id < right.id;
  }
};

dd::InferenceResult::InferenceResult(long _nvars, long _nweights):
  assignments_free(new VariableValue[_nvars]),
  assignments_evid(new VariableValue[_nvars]),
  agg_means(new double[_nvars]),
  agg_nsamples(new double[_nvars]),
  weight_values(new double [_nweights]),
  weights_isfixed(new bool [_nweights]),
  nweights(_nweights),
  nvars(_nvars){}

void dd::InferenceResult::init(Variable * variables, Weight * const weights){

  ntallies = 0;
  for(long t=0;t<nvars;t++){
    const Variable & variable = variables[t];
    assignments_free[variable.id] = variable.assignment_free;
    assignments_evid[variable.id] = variable.assignment_evid;
    agg_means[variable.id] = 0.0;
    agg_nsamples[variable.id] = 0.0;
    if(variable.domain_type == DTYPE_MULTINOMIAL){
      //variable.n_start_i_tally = ntallies;
      ntallies += variable.upper_bound - variable.lower_bound + 1;
    }
  }

  multinomial_tallies = new int[ntallies];
  for(long i=0;i<ntallies;i++){
    multinomial_tallies[i] = 0;
  }

  for(long t=0;t<nweights;t++){
    const Weight & weight = weights[t];
    weight_values[weight.id] = weight.weight;
    weights_isfixed[weight.id] = weight.isfixed;
  }
}

bool dd::FactorGraph::is_usable(){
  return this->loading_finalized && this->safety_check_passed;
}

dd::FactorGraph::FactorGraph(long _n_var, long _n_factor, long _n_weight, long _n_edge) :
  variables(new Variable[_n_var]),
  factors(new Factor[_n_factor]),
  weights(new Weight[_n_weight]),
  n_var(_n_var), n_factor(_n_factor), n_weight(_n_weight),
  infrs(new InferenceResult(_n_var, _n_weight)),
  n_edge(_n_edge),
  factor_ids(new long[_n_edge]),
  factors_dups(new CompactFactor[_n_edge]),
  vifs(new VariableInFactor[_n_edge]),
  factors_dups_weightids(new int[_n_edge])
{
  this->loading_finalized = false;
  this->safety_check_passed = false;
  c_nvar = 0;
  c_nfactor = 0;
  c_nweight = 0;
  n_evid = 0;
  n_query = 0;
}

void dd::FactorGraph::copy_from(const FactorGraph * const p_other_fg){
  // copy each member from the given graph
  memcpy(variables, p_other_fg->variables, sizeof(Variable)*n_var);
  memcpy(factors, p_other_fg->factors, sizeof(Factor)*n_factor);
  memcpy(weights, p_other_fg->weights, sizeof(Weight)*n_weight);
  memcpy(factor_ids, p_other_fg->factor_ids, sizeof(long)*n_edge);
  memcpy(vifs, p_other_fg->vifs, sizeof(VariableInFactor)*n_edge);

  memcpy(factors_dups, p_other_fg->factors_dups, sizeof(CompactFactor)*n_edge);
  memcpy(factors_dups_weightids, p_other_fg->factors_dups_weightids, sizeof(int)*n_edge);

  c_nvar = p_other_fg->c_nvar;
  c_nfactor = p_other_fg->c_nfactor;
  c_nweight = p_other_fg->c_nweight;
  c_edge = p_other_fg->c_edge;
  loading_finalized = p_other_fg->loading_finalized;
  safety_check_passed = p_other_fg->safety_check_passed;

  infrs->init(variables, weights);
  infrs->ntallies = p_other_fg->infrs->ntallies;
  infrs->multinomial_tallies = new int[p_other_fg->infrs->ntallies];
  for(long i=0;i<infrs->ntallies;i++){
    infrs->multinomial_tallies[i] = p_other_fg->infrs->multinomial_tallies[i];
  }
}

long dd::FactorGraph::get_weightid(const VariableValue *assignments, const CompactFactor& fs, long vid, long proposal) {
  /**
   * The weight ids are aligned in a continuous region according
   * to the numerical order of variable values.
   * Say for two variables v1, v2, v3, with cardinality d. The numerical value is
   * v1 * d^2 + v2 * d + v3.
   */
  long weight_offset = 0;
  // for each variable in the factor
  for (long i = fs.n_start_i_vif; i < fs.n_start_i_vif + fs.n_variables; i++) {
    const VariableInFactor & vif = vifs[i];
    if (vif.vid == vid) {
      weight_offset = weight_offset * (variables[vif.vid].upper_bound+1) + proposal;
    } else {
      weight_offset = weight_offset * (variables[vif.vid].upper_bound+1) + assignments[vif.vid];
    }
  }
  long base_offset = &fs - factors_dups; // note c++ will auto scale by sizeof(CompactFactor)
  return *(factors_dups_weightids + base_offset) + weight_offset;
}

void dd::FactorGraph::update_weight(const Variable & variable){
  // corresponding factors and weights in a continous region
  CompactFactor * const fs = factors_dups + variable.n_start_i_factors;
  const int * const ws = factors_dups_weightids + variable.n_start_i_factors;
  // for each factor
  for(long i=0;i<variable.n_factors;i++){
    // boolean variable
    if (variable.domain_type == DTYPE_BOOLEAN) {
      // only update weight when it is not fixed
      if(infrs->weights_isfixed[ws[i]] == false){
        if(fs[i].func_id != 20){
          // stochastic gradient ascent
          // increment weight with stepsize * gradient of weight
          // gradient of weight = E[f|D] - E[f], where D is evidence variables,
          // f is the factor function, E[] is expectation. Expectation is calculated
          // using a sample of the variable.
          infrs->weight_values[ws[i]] +=
            stepsize * (this->template potential<false>(fs[i]) - this->template potential<true>(fs[i]));
        }else{

          const int & dimension = vifs[fs[i].n_start_i_vif].dimension;

          const long & cvid = vifs[fs[i].n_start_i_vif].vid;
          const long & wid = ws[i];
          const long & bvid = vifs[fs[i].n_start_i_vif+1].vid;

          const long assignments_evid_bvid = infrs->assignments_evid[bvid];
          const long assignments_free_bvid = infrs->assignments_free[bvid];

          if(assignments_evid_bvid != assignments_free_bvid){
            for(int j=0;j<dimension;j++){
              infrs->weight_values[wid + j] +=
                  stepsize * (assignments_evid_bvid * infrs->assignments_evid[cvid+j]
                    - assignments_free_bvid * infrs->assignments_free[cvid+j]);
            }
          }
        }
      }
    } else if (variable.domain_type == DTYPE_MULTINOMIAL) {
      // two weights need to be updated
      // sample with evidence fixed, I0, with corresponding weight w1
      // sample without evidence unfixed, I1, with corresponding weight w2
      // gradient of wd0 = f(I0) - I(w1==w2)f(I1)
      // gradient of wd1 = I(w1==w2)f(I0) - f(I1)
      if(fs[i].func_id != 20){
        long wid1 = get_weightid(infrs->assignments_evid, fs[i], -1, -1);
        long wid2 = get_weightid(infrs->assignments_free, fs[i], -1, -1);
        int equal = (wid1 == wid2);

        if(infrs->weights_isfixed[wid1] == false){
          infrs->weight_values[wid1] +=
            stepsize * (this->template potential<false>(fs[i]) - equal * this->template potential<true>(fs[i]));
        }

        if(infrs->weights_isfixed[wid2] == false){
          infrs->weight_values[wid2] +=
            stepsize * (equal * this->template potential<false>(fs[i]) - this->template potential<true>(fs[i]));
        }
      }else{

        const int & dimension = vifs[fs[i].n_start_i_vif].dimension;
        const long & cvid = vifs[fs[i].n_start_i_vif].vid;
        const long & bvid = vifs[fs[i].n_start_i_vif+1].vid;

        const long assignments_evid_bvid = infrs->assignments_evid[bvid];
        const long assignments_free_bvid = infrs->assignments_free[bvid];

        if(assignments_evid_bvid != assignments_free_bvid){

          // udpate the weight for assignments_evid_bvid
          long wid = ws[i] + dimension * assignments_evid_bvid;
          for(int j=0;j<dimension;j++){
            infrs->weight_values[wid + j] +=
                stepsize * (infrs->assignments_evid[cvid+j]);
          }

          // update the wight for assignments_free_bvid
          wid = ws[i] + dimension * assignments_free_bvid;
          for(int j=0;j<dimension;j++){
            infrs->weight_values[wid + j] +=
                stepsize * (-infrs->assignments_evid[cvid+j]);
          }

        }

      }
    }
  }
}

void dd::FactorGraph::load(const CmdParser & cmd){

  // get factor graph file names from command line arguments
  std::string weight_file = cmd.weight_file->getValue();
  std::string variable_file = cmd.variable_file->getValue();
  std::string factor_file = cmd.factor_file->getValue();
  std::string edge_file = cmd.edge_file->getValue();

  std::string filename_edges = edge_file;
  std::string filename_factors = factor_file;
  std::string filename_variables = variable_file;
  std::string filename_weights = weight_file;

  // load variables
  long long n_loaded = read_variables(filename_variables, *this);
  assert(n_loaded == n_var);
  std::cout << "LOADED VARIABLES: #" << n_loaded << std::endl;
  std::cout << "         N_QUERY: #" << n_query << std::endl;
  std::cout << "         N_EVID : #" << n_evid << std::endl;

  // load factors
  n_loaded = read_factors(filename_factors, *this);
  assert(n_loaded == n_factor);
  std::cout << "LOADED FACTORS: #" << n_loaded << std::endl;

  // load weights
  n_loaded = read_weights(filename_weights, *this);
  assert(n_loaded == n_weight);
  std::cout << "LOADED WEIGHTS: #" << n_loaded << std::endl;

  // sort the above components
  // NOTE This is very important, as read_edges assume variables,
  // factors and weights are ordered so that their id is the index
  // where they are stored in the array
  this->finalize_loading();

  // load edges
  n_loaded = read_edges(edge_file, *this);
  std::cout << "LOADED EDGES: #" << n_loaded << std::endl;

  // construct edge-based store
  this->safety_check();

  assert(this->is_usable() == true);

}

void dd::FactorGraph::finalize_loading(){
  // sort variables, factors, and weights by id
  std::sort(&variables[0], &variables[n_var], idsorter<Variable>());
  std::sort(&factors[0], &factors[n_factor], idsorter<Factor>());
  std::sort(&weights[0], &weights[n_weight], idsorter<Weight>());
  this->loading_finalized = true;
  infrs->init(variables, weights);
}

void dd::FactorGraph::safety_check(){
  // number of edges
  c_edge = 0;
  // put variables into the edge-based variable array vifs
  for(long i=0;i<n_factor;i++){
    Factor & factor = factors[i];
    factor.n_start_i_vif = c_edge;
    for(const VariableInFactor & vif : factor.tmp_variables){
      vifs[c_edge] = vif;
      c_edge ++;
    }
  }

  c_edge = 0;
  long ntallies = 0;
  // for each variable, put the factors into factor_dups
  for(long i=0;i<n_var;i++){
    Variable & variable = variables[i];
    variable.n_factors = variable.tmp_factor_ids.size();  // no edge count any more

    variable.n_start_i_factors = c_edge;
    if(variable.domain_type == DTYPE_MULTINOMIAL){
      variable.n_start_i_tally = ntallies;
      ntallies += variable.upper_bound - variable.lower_bound + 1;
    }
    for(const long & fid : variable.tmp_factor_ids){
      factor_ids[c_edge] = fid;
      factors_dups[c_edge].id = factors[fid].id;
      factors_dups[c_edge].func_id = factors[fid].func_id;
      factors_dups[c_edge].n_variables = factors[fid].n_variables;
      factors_dups[c_edge].n_start_i_vif = factors[fid].n_start_i_vif;
      factors_dups_weightids[c_edge] = factors[fid].weight_id;
      c_edge ++;
    }
  }

  // check whether variables, factors, and weights are stored
  // in the order of their id
  long s = n_var;
  for(long i=0;i<s;i++){
    assert(this->variables[i].id == i);
  }
  s = n_factor;
  for(long i=0;i<s;i++){
    assert(this->factors[i].id == i);
  }
  s = n_weight;
  for(long i=0;i<s;i++){
    assert(this->weights[i].id == i);
  }
  std::cout << "FACTOR GRAPH: Safety Checking Passed..." << std::endl;
  this->safety_check_passed = true;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: comm_bas.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 11:18:45 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _COMM_BAS_HXX
#define _COMM_BAS_HXX

#ifndef __SBX_SBX_FACTORY_HXX //autogen
#include <basic/sbxfac.hxx>
#endif
#ifndef __SBX_SBXVARIABLE_HXX //autogen
#include <basic/sbxvar.hxx>
#endif
#ifndef _SBX_SBXOBJECT_HXX //autogen
#include <basic/sbxobj.hxx>
#endif

class CommunicationManagerClientViaSocket;
class CommunicationLink;

class CommunicationWrapper : public SbxObject   // Einer fr Manager und Links
{
    // Definition eines Tabelleneintrags. Dies wird hier gemacht,
    // da dadurch die Methoden und Properties als private deklariert
    // werden koennen.
#if defined ( ICC ) || defined ( HPUX ) || defined ( C50 ) || defined ( C52 )
public:
#endif
    typedef void( CommunicationWrapper::*pMeth )
        ( SbxVariable* pThis, SbxArray* pArgs, BOOL bWrite );
#if defined ( ICC ) || defined ( HPUX )
private:
#endif

    struct Methods {
        const char* pName;      // Name des Eintrags
        SbxDataType eType;      // Datentyp
        pMeth pFunc;            // Function Pointer
        short nArgs;            // Argumente und Flags
    };
    static Methods aManagerMethods[];   // Methodentabelle
    static Methods aLinkMethods[];      // Methodentabelle
    Methods *m_pMethods;    // Aktuelle Methodentabelle

    // Methoden
    //      Manager
    void MStartCommunication( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MStopAllCommunication( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MIsCommunicationRunning( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MGetMyName( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MIsLinkValid( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MSetCommunicationEventHandler( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );

    //      Link
    void LStopCommunication( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void LGetMyName( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void LGetHostName( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void LSend( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void LGetString( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );

    // Interne Member und Methoden
    CommunicationManagerClientViaSocket *m_pManager;
    CommunicationLink *m_pLink;
    BOOL m_bIsManager;  // Ist es kein Manager, so ist es ein Link

    // Kram fr Manager
    DECL_LINK( Open, CommunicationLink* );
    DECL_LINK( Close, CommunicationLink* );
    DECL_LINK( Data, CommunicationLink* );
    void Events( String aType, CommunicationLink* pLink );
    BOOL m_bCatchOpen;
    CommunicationLink *m_pNewLink;
    String m_aEventHandlerName;

    using SbxVariable::GetInfo;
    // Infoblock auffuellen
    SbxInfo* GetInfo( short nIdx );

    // Broadcaster Notification
    virtual void SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
                             const SfxHint& rHint, const TypeId& rHintType );
public:
    CommunicationWrapper( const String& );
    CommunicationWrapper( CommunicationLink *pThisLink );
    ~CommunicationWrapper();
    // Suchen eines Elements
    virtual SbxVariable* Find( const String&, SbxClassType );

    CommunicationLink* GetCommunicationLink() { return m_pLink; }
};

// Die dazugehoerige Factory:

class CommunicationFactory : public SbxFactory
{
public:
    virtual SbxObject* CreateObject( const String& );
};

#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.5.80); FILE MERGED 2008/04/01 15:00:04 thb 1.5.80.2: #i85898# Stripping all external header guards 2008/03/28 16:03:40 rt 1.5.80.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: comm_bas.hxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _COMM_BAS_HXX
#define _COMM_BAS_HXX

#include <basic/sbxfac.hxx>
#ifndef __SBX_SBXVARIABLE_HXX //autogen
#include <basic/sbxvar.hxx>
#endif
#include <basic/sbxobj.hxx>

class CommunicationManagerClientViaSocket;
class CommunicationLink;

class CommunicationWrapper : public SbxObject   // Einer fr Manager und Links
{
    // Definition eines Tabelleneintrags. Dies wird hier gemacht,
    // da dadurch die Methoden und Properties als private deklariert
    // werden koennen.
#if defined ( ICC ) || defined ( HPUX ) || defined ( C50 ) || defined ( C52 )
public:
#endif
    typedef void( CommunicationWrapper::*pMeth )
        ( SbxVariable* pThis, SbxArray* pArgs, BOOL bWrite );
#if defined ( ICC ) || defined ( HPUX )
private:
#endif

    struct Methods {
        const char* pName;      // Name des Eintrags
        SbxDataType eType;      // Datentyp
        pMeth pFunc;            // Function Pointer
        short nArgs;            // Argumente und Flags
    };
    static Methods aManagerMethods[];   // Methodentabelle
    static Methods aLinkMethods[];      // Methodentabelle
    Methods *m_pMethods;    // Aktuelle Methodentabelle

    // Methoden
    //      Manager
    void MStartCommunication( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MStopAllCommunication( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MIsCommunicationRunning( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MGetMyName( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MIsLinkValid( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void MSetCommunicationEventHandler( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );

    //      Link
    void LStopCommunication( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void LGetMyName( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void LGetHostName( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void LSend( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );
    void LGetString( SbxVariable* pVar, SbxArray* pPar, BOOL bWrite );

    // Interne Member und Methoden
    CommunicationManagerClientViaSocket *m_pManager;
    CommunicationLink *m_pLink;
    BOOL m_bIsManager;  // Ist es kein Manager, so ist es ein Link

    // Kram fr Manager
    DECL_LINK( Open, CommunicationLink* );
    DECL_LINK( Close, CommunicationLink* );
    DECL_LINK( Data, CommunicationLink* );
    void Events( String aType, CommunicationLink* pLink );
    BOOL m_bCatchOpen;
    CommunicationLink *m_pNewLink;
    String m_aEventHandlerName;

    using SbxVariable::GetInfo;
    // Infoblock auffuellen
    SbxInfo* GetInfo( short nIdx );

    // Broadcaster Notification
    virtual void SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
                             const SfxHint& rHint, const TypeId& rHintType );
public:
    CommunicationWrapper( const String& );
    CommunicationWrapper( CommunicationLink *pThisLink );
    ~CommunicationWrapper();
    // Suchen eines Elements
    virtual SbxVariable* Find( const String&, SbxClassType );

    CommunicationLink* GetCommunicationLink() { return m_pLink; }
};

// Die dazugehoerige Factory:

class CommunicationFactory : public SbxFactory
{
public:
    virtual SbxObject* CreateObject( const String& );
};

#endif
<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This 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.  See file COPYING.
 *
 */

#include <sys/stat.h>
#include <iostream>
#include <string>
using namespace std;

#include "config.h"

#include "mon/MonMap.h"
#include "mon/MonClient.h"
#include "mon/mon_types.h"
#include "mon/ClientMonitor.h"
#include "mon/PGMap.h"
#include "mon/ClientMap.h"
#include "osd/OSDMap.h"
#include "mds/MDSMap.h"
#include "msg/SimpleMessenger.h"
#include "messages/MMonCommand.h"
#include "messages/MMonObserve.h"
#include "messages/MMonObserveNotify.h"
#include "include/LogEntry.h"

#include "common/Timer.h"

#ifndef DARWIN
#include <envz.h>
#endif // DARWIN

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <sstream>

Mutex lock("cobserver.cc lock");
Messenger *messenger = 0;

static PGMap pgmap;
static MonMap monmap;
static MDSMap mdsmap;
static OSDMap osdmap;
static ClientMap clientmap;

version_t map_ver[PAXOS_NUM];

SafeTimer timer(lock);

void handle_notify(MMonObserveNotify *notify)
{
  generic_dout(1) << notify->get_source() << " -> " << get_paxos_name(notify->machine_id) << " v" << notify->ver
		  << (notify->is_incremental ? " (i)" : "") << dendl;

  if (!notify->is_incremental &&
      map_ver[notify->machine_id] >= notify->ver)
    return;

  switch (notify->machine_id) {
  case PAXOS_PGMAP:
    {
      bufferlist::iterator p = notify->bl.begin();
      if (notify->is_incremental) {
	PGMap::Incremental inc;
	inc.decode(p);
	pgmap.apply_incremental(inc);
      } else {
	pgmap.decode(p);
      }
      dout(0) << "    pg " << pgmap << dendl;
      break;
    }

  case PAXOS_MDSMAP:
    mdsmap.decode(notify->bl);
    dout(0) << "   mds " << mdsmap << dendl;
    break;

  case PAXOS_OSDMAP:
    {
      if (notify->is_incremental) {
	OSDMap::Incremental inc(notify->bl);
	osdmap.apply_incremental(inc);
      } else {
	osdmap.decode(notify->bl);
      }
      dout(0) << "   osd " << osdmap << dendl;
    }
    break;

  case PAXOS_CLIENTMAP:
    {
      bufferlist::iterator p = notify->bl.begin();
      if (notify->is_incremental) {
	ClientMap::Incremental inc;
	inc.decode(p);
	clientmap.apply_incremental(inc);
      } else
	clientmap.decode(p);
      dout(0) << "client " << clientmap << dendl;
    }
    break;

  case PAXOS_LOG:
    {
      LogEntry le;
      bufferlist::iterator p = notify->bl.begin();
      le.decode(p);
      dout(0) << "   log " << le << dendl;
      break;
    }
  }

  map_ver[notify->machine_id] = notify->ver;
}

class Admin : public Dispatcher {
  bool dispatch_impl(Message *m) {
    switch (m->get_type()) {
    case MSG_MON_OBSERVE_NOTIFY:
      handle_notify((MMonObserveNotify *)m);
      break;
    default:
      return false;
    }
    return true;
  }
} dispatcher;

void usage()
{
  cerr << "usage: cobserver [options] monhost] command" << std::endl;
  cerr << "Options:" << std::endl;
  cerr << "   -m monhost        -- specify monitor hostname or ip" << std::endl;
  exit(1);
}

static void send_requests();

class C_ObserverRefresh : public Context {
public:
  C_ObserverRefresh() {}
  void finish(int r) {
    send_requests();
  }
};

static void send_requests()
{
  bufferlist indata;
  for (int i=0; i<PAXOS_NUM; i++) {
    MMonObserve *m = new MMonObserve(monmap.fsid, i, map_ver[i]);
    m->set_data(indata);
    int mon = monmap.pick_mon();
    generic_dout(1) << "mon" << mon << " <- observe " << get_paxos_name(i) << dendl;
    messenger->send_message(m, monmap.get_inst(mon));
  }

  C_ObserverRefresh *observe_refresh_event = new C_ObserverRefresh();
  timer.add_event_after(g_conf.paxos_observer_timeout/2, observe_refresh_event);
}

int main(int argc, const char **argv, const char *envp[]) {

  vector<const char*> args;
  argv_to_vec(argc, argv, args);
  env_to_vec(args);
  parse_config_options(args);

  vec_to_argv(args, argc, argv);

  srand(getpid());

  vector<const char*> nargs;

  // get monmap
  MonClient mc;
  if (mc.get_monmap(&monmap) < 0)
    return -1;
   memset(map_ver, 0, sizeof(map_ver));

  // start up network
  rank.bind();
  g_conf.daemonize = false; // not us!
  messenger = rank.register_entity(entity_name_t::ADMIN());
  messenger->set_dispatcher(&dispatcher);

  rank.start();
  rank.set_policy(entity_name_t::TYPE_MON, Rank::Policy::lossy_fail_after(1.0));

  lock.Lock();
  send_requests();
  lock.Unlock();

  // wait for messenger to finish
  rank.wait();
  messenger->destroy();
  return 0;
}

<commit_msg>cobserver: simplify headers<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This 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.  See file COPYING.
 *
 */

#include <sys/stat.h>
#include <iostream>
#include <string>
using namespace std;

#include "config.h"

#include "mon/MonMap.h"
#include "mon/MonClient.h"
#include "mon/mon_types.h"

#include "mon/ClientMap.h"
#include "mon/PGMap.h"
#include "mon/ClientMap.h"
#include "osd/OSDMap.h"
#include "mds/MDSMap.h"
#include "include/LogEntry.h"

#include "msg/SimpleMessenger.h"

#include "messages/MMonObserve.h"
#include "messages/MMonObserveNotify.h"

#include "common/Timer.h"

#ifndef DARWIN
#include <envz.h>
#endif // DARWIN

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <sstream>

Mutex lock("cobserver.cc lock");
Messenger *messenger = 0;

static PGMap pgmap;
static MonMap monmap;
static MDSMap mdsmap;
static OSDMap osdmap;
static ClientMap clientmap;

version_t map_ver[PAXOS_NUM];

SafeTimer timer(lock);

void handle_notify(MMonObserveNotify *notify)
{
  generic_dout(1) << notify->get_source() << " -> " << get_paxos_name(notify->machine_id) << " v" << notify->ver
		  << (notify->is_incremental ? " (i)" : "") << dendl;

  if (!notify->is_incremental &&
      map_ver[notify->machine_id] >= notify->ver)
    return;

  switch (notify->machine_id) {
  case PAXOS_PGMAP:
    {
      bufferlist::iterator p = notify->bl.begin();
      if (notify->is_incremental) {
	PGMap::Incremental inc;
	inc.decode(p);
	pgmap.apply_incremental(inc);
      } else {
	pgmap.decode(p);
      }
      dout(0) << "    pg " << pgmap << dendl;
      break;
    }

  case PAXOS_MDSMAP:
    mdsmap.decode(notify->bl);
    dout(0) << "   mds " << mdsmap << dendl;
    break;

  case PAXOS_OSDMAP:
    {
      if (notify->is_incremental) {
	OSDMap::Incremental inc(notify->bl);
	osdmap.apply_incremental(inc);
      } else {
	osdmap.decode(notify->bl);
      }
      dout(0) << "   osd " << osdmap << dendl;
    }
    break;

  case PAXOS_CLIENTMAP:
    {
      bufferlist::iterator p = notify->bl.begin();
      if (notify->is_incremental) {
	ClientMap::Incremental inc;
	inc.decode(p);
	clientmap.apply_incremental(inc);
      } else
	clientmap.decode(p);
      dout(0) << "client " << clientmap << dendl;
    }
    break;

  case PAXOS_LOG:
    {
      LogEntry le;
      bufferlist::iterator p = notify->bl.begin();
      le.decode(p);
      dout(0) << "   log " << le << dendl;
      break;
    }
  }

  map_ver[notify->machine_id] = notify->ver;
}

class Admin : public Dispatcher {
  bool dispatch_impl(Message *m) {
    switch (m->get_type()) {
    case MSG_MON_OBSERVE_NOTIFY:
      handle_notify((MMonObserveNotify *)m);
      break;
    default:
      return false;
    }
    return true;
  }
} dispatcher;

void usage()
{
  cerr << "usage: cobserver [options] monhost] command" << std::endl;
  cerr << "Options:" << std::endl;
  cerr << "   -m monhost        -- specify monitor hostname or ip" << std::endl;
  exit(1);
}

static void send_requests();

class C_ObserverRefresh : public Context {
public:
  C_ObserverRefresh() {}
  void finish(int r) {
    send_requests();
  }
};

static void send_requests()
{
  bufferlist indata;
  for (int i=0; i<PAXOS_NUM; i++) {
    MMonObserve *m = new MMonObserve(monmap.fsid, i, map_ver[i]);
    m->set_data(indata);
    int mon = monmap.pick_mon();
    generic_dout(1) << "mon" << mon << " <- observe " << get_paxos_name(i) << dendl;
    messenger->send_message(m, monmap.get_inst(mon));
  }

  C_ObserverRefresh *observe_refresh_event = new C_ObserverRefresh();
  timer.add_event_after(g_conf.paxos_observer_timeout/2, observe_refresh_event);
}

int main(int argc, const char **argv, const char *envp[]) {

  vector<const char*> args;
  argv_to_vec(argc, argv, args);
  env_to_vec(args);
  parse_config_options(args);

  vec_to_argv(args, argc, argv);

  srand(getpid());

  vector<const char*> nargs;

  // get monmap
  MonClient mc;
  if (mc.get_monmap(&monmap) < 0)
    return -1;
   memset(map_ver, 0, sizeof(map_ver));

  // start up network
  rank.bind();
  g_conf.daemonize = false; // not us!
  messenger = rank.register_entity(entity_name_t::ADMIN());
  messenger->set_dispatcher(&dispatcher);

  rank.start();
  rank.set_policy(entity_name_t::TYPE_MON, Rank::Policy::lossy_fail_after(1.0));

  lock.Lock();
  send_requests();
  lock.Unlock();

  // wait for messenger to finish
  rank.wait();
  messenger->destroy();
  return 0;
}

<|endoftext|>


<commit_before><commit_msg>Revert "Make sure to dispose services supporting the XComponent protocol"<commit_after><|endoftext|>


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

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_model_test_utils.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/common/chrome_paths.h"
#include "content/common/json_value_serializer.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

const char kUrl1Title[] = "url1";
const char kUrl1Url[] = "http://www.url1.com";
const char kUrl2Title[] = "url2";
const char kUrl2Url[] = "http://www.url2.com";
const char kUrl3Title[] = "url3";
const char kUrl3Url[] = "http://www.url3.com";
const char kUrl4Title[] = "url4";
const char kUrl4Url[] = "http://www.url4.com";
const char kFolder1Title[] = "folder1";
const char kFolder2Title[] = "folder2";

// Helper to get a mutable bookmark node.
static BookmarkNode* AsMutable(const BookmarkNode* node) {
  return const_cast<BookmarkNode*>(node);
}

}  // anonymous namespace

class BookmarkCodecTest : public testing::Test {
 protected:
  // Helpers to create bookmark models with different data.
  BookmarkModel* CreateTestModel1() {
    scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
    const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
    model->AddURL(bookmark_bar, 0, ASCIIToUTF16(kUrl1Title), GURL(kUrl1Url));
    return model.release();
  }
  BookmarkModel* CreateTestModel2() {
    scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
    const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
    model->AddURL(bookmark_bar, 0, ASCIIToUTF16(kUrl1Title), GURL(kUrl1Url));
    model->AddURL(bookmark_bar, 1, ASCIIToUTF16(kUrl2Title), GURL(kUrl2Url));
    return model.release();
  }
  BookmarkModel* CreateTestModel3() {
    scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
    const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
    model->AddURL(bookmark_bar, 0, ASCIIToUTF16(kUrl1Title), GURL(kUrl1Url));
    const BookmarkNode* folder1 = model->AddFolder(bookmark_bar, 1,
                                                   ASCIIToUTF16(kFolder1Title));
    model->AddURL(folder1, 0, ASCIIToUTF16(kUrl2Title), GURL(kUrl2Url));
    return model.release();
  }

  void GetBookmarksBarChildValue(Value* value,
                                 size_t index,
                                 DictionaryValue** result_value) {
    ASSERT_EQ(Value::TYPE_DICTIONARY, value->GetType());

    DictionaryValue* d_value = static_cast<DictionaryValue*>(value);
    Value* roots;
    ASSERT_TRUE(d_value->Get(BookmarkCodec::kRootsKey, &roots));
    ASSERT_EQ(Value::TYPE_DICTIONARY, roots->GetType());

    DictionaryValue* roots_d_value = static_cast<DictionaryValue*>(roots);
    Value* bb_value;
    ASSERT_TRUE(roots_d_value->Get(BookmarkCodec::kRootFolderNameKey,
                                   &bb_value));
    ASSERT_EQ(Value::TYPE_DICTIONARY, bb_value->GetType());

    DictionaryValue* bb_d_value = static_cast<DictionaryValue*>(bb_value);
    Value* bb_children_value;
    ASSERT_TRUE(bb_d_value->Get(BookmarkCodec::kChildrenKey,
                                &bb_children_value));
    ASSERT_EQ(Value::TYPE_LIST, bb_children_value->GetType());

    ListValue* bb_children_l_value = static_cast<ListValue*>(bb_children_value);
    Value* child_value;
    ASSERT_TRUE(bb_children_l_value->Get(index, &child_value));
    ASSERT_EQ(Value::TYPE_DICTIONARY, child_value->GetType());

    *result_value = static_cast<DictionaryValue*>(child_value);
  }

  Value* EncodeHelper(BookmarkModel* model, std::string* checksum) {
    BookmarkCodec encoder;
    // Computed and stored checksums should be empty.
    EXPECT_EQ("", encoder.computed_checksum());
    EXPECT_EQ("", encoder.stored_checksum());

    scoped_ptr<Value> value(encoder.Encode(model));
    const std::string& computed_checksum = encoder.computed_checksum();
    const std::string& stored_checksum = encoder.stored_checksum();

    // Computed and stored checksums should not be empty and should be equal.
    EXPECT_FALSE(computed_checksum.empty());
    EXPECT_FALSE(stored_checksum.empty());
    EXPECT_EQ(computed_checksum, stored_checksum);

    *checksum = computed_checksum;
    return value.release();
  }

  bool Decode(BookmarkCodec* codec, BookmarkModel* model, const Value& value) {
    int64 max_id;
    bool result = codec->Decode(AsMutable(model->GetBookmarkBarNode()),
                                AsMutable(model->other_node()),
                                AsMutable(model->synced_node()),
                                &max_id, value);
    model->set_next_node_id(max_id);
    return result;
  }

  BookmarkModel* DecodeHelper(const Value& value,
                              const std::string& expected_stored_checksum,
                              std::string* computed_checksum,
                              bool expected_changes) {
    BookmarkCodec decoder;
    // Computed and stored checksums should be empty.
    EXPECT_EQ("", decoder.computed_checksum());
    EXPECT_EQ("", decoder.stored_checksum());

    scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
    EXPECT_TRUE(Decode(&decoder, model.get(), value));

    *computed_checksum = decoder.computed_checksum();
    const std::string& stored_checksum = decoder.stored_checksum();

    // Computed and stored checksums should not be empty.
    EXPECT_FALSE(computed_checksum->empty());
    EXPECT_FALSE(stored_checksum.empty());

    // Stored checksum should be as expected.
    EXPECT_EQ(expected_stored_checksum, stored_checksum);

    // The two checksums should be equal if expected_changes is true; otherwise
    // they should be different.
    if (expected_changes)
      EXPECT_NE(*computed_checksum, stored_checksum);
    else
      EXPECT_EQ(*computed_checksum, stored_checksum);

    return model.release();
  }

  void CheckIDs(const BookmarkNode* node, std::set<int64>* assigned_ids) {
    DCHECK(node);
    int64 node_id = node->id();
    EXPECT_TRUE(assigned_ids->find(node_id) == assigned_ids->end());
    assigned_ids->insert(node_id);
    for (int i = 0; i < node->child_count(); ++i)
      CheckIDs(node->GetChild(i), assigned_ids);
  }

  void ExpectIDsUnique(BookmarkModel* model) {
    std::set<int64> assigned_ids;
    CheckIDs(model->GetBookmarkBarNode(), &assigned_ids);
    CheckIDs(model->other_node(), &assigned_ids);
    CheckIDs(model->synced_node(), &assigned_ids);
  }
};

TEST_F(BookmarkCodecTest, ChecksumEncodeDecodeTest) {
  scoped_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  std::string enc_checksum;
  scoped_ptr<Value> value(EncodeHelper(model_to_encode.get(), &enc_checksum));

  EXPECT_TRUE(value.get() != NULL);

  std::string dec_checksum;
  scoped_ptr<BookmarkModel> decoded_model(DecodeHelper(
      *value.get(), enc_checksum, &dec_checksum, false));
}

TEST_F(BookmarkCodecTest, ChecksumEncodeIdenticalModelsTest) {
  // Encode two identical models and make sure the check-sums are same as long
  // as the data is the same.
  scoped_ptr<BookmarkModel> model1(CreateTestModel1());
  std::string enc_checksum1;
  scoped_ptr<Value> value1(EncodeHelper(model1.get(), &enc_checksum1));
  EXPECT_TRUE(value1.get() != NULL);

  scoped_ptr<BookmarkModel> model2(CreateTestModel1());
  std::string enc_checksum2;
  scoped_ptr<Value> value2(EncodeHelper(model2.get(), &enc_checksum2));
  EXPECT_TRUE(value2.get() != NULL);

  ASSERT_EQ(enc_checksum1, enc_checksum2);
}

TEST_F(BookmarkCodecTest, ChecksumManualEditTest) {
  scoped_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  std::string enc_checksum;
  scoped_ptr<Value> value(EncodeHelper(model_to_encode.get(), &enc_checksum));

  EXPECT_TRUE(value.get() != NULL);

  // Change something in the encoded value before decoding it.
  DictionaryValue* child1_value;
  GetBookmarksBarChildValue(value.get(), 0, &child1_value);
  std::string title;
  ASSERT_TRUE(child1_value->GetString(BookmarkCodec::kNameKey, &title));
  child1_value->SetString(BookmarkCodec::kNameKey, title + "1");

  std::string dec_checksum;
  scoped_ptr<BookmarkModel> decoded_model1(DecodeHelper(
      *value.get(), enc_checksum, &dec_checksum, true));

  // Undo the change and make sure the checksum is same as original.
  child1_value->SetString(BookmarkCodec::kNameKey, title);
  scoped_ptr<BookmarkModel> decoded_model2(DecodeHelper(
      *value.get(), enc_checksum, &dec_checksum, false));
}

TEST_F(BookmarkCodecTest, ChecksumManualEditIDsTest) {
  scoped_ptr<BookmarkModel> model_to_encode(CreateTestModel3());

  // The test depends on existence of multiple children under bookmark bar, so
  // make sure that's the case.
  int bb_child_count = model_to_encode->GetBookmarkBarNode()->child_count();
  ASSERT_GT(bb_child_count, 1);

  std::string enc_checksum;
  scoped_ptr<Value> value(EncodeHelper(model_to_encode.get(), &enc_checksum));

  EXPECT_TRUE(value.get() != NULL);

  // Change IDs for all children of bookmark bar to be 1.
  DictionaryValue* child_value;
  for (int i = 0; i < bb_child_count; ++i) {
    GetBookmarksBarChildValue(value.get(), i, &child_value);
    std::string id;
    ASSERT_TRUE(child_value->GetString(BookmarkCodec::kIdKey, &id));
    child_value->SetString(BookmarkCodec::kIdKey, "1");
  }

  std::string dec_checksum;
  scoped_ptr<BookmarkModel> decoded_model(DecodeHelper(
      *value.get(), enc_checksum, &dec_checksum, true));

  ExpectIDsUnique(decoded_model.get());

  // add a few extra nodes to bookmark model and make sure IDs are still uniuqe.
  const BookmarkNode* bb_node = decoded_model->GetBookmarkBarNode();
  decoded_model->AddURL(bb_node, 0, ASCIIToUTF16("new url1"),
                        GURL("http://newurl1.com"));
  decoded_model->AddURL(bb_node, 0, ASCIIToUTF16("new url2"),
                        GURL("http://newurl2.com"));

  ExpectIDsUnique(decoded_model.get());
}

TEST_F(BookmarkCodecTest, PersistIDsTest) {
  scoped_ptr<BookmarkModel> model_to_encode(CreateTestModel3());
  BookmarkCodec encoder;
  scoped_ptr<Value> model_value(encoder.Encode(model_to_encode.get()));

  BookmarkModel decoded_model(NULL);
  BookmarkCodec decoder;
  ASSERT_TRUE(Decode(&decoder, &decoded_model, *model_value.get()));
  BookmarkModelTestUtils::AssertModelsEqual(model_to_encode.get(),
                                            &decoded_model,
                                            true);

  // Add a couple of more items to the decoded bookmark model and make sure
  // ID persistence is working properly.
  const BookmarkNode* bookmark_bar = decoded_model.GetBookmarkBarNode();
  decoded_model.AddURL(
      bookmark_bar, bookmark_bar->child_count(), ASCIIToUTF16(kUrl3Title),
      GURL(kUrl3Url));
  const BookmarkNode* folder2_node = decoded_model.AddFolder(
      bookmark_bar, bookmark_bar->child_count(), ASCIIToUTF16(kFolder2Title));
  decoded_model.AddURL(folder2_node, 0, ASCIIToUTF16(kUrl4Title),
                       GURL(kUrl4Url));

  BookmarkCodec encoder2;
  scoped_ptr<Value> model_value2(encoder2.Encode(&decoded_model));

  BookmarkModel decoded_model2(NULL);
  BookmarkCodec decoder2;
  ASSERT_TRUE(Decode(&decoder2, &decoded_model2, *model_value2.get()));
  BookmarkModelTestUtils::AssertModelsEqual(&decoded_model,
                                            &decoded_model2,
                                            true);
}

TEST_F(BookmarkCodecTest, CanDecodeModelWithoutSyncedBookmarks) {
  FilePath test_data_directory;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory));
  FilePath test_file = test_data_directory.AppendASCII(
      "bookmarks/model_without_sync.json");
  ASSERT_TRUE(file_util::PathExists(test_file));

  JSONFileValueSerializer serializer(test_file);
  scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL));

  BookmarkModel decoded_model(NULL);
  BookmarkCodec decoder;
  ASSERT_TRUE(Decode(&decoder, &decoded_model, *root.get()));
  ExpectIDsUnique(&decoded_model);

  const BookmarkNode* bbn = decoded_model.GetBookmarkBarNode();
  ASSERT_EQ(1, bbn->child_count());

  const BookmarkNode* child = bbn->GetChild(0);
  EXPECT_EQ(BookmarkNode::FOLDER, child->type());
  EXPECT_EQ(ASCIIToUTF16("Folder A"), child->GetTitle());
  ASSERT_EQ(1, child->child_count());

  child = child->GetChild(0);
  EXPECT_EQ(BookmarkNode::URL, child->type());
  EXPECT_EQ(ASCIIToUTF16("Bookmark Manager"), child->GetTitle());

  const BookmarkNode* other = decoded_model.other_node();
  ASSERT_EQ(1, other->child_count());

  child = other->GetChild(0);
  EXPECT_EQ(BookmarkNode::FOLDER, child->type());
  EXPECT_EQ(ASCIIToUTF16("Folder B"), child->GetTitle());
  ASSERT_EQ(1, child->child_count());

  child = child->GetChild(0);
  EXPECT_EQ(BookmarkNode::URL, child->type());
  EXPECT_EQ(ASCIIToUTF16("Get started with Google Chrome"), child->GetTitle());

  ASSERT_TRUE(decoded_model.synced_node() != NULL);
}
<commit_msg>bookmarks: Wrap BookmarkCodec unittests into unnamed namespace.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_codec.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_model_test_utils.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/common/chrome_paths.h"
#include "content/common/json_value_serializer.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

const char kUrl1Title[] = "url1";
const char kUrl1Url[] = "http://www.url1.com";
const char kUrl2Title[] = "url2";
const char kUrl2Url[] = "http://www.url2.com";
const char kUrl3Title[] = "url3";
const char kUrl3Url[] = "http://www.url3.com";
const char kUrl4Title[] = "url4";
const char kUrl4Url[] = "http://www.url4.com";
const char kFolder1Title[] = "folder1";
const char kFolder2Title[] = "folder2";

// Helper to get a mutable bookmark node.
BookmarkNode* AsMutable(const BookmarkNode* node) {
  return const_cast<BookmarkNode*>(node);
}

class BookmarkCodecTest : public testing::Test {
 protected:
  // Helpers to create bookmark models with different data.
  BookmarkModel* CreateTestModel1() {
    scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
    const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
    model->AddURL(bookmark_bar, 0, ASCIIToUTF16(kUrl1Title), GURL(kUrl1Url));
    return model.release();
  }
  BookmarkModel* CreateTestModel2() {
    scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
    const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
    model->AddURL(bookmark_bar, 0, ASCIIToUTF16(kUrl1Title), GURL(kUrl1Url));
    model->AddURL(bookmark_bar, 1, ASCIIToUTF16(kUrl2Title), GURL(kUrl2Url));
    return model.release();
  }
  BookmarkModel* CreateTestModel3() {
    scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
    const BookmarkNode* bookmark_bar = model->GetBookmarkBarNode();
    model->AddURL(bookmark_bar, 0, ASCIIToUTF16(kUrl1Title), GURL(kUrl1Url));
    const BookmarkNode* folder1 = model->AddFolder(bookmark_bar, 1,
                                                   ASCIIToUTF16(kFolder1Title));
    model->AddURL(folder1, 0, ASCIIToUTF16(kUrl2Title), GURL(kUrl2Url));
    return model.release();
  }

  void GetBookmarksBarChildValue(Value* value,
                                 size_t index,
                                 DictionaryValue** result_value) {
    ASSERT_EQ(Value::TYPE_DICTIONARY, value->GetType());

    DictionaryValue* d_value = static_cast<DictionaryValue*>(value);
    Value* roots;
    ASSERT_TRUE(d_value->Get(BookmarkCodec::kRootsKey, &roots));
    ASSERT_EQ(Value::TYPE_DICTIONARY, roots->GetType());

    DictionaryValue* roots_d_value = static_cast<DictionaryValue*>(roots);
    Value* bb_value;
    ASSERT_TRUE(roots_d_value->Get(BookmarkCodec::kRootFolderNameKey,
                                   &bb_value));
    ASSERT_EQ(Value::TYPE_DICTIONARY, bb_value->GetType());

    DictionaryValue* bb_d_value = static_cast<DictionaryValue*>(bb_value);
    Value* bb_children_value;
    ASSERT_TRUE(bb_d_value->Get(BookmarkCodec::kChildrenKey,
                                &bb_children_value));
    ASSERT_EQ(Value::TYPE_LIST, bb_children_value->GetType());

    ListValue* bb_children_l_value = static_cast<ListValue*>(bb_children_value);
    Value* child_value;
    ASSERT_TRUE(bb_children_l_value->Get(index, &child_value));
    ASSERT_EQ(Value::TYPE_DICTIONARY, child_value->GetType());

    *result_value = static_cast<DictionaryValue*>(child_value);
  }

  Value* EncodeHelper(BookmarkModel* model, std::string* checksum) {
    BookmarkCodec encoder;
    // Computed and stored checksums should be empty.
    EXPECT_EQ("", encoder.computed_checksum());
    EXPECT_EQ("", encoder.stored_checksum());

    scoped_ptr<Value> value(encoder.Encode(model));
    const std::string& computed_checksum = encoder.computed_checksum();
    const std::string& stored_checksum = encoder.stored_checksum();

    // Computed and stored checksums should not be empty and should be equal.
    EXPECT_FALSE(computed_checksum.empty());
    EXPECT_FALSE(stored_checksum.empty());
    EXPECT_EQ(computed_checksum, stored_checksum);

    *checksum = computed_checksum;
    return value.release();
  }

  bool Decode(BookmarkCodec* codec, BookmarkModel* model, const Value& value) {
    int64 max_id;
    bool result = codec->Decode(AsMutable(model->GetBookmarkBarNode()),
                                AsMutable(model->other_node()),
                                AsMutable(model->synced_node()),
                                &max_id, value);
    model->set_next_node_id(max_id);
    return result;
  }

  BookmarkModel* DecodeHelper(const Value& value,
                              const std::string& expected_stored_checksum,
                              std::string* computed_checksum,
                              bool expected_changes) {
    BookmarkCodec decoder;
    // Computed and stored checksums should be empty.
    EXPECT_EQ("", decoder.computed_checksum());
    EXPECT_EQ("", decoder.stored_checksum());

    scoped_ptr<BookmarkModel> model(new BookmarkModel(NULL));
    EXPECT_TRUE(Decode(&decoder, model.get(), value));

    *computed_checksum = decoder.computed_checksum();
    const std::string& stored_checksum = decoder.stored_checksum();

    // Computed and stored checksums should not be empty.
    EXPECT_FALSE(computed_checksum->empty());
    EXPECT_FALSE(stored_checksum.empty());

    // Stored checksum should be as expected.
    EXPECT_EQ(expected_stored_checksum, stored_checksum);

    // The two checksums should be equal if expected_changes is true; otherwise
    // they should be different.
    if (expected_changes)
      EXPECT_NE(*computed_checksum, stored_checksum);
    else
      EXPECT_EQ(*computed_checksum, stored_checksum);

    return model.release();
  }

  void CheckIDs(const BookmarkNode* node, std::set<int64>* assigned_ids) {
    DCHECK(node);
    int64 node_id = node->id();
    EXPECT_TRUE(assigned_ids->find(node_id) == assigned_ids->end());
    assigned_ids->insert(node_id);
    for (int i = 0; i < node->child_count(); ++i)
      CheckIDs(node->GetChild(i), assigned_ids);
  }

  void ExpectIDsUnique(BookmarkModel* model) {
    std::set<int64> assigned_ids;
    CheckIDs(model->GetBookmarkBarNode(), &assigned_ids);
    CheckIDs(model->other_node(), &assigned_ids);
    CheckIDs(model->synced_node(), &assigned_ids);
  }
};

TEST_F(BookmarkCodecTest, ChecksumEncodeDecodeTest) {
  scoped_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  std::string enc_checksum;
  scoped_ptr<Value> value(EncodeHelper(model_to_encode.get(), &enc_checksum));

  EXPECT_TRUE(value.get() != NULL);

  std::string dec_checksum;
  scoped_ptr<BookmarkModel> decoded_model(DecodeHelper(
      *value.get(), enc_checksum, &dec_checksum, false));
}

TEST_F(BookmarkCodecTest, ChecksumEncodeIdenticalModelsTest) {
  // Encode two identical models and make sure the check-sums are same as long
  // as the data is the same.
  scoped_ptr<BookmarkModel> model1(CreateTestModel1());
  std::string enc_checksum1;
  scoped_ptr<Value> value1(EncodeHelper(model1.get(), &enc_checksum1));
  EXPECT_TRUE(value1.get() != NULL);

  scoped_ptr<BookmarkModel> model2(CreateTestModel1());
  std::string enc_checksum2;
  scoped_ptr<Value> value2(EncodeHelper(model2.get(), &enc_checksum2));
  EXPECT_TRUE(value2.get() != NULL);

  ASSERT_EQ(enc_checksum1, enc_checksum2);
}

TEST_F(BookmarkCodecTest, ChecksumManualEditTest) {
  scoped_ptr<BookmarkModel> model_to_encode(CreateTestModel1());
  std::string enc_checksum;
  scoped_ptr<Value> value(EncodeHelper(model_to_encode.get(), &enc_checksum));

  EXPECT_TRUE(value.get() != NULL);

  // Change something in the encoded value before decoding it.
  DictionaryValue* child1_value;
  GetBookmarksBarChildValue(value.get(), 0, &child1_value);
  std::string title;
  ASSERT_TRUE(child1_value->GetString(BookmarkCodec::kNameKey, &title));
  child1_value->SetString(BookmarkCodec::kNameKey, title + "1");

  std::string dec_checksum;
  scoped_ptr<BookmarkModel> decoded_model1(DecodeHelper(
      *value.get(), enc_checksum, &dec_checksum, true));

  // Undo the change and make sure the checksum is same as original.
  child1_value->SetString(BookmarkCodec::kNameKey, title);
  scoped_ptr<BookmarkModel> decoded_model2(DecodeHelper(
      *value.get(), enc_checksum, &dec_checksum, false));
}

TEST_F(BookmarkCodecTest, ChecksumManualEditIDsTest) {
  scoped_ptr<BookmarkModel> model_to_encode(CreateTestModel3());

  // The test depends on existence of multiple children under bookmark bar, so
  // make sure that's the case.
  int bb_child_count = model_to_encode->GetBookmarkBarNode()->child_count();
  ASSERT_GT(bb_child_count, 1);

  std::string enc_checksum;
  scoped_ptr<Value> value(EncodeHelper(model_to_encode.get(), &enc_checksum));

  EXPECT_TRUE(value.get() != NULL);

  // Change IDs for all children of bookmark bar to be 1.
  DictionaryValue* child_value;
  for (int i = 0; i < bb_child_count; ++i) {
    GetBookmarksBarChildValue(value.get(), i, &child_value);
    std::string id;
    ASSERT_TRUE(child_value->GetString(BookmarkCodec::kIdKey, &id));
    child_value->SetString(BookmarkCodec::kIdKey, "1");
  }

  std::string dec_checksum;
  scoped_ptr<BookmarkModel> decoded_model(DecodeHelper(
      *value.get(), enc_checksum, &dec_checksum, true));

  ExpectIDsUnique(decoded_model.get());

  // add a few extra nodes to bookmark model and make sure IDs are still uniuqe.
  const BookmarkNode* bb_node = decoded_model->GetBookmarkBarNode();
  decoded_model->AddURL(bb_node, 0, ASCIIToUTF16("new url1"),
                        GURL("http://newurl1.com"));
  decoded_model->AddURL(bb_node, 0, ASCIIToUTF16("new url2"),
                        GURL("http://newurl2.com"));

  ExpectIDsUnique(decoded_model.get());
}

TEST_F(BookmarkCodecTest, PersistIDsTest) {
  scoped_ptr<BookmarkModel> model_to_encode(CreateTestModel3());
  BookmarkCodec encoder;
  scoped_ptr<Value> model_value(encoder.Encode(model_to_encode.get()));

  BookmarkModel decoded_model(NULL);
  BookmarkCodec decoder;
  ASSERT_TRUE(Decode(&decoder, &decoded_model, *model_value.get()));
  BookmarkModelTestUtils::AssertModelsEqual(model_to_encode.get(),
                                            &decoded_model,
                                            true);

  // Add a couple of more items to the decoded bookmark model and make sure
  // ID persistence is working properly.
  const BookmarkNode* bookmark_bar = decoded_model.GetBookmarkBarNode();
  decoded_model.AddURL(
      bookmark_bar, bookmark_bar->child_count(), ASCIIToUTF16(kUrl3Title),
      GURL(kUrl3Url));
  const BookmarkNode* folder2_node = decoded_model.AddFolder(
      bookmark_bar, bookmark_bar->child_count(), ASCIIToUTF16(kFolder2Title));
  decoded_model.AddURL(folder2_node, 0, ASCIIToUTF16(kUrl4Title),
                       GURL(kUrl4Url));

  BookmarkCodec encoder2;
  scoped_ptr<Value> model_value2(encoder2.Encode(&decoded_model));

  BookmarkModel decoded_model2(NULL);
  BookmarkCodec decoder2;
  ASSERT_TRUE(Decode(&decoder2, &decoded_model2, *model_value2.get()));
  BookmarkModelTestUtils::AssertModelsEqual(&decoded_model,
                                            &decoded_model2,
                                            true);
}

TEST_F(BookmarkCodecTest, CanDecodeModelWithoutSyncedBookmarks) {
  FilePath test_data_directory;
  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory));
  FilePath test_file = test_data_directory.AppendASCII(
      "bookmarks/model_without_sync.json");
  ASSERT_TRUE(file_util::PathExists(test_file));

  JSONFileValueSerializer serializer(test_file);
  scoped_ptr<Value> root(serializer.Deserialize(NULL, NULL));

  BookmarkModel decoded_model(NULL);
  BookmarkCodec decoder;
  ASSERT_TRUE(Decode(&decoder, &decoded_model, *root.get()));
  ExpectIDsUnique(&decoded_model);

  const BookmarkNode* bbn = decoded_model.GetBookmarkBarNode();
  ASSERT_EQ(1, bbn->child_count());

  const BookmarkNode* child = bbn->GetChild(0);
  EXPECT_EQ(BookmarkNode::FOLDER, child->type());
  EXPECT_EQ(ASCIIToUTF16("Folder A"), child->GetTitle());
  ASSERT_EQ(1, child->child_count());

  child = child->GetChild(0);
  EXPECT_EQ(BookmarkNode::URL, child->type());
  EXPECT_EQ(ASCIIToUTF16("Bookmark Manager"), child->GetTitle());

  const BookmarkNode* other = decoded_model.other_node();
  ASSERT_EQ(1, other->child_count());

  child = other->GetChild(0);
  EXPECT_EQ(BookmarkNode::FOLDER, child->type());
  EXPECT_EQ(ASCIIToUTF16("Folder B"), child->GetTitle());
  ASSERT_EQ(1, child->child_count());

  child = child->GetChild(0);
  EXPECT_EQ(BookmarkNode::URL, child->type());
  EXPECT_EQ(ASCIIToUTF16("Get started with Google Chrome"), child->GetTitle());

  ASSERT_TRUE(decoded_model.synced_node() != NULL);
}

}  // namespace
<|endoftext|>