<commit_before>#include "OpcodeBase.hpp"
#include <map>
#include <vector>

/**
 * The busses are laid out:
 * busses[csound][bus][channel][frame].
 */
static std::map<CSOUND *, std::map<size_t,
                                   std::vector< std::vector<MYFLT> > > > busses;

/**
 * The mixer matrix is laid out:
 * matrix[csound][send][bus].
 */
static std::map<CSOUND *, std::map<size_t, std::map<size_t, MYFLT> > > matrix;

/**
 * MixerSetLevel isend, ibuss, kgain
 *
 * Controls the gain of any signal route from a send to a bus.
 * Also creates the bus if it does not exist.
 */
struct MixerSetLevel : public OpcodeBase<MixerSetLevel>
{
  // No outputs.
  // Inputs.
  MYFLT *isend;
  MYFLT *ibuss;
  MYFLT *kgain;
  // State.
  size_t send;
  size_t buss;
  int init(CSOUND *csound)
  {
    //warn(csound, "MixerSetLevel::init...\n");
    send = static_cast<size_t>(*isend);
    buss = static_cast<size_t>(*ibuss);
    if(busses[csound].find(buss) == busses[csound].end())
      {
        size_t channels = csound->nchnls;
        size_t frames = csound->ksmps;
        busses[csound][buss].resize(channels);
        for(size_t channel = 0; channel < channels; channel++)
          {
            busses[csound][buss][channel].resize(frames);
          }
        //warn(csound, "MixerSetLevel::init: initialized instance %d buss "
        //"%d channels %d frames %d\n", csound, buss, channels, frames);
      }
    matrix[csound][send][buss] = *kgain;
    //warn(csound, "MixerSetLevel::kontrol: instance %d send %d buss "
    //"%d gain %f\n", csound, send, buss, gain);
    return OK;
  }
  int kontrol(CSOUND *csound)
  {
    //warn(csound, "MixerSetLevel::kontrol...\n");
    matrix[csound][send][buss] = *kgain;
    //warn(csound, "MixerSetLevel::kontrol: instance %d send %d buss "
    //"%d gain %f\n", csound, send, buss, gain);
    return OK;
  }
};

extern "C" {
  PUBLIC int csoundModuleDestroy(CSOUND *csound)
  {
    if (busses.begin() != busses.end()) {
      busses.clear();
    }
    if (matrix.begin() != matrix.end()) {
      matrix.clear();
    }
    return 0;
  }
}

/**
 * kgain MixerGetLevel isend, ibuss
 *
 * Returns the gain of any signal route from a send to a bus.
 */
struct MixerGetLevel : public OpcodeBase<MixerGetLevel>
{
  // Outputs.
  MYFLT *kgain;
  // Inputs.
  MYFLT *isend;
  MYFLT *ibuss;
  // State.
  size_t send;
  size_t buss;
  int init(CSOUND *csound)
  {
    send = static_cast<size_t>(*isend);
    buss = static_cast<size_t>(*ibuss);
    return OK;
  }
  int noteoff(CSOUND *)
  {
    return OK;
  }
  int kontrol(CSOUND *csound)
  {
    *kgain = matrix[csound][send][buss];
    return OK;
  }
};
/**
 * MixerSend asignal, isend, ibus, ichannel
 *
 * Routes a signal from a send to a channel of a mixer bus.
 * The gain of the send is controlled by the previously set mixer level.
 */
struct MixerSend : public OpcodeBase<MixerSend>
{
  // No outputs.
  // Inputs.
  MYFLT *ainput;
  MYFLT *isend;
  MYFLT *ibuss;
  MYFLT *ichannel;
  // State.
  size_t send;
  size_t buss;
  size_t channel;
  size_t frames;
  MYFLT *busspointer;
  int init(CSOUND *csound)
  {
    //warn(csound, "MixerSend::init...\n");
    send = static_cast<size_t>(*isend);
    buss = static_cast<size_t>(*ibuss);
    channel = static_cast<size_t>(*ichannel);
    frames = csound->ksmps;
    busspointer = &busses[csound][buss][channel].front();
    //warn(csound, "MixerSend::init: instance %d send %d buss "
    //"%d channel %d frames %d busspointer 0x%x\n",
    //csound, send, buss, channel, frames, busspointer);
    return OK;
  }
  int noteoff(CSOUND *)
  {
    return OK;
  }
  int audio(CSOUND *csound)
  {
    //warn(csound, "MixerSend::audio...\n");
    MYFLT gain = matrix[csound][send][buss];
    for(size_t i = 0; i < frames; i++)
      {
        busspointer[i] += (ainput[i] * gain);
      }
    //warn(csound, "MixerSend::audio: instance %d send %d buss "
    //"%d gain %f busspointer 0x%x\n", csound, send, buss, gain, busspointer);
    return OK;
  }
};

/**
 * asignal MixerReceive ibuss, ichannel
 *
 * Receives a signal from a channel of a bus.
 * Obviously, instruments receiving signals must be numbered higher
 * than instruments sending those signals.
 */
struct MixerReceive : public OpcodeBase<MixerReceive>
{
  // Output.
  MYFLT *aoutput;
  // Inputs.
  MYFLT *ibuss;
  MYFLT *ichannel;
  // State.
  size_t buss;
  size_t channel;
  size_t frames;
  MYFLT *busspointer;
  int init(CSOUND *csound)
  {
    //warn(csound, "MixerReceive::init...\n");
    buss = static_cast<size_t>(*ibuss);
    channel = static_cast<size_t>(*ichannel);
    frames = csound->ksmps;
    busspointer = &busses[csound][buss][channel].front();
    //warn(csound, "MixerReceive::init instance %d buss %d channel "
    //"%d frames %d busspointer 0x%x\n", instance, buss, channel,
    //frames, busspointer);
    return OK;
  }
  int noteoff(CSOUND *)
  {
    return OK;
  }
  int audio(CSOUND *csound)
  {
    //warn(csound, "MixerReceive::audio...\n");
    for(size_t i = 0; i < frames; i++)
      {
        aoutput[i] = busspointer[i];
      }
    //warn(csound, "MixerReceive::audio aoutput 0x%x busspointer 0x%x\n",
    //aoutput, busspointer);
    return OK;
  }
};

/**
 * MixerClear
 *
 * Clears all busses. Must be invoked after last MixerReceive.
 * You should probably use a highest-numbered instrument
 * with an indefinite duration that invokes only this opcode.
 */
struct MixerClear : public OpcodeBase<MixerClear>
{
  // No output.
  // No input.
  // No state.
  int audio(CSOUND *csound)
  {
    //warn(csound, "MixerClear::audio...\n")
    for(std::map<size_t,
          std::vector< std::vector<MYFLT> > >::iterator
          busi = busses[csound].begin(); busi != busses[csound].end(); ++busi)
      {
        for(std::vector< std::vector<MYFLT> >::iterator
              channeli = busi->second.begin();
            channeli != busi->second.end(); ++channeli)
          {
            for(std::vector<MYFLT>::iterator
                  framei = (*channeli).begin();
                framei != (*channeli).end(); ++framei)
              {
                *framei = 0;
              }
          }
      }
    //warn(csound, "MixerClear::audio\n")
    return OK;
  }
};

extern "C"
{

  static OENTRY localops[] = {
    {
      (char*)"MixerSetLevel",
      sizeof(MixerSetLevel),
      3,
      (char*)"",
      (char*)"iik",
      (SUBR)&MixerSetLevel::init_,
      (SUBR)&MixerSetLevel::kontrol_,
      0
    },
    {
      (char*)"MixerGetLevel",
      sizeof(MixerGetLevel),
      3,
      (char*)"k",
      (char*)"ii",
      (SUBR)&MixerGetLevel::init_,
      (SUBR)&MixerGetLevel::kontrol_,
      0
    },
    {
      (char*)"MixerSend",
      sizeof(MixerSend),
      5,
      (char*)"",
      (char*)"aiii",
      (SUBR)&MixerSend::init_,
      0,
      (SUBR)&MixerSend::audio_
    },
    {
      (char*)"MixerReceive",
      sizeof(MixerReceive),
      5,
      (char*)"a",
      (char*)"ii",
      (SUBR)&MixerReceive::init_,
      0,
      (SUBR)&MixerReceive::audio_
    },
    {
      (char*)"MixerClear",
      sizeof(MixerClear),
      4,
      (char*)"",
      (char*)"",
      0,
      0,
      (SUBR)&MixerClear::audio_
    },
    { NULL, 0, 0, NULL, NULL, (SUBR) NULL, (SUBR) NULL, (SUBR) NULL }
  };

  PUBLIC int csoundModuleCreate(CSOUND *csound)
  {
    return 0;
  }

  PUBLIC int csoundModuleInit(CSOUND *csound)
  {
    OENTRY  *ep = (OENTRY*) &(localops[0]);
    int     err = 0;

    while (ep->opname != NULL) {
      err |= csound->AppendOpcode(csound,
                                  ep->opname, ep->dsblksiz, ep->thread,
                                  ep->outypes, ep->intypes,
                                  (int (*)(CSOUND *, void*)) ep->iopadr,
                                  (int (*)(CSOUND *, void*)) ep->kopadr,
                                  (int (*)(CSOUND *, void*)) ep->aopadr);
      ep++;
    }
    return err;
  }

}   // END EXTERN C

<commit_msg>no message<commit_after>#include "OpcodeBase.hpp"
#include <map>
#include <vector>

/**
 * The busses are laid out:
 * busses[csound][bus][channel][frame].
 */
static std::map<CSOUND *, std::map<size_t,
                                   std::vector< std::vector<MYFLT> > > > busses;

/**
 * The mixer matrix is laid out:
 * matrix[csound][send][bus].
 */
static std::map<CSOUND *, std::map<size_t, std::map<size_t, MYFLT> > > matrix;

/**
 * MixerSetLevel isend, ibuss, kgain
 *
 * Controls the gain of any signal route from a send to a bus.
 * Also creates the bus if it does not exist.
 */
struct MixerSetLevel : public OpcodeBase<MixerSetLevel>
{
  // No outputs.
  // Inputs.
  MYFLT *isend;
  MYFLT *ibuss;
  MYFLT *kgain;
  // State.
  size_t send;
  size_t buss;
  int init(CSOUND *csound)
  {
    //warn(csound, "MixerSetLevel::init...\n");
    send = static_cast<size_t>(*isend);
    buss = static_cast<size_t>(*ibuss);
    if(busses[csound].find(buss) == busses[csound].end())
      {
        size_t channels = csound->nchnls;
        size_t frames = csound->ksmps;
        busses[csound][buss].resize(channels);
        for(size_t channel = 0; channel < channels; channel++)
          {
            busses[csound][buss][channel].resize(frames);
          }
        //warn(csound, "MixerSetLevel::init: initialized instance %d buss "
        //"%d channels %d frames %d\n", csound, buss, channels, frames);
      }
    matrix[csound][send][buss] = *kgain;
    //warn(csound, "MixerSetLevel::kontrol: instance %d send %d buss "
    //"%d gain %f\n", csound, send, buss, gain);
    return OK;
  }
  int kontrol(CSOUND *csound)
  {
    //warn(csound, "MixerSetLevel::kontrol...\n");
    matrix[csound][send][buss] = *kgain;
    //warn(csound, "MixerSetLevel::kontrol: instance %d send %d buss "
    //"%d gain %f\n", csound, send, buss, gain);
    return OK;
  }
};

extern "C" {
  PUBLIC int csoundModuleDestroy(CSOUND *csound)
  {
    if (busses.begin() != busses.end()) {
      busses.clear();
    }
    if (matrix.begin() != matrix.end()) {
      matrix.clear();
    }
    return 0;
  }
}

/**
 * kgain MixerGetLevel isend, ibuss
 *
 * Returns the gain of any signal route from a send to a bus.
 */
struct MixerGetLevel : public OpcodeBase<MixerGetLevel>
{
  // Outputs.
  MYFLT *kgain;
  // Inputs.
  MYFLT *isend;
  MYFLT *ibuss;
  // State.
  size_t send;
  size_t buss;
  int init(CSOUND *csound)
  {
    send = static_cast<size_t>(*isend);
    buss = static_cast<size_t>(*ibuss);
    return OK;
  }
  int noteoff(CSOUND *)
  {
    return OK;
  }
  int kontrol(CSOUND *csound)
  {
    *kgain = matrix[csound][send][buss];
    return OK;
  }
};
/**
 * MixerSend asignal, isend, ibus, ichannel
 *
 * Routes a signal from a send to a channel of a mixer bus.
 * The gain of the send is controlled by the previously set mixer level.
 */
struct MixerSend : public OpcodeBase<MixerSend>
{
  // No outputs.
  // Inputs.
  MYFLT *ainput;
  MYFLT *isend;
  MYFLT *ibuss;
  MYFLT *ichannel;
  // State.
  size_t send;
  size_t buss;
  size_t channel;
  size_t frames;
  MYFLT *busspointer;
  int init(CSOUND *csound)
  {
    //warn(csound, "MixerSend::init...\n");
    send = static_cast<size_t>(*isend);
    buss = static_cast<size_t>(*ibuss);
    channel = static_cast<size_t>(*ichannel);
    frames = csound->ksmps;
    busspointer = &busses[csound][buss][channel].front();
    //warn(csound, "MixerSend::init: instance %d send %d buss "
    //"%d channel %d frames %d busspointer 0x%p\n",
    //csound, send, buss, channel, frames, busspointer);
    return OK;
  }
  int noteoff(CSOUND *)
  {
    return OK;
  }
  int audio(CSOUND *csound)
  {
    //warn(csound, "MixerSend::audio...\n");
    MYFLT gain = matrix[csound][send][buss];
    for(size_t i = 0; i < frames; i++)
      {
        busspointer[i] += (ainput[i] * gain);
      }
    //warn(csound, "MixerSend::audio: instance %d send %d buss "
    //"%d gain %f busspointer 0x%p\n", csound, send, buss, gain, busspointer);
    return OK;
  }
};

/**
 * asignal MixerReceive ibuss, ichannel
 *
 * Receives a signal from a channel of a bus.
 * Obviously, instruments receiving signals must be numbered higher
 * than instruments sending those signals.
 */
struct MixerReceive : public OpcodeBase<MixerReceive>
{
  // Output.
  MYFLT *aoutput;
  // Inputs.
  MYFLT *ibuss;
  MYFLT *ichannel;
  // State.
  size_t buss;
  size_t channel;
  size_t frames;
  MYFLT *busspointer;
  int init(CSOUND *csound)
  {
    //warn(csound, "MixerReceive::init...\n");
    buss = static_cast<size_t>(*ibuss);
    channel = static_cast<size_t>(*ichannel);
    frames = csound->ksmps;
    busspointer = &busses[csound][buss][channel].front();
    //warn(csound, "MixerReceive::init instance %d buss %d channel "
    //"%d frames %d busspointer 0x%p\n", instance, buss, channel,
    //frames, busspointer);
    return OK;
  }
  int noteoff(CSOUND *)
  {
    return OK;
  }
  int audio(CSOUND *csound)
  {
    //warn(csound, "MixerReceive::audio...\n");
    for(size_t i = 0; i < frames; i++)
      {
        aoutput[i] = busspointer[i];
      }
    //warn(csound, "MixerReceive::audio aoutput 0x%p busspointer 0x%p\n",
    //aoutput, busspointer);
    return OK;
  }
};

/**
 * MixerClear
 *
 * Clears all busses. Must be invoked after last MixerReceive.
 * You should probably use a highest-numbered instrument
 * with an indefinite duration that invokes only this opcode.
 */
struct MixerClear : public OpcodeBase<MixerClear>
{
  // No output.
  // No input.
  // No state.
  int audio(CSOUND *csound)
  {
    //warn(csound, "MixerClear::audio...\n")
    for(std::map<size_t,
          std::vector< std::vector<MYFLT> > >::iterator
          busi = busses[csound].begin(); busi != busses[csound].end(); ++busi)
      {
        for(std::vector< std::vector<MYFLT> >::iterator
              channeli = busi->second.begin();
            channeli != busi->second.end(); ++channeli)
          {
            for(std::vector<MYFLT>::iterator
                  framei = (*channeli).begin();
                framei != (*channeli).end(); ++framei)
              {
                *framei = 0;
              }
          }
      }
    //warn(csound, "MixerClear::audio\n")
    return OK;
  }
};

extern "C"
{

  static OENTRY localops[] = {
    {
      (char*)"MixerSetLevel",
      sizeof(MixerSetLevel),
      3,
      (char*)"",
      (char*)"iik",
      (SUBR)&MixerSetLevel::init_,
      (SUBR)&MixerSetLevel::kontrol_,
      0
    },
    {
      (char*)"MixerGetLevel",
      sizeof(MixerGetLevel),
      3,
      (char*)"k",
      (char*)"ii",
      (SUBR)&MixerGetLevel::init_,
      (SUBR)&MixerGetLevel::kontrol_,
      0
    },
    {
      (char*)"MixerSend",
      sizeof(MixerSend),
      5,
      (char*)"",
      (char*)"aiii",
      (SUBR)&MixerSend::init_,
      0,
      (SUBR)&MixerSend::audio_
    },
    {
      (char*)"MixerReceive",
      sizeof(MixerReceive),
      5,
      (char*)"a",
      (char*)"ii",
      (SUBR)&MixerReceive::init_,
      0,
      (SUBR)&MixerReceive::audio_
    },
    {
      (char*)"MixerClear",
      sizeof(MixerClear),
      4,
      (char*)"",
      (char*)"",
      0,
      0,
      (SUBR)&MixerClear::audio_
    },
    { NULL, 0, 0, NULL, NULL, (SUBR) NULL, (SUBR) NULL, (SUBR) NULL }
  };

  PUBLIC int csoundModuleCreate(CSOUND *csound)
  {
    return 0;
  }

  PUBLIC int csoundModuleInit(CSOUND *csound)
  {
    OENTRY  *ep = (OENTRY*) &(localops[0]);
    int     err = 0;

    while (ep->opname != NULL) {
      err |= csound->AppendOpcode(csound,
                                  ep->opname, ep->dsblksiz, ep->thread,
                                  ep->outypes, ep->intypes,
                                  (int (*)(CSOUND *, void*)) ep->iopadr,
                                  (int (*)(CSOUND *, void*)) ep->kopadr,
                                  (int (*)(CSOUND *, void*)) ep->aopadr);
      ep++;
    }
    return err;
  }

}   // END EXTERN C

<|endoftext|>


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

#include "xwalk/runtime/common/xwalk_runtime_features.h"

#include <algorithm>
#include <functional>
#include <iostream> // NOLINT

#include "base/logging.h"
#include "xwalk/runtime/common/xwalk_switches.h"

namespace xwalk {

XWalkRuntimeFeatures::Feature::Feature()
    : status(Experimental),
      enabled(false) {
}

XWalkRuntimeFeatures::Feature::Feature(
    const std::string& name,
    const std::string& cmd_line,
    const std::string& description,
    Status status,
    bool enabled)
    : name(name),
      cmd_line(cmd_line),
      description(description),
      status(status),
      enabled(enabled) {
}

XWalkRuntimeFeatures::Feature::Feature(const XWalkRuntimeFeatures::Feature&) =
    default;

// static
XWalkRuntimeFeatures* XWalkRuntimeFeatures::GetInstance() {
  return base::Singleton<XWalkRuntimeFeatures>::get();
}

XWalkRuntimeFeatures::XWalkRuntimeFeatures()
  : command_line_(0),
    initialized_(false),
    experimental_features_enabled_(false) {}

void XWalkRuntimeFeatures::Initialize(const base::CommandLine* cmd) {
  command_line_ = cmd;
  initialized_ = true;
  runtime_features_.clear();
  if (cmd->HasSwitch(switches::kExperimentalFeatures))
    experimental_features_enabled_ = true;
  else
    experimental_features_enabled_ = false;

#if !defined(DISABLE_BUNDLED_EXTENSIONS)
#if defined(OS_ANDROID)
  // FIXME(cmarcelo): The application extensions are currently not fully working
  // for Android, so disable them. See
  // https://crosswalk-project.org/jira/browse/XWALK-674.
  // Android uses a Java extension for device capabilities, so disable the one
  // from sysapps/.
  AddFeature("SysApps", "sysapps",
      "Master switch for the SysApps category of APIs", Feature::Stable);
  AddFeature("RawSocketsAPI", "raw-sockets",
      "JavaScript support for using TCP and UDP sockets", Feature::Stable);
  AddFeature("StorageAPI", "storage",
      "JavaScript support to file system beyond W3C spec", Feature::Stable);
  AddFeature("DialogAPI", "dialog-api",
      "JavaScript support for dialog APIs", Feature::Experimental);
#else
  AddFeature("SysApps", "sysapps",
      "Master switch for the SysApps category of APIs", Feature::Stable);
  AddFeature("RawSocketsAPI", "raw-sockets",
      "JavaScript support for using TCP and UDP sockets", Feature::Stable);
  AddFeature("StorageAPI", "storage",
      "JavaScript support to file system beyond W3C spec", Feature::Stable);
  AddFeature("ApplicationAPI", "application-api",
      "JavaScript support for Widget and Manifest APIs", Feature::Stable);
  AddFeature("DialogAPI", "dialog-api",
      "JavaScript support for dialog APIs", Feature::Experimental);
  AddFeature("WiFiDirectAPI", "wifidirect-api",
      "JavaScript support for WiFiDirect", Feature::Experimental);
#endif
#endif
}

XWalkRuntimeFeatures::~XWalkRuntimeFeatures() {}

void XWalkRuntimeFeatures::AddFeature(const char* name,
                                      const char* cmd_line,
                                      const char* description,
                                      Feature::Status status) {
  Feature feature(name, cmd_line, description, status);
  if (experimental_features_enabled_) {
    feature.enabled = true;
  } else if (command_line_->HasSwitch("disable-" + std::string(cmd_line))) {
    feature.enabled = false;
  } else if (command_line_->HasSwitch("enable-" + std::string(cmd_line))) {
    feature.enabled = true;
  } else {
    feature.enabled = (status == Feature::Stable);
  }

  runtime_features_[name] = feature;
}

void XWalkRuntimeFeatures::DumpFeaturesFlags() {
  std::cout << "Available runtime features flags : " << std::endl;
  const std::string command_line_title("  Command Line Switch");
  const std::string description_title("Description");
  const std::string status_title("Status");
  const int command_line_description_space = 16;
  const int description_status_space = 51;
  const int status_space = 7;

  std::string output;
  output += command_line_title;
  output += std::string(command_line_description_space, ' ');
  output += description_title;
  output += std::string(description_status_space, ' ');
  output += status_title + std::string(status_space, ' ') + '\n';
  int total_length = status_space + description_status_space
    + command_line_description_space + description_title.length()
    + command_line_title.length() + status_title.length();
  output += std::string(total_length, '-') + '\n';

  for (const auto& pair : runtime_features_) {
    const Feature& feature = pair.second;
    std::string status = (feature.status == Feature::Stable) ?
      std::string("Stable") : std::string("Experimental");
    std::string command_line;

    feature.enabled ? command_line = "--disable-"
      : command_line = "--enable-";
    command_line += feature.cmd_line;

    output += command_line;
    std::string space(command_line_description_space
      + command_line_title.length() - command_line.length(), ' ');
    output +=  space + feature.description;
    std::string space2(description_status_space + description_title.length()
      - feature.description.length(), ' ');
    output += space2 + status + '\n';
  }
  std::cout << output << std::endl;
}

bool XWalkRuntimeFeatures::isFeatureEnabled(const char* name) const {
  CHECK(initialized_);
  auto it = runtime_features_.find(name);
  if (it == runtime_features_.end())
    return false;
  return it->second.enabled;
}

}  // namespace xwalk
<commit_msg>Mark features experimental when disabling bundled extensions<commit_after>// Copyright (c) 2013 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/runtime/common/xwalk_runtime_features.h"

#include <algorithm>
#include <functional>
#include <iostream> // NOLINT

#include "base/logging.h"
#include "xwalk/runtime/common/xwalk_switches.h"

namespace xwalk {

XWalkRuntimeFeatures::Feature::Feature()
    : status(Experimental),
      enabled(false) {
}

XWalkRuntimeFeatures::Feature::Feature(
    const std::string& name,
    const std::string& cmd_line,
    const std::string& description,
    Status status,
    bool enabled)
    : name(name),
      cmd_line(cmd_line),
      description(description),
      status(status),
      enabled(enabled) {
}

XWalkRuntimeFeatures::Feature::Feature(const XWalkRuntimeFeatures::Feature&) =
    default;

// static
XWalkRuntimeFeatures* XWalkRuntimeFeatures::GetInstance() {
  return base::Singleton<XWalkRuntimeFeatures>::get();
}

XWalkRuntimeFeatures::XWalkRuntimeFeatures()
  : command_line_(0),
    initialized_(false),
    experimental_features_enabled_(false) {}

void XWalkRuntimeFeatures::Initialize(const base::CommandLine* cmd) {
  command_line_ = cmd;
  initialized_ = true;
  runtime_features_.clear();
  if (cmd->HasSwitch(switches::kExperimentalFeatures))
    experimental_features_enabled_ = true;
  else
    experimental_features_enabled_ = false;

#if !defined(DISABLE_BUNDLED_EXTENSIONS)
  const Feature::Status default_status = Feature::Stable;
#else
  // mark all features as experimental so they are disabled by default
  const Feature::Status default_status = Feature::Experimental;
#endif

#if defined(OS_ANDROID)
  // FIXME(cmarcelo): The application extensions are currently not fully working
  // for Android, so disable them. See
  // https://crosswalk-project.org/jira/browse/XWALK-674.
  // Android uses a Java extension for device capabilities, so disable the one
  // from sysapps/.
  AddFeature("SysApps", "sysapps",
      "Master switch for the SysApps category of APIs", default_status);
  AddFeature("RawSocketsAPI", "raw-sockets",
      "JavaScript support for using TCP and UDP sockets", default_status);
  AddFeature("StorageAPI", "storage",
      "JavaScript support to file system beyond W3C spec", default_status);
  AddFeature("DialogAPI", "dialog-api",
      "JavaScript support for dialog APIs", Feature::Experimental);
#else
  AddFeature("SysApps", "sysapps",
      "Master switch for the SysApps category of APIs", default_status);
  AddFeature("RawSocketsAPI", "raw-sockets",
      "JavaScript support for using TCP and UDP sockets", default_status);
  AddFeature("StorageAPI", "storage",
      "JavaScript support to file system beyond W3C spec", default_status);
  AddFeature("ApplicationAPI", "application-api",
      "JavaScript support for Widget and Manifest APIs", default_status);
  AddFeature("DialogAPI", "dialog-api",
      "JavaScript support for dialog APIs", Feature::Experimental);
  AddFeature("WiFiDirectAPI", "wifidirect-api",
      "JavaScript support for WiFiDirect", Feature::Experimental);
#endif
}

XWalkRuntimeFeatures::~XWalkRuntimeFeatures() {}

void XWalkRuntimeFeatures::AddFeature(const char* name,
                                      const char* cmd_line,
                                      const char* description,
                                      Feature::Status status) {
  Feature feature(name, cmd_line, description, status);
  if (experimental_features_enabled_) {
    feature.enabled = true;
  } else if (command_line_->HasSwitch("disable-" + std::string(cmd_line))) {
    feature.enabled = false;
  } else if (command_line_->HasSwitch("enable-" + std::string(cmd_line))) {
    feature.enabled = true;
  } else {
    feature.enabled = (status == Feature::Stable);
  }

  runtime_features_[name] = feature;
}

void XWalkRuntimeFeatures::DumpFeaturesFlags() {
  std::cout << "Available runtime features flags : " << std::endl;
  const std::string command_line_title("  Command Line Switch");
  const std::string description_title("Description");
  const std::string status_title("Status");
  const int command_line_description_space = 16;
  const int description_status_space = 51;
  const int status_space = 7;

  std::string output;
  output += command_line_title;
  output += std::string(command_line_description_space, ' ');
  output += description_title;
  output += std::string(description_status_space, ' ');
  output += status_title + std::string(status_space, ' ') + '\n';
  int total_length = status_space + description_status_space
    + command_line_description_space + description_title.length()
    + command_line_title.length() + status_title.length();
  output += std::string(total_length, '-') + '\n';

  for (const auto& pair : runtime_features_) {
    const Feature& feature = pair.second;
    std::string status = (feature.status == Feature::Stable) ?
      std::string("Stable") : std::string("Experimental");
    std::string command_line;

    feature.enabled ? command_line = "--disable-"
      : command_line = "--enable-";
    command_line += feature.cmd_line;

    output += command_line;
    std::string space(command_line_description_space
      + command_line_title.length() - command_line.length(), ' ');
    output +=  space + feature.description;
    std::string space2(description_status_space + description_title.length()
      - feature.description.length(), ' ');
    output += space2 + status + '\n';
  }
  std::cout << output << std::endl;
}

bool XWalkRuntimeFeatures::isFeatureEnabled(const char* name) const {
  CHECK(initialized_);
  auto it = runtime_features_.find(name);
  if (it == runtime_features_.end())
    return false;
  return it->second.enabled;
}

}  // namespace xwalk
<|endoftext|>


<commit_before>// Copyright (c) 2012 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 "printing/backend/print_backend.h"

#include <algorithm>
#include <objidl.h>
#include <winspool.h>

#include "base/file_path.h"
#include "base/file_version_info.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_hglobal.h"
#include "printing/backend/print_backend_consts.h"
#include "printing/backend/win_helper.h"

namespace {

HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) {
  DCHECK(stream);
  DCHECK(out);
  HGLOBAL hdata = NULL;
  HRESULT hr = GetHGlobalFromStream(stream, &hdata);
  if (SUCCEEDED(hr)) {
    DCHECK(hdata);
    base::win::ScopedHGlobal<char> locked_data(hdata);
    out->assign(locked_data.release(), locked_data.Size());
  }
  return hr;
}

}  // namespace

namespace printing {

class PrintBackendWin : public PrintBackend {
 public:
  PrintBackendWin() {}
  virtual ~PrintBackendWin() {}

  virtual bool EnumeratePrinters(PrinterList* printer_list);

  virtual std::string GetDefaultPrinterName();

  virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name,
                                         PrinterCapsAndDefaults* printer_info);

  virtual std::string GetPrinterDriverInfo(const std::string& printer_name);

  virtual bool IsValidPrinter(const std::string& printer_name);
};

bool PrintBackendWin::EnumeratePrinters(PrinterList* printer_list) {
  DCHECK(printer_list);
  DWORD bytes_needed = 0;
  DWORD count_returned = 0;
  BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2,
                          NULL, 0, &bytes_needed, &count_returned);
  if (!bytes_needed)
    return false;
  scoped_array<BYTE> printer_info_buffer(new BYTE[bytes_needed]);
  ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2,
                     printer_info_buffer.get(), bytes_needed, &bytes_needed,
                     &count_returned);
  DCHECK(ret);
  if (!ret)
    return false;

  std::string default_printer = GetDefaultPrinterName();
  PRINTER_INFO_2* printer_info =
      reinterpret_cast<PRINTER_INFO_2*>(printer_info_buffer.get());
  for (DWORD index = 0; index < count_returned; index++) {
    PrinterBasicInfo info;
    info.printer_name = WideToUTF8(printer_info[index].pPrinterName);
    info.is_default = (info.printer_name == default_printer);
    if (printer_info[index].pComment)
      info.printer_description = WideToUTF8(printer_info[index].pComment);
    info.printer_status = printer_info[index].Status;
    if (printer_info[index].pLocation)
      info.options[kLocationTagName] =
          WideToUTF8(printer_info[index].pLocation);
    if (printer_info[index].pDriverName)
      info.options[kDriverNameTagName] =
          WideToUTF8(printer_info[index].pDriverName);
    printer_list->push_back(info);
  }
  return true;
}

std::string PrintBackendWin::GetDefaultPrinterName() {
  DWORD size = MAX_PATH;
  TCHAR default_printer_name[MAX_PATH];
  if (!::GetDefaultPrinter(default_printer_name, &size))
    return std::string();
  return WideToUTF8(default_printer_name);
}

bool PrintBackendWin::GetPrinterCapsAndDefaults(
    const std::string& printer_name,
    PrinterCapsAndDefaults* printer_info) {
  ScopedXPSInitializer xps_initializer;
  if (!xps_initializer.initialized()) {
    // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
    return false;
  }
  if (!IsValidPrinter(printer_name)) {
    return false;
  }
  DCHECK(printer_info);
  HPTPROVIDER provider = NULL;
  std::wstring printer_name_wide = UTF8ToWide(printer_name);
  HRESULT hr = XPSModule::OpenProvider(printer_name_wide, 1, &provider);
  DCHECK(SUCCEEDED(hr));
  if (provider) {
    base::win::ScopedComPtr<IStream> print_capabilities_stream;
    hr = CreateStreamOnHGlobal(NULL, TRUE,
                               print_capabilities_stream.Receive());
    DCHECK(SUCCEEDED(hr));
    if (print_capabilities_stream) {
      base::win::ScopedBstr error;
      hr = XPSModule::GetPrintCapabilities(provider,
                                           NULL,
                                           print_capabilities_stream,
                                           error.Receive());
      DCHECK(SUCCEEDED(hr));
      if (FAILED(hr)) {
        return false;
      }
      hr = StreamOnHGlobalToString(print_capabilities_stream.get(),
                                   &printer_info->printer_capabilities);
      DCHECK(SUCCEEDED(hr));
      printer_info->caps_mime_type = "text/xml";
    }
    ScopedPrinterHandle printer_handle;
    OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()),
                printer_handle.Receive(), NULL);
    DCHECK(printer_handle);
    if (printer_handle.IsValid()) {
      LONG devmode_size = DocumentProperties(
          NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
          NULL, NULL, 0);
      if (devmode_size <= 0)
        return false;
      scoped_array<BYTE> devmode_out_buffer(new BYTE[devmode_size]);
      DEVMODE* devmode_out =
          reinterpret_cast<DEVMODE*>(devmode_out_buffer.get());
      DocumentProperties(
          NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
          devmode_out, NULL, DM_OUT_BUFFER);
      base::win::ScopedComPtr<IStream> printer_defaults_stream;
      hr = CreateStreamOnHGlobal(NULL, TRUE,
                                 printer_defaults_stream.Receive());
      DCHECK(SUCCEEDED(hr));
      if (printer_defaults_stream) {
        hr = XPSModule::ConvertDevModeToPrintTicket(provider,
                                                    devmode_size,
                                                    devmode_out,
                                                    kPTJobScope,
                                                    printer_defaults_stream);
        DCHECK(SUCCEEDED(hr));
        if (SUCCEEDED(hr)) {
          hr = StreamOnHGlobalToString(printer_defaults_stream.get(),
                                       &printer_info->printer_defaults);
          DCHECK(SUCCEEDED(hr));
          printer_info->defaults_mime_type = "text/xml";
        }
      }
    }
    XPSModule::CloseProvider(provider);
  }
  return true;
}

// Gets the information about driver for a specific printer.
std::string PrintBackendWin::GetPrinterDriverInfo(
    const std::string& printer_name) {
  std::string driver_info;
  ScopedPrinterHandle printer_handle;
  if (!::OpenPrinter(const_cast<LPTSTR>(UTF8ToWide(printer_name).c_str()),
                     printer_handle.Receive(), NULL)) {
    return false;
  }
  DCHECK(printer_handle.IsValid());
  DWORD bytes_needed = 0;
  ::GetPrinterDriver(printer_handle, NULL, 6, NULL, 0, &bytes_needed);
  scoped_array<BYTE> driver_info_buffer(new BYTE[bytes_needed]);
  if (!bytes_needed || !driver_info_buffer.get())
    return false;
  if (!::GetPrinterDriver(printer_handle, NULL, 6, driver_info_buffer.get(),
                          bytes_needed, &bytes_needed)) {
    return false;
  }
  if (!bytes_needed)
    return false;
  const DRIVER_INFO_6* driver_info_6 =
      reinterpret_cast<DRIVER_INFO_6*>(driver_info_buffer.get());

  std::string info[4];

  if (driver_info_6->pName)
    info[0] = WideToUTF8(driver_info_6->pName);

  if (driver_info_6->pDriverPath) {
    scoped_ptr<FileVersionInfo> version_info(
        FileVersionInfo::CreateFileVersionInfo(
            FilePath(driver_info_6->pDriverPath)));
    info[1] = WideToUTF8(version_info->file_version());
    info[2] = WideToUTF8(version_info->product_name());
    info[3] = WideToUTF8(version_info->product_version());
  }

  for (size_t i = 0; i < arraysize(info); ++i) {
    std::replace(info[i].begin(), info[i].end(), ';', ',');
    driver_info.append(info[i]);
    driver_info.append(";");
  }

  return driver_info;
}

bool PrintBackendWin::IsValidPrinter(const std::string& printer_name) {
  ScopedPrinterHandle printer_handle;
  OpenPrinter(const_cast<LPTSTR>(UTF8ToWide(printer_name).c_str()),
              printer_handle.Receive(), NULL);
  return printer_handle.IsValid();
}

scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
    const base::DictionaryValue* print_backend_settings) {
  return new PrintBackendWin;
}

}  // namespace printing
<commit_msg>Fix invalid return value.<commit_after>// Copyright (c) 2012 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 "printing/backend/print_backend.h"

#include <algorithm>
#include <objidl.h>
#include <winspool.h>

#include "base/file_path.h"
#include "base/file_version_info.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_piece.h"
#include "base/utf_string_conversions.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_hglobal.h"
#include "printing/backend/print_backend_consts.h"
#include "printing/backend/win_helper.h"

namespace {

HRESULT StreamOnHGlobalToString(IStream* stream, std::string* out) {
  DCHECK(stream);
  DCHECK(out);
  HGLOBAL hdata = NULL;
  HRESULT hr = GetHGlobalFromStream(stream, &hdata);
  if (SUCCEEDED(hr)) {
    DCHECK(hdata);
    base::win::ScopedHGlobal<char> locked_data(hdata);
    out->assign(locked_data.release(), locked_data.Size());
  }
  return hr;
}

}  // namespace

namespace printing {

class PrintBackendWin : public PrintBackend {
 public:
  PrintBackendWin() {}
  virtual ~PrintBackendWin() {}

  virtual bool EnumeratePrinters(PrinterList* printer_list);

  virtual std::string GetDefaultPrinterName();

  virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name,
                                         PrinterCapsAndDefaults* printer_info);

  virtual std::string GetPrinterDriverInfo(const std::string& printer_name);

  virtual bool IsValidPrinter(const std::string& printer_name);
};

bool PrintBackendWin::EnumeratePrinters(PrinterList* printer_list) {
  DCHECK(printer_list);
  DWORD bytes_needed = 0;
  DWORD count_returned = 0;
  BOOL ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2,
                          NULL, 0, &bytes_needed, &count_returned);
  if (!bytes_needed)
    return false;
  scoped_array<BYTE> printer_info_buffer(new BYTE[bytes_needed]);
  ret = EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2,
                     printer_info_buffer.get(), bytes_needed, &bytes_needed,
                     &count_returned);
  DCHECK(ret);
  if (!ret)
    return false;

  std::string default_printer = GetDefaultPrinterName();
  PRINTER_INFO_2* printer_info =
      reinterpret_cast<PRINTER_INFO_2*>(printer_info_buffer.get());
  for (DWORD index = 0; index < count_returned; index++) {
    PrinterBasicInfo info;
    info.printer_name = WideToUTF8(printer_info[index].pPrinterName);
    info.is_default = (info.printer_name == default_printer);
    if (printer_info[index].pComment)
      info.printer_description = WideToUTF8(printer_info[index].pComment);
    info.printer_status = printer_info[index].Status;
    if (printer_info[index].pLocation)
      info.options[kLocationTagName] =
          WideToUTF8(printer_info[index].pLocation);
    if (printer_info[index].pDriverName)
      info.options[kDriverNameTagName] =
          WideToUTF8(printer_info[index].pDriverName);
    printer_list->push_back(info);
  }
  return true;
}

std::string PrintBackendWin::GetDefaultPrinterName() {
  DWORD size = MAX_PATH;
  TCHAR default_printer_name[MAX_PATH];
  if (!::GetDefaultPrinter(default_printer_name, &size))
    return std::string();
  return WideToUTF8(default_printer_name);
}

bool PrintBackendWin::GetPrinterCapsAndDefaults(
    const std::string& printer_name,
    PrinterCapsAndDefaults* printer_info) {
  ScopedXPSInitializer xps_initializer;
  if (!xps_initializer.initialized()) {
    // TODO(sanjeevr): Handle legacy proxy case (with no prntvpt.dll)
    return false;
  }
  if (!IsValidPrinter(printer_name)) {
    return false;
  }
  DCHECK(printer_info);
  HPTPROVIDER provider = NULL;
  std::wstring printer_name_wide = UTF8ToWide(printer_name);
  HRESULT hr = XPSModule::OpenProvider(printer_name_wide, 1, &provider);
  DCHECK(SUCCEEDED(hr));
  if (provider) {
    base::win::ScopedComPtr<IStream> print_capabilities_stream;
    hr = CreateStreamOnHGlobal(NULL, TRUE,
                               print_capabilities_stream.Receive());
    DCHECK(SUCCEEDED(hr));
    if (print_capabilities_stream) {
      base::win::ScopedBstr error;
      hr = XPSModule::GetPrintCapabilities(provider,
                                           NULL,
                                           print_capabilities_stream,
                                           error.Receive());
      DCHECK(SUCCEEDED(hr));
      if (FAILED(hr)) {
        return false;
      }
      hr = StreamOnHGlobalToString(print_capabilities_stream.get(),
                                   &printer_info->printer_capabilities);
      DCHECK(SUCCEEDED(hr));
      printer_info->caps_mime_type = "text/xml";
    }
    ScopedPrinterHandle printer_handle;
    OpenPrinter(const_cast<LPTSTR>(printer_name_wide.c_str()),
                printer_handle.Receive(), NULL);
    DCHECK(printer_handle);
    if (printer_handle.IsValid()) {
      LONG devmode_size = DocumentProperties(
          NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
          NULL, NULL, 0);
      if (devmode_size <= 0)
        return false;
      scoped_array<BYTE> devmode_out_buffer(new BYTE[devmode_size]);
      DEVMODE* devmode_out =
          reinterpret_cast<DEVMODE*>(devmode_out_buffer.get());
      DocumentProperties(
          NULL, printer_handle, const_cast<LPTSTR>(printer_name_wide.c_str()),
          devmode_out, NULL, DM_OUT_BUFFER);
      base::win::ScopedComPtr<IStream> printer_defaults_stream;
      hr = CreateStreamOnHGlobal(NULL, TRUE,
                                 printer_defaults_stream.Receive());
      DCHECK(SUCCEEDED(hr));
      if (printer_defaults_stream) {
        hr = XPSModule::ConvertDevModeToPrintTicket(provider,
                                                    devmode_size,
                                                    devmode_out,
                                                    kPTJobScope,
                                                    printer_defaults_stream);
        DCHECK(SUCCEEDED(hr));
        if (SUCCEEDED(hr)) {
          hr = StreamOnHGlobalToString(printer_defaults_stream.get(),
                                       &printer_info->printer_defaults);
          DCHECK(SUCCEEDED(hr));
          printer_info->defaults_mime_type = "text/xml";
        }
      }
    }
    XPSModule::CloseProvider(provider);
  }
  return true;
}

// Gets the information about driver for a specific printer.
std::string PrintBackendWin::GetPrinterDriverInfo(
    const std::string& printer_name) {
  std::string driver_info;
  ScopedPrinterHandle printer_handle;
  if (!::OpenPrinter(const_cast<LPTSTR>(UTF8ToWide(printer_name).c_str()),
                     printer_handle.Receive(), NULL)) {
    return driver_info;
  }
  DCHECK(printer_handle.IsValid());
  DWORD bytes_needed = 0;
  ::GetPrinterDriver(printer_handle, NULL, 6, NULL, 0, &bytes_needed);
  scoped_array<BYTE> driver_info_buffer(new BYTE[bytes_needed]);
  if (!bytes_needed || !driver_info_buffer.get())
    return driver_info;
  if (!::GetPrinterDriver(printer_handle, NULL, 6, driver_info_buffer.get(),
                          bytes_needed, &bytes_needed)) {
    return driver_info;
  }
  if (!bytes_needed)
    return driver_info;
  const DRIVER_INFO_6* driver_info_6 =
      reinterpret_cast<DRIVER_INFO_6*>(driver_info_buffer.get());

  std::string info[4];

  if (driver_info_6->pName)
    info[0] = WideToUTF8(driver_info_6->pName);

  if (driver_info_6->pDriverPath) {
    scoped_ptr<FileVersionInfo> version_info(
        FileVersionInfo::CreateFileVersionInfo(
            FilePath(driver_info_6->pDriverPath)));
    info[1] = WideToUTF8(version_info->file_version());
    info[2] = WideToUTF8(version_info->product_name());
    info[3] = WideToUTF8(version_info->product_version());
  }

  for (size_t i = 0; i < arraysize(info); ++i) {
    std::replace(info[i].begin(), info[i].end(), ';', ',');
    driver_info.append(info[i]);
    driver_info.append(";");
  }

  return driver_info;
}

bool PrintBackendWin::IsValidPrinter(const std::string& printer_name) {
  ScopedPrinterHandle printer_handle;
  OpenPrinter(const_cast<LPTSTR>(UTF8ToWide(printer_name).c_str()),
              printer_handle.Receive(), NULL);
  return printer_handle.IsValid();
}

scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
    const base::DictionaryValue* print_backend_settings) {
  return new PrintBackendWin;
}

}  // namespace printing
<|endoftext|>


<commit_before>/** \file   ControlNumberGuesser.cc
 *  \brief  Implementation of the ControlNumberGuesser class.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "ControlNumberGuesser.h"
#include <algorithm>
#include <iterator>
#include <unordered_set>
#include <vector>
#include "StringUtil.h"
#include "TextUtil.h"
#include "util.h"

const std::set<std::string> ControlNumberGuesser::EMPTY_SET;

static kyotocabinet::HashDB *CreateOrOpenKeyValueDB(const std::string &db_path) {
    auto db(new kyotocabinet::HashDB());
    if (not (db->open(db_path, kyotocabinet::HashDB::OWRITER | kyotocabinet::HashDB::OCREATE)))
        LOG_ERROR("failed to open or create \"" + db_path + "\"!");
    return db;
}

static const std::string MATCH_DB_PREFIX("/usr/local/var/lib/tuelib/normalised_");

ControlNumberGuesser::ControlNumberGuesser(const OpenMode open_mode) : title_cursor_(nullptr), author_cursor_(nullptr) {
    const std::string TITLES_DB_PATH(MATCH_DB_PREFIX + "titles.db");
    const std::string AUTHORS_DB_PATH(MATCH_DB_PREFIX + "authors.db");

    if (open_mode == CLEAR_DATABASES) {
        ::unlink(TITLES_DB_PATH.c_str());
        ::unlink(AUTHORS_DB_PATH.c_str());
    }

    titles_db_  = CreateOrOpenKeyValueDB(TITLES_DB_PATH);
    authors_db_ = CreateOrOpenKeyValueDB(AUTHORS_DB_PATH);
}

ControlNumberGuesser::~ControlNumberGuesser() {
    delete title_cursor_; delete author_cursor_; delete titles_db_; delete authors_db_;

    std::unordered_set<std::set<std::string> *> already_deleted;
    for (auto &control_number_and_set_ptr : control_number_to_control_number_set_map_) {
        if (already_deleted.find(control_number_and_set_ptr.second) == already_deleted.end()) {
            delete control_number_and_set_ptr.second;
            already_deleted.emplace(control_number_and_set_ptr.second);
        }
    }
}

void ControlNumberGuesser::insertTitle(const std::string &title, const std::string &control_number) {
    const auto normalised_title(NormaliseTitle(title));
    LOG_DEBUG("normalised_title=\"" + normalised_title + "\".");
    if (unlikely(normalised_title.empty()))
        LOG_WARNING("Empty normalised title in record w/ control number: " + control_number);
    else {
        std::string control_numbers;
        if (titles_db_->get(normalised_title, &control_numbers)) {
            control_numbers += '\0';
            control_numbers += control_number;
        } else
            control_numbers = control_number;
        if (unlikely(not titles_db_->set(normalised_title, control_numbers)))
            LOG_ERROR("failed to insert normalised title into the database!");
    }
}

void ControlNumberGuesser::insertAuthors(const std::set<std::string> &authors, const std::string &control_number) {
    for (const auto author : authors) {
        const auto normalised_author_name(TextUtil::UTF8ToLower(NormaliseAuthorName(author)));
        LOG_DEBUG("normalised_author_name=\"" + normalised_author_name + "\".");
        std::string control_numbers;
        if (authors_db_->get(normalised_author_name, &control_numbers)) {
            control_numbers += '\0';
            control_numbers += control_number;
        } else
            control_numbers = control_number;
        if (unlikely(not authors_db_->set(normalised_author_name, control_numbers)))
            LOG_ERROR("failed to insert normalised author into the database!");
    }
}

std::set<std::string> ControlNumberGuesser::getGuessedControlNumbers(const std::string &title, const std::vector<std::string> &authors) const
{
    const auto normalised_title(NormaliseTitle(title));
    if (logger->getMinimumLogLevel() >= Logger::LL_DEBUG)
        LOG_DEBUG("in ControlNumberGuesser::getGuessedControlNumbers: normalised_title=\"" + normalised_title + "\".");
    std::string concatenated_title_control_numbers;
    std::vector<std::string> title_control_numbers;
    if (not titles_db_->get(normalised_title, &concatenated_title_control_numbers)
        or StringUtil::Split(concatenated_title_control_numbers, '\0', &title_control_numbers) == 0)
        return { };

    std::vector<std::string> all_author_control_numbers;
    for (const auto &author : authors) {
        const auto normalised_author(NormaliseAuthorName(author));
        if (logger->getMinimumLogLevel() >= Logger::LL_DEBUG)
            LOG_DEBUG("in ControlNumberGuesser::getGuessedControlNumbers: normalised_author=\"" + normalised_author + "\".");
        std::string concatenated_author_control_numbers;
        std::set<std::string> author_control_numbers;
        if (authors_db_->get(normalised_author, &concatenated_author_control_numbers)) {
            StringUtil::Split(concatenated_author_control_numbers, '\0', &author_control_numbers);
            for (const auto author_control_number : author_control_numbers)
                all_author_control_numbers.emplace_back(author_control_number);
        }
    }
    if (all_author_control_numbers.empty())
        return { };

    std::sort(title_control_numbers.begin(), title_control_numbers.end());
    std::sort(all_author_control_numbers.begin(), all_author_control_numbers.end());
    std::vector<std::string> common_control_numbers;
    std::set_intersection(title_control_numbers.begin(), title_control_numbers.end(),
                          all_author_control_numbers.begin(), all_author_control_numbers.end(),
                          std::back_inserter(common_control_numbers));

    return std::set<std::string>(common_control_numbers.cbegin(), common_control_numbers.cend());
}

bool ControlNumberGuesser::getNextTitle(std::string * const title, std::set<std::string> * const control_numbers) const {
    if (title_cursor_ == nullptr) {
        title_cursor_ = titles_db_->cursor();
        title_cursor_->jump();
    }

    std::string concatenated_control_numbers;
    if (title_cursor_->get(title, &concatenated_control_numbers, /* Move cursor to the next record */true)) {
        StringUtil::Split(concatenated_control_numbers, '\0', control_numbers);
        return true;
    } else {
        delete title_cursor_;
        title_cursor_ = nullptr;
        return false;
    }
}

bool ControlNumberGuesser::getNextAuthor(std::string * const author_name, std::set<std::string> * const control_numbers) const {
    if (author_cursor_ == nullptr) {
        author_cursor_ = authors_db_->cursor();
        author_cursor_->jump();
    }

    std::string concatenated_control_numbers;
    if (author_cursor_->get(author_name, &concatenated_control_numbers, /* Move cursor to the next record */true)) {
        StringUtil::Split(concatenated_control_numbers, '\0', control_numbers);
        return true;
    } else {
        delete author_cursor_;
        author_cursor_ = nullptr;
        return false;
    }
}

void ControlNumberGuesser::FindDups(const std::unordered_map<std::string, std::set<std::string>> &title_to_control_numbers_map,
                                    const std::unordered_map<std::string, std::set<std::string>> &control_number_to_authors_map) const
{
    for (const auto &title_and_control_numbers : title_to_control_numbers_map) {
        if (title_and_control_numbers.second.size() < 2)
            continue;

        // Collect all control numbers for all authors of the current title:
        std::map<std::string, std::set<std::string>> author_to_control_numbers_map;
        for (const auto &control_number : title_and_control_numbers.second) {
            const auto control_number_and_authors(control_number_to_authors_map.find(control_number));
            if (control_number_and_authors == control_number_to_authors_map.cend())
                continue;

            for (const auto &author : control_number_and_authors->second) {
                auto author_and_control_numbers(author_to_control_numbers_map.find(author));
                if (author_and_control_numbers == author_to_control_numbers_map.end())
                    author_to_control_numbers_map[author] = std::set<std::string>{ control_number };
                else
                    author_and_control_numbers->second.emplace(control_number);
            }
        }

        // Record those cases where we found multiple control numbers for the same author for a single title:
        std::unordered_set<std::string> already_processed_control_numbers;
        for (const auto &author_and_control_numbers : author_to_control_numbers_map) {
            if (author_and_control_numbers.second.size() >= 2) {
                bool skip_author(false);

                // We may have multiple authors for the same work but only wish to report each duplicate work once:
                for (const auto &control_number : author_and_control_numbers.second) {
                    if (already_processed_control_numbers.find(control_number) != already_processed_control_numbers.cend()) {
                        skip_author = true;
                        break;

                    }
                }

                if (not skip_author) {
                    std::set<std::string> *new_set(new std::set<std::string>());
                    for (const auto &control_number : author_and_control_numbers.second) {
                        already_processed_control_numbers.emplace(control_number);
                        new_set->emplace(control_number);
                        control_number_to_control_number_set_map_[control_number] = new_set;
                    }
                }
            }
        }
    }
}

void ControlNumberGuesser::InitControlNumberToControlNumberSetMap() const {
    std::unordered_map<std::string, std::set<std::string>> title_to_control_numbers_map;
    std::string title;
    std::set<std::string> control_numbers;
    while (getNextTitle(&title, &control_numbers))
        title_to_control_numbers_map.emplace(title, control_numbers);

    std::unordered_map<std::string, std::set<std::string>> control_number_to_authors_map;
    std::string author;
    while (getNextAuthor(&author, &control_numbers)) {
        for (const auto &control_number : control_numbers) {
            auto control_number_and_authors(control_number_to_authors_map.find(control_number));
            if (control_number_and_authors == control_number_to_authors_map.end())
                control_number_to_authors_map[control_number] = std::set<std::string>{ author };
            else
                control_number_and_authors->second.emplace(author);
        }
    }

    FindDups(title_to_control_numbers_map, control_number_to_authors_map);
}

const std::set<std::string> &ControlNumberGuesser::getControlNumberPartners(const std::string &control_number) const {
    if (control_number_to_control_number_set_map_.empty())
        InitControlNumberToControlNumberSetMap();

    const auto control_number_and_set_ptr(control_number_to_control_number_set_map_.find(control_number));
    if (control_number_and_set_ptr == control_number_to_control_number_set_map_.cend())
        return EMPTY_SET;
    return *control_number_and_set_ptr->second;
}

std::string ControlNumberGuesser::NormaliseTitle(const std::string &title) {
    std::wstring wtitle;
    if (unlikely(not TextUtil::UTF8ToWCharString(title, &wtitle)))
        LOG_ERROR("failed to convert \"" + title + "\" to a wide character string!");

    std::wstring normalised_title;
    bool space_separator_seen(true);
    for (const auto ch : wtitle) {
        if (TextUtil::IsGeneralPunctuationCharacter(ch) or ch == '-' or TextUtil::IsSpaceSeparatorCharacter(ch)) {
            if (not space_separator_seen)
                normalised_title += ' ';
            space_separator_seen = true;
        } else {
            space_separator_seen = false;
            normalised_title += ch;
        }
    }
    if (not normalised_title.empty() and TextUtil::IsSpaceSeparatorCharacter(normalised_title.back()))
        normalised_title.resize(normalised_title.size() - 1);

    TextUtil::ToLower(&normalised_title);

    std::string utf8_normalised_title;
    if (unlikely(not TextUtil::WCharToUTF8String(normalised_title, &utf8_normalised_title)))
        LOG_ERROR("failed to convert a wstring to an UTF8 string!");

    return utf8_normalised_title;
}

std::string ControlNumberGuesser::NormaliseAuthorName(const std::string &author_name) {
    auto trimmed_author_name = StringUtil::TrimWhite(author_name);
    const auto comma_pos(trimmed_author_name.find(','));
    if (comma_pos != std::string::npos)
        trimmed_author_name = StringUtil::TrimWhite(trimmed_author_name.substr(comma_pos + 1) + " "
                                                    + trimmed_author_name.substr(0, comma_pos));

    std::string normalised_author_name;
    bool space_seen(false);
    unsigned non_space_sequence_length(0);
    for (const char ch : trimmed_author_name) {
        switch (ch) {
        case '.':
            if (non_space_sequence_length == 1)
                normalised_author_name.resize(normalised_author_name.length() - 1);
            else
                normalised_author_name += ch;
            if (normalised_author_name.empty())
                space_seen = false;
            else {
                if (normalised_author_name.back() != ' ')
                    normalised_author_name += ' ';
                space_seen = true;
            }
            non_space_sequence_length = 0;
            break;
        case ' ':
            if (not space_seen)
                normalised_author_name += ' ';
            space_seen = true;
            non_space_sequence_length = 0;
            break;
        default:
            normalised_author_name += ch;
            space_seen = false;
            ++non_space_sequence_length;
        }
    }

    return TextUtil::UTF8ToLower(normalised_author_name);
}
<commit_msg>Update ControlNumberGuesser.cc<commit_after>/** \file   ControlNumberGuesser.cc
 *  \brief  Implementation of the ControlNumberGuesser class.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "ControlNumberGuesser.h"
#include <algorithm>
#include <iterator>
#include <unordered_set>
#include <vector>
#include "StringUtil.h"
#include "TextUtil.h"
#include "util.h"

const std::set<std::string> ControlNumberGuesser::EMPTY_SET;

static kyotocabinet::HashDB *CreateOrOpenKeyValueDB(const std::string &db_path) {
    auto db(new kyotocabinet::HashDB());
    if (not (db->open(db_path, kyotocabinet::HashDB::OWRITER | kyotocabinet::HashDB::OCREATE)))
        LOG_ERROR("failed to open or create \"" + db_path + "\"!");
    return db;
}

static const std::string MATCH_DB_PREFIX("/usr/local/var/lib/tuelib/normalised_");

ControlNumberGuesser::ControlNumberGuesser(const OpenMode open_mode) : title_cursor_(nullptr), author_cursor_(nullptr) {
    const std::string TITLES_DB_PATH(MATCH_DB_PREFIX + "titles.db");
    const std::string AUTHORS_DB_PATH(MATCH_DB_PREFIX + "authors.db");

    if (open_mode == CLEAR_DATABASES) {
        ::unlink(TITLES_DB_PATH.c_str());
        ::unlink(AUTHORS_DB_PATH.c_str());
    }

    titles_db_  = CreateOrOpenKeyValueDB(TITLES_DB_PATH);
    authors_db_ = CreateOrOpenKeyValueDB(AUTHORS_DB_PATH);
}

ControlNumberGuesser::~ControlNumberGuesser() {
    delete title_cursor_; delete author_cursor_; delete titles_db_; delete authors_db_;

    std::unordered_set<std::set<std::string> *> already_deleted;
    for (auto &control_number_and_set_ptr : control_number_to_control_number_set_map_) {
        if (already_deleted.find(control_number_and_set_ptr.second) == already_deleted.end()) {
            delete control_number_and_set_ptr.second;
            already_deleted.emplace(control_number_and_set_ptr.second);
        }
    }
}

void ControlNumberGuesser::insertTitle(const std::string &title, const std::string &control_number) {
    const auto normalised_title(NormaliseTitle(title));
    LOG_DEBUG("normalised_title=\"" + normalised_title + "\".");
    if (unlikely(normalised_title.empty()))
        LOG_WARNING("Empty normalised title in record w/ control number: " + control_number);
    else {
        std::string control_numbers;
        if (titles_db_->get(normalised_title, &control_numbers)) {
            control_numbers += '\0';
            control_numbers += control_number;
        } else
            control_numbers = control_number;
        if (unlikely(not titles_db_->set(normalised_title, control_numbers)))
            LOG_ERROR("failed to insert normalised title into the database!");
    }
}

void ControlNumberGuesser::insertAuthors(const std::set<std::string> &authors, const std::string &control_number) {
    for (const auto author : authors) {
        const auto normalised_author_name(TextUtil::UTF8ToLower(NormaliseAuthorName(author)));
        LOG_DEBUG("normalised_author_name=\"" + normalised_author_name + "\".");
        std::string control_numbers;
        if (authors_db_->get(normalised_author_name, &control_numbers)) {
            control_numbers += '\0';
            control_numbers += control_number;
        } else
            control_numbers = control_number;
        if (unlikely(not authors_db_->set(normalised_author_name, control_numbers)))
            LOG_ERROR("failed to insert normalised author into the database!");
    }
}

std::set<std::string> ControlNumberGuesser::getGuessedControlNumbers(const std::string &title, const std::vector<std::string> &authors) const
{
    const auto normalised_title(NormaliseTitle(title));
    if (logger->getMinimumLogLevel() >= Logger::LL_DEBUG)
        LOG_DEBUG("in ControlNumberGuesser::getGuessedControlNumbers: normalised_title=\"" + normalised_title + "\".");
    std::string concatenated_title_control_numbers;
    std::vector<std::string> title_control_numbers;
    if (not titles_db_->get(normalised_title, &concatenated_title_control_numbers)
        or StringUtil::Split(concatenated_title_control_numbers, '\0', &title_control_numbers) == 0)
        return { };

    std::vector<std::string> all_author_control_numbers;
    for (const auto &author : authors) {
        const auto normalised_author(NormaliseAuthorName(author));
        if (logger->getMinimumLogLevel() >= Logger::LL_DEBUG)
            LOG_DEBUG("in ControlNumberGuesser::getGuessedControlNumbers: normalised_author=\"" + normalised_author + "\".");
        std::string concatenated_author_control_numbers;
        std::set<std::string> author_control_numbers;
        if (authors_db_->get(normalised_author, &concatenated_author_control_numbers)) {
            StringUtil::Split(concatenated_author_control_numbers, '\0', &author_control_numbers);
            for (const auto author_control_number : author_control_numbers)
                all_author_control_numbers.emplace_back(author_control_number);
        }
    }
    if (all_author_control_numbers.empty())
        return { };

    std::sort(title_control_numbers.begin(), title_control_numbers.end());
    std::sort(all_author_control_numbers.begin(), all_author_control_numbers.end());
    std::vector<std::string> common_control_numbers;
    std::set_intersection(title_control_numbers.begin(), title_control_numbers.end(),
                          all_author_control_numbers.begin(), all_author_control_numbers.end(),
                          std::back_inserter(common_control_numbers));

    return std::set<std::string>(common_control_numbers.cbegin(), common_control_numbers.cend());
}

bool ControlNumberGuesser::getNextTitle(std::string * const title, std::set<std::string> * const control_numbers) const {
    if (title_cursor_ == nullptr) {
        title_cursor_ = titles_db_->cursor();
        title_cursor_->jump();
    }

    std::string concatenated_control_numbers;
    if (title_cursor_->get(title, &concatenated_control_numbers, /* Move cursor to the next record */true)) {
        StringUtil::Split(concatenated_control_numbers, '\0', control_numbers);
        return true;
    } else {
        delete title_cursor_;
        title_cursor_ = nullptr;
        return false;
    }
}

bool ControlNumberGuesser::getNextAuthor(std::string * const author_name, std::set<std::string> * const control_numbers) const {
    if (author_cursor_ == nullptr) {
        author_cursor_ = authors_db_->cursor();
        author_cursor_->jump();
    }

    std::string concatenated_control_numbers;
    if (author_cursor_->get(author_name, &concatenated_control_numbers, /* Move cursor to the next record */true)) {
        StringUtil::Split(concatenated_control_numbers, '\0', control_numbers);
        return true;
    } else {
        delete author_cursor_;
        author_cursor_ = nullptr;
        return false;
    }
}

void ControlNumberGuesser::FindDups(const std::unordered_map<std::string, std::set<std::string>> &title_to_control_numbers_map,
                                    const std::unordered_map<std::string, std::set<std::string>> &control_number_to_authors_map) const
{
    for (const auto &title_and_control_numbers : title_to_control_numbers_map) {
        if (title_and_control_numbers.second.size() < 2)
            continue;

        // Collect all control numbers for all authors of the current title:
        std::map<std::string, std::set<std::string>> author_to_control_numbers_map;
        for (const auto &control_number : title_and_control_numbers.second) {
            const auto control_number_and_authors(control_number_to_authors_map.find(control_number));
            if (control_number_and_authors == control_number_to_authors_map.cend())
                continue;

            for (const auto &author : control_number_and_authors->second) {
                auto author_and_control_numbers(author_to_control_numbers_map.find(author));
                if (author_and_control_numbers == author_to_control_numbers_map.end())
                    author_to_control_numbers_map[author] = std::set<std::string>{ control_number };
                else
                    author_and_control_numbers->second.emplace(control_number);
            }
        }

        // Record those cases where we found multiple control numbers for the same author for a single title:
        std::unordered_set<std::string> already_processed_control_numbers;
        for (const auto &author_and_control_numbers : author_to_control_numbers_map) {
            if (author_and_control_numbers.second.size() >= 2) {
                bool skip_author(false);

                // We may have multiple authors for the same work but only wish to report each duplicate work once:
                for (const auto &control_number : author_and_control_numbers.second) {
                    if (already_processed_control_numbers.find(control_number) != already_processed_control_numbers.cend()) {
                        skip_author = true;
                        break;
                    }
                }

                if (not skip_author) {
                    std::set<std::string> *new_set(new std::set<std::string>());
                    for (const auto &control_number : author_and_control_numbers.second) {
                        already_processed_control_numbers.emplace(control_number);
                        new_set->emplace(control_number);
                        control_number_to_control_number_set_map_[control_number] = new_set;
                    }
                }
            }
        }
    }
}

void ControlNumberGuesser::InitControlNumberToControlNumberSetMap() const {
    std::unordered_map<std::string, std::set<std::string>> title_to_control_numbers_map;
    std::string title;
    std::set<std::string> control_numbers;
    while (getNextTitle(&title, &control_numbers))
        title_to_control_numbers_map.emplace(title, control_numbers);

    std::unordered_map<std::string, std::set<std::string>> control_number_to_authors_map;
    std::string author;
    while (getNextAuthor(&author, &control_numbers)) {
        for (const auto &control_number : control_numbers) {
            auto control_number_and_authors(control_number_to_authors_map.find(control_number));
            if (control_number_and_authors == control_number_to_authors_map.end())
                control_number_to_authors_map[control_number] = std::set<std::string>{ author };
            else
                control_number_and_authors->second.emplace(author);
        }
    }

    FindDups(title_to_control_numbers_map, control_number_to_authors_map);
}

const std::set<std::string> &ControlNumberGuesser::getControlNumberPartners(const std::string &control_number) const {
    if (control_number_to_control_number_set_map_.empty())
        InitControlNumberToControlNumberSetMap();

    const auto control_number_and_set_ptr(control_number_to_control_number_set_map_.find(control_number));
    if (control_number_and_set_ptr == control_number_to_control_number_set_map_.cend())
        return EMPTY_SET;
    return *control_number_and_set_ptr->second;
}

std::string ControlNumberGuesser::NormaliseTitle(const std::string &title) {
    std::wstring wtitle;
    if (unlikely(not TextUtil::UTF8ToWCharString(title, &wtitle)))
        LOG_ERROR("failed to convert \"" + title + "\" to a wide character string!");

    std::wstring normalised_title;
    bool space_separator_seen(true);
    for (const auto ch : wtitle) {
        if (TextUtil::IsGeneralPunctuationCharacter(ch) or ch == '-' or TextUtil::IsSpaceSeparatorCharacter(ch)) {
            if (not space_separator_seen)
                normalised_title += ' ';
            space_separator_seen = true;
        } else {
            space_separator_seen = false;
            normalised_title += ch;
        }
    }
    if (not normalised_title.empty() and TextUtil::IsSpaceSeparatorCharacter(normalised_title.back()))
        normalised_title.resize(normalised_title.size() - 1);

    TextUtil::ToLower(&normalised_title);

    std::string utf8_normalised_title;
    if (unlikely(not TextUtil::WCharToUTF8String(normalised_title, &utf8_normalised_title)))
        LOG_ERROR("failed to convert a wstring to an UTF8 string!");

    return utf8_normalised_title;
}

std::string ControlNumberGuesser::NormaliseAuthorName(const std::string &author_name) {
    auto trimmed_author_name = StringUtil::TrimWhite(author_name);
    const auto comma_pos(trimmed_author_name.find(','));
    if (comma_pos != std::string::npos)
        trimmed_author_name = StringUtil::TrimWhite(trimmed_author_name.substr(comma_pos + 1) + " "
                                                    + trimmed_author_name.substr(0, comma_pos));

    std::string normalised_author_name;
    bool space_seen(false);
    unsigned non_space_sequence_length(0);
    for (const char ch : trimmed_author_name) {
        switch (ch) {
        case '.':
            if (non_space_sequence_length == 1)
                normalised_author_name.resize(normalised_author_name.length() - 1);
            else
                normalised_author_name += ch;
            if (normalised_author_name.empty())
                space_seen = false;
            else {
                if (normalised_author_name.back() != ' ')
                    normalised_author_name += ' ';
                space_seen = true;
            }
            non_space_sequence_length = 0;
            break;
        case ' ':
            if (not space_seen)
                normalised_author_name += ' ';
            space_seen = true;
            non_space_sequence_length = 0;
            break;
        default:
            normalised_author_name += ch;
            space_seen = false;
            ++non_space_sequence_length;
        }
    }

    return TextUtil::UTF8ToLower(normalised_author_name);
}
<|endoftext|>


<commit_before>/* Copyright (c) 2016, the Cap authors.
 *
 * This file is subject to the Modified BSD License and may not be distributed
 * without copyright and license information. Please refer to the file LICENSE
 * for the text and further information on this license.
 */

#include <cap/resistor_capacitor.h>
#ifdef WITH_DEAL_II
#include <cap/supercapacitor.h>
#include <cap/new_supercapacitor.h>
#endif

namespace cap
{

EnergyStorageDeviceInspector::~EnergyStorageDeviceInspector() = default;

EnergyStorageDeviceBuilder::~EnergyStorageDeviceBuilder() = default;

void EnergyStorageDeviceBuilder::register_energy_storage_device(
    std::string const &type, EnergyStorageDeviceBuilder *builder)
{
  EnergyStorageDevice::_builders[type] = builder;
}

std::map<std::string, EnergyStorageDeviceBuilder *>
    EnergyStorageDevice::_builders =
        std::map<std::string, EnergyStorageDeviceBuilder *>();

std::unique_ptr<EnergyStorageDevice>
EnergyStorageDevice::build(boost::mpi::communicator const &comm,
                           boost::property_tree::ptree const &ptree)
{
  auto const type = ptree.get<std::string>("type");
  auto const it = _builders.find(type);
  if (it != _builders.end())
    return (it->second)->build(comm, ptree);
  else
    throw std::runtime_error("invalid EnergyStorageDevice type `" + type +
                             "`\n");
}

EnergyStorageDevice::EnergyStorageDevice(
    boost::mpi::communicator const &communicator)
    : _communicator(communicator)
{
}

std::shared_ptr<EnergyStorageDevice>
buildEnergyStorageDevice(boost::mpi::communicator const &comm,
                         boost::property_tree::ptree const &ptree)
{
  std::string const type = ptree.get<std::string>("type", "unknown_type");
  if (type.compare("SeriesRC") == 0)
    return std::make_shared<cap::SeriesRC>(comm, ptree);
  else if (type.compare("ParallelRC") == 0)
    return std::make_shared<cap::ParallelRC>(comm, ptree);
  else if (type.compare("SuperCapacitor") == 0)
  {
#ifdef WITH_DEAL_II
    int const dim = ptree.get<int>("dim");
    if (dim == 2)
      return std::make_shared<cap::SuperCapacitor<2>>(comm, ptree);
    else if (dim == 3)
      return std::make_shared<cap::SuperCapacitor<3>>(comm, ptree);
    else
      throw std::runtime_error("dim=" + std::to_string(dim) +
                               " must be 2 or 3");
#else
    throw std::runtime_error("reconfigure with deal.II");
#endif
  }
  else if (type.compare("New_SuperCapacitor") == 0)
  {
#ifdef WITH_DEAL_II
    int const dim = ptree.get<int>("dim");
    if (dim == 2)
      return std::make_shared<cap::New_SuperCapacitor<2>>(comm, ptree);
    else if (dim == 3)
      return std::make_shared<cap::New_SuperCapacitor<3>>(comm, ptree);
    else
      throw std::runtime_error("dim=" + std::to_string(dim) +
                               " must be 2 or 3");
#else
    throw std::runtime_error("reconfigure with deal.II");
#endif
  }
  else
    throw std::runtime_error("invalid energy storage type ``" + type + "''\n");
}

EnergyStorageDevice::~EnergyStorageDevice() = default;

} // end namespace cap
<commit_msg>Remove unused code.<commit_after>/* Copyright (c) 2016, the Cap authors.
 *
 * This file is subject to the Modified BSD License and may not be distributed
 * without copyright and license information. Please refer to the file LICENSE
 * for the text and further information on this license.
 */

#include <cap/resistor_capacitor.h>
#ifdef WITH_DEAL_II
#include <cap/supercapacitor.h>
#include <cap/new_supercapacitor.h>
#endif

namespace cap
{

EnergyStorageDeviceInspector::~EnergyStorageDeviceInspector() = default;

EnergyStorageDeviceBuilder::~EnergyStorageDeviceBuilder() = default;

void EnergyStorageDeviceBuilder::register_energy_storage_device(
    std::string const &type, EnergyStorageDeviceBuilder *builder)
{
  EnergyStorageDevice::_builders[type] = builder;
}

std::map<std::string, EnergyStorageDeviceBuilder *>
    EnergyStorageDevice::_builders =
        std::map<std::string, EnergyStorageDeviceBuilder *>();

std::unique_ptr<EnergyStorageDevice>
EnergyStorageDevice::build(boost::mpi::communicator const &comm,
                           boost::property_tree::ptree const &ptree)
{
  auto const type = ptree.get<std::string>("type");
  auto const it = _builders.find(type);
  if (it != _builders.end())
    return (it->second)->build(comm, ptree);
  else
    throw std::runtime_error("invalid EnergyStorageDevice type `" + type +
                             "`\n");
}

EnergyStorageDevice::EnergyStorageDevice(
    boost::mpi::communicator const &communicator)
    : _communicator(communicator)
{
}

EnergyStorageDevice::~EnergyStorageDevice() = default;

} // end namespace cap
<|endoftext|>