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

#include <list>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <utility>
#include <vector>

#include <grpc/grpc.h>
#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
#include <grpcpp/alarm.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>

#include "src/proto/grpc/testing/benchmark_service.grpc.pb.h"
#include "test/cpp/qps/client.h"
#include "test/cpp/qps/usage_timer.h"

namespace grpc {
namespace testing {

/**
 * Maintains context info per RPC
 */
struct CallbackClientRpcContext {
  CallbackClientRpcContext(BenchmarkService::Stub* stub)
      : alarm_(nullptr), stub_(stub) {}

  ~CallbackClientRpcContext() {}

  SimpleResponse response_;
  ClientContext context_;
  std::unique_ptr<Alarm> alarm_;
  BenchmarkService::Stub* stub_;
};

static std::unique_ptr<BenchmarkService::Stub> BenchmarkStubCreator(
    const std::shared_ptr<Channel>& ch) {
  return BenchmarkService::NewStub(ch);
}

class CallbackClient
    : public ClientImpl<BenchmarkService::Stub, SimpleRequest> {
 public:
  CallbackClient(const ClientConfig& config)
      : ClientImpl<BenchmarkService::Stub, SimpleRequest>(
            config, BenchmarkStubCreator) {
    num_threads_ = NumThreads(config);
    rpcs_done_ = 0;

    //  Don't divide the fixed load among threads as the user threads
    //  only bootstrap the RPCs
    SetupLoadTest(config, 1);
    total_outstanding_rpcs_ =
        config.client_channels() * config.outstanding_rpcs_per_channel();
  }

  virtual ~CallbackClient() {}

  /**
   * The main thread of the benchmark will be waiting on DestroyMultithreading.
   * Increment the rpcs_done_ variable to signify that the Callback RPC
   * after thread completion is done. When the last outstanding rpc increments
   * the counter it should also signal the main thread's conditional variable.
   */
  void NotifyMainThreadOfThreadCompletion() {
    std::lock_guard<std::mutex> l(shutdown_mu_);
    rpcs_done_++;
    if (rpcs_done_ == total_outstanding_rpcs_) {
      shutdown_cv_.notify_one();
    }
  }

  gpr_timespec NextRPCIssueTime() {
    std::lock_guard<std::mutex> l(next_issue_time_mu_);
    return Client::NextIssueTime(0);
  }

 protected:
  size_t num_threads_;
  size_t total_outstanding_rpcs_;
  // The below mutex and condition variable is used by main benchmark thread to
  // wait on completion of all RPCs before shutdown
  std::mutex shutdown_mu_;
  std::condition_variable shutdown_cv_;
  // Number of rpcs done after thread completion
  size_t rpcs_done_;
  // Vector of Context data pointers for running a RPC
  std::vector<std::unique_ptr<CallbackClientRpcContext>> ctx_;

  virtual void InitThreadFuncImpl(size_t thread_idx) = 0;
  virtual bool ThreadFuncImpl(Thread* t, size_t thread_idx) = 0;

  void ThreadFunc(size_t thread_idx, Thread* t) override {
    InitThreadFuncImpl(thread_idx);
    ThreadFuncImpl(t, thread_idx);
  }

 private:
  std::mutex next_issue_time_mu_;  // Used by next issue time

  int NumThreads(const ClientConfig& config) {
    int num_threads = config.async_client_threads();
    if (num_threads <= 0) {  // Use dynamic sizing
      num_threads = cores_;
      gpr_log(GPR_INFO, "Sizing callback client to %d threads", num_threads);
    }
    return num_threads;
  }

  /**
   * Wait until all outstanding Callback RPCs are done
   */
  void DestroyMultithreading() final {
    std::unique_lock<std::mutex> l(shutdown_mu_);
    while (rpcs_done_ != total_outstanding_rpcs_) {
      shutdown_cv_.wait(l);
    }
    EndThreads();
  }
};

class CallbackUnaryClient final : public CallbackClient {
 public:
  CallbackUnaryClient(const ClientConfig& config) : CallbackClient(config) {
    for (int ch = 0; ch < config.client_channels(); ch++) {
      for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
        ctx_.emplace_back(
            new CallbackClientRpcContext(channels_[ch].get_stub()));
      }
    }
    StartThreads(num_threads_);
  }
  ~CallbackUnaryClient() {}

 protected:
  bool ThreadFuncImpl(Thread* t, size_t thread_idx) override {
    for (size_t vector_idx = thread_idx; vector_idx < total_outstanding_rpcs_;
         vector_idx += num_threads_) {
      ScheduleRpc(t, vector_idx);
    }
    return true;
  }

  void InitThreadFuncImpl(size_t thread_idx) override { return; }

 private:
  void ScheduleRpc(Thread* t, size_t vector_idx) {
    if (!closed_loop_) {
      gpr_timespec next_issue_time = NextRPCIssueTime();
      // Start an alarm callback to run the internal callback after
      // next_issue_time
      if (ctx_[vector_idx]->alarm_ == nullptr) {
        ctx_[vector_idx]->alarm_.reset(new Alarm);
      }
      ctx_[vector_idx]->alarm_->experimental().Set(
          next_issue_time, [this, t, vector_idx](bool ok) {
            IssueUnaryCallbackRpc(t, vector_idx);
          });
    } else {
      IssueUnaryCallbackRpc(t, vector_idx);
    }
  }

  void IssueUnaryCallbackRpc(Thread* t, size_t vector_idx) {
    GPR_TIMER_SCOPE("CallbackUnaryClient::ThreadFunc", 0);
    double start = UsageTimer::Now();
    ctx_[vector_idx]->stub_->experimental_async()->UnaryCall(
        (&ctx_[vector_idx]->context_), &request_, &ctx_[vector_idx]->response_,
        [this, t, start, vector_idx](grpc::Status s) {
          // Update Histogram with data from the callback run
          HistogramEntry entry;
          if (s.ok()) {
            entry.set_value((UsageTimer::Now() - start) * 1e9);
          }
          entry.set_status(s.error_code());
          t->UpdateHistogram(&entry);

          if (ThreadCompleted() || !s.ok()) {
            // Notify thread of completion
            NotifyMainThreadOfThreadCompletion();
          } else {
            // Reallocate ctx for next RPC
            ctx_[vector_idx].reset(
                new CallbackClientRpcContext(ctx_[vector_idx]->stub_));
            // Schedule a new RPC
            ScheduleRpc(t, vector_idx);
          }
        });
  }
};

class CallbackStreamingClient : public CallbackClient {
 public:
  CallbackStreamingClient(const ClientConfig& config)
      : CallbackClient(config),
        messages_per_stream_(config.messages_per_stream()) {
    for (int ch = 0; ch < config.client_channels(); ch++) {
      for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
        ctx_.emplace_back(
            new CallbackClientRpcContext(channels_[ch].get_stub()));
      }
    }
    StartThreads(num_threads_);
  }
  ~CallbackStreamingClient() {}

  void AddHistogramEntry(double start, bool ok, Thread* thread_ptr) {
    // Update Histogram with data from the callback run
    HistogramEntry entry;
    if (ok) {
      entry.set_value((UsageTimer::Now() - start) * 1e9);
    }
    thread_ptr->UpdateHistogram(&entry);
  }

  int messages_per_stream() { return messages_per_stream_; }

 protected:
  const int messages_per_stream_;
};

class CallbackStreamingPingPongClient : public CallbackStreamingClient {
 public:
  CallbackStreamingPingPongClient(const ClientConfig& config)
      : CallbackStreamingClient(config) {}
  ~CallbackStreamingPingPongClient() {}
};

class CallbackStreamingPingPongReactor final
    : public grpc::experimental::ClientBidiReactor<SimpleRequest,
                                                   SimpleResponse> {
 public:
  CallbackStreamingPingPongReactor(
      CallbackStreamingPingPongClient* client,
      std::unique_ptr<CallbackClientRpcContext> ctx)
      : client_(client), ctx_(std::move(ctx)), messages_issued_(0) {}

  void StartNewRpc() {
    ctx_->stub_->experimental_async()->StreamingCall(&(ctx_->context_), this);
    write_time_ = UsageTimer::Now();
    StartWrite(client_->request());
    writes_done_started_.clear();
    StartCall();
  }

  void OnWriteDone(bool ok) override {
    if (!ok) {
      gpr_log(GPR_ERROR, "Error writing RPC");
    }
    if ((!ok || client_->ThreadCompleted()) &&
        !writes_done_started_.test_and_set()) {
      StartWritesDone();
    }
    StartRead(&ctx_->response_);
  }

  void OnReadDone(bool ok) override {
    client_->AddHistogramEntry(write_time_, ok, thread_ptr_);

    if (client_->ThreadCompleted() || !ok ||
        (client_->messages_per_stream() != 0 &&
         ++messages_issued_ >= client_->messages_per_stream())) {
      if (!ok) {
        gpr_log(GPR_ERROR, "Error reading RPC");
      }
      if (!writes_done_started_.test_and_set()) {
        StartWritesDone();
      }
      return;
    }
    if (!client_->IsClosedLoop()) {
      gpr_timespec next_issue_time = client_->NextRPCIssueTime();
      // Start an alarm callback to run the internal callback after
      // next_issue_time
      ctx_->alarm_.experimental().Set(next_issue_time, [this](bool ok) {
        write_time_ = UsageTimer::Now();
        StartWrite(client_->request());
      });
    } else {
      write_time_ = UsageTimer::Now();
      StartWrite(client_->request());
    }
  }

  void OnDone(const Status& s) override {
    if (client_->ThreadCompleted() || !s.ok()) {
      client_->NotifyMainThreadOfThreadCompletion();
      return;
    }
    ctx_.reset(new CallbackClientRpcContext(ctx_->stub_));
    ScheduleRpc();
  }

  void ScheduleRpc() {
    if (!client_->IsClosedLoop()) {
      gpr_timespec next_issue_time = client_->NextRPCIssueTime();
      // Start an alarm callback to run the internal callback after
      // next_issue_time
      if (ctx_->alarm_ == nullptr) {
        ctx_->alarm_.reset(new Alarm);
      }
      ctx_->alarm_->experimental().Set(next_issue_time,
                                       [this](bool ok) { StartNewRpc(); });
    } else {
      StartNewRpc();
    }
  }

  void set_thread_ptr(Client::Thread* ptr) { thread_ptr_ = ptr; }

  CallbackStreamingPingPongClient* client_;
  std::unique_ptr<CallbackClientRpcContext> ctx_;
  std::atomic_flag writes_done_started_;
  Client::Thread* thread_ptr_;  // Needed to update histogram entries
  double write_time_;           // Track ping-pong round start time
  int messages_issued_;         // Messages issued by this stream
};

class CallbackStreamingPingPongClientImpl final
    : public CallbackStreamingPingPongClient {
 public:
  CallbackStreamingPingPongClientImpl(const ClientConfig& config)
      : CallbackStreamingPingPongClient(config) {
    for (size_t i = 0; i < total_outstanding_rpcs_; i++)
      reactor_.emplace_back(
          new CallbackStreamingPingPongReactor(this, std::move(ctx_[i])));
  }
  ~CallbackStreamingPingPongClientImpl() {}

  bool ThreadFuncImpl(Client::Thread* t, size_t thread_idx) override {
    for (size_t vector_idx = thread_idx; vector_idx < total_outstanding_rpcs_;
         vector_idx += num_threads_) {
      reactor_[vector_idx]->set_thread_ptr(t);
      reactor_[vector_idx]->ScheduleRpc();
    }
    return true;
  }

  void InitThreadFuncImpl(size_t thread_idx) override {}

 private:
  std::vector<std::unique_ptr<CallbackStreamingPingPongReactor>> reactor_;
};

// TODO(mhaidry) : Implement Streaming from client, server and both ways

std::unique_ptr<Client> CreateCallbackClient(const ClientConfig& config) {
  switch (config.rpc_type()) {
    case UNARY:
      return std::unique_ptr<Client>(new CallbackUnaryClient(config));
    case STREAMING:
      return std::unique_ptr<Client>(
          new CallbackStreamingPingPongClientImpl(config));
    case STREAMING_FROM_CLIENT:
    case STREAMING_FROM_SERVER:
    case STREAMING_BOTH_WAYS:
      assert(false);
      return nullptr;
    default:
      assert(false);
      return nullptr;
  }
}

}  // namespace testing
}  // namespace grpc
<commit_msg>Fix another call of Alarm::experimental()::Set.<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <list>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <utility>
#include <vector>

#include <grpc/grpc.h>
#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
#include <grpcpp/alarm.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>

#include "src/proto/grpc/testing/benchmark_service.grpc.pb.h"
#include "test/cpp/qps/client.h"
#include "test/cpp/qps/usage_timer.h"

namespace grpc {
namespace testing {

/**
 * Maintains context info per RPC
 */
struct CallbackClientRpcContext {
  CallbackClientRpcContext(BenchmarkService::Stub* stub)
      : alarm_(nullptr), stub_(stub) {}

  ~CallbackClientRpcContext() {}

  SimpleResponse response_;
  ClientContext context_;
  std::unique_ptr<Alarm> alarm_;
  BenchmarkService::Stub* stub_;
};

static std::unique_ptr<BenchmarkService::Stub> BenchmarkStubCreator(
    const std::shared_ptr<Channel>& ch) {
  return BenchmarkService::NewStub(ch);
}

class CallbackClient
    : public ClientImpl<BenchmarkService::Stub, SimpleRequest> {
 public:
  CallbackClient(const ClientConfig& config)
      : ClientImpl<BenchmarkService::Stub, SimpleRequest>(
            config, BenchmarkStubCreator) {
    num_threads_ = NumThreads(config);
    rpcs_done_ = 0;

    //  Don't divide the fixed load among threads as the user threads
    //  only bootstrap the RPCs
    SetupLoadTest(config, 1);
    total_outstanding_rpcs_ =
        config.client_channels() * config.outstanding_rpcs_per_channel();
  }

  virtual ~CallbackClient() {}

  /**
   * The main thread of the benchmark will be waiting on DestroyMultithreading.
   * Increment the rpcs_done_ variable to signify that the Callback RPC
   * after thread completion is done. When the last outstanding rpc increments
   * the counter it should also signal the main thread's conditional variable.
   */
  void NotifyMainThreadOfThreadCompletion() {
    std::lock_guard<std::mutex> l(shutdown_mu_);
    rpcs_done_++;
    if (rpcs_done_ == total_outstanding_rpcs_) {
      shutdown_cv_.notify_one();
    }
  }

  gpr_timespec NextRPCIssueTime() {
    std::lock_guard<std::mutex> l(next_issue_time_mu_);
    return Client::NextIssueTime(0);
  }

 protected:
  size_t num_threads_;
  size_t total_outstanding_rpcs_;
  // The below mutex and condition variable is used by main benchmark thread to
  // wait on completion of all RPCs before shutdown
  std::mutex shutdown_mu_;
  std::condition_variable shutdown_cv_;
  // Number of rpcs done after thread completion
  size_t rpcs_done_;
  // Vector of Context data pointers for running a RPC
  std::vector<std::unique_ptr<CallbackClientRpcContext>> ctx_;

  virtual void InitThreadFuncImpl(size_t thread_idx) = 0;
  virtual bool ThreadFuncImpl(Thread* t, size_t thread_idx) = 0;

  void ThreadFunc(size_t thread_idx, Thread* t) override {
    InitThreadFuncImpl(thread_idx);
    ThreadFuncImpl(t, thread_idx);
  }

 private:
  std::mutex next_issue_time_mu_;  // Used by next issue time

  int NumThreads(const ClientConfig& config) {
    int num_threads = config.async_client_threads();
    if (num_threads <= 0) {  // Use dynamic sizing
      num_threads = cores_;
      gpr_log(GPR_INFO, "Sizing callback client to %d threads", num_threads);
    }
    return num_threads;
  }

  /**
   * Wait until all outstanding Callback RPCs are done
   */
  void DestroyMultithreading() final {
    std::unique_lock<std::mutex> l(shutdown_mu_);
    while (rpcs_done_ != total_outstanding_rpcs_) {
      shutdown_cv_.wait(l);
    }
    EndThreads();
  }
};

class CallbackUnaryClient final : public CallbackClient {
 public:
  CallbackUnaryClient(const ClientConfig& config) : CallbackClient(config) {
    for (int ch = 0; ch < config.client_channels(); ch++) {
      for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
        ctx_.emplace_back(
            new CallbackClientRpcContext(channels_[ch].get_stub()));
      }
    }
    StartThreads(num_threads_);
  }
  ~CallbackUnaryClient() {}

 protected:
  bool ThreadFuncImpl(Thread* t, size_t thread_idx) override {
    for (size_t vector_idx = thread_idx; vector_idx < total_outstanding_rpcs_;
         vector_idx += num_threads_) {
      ScheduleRpc(t, vector_idx);
    }
    return true;
  }

  void InitThreadFuncImpl(size_t thread_idx) override { return; }

 private:
  void ScheduleRpc(Thread* t, size_t vector_idx) {
    if (!closed_loop_) {
      gpr_timespec next_issue_time = NextRPCIssueTime();
      // Start an alarm callback to run the internal callback after
      // next_issue_time
      if (ctx_[vector_idx]->alarm_ == nullptr) {
        ctx_[vector_idx]->alarm_.reset(new Alarm);
      }
      ctx_[vector_idx]->alarm_->experimental().Set(
          next_issue_time, [this, t, vector_idx](bool ok) {
            IssueUnaryCallbackRpc(t, vector_idx);
          });
    } else {
      IssueUnaryCallbackRpc(t, vector_idx);
    }
  }

  void IssueUnaryCallbackRpc(Thread* t, size_t vector_idx) {
    GPR_TIMER_SCOPE("CallbackUnaryClient::ThreadFunc", 0);
    double start = UsageTimer::Now();
    ctx_[vector_idx]->stub_->experimental_async()->UnaryCall(
        (&ctx_[vector_idx]->context_), &request_, &ctx_[vector_idx]->response_,
        [this, t, start, vector_idx](grpc::Status s) {
          // Update Histogram with data from the callback run
          HistogramEntry entry;
          if (s.ok()) {
            entry.set_value((UsageTimer::Now() - start) * 1e9);
          }
          entry.set_status(s.error_code());
          t->UpdateHistogram(&entry);

          if (ThreadCompleted() || !s.ok()) {
            // Notify thread of completion
            NotifyMainThreadOfThreadCompletion();
          } else {
            // Reallocate ctx for next RPC
            ctx_[vector_idx].reset(
                new CallbackClientRpcContext(ctx_[vector_idx]->stub_));
            // Schedule a new RPC
            ScheduleRpc(t, vector_idx);
          }
        });
  }
};

class CallbackStreamingClient : public CallbackClient {
 public:
  CallbackStreamingClient(const ClientConfig& config)
      : CallbackClient(config),
        messages_per_stream_(config.messages_per_stream()) {
    for (int ch = 0; ch < config.client_channels(); ch++) {
      for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
        ctx_.emplace_back(
            new CallbackClientRpcContext(channels_[ch].get_stub()));
      }
    }
    StartThreads(num_threads_);
  }
  ~CallbackStreamingClient() {}

  void AddHistogramEntry(double start, bool ok, Thread* thread_ptr) {
    // Update Histogram with data from the callback run
    HistogramEntry entry;
    if (ok) {
      entry.set_value((UsageTimer::Now() - start) * 1e9);
    }
    thread_ptr->UpdateHistogram(&entry);
  }

  int messages_per_stream() { return messages_per_stream_; }

 protected:
  const int messages_per_stream_;
};

class CallbackStreamingPingPongClient : public CallbackStreamingClient {
 public:
  CallbackStreamingPingPongClient(const ClientConfig& config)
      : CallbackStreamingClient(config) {}
  ~CallbackStreamingPingPongClient() {}
};

class CallbackStreamingPingPongReactor final
    : public grpc::experimental::ClientBidiReactor<SimpleRequest,
                                                   SimpleResponse> {
 public:
  CallbackStreamingPingPongReactor(
      CallbackStreamingPingPongClient* client,
      std::unique_ptr<CallbackClientRpcContext> ctx)
      : client_(client), ctx_(std::move(ctx)), messages_issued_(0) {}

  void StartNewRpc() {
    ctx_->stub_->experimental_async()->StreamingCall(&(ctx_->context_), this);
    write_time_ = UsageTimer::Now();
    StartWrite(client_->request());
    writes_done_started_.clear();
    StartCall();
  }

  void OnWriteDone(bool ok) override {
    if (!ok) {
      gpr_log(GPR_ERROR, "Error writing RPC");
    }
    if ((!ok || client_->ThreadCompleted()) &&
        !writes_done_started_.test_and_set()) {
      StartWritesDone();
    }
    StartRead(&ctx_->response_);
  }

  void OnReadDone(bool ok) override {
    client_->AddHistogramEntry(write_time_, ok, thread_ptr_);

    if (client_->ThreadCompleted() || !ok ||
        (client_->messages_per_stream() != 0 &&
         ++messages_issued_ >= client_->messages_per_stream())) {
      if (!ok) {
        gpr_log(GPR_ERROR, "Error reading RPC");
      }
      if (!writes_done_started_.test_and_set()) {
        StartWritesDone();
      }
      return;
    }
    if (!client_->IsClosedLoop()) {
      gpr_timespec next_issue_time = client_->NextRPCIssueTime();
      // Start an alarm callback to run the internal callback after
      // next_issue_time
      if (ctx_->alarm_ == nullptr) {
        ctx_->alarm_.reset(new Alarm);
      }
      ctx_->alarm_->experimental().Set(next_issue_time, [this](bool ok) {
        write_time_ = UsageTimer::Now();
        StartWrite(client_->request());
      });
    } else {
      write_time_ = UsageTimer::Now();
      StartWrite(client_->request());
    }
  }

  void OnDone(const Status& s) override {
    if (client_->ThreadCompleted() || !s.ok()) {
      client_->NotifyMainThreadOfThreadCompletion();
      return;
    }
    ctx_.reset(new CallbackClientRpcContext(ctx_->stub_));
    ScheduleRpc();
  }

  void ScheduleRpc() {
    if (!client_->IsClosedLoop()) {
      gpr_timespec next_issue_time = client_->NextRPCIssueTime();
      // Start an alarm callback to run the internal callback after
      // next_issue_time
      if (ctx_->alarm_ == nullptr) {
        ctx_->alarm_.reset(new Alarm);
      }
      ctx_->alarm_->experimental().Set(next_issue_time,
                                       [this](bool ok) { StartNewRpc(); });
    } else {
      StartNewRpc();
    }
  }

  void set_thread_ptr(Client::Thread* ptr) { thread_ptr_ = ptr; }

  CallbackStreamingPingPongClient* client_;
  std::unique_ptr<CallbackClientRpcContext> ctx_;
  std::atomic_flag writes_done_started_;
  Client::Thread* thread_ptr_;  // Needed to update histogram entries
  double write_time_;           // Track ping-pong round start time
  int messages_issued_;         // Messages issued by this stream
};

class CallbackStreamingPingPongClientImpl final
    : public CallbackStreamingPingPongClient {
 public:
  CallbackStreamingPingPongClientImpl(const ClientConfig& config)
      : CallbackStreamingPingPongClient(config) {
    for (size_t i = 0; i < total_outstanding_rpcs_; i++)
      reactor_.emplace_back(
          new CallbackStreamingPingPongReactor(this, std::move(ctx_[i])));
  }
  ~CallbackStreamingPingPongClientImpl() {}

  bool ThreadFuncImpl(Client::Thread* t, size_t thread_idx) override {
    for (size_t vector_idx = thread_idx; vector_idx < total_outstanding_rpcs_;
         vector_idx += num_threads_) {
      reactor_[vector_idx]->set_thread_ptr(t);
      reactor_[vector_idx]->ScheduleRpc();
    }
    return true;
  }

  void InitThreadFuncImpl(size_t thread_idx) override {}

 private:
  std::vector<std::unique_ptr<CallbackStreamingPingPongReactor>> reactor_;
};

// TODO(mhaidry) : Implement Streaming from client, server and both ways

std::unique_ptr<Client> CreateCallbackClient(const ClientConfig& config) {
  switch (config.rpc_type()) {
    case UNARY:
      return std::unique_ptr<Client>(new CallbackUnaryClient(config));
    case STREAMING:
      return std::unique_ptr<Client>(
          new CallbackStreamingPingPongClientImpl(config));
    case STREAMING_FROM_CLIENT:
    case STREAMING_FROM_SERVER:
    case STREAMING_BOTH_WAYS:
      assert(false);
      return nullptr;
    default:
      assert(false);
      return nullptr;
  }
}

}  // namespace testing
}  // namespace grpc
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/meta/container.hpp>
#include <entt/meta/context.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/pointer.hpp>
#include <entt/meta/template.hpp>

struct base {};

struct clazz: base {
    clazz() = default;

    clazz(int)
        : clazz{} {}

    clazz(char, int)
        : clazz{} {}

    int func(int v) {
        return (value = v);
    }

    int cfunc(int v) const {
        return v;
    }

    static void move_to_bucket(const clazz &instance) {
        bucket = instance.value;
    }

    int value{};
    static inline int bucket{};
};

struct local_only {};

struct argument {
    argument(int val)
        : value{val} {}

    int get() const {
        return value;
    }

    int get_mul() const {
        return value * 2;
    }

private:
    int value{};
};

template<typename...>
struct template_clazz {};

class MetaContext: public ::testing::Test {
    void init_global_context() {
        using namespace entt::literals;

        entt::meta<int>()
            .data<global_marker>("marker"_hs);

        entt::meta<argument>()
            .conv<&argument::get>();

        entt::meta<clazz>()
            .type("foo"_hs)
            .prop("prop"_hs, prop_value)
            .ctor<int>()
            .data<&clazz::value>("value"_hs)
            .data<&clazz::value>("rw"_hs)
            .func<&clazz::func>("func"_hs);

        entt::meta<template_clazz<int>>()
            .type("template"_hs);
    }

    void init_local_context() {
        using namespace entt::literals;

        entt::meta<int>(context)
            .data<local_marker>("marker"_hs);

        entt::meta<local_only>(context)
            .type("quux"_hs);

        entt::meta<argument>(context)
            .conv<&argument::get_mul>();

        entt::meta<clazz>(context)
            .type("bar"_hs)
            .prop("prop"_hs, prop_value)
            .base<base>()
            .ctor<char, int>()
            .dtor<&clazz::move_to_bucket>()
            .data<nullptr, &clazz::value>("value"_hs)
            .data<&clazz::value>("rw"_hs)
            .func<&clazz::cfunc>("func"_hs);

        entt::meta<template_clazz<int, char>>(context)
            .type("template"_hs);
    }

public:
    void SetUp() override {
        init_global_context();
        init_local_context();

        clazz::bucket = bucket_value;
    }

    void TearDown() override {
        entt::meta_reset(context);
        entt::meta_reset();
    }

protected:
    static constexpr int global_marker = 1;
    static constexpr int local_marker = 42;
    static constexpr int bucket_value = 99;
    static constexpr int prop_value = 3;
    entt::meta_ctx context{};
};

TEST_F(MetaContext, Resolve) {
    using namespace entt::literals;

    ASSERT_TRUE(entt::resolve<clazz>());
    ASSERT_TRUE(entt::resolve<clazz>(context));

    ASSERT_TRUE(entt::resolve<local_only>());
    ASSERT_TRUE(entt::resolve<local_only>(context));

    ASSERT_TRUE(entt::resolve(entt::type_id<clazz>()));
    ASSERT_TRUE(entt::resolve(context, entt::type_id<clazz>()));

    ASSERT_FALSE(entt::resolve(entt::type_id<local_only>()));
    ASSERT_TRUE(entt::resolve(context, entt::type_id<local_only>()));

    ASSERT_TRUE(entt::resolve("foo"_hs));
    ASSERT_FALSE(entt::resolve(context, "foo"_hs));

    ASSERT_FALSE(entt::resolve("bar"_hs));
    ASSERT_TRUE(entt::resolve(context, "bar"_hs));

    ASSERT_FALSE(entt::resolve("quux"_hs));
    ASSERT_TRUE(entt::resolve(context, "quux"_hs));

    ASSERT_EQ((std::distance(entt::resolve().cbegin(), entt::resolve().cend())), 4);
    ASSERT_EQ((std::distance(entt::resolve(context).cbegin(), entt::resolve(context).cend())), 5);
}

TEST_F(MetaContext, MetaType) {
    using namespace entt::literals;

    const auto global = entt::resolve<clazz>();
    const auto local = entt::resolve<clazz>(context);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_NE(global, local);

    ASSERT_EQ(global, entt::resolve("foo"_hs));
    ASSERT_EQ(local, entt::resolve(context, "bar"_hs));

    ASSERT_EQ(global.id(), "foo"_hs);
    ASSERT_EQ(local.id(), "bar"_hs);
}

TEST_F(MetaContext, MetaBase) {
    const auto global = entt::resolve<clazz>();
    const auto local = entt::resolve<clazz>(context);

    ASSERT_EQ((std::distance(global.base().cbegin(), global.base().cend())), 0);
    ASSERT_EQ((std::distance(local.base().cbegin(), local.base().cend())), 1);

    ASSERT_EQ(local.base().cbegin()->second.info(), entt::type_id<base>());

    ASSERT_FALSE(entt::resolve(entt::type_id<base>()));
    ASSERT_FALSE(entt::resolve(context, entt::type_id<base>()));
}

TEST_F(MetaContext, MetaData) {
    using namespace entt::literals;

    const auto global = entt::resolve<clazz>().data("value"_hs);
    const auto local = entt::resolve<clazz>(context).data("value"_hs);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_FALSE(global.is_const());
    ASSERT_TRUE(local.is_const());

    ASSERT_EQ(global.type().data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.type().data("marker"_hs).get({}).cast<int>(), local_marker);

    const auto grw = entt::resolve<clazz>().data("rw"_hs);
    const auto lrw = entt::resolve<clazz>(context).data("rw"_hs);

    ASSERT_EQ(grw.arg(0u).data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(lrw.arg(0u).data("marker"_hs).get({}).cast<int>(), local_marker);

    clazz instance{};
    const argument value{2};

    grw.set(instance, value);

    ASSERT_EQ(instance.value, value.get());

    lrw.set(entt::meta_handle{context, instance}, entt::meta_any{context, value});

    ASSERT_EQ(instance.value, value.get_mul());
}

TEST_F(MetaContext, MetaFunc) {
    using namespace entt::literals;

    const auto global = entt::resolve<clazz>().func("func"_hs);
    const auto local = entt::resolve<clazz>(context).func("func"_hs);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_FALSE(global.is_const());
    ASSERT_TRUE(local.is_const());

    ASSERT_EQ(global.arg(0u).data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.arg(0u).data("marker"_hs).get({}).cast<int>(), local_marker);

    ASSERT_EQ(global.ret().data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.ret().data("marker"_hs).get({}).cast<int>(), local_marker);

    clazz instance{};
    const argument value{2};

    ASSERT_NE(instance.value, value.get());
    ASSERT_EQ(global.invoke(instance, value).cast<int>(), value.get());
    ASSERT_EQ(instance.value, value.get());

    ASSERT_NE(instance.value, value.get_mul());
    ASSERT_EQ(local.invoke(entt::meta_handle{context, instance}, entt::meta_any{context, value}).cast<int>(), value.get_mul());
    ASSERT_NE(instance.value, value.get_mul());
}

TEST_F(MetaContext, MetaCtor) {
    const auto global = entt::resolve<clazz>();
    const auto local = entt::resolve<clazz>(context);

    ASSERT_TRUE(global.construct());
    ASSERT_TRUE(local.construct());

    ASSERT_TRUE(global.construct(0));
    ASSERT_FALSE(local.construct(0));

    ASSERT_FALSE(global.construct('c', 0));
    ASSERT_TRUE(local.construct('c', 0));
}

TEST_F(MetaContext, MetaConv) {
    argument value{2};

    auto global = entt::forward_as_meta(value);
    auto local = entt::forward_as_meta(context, value);

    ASSERT_TRUE(global.allow_cast<int>());
    ASSERT_TRUE(local.allow_cast<int>());

    ASSERT_EQ(global.cast<int>(), value.get());
    ASSERT_EQ(local.cast<int>(), value.get_mul());
}

TEST_F(MetaContext, MetaDtor) {
    auto global = entt::resolve<clazz>().construct();
    auto local = entt::resolve<clazz>(context).construct();

    ASSERT_EQ(clazz::bucket, bucket_value);

    global.reset();

    ASSERT_EQ(clazz::bucket, bucket_value);

    local.reset();

    ASSERT_NE(clazz::bucket, bucket_value);
}

TEST_F(MetaContext, MetaProp) {
    using namespace entt::literals;

    const auto global = entt::resolve<clazz>().prop("prop"_hs);
    const auto local = entt::resolve<clazz>(context).prop("prop"_hs);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_EQ(global.value().type(), entt::resolve<int>());
    ASSERT_EQ(local.value().type(), entt::resolve<int>(context));

    ASSERT_EQ(global.value().cast<int>(), prop_value);
    ASSERT_EQ(local.value().cast<int>(), prop_value);

    ASSERT_EQ(global.value().type().data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.value().type().data("marker"_hs).get({}).cast<int>(), local_marker);
}

TEST_F(MetaContext, MetaTemplate) {
    using namespace entt::literals;

    const auto global = entt::resolve("template"_hs);
    const auto local = entt::resolve(context, "template"_hs);

    ASSERT_TRUE(global.is_template_specialization());
    ASSERT_TRUE(local.is_template_specialization());

    ASSERT_EQ(global.template_arity(), 1u);
    ASSERT_EQ(local.template_arity(), 2u);

    ASSERT_EQ(global.template_arg(0u), entt::resolve<int>());
    ASSERT_EQ(local.template_arg(0u), entt::resolve<int>(context));
    ASSERT_EQ(local.template_arg(1u), entt::resolve<char>(context));

    ASSERT_EQ(global.template_arg(0u).data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.template_arg(0u).data("marker"_hs).get({}).cast<int>(), local_marker);
}

TEST_F(MetaContext, MetaPointer) {
    // TODO
}

TEST_F(MetaContext, MetaAssociativeContainer) {
    // TODO
}

TEST_F(MetaContext, MetaSequenceContainer) {
    // TODO
}

TEST_F(MetaContext, MetaAny) {
    // TODO
}

TEST_F(MetaContext, MetaHandle) {
    // TODO
}

TEST_F(MetaContext, ForwardAsMeta) {
    using namespace entt::literals;

    const auto global = entt::forward_as_meta(42);
    const auto local = entt::forward_as_meta(context, 42);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_EQ(global.type().data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.type().data("marker"_hs).get({}).cast<int>(), local_marker);
}

TEST_F(MetaContext, ContextMix) {
    // TODO
}
<commit_msg>test: context aware meta pointers (dereferencing picks the type from the right context)<commit_after>#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/meta/container.hpp>
#include <entt/meta/context.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/pointer.hpp>
#include <entt/meta/template.hpp>

struct base {};

struct clazz: base {
    clazz() = default;

    clazz(int)
        : clazz{} {}

    clazz(char, int)
        : clazz{} {}

    int func(int v) {
        return (value = v);
    }

    int cfunc(int v) const {
        return v;
    }

    static void move_to_bucket(const clazz &instance) {
        bucket = instance.value;
    }

    int value{};
    static inline int bucket{};
};

struct local_only {};

struct argument {
    argument(int val)
        : value{val} {}

    int get() const {
        return value;
    }

    int get_mul() const {
        return value * 2;
    }

private:
    int value{};
};

template<typename...>
struct template_clazz {};

class MetaContext: public ::testing::Test {
    void init_global_context() {
        using namespace entt::literals;

        entt::meta<int>()
            .data<global_marker>("marker"_hs);

        entt::meta<argument>()
            .conv<&argument::get>();

        entt::meta<clazz>()
            .type("foo"_hs)
            .prop("prop"_hs, prop_value)
            .ctor<int>()
            .data<&clazz::value>("value"_hs)
            .data<&clazz::value>("rw"_hs)
            .func<&clazz::func>("func"_hs);

        entt::meta<template_clazz<int>>()
            .type("template"_hs);
    }

    void init_local_context() {
        using namespace entt::literals;

        entt::meta<int>(context)
            .data<local_marker>("marker"_hs);

        entt::meta<local_only>(context)
            .type("quux"_hs);

        entt::meta<argument>(context)
            .conv<&argument::get_mul>();

        entt::meta<clazz>(context)
            .type("bar"_hs)
            .prop("prop"_hs, prop_value)
            .base<base>()
            .ctor<char, int>()
            .dtor<&clazz::move_to_bucket>()
            .data<nullptr, &clazz::value>("value"_hs)
            .data<&clazz::value>("rw"_hs)
            .func<&clazz::cfunc>("func"_hs);

        entt::meta<template_clazz<int, char>>(context)
            .type("template"_hs);
    }

public:
    void SetUp() override {
        init_global_context();
        init_local_context();

        clazz::bucket = bucket_value;
    }

    void TearDown() override {
        entt::meta_reset(context);
        entt::meta_reset();
    }

protected:
    static constexpr int global_marker = 1;
    static constexpr int local_marker = 42;
    static constexpr int bucket_value = 99;
    static constexpr int prop_value = 3;
    entt::meta_ctx context{};
};

TEST_F(MetaContext, Resolve) {
    using namespace entt::literals;

    ASSERT_TRUE(entt::resolve<clazz>());
    ASSERT_TRUE(entt::resolve<clazz>(context));

    ASSERT_TRUE(entt::resolve<local_only>());
    ASSERT_TRUE(entt::resolve<local_only>(context));

    ASSERT_TRUE(entt::resolve(entt::type_id<clazz>()));
    ASSERT_TRUE(entt::resolve(context, entt::type_id<clazz>()));

    ASSERT_FALSE(entt::resolve(entt::type_id<local_only>()));
    ASSERT_TRUE(entt::resolve(context, entt::type_id<local_only>()));

    ASSERT_TRUE(entt::resolve("foo"_hs));
    ASSERT_FALSE(entt::resolve(context, "foo"_hs));

    ASSERT_FALSE(entt::resolve("bar"_hs));
    ASSERT_TRUE(entt::resolve(context, "bar"_hs));

    ASSERT_FALSE(entt::resolve("quux"_hs));
    ASSERT_TRUE(entt::resolve(context, "quux"_hs));

    ASSERT_EQ((std::distance(entt::resolve().cbegin(), entt::resolve().cend())), 4);
    ASSERT_EQ((std::distance(entt::resolve(context).cbegin(), entt::resolve(context).cend())), 5);
}

TEST_F(MetaContext, MetaType) {
    using namespace entt::literals;

    const auto global = entt::resolve<clazz>();
    const auto local = entt::resolve<clazz>(context);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_NE(global, local);

    ASSERT_EQ(global, entt::resolve("foo"_hs));
    ASSERT_EQ(local, entt::resolve(context, "bar"_hs));

    ASSERT_EQ(global.id(), "foo"_hs);
    ASSERT_EQ(local.id(), "bar"_hs);
}

TEST_F(MetaContext, MetaBase) {
    const auto global = entt::resolve<clazz>();
    const auto local = entt::resolve<clazz>(context);

    ASSERT_EQ((std::distance(global.base().cbegin(), global.base().cend())), 0);
    ASSERT_EQ((std::distance(local.base().cbegin(), local.base().cend())), 1);

    ASSERT_EQ(local.base().cbegin()->second.info(), entt::type_id<base>());

    ASSERT_FALSE(entt::resolve(entt::type_id<base>()));
    ASSERT_FALSE(entt::resolve(context, entt::type_id<base>()));
}

TEST_F(MetaContext, MetaData) {
    using namespace entt::literals;

    const auto global = entt::resolve<clazz>().data("value"_hs);
    const auto local = entt::resolve<clazz>(context).data("value"_hs);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_FALSE(global.is_const());
    ASSERT_TRUE(local.is_const());

    ASSERT_EQ(global.type().data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.type().data("marker"_hs).get({}).cast<int>(), local_marker);

    const auto grw = entt::resolve<clazz>().data("rw"_hs);
    const auto lrw = entt::resolve<clazz>(context).data("rw"_hs);

    ASSERT_EQ(grw.arg(0u).data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(lrw.arg(0u).data("marker"_hs).get({}).cast<int>(), local_marker);

    clazz instance{};
    const argument value{2};

    grw.set(instance, value);

    ASSERT_EQ(instance.value, value.get());

    lrw.set(entt::meta_handle{context, instance}, entt::meta_any{context, value});

    ASSERT_EQ(instance.value, value.get_mul());
}

TEST_F(MetaContext, MetaFunc) {
    using namespace entt::literals;

    const auto global = entt::resolve<clazz>().func("func"_hs);
    const auto local = entt::resolve<clazz>(context).func("func"_hs);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_FALSE(global.is_const());
    ASSERT_TRUE(local.is_const());

    ASSERT_EQ(global.arg(0u).data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.arg(0u).data("marker"_hs).get({}).cast<int>(), local_marker);

    ASSERT_EQ(global.ret().data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.ret().data("marker"_hs).get({}).cast<int>(), local_marker);

    clazz instance{};
    const argument value{2};

    ASSERT_NE(instance.value, value.get());
    ASSERT_EQ(global.invoke(instance, value).cast<int>(), value.get());
    ASSERT_EQ(instance.value, value.get());

    ASSERT_NE(instance.value, value.get_mul());
    ASSERT_EQ(local.invoke(entt::meta_handle{context, instance}, entt::meta_any{context, value}).cast<int>(), value.get_mul());
    ASSERT_NE(instance.value, value.get_mul());
}

TEST_F(MetaContext, MetaCtor) {
    const auto global = entt::resolve<clazz>();
    const auto local = entt::resolve<clazz>(context);

    ASSERT_TRUE(global.construct());
    ASSERT_TRUE(local.construct());

    ASSERT_TRUE(global.construct(0));
    ASSERT_FALSE(local.construct(0));

    ASSERT_FALSE(global.construct('c', 0));
    ASSERT_TRUE(local.construct('c', 0));
}

TEST_F(MetaContext, MetaConv) {
    argument value{2};

    auto global = entt::forward_as_meta(value);
    auto local = entt::forward_as_meta(context, value);

    ASSERT_TRUE(global.allow_cast<int>());
    ASSERT_TRUE(local.allow_cast<int>());

    ASSERT_EQ(global.cast<int>(), value.get());
    ASSERT_EQ(local.cast<int>(), value.get_mul());
}

TEST_F(MetaContext, MetaDtor) {
    auto global = entt::resolve<clazz>().construct();
    auto local = entt::resolve<clazz>(context).construct();

    ASSERT_EQ(clazz::bucket, bucket_value);

    global.reset();

    ASSERT_EQ(clazz::bucket, bucket_value);

    local.reset();

    ASSERT_NE(clazz::bucket, bucket_value);
}

TEST_F(MetaContext, MetaProp) {
    using namespace entt::literals;

    const auto global = entt::resolve<clazz>().prop("prop"_hs);
    const auto local = entt::resolve<clazz>(context).prop("prop"_hs);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_EQ(global.value().type(), entt::resolve<int>());
    ASSERT_EQ(local.value().type(), entt::resolve<int>(context));

    ASSERT_EQ(global.value().cast<int>(), prop_value);
    ASSERT_EQ(local.value().cast<int>(), prop_value);

    ASSERT_EQ(global.value().type().data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.value().type().data("marker"_hs).get({}).cast<int>(), local_marker);
}

TEST_F(MetaContext, MetaTemplate) {
    using namespace entt::literals;

    const auto global = entt::resolve("template"_hs);
    const auto local = entt::resolve(context, "template"_hs);

    ASSERT_TRUE(global.is_template_specialization());
    ASSERT_TRUE(local.is_template_specialization());

    ASSERT_EQ(global.template_arity(), 1u);
    ASSERT_EQ(local.template_arity(), 2u);

    ASSERT_EQ(global.template_arg(0u), entt::resolve<int>());
    ASSERT_EQ(local.template_arg(0u), entt::resolve<int>(context));
    ASSERT_EQ(local.template_arg(1u), entt::resolve<char>(context));

    ASSERT_EQ(global.template_arg(0u).data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.template_arg(0u).data("marker"_hs).get({}).cast<int>(), local_marker);
}

TEST_F(MetaContext, MetaPointer) {
    using namespace entt::literals;

    int value = 42;

    const entt::meta_any global{&value};
    const entt::meta_any local{context, &value};

    ASSERT_TRUE(global.type().is_pointer());
    ASSERT_TRUE(local.type().is_pointer());

    ASSERT_TRUE(global.type().is_pointer_like());
    ASSERT_TRUE(local.type().is_pointer_like());

    ASSERT_EQ((*global).type().data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ((*local).type().data("marker"_hs).get({}).cast<int>(), local_marker);
}

TEST_F(MetaContext, MetaAssociativeContainer) {
    // TODO
}

TEST_F(MetaContext, MetaSequenceContainer) {
    // TODO
}

TEST_F(MetaContext, MetaAny) {
    // TODO
}

TEST_F(MetaContext, MetaHandle) {
    // TODO
}

TEST_F(MetaContext, ForwardAsMeta) {
    using namespace entt::literals;

    const auto global = entt::forward_as_meta(42);
    const auto local = entt::forward_as_meta(context, 42);

    ASSERT_TRUE(global);
    ASSERT_TRUE(local);

    ASSERT_EQ(global.type().data("marker"_hs).get({}).cast<int>(), global_marker);
    ASSERT_EQ(local.type().data("marker"_hs).get({}).cast<int>(), local_marker);
}

TEST_F(MetaContext, ContextMix) {
    // TODO
}
<|endoftext|>


<commit_before>#include <cstdio> // for sprintf
#include <cstring> // for strcmp

#include <sampgdk.h>

#include "amxplugin.h"

typedef void (*logprintf_t)(const char *fmt, ...);
static logprintf_t logprintf;

PLUGIN_EXPORT bool PLUGIN_CALL OnGameModeInit() {
	SetGameModeText("Hello, World!");

	AddPlayerClass(0, 1958.3783f, 1343.1572f, 15.3746f, 269.1425f, 0, 0, 0, 0, 0, 0);

	logprintf("------------------------------------------\n");
	logprintf(" HelloWorld gamemode got loaded. \n");
	logprintf("------------------------------------------\n");

	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerConnect(int playerid) {
	SendClientMessage(playerid, 0xFFFFFFFF, "Welcome to the HelloWorld server!");
	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerRequestClass(int playerid, int classid) {
	SetPlayerPos(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	SetPlayerCameraPos(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	SetPlayerCameraLookAt(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerCommandText(int playerid, const char *cmdtext) {
	if (std::strcmp(cmdtext, "/hello") == 0) {
		char name[MAX_PLAYER_NAME];
		GetPlayerName(playerid, name);
		char message[128];
		std::sprintf(message, "Hello, %s!", name);
		SendClientMessage(playerid, 0x00FF00FF, message);
	}
	return true;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppPluginData) {
	logprintf = (logprintf_t)ppPluginData[PLUGIN_DATA_LOGPRINTF];

	SampGdkInit(ppPluginData);
	SampGdkRegisterPlugin(SampGdkGetPluginHandle((void*)Load));

	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	return;
}
<commit_msg>Fix spacing<commit_after>#include <cstdio> // for sprintf
#include <cstring> // for strcmp

#include <sampgdk.h>

#include "amxplugin.h"

typedef void (*logprintf_t)(const char *fmt, ...);
static logprintf_t logprintf;

PLUGIN_EXPORT bool PLUGIN_CALL OnGameModeInit() {
	SetGameModeText("Hello, World!");

	AddPlayerClass(0, 1958.3783f, 1343.1572f, 15.3746f, 269.1425f, 0, 0, 0, 0, 0, 0);

	logprintf("------------------------------------------\n");
	logprintf("      HelloWorld gamemode got loaded.     \n");
	logprintf("------------------------------------------\n");

	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerConnect(int playerid) {
	SendClientMessage(playerid, 0xFFFFFFFF, "Welcome to the HelloWorld server!");
	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerRequestClass(int playerid, int classid) {
	SetPlayerPos(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	SetPlayerCameraPos(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	SetPlayerCameraLookAt(playerid, 1958.3783f, 1343.1572f, 15.3746f);
	return true;
}

PLUGIN_EXPORT bool PLUGIN_CALL OnPlayerCommandText(int playerid, const char *cmdtext) {
	if (std::strcmp(cmdtext, "/hello") == 0) {
		char name[MAX_PLAYER_NAME];
		GetPlayerName(playerid, name);
		char message[128];
		std::sprintf(message, "Hello, %s!", name);
		SendClientMessage(playerid, 0x00FF00FF, message);
	}
	return true;
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
	return SUPPORTS_VERSION;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppPluginData) {
	logprintf = (logprintf_t)ppPluginData[PLUGIN_DATA_LOGPRINTF];

	SampGdkInit(ppPluginData);
	SampGdkRegisterPlugin(SampGdkGetPluginHandle((void*)Load));

	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
	return;
}
<|endoftext|>


<commit_before>/* Rapicorn
 * Copyright (C) 2005 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include "slider.hh"
#include "tableimpl.hh"
#include "painter.hh"
#include "factory.hh"
#include "root.hh"

namespace Rapicorn {

SliderArea::SliderArea() :
  sig_slider_changed (*this, &SliderArea::slider_changed)
{}

void
SliderArea::slider_changed()
{}

bool
SliderArea::move (int distance)
{
  Adjustment *adj = adjustment();
  double pi = adj->page_increment();
  double si = adj->step_increment();
  if (flipped())
    {
      pi = -pi;
      si = -si;
    }
  switch (adj ? distance : 0)
    {
    case +2:
      adj->value (adj->value() + pi);
      return true;
    case +1:
      adj->value (adj->value() + si);
      return true;
    case -1:
      adj->value (adj->value() - si);
      return true;
    case -2:
      adj->value (adj->value() - pi);
      return true;
    default:
      return false;
    }
}

const CommandList&
SliderArea::list_commands ()
{
  static Command *commands[] = {
    MakeNamedCommand (SliderArea, "increment", _("Increment slider"), move, +1),
    MakeNamedCommand (SliderArea, "decrement", _("Decrement slider"), move, -1),
    MakeNamedCommand (SliderArea, "page-increment", _("Large slider increment"), move, +2),
    MakeNamedCommand (SliderArea, "page-decrement", _("Large slider decrement"), move, -2),
  };
  static const CommandList command_list (commands, Container::list_commands());
  return command_list;
}

const PropertyList&
SliderArea::list_properties()
{
  static Property *properties[] = {
    MakeProperty (SliderArea, flipped,           _("Flipped"),           _("Invert (flip) display of the adjustment value"), "rw"),
    MakeProperty (SliderArea, adjustment_source, _("Adjustment Source"), _("Type of source to retrive an adjustment from"), "rw"),
  };
  static const PropertyList property_list (properties, Container::list_properties());
  return property_list;
}

class SliderAreaImpl : public virtual SliderArea, public virtual TableImpl {
  Adjustment          *m_adjustment;
  AdjustmentSourceType m_adjustment_source;
  bool                 m_flip;
  void
  unset_adjustment()
  {
    m_adjustment->sig_value_changed -= slot (sig_slider_changed);
    m_adjustment->sig_range_changed -= slot (sig_slider_changed);
    m_adjustment->unref();
    m_adjustment = NULL;
  }
  virtual const PropertyList& list_properties() { return SliderArea::list_properties(); }
protected:
  virtual AdjustmentSourceType
  adjustment_source () const
  {
    return m_adjustment_source;
  }
  virtual void
  adjustment_source (AdjustmentSourceType adj_source)
  {
    m_adjustment_source = adj_source;
  }
  virtual void
  hierarchy_changed (Item *old_toplevel)
  {
    this->TableImpl::hierarchy_changed (old_toplevel);
    if (anchored() && m_adjustment_source != ADJUSTMENT_SOURCE_NONE)
      {
        Adjustment *adj = NULL;
        find_adjustments (m_adjustment_source, &adj);
        if (!adj)
          {
            EnumTypeAdjustmentSourceType ast;
            throw Exception ("SliderArea failed to get Adjustment (",
                             ast.string (m_adjustment_source),
                             ") from ancestors: ", name());
          }
        adjustment (*adj);
      }
  }
  virtual bool
  flipped () const
  {
    return m_flip;
  }
  virtual void
  flipped (bool flip)
  {
    if (m_flip != flip)
      {
        m_flip = flip;
        changed();
      }
  }
  virtual ~SliderAreaImpl()
  {
    unset_adjustment();
  }
public:
  SliderAreaImpl() :
    m_adjustment (NULL),
    m_adjustment_source (ADJUSTMENT_SOURCE_NONE),
    m_flip (false)
  {
    Adjustment *adj = Adjustment::create();
    adjustment (*adj);
    adj->unref();
  }
  virtual void
  adjustment (Adjustment &adjustment)
  {
    adjustment.ref();
    if (m_adjustment)
      unset_adjustment();
    m_adjustment = &adjustment;
    m_adjustment->sig_value_changed += slot (sig_slider_changed);
    m_adjustment->sig_range_changed += slot (sig_slider_changed);
    changed();
  }
  virtual Adjustment*
  adjustment () const
  {
    return m_adjustment;
  }
  virtual void
  control (const String &command_name,
           const String &arg)
  {
  }
};
static const ItemFactory<SliderAreaImpl> slider_area_factory ("Rapicorn::Factory::SliderArea");

class SliderSkidImpl;

class SliderTroughImpl : public virtual EventHandler, public virtual SingleContainerImpl {
  bool
  flipped()
  {
    SliderArea *slider_area = parent_interface<SliderArea*>();
    return slider_area ? slider_area->flipped() : false;
  }
public:
  SliderTroughImpl()
  {}
  ~SliderTroughImpl()
  {}
protected:
  virtual void
  hierarchy_changed (Item *old_toplevel)
  {
    SliderArea *slider_area = parent_interface<SliderArea*>();
    if (slider_area)
      slider_area->sig_slider_changed -= slot (*this, &SliderTroughImpl::reallocate_child);
    this->SingleContainerImpl::hierarchy_changed (old_toplevel);
    if (anchored())
      {
        if (!slider_area)
          throw Exception ("SliderTrough without SliderArea ancestor: ", name());
        slider_area->sig_slider_changed += slot (*this, &SliderTroughImpl::reallocate_child);
      }
  }
  Adjustment*
  adjustment () const
  {
    SliderArea *slider_area = parent_interface<SliderArea*>();
    return slider_area ? slider_area->adjustment() : NULL;
  }
  double
  nvalue()
  {
    Adjustment &adj = *adjustment();
    return flipped() ? adj.flipped_nvalue() : adj.nvalue();
  }
  void
  size_request (Requisition &requisition)
  {
    if (has_allocatable_child())
      {
        Item &child = get_child();
        requisition = child.size_request ();
        /* we confine spreading to within the trough, so don't propagate hspread/vspread here */
      }
  }
  virtual void
  size_allocate (Allocation area)
  {
    allocation (area);
    reallocate_child();
  }
  void
  reallocate_child ()
  {
    Allocation area = allocation();
    if (!has_allocatable_child())
      return;
    Item &child = get_child();
    Requisition rq = child.size_request();
    /* expand/scale child */
    if (area.width > rq.width && !child.hspread())
      {
        if (child.hexpand())
          {
            Adjustment &adj = *adjustment();
            double cwidth = round (adj.abs_length() * area.width);
            rq.width = MAX (cwidth, rq.width);
          }
        area.x += round (nvalue() * (area.width - rq.width));
        area.width = round (rq.width);
      }
    if (area.height > rq.height && !child.vspread())
      {
        if (child.vexpand())
          {
            Adjustment &adj = *adjustment();
            double cheight = round (adj.abs_length() * area.height);
            rq.height = MAX (cheight, rq.height);
          }
        area.y += round ((1.0 - nvalue()) * (area.height - rq.height));
        area.height = round (rq.height);
      }
    child.set_allocation (area);
  }
  friend class SliderSkidImpl;
  virtual void
  reset (ResetMode mode = RESET_ALL)
  {}
  virtual bool
  handle_event (const Event &event)
  {
    bool handled = false;
    switch (event.type)
      {
      case BUTTON_PRESS:
      case BUTTON_2PRESS:
      case BUTTON_3PRESS:
      case BUTTON_RELEASE:
      case BUTTON_2RELEASE:
      case BUTTON_3RELEASE:
      case BUTTON_CANCELED:
        /* forward button events to allow slider warps */
        if (has_visible_child())
          handled = get_child().process_event (event);
        break;
      case SCROLL_UP:
      case SCROLL_RIGHT:
        exec_command ("increment");
        break;
      case SCROLL_DOWN:
      case SCROLL_LEFT:
        exec_command ("decrement");
        break;
      default: break;
      }
    return handled;
  }
};
static const ItemFactory<SliderTroughImpl> slider_trough_factory ("Rapicorn::Factory::SliderTrough");

class SliderSkidImpl : public virtual EventHandler, public virtual SingleContainerImpl {
  uint        m_button;
  double      m_coffset;
  bool        m_vertical_skid;
  bool
  flipped()
  {
    SliderTroughImpl &trough = parent_interface<SliderTroughImpl>();
    return trough.flipped() ^ m_vertical_skid;
  }
  bool
  vertical_skid () const
  {
    return m_vertical_skid;
  }
  void
  vertical_skid (bool vs)
  {
    if (m_vertical_skid != vs)
      {
        m_vertical_skid = vs;
        changed();
      }
  }
public:
  SliderSkidImpl() :
    m_button (0),
    m_coffset (0),
    m_vertical_skid (false)
  {}
  ~SliderSkidImpl()
  {}
protected:
  virtual void
  size_request (Requisition &requisition)
  {
    bool chspread = false, cvspread = false;
    if (has_children())
      {
        Item &child = get_child();
        if (child.allocatable())
          {
            requisition = child.size_request ();
            chspread = child.hspread();
            cvspread = child.vspread();
          }
      }
    set_flag (HSPREAD_CONTAINER, chspread);
    set_flag (VSPREAD_CONTAINER, cvspread);
  }
#if 0
  double
  nvalue()
  {
    SliderTroughImpl &trough = parent_interface<SliderTroughImpl>();
    Adjustment &adj = *trough.adjustment();
    return flipped() ? adj.flipped_nvalue() : adj.nvalue();
  }
#endif
  virtual void
  reset (ResetMode mode = RESET_ALL)
  {
    m_button = 0;
    m_coffset = 0;
  }
  virtual bool
  handle_event (const Event &event)
  {
    bool handled = false, proper_release = false;
    SliderTroughImpl &trough = parent_interface<SliderTroughImpl>();
    Adjustment &adj = *trough.adjustment();
    switch (event.type)
      {
        const EventButton *bevent;
      case MOUSE_ENTER:
        this->prelight (true);
        break;
      case MOUSE_LEAVE:
        this->prelight (false);
        break;
      case BUTTON_PRESS:
      case BUTTON_2PRESS:
      case BUTTON_3PRESS:
        bevent = dynamic_cast<const EventButton*> (&event);
        if (!m_button and (bevent->button == 1 or bevent->button == 2))
          {
            m_button = bevent->button;
            get_root()->add_grab (this, true);
            handled = true;
            m_coffset = 0;
            double ep = vertical_skid() ? event.y : event.x;
            double cp = vertical_skid() ? ep - allocation().y : ep - allocation().x;
            double clength = vertical_skid() ? allocation().height : allocation().width;
            if (cp >= 0 && cp < clength)
              m_coffset = cp / clength;
            else
              {
                m_coffset = 0.5;
                /* confine offset to not slip the skip off trough boundaries */
                cp = ep - clength * m_coffset;
                const Allocation &ta = trough.allocation();
                double start_slip = (vertical_skid() ? ta.y : ta.x) - cp;
                double tlength = vertical_skid() ? ta.y + ta.height : ta.x + ta.width;
                double end_slip = cp + clength - tlength;
                /* adjust skid position */
                cp += MAX (0, start_slip);
                cp -= MAX (0, end_slip);
                /* recalculate offset */
                m_coffset = (ep - cp) / clength;
              }
          }
        break;
      case MOUSE_MOVE:
        if (m_button)
          {
            double ep = vertical_skid() ? event.y : event.x;
            const Allocation &ta = trough.allocation();
            double tp = vertical_skid() ? ta.y : ta.x;
            double pos = ep - tp;
            double tlength = vertical_skid() ? ta.height : ta.width;
            double clength = vertical_skid() ? allocation().height : allocation().width;
            tlength -= clength;
            pos -= m_coffset * clength;
            if (tlength > 0)
              pos /= tlength;
            pos = CLAMP (pos, 0, 1);
            if (flipped())
              adj.flipped_nvalue (pos);
            else
              adj.nvalue (pos);
          }
        break;
      case BUTTON_RELEASE:
      case BUTTON_2RELEASE:
      case BUTTON_3RELEASE:
        proper_release = true;
      case BUTTON_CANCELED:
        bevent = dynamic_cast<const EventButton*> (&event);
        if (m_button == bevent->button)
          {
            get_root()->remove_grab (this);
            m_button = 0;
            m_coffset = 0;
            handled = true;
          }
        break;
      default: break;
      }
    return handled;
  }
private:
  virtual const PropertyList&
  list_properties() // escape check-list_properties ';'
  {
    static Property *properties[] = {
      MakeProperty (SliderSkidImpl, vertical_skid, _("Vertical Skid"), _("Adjust behaviour to vertical skid movement"), "rw"),
    };
    static const PropertyList property_list (properties, SingleContainerImpl::list_properties());
    return property_list;
  }
};
static const ItemFactory<SliderSkidImpl> slider_skid_factory ("Rapicorn::Factory::SliderSkid");

} // Rapicorn
<commit_msg>slider.cc: fixed scroll wheel handling to decrement for left/up, otherwise increment<commit_after>/* Rapicorn
 * Copyright (C) 2005 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#include "slider.hh"
#include "tableimpl.hh"
#include "painter.hh"
#include "factory.hh"
#include "root.hh"

namespace Rapicorn {

SliderArea::SliderArea() :
  sig_slider_changed (*this, &SliderArea::slider_changed)
{}

void
SliderArea::slider_changed()
{}

bool
SliderArea::move (int distance)
{
  Adjustment *adj = adjustment();
  double pi = adj->page_increment();
  double si = adj->step_increment();
  if (flipped())
    {
      pi = -pi;
      si = -si;
    }
  switch (adj ? distance : 0)
    {
    case +2:
      adj->value (adj->value() + pi);
      return true;
    case +1:
      adj->value (adj->value() + si);
      return true;
    case -1:
      adj->value (adj->value() - si);
      return true;
    case -2:
      adj->value (adj->value() - pi);
      return true;
    default:
      return false;
    }
}

const CommandList&
SliderArea::list_commands ()
{
  static Command *commands[] = {
    MakeNamedCommand (SliderArea, "increment", _("Increment slider"), move, +1),
    MakeNamedCommand (SliderArea, "decrement", _("Decrement slider"), move, -1),
    MakeNamedCommand (SliderArea, "page-increment", _("Large slider increment"), move, +2),
    MakeNamedCommand (SliderArea, "page-decrement", _("Large slider decrement"), move, -2),
  };
  static const CommandList command_list (commands, Container::list_commands());
  return command_list;
}

const PropertyList&
SliderArea::list_properties()
{
  static Property *properties[] = {
    MakeProperty (SliderArea, flipped,           _("Flipped"),           _("Invert (flip) display of the adjustment value"), "rw"),
    MakeProperty (SliderArea, adjustment_source, _("Adjustment Source"), _("Type of source to retrive an adjustment from"), "rw"),
  };
  static const PropertyList property_list (properties, Container::list_properties());
  return property_list;
}

class SliderAreaImpl : public virtual SliderArea, public virtual TableImpl {
  Adjustment          *m_adjustment;
  AdjustmentSourceType m_adjustment_source;
  bool                 m_flip;
  void
  unset_adjustment()
  {
    m_adjustment->sig_value_changed -= slot (sig_slider_changed);
    m_adjustment->sig_range_changed -= slot (sig_slider_changed);
    m_adjustment->unref();
    m_adjustment = NULL;
  }
  virtual const PropertyList& list_properties() { return SliderArea::list_properties(); }
protected:
  virtual AdjustmentSourceType
  adjustment_source () const
  {
    return m_adjustment_source;
  }
  virtual void
  adjustment_source (AdjustmentSourceType adj_source)
  {
    m_adjustment_source = adj_source;
  }
  virtual void
  hierarchy_changed (Item *old_toplevel)
  {
    this->TableImpl::hierarchy_changed (old_toplevel);
    if (anchored() && m_adjustment_source != ADJUSTMENT_SOURCE_NONE)
      {
        Adjustment *adj = NULL;
        find_adjustments (m_adjustment_source, &adj);
        if (!adj)
          {
            EnumTypeAdjustmentSourceType ast;
            throw Exception ("SliderArea failed to get Adjustment (",
                             ast.string (m_adjustment_source),
                             ") from ancestors: ", name());
          }
        adjustment (*adj);
      }
  }
  virtual bool
  flipped () const
  {
    return m_flip;
  }
  virtual void
  flipped (bool flip)
  {
    if (m_flip != flip)
      {
        m_flip = flip;
        changed();
      }
  }
  virtual ~SliderAreaImpl()
  {
    unset_adjustment();
  }
public:
  SliderAreaImpl() :
    m_adjustment (NULL),
    m_adjustment_source (ADJUSTMENT_SOURCE_NONE),
    m_flip (false)
  {
    Adjustment *adj = Adjustment::create();
    adjustment (*adj);
    adj->unref();
  }
  virtual void
  adjustment (Adjustment &adjustment)
  {
    adjustment.ref();
    if (m_adjustment)
      unset_adjustment();
    m_adjustment = &adjustment;
    m_adjustment->sig_value_changed += slot (sig_slider_changed);
    m_adjustment->sig_range_changed += slot (sig_slider_changed);
    changed();
  }
  virtual Adjustment*
  adjustment () const
  {
    return m_adjustment;
  }
  virtual void
  control (const String &command_name,
           const String &arg)
  {
  }
};
static const ItemFactory<SliderAreaImpl> slider_area_factory ("Rapicorn::Factory::SliderArea");

class SliderSkidImpl;

class SliderTroughImpl : public virtual EventHandler, public virtual SingleContainerImpl {
  bool
  flipped()
  {
    SliderArea *slider_area = parent_interface<SliderArea*>();
    return slider_area ? slider_area->flipped() : false;
  }
public:
  SliderTroughImpl()
  {}
  ~SliderTroughImpl()
  {}
protected:
  virtual void
  hierarchy_changed (Item *old_toplevel)
  {
    SliderArea *slider_area = parent_interface<SliderArea*>();
    if (slider_area)
      slider_area->sig_slider_changed -= slot (*this, &SliderTroughImpl::reallocate_child);
    this->SingleContainerImpl::hierarchy_changed (old_toplevel);
    if (anchored())
      {
        if (!slider_area)
          throw Exception ("SliderTrough without SliderArea ancestor: ", name());
        slider_area->sig_slider_changed += slot (*this, &SliderTroughImpl::reallocate_child);
      }
  }
  Adjustment*
  adjustment () const
  {
    SliderArea *slider_area = parent_interface<SliderArea*>();
    return slider_area ? slider_area->adjustment() : NULL;
  }
  double
  nvalue()
  {
    Adjustment &adj = *adjustment();
    return flipped() ? adj.flipped_nvalue() : adj.nvalue();
  }
  void
  size_request (Requisition &requisition)
  {
    if (has_allocatable_child())
      {
        Item &child = get_child();
        requisition = child.size_request ();
        /* we confine spreading to within the trough, so don't propagate hspread/vspread here */
      }
  }
  virtual void
  size_allocate (Allocation area)
  {
    allocation (area);
    reallocate_child();
  }
  void
  reallocate_child ()
  {
    Allocation area = allocation();
    if (!has_allocatable_child())
      return;
    Item &child = get_child();
    Requisition rq = child.size_request();
    /* expand/scale child */
    if (area.width > rq.width && !child.hspread())
      {
        if (child.hexpand())
          {
            Adjustment &adj = *adjustment();
            double cwidth = round (adj.abs_length() * area.width);
            rq.width = MAX (cwidth, rq.width);
          }
        area.x += round (nvalue() * (area.width - rq.width));
        area.width = round (rq.width);
      }
    if (area.height > rq.height && !child.vspread())
      {
        if (child.vexpand())
          {
            Adjustment &adj = *adjustment();
            double cheight = round (adj.abs_length() * area.height);
            rq.height = MAX (cheight, rq.height);
          }
        area.y += round ((1.0 - nvalue()) * (area.height - rq.height));
        area.height = round (rq.height);
      }
    child.set_allocation (area);
  }
  friend class SliderSkidImpl;
  virtual void
  reset (ResetMode mode = RESET_ALL)
  {}
  virtual bool
  handle_event (const Event &event)
  {
    bool handled = false;
    switch (event.type)
      {
      case BUTTON_PRESS:
      case BUTTON_2PRESS:
      case BUTTON_3PRESS:
      case BUTTON_RELEASE:
      case BUTTON_2RELEASE:
      case BUTTON_3RELEASE:
      case BUTTON_CANCELED:
        /* forward button events to allow slider warps */
        if (has_visible_child())
          handled = get_child().process_event (event);
        break;
      case SCROLL_UP:
      case SCROLL_LEFT:
        exec_command ("decrement");
        break;
      case SCROLL_DOWN:
      case SCROLL_RIGHT:
        exec_command ("increment");
        break;
      default: break;
      }
    return handled;
  }
};
static const ItemFactory<SliderTroughImpl> slider_trough_factory ("Rapicorn::Factory::SliderTrough");

class SliderSkidImpl : public virtual EventHandler, public virtual SingleContainerImpl {
  uint        m_button;
  double      m_coffset;
  bool        m_vertical_skid;
  bool
  flipped()
  {
    SliderTroughImpl &trough = parent_interface<SliderTroughImpl>();
    return trough.flipped() ^ m_vertical_skid;
  }
  bool
  vertical_skid () const
  {
    return m_vertical_skid;
  }
  void
  vertical_skid (bool vs)
  {
    if (m_vertical_skid != vs)
      {
        m_vertical_skid = vs;
        changed();
      }
  }
public:
  SliderSkidImpl() :
    m_button (0),
    m_coffset (0),
    m_vertical_skid (false)
  {}
  ~SliderSkidImpl()
  {}
protected:
  virtual void
  size_request (Requisition &requisition)
  {
    bool chspread = false, cvspread = false;
    if (has_children())
      {
        Item &child = get_child();
        if (child.allocatable())
          {
            requisition = child.size_request ();
            chspread = child.hspread();
            cvspread = child.vspread();
          }
      }
    set_flag (HSPREAD_CONTAINER, chspread);
    set_flag (VSPREAD_CONTAINER, cvspread);
  }
#if 0
  double
  nvalue()
  {
    SliderTroughImpl &trough = parent_interface<SliderTroughImpl>();
    Adjustment &adj = *trough.adjustment();
    return flipped() ? adj.flipped_nvalue() : adj.nvalue();
  }
#endif
  virtual void
  reset (ResetMode mode = RESET_ALL)
  {
    m_button = 0;
    m_coffset = 0;
  }
  virtual bool
  handle_event (const Event &event)
  {
    bool handled = false, proper_release = false;
    SliderTroughImpl &trough = parent_interface<SliderTroughImpl>();
    Adjustment &adj = *trough.adjustment();
    switch (event.type)
      {
        const EventButton *bevent;
      case MOUSE_ENTER:
        this->prelight (true);
        break;
      case MOUSE_LEAVE:
        this->prelight (false);
        break;
      case BUTTON_PRESS:
      case BUTTON_2PRESS:
      case BUTTON_3PRESS:
        bevent = dynamic_cast<const EventButton*> (&event);
        if (!m_button and (bevent->button == 1 or bevent->button == 2))
          {
            m_button = bevent->button;
            get_root()->add_grab (this, true);
            handled = true;
            m_coffset = 0;
            double ep = vertical_skid() ? event.y : event.x;
            double cp = vertical_skid() ? ep - allocation().y : ep - allocation().x;
            double clength = vertical_skid() ? allocation().height : allocation().width;
            if (cp >= 0 && cp < clength)
              m_coffset = cp / clength;
            else
              {
                m_coffset = 0.5;
                /* confine offset to not slip the skip off trough boundaries */
                cp = ep - clength * m_coffset;
                const Allocation &ta = trough.allocation();
                double start_slip = (vertical_skid() ? ta.y : ta.x) - cp;
                double tlength = vertical_skid() ? ta.y + ta.height : ta.x + ta.width;
                double end_slip = cp + clength - tlength;
                /* adjust skid position */
                cp += MAX (0, start_slip);
                cp -= MAX (0, end_slip);
                /* recalculate offset */
                m_coffset = (ep - cp) / clength;
              }
          }
        break;
      case MOUSE_MOVE:
        if (m_button)
          {
            double ep = vertical_skid() ? event.y : event.x;
            const Allocation &ta = trough.allocation();
            double tp = vertical_skid() ? ta.y : ta.x;
            double pos = ep - tp;
            double tlength = vertical_skid() ? ta.height : ta.width;
            double clength = vertical_skid() ? allocation().height : allocation().width;
            tlength -= clength;
            pos -= m_coffset * clength;
            if (tlength > 0)
              pos /= tlength;
            pos = CLAMP (pos, 0, 1);
            if (flipped())
              adj.flipped_nvalue (pos);
            else
              adj.nvalue (pos);
          }
        break;
      case BUTTON_RELEASE:
      case BUTTON_2RELEASE:
      case BUTTON_3RELEASE:
        proper_release = true;
      case BUTTON_CANCELED:
        bevent = dynamic_cast<const EventButton*> (&event);
        if (m_button == bevent->button)
          {
            get_root()->remove_grab (this);
            m_button = 0;
            m_coffset = 0;
            handled = true;
          }
        break;
      default: break;
      }
    return handled;
  }
private:
  virtual const PropertyList&
  list_properties() // escape check-list_properties ';'
  {
    static Property *properties[] = {
      MakeProperty (SliderSkidImpl, vertical_skid, _("Vertical Skid"), _("Adjust behaviour to vertical skid movement"), "rw"),
    };
    static const PropertyList property_list (properties, SingleContainerImpl::list_properties());
    return property_list;
  }
};
static const ItemFactory<SliderSkidImpl> slider_skid_factory ("Rapicorn::Factory::SliderSkid");

} // Rapicorn
<|endoftext|>


<commit_before>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)
//  Based on original Protocol Buffers design by
//  Sanjay Ghemawat, Jeff Dean, and others.

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

// Modified to implement C code by Dave Benson.

#include <protoc-c/c_file.h>
#include <protoc-c/c_enum.h>
#include <protoc-c/c_service.h>
#include <protoc-c/c_extension.h>
#include <protoc-c/c_helpers.h>
#include <protoc-c/c_message.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>

#include "protobuf-c.h"

namespace google {
namespace protobuf {
namespace compiler {
namespace c {

// ===================================================================

FileGenerator::FileGenerator(const FileDescriptor* file,
                             const string& dllexport_decl)
  : file_(file),
    message_generators_(
      new scoped_ptr<MessageGenerator>[file->message_type_count()]),
    enum_generators_(
      new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
    service_generators_(
      new scoped_ptr<ServiceGenerator>[file->service_count()]),
    extension_generators_(
      new scoped_ptr<ExtensionGenerator>[file->extension_count()]) {

  for (int i = 0; i < file->message_type_count(); i++) {
    message_generators_[i].reset(
      new MessageGenerator(file->message_type(i), dllexport_decl));
  }

  for (int i = 0; i < file->enum_type_count(); i++) {
    enum_generators_[i].reset(
      new EnumGenerator(file->enum_type(i), dllexport_decl));
  }

  for (int i = 0; i < file->service_count(); i++) {
    service_generators_[i].reset(
      new ServiceGenerator(file->service(i), dllexport_decl));
  }

  for (int i = 0; i < file->extension_count(); i++) {
    extension_generators_[i].reset(
      new ExtensionGenerator(file->extension(i), dllexport_decl));
  }

  SplitStringUsing(file_->package(), ".", &package_parts_);
}

FileGenerator::~FileGenerator() {}

void FileGenerator::GenerateHeader(io::Printer* printer) {
  string filename_identifier = FilenameIdentifier(file_->name());

  static const int min_header_version = 1000000;

  // Generate top of header.
  printer->Print(
    "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n"
    "/* Generated from: $filename$ */\n"
    "\n"
    "#ifndef PROTOBUF_C_$filename_identifier$__INCLUDED\n"
    "#define PROTOBUF_C_$filename_identifier$__INCLUDED\n"
    "\n"
    "#include <protobuf-c/protobuf-c.h>\n"
    "\n"
    "PROTOBUF_C_BEGIN_DECLS\n"
    "\n",
    "filename", file_->name(),
    "filename_identifier", filename_identifier);

  // Verify the protobuf-c library header version is compatible with the
  // protoc-c version before going any further.
  printer->Print(
    "#if PROTOBUF_C_VERSION_NUMBER < $min_header_version$\n"
    "# error This file was generated by a newer version of protoc-c which is "
    "incompatible with your libprotobuf-c headers. Please update your headers.\n"
    "#elif $protoc_version$ < PROTOBUF_C_MIN_COMPILER_VERSION\n"
    "# error This file was generated by an older version of protoc-c which is "
    "incompatible with your libprotobuf-c headers. Please regenerate this file "
    "with a newer version of protoc-c.\n"
    "#endif\n"
    "\n",
    "min_header_version", SimpleItoa(min_header_version),
    "protoc_version", SimpleItoa(PROTOBUF_C_VERSION_NUMBER));

  for (int i = 0; i < file_->dependency_count(); i++) {
    printer->Print(
      "#include \"$dependency$.pb-c.h\"\n",
      "dependency", StripProto(file_->dependency(i)->name()));
  }

  printer->Print("\n");

  // Generate forward declarations of classes.
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateStructTypedef(printer);
  }

  printer->Print("\n");

  // Generate enum definitions.
  printer->Print("\n/* --- enums --- */\n\n");
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateEnumDefinitions(printer);
  }
  for (int i = 0; i < file_->enum_type_count(); i++) {
    enum_generators_[i]->GenerateDefinition(printer);
  }

  // Generate class definitions.
  printer->Print("\n/* --- messages --- */\n\n");
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateStructDefinition(printer);
  }

  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateHelperFunctionDeclarations(printer, false);
  }

  printer->Print("/* --- per-message closures --- */\n\n");
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateClosureTypedef(printer);
  }

  // Generate service definitions.
  printer->Print("\n/* --- services --- */\n\n");
  for (int i = 0; i < file_->service_count(); i++) {
    service_generators_[i]->GenerateMainHFile(printer);
  }

  // Declare extension identifiers.
  for (int i = 0; i < file_->extension_count(); i++) {
    extension_generators_[i]->GenerateDeclaration(printer);
  }

  printer->Print("\n/* --- descriptors --- */\n\n");
  for (int i = 0; i < file_->enum_type_count(); i++) {
    enum_generators_[i]->GenerateDescriptorDeclarations(printer);
  }
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateDescriptorDeclarations(printer);
  }
  for (int i = 0; i < file_->service_count(); i++) {
    service_generators_[i]->GenerateDescriptorDeclarations(printer);
  }

  printer->Print(
    "\n"
    "PROTOBUF_C_END_DECLS\n"
    "\n\n#endif  /* PROTOBUF_$filename_identifier$__INCLUDED */\n",
    "filename_identifier", filename_identifier);
}

void FileGenerator::GenerateSource(io::Printer* printer) {
  printer->Print(
    "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n"
    "/* Generated from: $filename$ */\n"
    "\n"
    "/* Do not generate deprecated warnings for self */\n"
    "#ifndef PROTOBUF_C_NO_DEPRECATED\n"
    "#define PROTOBUF_C_NO_DEPRECATED\n"
    "#endif\n"
    "\n"
    "#include \"$basename$.pb-c.h\"\n",
    "filename", file_->name(),
    "basename", StripProto(file_->name()));

#if 0
  // For each dependency, write a prototype for that dependency's
  // BuildDescriptors() function.  We don't expose these in the header because
  // they are internal implementation details, and since this is generated code
  // we don't have the usual risks involved with declaring external functions
  // within a .cc file.
  for (int i = 0; i < file_->dependency_count(); i++) {
    const FileDescriptor* dependency = file_->dependency(i);
    // Open the dependency's namespace.
    vector<string> dependency_package_parts;
    SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
    // Declare its BuildDescriptors() function.
    printer->Print(
      "void $function$();",
      "function", GlobalBuildDescriptorsName(dependency->name()));
    // Close the namespace.
    for (int i = 0; i < dependency_package_parts.size(); i++) {
      printer->Print(" }");
    }
    printer->Print("\n");
  }
#endif

  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateHelperFunctionDefinitions(printer, false);
  }
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateMessageDescriptor(printer);
  }
  for (int i = 0; i < file_->enum_type_count(); i++) {
    enum_generators_[i]->GenerateEnumDescriptor(printer);
  }
  for (int i = 0; i < file_->service_count(); i++) {
    service_generators_[i]->GenerateCFile(printer);
  }

}

}  // namespace c
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
<commit_msg>cosmetics<commit_after>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)
//  Based on original Protocol Buffers design by
//  Sanjay Ghemawat, Jeff Dean, and others.

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

// Modified to implement C code by Dave Benson.

#include <protoc-c/c_file.h>
#include <protoc-c/c_enum.h>
#include <protoc-c/c_service.h>
#include <protoc-c/c_extension.h>
#include <protoc-c/c_helpers.h>
#include <protoc-c/c_message.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/descriptor.pb.h>

#include "protobuf-c.h"

namespace google {
namespace protobuf {
namespace compiler {
namespace c {

// ===================================================================

FileGenerator::FileGenerator(const FileDescriptor* file,
                             const string& dllexport_decl)
  : file_(file),
    message_generators_(
      new scoped_ptr<MessageGenerator>[file->message_type_count()]),
    enum_generators_(
      new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
    service_generators_(
      new scoped_ptr<ServiceGenerator>[file->service_count()]),
    extension_generators_(
      new scoped_ptr<ExtensionGenerator>[file->extension_count()]) {

  for (int i = 0; i < file->message_type_count(); i++) {
    message_generators_[i].reset(
      new MessageGenerator(file->message_type(i), dllexport_decl));
  }

  for (int i = 0; i < file->enum_type_count(); i++) {
    enum_generators_[i].reset(
      new EnumGenerator(file->enum_type(i), dllexport_decl));
  }

  for (int i = 0; i < file->service_count(); i++) {
    service_generators_[i].reset(
      new ServiceGenerator(file->service(i), dllexport_decl));
  }

  for (int i = 0; i < file->extension_count(); i++) {
    extension_generators_[i].reset(
      new ExtensionGenerator(file->extension(i), dllexport_decl));
  }

  SplitStringUsing(file_->package(), ".", &package_parts_);
}

FileGenerator::~FileGenerator() {}

void FileGenerator::GenerateHeader(io::Printer* printer) {
  string filename_identifier = FilenameIdentifier(file_->name());

  static const int min_header_version = 1000000;

  // Generate top of header.
  printer->Print(
    "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n"
    "/* Generated from: $filename$ */\n"
    "\n"
    "#ifndef PROTOBUF_C_$filename_identifier$__INCLUDED\n"
    "#define PROTOBUF_C_$filename_identifier$__INCLUDED\n"
    "\n"
    "#include <protobuf-c/protobuf-c.h>\n"
    "\n"
    "PROTOBUF_C_BEGIN_DECLS\n"
    "\n",
    "filename", file_->name(),
    "filename_identifier", filename_identifier);

  // Verify the protobuf-c library header version is compatible with the
  // protoc-c version before going any further.
  printer->Print(
    "#if PROTOBUF_C_VERSION_NUMBER < $min_header_version$\n"
    "# error This file was generated by a newer version of protoc-c which is "
    "incompatible with your libprotobuf-c headers. Please update your headers.\n"
    "#elif $protoc_version$ < PROTOBUF_C_MIN_COMPILER_VERSION\n"
    "# error This file was generated by an older version of protoc-c which is "
    "incompatible with your libprotobuf-c headers. Please regenerate this file "
    "with a newer version of protoc-c.\n"
    "#endif\n"
    "\n",
    "min_header_version", SimpleItoa(min_header_version),
    "protoc_version", SimpleItoa(PROTOBUF_C_VERSION_NUMBER));

  for (int i = 0; i < file_->dependency_count(); i++) {
    printer->Print(
      "#include \"$dependency$.pb-c.h\"\n",
      "dependency", StripProto(file_->dependency(i)->name()));
  }

  printer->Print("\n");

  // Generate forward declarations of classes.
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateStructTypedef(printer);
  }

  printer->Print("\n");

  // Generate enum definitions.
  printer->Print("\n/* --- enums --- */\n\n");
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateEnumDefinitions(printer);
  }
  for (int i = 0; i < file_->enum_type_count(); i++) {
    enum_generators_[i]->GenerateDefinition(printer);
  }

  // Generate class definitions.
  printer->Print("\n/* --- messages --- */\n\n");
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateStructDefinition(printer);
  }

  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateHelperFunctionDeclarations(printer, false);
  }

  printer->Print("/* --- per-message closures --- */\n\n");
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateClosureTypedef(printer);
  }

  // Generate service definitions.
  printer->Print("\n/* --- services --- */\n\n");
  for (int i = 0; i < file_->service_count(); i++) {
    service_generators_[i]->GenerateMainHFile(printer);
  }

  // Declare extension identifiers.
  for (int i = 0; i < file_->extension_count(); i++) {
    extension_generators_[i]->GenerateDeclaration(printer);
  }

  printer->Print("\n/* --- descriptors --- */\n\n");
  for (int i = 0; i < file_->enum_type_count(); i++) {
    enum_generators_[i]->GenerateDescriptorDeclarations(printer);
  }
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateDescriptorDeclarations(printer);
  }
  for (int i = 0; i < file_->service_count(); i++) {
    service_generators_[i]->GenerateDescriptorDeclarations(printer);
  }

  printer->Print(
    "\n"
    "PROTOBUF_C_END_DECLS\n"
    "\n\n#endif  /* PROTOBUF_C_$filename_identifier$__INCLUDED */\n",
    "filename_identifier", filename_identifier);
}

void FileGenerator::GenerateSource(io::Printer* printer) {
  printer->Print(
    "/* Generated by the protocol buffer compiler.  DO NOT EDIT! */\n"
    "/* Generated from: $filename$ */\n"
    "\n"
    "/* Do not generate deprecated warnings for self */\n"
    "#ifndef PROTOBUF_C_NO_DEPRECATED\n"
    "#define PROTOBUF_C_NO_DEPRECATED\n"
    "#endif\n"
    "\n"
    "#include \"$basename$.pb-c.h\"\n",
    "filename", file_->name(),
    "basename", StripProto(file_->name()));

#if 0
  // For each dependency, write a prototype for that dependency's
  // BuildDescriptors() function.  We don't expose these in the header because
  // they are internal implementation details, and since this is generated code
  // we don't have the usual risks involved with declaring external functions
  // within a .cc file.
  for (int i = 0; i < file_->dependency_count(); i++) {
    const FileDescriptor* dependency = file_->dependency(i);
    // Open the dependency's namespace.
    vector<string> dependency_package_parts;
    SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
    // Declare its BuildDescriptors() function.
    printer->Print(
      "void $function$();",
      "function", GlobalBuildDescriptorsName(dependency->name()));
    // Close the namespace.
    for (int i = 0; i < dependency_package_parts.size(); i++) {
      printer->Print(" }");
    }
    printer->Print("\n");
  }
#endif

  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateHelperFunctionDefinitions(printer, false);
  }
  for (int i = 0; i < file_->message_type_count(); i++) {
    message_generators_[i]->GenerateMessageDescriptor(printer);
  }
  for (int i = 0; i < file_->enum_type_count(); i++) {
    enum_generators_[i]->GenerateEnumDescriptor(printer);
  }
  for (int i = 0; i < file_->service_count(); i++) {
    service_generators_[i]->GenerateCFile(printer);
  }

}

}  // namespace c
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
<|endoftext|>