<commit_before>#include "library/common/engine.h"

#include "envoy/stats/histogram.h"

#include "source/common/common/lock_guard.h"

#include "library/common/bridge/utility.h"
#include "library/common/config/internal.h"
#include "library/common/data/utility.h"
#include "library/common/stats/utility.h"

namespace Envoy {

Engine::Engine(envoy_engine_callbacks callbacks, envoy_logger logger,
               envoy_event_tracker event_tracker)
    : callbacks_(callbacks), logger_(logger), event_tracker_(event_tracker),
      dispatcher_(std::make_unique<Event::ProvisionalDispatcher>()) {
  // Ensure static factory registration occurs on time.
  // TODO: ensure this is only called one time once multiple Engine objects can be allocated.
  // https://github.com/lyft/envoy-mobile/issues/332
  ExtensionRegistry::registerFactories();

  // TODO(Augustyniak): Capturing an address of event_tracker_ and registering it in the API
  // registry may lead to crashes at Engine shutdown. To be figured out as part of
  // https://github.com/lyft/envoy-mobile/issues/332
  Envoy::Api::External::registerApi(std::string(envoy_event_tracker_api_name), &event_tracker_);
}

envoy_status_t Engine::run(const std::string config, const std::string log_level) {
  // Start the Envoy on the dedicated thread. Note: due to how the assignment operator works with
  // std::thread, main_thread_ is the same object after this call, but its state is replaced with
  // that of the temporary. The temporary object's state becomes the default state, which does
  // nothing.
  main_thread_ = std::thread(&Engine::main, this, std::string(config), std::string(log_level));
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::main(const std::string config, const std::string log_level) {
  // Using unique_ptr ensures main_common's lifespan is strictly scoped to this function.
  std::unique_ptr<EngineCommon> main_common;
  const std::string name = "envoy";
  const std::string config_flag = "--config-yaml";
  const std::string composed_config = absl::StrCat(config_header, config);
  const std::string log_flag = "-l";
  const std::string concurrency_option = "--concurrency";
  const std::string concurrency_arg = "0";
  std::vector<const char*> envoy_argv = {name.c_str(),
                                         config_flag.c_str(),
                                         composed_config.c_str(),
                                         concurrency_option.c_str(),
                                         concurrency_arg.c_str(),
                                         log_flag.c_str(),
                                         log_level.c_str(),
                                         nullptr};
  {
    Thread::LockGuard lock(mutex_);
    try {
      if (event_tracker_.track != nullptr) {
        assert_handler_registration_ =
            Assert::addDebugAssertionFailureRecordAction([this](const char* location) {
              const auto event = Bridge::Utility::makeEnvoyMap(
                  {{"name", "assertion"}, {"location", std::string(location)}});
              event_tracker_.track(event, event_tracker_.context);
            });
        bug_handler_registration_ =
            Assert::addEnvoyBugFailureRecordAction([this](const char* location) {
              const auto event = Bridge::Utility::makeEnvoyMap(
                  {{"name", "bug"}, {"location", std::string(location)}});
              event_tracker_.track(event, event_tracker_.context);
            });
      }

      if (logger_.log) {
        log_delegate_ptr_ =
            std::make_unique<Logger::LambdaDelegate>(logger_, Logger::Registry::getSink());
      } else {
        log_delegate_ptr_ =
            std::make_unique<Logger::DefaultDelegate>(log_mutex_, Logger::Registry::getSink());
      }

      main_common = std::make_unique<EngineCommon>(envoy_argv.size() - 1, envoy_argv.data());
      server_ = main_common->server();
      event_dispatcher_ = &server_->dispatcher();

      cv_.notifyAll();
    } catch (const Envoy::NoServingException& e) {
      PANIC(e.what());
    } catch (const Envoy::MalformedArgvException& e) {
      PANIC(e.what());
    } catch (const Envoy::EnvoyException& e) {
      PANIC(e.what());
    }

    // Note: We're waiting longer than we might otherwise to drain to the main thread's dispatcher.
    // This is because we're not simply waiting for its availability and for it to have started, but
    // also because we're waiting for clusters to have done their first attempt at DNS resolution.
    // When we improve synchronous failure handling and/or move to dynamic forwarding, we only need
    // to wait until the dispatcher is running (and can drain by enqueueing a drain callback on it,
    // as we did previously).

    postinit_callback_handler_ = main_common->server()->lifecycleNotifier().registerCallback(
        Envoy::Server::ServerLifecycleNotifier::Stage::PostInit, [this]() -> void {
          ASSERT(Thread::MainThread::isMainOrTestThread());

          network_configurator_ =
              Network::ConfiguratorFactory{server_->serverFactoryContext()}.get();
          auto v4_interfaces = network_configurator_->enumerateV4Interfaces();
          auto v6_interfaces = network_configurator_->enumerateV4Interfaces();
          logInterfaces("netconf_get_v4_interfaces", v4_interfaces);
          logInterfaces("netconf_get_v6_interfaces", v6_interfaces);
          client_scope_ = server_->serverFactoryContext().scope().createScope("pulse.");
          // StatNameSet is lock-free, the benefit of using it is being able to create StatsName
          // on-the-fly without risking contention on system with lots of threads.
          // It also comes with ease of programming.
          stat_name_set_ = client_scope_->symbolTable().makeSet("pulse");
          auto api_listener = server_->listenerManager().apiListener()->get().http();
          ASSERT(api_listener.has_value());
          http_client_ = std::make_unique<Http::Client>(api_listener.value(), *dispatcher_,
                                                        server_->serverFactoryContext().scope(),
                                                        server_->api().randomGenerator());
          dispatcher_->drain(server_->dispatcher());
          if (callbacks_.on_engine_running != nullptr) {
            callbacks_.on_engine_running(callbacks_.context);
          }
        });
  } // mutex_

  // The main run loop must run without holding the mutex, so that the destructor can acquire it.
  bool run_success = main_common->run();
  // The above call is blocking; at this point the event loop has exited.

  // Ensure destructors run on Envoy's main thread.
  postinit_callback_handler_.reset(nullptr);
  network_configurator_.reset();
  client_scope_.reset(nullptr);
  stat_name_set_.reset();
  log_delegate_ptr_.reset(nullptr);
  main_common.reset(nullptr);
  bug_handler_registration_.reset(nullptr);
  assert_handler_registration_.reset(nullptr);

  callbacks_.on_exit(callbacks_.context);

  return run_success ? ENVOY_SUCCESS : ENVOY_FAILURE;
}

envoy_status_t Engine::terminate() {
  // If main_thread_ has finished (or hasn't started), there's nothing more to do.
  if (!main_thread_.joinable()) {
    return ENVOY_FAILURE;
  }

  // We need to be sure that MainCommon is finished being constructed so we can dispatch shutdown.
  {
    Thread::LockGuard lock(mutex_);

    if (!event_dispatcher_) {
      cv_.wait(mutex_);
    }

    ASSERT(event_dispatcher_);

    // Exit the event loop and finish up in Engine::run(...)
    if (std::this_thread::get_id() == main_thread_.get_id()) {
      // TODO(goaway): figure out some way to support this.
      PANIC("Terminating the engine from its own main thread is currently unsupported.");
    } else {
      event_dispatcher_->exit();
    }
  } // lock(_mutex)

  if (std::this_thread::get_id() != main_thread_.get_id()) {
    main_thread_.join();
  }

  return ENVOY_SUCCESS;
}

Engine::~Engine() { terminate(); }

envoy_status_t Engine::recordCounterInc(const std::string& elements, envoy_stats_tags tags,
                                        uint64_t count) {
  ENVOY_LOG(trace, "[pulse.{}] recordCounterInc", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Utility::counterFromElements(*client_scope_, {Stats::DynamicName(name)}, tags_vctr)
      .add(count);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::recordGaugeSet(const std::string& elements, envoy_stats_tags tags,
                                      uint64_t value) {
  ENVOY_LOG(trace, "[pulse.{}] recordGaugeSet", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Utility::gaugeFromElements(*client_scope_, {Stats::DynamicName(name)},
                                    Stats::Gauge::ImportMode::NeverImport, tags_vctr)
      .set(value);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::recordGaugeAdd(const std::string& elements, envoy_stats_tags tags,
                                      uint64_t amount) {
  ENVOY_LOG(trace, "[pulse.{}] recordGaugeAdd", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Utility::gaugeFromElements(*client_scope_, {Stats::DynamicName(name)},
                                    Stats::Gauge::ImportMode::NeverImport, tags_vctr)
      .add(amount);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::recordGaugeSub(const std::string& elements, envoy_stats_tags tags,
                                      uint64_t amount) {
  ENVOY_LOG(trace, "[pulse.{}] recordGaugeSub", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Utility::gaugeFromElements(*client_scope_, {Stats::DynamicName(name)},
                                    Stats::Gauge::ImportMode::NeverImport, tags_vctr)
      .sub(amount);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::recordHistogramValue(const std::string& elements, envoy_stats_tags tags,
                                            uint64_t value,
                                            envoy_histogram_stat_unit_t unit_measure) {
  ENVOY_LOG(trace, "[pulse.{}] recordHistogramValue", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Histogram::Unit envoy_unit_measure = Stats::Histogram::Unit::Unspecified;
  switch (unit_measure) {
  case MILLISECONDS:
    envoy_unit_measure = Stats::Histogram::Unit::Milliseconds;
    break;
  case MICROSECONDS:
    envoy_unit_measure = Stats::Histogram::Unit::Microseconds;
    break;
  case BYTES:
    envoy_unit_measure = Stats::Histogram::Unit::Bytes;
    break;
  case UNSPECIFIED:
    envoy_unit_measure = Stats::Histogram::Unit::Unspecified;
    break;
  }

  Stats::Utility::histogramFromElements(*client_scope_, {Stats::DynamicName(name)},
                                        envoy_unit_measure, tags_vctr)
      .recordValue(value);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::makeAdminCall(absl::string_view path, absl::string_view method,
                                     envoy_data& out) {
  ENVOY_LOG(trace, "admin call {} {}", method, path);

  ASSERT(dispatcher_->isThreadSafe(), "admin calls must be run from the dispatcher's context");
  auto response_headers = Http::ResponseHeaderMapImpl::create();
  std::string body;
  const auto code = server_->admin().request(path, method, *response_headers, body);
  if (code != Http::Code::OK) {
    ENVOY_LOG(warn, "admin call failed with status {} body {}", code, body);
    return ENVOY_FAILURE;
  }

  out = Data::Utility::copyToBridgeData(body);

  return ENVOY_SUCCESS;
}

Event::ProvisionalDispatcher& Engine::dispatcher() { return *dispatcher_; }

Http::Client& Engine::httpClient() {
  RELEASE_ASSERT(dispatcher_->isThreadSafe(),
                 "httpClient must be accessed from dispatcher's context");
  return *http_client_;
}

Network::Configurator& Engine::networkConfigurator() {
  RELEASE_ASSERT(dispatcher_->isThreadSafe(),
                 "networkConfigurator must be accessed from dispatcher's context");
  return *network_configurator_;
}

void Engine::flushStats() {
  ASSERT(dispatcher_->isThreadSafe(), "flushStats must be called from the dispatcher's context");

  server_->flushStats();
}

void Engine::drainConnections() {
  ASSERT(dispatcher_->isThreadSafe(),
         "drainConnections must be called from the dispatcher's context");
  server_->clusterManager().drainConnections();
}

Upstream::ClusterManager& Engine::getClusterManager() {
  ASSERT(dispatcher_->isThreadSafe(),
         "getClusterManager must be called from the dispatcher's context");
  return server_->clusterManager();
}

void Engine::logInterfaces(absl::string_view event,
                           std::vector<Network::InterfacePair>& interfaces) {
  std::vector<std::string> names;
  names.resize(interfaces.size());
  std::transform(interfaces.begin(), interfaces.end(), names.begin(),
                 [](Network::InterfacePair& pair) { return std::get<0>(pair); });

  auto unique_end = std::unique(names.begin(), names.end());
  std::string all_names = std::accumulate(names.begin(), unique_end, std::string{},
                                          [](std::string acc, std::string next) {
                                            return acc.empty() ? next : std::move(acc) + "," + next;
                                          });
  ENVOY_LOG_EVENT(debug, event, all_names);
}

} // namespace Envoy
<commit_msg>Fix V6 interface binding logging (#1959)<commit_after>#include "library/common/engine.h"

#include "envoy/stats/histogram.h"

#include "source/common/common/lock_guard.h"

#include "library/common/bridge/utility.h"
#include "library/common/config/internal.h"
#include "library/common/data/utility.h"
#include "library/common/stats/utility.h"

namespace Envoy {

Engine::Engine(envoy_engine_callbacks callbacks, envoy_logger logger,
               envoy_event_tracker event_tracker)
    : callbacks_(callbacks), logger_(logger), event_tracker_(event_tracker),
      dispatcher_(std::make_unique<Event::ProvisionalDispatcher>()) {
  // Ensure static factory registration occurs on time.
  // TODO: ensure this is only called one time once multiple Engine objects can be allocated.
  // https://github.com/lyft/envoy-mobile/issues/332
  ExtensionRegistry::registerFactories();

  // TODO(Augustyniak): Capturing an address of event_tracker_ and registering it in the API
  // registry may lead to crashes at Engine shutdown. To be figured out as part of
  // https://github.com/lyft/envoy-mobile/issues/332
  Envoy::Api::External::registerApi(std::string(envoy_event_tracker_api_name), &event_tracker_);
}

envoy_status_t Engine::run(const std::string config, const std::string log_level) {
  // Start the Envoy on the dedicated thread. Note: due to how the assignment operator works with
  // std::thread, main_thread_ is the same object after this call, but its state is replaced with
  // that of the temporary. The temporary object's state becomes the default state, which does
  // nothing.
  main_thread_ = std::thread(&Engine::main, this, std::string(config), std::string(log_level));
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::main(const std::string config, const std::string log_level) {
  // Using unique_ptr ensures main_common's lifespan is strictly scoped to this function.
  std::unique_ptr<EngineCommon> main_common;
  const std::string name = "envoy";
  const std::string config_flag = "--config-yaml";
  const std::string composed_config = absl::StrCat(config_header, config);
  const std::string log_flag = "-l";
  const std::string concurrency_option = "--concurrency";
  const std::string concurrency_arg = "0";
  std::vector<const char*> envoy_argv = {name.c_str(),
                                         config_flag.c_str(),
                                         composed_config.c_str(),
                                         concurrency_option.c_str(),
                                         concurrency_arg.c_str(),
                                         log_flag.c_str(),
                                         log_level.c_str(),
                                         nullptr};
  {
    Thread::LockGuard lock(mutex_);
    try {
      if (event_tracker_.track != nullptr) {
        assert_handler_registration_ =
            Assert::addDebugAssertionFailureRecordAction([this](const char* location) {
              const auto event = Bridge::Utility::makeEnvoyMap(
                  {{"name", "assertion"}, {"location", std::string(location)}});
              event_tracker_.track(event, event_tracker_.context);
            });
        bug_handler_registration_ =
            Assert::addEnvoyBugFailureRecordAction([this](const char* location) {
              const auto event = Bridge::Utility::makeEnvoyMap(
                  {{"name", "bug"}, {"location", std::string(location)}});
              event_tracker_.track(event, event_tracker_.context);
            });
      }

      if (logger_.log) {
        log_delegate_ptr_ =
            std::make_unique<Logger::LambdaDelegate>(logger_, Logger::Registry::getSink());
      } else {
        log_delegate_ptr_ =
            std::make_unique<Logger::DefaultDelegate>(log_mutex_, Logger::Registry::getSink());
      }

      main_common = std::make_unique<EngineCommon>(envoy_argv.size() - 1, envoy_argv.data());
      server_ = main_common->server();
      event_dispatcher_ = &server_->dispatcher();

      cv_.notifyAll();
    } catch (const Envoy::NoServingException& e) {
      PANIC(e.what());
    } catch (const Envoy::MalformedArgvException& e) {
      PANIC(e.what());
    } catch (const Envoy::EnvoyException& e) {
      PANIC(e.what());
    }

    // Note: We're waiting longer than we might otherwise to drain to the main thread's dispatcher.
    // This is because we're not simply waiting for its availability and for it to have started, but
    // also because we're waiting for clusters to have done their first attempt at DNS resolution.
    // When we improve synchronous failure handling and/or move to dynamic forwarding, we only need
    // to wait until the dispatcher is running (and can drain by enqueueing a drain callback on it,
    // as we did previously).

    postinit_callback_handler_ = main_common->server()->lifecycleNotifier().registerCallback(
        Envoy::Server::ServerLifecycleNotifier::Stage::PostInit, [this]() -> void {
          ASSERT(Thread::MainThread::isMainOrTestThread());

          network_configurator_ =
              Network::ConfiguratorFactory{server_->serverFactoryContext()}.get();
          auto v4_interfaces = network_configurator_->enumerateV4Interfaces();
          auto v6_interfaces = network_configurator_->enumerateV6Interfaces();
          logInterfaces("netconf_get_v4_interfaces", v4_interfaces);
          logInterfaces("netconf_get_v6_interfaces", v6_interfaces);
          client_scope_ = server_->serverFactoryContext().scope().createScope("pulse.");
          // StatNameSet is lock-free, the benefit of using it is being able to create StatsName
          // on-the-fly without risking contention on system with lots of threads.
          // It also comes with ease of programming.
          stat_name_set_ = client_scope_->symbolTable().makeSet("pulse");
          auto api_listener = server_->listenerManager().apiListener()->get().http();
          ASSERT(api_listener.has_value());
          http_client_ = std::make_unique<Http::Client>(api_listener.value(), *dispatcher_,
                                                        server_->serverFactoryContext().scope(),
                                                        server_->api().randomGenerator());
          dispatcher_->drain(server_->dispatcher());
          if (callbacks_.on_engine_running != nullptr) {
            callbacks_.on_engine_running(callbacks_.context);
          }
        });
  } // mutex_

  // The main run loop must run without holding the mutex, so that the destructor can acquire it.
  bool run_success = main_common->run();
  // The above call is blocking; at this point the event loop has exited.

  // Ensure destructors run on Envoy's main thread.
  postinit_callback_handler_.reset(nullptr);
  network_configurator_.reset();
  client_scope_.reset(nullptr);
  stat_name_set_.reset();
  log_delegate_ptr_.reset(nullptr);
  main_common.reset(nullptr);
  bug_handler_registration_.reset(nullptr);
  assert_handler_registration_.reset(nullptr);

  callbacks_.on_exit(callbacks_.context);

  return run_success ? ENVOY_SUCCESS : ENVOY_FAILURE;
}

envoy_status_t Engine::terminate() {
  // If main_thread_ has finished (or hasn't started), there's nothing more to do.
  if (!main_thread_.joinable()) {
    return ENVOY_FAILURE;
  }

  // We need to be sure that MainCommon is finished being constructed so we can dispatch shutdown.
  {
    Thread::LockGuard lock(mutex_);

    if (!event_dispatcher_) {
      cv_.wait(mutex_);
    }

    ASSERT(event_dispatcher_);

    // Exit the event loop and finish up in Engine::run(...)
    if (std::this_thread::get_id() == main_thread_.get_id()) {
      // TODO(goaway): figure out some way to support this.
      PANIC("Terminating the engine from its own main thread is currently unsupported.");
    } else {
      event_dispatcher_->exit();
    }
  } // lock(_mutex)

  if (std::this_thread::get_id() != main_thread_.get_id()) {
    main_thread_.join();
  }

  return ENVOY_SUCCESS;
}

Engine::~Engine() { terminate(); }

envoy_status_t Engine::recordCounterInc(const std::string& elements, envoy_stats_tags tags,
                                        uint64_t count) {
  ENVOY_LOG(trace, "[pulse.{}] recordCounterInc", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Utility::counterFromElements(*client_scope_, {Stats::DynamicName(name)}, tags_vctr)
      .add(count);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::recordGaugeSet(const std::string& elements, envoy_stats_tags tags,
                                      uint64_t value) {
  ENVOY_LOG(trace, "[pulse.{}] recordGaugeSet", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Utility::gaugeFromElements(*client_scope_, {Stats::DynamicName(name)},
                                    Stats::Gauge::ImportMode::NeverImport, tags_vctr)
      .set(value);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::recordGaugeAdd(const std::string& elements, envoy_stats_tags tags,
                                      uint64_t amount) {
  ENVOY_LOG(trace, "[pulse.{}] recordGaugeAdd", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Utility::gaugeFromElements(*client_scope_, {Stats::DynamicName(name)},
                                    Stats::Gauge::ImportMode::NeverImport, tags_vctr)
      .add(amount);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::recordGaugeSub(const std::string& elements, envoy_stats_tags tags,
                                      uint64_t amount) {
  ENVOY_LOG(trace, "[pulse.{}] recordGaugeSub", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Utility::gaugeFromElements(*client_scope_, {Stats::DynamicName(name)},
                                    Stats::Gauge::ImportMode::NeverImport, tags_vctr)
      .sub(amount);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::recordHistogramValue(const std::string& elements, envoy_stats_tags tags,
                                            uint64_t value,
                                            envoy_histogram_stat_unit_t unit_measure) {
  ENVOY_LOG(trace, "[pulse.{}] recordHistogramValue", elements);
  ASSERT(dispatcher_->isThreadSafe(), "pulse calls must run from dispatcher's context");
  Stats::StatNameTagVector tags_vctr =
      Stats::Utility::transformToStatNameTagVector(tags, stat_name_set_);
  std::string name = Stats::Utility::sanitizeStatsName(elements);
  Stats::Histogram::Unit envoy_unit_measure = Stats::Histogram::Unit::Unspecified;
  switch (unit_measure) {
  case MILLISECONDS:
    envoy_unit_measure = Stats::Histogram::Unit::Milliseconds;
    break;
  case MICROSECONDS:
    envoy_unit_measure = Stats::Histogram::Unit::Microseconds;
    break;
  case BYTES:
    envoy_unit_measure = Stats::Histogram::Unit::Bytes;
    break;
  case UNSPECIFIED:
    envoy_unit_measure = Stats::Histogram::Unit::Unspecified;
    break;
  }

  Stats::Utility::histogramFromElements(*client_scope_, {Stats::DynamicName(name)},
                                        envoy_unit_measure, tags_vctr)
      .recordValue(value);
  return ENVOY_SUCCESS;
}

envoy_status_t Engine::makeAdminCall(absl::string_view path, absl::string_view method,
                                     envoy_data& out) {
  ENVOY_LOG(trace, "admin call {} {}", method, path);

  ASSERT(dispatcher_->isThreadSafe(), "admin calls must be run from the dispatcher's context");
  auto response_headers = Http::ResponseHeaderMapImpl::create();
  std::string body;
  const auto code = server_->admin().request(path, method, *response_headers, body);
  if (code != Http::Code::OK) {
    ENVOY_LOG(warn, "admin call failed with status {} body {}", code, body);
    return ENVOY_FAILURE;
  }

  out = Data::Utility::copyToBridgeData(body);

  return ENVOY_SUCCESS;
}

Event::ProvisionalDispatcher& Engine::dispatcher() { return *dispatcher_; }

Http::Client& Engine::httpClient() {
  RELEASE_ASSERT(dispatcher_->isThreadSafe(),
                 "httpClient must be accessed from dispatcher's context");
  return *http_client_;
}

Network::Configurator& Engine::networkConfigurator() {
  RELEASE_ASSERT(dispatcher_->isThreadSafe(),
                 "networkConfigurator must be accessed from dispatcher's context");
  return *network_configurator_;
}

void Engine::flushStats() {
  ASSERT(dispatcher_->isThreadSafe(), "flushStats must be called from the dispatcher's context");

  server_->flushStats();
}

void Engine::drainConnections() {
  ASSERT(dispatcher_->isThreadSafe(),
         "drainConnections must be called from the dispatcher's context");
  server_->clusterManager().drainConnections();
}

Upstream::ClusterManager& Engine::getClusterManager() {
  ASSERT(dispatcher_->isThreadSafe(),
         "getClusterManager must be called from the dispatcher's context");
  return server_->clusterManager();
}

void Engine::logInterfaces(absl::string_view event,
                           std::vector<Network::InterfacePair>& interfaces) {
  std::vector<std::string> names;
  names.resize(interfaces.size());
  std::transform(interfaces.begin(), interfaces.end(), names.begin(),
                 [](Network::InterfacePair& pair) { return std::get<0>(pair); });

  auto unique_end = std::unique(names.begin(), names.end());
  std::string all_names = std::accumulate(names.begin(), unique_end, std::string{},
                                          [](std::string acc, std::string next) {
                                            return acc.empty() ? next : std::move(acc) + "," + next;
                                          });
  ENVOY_LOG_EVENT(debug, event, all_names);
}

} // namespace Envoy
<|endoftext|>


<commit_before>#include "bayesian/graph.hpp"
#include "bayesian/bp.hpp"

namespace bn {

// 辺のlikelihoodを保持し，簡易に前の状態をコピーすることが可能にするため
class likelihood_list {
public:
    class value_type {
    public:
        value_type(vertex_type const& from, vertex_type const& to, edge_type const& edge)
            : from_(from), to_(to), edge_(edge), likelihood_(from->selectable_num, to->selectable_num)
        {
        }
        virtual ~value_type() = default;

        vertex_type const from() const { return from_; }
        vertex_type const to() const { return to_; }
        edge_type const edge() const { return edge_; }

        matrix_type& likelihood()
        {
            return likelihood_;
        }
        matrix_type const& likelihood() const
        {
            return likelihood_;
        }

    private:
        vertex_type from_;
        vertex_type to_;
        edge_type edge_;
        matrix_type likelihood_;
    };

    matrix_type& add_manage(vertex_type const& from, vertex_type const& to, edge_type const& edge)
    {
        data_.emplace_back(from, to, edge);
        return data_.back().likelihood();
    }

    void del_manage(edge_type const& edge)
    {
        auto it = find(edge);
        if(it != data_.end()) data_.erase(it);
    }

    void del_manage(vertex_type const& from, vertex_type const& to)
    {
        auto it = find(from, to);
        if(it != data_.end()) data_.erase(it);
    }

    matrix_type& operator() (edge_type const& edge)
    {
        auto it = find(edge);
        if(it == data_.end()) throw std::runtime_error("likelihood_list: operator() (edge_type)");
        return it->likelihood();
    }

    matrix_type const& operator() (edge_type const& edge) const
    {
        auto it = find(edge);
        if(it == data_.end()) throw std::runtime_error("likelihood_list: operator() (edge_type) const");
        return it->likelihood();
    }

    matrix_type& operator() (vertex_type const& from, vertex_type const& to)
    {
        auto it = find(from, to);
        if(it == data_.end()) throw std::runtime_error("likelihood_list: operator() (vertex_type,vertex_type)");
        return it->likelihood();
    }

    matrix_type const& operator() (vertex_type const& from, vertex_type const& to) const
    {
        auto it = find(from, to);
        if(it == data_.end()) throw std::runtime_error("likelihood_list: operator() (vertex_type,vertex_type) const");
        return it->likelihood();
    }

private:
    std::vector<value_type>::iterator find(edge_type const& edge)
    {
        auto it = data_.begin();
        while(it != data_.end())
        {
            if(it->edge() == edge) break;
            else ++it;
        }
        return it;
    }

    std::vector<value_type>::iterator find(vertex_type const& from, vertex_type const& to)
    {
        auto it = data_.begin();
        while(it != data_.end())
        {
            if(std::tie(it->from(), it->to()) == std::tie(from, to)) break;
            else ++it;
        }
        return it;
    }

    std::vector<value_type>::const_iterator find(edge_type const& edge) const
    {
        auto it = data_.cbegin();
        while(it != data_.cend())
        {
            if(it->edge() == edge) break;
            else ++it;
        }
        return it;
    }

    std::vector<value_type>::const_iterator find(vertex_type const& from, vertex_type const& to) const
    {
        auto it = data_.cbegin();
        while(it != data_.cend())
        {
            if(std::tie(it->from(), it->to()) == std::tie(from, to)) break;
            else ++it;
        }
        return it;
    }

    std::vector<value_type> data_;
};

matrix_type bp::operator()(
    graph_t const& graph,
    vertex_type const& node,
    std::vector<std::pair<vertex_type, int>> const& condition
    )
{
    // 前後の要素に伝播させる
    auto const e_minus = propagate_forward(graph, node, condition);
    auto const e_plus = propagate_backward(graph, node, condition);

    // 掛け算
    auto const elem_num = node->selectable_num;
    double sum = 0.0;
    matrix_type mat(elem_num, 1);
    for(std::size_t i = 0; i < e_minus.height(); ++i)
    {
        double const product = e_minus[i][0] * e_plus[0][i];
        sum += product;
        mat[i][0] = product;
    }

    // 正規化
    for(std::size_t i = 0; i < e_minus.height(); ++i)
    {
        mat[i][0] /= sum;
    }

    return mat;
}

std::pair<bool, int> find_condition(
    vertex_type const& node,
    std::vector<std::pair<vertex_type, int>> const& condition
    )
{
    for(auto const& c : condition)
    {
        if(c.first == node)
        {
            return std::make_pair(true, c.second);
        }
    }

    return std::make_pair(false, 0);
}

// 下流要素の確率推論
matrix_type bp::propagate_forward(
    graph_t const& graph,
    vertex_type const& node,
    std::vector<std::pair<vertex_type, int>> const& condition
    )
{
    auto const elem_num = node->selectable_num;
    matrix_type mat(elem_num, 1, 1);

    // node ∈ condition
    auto is_condition = find_condition(node, condition);
    if(is_condition.first)
    {
        for(int i = 0; i < elem_num; ++i)
        {
            mat[i][0] = (i == is_condition.second) ? 1 : 0;
        }
        return mat;
    }

    // conditionに含まれないから伝播 (e-要素)
    auto const out_edges = graph.out_edges(node);
    if(!out_edges.empty())
    {
        for(auto const& edge : out_edges)
        {
            if(!edge->likelihood.first) throw std::runtime_error("no set edge of likelihood");
            mat = mat % (edge->likelihood.second * propagate_forward(graph, graph.target(edge), condition));
        }

        return mat;
    }

    // 末端は全ての確率が等しいとする
    for(int i = 0; i < elem_num; ++i)
    {
        mat[i][0] = 1.0;
    }
    return mat;
}

// 上流要素の確率推論
matrix_type bp::propagate_backward(
    graph_t const& graph,
    vertex_type const& node,
    std::vector<std::pair<vertex_type, int>> const& condition
    )
{
    auto const elem_num = node->selectable_num;
    matrix_type mat(1, elem_num, 1);

    // node ∈ condition
    auto is_condition = find_condition(node, condition);
    if(is_condition.first)
    {
        for(int i = 0; i < elem_num; ++i)
        {
            mat[0][i] = (i == is_condition.second) ? 1 : 0;
        }
        return mat;
    }

    // conditionに含まれないから伝播 (e+要素)
    auto const in_edges = graph.in_edges(node);
    if(!in_edges.empty())
    {
        for(auto const& edge : in_edges)
        {
            if(!edge->likelihood.first) throw std::runtime_error("no set edge of likelihood");
            mat = mat % (propagate_backward(graph, graph.source(edge), condition) * edge->likelihood.second);
        }

        return mat;
    }

    // 最上位ノードは事前確率を割り当てる
    auto& e = node->evidence;
    if(e.first)
    {
        return e.second;
    }
    else
    {
        throw std::runtime_error("highest node doesn't have prior probability.");
    }
}

} // namespace bn

<commit_msg>!cannot compile, from cpt to likelihood.<commit_after>#include "bayesian/graph.hpp"
#include "bayesian/bp.hpp"
#include "cpt.hpp" // unordered_mapのネストの解決

namespace bn {

// 辺のlikelihoodを保持し，簡易に前の状態をコピーすることが可能にするため
class likelihood_list {
public:
    class value_type {
    public:
        value_type(vertex_type const& from, vertex_type const& to, edge_type const& edge)
            : from_(from), to_(to), edge_(edge), likelihood_(from->selectable_num, to->selectable_num)
        {
        }
        virtual ~value_type() = default;

        vertex_type const from() const { return from_; }
        vertex_type const to() const { return to_; }
        edge_type const edge() const { return edge_; }

        matrix_type& likelihood()
        {
            return likelihood_;
        }
        matrix_type const& likelihood() const
        {
            return likelihood_;
        }

    private:
        vertex_type from_;
        vertex_type to_;
        edge_type edge_;
        matrix_type likelihood_;
    };

    matrix_type& add_manage(vertex_type const& from, vertex_type const& to, edge_type const& edge)
    {
        data_.emplace_back(from, to, edge);
        return data_.back().likelihood();
    }

    void del_manage(edge_type const& edge)
    {
        auto it = find(edge);
        if(it != data_.end()) data_.erase(it);
    }

    void del_manage(vertex_type const& from, vertex_type const& to)
    {
        auto it = find(from, to);
        if(it != data_.end()) data_.erase(it);
    }

    matrix_type& operator() (edge_type const& edge)
    {
        auto it = find(edge);
        if(it == data_.end()) throw std::runtime_error("likelihood_list: operator() (edge_type)");
        return it->likelihood();
    }

    matrix_type const& operator() (edge_type const& edge) const
    {
        auto it = find(edge);
        if(it == data_.end()) throw std::runtime_error("likelihood_list: operator() (edge_type) const");
        return it->likelihood();
    }

    matrix_type& operator() (vertex_type const& from, vertex_type const& to)
    {
        auto it = find(from, to);
        if(it == data_.end()) throw std::runtime_error("likelihood_list: operator() (vertex_type,vertex_type)");
        return it->likelihood();
    }

    matrix_type const& operator() (vertex_type const& from, vertex_type const& to) const
    {
        auto it = find(from, to);
        if(it == data_.end()) throw std::runtime_error("likelihood_list: operator() (vertex_type,vertex_type) const");
        return it->likelihood();
    }

private:
    std::vector<value_type>::iterator find(edge_type const& edge)
    {
        auto it = data_.begin();
        while(it != data_.end())
        {
            if(it->edge() == edge) break;
            else ++it;
        }
        return it;
    }

    std::vector<value_type>::iterator find(vertex_type const& from, vertex_type const& to)
    {
        auto it = data_.begin();
        while(it != data_.end())
        {
            if(std::tie(it->from(), it->to()) == std::tie(from, to)) break;
            else ++it;
        }
        return it;
    }

    std::vector<value_type>::const_iterator find(edge_type const& edge) const
    {
        auto it = data_.cbegin();
        while(it != data_.cend())
        {
            if(it->edge() == edge) break;
            else ++it;
        }
        return it;
    }

    std::vector<value_type>::const_iterator find(vertex_type const& from, vertex_type const& to) const
    {
        auto it = data_.cbegin();
        while(it != data_.cend())
        {
            if(std::tie(it->from(), it->to()) == std::tie(from, to)) break;
            else ++it;
        }
        return it;
    }

    std::vector<value_type> data_;
};

// all_combination
void all_combination_pattern(
    std::unordered_map<vertex_type, int>& combination,
    std::unordered_map<vertex_type, int>::iterator it,
    std::function<void(std::unordered_map<vertex_type, int> const& combination)> const& func
    )
{
    if(it == conbination.end())
    {
        func(combination);
    }
    else
    {
        for(int i = 0; i < it->first->selectable_num; ++i)
        {
            it->second = i;
            all_combination_pattern(combination, it + 1, func);
        }
    }
}

// combinationから必要なノードの選択状態だけ取り出して，条件を更新する
std::unordered_map<vertex_type, int> update_select_condition(
    std::unordered_map<vertex_type, int> const& whole_condition,
    std::unordered_map<vertex_type, int> const& base_condition
    )
{
    std::unordered_map<vertex_type, int> particle_condition = base_condition;
    for(auto it = particle_condition.begin(); it != particle_condition.end(); ++it)
    {
        it->second = whole_condition[it->first];
    }
    return particle_condition;
}

// 周辺化
std::unordered_map<std::unordered_map<vertex_type, int>, double> marginalize(
    std::unordered_map<std::unordered_map<vertex_type, int>, double> const& base,
    vertex_type const& target
    )
{
    std::unordered_map<std::unordered_map<vertex_type, int>, double> result;
    all_combination_pattern(
        base, base.begin(),
        [&result, &base, &target](std::unordered_map<std::unordered_map<vertex_type, int>, double> const& condition)
        {
            auto new_condition = condition;
            new_condtion.erase(target);

            if(result.count(new_condition))
            {
                result[new_condition] += base[condition];
            }
            else
            {
                result[new_condition] = base[condition];
            }
        });

    return result;
}

likelihood_list lilelihood_list_;

// 条件化(条件を添加する)
void conditioning(
    std::unordered_map<std::unordered_map<vertex_type, int>, double> const& probabilities,
    vertex_type const& target_node,
    vertex_type const& condition_node
    )
{
    auto pair_probabilities = probabilities;
    for(auto it = probabilities.begin()->first.begin(); it != probabilities.begin()->first.end(); ++it)
    {
        if(it->first != target_node && it->first != condition_node)
        {
            pair_probabilities = marginalize(pair_probabilities, it->first);
        }
    }

    for(int i = 0; i < condition_node.selectable_num; ++i)
    {
        double denominator = 0;
        for(int j = 0; j < target_node.selectable; ++j)
        {
            auto const target_prob = pair_probabilities[{{condition_node,i},{target_node,j}}];
            denominator += target_prob;
            lilelihood_list_(condition_node, target_node)[i][j] = target_prob;
        }

        for(int j = 0; j < target_node.selectable; ++j)
        {
            lilelihood_list_(condition_node, target_node)[i][j] /= denominator;
        }
    }
}

// 指定ノードから上流に拡散，上流が確定した後に自身を算出することで解を得る
std::unordered_map<std::unordered_map<vertex_type, int>, double> calculate_likelihood_from_backward(
    graph_t const& graph,
    vertex_type const& node
    )
{
    std::vector<vertex_type> direct_parents; // 直接の親
    std::vector<vertex_type> indirect_parents; // 間接の親

    std::vector<std::unordered_map<std::unordered_map<vertex_type, int>, double>> upward_probabilities;

    // 上流ノードの列挙(boost::transformを使うと簡潔)
    for(auto const& upward_edge : graph.in_edges(node))
    {
        auto const upward_node = graph.source(upward_edge);
        direct_parents.push_back(upward_node);

        likelihood_list_.ad_manage(upward_node, node, upward_edge);
    }

    // 上流ノードがあるならば，上流を先に確定させる
    // なんでこんなの書いてるんだろうかとイライラしてきた
    for(auto const& upward_node : direct_parents)
    {
        auto const result = calculate_likelihood_from_backward(graph, upward_node);
        if(result.size() == 0) throw std::runtime_error("calculate_likelihood_from_backward: size = 0");
        for(auto const& probability : result.begin()->first)
        {
            // 間接の親かどうか
            auto const& parent_node = probability->first;
            if(std::find(direct_parents.cbegin(), direct_parents.cend(), parent_node) == direct_parents.cend() &&
               std::find(indirect_parents.cbegin(), indirect_parents.cend(), parent_node) == indirect_parents.cend())
            {
                indirect_parents.push_back(parent_node);
            }
        }

        upward_probabilities.push_back(std::move(result));
    }

    // 上流ノード全ての組み合わせを作製して回す
    std::unordered_map<vertex_type, int> combination = {{node, 0}};
    for(auto const& key : direct_parents) combination[key] = 0;
    for(auto const& key : indirect_parents) combination[key] = 0;

    // returnにも使われる同時確率を計算
    std::unordered_map<std::unordered_map<vertex_type, int>, double> target_node_probability;
    all_combination_pattern(
        combination, combination.begin(),
        [&target_node_probability, &upward_probabilities](std::unordered_map<vertex_type, int> const& combination)
        {
            // foldl使うと，どうせVC落ちるからやめた
            double probability = node->cpt[update_select_condition(combination, node->cpt.begin()->first)]
                                          [combination[node]];

            for(auto const& upward : upward_probabilities)
            {
               probability *= upward[update_select_condition(combination, upward.begin()->first)];
            }
            target_node_probability[combination] = probability;
        });

    // 自身と直接の親以外の要素について，周辺化
    auto marginalized_probability = target_node_probability;
    for(auto it = indirect_parents.begin(); it != indirect_parents.end(); ++it)
    {
        marginalized_probability = marginalize(marginalized_probability, *it);
    }

    for(auto it = direct_parents.begin(); it != direct_parents.end(); ++it)
    {
        conditioning(marginalized_probability, node, *it);
    }

    return target_node_probability;
}

// cptを元に全てのエッジのlikelihoodを算出する
void calculate_likelihood(graph_t const& graph)
{
    auto node_list = graph.vertex_list();
    for(auto const& node : node_list)
    {
        auto edges = graph.out_edges(node);
        if(edges.size() == 0)
        {
            // 末端から走査したほうが都合がいいので，末端のノードを全網羅(==全エッジ走査)
            calculate_likelihood_from_backward // TODO:
        }
    }
}

matrix_type bp::operator()(
    graph_t const& graph,
    vertex_type const& node,
    std::vector<std::pair<vertex_type, int>> const& condition
    )
{
    // 前後の要素に伝播させる
    auto const e_minus = propagate_forward(graph, node, condition);
    auto const e_plus = propagate_backward(graph, node, condition);

    // 掛け算
    auto const elem_num = node->selectable_num;
    double sum = 0.0;
    matrix_type mat(elem_num, 1);
    for(std::size_t i = 0; i < e_minus.height(); ++i)
    {
        double const product = e_minus[i][0] * e_plus[0][i];
        sum += product;
        mat[i][0] = product;
    }

    // 正規化
    for(std::size_t i = 0; i < e_minus.height(); ++i)
    {
        mat[i][0] /= sum;
    }

    return mat;
}

std::pair<bool, int> find_condition(
    vertex_type const& node,
    std::vector<std::pair<vertex_type, int>> const& condition
    )
{
    for(auto const& c : condition)
    {
        if(c.first == node)
        {
            return std::make_pair(true, c.second);
        }
    }

    return std::make_pair(false, 0);
}

// 下流要素の確率推論
matrix_type bp::propagate_forward(
    graph_t const& graph,
    vertex_type const& node,
    std::vector<std::pair<vertex_type, int>> const& condition
    )
{
    auto const elem_num = node->selectable_num;
    matrix_type mat(elem_num, 1, 1);

    // node ∈ condition
    auto is_condition = find_condition(node, condition);
    if(is_condition.first)
    {
        for(int i = 0; i < elem_num; ++i)
        {
            mat[i][0] = (i == is_condition.second) ? 1 : 0;
        }
        return mat;
    }

    // conditionに含まれないから伝播 (e-要素)
    auto const out_edges = graph.out_edges(node);
    if(!out_edges.empty())
    {
        for(auto const& edge : out_edges)
        {
            if(!edge->likelihood.first) throw std::runtime_error("no set edge of likelihood");
            mat = mat % (edge->likelihood.second * propagate_forward(graph, graph.target(edge), condition));
        }

        return mat;
    }

    // 末端は全ての確率が等しいとする
    for(int i = 0; i < elem_num; ++i)
    {
        mat[i][0] = 1.0;
    }
    return mat;
}

// 上流要素の確率推論
matrix_type bp::propagate_backward(
    graph_t const& graph,
    vertex_type const& node,
    std::vector<std::pair<vertex_type, int>> const& condition
    )
{
    auto const elem_num = node->selectable_num;
    matrix_type mat(1, elem_num, 1);

    // node ∈ condition
    auto is_condition = find_condition(node, condition);
    if(is_condition.first)
    {
        for(int i = 0; i < elem_num; ++i)
        {
            mat[0][i] = (i == is_condition.second) ? 1 : 0;
        }
        return mat;
    }

    // conditionに含まれないから伝播 (e+要素)
    auto const in_edges = graph.in_edges(node);
    if(!in_edges.empty())
    {
        for(auto const& edge : in_edges)
        {
            if(!edge->likelihood.first) throw std::runtime_error("no set edge of likelihood");
            mat = mat % (propagate_backward(graph, graph.source(edge), condition) * edge->likelihood.second);
        }

        return mat;
    }

    // 最上位ノードは事前確率を割り当てる
    auto& e = node->evidence;
    if(e.first)
    {
        return e.second;
    }
    else
    {
        throw std::runtime_error("highest node doesn't have prior probability.");
    }
}

} // namespace bn

<|endoftext|>


<commit_before>/*
    Crystal Space input library
    Copyright (C) 2000 by Andrew Zabolotny <bit@eltech.ru>
    Copyright (C) 2002 by Mathew Sutcliffe <oktal@gmx.co.uk>

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "iutil/event.h"
#include "csutil/csevent.h"
#include "csutil/inpnames.h"

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

static struct csKeyCodeDef
{
  const char *key;
  int code;
} KeyDefs [] =
{
  { "Esc",	CSKEY_ESC	},
  { "Enter",	CSKEY_ENTER	},
  { "Tab",	CSKEY_TAB	},
  { "Back",	CSKEY_BACKSPACE },
  { "BackSpace",CSKEY_BACKSPACE },
  { "Up",	CSKEY_UP	},
  { "Down",	CSKEY_DOWN	},
  { "Left",	CSKEY_LEFT	},
  { "Right",	CSKEY_RIGHT	},
  { "PgUp",	CSKEY_PGUP	},
  { "PageUp",	CSKEY_PGUP	},
  { "PgDn",	CSKEY_PGDN	},
  { "PageDown",	CSKEY_PGDN	},
  { "Home",	CSKEY_HOME	},
  { "End",	CSKEY_END	},
  { "Ins",	CSKEY_INS	},
  { "Insert",	CSKEY_INS	},
  { "Del",	CSKEY_DEL	},
  { "Delete",	CSKEY_DEL	},
  { "Ctrl",	CSKEY_CTRL	},
  { "Control",	CSKEY_CTRL	},
  { "Alt",	CSKEY_ALT	},
  { "Shift",	CSKEY_SHIFT	},
  { "Center",	CSKEY_CENTER	},
  { "F1",	CSKEY_F1	},
  { "F2",	CSKEY_F2	},
  { "F3",	CSKEY_F3	},
  { "F4",	CSKEY_F4	},
  { "F5",	CSKEY_F5	},
  { "F6",	CSKEY_F6	},
  { "F7",	CSKEY_F7	},
  { "F8",	CSKEY_F8	},
  { "F9",	CSKEY_F9	},
  { "F10",	CSKEY_F10	},
  { "F11",	CSKEY_F11	},
  { "F12",	CSKEY_F12	},
  { "PAD+",	CSKEY_PADPLUS	},
  { "PAD-",	CSKEY_PADMINUS	},
  { "PAD*",	CSKEY_PADMULT	},
  { "PAD/",	CSKEY_PADDIV	},
  { NULL,	0		}
};

static struct csKeyMaskDef
{
  const char *key;
  int mask;
} KeyMasks [] =
{
  { "Ctrl+",	CSMASK_CTRL	},
  { "Alt+",	CSMASK_ALT	},
  { "Shift+",	CSMASK_SHIFT	},
  { NULL,	0		}
};

bool csParseInputDef (const char *name, iEvent* ev, bool use_shift)
{
  int mod = 0;
  bool ismask;
  do
  {
    ismask = false;
    for (csKeyMaskDef *m = KeyMasks; m->key; m++)
      if (! strncasecmp (m->key, name, strlen (m->key)))
      {
        if (use_shift) mod |= m->mask;
        name += strlen (m->key);
        ismask = true;
      }
  } while (ismask);

  if (! strncasecmp (name, "Mouse", 5))
  {
    name += 5;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevMouseMove, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevMouseMove, 0, 1, 0, 0);
    else *ev = csEvent (0, csevMouseDown, 0, 0, atoi (name), mod);
  }
  else if (! strncasecmp (name, "Joystick", 8))
  {
    name += 8;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevJoystickMove, 1, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevJoystickMove, 1, 0, 1, 0, 0);
    else *ev = csEvent (0, csevJoystickDown, 1, 0, 0, atoi (name), mod);
  }
  else
  {
    int code = 0;

    for (csKeyCodeDef *c = KeyDefs; c->key; c++)
      if (! strcasecmp (c->key, name)) code = c->code;

    if	(code)
      *ev = csEvent (0, csevKeyDown, code, 0, mod);
    else if (strlen (name) != 1)
      return false;
    else
      *ev = csEvent (0, csevKeyDown, 0, (int)*name, mod);
  }
  return true;
}

bool csParseInputDef (const char* name, csEvent& ev, bool use_shift)
{
  return csParseInputDef (name, &ev, use_shift);
}

bool csParseKeyDef (const char *name, int &key, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Key.Code >= CSKEY_FIRST && ev.Key.Code <= CSKEY_LAST)
      key = ev.Key.Code;
    else if (ev.Key.Char < 256 && ev.Key.Char > 0)
      key = ev.Key.Char;
    else return false;
    shift = ev.Key.Modifiers;
  }
  return ret;
}

bool csParseMouseDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevMouseMove)
      button = ev.Mouse.x > ev.Mouse.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Mouse.Button;
    shift = ev.Mouse.Modifiers;
  }
  return ret;
}

bool csParseJoyDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevJoystickMove)
      button = ev.Joystick.x > ev.Joystick.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Joystick.Button;
    shift = ev.Joystick.Modifiers;
  }
  return ret;
}

bool csGetInputDesc (iEvent *ev, char *buf, bool use_shift)
{
  if (use_shift)
  {
    int mod = 0;
    switch (ev->Type)
    {
      case csevKeyUp:
      case csevKeyDown:
        mod = ev->Key.Modifiers;
        break;

      case csevMouseUp:
      case csevMouseDown:
        mod = ev->Mouse.Modifiers;
        break;

      case csevJoystickUp:
      case csevJoystickDown:
        mod = ev->Joystick.Modifiers;
        break;

      default:
        break;
    }
    for (csKeyMaskDef *mask = KeyMasks; mask->key; mask++)
    {
      if (mod & mask->mask)
      {
        strcpy (buf, mask->key);
        buf = strchr (buf, 0);
      }
    }
  }

  const char *key = NULL;
  switch (ev->Type)
  {
    case csevKeyUp:
    case csevKeyDown:
    {
      for (csKeyCodeDef *k = KeyDefs; k->key; k++)
        if (k->code == ev->Key.Code) key = k->key;
      if (key)
      {
        strcpy (buf, key);
        return true;
      }
      else if (ev->Key.Char < 256 && ev->Key.Char > 0)
      {
        *buf = (char)ev->Key.Char;
        *++buf = 0;
        return true;
      }
    }  break;

    case csevMouseUp:
    case csevMouseDown:
      strcpy (buf, "Mouse");
      sprintf (strchr (buf, 0), "%i", ev->Mouse.Button);
      return true;

    case csevJoystickUp:
    case csevJoystickDown:
      strcpy (buf, "Joystick");
      sprintf (strchr (buf, 0), "%i", ev->Joystick.Button);
      return true;

    case csevMouseMove:
      strcpy (buf, "Mouse");
      buf = strchr (buf, 0);
      if (ev->Mouse.x > ev->Mouse.y) *buf++ = 'X';
      else if (ev->Mouse.x < ev->Mouse.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    case csevJoystickMove:
      strcpy (buf, "Joystick");
      buf = strchr (buf, 0);
      if (ev->Joystick.x > ev->Joystick.y) *buf++ = 'X';
      else if (ev->Joystick.x < ev->Joystick.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    default:
      break;
  }
  return false;
}

bool csGetInputDesc (csEvent &ev, char *buf, bool use_shift)
{
  return csGetInputDesc (&ev, buf, use_shift);
}

bool csGetKeyDesc (int key, int shift, char *buf, bool use_shift)
{
  csEvent ev (0, csevKeyDown,
    key >= CSKEY_FIRST && key <= CSKEY_LAST ? key : 0,
    key < 256 && key > 0 ? 0 : key,
    shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetMouseDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevMouseMove : csevMouseDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetJoyDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevJoystickMove : csevJoystickDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

<commit_msg>very small optimisation for key parsing (suggest by Vengeance <keith@paqrat.com><commit_after>/*
    Crystal Space input library
    Copyright (C) 2000 by Andrew Zabolotny <bit@eltech.ru>
    Copyright (C) 2002 by Mathew Sutcliffe <oktal@gmx.co.uk>

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"
#include "iutil/event.h"
#include "csutil/csevent.h"
#include "csutil/inpnames.h"

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

static struct csKeyCodeDef
{
  const char *key;
  int code;
} KeyDefs [] =
{
  { "Esc",	CSKEY_ESC	},
  { "Enter",	CSKEY_ENTER	},
  { "Tab",	CSKEY_TAB	},
  { "Back",	CSKEY_BACKSPACE },
  { "BackSpace",CSKEY_BACKSPACE },
  { "Up",	CSKEY_UP	},
  { "Down",	CSKEY_DOWN	},
  { "Left",	CSKEY_LEFT	},
  { "Right",	CSKEY_RIGHT	},
  { "PgUp",	CSKEY_PGUP	},
  { "PageUp",	CSKEY_PGUP	},
  { "PgDn",	CSKEY_PGDN	},
  { "PageDown",	CSKEY_PGDN	},
  { "Home",	CSKEY_HOME	},
  { "End",	CSKEY_END	},
  { "Ins",	CSKEY_INS	},
  { "Insert",	CSKEY_INS	},
  { "Del",	CSKEY_DEL	},
  { "Delete",	CSKEY_DEL	},
  { "Ctrl",	CSKEY_CTRL	},
  { "Control",	CSKEY_CTRL	},
  { "Alt",	CSKEY_ALT	},
  { "Shift",	CSKEY_SHIFT	},
  { "Center",	CSKEY_CENTER	},
  { "F1",	CSKEY_F1	},
  { "F2",	CSKEY_F2	},
  { "F3",	CSKEY_F3	},
  { "F4",	CSKEY_F4	},
  { "F5",	CSKEY_F5	},
  { "F6",	CSKEY_F6	},
  { "F7",	CSKEY_F7	},
  { "F8",	CSKEY_F8	},
  { "F9",	CSKEY_F9	},
  { "F10",	CSKEY_F10	},
  { "F11",	CSKEY_F11	},
  { "F12",	CSKEY_F12	},
  { "PAD+",	CSKEY_PADPLUS	},
  { "PAD-",	CSKEY_PADMINUS	},
  { "PAD*",	CSKEY_PADMULT	},
  { "PAD/",	CSKEY_PADDIV	},
  { NULL,	0		}
};

static struct csKeyMaskDef
{
  const char *key;
  int mask;
} KeyMasks [] =
{
  { "Ctrl+",	CSMASK_CTRL	},
  { "Alt+",	CSMASK_ALT	},
  { "Shift+",	CSMASK_SHIFT	},
  { NULL,	0		}
};

bool csParseInputDef (const char *name, iEvent* ev, bool use_shift)
{
  int mod = 0;
  bool ismask;
  do
  {
    ismask = false;
    for (csKeyMaskDef *m = KeyMasks; m->key; m++)
      if (! strncasecmp (m->key, name, strlen (m->key)))
      {
        if (use_shift) mod |= m->mask;
        name += strlen (m->key);
        ismask = true;
      }
  } while (ismask);

  if (! strncasecmp (name, "Mouse", 5))
  {
    name += 5;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevMouseMove, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevMouseMove, 0, 1, 0, 0);
    else *ev = csEvent (0, csevMouseDown, 0, 0, atoi (name), mod);
  }
  else if (! strncasecmp (name, "Joystick", 8))
  {
    name += 8;
    if (*name == 'X' || *name == 'x')
      *ev = csEvent (0, csevJoystickMove, 1, 1, 0, 0, 0);
    else if (*name == 'Y' || *name == 'y')
      *ev = csEvent (0, csevJoystickMove, 1, 0, 1, 0, 0);
    else *ev = csEvent (0, csevJoystickDown, 1, 0, 0, atoi (name), mod);
  }
  else
  {
    int code = 0;

    for (csKeyCodeDef *c = KeyDefs; c->key; c++)
      if (! strcasecmp (c->key, name)) { code = c->code; break; }

    if	(code)
      *ev = csEvent (0, csevKeyDown, code, 0, mod);
    else if (strlen (name) != 1)
      return false;
    else
      *ev = csEvent (0, csevKeyDown, 0, (int)*name, mod);
  }
  return true;
}

bool csParseInputDef (const char* name, csEvent& ev, bool use_shift)
{
  return csParseInputDef (name, &ev, use_shift);
}

bool csParseKeyDef (const char *name, int &key, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Key.Code >= CSKEY_FIRST && ev.Key.Code <= CSKEY_LAST)
      key = ev.Key.Code;
    else if (ev.Key.Char < 256 && ev.Key.Char > 0)
      key = ev.Key.Char;
    else return false;
    shift = ev.Key.Modifiers;
  }
  return ret;
}

bool csParseMouseDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevMouseMove)
      button = ev.Mouse.x > ev.Mouse.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Mouse.Button;
    shift = ev.Mouse.Modifiers;
  }
  return ret;
}

bool csParseJoyDef (const char *name, int &button, int &shift, bool use_shift)
{
  csEvent ev;
  bool ret = csParseInputDef (name, ev, use_shift);
  if (ret)
  {
    if (ev.Type == csevJoystickMove)
      button = ev.Joystick.x > ev.Joystick.y ? CSAXIS_X : CSAXIS_Y;
    else button = ev.Joystick.Button;
    shift = ev.Joystick.Modifiers;
  }
  return ret;
}

bool csGetInputDesc (iEvent *ev, char *buf, bool use_shift)
{
  if (use_shift)
  {
    int mod = 0;
    switch (ev->Type)
    {
      case csevKeyUp:
      case csevKeyDown:
        mod = ev->Key.Modifiers;
        break;

      case csevMouseUp:
      case csevMouseDown:
        mod = ev->Mouse.Modifiers;
        break;

      case csevJoystickUp:
      case csevJoystickDown:
        mod = ev->Joystick.Modifiers;
        break;

      default:
        break;
    }
    for (csKeyMaskDef *mask = KeyMasks; mask->key; mask++)
    {
      if (mod & mask->mask)
      {
        strcpy (buf, mask->key);
        buf = strchr (buf, 0);
      }
    }
  }

  const char *key = NULL;
  switch (ev->Type)
  {
    case csevKeyUp:
    case csevKeyDown:
    {
      for (csKeyCodeDef *k = KeyDefs; k->key; k++)
        if (k->code == ev->Key.Code) key = k->key;
      if (key)
      {
        strcpy (buf, key);
        return true;
      }
      else if (ev->Key.Char < 256 && ev->Key.Char > 0)
      {
        *buf = (char)ev->Key.Char;
        *++buf = 0;
        return true;
      }
    }  break;

    case csevMouseUp:
    case csevMouseDown:
      strcpy (buf, "Mouse");
      sprintf (strchr (buf, 0), "%i", ev->Mouse.Button);
      return true;

    case csevJoystickUp:
    case csevJoystickDown:
      strcpy (buf, "Joystick");
      sprintf (strchr (buf, 0), "%i", ev->Joystick.Button);
      return true;

    case csevMouseMove:
      strcpy (buf, "Mouse");
      buf = strchr (buf, 0);
      if (ev->Mouse.x > ev->Mouse.y) *buf++ = 'X';
      else if (ev->Mouse.x < ev->Mouse.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    case csevJoystickMove:
      strcpy (buf, "Joystick");
      buf = strchr (buf, 0);
      if (ev->Joystick.x > ev->Joystick.y) *buf++ = 'X';
      else if (ev->Joystick.x < ev->Joystick.y) *buf++ = 'Y';
      *buf = 0;
      return true;

    default:
      break;
  }
  return false;
}

bool csGetInputDesc (csEvent &ev, char *buf, bool use_shift)
{
  return csGetInputDesc (&ev, buf, use_shift);
}

bool csGetKeyDesc (int key, int shift, char *buf, bool use_shift)
{
  csEvent ev (0, csevKeyDown,
    key >= CSKEY_FIRST && key <= CSKEY_LAST ? key : 0,
    key < 256 && key > 0 ? 0 : key,
    shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetMouseDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevMouseMove : csevMouseDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

bool csGetJoyDesc (int button, int shift, char *buf, bool use_shift)
{
  csEvent ev (0,
    button == CSAXIS_X || button == CSAXIS_Y ? csevJoystickMove : csevJoystickDown,
    button == CSAXIS_X ? 1 : 0,
    button == CSAXIS_Y ? 1 : 0,
    button, shift);
  return csGetInputDesc (ev, buf, use_shift);
}

<|endoftext|>


<commit_before>#include <iostream>
#include <iterator>
#include <map>
#include <boost/foreach.hpp>
#include <algorithm>

template <typename Iterator, typename Tag> struct iterator_adapter;

namespace detail {
struct value_iterator_tag {};
}

template <typename AdapterIterator, typename BaseIterator>
class iterator_adapter_base {
public:
	bool operator==(iterator_adapter_base const& o) const
	{
		return base_iter_ == o.base_iter_;
	}

	bool operator!=(iterator_adapter_base const& o) const
	{
		return base_iter_ != o.base_iter_;
	}

	bool operator<(iterator_adapter_base const& o) const
	{
		return base_iter_ < o.base_iter_;
	}

	bool operator<=(iterator_adapter_base const& o) const
	{
		return base_iter_ <= o.base_iter_;
	}

	bool operator>=(iterator_adapter_base const& o) const
	{
		return base_iter_ >= o.base_iter_;
	}

	AdapterIterator & operator++()
	{
		++base_iter_;
		return *static_cast<AdapterIterator*>(this);
	}

	AdapterIterator operator++(int)
	{
		AdapterIterator res(base_iter_);
		++base_iter_;
		return res;
	}

	AdapterIterator & operator--()
	{
		--base_iter_;
		return *this;
	}

	AdapterIterator operator--(int)
	{
		AdapterIterator res(base_iter_);
		--base_iter_;
		return res;
	}

protected:
	iterator_adapter_base()
	:
		base_iter_()
	{ }

	iterator_adapter_base(BaseIterator const& base_iter)
	:
		base_iter_(base_iter)
	{ }

	BaseIterator base_iter_;
};

template <typename Iterator>
class iterator_adapter<Iterator, detail::value_iterator_tag> : public iterator_adapter_base<iterator_adapter<Iterator, detail::value_iterator_tag>, Iterator > {
public:
	typedef typename std::iterator_traits<Iterator>::iterator_category iterator_category;
	typedef typename std::iterator_traits<Iterator>::value_type::second_type value_type;
	typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
	typedef typename std::iterator_traits<Iterator>::value_type::second_type const* pointer;
	typedef typename std::iterator_traits<Iterator>::value_type::second_type const& reference;

	iterator_adapter() { }

	iterator_adapter(Iterator const& base_iter)
	:
		iterator_adapter_base<iterator_adapter<Iterator, detail::value_iterator_tag>, Iterator >(base_iter)
	{ }

	iterator_adapter(iterator_adapter const& o)
	:
		iterator_adapter_base<iterator_adapter<Iterator, detail::value_iterator_tag>, Iterator >(o.base_iter_)
	{ }

	iterator_adapter & operator=(iterator_adapter const& o)
	{
		this->base_iter_ = o.base_iter_;
		return *this;
	}

	reference operator*() const
	{
		return this->base_iter_->second;
	}

	pointer operator->() const
	{
		return &(this->base_iter_->second);
	}
};

template <typename Iterator>
iterator_adapter<Iterator, detail::value_iterator_tag> make_value_iterator(Iterator const& it)
{
	return iterator_adapter<Iterator, detail::value_iterator_tag>(it);
}

detail::value_iterator_tag value_adapter;

template <typename ContainerT, typename Tag>
struct range_adaptor;

template <typename ContainerT, typename Tag>
struct range_adaptor {
	range_adaptor(ContainerT & container)
	:
		begin_(container.begin()),
		end_(container.end())
	{ }

	range_adaptor(ContainerT const& container)
	:
		cbegin_(container.begin()),
		cend_(container.end())
	{ }

	// needed
	range_adaptor(range_adaptor const& o)
	{ }

	typedef iterator_adapter<typename ContainerT::iterator, Tag> iterator;
	typedef iterator_adapter<typename ContainerT::const_iterator, Tag> const_iterator;

	iterator begin()
	{
		return begin_;
	}

	iterator end()
	{
		return end_;
	}

	const_iterator begin() const
	{
		return cbegin_;
	}

	const_iterator end() const
	{
		return cend_;
	}

private:
	range_adaptor() {}
	range_adaptor & operator=(range_adaptor const&) {}

	iterator begin_;
	iterator end_;
	const_iterator cbegin_;
	const_iterator cend_;
};

template <typename ContainerT, typename Tag>
range_adaptor<ContainerT, Tag> operator|(ContainerT const& container, Tag)
{
	return range_adaptor<ContainerT, Tag>(container);
}

template <typename ContainerT, typename Tag>
range_adaptor<ContainerT, Tag> operator|(ContainerT & container, Tag)
{
	return range_adaptor<ContainerT, Tag>(container);
}

void foo(bool const&)
{
}

int main()
{
	typedef std::map<int, bool> map_type;
	map_type m;

	BOOST_FOREACH(bool x, m | value_adapter) {
		(void) x;
	}

	BOOST_FOREACH(bool const& x, m | value_adapter) {
		(void) x;
	}
#if 0
	BOOST_FOREACH(bool & x, m | value_adapter) {
		(void) x;
	}
#endif
	std::for_each(make_value_iterator(m.begin()), make_value_iterator(m.end()), foo);

	return 0;
}
<commit_msg>add usefull comments<commit_after>#include <iostream>
#include <iterator>
#include <map>
#include <boost/foreach.hpp>
#include <algorithm>

template <typename Iterator, typename Tag> struct iterator_adapter;

// modern C++ no way to hide...
// just like calling a funktion dont_call_me_XXXX()
namespace detail {
struct value_iterator_tag {};
}

template <typename AdapterIterator, typename BaseIterator>
class iterator_adapter_base {
public:
	bool operator==(iterator_adapter_base const& o) const
	{
		return base_iter_ == o.base_iter_;
	}

	bool operator!=(iterator_adapter_base const& o) const
	{
		return base_iter_ != o.base_iter_;
	}

	bool operator<(iterator_adapter_base const& o) const
	{
		return base_iter_ < o.base_iter_;
	}

	bool operator<=(iterator_adapter_base const& o) const
	{
		return base_iter_ <= o.base_iter_;
	}

	bool operator>=(iterator_adapter_base const& o) const
	{
		return base_iter_ >= o.base_iter_;
	}

	AdapterIterator & operator++()
	{
		++base_iter_;
		return *static_cast<AdapterIterator*>(this);
	}

	AdapterIterator operator++(int)
	{
		AdapterIterator res(base_iter_);
		++base_iter_;
		return res;
	}

	AdapterIterator & operator--()
	{
		--base_iter_;
		return *this;
	}

	AdapterIterator operator--(int)
	{
		AdapterIterator res(base_iter_);
		--base_iter_;
		return res;
	}

protected:
	iterator_adapter_base()
	:
		base_iter_()
	{ }

	iterator_adapter_base(BaseIterator const& base_iter)
	:
		base_iter_(base_iter)
	{ }

	BaseIterator base_iter_;
};

template <typename Iterator>
// yeah looks sophisticated, doesn't it? Sophisticate my arse!
class iterator_adapter<Iterator, detail::value_iterator_tag> : public iterator_adapter_base<iterator_adapter<Iterator, detail::value_iterator_tag>, Iterator > {
public:
	// STL is just broken...
	typedef typename std::iterator_traits<Iterator>::iterator_category iterator_category;
	typedef typename std::iterator_traits<Iterator>::value_type::second_type value_type;
	typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
	// uhrg yes well you see it's a const iterator, but there is this std::pair...
	typedef typename std::iterator_traits<Iterator>::value_type::second_type const* pointer;
	typedef typename std::iterator_traits<Iterator>::value_type::second_type const& reference;

	iterator_adapter() { }

	iterator_adapter(Iterator const& base_iter)
	:
		// well we don't know what this means, could be anything... so please be explicit.
		iterator_adapter_base<iterator_adapter<Iterator, detail::value_iterator_tag>, Iterator >(base_iter)
	{ }

	iterator_adapter(iterator_adapter const& o)
	:
		// oh, and mark the space at the end. C++1X finally did away with this HOORAYY! (sryly?)
		iterator_adapter_base<iterator_adapter<Iterator, detail::value_iterator_tag>, Iterator >(o.base_iter_)
	{ }

	iterator_adapter & operator=(iterator_adapter const& o)
	{
		// again... what is base_iter_? ahh this one.
		this->base_iter_ = o.base_iter_;
		return *this;
	}

	reference operator*() const
	{
		return this->base_iter_->second;
	}

	pointer operator->() const
	{
		// looks beautiful doesn't it?
		return &(this->base_iter_->second);
	}
};

template <typename Iterator>
iterator_adapter<Iterator, detail::value_iterator_tag> make_value_iterator(Iterator const& it)
{
	return iterator_adapter<Iterator, detail::value_iterator_tag>(it);
}

detail::value_iterator_tag value_adapter;

template <typename ContainerT, typename Tag>
struct range_adaptor;

template <typename ContainerT, typename Tag>
struct range_adaptor {
	range_adaptor(ContainerT & container)
	:
		begin_(container.begin()),
		end_(container.end())
	{ }

	range_adaptor(ContainerT const& container)
	:
		cbegin_(container.begin()),
		cend_(container.end())
	{ }

	// needed
	range_adaptor(range_adaptor const& o)
	{ }

	// I just *love* the typename shit.
	typedef iterator_adapter<typename ContainerT::iterator, Tag> iterator;
	typedef iterator_adapter<typename ContainerT::const_iterator, Tag> const_iterator;

	iterator begin()
	{
		return begin_;
	}

	iterator end()
	{
		return end_;
	}

	const_iterator begin() const
	{
		return cbegin_;
	}

	const_iterator end() const
	{
		return cend_;
	}

private:
	range_adaptor() {}
	range_adaptor & operator=(range_adaptor const&) {}

	iterator begin_;
	iterator end_;
	// meh. giving up.
	const_iterator cbegin_;
	const_iterator cend_;
};

// Yay let's overload some operators. 'Cause you know *frameworks*
template <typename ContainerT, typename Tag>
range_adaptor<ContainerT, Tag> operator|(ContainerT const& container, Tag)
{
	return range_adaptor<ContainerT, Tag>(container);
}

template <typename ContainerT, typename Tag>
range_adaptor<ContainerT, Tag> operator|(ContainerT & container, Tag)
{
	return range_adaptor<ContainerT, Tag>(container);
}

void foo(bool const&)
{
}

int main()
{
	typedef std::map<int, bool> map_type;
	map_type m;

	// now any decent language has had this since 1995.
	BOOST_FOREACH(bool x, m | value_adapter) {
		(void) x;
	}

	BOOST_FOREACH(bool const& x, m | value_adapter) {
		(void) x;
	}

#if 0
	// ahhrgg...
	BOOST_FOREACH(bool & x, m | value_adapter) {
		(void) x;
	}
#endif
	std::for_each(make_value_iterator(m.begin()), make_value_iterator(m.end()), foo);

	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <cstdlib>

#include <unistd.h>

#include <ft2build.h>
#include FT_FREETYPE_H

int main(int argc, char **argv) {

    return 0;
}

<commit_msg>got arguments input<commit_after>#include <iostream>
#include <cstdio>
#include <cstdlib>

#include <getopt.h>

#include <ft2build.h>
#include FT_FREETYPE_H

int main(int argc, char **argv) {

    int c;

    char *text_file_name;
    char *font_file_name;

    while (1) {
        static struct option long_options[] = { { "font", required_argument,
                NULL, 'f' }, { "text", required_argument, NULL, 't' }, { 0, 0,
                0, 0 } };

        int option_index = 0;

        c = getopt_long(argc, argv, "f:t:", long_options, &option_index);

        if (c == -1) {
            break;
        }

        switch (c) {
        case 0:
            break;

        case 't':
            text_file_name = optarg;
            break;

        case 'f':
            font_file_name = optarg;
            break;

        case '?':
            /* getopt_long already printed an error message. */
            break;

        default:
            return 1;
        }
    }

    return 0;
}

<|endoftext|>


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

#include <QtGlobal>

#if defined(Q_OS_WIN32)
#  define NTDDI_VERSION NTDDI_VISTA
#  include <Objbase.h>
#  include <Shlobj.h>
#endif

#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QString>

#if defined(Q_OS_WIN32)
#  include <QSettings>
#endif

#include <nitroshare/fileutil.h>

#include "util.h"

#if defined(Q_OS_WIN32)
const QString RegistryKey = "HKEY_CURRENT_USER\\Software\\Google\\Chrome\\NativeMessagingHosts\\net.nitroshare.chrome";
#endif

const QString JsonTemplate =
    "{\n"
    "    \"name\": \"net.nitroshare.chrome\",\n"
    "    \"description\": \"NitroShare\",\n"
    "    \"path\": \"%1\",\n"
    "    \"type\": \"stdio\",\n"
    "    \"allowed_origins\": [\n"
    "        \"chrome-extension://cljjpoinofmbdnbnpebolibochlfenag/\"\n"
    "    ]\n"
    "}\n";

// TODO: add support for Chromium

bool Util::installJson()
{
    QString parentPath;

#if defined(Q_OS_WIN32)

    // Obtain the path to the AppData\Local directory
    PWSTR pszPath;
    HRESULT hr = SHGetKnownFolderPath(
        FOLDERID_LocalAppData,
        KF_FLAG_CREATE,
        NULL,
        &pszPath
    );
    if (FAILED(hr)) {
        return false;
    }
    QDir appData(QString::fromUtf16(reinterpret_cast<const ushort*>(pszPath)));
    CoTaskMemFree(pszPath);

    // Use the folder for storing the JSON file
    parentPath = appData.absoluteFilePath("NitroShare");

#elif defined(Q_OS_MACX)
    parentPath = QDir::home().absoluteFilePath("Library/Application Support/Google/Chrome/NativeMessagingHosts");
#elif defined(Q_OS_LINUX)
    parentPath = QDir::home().absoluteFilePath(".config/google-chrome/NativeMessagingHosts");
#else
    // Unknown platform; fail automatically
    return false;
#endif

    // Ensure that the parent path exists
    if (!QDir(parentPath).mkpath(".")) {
        return false;
    }

    // It is assumed that the nitroshare-nmh executable is located in the same
    // directory as the host for this plugin
    QString nmhPath = QDir::cleanPath(
        QFileInfo(QCoreApplication::arguments().at(0)).absolutePath() +
        QDir::separator() + "nitroshare-nmh"
#if defined(Q_OS_WIN32)
        + ".exe"
#endif
    );

    // Create the JSON file
    QString jsonFilename = QDir(parentPath).absoluteFilePath("net.nitroshare.chrome.json");
    if (!FileUtil::createFile(jsonFilename, JsonTemplate.arg(nmhPath).toUtf8())) {
        return false;
    }

#if defined(Q_OS_WIN32)

    // Windows requires one additional step - a registry entry must be created
    QSettings settings(RegistryKey, QSettings::NativeFormat);
    settings.setValue("Default", jsonFilename);

#endif

    // Everything succeeded
    return true;
}
<commit_msg>Add another missing definition required for compilation on Windows.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <QtGlobal>

#if defined(Q_OS_WIN32)
#  define NTDDI_VERSION NTDDI_VISTA
#  define _WIN32_WINNT _WIN32_WINNT_VISTA
#  include <Objbase.h>
#  include <Shlobj.h>
#endif

#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QString>

#if defined(Q_OS_WIN32)
#  include <QSettings>
#endif

#include <nitroshare/fileutil.h>

#include "util.h"

#if defined(Q_OS_WIN32)
const QString RegistryKey = "HKEY_CURRENT_USER\\Software\\Google\\Chrome\\NativeMessagingHosts\\net.nitroshare.chrome";
#endif

const QString JsonTemplate =
    "{\n"
    "    \"name\": \"net.nitroshare.chrome\",\n"
    "    \"description\": \"NitroShare\",\n"
    "    \"path\": \"%1\",\n"
    "    \"type\": \"stdio\",\n"
    "    \"allowed_origins\": [\n"
    "        \"chrome-extension://cljjpoinofmbdnbnpebolibochlfenag/\"\n"
    "    ]\n"
    "}\n";

// TODO: add support for Chromium

bool Util::installJson()
{
    QString parentPath;

#if defined(Q_OS_WIN32)

    // Obtain the path to the AppData\Local directory
    PWSTR pszPath;
    HRESULT hr = SHGetKnownFolderPath(
        FOLDERID_LocalAppData,
        KF_FLAG_CREATE,
        NULL,
        &pszPath
    );
    if (FAILED(hr)) {
        return false;
    }
    QDir appData(QString::fromUtf16(reinterpret_cast<const ushort*>(pszPath)));
    CoTaskMemFree(pszPath);

    // Use the folder for storing the JSON file
    parentPath = appData.absoluteFilePath("NitroShare");

#elif defined(Q_OS_MACX)
    parentPath = QDir::home().absoluteFilePath("Library/Application Support/Google/Chrome/NativeMessagingHosts");
#elif defined(Q_OS_LINUX)
    parentPath = QDir::home().absoluteFilePath(".config/google-chrome/NativeMessagingHosts");
#else
    // Unknown platform; fail automatically
    return false;
#endif

    // Ensure that the parent path exists
    if (!QDir(parentPath).mkpath(".")) {
        return false;
    }

    // It is assumed that the nitroshare-nmh executable is located in the same
    // directory as the host for this plugin
    QString nmhPath = QDir::cleanPath(
        QFileInfo(QCoreApplication::arguments().at(0)).absolutePath() +
        QDir::separator() + "nitroshare-nmh"
#if defined(Q_OS_WIN32)
        + ".exe"
#endif
    );

    // Create the JSON file
    QString jsonFilename = QDir(parentPath).absoluteFilePath("net.nitroshare.chrome.json");
    if (!FileUtil::createFile(jsonFilename, JsonTemplate.arg(nmhPath).toUtf8())) {
        return false;
    }

#if defined(Q_OS_WIN32)

    // Windows requires one additional step - a registry entry must be created
    QSettings settings(RegistryKey, QSettings::NativeFormat);
    settings.setValue("Default", jsonFilename);

#endif

    // Everything succeeded
    return true;
}
<|endoftext|>


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

#include <osc/reader/types/OscBlob.h>
#include <tools/ByteBuffer.h>
#include <osc/exceptions/CharConversionException.h>
#include <osc/exceptions/DoubleConversionException.h>
#include <osc/exceptions/IntegerConversionException.h>
#include <osc/exceptions/FloatConversionException.h>
#include <osc/exceptions/LongConversionException.h>
#include <osc/exceptions/StringConversionException.h>

OscBlob::OscBlob(ByteBuffer* packet, qint32 pos)
: OscValue('b', packet, pos)
{
	try
	{
		get();
	}
	catch (const QException& e)
	{
		throw e;
	}
}

/**
 * Returns the blob data.
 *
 * @return a blob data.
 */
QByteArray& OscBlob::get()
{
	try
	{
		mBlobSize = mPacket->getInt(mPos);
		mData = QByteArray(mBlobSize, 0);
		mPacket->setPosition(mPos + 4);
		mPacket->get(&mData, 0, mBlobSize);

        qint32 alignedEnd = (mPos + 4 + mBlobSize + 4) & ~((qint32)0x03);
        mPacket->setPosition(alignedEnd);

		return mData;
	}
	catch (const QException& e)
	{
		throw e;
	}
}

bool OscBlob::toBoolean()
{
	return (get().length() != 0);
}

QByteArray OscBlob::toBytes()
{
	return get();
}

char OscBlob::toChar()
{
	throw CharConversionException();
}

double OscBlob::toDouble()
{
	throw DoubleConversionException();
}

float OscBlob::toFloat()
{
	throw FloatConversionException();
}

qint32 OscBlob::toInteger()
{
	throw IntegerConversionException();
}

qint64 OscBlob::toLong()
{
	throw LongConversionException();
}

QString OscBlob::toString()
{
	throw StringConversionException();
}
<commit_msg>fix: Blob<commit_after>/*
 * Copyright (c) 2014 MUGEN SAS
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <osc/reader/types/OscBlob.h>
#include <tools/ByteBuffer.h>
#include <osc/exceptions/CharConversionException.h>
#include <osc/exceptions/DoubleConversionException.h>
#include <osc/exceptions/IntegerConversionException.h>
#include <osc/exceptions/FloatConversionException.h>
#include <osc/exceptions/LongConversionException.h>
#include <osc/exceptions/StringConversionException.h>

OscBlob::OscBlob(ByteBuffer* packet, qint32 pos)
: OscValue('b', packet, pos)
{
	try
	{
		get();
	}
	catch (const QException& e)
	{
		throw e;
	}
}

/**
 * Returns the blob data.
 *
 * @return a blob data.
 */
QByteArray& OscBlob::get()
{
	try
	{
		mBlobSize = mPacket->getInt(mPos);
        mPacket->setPosition(mPos + 4);

        if (mBlobSize != 0)
        {
            mData = QByteArray(mBlobSize, 0);
            mPacket->get(&mData, 0, mBlobSize);
            mPacket->setPosition((mBlobSize + 4) & ~((qint32)0x03));
        }

		return mData;
	}
	catch (const QException& e)
	{
		throw e;
	}
}

bool OscBlob::toBoolean()
{
	return (get().length() != 0);
}

QByteArray OscBlob::toBytes()
{
	return get();
}

char OscBlob::toChar()
{
	throw CharConversionException();
}

double OscBlob::toDouble()
{
	throw DoubleConversionException();
}

float OscBlob::toFloat()
{
	throw FloatConversionException();
}

qint32 OscBlob::toInteger()
{
	throw IntegerConversionException();
}

qint64 OscBlob::toLong()
{
	throw LongConversionException();
}

QString OscBlob::toString()
{
	throw StringConversionException();
}
<|endoftext|>


<commit_before>#include "Gina.h"

namespace pGina
{
	namespace GINA
	{
		static WinlogonInterface * WinlogonInterfaceFactory(HANDLE hWlx, void * pFuncs)
		{
#if _DEBUG
			// In debug only, if hWlx == NULL || pFuncs is null, then we
			//	create a winlogon interface that is fake for testing purposes.
			if(hWlx == NULL || pFuncs == NULL)
				return new DebugWinlogonInterface();
#endif
			return new RealWinlogonInterface(hWlx, pFuncs);
		}

		/*static*/
		bool Gina::Initialize(HANDLE hWlx, void * pWinlogonFunctions, Gina **context)
		{
			// Create a winlogon interface class, and a Gina class, and pair them
			//  the result becomes our context, which Winlogon will give us on all
			//  calls.
			*context = new Gina(WinlogonInterfaceFactory(hWlx, pWinlogonFunctions));
			return true;
		}

		Gina::Gina(WinlogonInterface *pWinLogonIface) :
			m_winlogon(pWinLogonIface)
		{
		}
	}
}<commit_msg>forgot license<commit_after>/*
	Copyright (c) 2011, pGina Team
	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 the pGina Team 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
	DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
	ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Gina.h"

namespace pGina
{
	namespace GINA
	{
		static WinlogonInterface * WinlogonInterfaceFactory(HANDLE hWlx, void * pFuncs)
		{
#if _DEBUG
			// In debug only, if hWlx == NULL || pFuncs is null, then we
			//	create a winlogon interface that is fake for testing purposes.
			if(hWlx == NULL || pFuncs == NULL)
				return new DebugWinlogonInterface();
#endif
			return new RealWinlogonInterface(hWlx, pFuncs);
		}

		/*static*/
		bool Gina::Initialize(HANDLE hWlx, void * pWinlogonFunctions, Gina **context)
		{
			// Create a winlogon interface class, and a Gina class, and pair them
			//  the result becomes our context, which Winlogon will give us on all
			//  calls.
			*context = new Gina(WinlogonInterfaceFactory(hWlx, pWinlogonFunctions));
			return true;
		}

		Gina::Gina(WinlogonInterface *pWinLogonIface) :
			m_winlogon(pWinLogonIface)
		{
		}
	}
}<|endoftext|>