<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * 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 <folly/ThreadLocal.h>
#include <folly/io/async/EventBase.h>
#include <folly/io/async/Request.h>
#include <folly/portability/GTest.h>
#include <thrift/lib/cpp/async/TAsyncSocket.h>
#include <thrift/lib/cpp2/async/AsyncProcessor.h>
#include <thrift/lib/cpp2/async/FutureRequest.h>
#include <thrift/lib/cpp2/async/HeaderClientChannel.h>
#include <thrift/lib/cpp2/async/RequestChannel.h>
#include <thrift/lib/cpp2/async/RocketClientChannel.h>
#include <thrift/lib/cpp2/server/Cpp2Worker.h>
#include <thrift/lib/cpp2/server/ServerInstrumentation.h>
#include <thrift/lib/cpp2/server/ThriftServer.h>
#include <thrift/lib/cpp2/test/gen-cpp2/DebugTestService.h>
#include <thrift/lib/cpp2/test/gen-cpp2/InstrumentationTestService.h>
#include <thrift/lib/cpp2/transport/rsocket/server/RSRoutingHandler.h>
#include <thrift/lib/cpp2/util/ScopedServerInterfaceThread.h>
#include <atomic>
#include <thread>

using namespace apache::thrift;
using namespace apache::thrift::concurrency;
using namespace apache::thrift::test;

class RequestPayload : public folly::RequestData {
 public:
  static const folly::RequestToken& getRequestToken() {
    static folly::RequestToken token("InstrumentationTest::RequestPayload");
    return token;
  }
  explicit RequestPayload(std::unique_ptr<folly::IOBuf> buf)
      : buf_(std::move(buf)) {}
  bool hasCallback() override {
    return false;
  }
  const folly::IOBuf* getPayload() {
    return buf_.get();
  }

 private:
  std::unique_ptr<folly::IOBuf> buf_;
};

class InstrumentationTestProcessor
    : public InstrumentationTestServiceAsyncProcessor {
 public:
  explicit InstrumentationTestProcessor(InstrumentationTestServiceSvIf* iface)
      : InstrumentationTestServiceAsyncProcessor(iface) {}

  /**
   * Intercepts and clones incoming payload buffers, then passes them down to
   * method handlers.
   */
  void process(
      std::unique_ptr<ResponseChannelRequest> req,
      std::unique_ptr<folly::IOBuf> buf,
      apache::thrift::protocol::PROTOCOL_TYPES protType,
      apache::thrift::Cpp2RequestContext* context,
      folly::EventBase* eb,
      apache::thrift::concurrency::ThreadManager* tm) override {
    folly::RequestContext::get()->setContextData(
        RequestPayload::getRequestToken(),
        std::make_unique<RequestPayload>(buf->clone()));
    InstrumentationTestServiceAsyncProcessor::process(
        std::move(req), std::move(buf), protType, context, eb, tm);
  }
};

class TestInterface : public InstrumentationTestServiceSvIf {
 public:
  auto requestGuard() {
    reqCount_++;
    return folly::makeGuard([&] { --reqCount_; });
  }

  folly::coro::Task<void> co_sendRequest() override {
    auto rg = requestGuard();
    auto ctx = folly::RequestContext::get();
    EXPECT_TRUE(
        ctx->setContextDataIfAbsent("TestInterface::co_sendRequest", nullptr));
    co_await finished_;
  }

  folly::coro::Task<apache::thrift::Stream<int32_t>> co_sendStreamingRequest()
      override {
    auto rg = requestGuard();
    co_await finished_;
    co_return createStreamGenerator(
        []() -> folly::coro::AsyncGenerator<int32_t> { co_yield 0; });
  }

  folly::coro::Task<apache::thrift::test::IOBuf> co_sendPayload(
      int32_t id,
      const std::string& /* str */) override {
    auto rg = requestGuard();
    auto payload = dynamic_cast<RequestPayload*>(
        folly::RequestContext::get()->getContextData(
            RequestPayload::getRequestToken()));
    EXPECT_NE(payload, nullptr);
    co_await finished_;
    co_return * payload->getPayload()->clone();
  }

  void stopRequests() {
    finished_.post();
    while (reqCount_ > 0) {
      std::this_thread::yield();
    }
  }

  void waitForRequests(int32_t num) {
    while (reqCount_ != num) {
      std::this_thread::yield();
    }
  }

  folly::coro::Task<void> co_wait(int value, bool busyWait, bool shallowRC)
      override {
    std::unique_ptr<folly::ShallowCopyRequestContextScopeGuard> g;
    if (shallowRC) {
      g = std::make_unique<folly::ShallowCopyRequestContextScopeGuard>();
    }
    auto rg = requestGuard();
    if (busyWait) {
      while (!finished_.ready()) {
        std::this_thread::yield();
      }
    }
    co_await finished_;
  }

  std::unique_ptr<apache::thrift::AsyncProcessor> getProcessor() override {
    return std::make_unique<InstrumentationTestProcessor>(this);
  }

 private:
  folly::coro::Baton finished_;
  std::atomic<int32_t> reqCount_{0};
};

class DebugInterface : public DebugTestServiceSvIf {
 public:
  void echo(std::string& r, const std::string& s) override {
    r = folly::format("{}:{}", s, folly::getCurrentThreadName().value()).str();
  }
};

class DebuggingFrameHandler : public rocket::SetupFrameHandler {
 public:
  explicit DebuggingFrameHandler(ThriftServer& server)
      : origServer_(server), reqRegistry_([] {
          auto p = new ActiveRequestsRegistry(0, 0);
          return new std::shared_ptr<ActiveRequestsRegistry>(p);
        }) {
    auto tf =
        std::make_shared<PosixThreadFactory>(PosixThreadFactory::ATTACHED);
    tm_ = std::make_shared<SimpleThreadManager<folly::LifoSem>>(1, false);
    tm_->setNamePrefix("DebugInterface");
    tm_->threadFactory(move(tf));
    tm_->start();
  }
  folly::Optional<rocket::ProcessorInfo> tryHandle(
      const RequestSetupMetadata& meta) override {
    if (meta.interfaceKind_ref().has_value() &&
        meta.interfaceKind_ref().value() == InterfaceKind::DEBUGGING) {
      auto info = rocket::ProcessorInfo{
          debug_.getProcessor(), tm_, origServer_, *reqRegistry_.get()};
      return folly::Optional<rocket::ProcessorInfo>(std::move(info));
    }
    return folly::Optional<rocket::ProcessorInfo>();
  }

 private:
  ThriftServer& origServer_;
  DebugInterface debug_;
  std::shared_ptr<ThreadManager> tm_;
  folly::ThreadLocal<std::shared_ptr<ActiveRequestsRegistry>> reqRegistry_;
};

class RequestInstrumentationTest : public testing::Test {
 protected:
  RequestInstrumentationTest()
      : handler_(std::make_shared<TestInterface>()),
        server_(handler_, "::1", 0),
        thriftServer_(dynamic_cast<ThriftServer*>(&server_.getThriftServer())) {
    EXPECT_NE(thriftServer_, nullptr);
  }

  std::vector<ThriftServer::RequestSnapshot> getRequestSnapshots(
      size_t reqNum) {
    SCOPE_EXIT {
      handler_->stopRequests();
    };
    handler_->waitForRequests(reqNum);

    auto serverReqSnapshots = thriftServer_->snapshotActiveRequests().get();

    EXPECT_EQ(serverReqSnapshots.size(), reqNum);
    return serverReqSnapshots;
  }

  std::vector<intptr_t> getRootIdsOnThreads() {
    std::vector<intptr_t> results;
    for (auto& root : folly::RequestContext::getRootIdsFromAllThreads()) {
      if (!root.second) {
        continue;
      }
      results.push_back(root.second);
    }
    return results;
  }

  std::shared_ptr<TestInterface> handler_;
  apache::thrift::ScopedServerInterfaceThread server_;
  ThriftServer* thriftServer_;
};

TEST_F(RequestInstrumentationTest, simpleRocketRequestTest) {
  size_t reqNum = 5;
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket));
      });

  for (size_t i = 0; i < reqNum; i++) {
    client->semifuture_sendStreamingRequest();
    client->semifuture_sendRequest();
  }
  handler_->waitForRequests(2 * reqNum);

  // we expect all requests to get off the thread, eventually
  int attempt = 0;
  while (attempt < 5 && getRootIdsOnThreads().size() > 0) {
    sleep(1);
    attempt++;
  }
  EXPECT_LT(attempt, 5);

  for (auto& reqSnapshot : getRequestSnapshots(2 * reqNum)) {
    auto methodName = reqSnapshot.getMethodName();
    EXPECT_NE(reqSnapshot.getRootRequestContextId(), 0);
    EXPECT_TRUE(
        methodName == "sendRequest" || methodName == "sendStreamingRequest");
  }
}

TEST_F(RequestInstrumentationTest, threadSnapshot) {
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket));
      });

  client->semifuture_sendRequest();
  client->semifuture_wait(0, true, false);

  handler_->waitForRequests(2);
  auto onThreadReqs = getRootIdsOnThreads();
  auto allReqs = getRequestSnapshots(2);
  EXPECT_EQ(1, onThreadReqs.size());
  EXPECT_EQ(2, allReqs.size());

  for (const auto& req : allReqs) {
    if (req.getMethodName() == "wait") {
      EXPECT_EQ(req.getRootRequestContextId(), onThreadReqs[0]);
    } else {
      EXPECT_NE(req.getRootRequestContextId(), onThreadReqs[0]);
    }
  }
}

TEST_F(RequestInstrumentationTest, threadSnapshotWithShallowRC) {
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket));
      });

  client->semifuture_sendRequest();
  handler_->waitForRequests(1);
  client->semifuture_wait(0, true, true);
  handler_->waitForRequests(2);

  auto onThreadReqs = getRootIdsOnThreads();
  auto allReqs = getRequestSnapshots(2);
  EXPECT_EQ(1, onThreadReqs.size());
  EXPECT_EQ(2, allReqs.size());

  for (const auto& req : allReqs) {
    if (req.getMethodName() == "wait") {
      EXPECT_EQ(req.getRootRequestContextId(), onThreadReqs.front());
    } else {
      EXPECT_NE(req.getRootRequestContextId(), onThreadReqs.front());
    }
  }
}

TEST_F(RequestInstrumentationTest, debugInterfaceTest) {
  size_t reqNum = 5;

  // inject our setup frame handler for rocket connections
  for (const auto& rh : *thriftServer_->getRoutingHandlers()) {
    auto rs = dynamic_cast<RSRoutingHandler*>(rh.get());
    if (rs != nullptr) {
      rs->addSetupFrameHandler(
          std::make_unique<DebuggingFrameHandler>(*thriftServer_));
      break;
    }
  }

  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket));
      });
  auto debugClient = server_.newClient<DebugTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        RequestSetupMetadata meta;
        meta.set_interfaceKind(InterfaceKind::DEBUGGING);

        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket), std::move(meta));
      });

  for (size_t i = 0; i < reqNum; i++) {
    client->semifuture_sendStreamingRequest();
    client->semifuture_sendRequest();
  }

  auto echoed = debugClient->semifuture_echo("echome").get();
  EXPECT_TRUE(folly::StringPiece(echoed).startsWith("echome:DebugInterface-"));

  for (auto& reqSnapshot : getRequestSnapshots(2 * reqNum)) {
    auto methodName = reqSnapshot.getMethodName();
    EXPECT_TRUE(
        methodName == "sendRequest" || methodName == "sendStreamingRequest");
  }
}

TEST_F(RequestInstrumentationTest, simpleHeaderRequestTest) {
  size_t reqNum = 5;
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::HeaderClientChannel::newChannel(
            std::move(socket));
      });

  for (size_t i = 0; i < reqNum; i++) {
    client->semifuture_sendRequest();
  }

  for (auto& reqSnapshot : getRequestSnapshots(reqNum)) {
    EXPECT_EQ(reqSnapshot.getMethodName(), "sendRequest");
    EXPECT_NE(reqSnapshot.getRootRequestContextId(), 0);
  }
}

TEST_F(RequestInstrumentationTest, requestPayloadTest) {
  std::array<std::string, 4> strList = {
      "apache", "thrift", "test", "InstrumentationTest"};
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>();

  std::vector<folly::SemiFuture<folly::IOBuf>> tasks;
  int32_t reqId = 0;
  for (const auto& testStr : strList) {
    auto task = client->semifuture_sendPayload(reqId, testStr)
                    .deferValue([](const apache::thrift::test::IOBuf& buf) {
                      return buf;
                    });
    tasks.emplace_back(std::move(task));
    reqId++;
  }
  auto reqSnapshots = getRequestSnapshots(strList.size());

  auto interceptedPayloadList =
      folly::collectSemiFuture(tasks.begin(), tasks.end()).get();

  std::set<const folly::IOBuf*, folly::IOBufLess> snapshotPayloadSet;
  for (const auto& reqSnapshot : reqSnapshots) {
    auto payload = reqSnapshot.getPayload();
    EXPECT_NE(payload, nullptr);
    snapshotPayloadSet.insert(payload);
  }

  EXPECT_EQ(interceptedPayloadList.size(), snapshotPayloadSet.size());
  for (const auto& interceptedPayload : interceptedPayloadList) {
    auto it = snapshotPayloadSet.find(&interceptedPayload);
    EXPECT_TRUE(it != snapshotPayloadSet.end());
  }
}

class ServerInstrumentationTest : public testing::Test {};

TEST_F(ServerInstrumentationTest, simpleServerTest) {
  ThriftServer server0;
  {
    auto handler = std::make_shared<TestInterface>();
    apache::thrift::ScopedServerInterfaceThread server1(handler);
    EXPECT_EQ(ServerInstrumentation::getServerCount(), 2);
  }
  EXPECT_EQ(ServerInstrumentation::getServerCount(), 1);
}
<commit_msg>fix flaky tes<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * 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 <folly/ThreadLocal.h>
#include <folly/io/async/EventBase.h>
#include <folly/io/async/Request.h>
#include <folly/portability/GTest.h>
#include <thrift/lib/cpp/async/TAsyncSocket.h>
#include <thrift/lib/cpp2/async/AsyncProcessor.h>
#include <thrift/lib/cpp2/async/FutureRequest.h>
#include <thrift/lib/cpp2/async/HeaderClientChannel.h>
#include <thrift/lib/cpp2/async/RequestChannel.h>
#include <thrift/lib/cpp2/async/RocketClientChannel.h>
#include <thrift/lib/cpp2/server/Cpp2Worker.h>
#include <thrift/lib/cpp2/server/ServerInstrumentation.h>
#include <thrift/lib/cpp2/server/ThriftServer.h>
#include <thrift/lib/cpp2/test/gen-cpp2/DebugTestService.h>
#include <thrift/lib/cpp2/test/gen-cpp2/InstrumentationTestService.h>
#include <thrift/lib/cpp2/transport/rsocket/server/RSRoutingHandler.h>
#include <thrift/lib/cpp2/util/ScopedServerInterfaceThread.h>
#include <atomic>
#include <thread>

using namespace apache::thrift;
using namespace apache::thrift::concurrency;
using namespace apache::thrift::test;

class RequestPayload : public folly::RequestData {
 public:
  static const folly::RequestToken& getRequestToken() {
    static folly::RequestToken token("InstrumentationTest::RequestPayload");
    return token;
  }
  explicit RequestPayload(std::unique_ptr<folly::IOBuf> buf)
      : buf_(std::move(buf)) {}
  bool hasCallback() override {
    return false;
  }
  const folly::IOBuf* getPayload() {
    return buf_.get();
  }

 private:
  std::unique_ptr<folly::IOBuf> buf_;
};

class InstrumentationTestProcessor
    : public InstrumentationTestServiceAsyncProcessor {
 public:
  explicit InstrumentationTestProcessor(InstrumentationTestServiceSvIf* iface)
      : InstrumentationTestServiceAsyncProcessor(iface) {}

  /**
   * Intercepts and clones incoming payload buffers, then passes them down to
   * method handlers.
   */
  void process(
      std::unique_ptr<ResponseChannelRequest> req,
      std::unique_ptr<folly::IOBuf> buf,
      apache::thrift::protocol::PROTOCOL_TYPES protType,
      apache::thrift::Cpp2RequestContext* context,
      folly::EventBase* eb,
      apache::thrift::concurrency::ThreadManager* tm) override {
    folly::RequestContext::get()->setContextData(
        RequestPayload::getRequestToken(),
        std::make_unique<RequestPayload>(buf->clone()));
    InstrumentationTestServiceAsyncProcessor::process(
        std::move(req), std::move(buf), protType, context, eb, tm);
  }
};

class TestInterface : public InstrumentationTestServiceSvIf {
 public:
  auto requestGuard() {
    reqCount_++;
    return folly::makeGuard([&] { --reqCount_; });
  }

  folly::coro::Task<void> co_sendRequest() override {
    auto rg = requestGuard();
    auto ctx = folly::RequestContext::get();
    EXPECT_TRUE(
        ctx->setContextDataIfAbsent("TestInterface::co_sendRequest", nullptr));
    co_await finished_;
  }

  folly::coro::Task<apache::thrift::Stream<int32_t>> co_sendStreamingRequest()
      override {
    auto rg = requestGuard();
    co_await finished_;
    co_return createStreamGenerator(
        []() -> folly::coro::AsyncGenerator<int32_t> { co_yield 0; });
  }

  folly::coro::Task<apache::thrift::test::IOBuf> co_sendPayload(
      int32_t id,
      const std::string& /* str */) override {
    auto rg = requestGuard();
    auto payload = dynamic_cast<RequestPayload*>(
        folly::RequestContext::get()->getContextData(
            RequestPayload::getRequestToken()));
    EXPECT_NE(payload, nullptr);
    co_await finished_;
    co_return * payload->getPayload()->clone();
  }

  void stopRequests() {
    finished_.post();
    while (reqCount_ > 0) {
      std::this_thread::yield();
    }
  }

  void waitForRequests(int32_t num) {
    while (reqCount_ != num) {
      std::this_thread::yield();
    }
  }

  folly::coro::Task<void> co_wait(int value, bool busyWait, bool shallowRC)
      override {
    std::unique_ptr<folly::ShallowCopyRequestContextScopeGuard> g;
    if (shallowRC) {
      g = std::make_unique<folly::ShallowCopyRequestContextScopeGuard>();
    }
    auto rg = requestGuard();
    if (busyWait) {
      while (!finished_.ready()) {
        std::this_thread::yield();
      }
    }
    co_await finished_;
  }

  std::unique_ptr<apache::thrift::AsyncProcessor> getProcessor() override {
    return std::make_unique<InstrumentationTestProcessor>(this);
  }

 private:
  folly::coro::Baton finished_;
  std::atomic<int32_t> reqCount_{0};
};

class DebugInterface : public DebugTestServiceSvIf {
 public:
  void echo(std::string& r, const std::string& s) override {
    r = folly::format("{}:{}", s, folly::getCurrentThreadName().value()).str();
  }
};

class DebuggingFrameHandler : public rocket::SetupFrameHandler {
 public:
  explicit DebuggingFrameHandler(ThriftServer& server)
      : origServer_(server), reqRegistry_([] {
          auto p = new ActiveRequestsRegistry(0, 0);
          return new std::shared_ptr<ActiveRequestsRegistry>(p);
        }) {
    auto tf =
        std::make_shared<PosixThreadFactory>(PosixThreadFactory::ATTACHED);
    tm_ = std::make_shared<SimpleThreadManager<folly::LifoSem>>(1, false);
    tm_->setNamePrefix("DebugInterface");
    tm_->threadFactory(move(tf));
    tm_->start();
  }
  folly::Optional<rocket::ProcessorInfo> tryHandle(
      const RequestSetupMetadata& meta) override {
    if (meta.interfaceKind_ref().has_value() &&
        meta.interfaceKind_ref().value() == InterfaceKind::DEBUGGING) {
      auto info = rocket::ProcessorInfo{
          debug_.getProcessor(), tm_, origServer_, *reqRegistry_.get()};
      return folly::Optional<rocket::ProcessorInfo>(std::move(info));
    }
    return folly::Optional<rocket::ProcessorInfo>();
  }

 private:
  ThriftServer& origServer_;
  DebugInterface debug_;
  std::shared_ptr<ThreadManager> tm_;
  folly::ThreadLocal<std::shared_ptr<ActiveRequestsRegistry>> reqRegistry_;
};

class RequestInstrumentationTest : public testing::Test {
 protected:
  RequestInstrumentationTest()
      : handler_(std::make_shared<TestInterface>()),
        server_(handler_, "::1", 0),
        thriftServer_(dynamic_cast<ThriftServer*>(&server_.getThriftServer())) {
    EXPECT_NE(thriftServer_, nullptr);
  }

  std::vector<ThriftServer::RequestSnapshot> getRequestSnapshots(
      size_t reqNum) {
    SCOPE_EXIT {
      handler_->stopRequests();
    };
    handler_->waitForRequests(reqNum);

    auto serverReqSnapshots = thriftServer_->snapshotActiveRequests().get();

    EXPECT_EQ(serverReqSnapshots.size(), reqNum);
    return serverReqSnapshots;
  }

  std::vector<intptr_t> getRootIdsOnThreads() {
    std::vector<intptr_t> results;
    for (auto& root : folly::RequestContext::getRootIdsFromAllThreads()) {
      if (!root.second) {
        continue;
      }
      results.push_back(root.second);
    }
    return results;
  }

  std::shared_ptr<TestInterface> handler_;
  apache::thrift::ScopedServerInterfaceThread server_;
  ThriftServer* thriftServer_;
};

TEST_F(RequestInstrumentationTest, simpleRocketRequestTest) {
  size_t reqNum = 5;
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket));
      });

  for (size_t i = 0; i < reqNum; i++) {
    client->semifuture_sendStreamingRequest();
    client->semifuture_sendRequest();
  }
  handler_->waitForRequests(2 * reqNum);

  // we expect all requests to get off the thread, eventually
  int attempt = 0;
  while (attempt < 5 && getRootIdsOnThreads().size() > 0) {
    sleep(1);
    attempt++;
  }
  EXPECT_LT(attempt, 5);

  for (auto& reqSnapshot : getRequestSnapshots(2 * reqNum)) {
    auto methodName = reqSnapshot.getMethodName();
    EXPECT_NE(reqSnapshot.getRootRequestContextId(), 0);
    EXPECT_TRUE(
        methodName == "sendRequest" || methodName == "sendStreamingRequest");
  }
}

TEST_F(RequestInstrumentationTest, threadSnapshot) {
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket));
      });

  client->semifuture_sendRequest();
  handler_->waitForRequests(1);
  client->semifuture_wait(0, true, false);

  handler_->waitForRequests(2);
  auto onThreadReqs = getRootIdsOnThreads();
  auto allReqs = getRequestSnapshots(2);
  EXPECT_EQ(1, onThreadReqs.size());
  EXPECT_EQ(2, allReqs.size());

  for (const auto& req : allReqs) {
    if (req.getMethodName() == "wait") {
      EXPECT_EQ(req.getRootRequestContextId(), onThreadReqs[0]);
    } else {
      EXPECT_NE(req.getRootRequestContextId(), onThreadReqs[0]);
    }
  }
}

TEST_F(RequestInstrumentationTest, threadSnapshotWithShallowRC) {
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket));
      });

  client->semifuture_sendRequest();
  handler_->waitForRequests(1);
  client->semifuture_wait(0, true, true);
  handler_->waitForRequests(2);

  auto onThreadReqs = getRootIdsOnThreads();
  auto allReqs = getRequestSnapshots(2);
  EXPECT_EQ(1, onThreadReqs.size());
  EXPECT_EQ(2, allReqs.size());

  for (const auto& req : allReqs) {
    if (req.getMethodName() == "wait") {
      EXPECT_EQ(req.getRootRequestContextId(), onThreadReqs.front());
    } else {
      EXPECT_NE(req.getRootRequestContextId(), onThreadReqs.front());
    }
  }
}

TEST_F(RequestInstrumentationTest, debugInterfaceTest) {
  size_t reqNum = 5;

  // inject our setup frame handler for rocket connections
  for (const auto& rh : *thriftServer_->getRoutingHandlers()) {
    auto rs = dynamic_cast<RSRoutingHandler*>(rh.get());
    if (rs != nullptr) {
      rs->addSetupFrameHandler(
          std::make_unique<DebuggingFrameHandler>(*thriftServer_));
      break;
    }
  }

  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket));
      });
  auto debugClient = server_.newClient<DebugTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        RequestSetupMetadata meta;
        meta.set_interfaceKind(InterfaceKind::DEBUGGING);

        return apache::thrift::RocketClientChannel::newChannel(
            std::move(socket), std::move(meta));
      });

  for (size_t i = 0; i < reqNum; i++) {
    client->semifuture_sendStreamingRequest();
    client->semifuture_sendRequest();
  }

  auto echoed = debugClient->semifuture_echo("echome").get();
  EXPECT_TRUE(folly::StringPiece(echoed).startsWith("echome:DebugInterface-"));

  for (auto& reqSnapshot : getRequestSnapshots(2 * reqNum)) {
    auto methodName = reqSnapshot.getMethodName();
    EXPECT_TRUE(
        methodName == "sendRequest" || methodName == "sendStreamingRequest");
  }
}

TEST_F(RequestInstrumentationTest, simpleHeaderRequestTest) {
  size_t reqNum = 5;
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>(
      nullptr, [](auto socket) mutable {
        return apache::thrift::HeaderClientChannel::newChannel(
            std::move(socket));
      });

  for (size_t i = 0; i < reqNum; i++) {
    client->semifuture_sendRequest();
  }

  for (auto& reqSnapshot : getRequestSnapshots(reqNum)) {
    EXPECT_EQ(reqSnapshot.getMethodName(), "sendRequest");
    EXPECT_NE(reqSnapshot.getRootRequestContextId(), 0);
  }
}

TEST_F(RequestInstrumentationTest, requestPayloadTest) {
  std::array<std::string, 4> strList = {
      "apache", "thrift", "test", "InstrumentationTest"};
  auto client = server_.newClient<InstrumentationTestServiceAsyncClient>();

  std::vector<folly::SemiFuture<folly::IOBuf>> tasks;
  int32_t reqId = 0;
  for (const auto& testStr : strList) {
    auto task = client->semifuture_sendPayload(reqId, testStr)
                    .deferValue([](const apache::thrift::test::IOBuf& buf) {
                      return buf;
                    });
    tasks.emplace_back(std::move(task));
    reqId++;
  }
  auto reqSnapshots = getRequestSnapshots(strList.size());

  auto interceptedPayloadList =
      folly::collectSemiFuture(tasks.begin(), tasks.end()).get();

  std::set<const folly::IOBuf*, folly::IOBufLess> snapshotPayloadSet;
  for (const auto& reqSnapshot : reqSnapshots) {
    auto payload = reqSnapshot.getPayload();
    EXPECT_NE(payload, nullptr);
    snapshotPayloadSet.insert(payload);
  }

  EXPECT_EQ(interceptedPayloadList.size(), snapshotPayloadSet.size());
  for (const auto& interceptedPayload : interceptedPayloadList) {
    auto it = snapshotPayloadSet.find(&interceptedPayload);
    EXPECT_TRUE(it != snapshotPayloadSet.end());
  }
}

class ServerInstrumentationTest : public testing::Test {};

TEST_F(ServerInstrumentationTest, simpleServerTest) {
  ThriftServer server0;
  {
    auto handler = std::make_shared<TestInterface>();
    apache::thrift::ScopedServerInterfaceThread server1(handler);
    EXPECT_EQ(ServerInstrumentation::getServerCount(), 2);
  }
  EXPECT_EQ(ServerInstrumentation::getServerCount(), 1);
}
<|endoftext|>


<commit_before>#include "BoundingBox.hpp"
#include "formats/osm/xml/OsmXmlParser.hpp"
#include "config.hpp"

#include <fstream>
#include <boost/test/unit_test.hpp>

using namespace utymap::formats;

namespace {
    struct Formats_Osm_Xml_OsmXmlParserFixture
    {
        Formats_Osm_Xml_OsmXmlParserFixture() :
            istream(TEST_XML_FILE, std::ios::in)
        {
        }

        OsmXmlParser<CountableOsmDataVisitor> parser;
        CountableOsmDataVisitor visitor;
        std::ifstream istream;
    };
}

BOOST_FIXTURE_TEST_SUITE(Formats_Osm_Xml_Parser, Formats_Osm_Xml_OsmXmlParserFixture)

BOOST_AUTO_TEST_CASE(GivenDefaultXml_WhenParserParse_ThenHasExpectedElementCount)
{
    parser.parse(istream, visitor);

    BOOST_CHECK_EQUAL(1, visitor.bounds);
    BOOST_CHECK_EQUAL(7653, visitor.nodes);
    BOOST_CHECK_EQUAL(1116, visitor.ways);
    BOOST_CHECK_EQUAL(92, visitor.relations);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>core: add unit test for checking osm xml node parsing<commit_after>#include "BoundingBox.hpp"
#include "entities/Node.hpp"
#include "formats/osm/xml/OsmXmlParser.hpp"

#include "config.hpp"
#include "test_utils/ElementUtils.hpp"
#include "test_utils/DependencyProvider.hpp"

#include <fstream>
#include <numeric>
#include <boost/test/unit_test.hpp>

using namespace utymap::entities;
using namespace utymap::formats;

namespace {

    //typedef std::vector<std::pair<std::string, std::string>> RawTags;

    struct Formats_Osm_Xml_OsmXmlParserFixture
    {
        utymap::tests::DependencyProvider dependencyProvider;

        utymap::entities::Tag createTag(const std::string& key, const std::string& value)
        {
            return utymap::tests::ElementUtils::createTag(*dependencyProvider.getStringTable(), key, value);
        }
    };

    template <typename Iterator>
    bool reduce(Iterator begin, Iterator end)
    {
        return std::accumulate(begin, end, true, [](bool a, bool b) {
            return a && b;
        });
    }

    void assertTags(const std::vector<utymap::entities::Tag> expectedTags,
        const std::vector<utymap::entities::Tag> actualTags)
    {
        BOOST_CHECK_EQUAL(expectedTags.size(), actualTags.size());
        for (int i = 0; i < actualTags.size(); ++i)
        {
            BOOST_CHECK_EQUAL(expectedTags.at(i).key, actualTags.at(i).key);
            BOOST_CHECK_EQUAL(expectedTags.at(i).value, actualTags.at(i).value);
        }
    }

    void assertNode(const Node& node,
        const utymap::GeoCoordinate coordinate,
        const std::vector<utymap::entities::Tag> tags)
    {
        BOOST_CHECK_EQUAL(coordinate.latitude, node.coordinate.latitude);
        BOOST_CHECK_EQUAL(coordinate.longitude, node.coordinate.longitude);
        assertTags(tags, node.tags);
    }
}

BOOST_FIXTURE_TEST_SUITE(Formats_Osm_Xml_Parser, Formats_Osm_Xml_OsmXmlParserFixture)

BOOST_AUTO_TEST_CASE(GivenDefaultXml_WhenParserParse_ThenHasExpectedElementCount)
{
    std::ifstream istream(TEST_XML_FILE, std::ios::in);
    OsmXmlParser<CountableOsmDataVisitor> parser;
    CountableOsmDataVisitor visitor;

    parser.parse(istream, visitor);

    BOOST_CHECK_EQUAL(1, visitor.bounds);
    BOOST_CHECK_EQUAL(7653, visitor.nodes);
    BOOST_CHECK_EQUAL(1116, visitor.ways);
    BOOST_CHECK_EQUAL(92, visitor.relations);
}

BOOST_AUTO_TEST_CASE(GivenTestDummyXml_WhenParserParse_ThenHasProperNodes)
{
    std::vector<bool> checkList { false, false };
    std::ifstream istream(TEST_OSM_DUMMY_FILE, std::ios::in);
    OsmXmlParser<OsmDataVisitor> parser;
    OsmDataVisitor visitor(*dependencyProvider.getStringTable(), [&](Element& element) {
        if (Node* node = dynamic_cast<Node*>(&element)) {
            if (node->id == 42421951) {
                assertNode(*node, utymap::GeoCoordinate(40.7033242, -74.0077787), { createTag("highway","traffic_signals") });
                checkList[0] = true;
            }
            else if (node->id == 42424605) {
                assertNode(*node, utymap::GeoCoordinate(40.8142100, -73.9341897), {});
                checkList[1] = true;
            }
        }
        return true;
    });

    parser.parse(istream, visitor);
    visitor.complete();

    BOOST_CHECK(reduce(checkList.begin(), checkList.end()));
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include <QDir>
#include <QDateTime>
#include <QUdpSocket>

#include <protobuf/messages_robocup_ssl_wrapper.pb.h>
#include <protobuf/LogFrame.pb.h>
#include <protobuf/referee.pb.h>
#include <git_version.hpp>

#include <multicast.hpp>
#include <Network.hpp>
#include <Utils.hpp>

#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <termios.h>

using namespace std;
using namespace Packet;

void usage(const char* prog) {
    fprintf(stderr, "Usage: %s[-sim] <filename.log>\n", prog);
    fprintf(stderr, "-sim:\t Connect to the simulator for vision packets.\n");
    exit(1);
}

int main(int argc, char* argv[]) {
    int framePeriod = 1000000 / 60;

    bool simulation = false;
    QString logFile;

    // Process args
    if (argc == 3 && strcmp(argv[1], "-sim") == 0) {
        logFile = argv[2];
        simulation = true;
    } else if (argc == 2) {
        logFile = argv[1];
    } else if (argc != 1) {
        usage(argv[0]);
    }

    if (logFile.isNull()) {
        if (!QDir("logs").exists()) {
            printf("No logs directory and no log file specified\n");
            return 1;
        }

        logFile = QString("logs/") +
                  QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss.log");
    }

    // Create vision socket
    QUdpSocket visionSocket;
    if (simulation) {
        // The simulator doesn't multicast its vision.  Instead, it sends to two
        // different ports.
        // Try to bind to the first one and, if that fails, use the second one.
        if (!visionSocket.bind(SimVisionPort)) {
            if (!visionSocket.bind(SimVisionPort + 1)) {
                throw runtime_error(
                    "Can't bind to either simulated vision port");
            }
        }
    } else {
        if (!visionSocket.bind(SharedVisionPortDoubleNew,
                               QUdpSocket::ShareAddress)) {
            printf("Can't bind to shared vision port");
            return 1;
        }
    }
    multicast_add(&visionSocket, SharedVisionAddress);

    // Create referee socket
    QUdpSocket refereeSocket;
    if (!refereeSocket.bind(ProtobufRefereePort, QUdpSocket::ShareAddress)) {
        throw runtime_error("Can't bind to shared referee port");
    }

    multicast_add(&refereeSocket, RefereeAddress);

    // Create log file
    int fd = creat(logFile.toLatin1(), 0666);
    if (fd < 0) {
        printf("Can't create %s: %m\n", (const char*)logFile.toLatin1());
        return 1;
    }

    fprintf(stderr, "Writing to %s\n", (const char*)logFile.toLatin1());
    fprintf(stderr, "Press any key and press ENTER to exit\n");

    // Main loop
    LogFrame logFrame;
    bool first = true;
    while (true) {
        RJ::Time startTime = RJ::timestamp();

        logFrame.Clear();
        logFrame.set_command_time(startTime);
        logFrame.set_timestamp(startTime);
        logFrame.set_blue_team(false);  // Always assume self is Yellow for logs

        // Check for user input (to exit)
        struct pollfd pfd;
        pfd.fd = 0;
        pfd.events = POLLIN;
        if (poll(&pfd, 1, 0) > 0) {
            // Enter pressed
            break;
        }

        // Read vision data
        while (visionSocket.hasPendingDatagrams()) {
            string buf;
            unsigned int n = visionSocket.pendingDatagramSize();
            buf.resize(n);
            visionSocket.readDatagram(&buf[0], n);

            SSL_WrapperPacket* packet = logFrame.add_raw_vision();
            if (!packet->ParseFromString(buf)) {
                printf("Bad vision packet of %d bytes\n", n);
                continue;
            }

            // LogFrame_Robot* robot = logFrame
        }

        // Read referee data
        bool firstRefpacket = true;
        while (refereeSocket.hasPendingDatagrams()) {
            string buf;
            unsigned int n = refereeSocket.pendingDatagramSize();
            buf.resize(n);
            refereeSocket.readDatagram(&buf[0], n);

            SSL_Referee* packet = logFrame.add_raw_refbox();
            if (!packet->ParseFromString(buf)) {
                printf("Bad referee packet of %d bytes\n", n);
                continue;
            }

            // Copy team names into LogFrame
            if (firstRefpacket) {
                firstRefpacket = false;

                logFrame.set_team_name_yellow(packet->yellow().name());
                logFrame.set_team_name_blue(packet->blue().name());
            }
        }

        if (first) {
            first = false;

            LogConfig* logConfig = logFrame.mutable_log_config();
            logConfig->set_generator("simple_logger");
            logConfig->set_git_version_hash(git_version_hash);
            logConfig->set_git_version_dirty(git_version_dirty);
            logConfig->set_simulation(simulation);
        }

        uint32_t size = logFrame.ByteSize();
        if (write(fd, &size, sizeof(size)) != sizeof(size)) {
            printf("Failed to write size: %m\n");
            break;
        } else if (!logFrame.SerializeToFileDescriptor(fd)) {
            printf("Failed to write frame: %m\n");
            break;
        }

        RJ::Time endTime = RJ::timestamp();
        int lastFrameTime = endTime - startTime;
        if (lastFrameTime < framePeriod) {
            usleep(framePeriod - lastFrameTime);
        } else {
            printf("Processor took too long: %d us\n", lastFrameTime);
        }
    }

    // Discard input on stdin
    tcflush(0, TCIFLUSH);

    printf("Done.\n");

    return 0;
}
<commit_msg>Remove unused code<commit_after>#include <QDir>
#include <QDateTime>
#include <QUdpSocket>

#include <protobuf/messages_robocup_ssl_wrapper.pb.h>
#include <protobuf/LogFrame.pb.h>
#include <protobuf/referee.pb.h>
#include <git_version.hpp>

#include <multicast.hpp>
#include <Network.hpp>
#include <Utils.hpp>

#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <termios.h>

using namespace std;
using namespace Packet;

void usage(const char* prog) {
    fprintf(stderr, "Usage: %s[-sim] <filename.log>\n", prog);
    fprintf(stderr, "-sim:\t Connect to the simulator for vision packets.\n");
    exit(1);
}

int main(int argc, char* argv[]) {
    int framePeriod = 1000000 / 60;

    bool simulation = false;
    QString logFile;

    // Process args
    if (argc == 3 && strcmp(argv[1], "-sim") == 0) {
        logFile = argv[2];
        simulation = true;
    } else if (argc == 2) {
        logFile = argv[1];
    } else if (argc != 1) {
        usage(argv[0]);
    }

    if (logFile.isNull()) {
        if (!QDir("logs").exists()) {
            printf("No logs directory and no log file specified\n");
            return 1;
        }

        logFile = QString("logs/") +
                  QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss.log");
    }

    // Create vision socket
    QUdpSocket visionSocket;
    if (simulation) {
        // The simulator doesn't multicast its vision.  Instead, it sends to two
        // different ports.
        // Try to bind to the first one and, if that fails, use the second one.
        if (!visionSocket.bind(SimVisionPort)) {
            if (!visionSocket.bind(SimVisionPort + 1)) {
                throw runtime_error(
                    "Can't bind to either simulated vision port");
            }
        }
    } else {
        if (!visionSocket.bind(SharedVisionPortDoubleNew,
                               QUdpSocket::ShareAddress)) {
            printf("Can't bind to shared vision port");
            return 1;
        }
    }
    multicast_add(&visionSocket, SharedVisionAddress);

    // Create referee socket
    QUdpSocket refereeSocket;
    if (!refereeSocket.bind(ProtobufRefereePort, QUdpSocket::ShareAddress)) {
        throw runtime_error("Can't bind to shared referee port");
    }

    multicast_add(&refereeSocket, RefereeAddress);

    // Create log file
    int fd = creat(logFile.toLatin1(), 0666);
    if (fd < 0) {
        printf("Can't create %s: %m\n", (const char*)logFile.toLatin1());
        return 1;
    }

    fprintf(stderr, "Writing to %s\n", (const char*)logFile.toLatin1());
    fprintf(stderr, "Press any key and press ENTER to exit\n");

    // Main loop
    LogFrame logFrame;
    bool first = true;
    while (true) {
        RJ::Time startTime = RJ::timestamp();

        logFrame.Clear();
        logFrame.set_command_time(startTime);
        logFrame.set_timestamp(startTime);
        logFrame.set_blue_team(false);  // Always assume self is Yellow for logs

        // Check for user input (to exit)
        struct pollfd pfd;
        pfd.fd = 0;
        pfd.events = POLLIN;
        if (poll(&pfd, 1, 0) > 0) {
            // Enter pressed
            break;
        }

        // Read vision data
        while (visionSocket.hasPendingDatagrams()) {
            string buf;
            unsigned int n = visionSocket.pendingDatagramSize();
            buf.resize(n);
            visionSocket.readDatagram(&buf[0], n);

            SSL_WrapperPacket* packet = logFrame.add_raw_vision();
            if (!packet->ParseFromString(buf)) {
                printf("Bad vision packet of %d bytes\n", n);
                continue;
            }
        }

        // Read referee data
        bool firstRefpacket = true;
        while (refereeSocket.hasPendingDatagrams()) {
            string buf;
            unsigned int n = refereeSocket.pendingDatagramSize();
            buf.resize(n);
            refereeSocket.readDatagram(&buf[0], n);

            SSL_Referee* packet = logFrame.add_raw_refbox();
            if (!packet->ParseFromString(buf)) {
                printf("Bad referee packet of %d bytes\n", n);
                continue;
            }

            // Copy team names into LogFrame
            if (firstRefpacket) {
                firstRefpacket = false;

                logFrame.set_team_name_yellow(packet->yellow().name());
                logFrame.set_team_name_blue(packet->blue().name());
            }
        }

        if (first) {
            first = false;

            LogConfig* logConfig = logFrame.mutable_log_config();
            logConfig->set_generator("simple_logger");
            logConfig->set_git_version_hash(git_version_hash);
            logConfig->set_git_version_dirty(git_version_dirty);
            logConfig->set_simulation(simulation);
        }

        uint32_t size = logFrame.ByteSize();
        if (write(fd, &size, sizeof(size)) != sizeof(size)) {
            printf("Failed to write size: %m\n");
            break;
        } else if (!logFrame.SerializeToFileDescriptor(fd)) {
            printf("Failed to write frame: %m\n");
            break;
        }

        RJ::Time endTime = RJ::timestamp();
        int lastFrameTime = endTime - startTime;
        if (lastFrameTime < framePeriod) {
            usleep(framePeriod - lastFrameTime);
        } else {
            printf("Processor took too long: %d us\n", lastFrameTime);
        }
    }

    // Discard input on stdin
    tcflush(0, TCIFLUSH);

    printf("Done.\n");

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef DATABASE_HH_
#define DATABASE_HH_

#include "core/sstring.hh"
#include "core/shared_ptr.hh"
#include <functional>
#include <boost/any.hpp>
#include <cstdint>
#include <boost/variant.hpp>
#include <unordered_map>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <boost/functional/hash.hpp>

// FIXME: should be int8_t
using bytes = basic_sstring<char, uint32_t, 31>;

class abstract_type {
        sstring _name;
public:
        abstract_type(sstring name) : _name(name) {}
        virtual ~abstract_type() {}
        virtual void serialize(const boost::any& value, std::ostream& out) = 0;
        virtual boost::any deserialize(std::istream& in) = 0;
        virtual bool less(const bytes& v1, const bytes& v2) = 0;
        boost::any deserialize(const bytes& v) {
            // FIXME: optimize
            std::istringstream iss(v);
            return deserialize(iss);
        }
        bytes decompose(const boost::any& value) {
            // FIXME: optimize
            std::ostringstream oss;
            serialize(value, oss);
            auto s = oss.str();
            return bytes(s.data(), s.size());
        }
        sstring name() const {
            return _name;
        }
};

using data_type = shared_ptr<abstract_type>;

inline
size_t hash_value(const shared_ptr<abstract_type>& x) {
    return std::hash<abstract_type*>()(x.get());
}

template <typename Type>
shared_ptr<abstract_type> data_type_for();

class key_compare {
    shared_ptr<abstract_type> _type;
public:
    key_compare(shared_ptr<abstract_type> type) : _type(type) {}
    bool operator()(const bytes& v1, const bytes& v2) const {
        return _type->less(v1, v2);
    }
};

struct row;
struct paritition;
struct column_family;

struct row {
    std::vector<bytes> cells;
};

struct partition {
    explicit partition(column_family& cf);
    row static_columns;
    // row key within partition -> row
    std::map<bytes, row, key_compare> rows;
};

// FIXME: add missing types
extern thread_local shared_ptr<abstract_type> int32_type;
extern thread_local shared_ptr<abstract_type> long_type;
extern thread_local shared_ptr<abstract_type> ascii_type;
extern thread_local shared_ptr<abstract_type> bytes_type;
extern thread_local shared_ptr<abstract_type> utf8_type;

template <>
inline
shared_ptr<abstract_type> data_type_for<int32_t>() {
    return int32_type;
}

template <>
inline
shared_ptr<abstract_type> data_type_for<int64_t>() {
    return long_type;
}

template <>
inline
shared_ptr<abstract_type> data_type_for<sstring>() {
    return utf8_type;
}

struct column_definition {
    sstring name;
    shared_ptr<abstract_type> type;
    struct name_compare {
        bool operator()(const column_definition& cd1, const column_definition& cd2) const {
            return std::lexicographical_compare(
                    cd1.name.begin(), cd1.name.end(),
                    cd2.name.begin(), cd2.name.end(),
                    [] (char c1, char c2) { return uint8_t(c1) < uint8_t(c1); });
        }
    };
};

struct column_family {
    column_family(shared_ptr<abstract_type> partition_key_type, shared_ptr<abstract_type> clustering_key_type);
    // primary key = paritition key + clustering_key
    shared_ptr<abstract_type> partition_key_type;
    shared_ptr<abstract_type> clustering_key_type;
    std::vector<column_definition> partition_key;
    std::vector<column_definition> clustering_key;
    std::vector<column_definition> column_defs; // sorted by name
    partition& find_or_create_partition(const bytes& key);
    row& find_or_create_row(const bytes& partition_key, const bytes& clustering_key);
    partition* find_partition(const bytes& key);
    row* find_row(const bytes& partition_key, const bytes& clustering_key);
    // partition key -> partition
    std::map<bytes, partition, key_compare> partitions;
};

struct keyspace {
    std::unordered_map<sstring, column_family> column_families;
};

struct database {
    std::unordered_map<sstring, keyspace> keyspaces;
};

namespace std {

template <>
struct hash<shared_ptr<abstract_type>> : boost::hash<shared_ptr<abstract_type>> {
};

}

inline
bytes
to_bytes(const char* x) {
    return bytes(reinterpret_cast<const char*>(x), std::strlen(x));
}

inline
bytes
to_bytes(const std::string& x) {
    return bytes(reinterpret_cast<const char*>(x.data()), x.size());
}

inline
bytes
to_bytes(const sstring& x) {
    return bytes(reinterpret_cast<const char*>(x.c_str()), x.size());
}

// This follows java.util.Comparator
// FIXME: Choose a better place than database.hh
template <typename T>
struct comparator {
    virtual ~comparator() {}
    virtual bool operator()(const T& v1, const T& v2) const = 0;
};

#endif /* DATABASE_HH_ */
<commit_msg>db: adjust abstract_type indentation<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef DATABASE_HH_
#define DATABASE_HH_

#include "core/sstring.hh"
#include "core/shared_ptr.hh"
#include <functional>
#include <boost/any.hpp>
#include <cstdint>
#include <boost/variant.hpp>
#include <unordered_map>
#include <map>
#include <set>
#include <vector>
#include <iostream>
#include <boost/functional/hash.hpp>

// FIXME: should be int8_t
using bytes = basic_sstring<char, uint32_t, 31>;

class abstract_type {
    sstring _name;
public:
    abstract_type(sstring name) : _name(name) {}
    virtual ~abstract_type() {}
    virtual void serialize(const boost::any& value, std::ostream& out) = 0;
    virtual boost::any deserialize(std::istream& in) = 0;
    virtual bool less(const bytes& v1, const bytes& v2) = 0;
    boost::any deserialize(const bytes& v) {
        // FIXME: optimize
        std::istringstream iss(v);
        return deserialize(iss);
    }
    bytes decompose(const boost::any& value) {
        // FIXME: optimize
        std::ostringstream oss;
        serialize(value, oss);
        auto s = oss.str();
        return bytes(s.data(), s.size());
    }
    sstring name() const {
        return _name;
    }
};

using data_type = shared_ptr<abstract_type>;

inline
size_t hash_value(const shared_ptr<abstract_type>& x) {
    return std::hash<abstract_type*>()(x.get());
}

template <typename Type>
shared_ptr<abstract_type> data_type_for();

class key_compare {
    shared_ptr<abstract_type> _type;
public:
    key_compare(shared_ptr<abstract_type> type) : _type(type) {}
    bool operator()(const bytes& v1, const bytes& v2) const {
        return _type->less(v1, v2);
    }
};

struct row;
struct paritition;
struct column_family;

struct row {
    std::vector<bytes> cells;
};

struct partition {
    explicit partition(column_family& cf);
    row static_columns;
    // row key within partition -> row
    std::map<bytes, row, key_compare> rows;
};

// FIXME: add missing types
extern thread_local shared_ptr<abstract_type> int32_type;
extern thread_local shared_ptr<abstract_type> long_type;
extern thread_local shared_ptr<abstract_type> ascii_type;
extern thread_local shared_ptr<abstract_type> bytes_type;
extern thread_local shared_ptr<abstract_type> utf8_type;

template <>
inline
shared_ptr<abstract_type> data_type_for<int32_t>() {
    return int32_type;
}

template <>
inline
shared_ptr<abstract_type> data_type_for<int64_t>() {
    return long_type;
}

template <>
inline
shared_ptr<abstract_type> data_type_for<sstring>() {
    return utf8_type;
}

struct column_definition {
    sstring name;
    shared_ptr<abstract_type> type;
    struct name_compare {
        bool operator()(const column_definition& cd1, const column_definition& cd2) const {
            return std::lexicographical_compare(
                    cd1.name.begin(), cd1.name.end(),
                    cd2.name.begin(), cd2.name.end(),
                    [] (char c1, char c2) { return uint8_t(c1) < uint8_t(c1); });
        }
    };
};

struct column_family {
    column_family(shared_ptr<abstract_type> partition_key_type, shared_ptr<abstract_type> clustering_key_type);
    // primary key = paritition key + clustering_key
    shared_ptr<abstract_type> partition_key_type;
    shared_ptr<abstract_type> clustering_key_type;
    std::vector<column_definition> partition_key;
    std::vector<column_definition> clustering_key;
    std::vector<column_definition> column_defs; // sorted by name
    partition& find_or_create_partition(const bytes& key);
    row& find_or_create_row(const bytes& partition_key, const bytes& clustering_key);
    partition* find_partition(const bytes& key);
    row* find_row(const bytes& partition_key, const bytes& clustering_key);
    // partition key -> partition
    std::map<bytes, partition, key_compare> partitions;
};

struct keyspace {
    std::unordered_map<sstring, column_family> column_families;
};

struct database {
    std::unordered_map<sstring, keyspace> keyspaces;
};

namespace std {

template <>
struct hash<shared_ptr<abstract_type>> : boost::hash<shared_ptr<abstract_type>> {
};

}

inline
bytes
to_bytes(const char* x) {
    return bytes(reinterpret_cast<const char*>(x), std::strlen(x));
}

inline
bytes
to_bytes(const std::string& x) {
    return bytes(reinterpret_cast<const char*>(x.data()), x.size());
}

inline
bytes
to_bytes(const sstring& x) {
    return bytes(reinterpret_cast<const char*>(x.c_str()), x.size());
}

// This follows java.util.Comparator
// FIXME: Choose a better place than database.hh
template <typename T>
struct comparator {
    virtual ~comparator() {}
    virtual bool operator()(const T& v1, const T& v2) const = 0;
};

#endif /* DATABASE_HH_ */
<|endoftext|>


<commit_before>/*
    Copyright 2005-2007 Adobe Systems Incorporated
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
    or a copy at http://stlab.adobe.com/licenses.html)
*/

/****************************************************************************************************/

#define ADOBE_DLL_SAFE 0

#include <GG/Wnd.h>

#include <GG/adobe/config.hpp>
#include <GG/adobe/future/modal_dialog_interface.hpp>
#include <GG/adobe/adam_evaluate.hpp>
#include <GG/adobe/adam_parser.hpp>
#include <GG/adobe/future/assemblage.hpp>
#include <GG/adobe/future/resources.hpp>
#include <GG/adobe/future/widgets/headers/platform_window.hpp>
#include <GG/adobe/future/widgets/headers/widget_factory.hpp>
#include <GG/adobe/future/widgets/headers/widget_utils.hpp>
#include <GG/adobe/keyboard.hpp>

#include <GG/DrawUtil.h>
#include <GG/GUI.h>
#include <GG/StyleFactory.h>
#include <GG/TextControl.h>
#include <GG/Wnd.h>

/****************************************************************************************************/

namespace GG {

/****************************************************************************************************/

    const int Window::FRAME_WIDTH = 2;
    const Pt Window::BEVEL_OFFSET(X(Window::FRAME_WIDTH), Y(Window::FRAME_WIDTH));

    Window::Window(adobe::window_t& imp) :
        Wnd(X0, Y0, X1, Y1, imp.flags_m),
        m_imp(imp),
        m_title(0)
    {
        if (!m_imp.name_m.empty()) {
            m_title = adobe::implementation::Factory().NewTextControl(
                BEVEL_OFFSET.x, BEVEL_OFFSET.y - adobe::implementation::CharHeight(),
                m_imp.name_m, adobe::implementation::DefaultFont()
            );
            AttachChild(m_title);
        }
    }

    Pt Window::ClientUpperLeft() const
    { return UpperLeft() + BEVEL_OFFSET + Pt(X0, m_title ? m_title->Height() : Y0); }

    Pt Window::ClientLowerRight() const
    { return LowerRight() - BEVEL_OFFSET; }

    WndRegion Window::WindowRegion(const Pt& pt) const
    {
        enum {LEFT = 0, MIDDLE = 1, RIGHT = 2};
        enum {TOP = 0, BOTTOM = 2};

        // window regions look like this:
        // 0111112
        // 3444445   // 4 is client area, 0,2,6,8 are corners
        // 3444445
        // 6777778

        int x_pos = MIDDLE;   // default & typical case is that the mouse is over the (non-border) client area
        int y_pos = MIDDLE;

        Pt ul = UpperLeft() + BEVEL_OFFSET, lr = LowerRight() - BEVEL_OFFSET;

        if (pt.x < ul.x)
            x_pos = LEFT;
        else if (pt.x > lr.x)
            x_pos = RIGHT;

        if (pt.y < ul.y)
            y_pos = TOP;
        else if (pt.y > lr.y)
            y_pos = BOTTOM;

        return (Resizable() ? WndRegion(x_pos + 3 * y_pos) : WR_NONE);
    }

    void Window::SizeMove(const Pt& ul, const Pt& lr)
    {
        Wnd::SizeMove(ul, lr);

        Pt client_size = ClientSize();

        if (!m_imp.debounce_m && !m_imp.resize_proc_m.empty()) {
            m_imp.debounce_m = true;

            if (adobe::width(m_imp.place_data_m) != Value(client_size.x) ||
                adobe::height(m_imp.place_data_m) != Value(client_size.y)) {
                m_imp.resize_proc_m(Value(client_size.x), Value(client_size.y));

                adobe::width(m_imp.place_data_m) = Value(client_size.x);
                adobe::height(m_imp.place_data_m) = Value(client_size.y);
            }

            m_imp.debounce_m = false;
        }

        Pt new_title_size((LowerRight() - UpperLeft()).x - BEVEL_OFFSET.x * 2, m_title->Height());
        m_title->Resize(new_title_size);
    }

    void Window::Render()
    { BeveledRectangle(UpperLeft(), LowerRight(), CLR_GRAY, CLR_GRAY, true, BEVEL); }

    void Window::KeyPress(Key key, boost::uint32_t key_code_point, Flags<ModKey> mod_keys)
    {
        adobe::keyboard_t::get().dispatch(adobe::key_type(key, key_code_point),
                                          true,
                                          adobe::modifier_state(),
                                          adobe::any_regular_t(this));
    }

    void Window::KeyRelease(Key key, boost::uint32_t key_code_point, Flags<ModKey> mod_keys)
    {
        adobe::keyboard_t::get().dispatch(adobe::key_type(key, key_code_point),
                                          false,
                                          adobe::modifier_state(),
                                          adobe::any_regular_t(this));
    }

    void Window::SetEveModalDialog(adobe::modal_dialog_t* modal_dialog)
    { m_eve_modal_dialog.reset(modal_dialog); }

} // namespace GG

/****************************************************************************************************/

namespace adobe {

/****************************************************************************************************/

std::string getline(std::istream& stream)
{
    std::string result;

    result.reserve(128);

    while (true)
    {
        int c(stream.get());

        if (c == EOF || c == '\n')
        {
            break;
        }
        else if (c == '\r')
        {
            c = stream.get();

            if (c != '\n')
                stream.putback(c);

            break;
        }

        result += static_cast<char>(c);
    }

    return result;
}

/****************************************************************************************************/

std::string mdi_error_getline(std::istream& layout_definition, name_t, std::streampos line_start_position)
{
    std::streampos old_pos(layout_definition.tellg());

    layout_definition.clear();

    layout_definition.seekg(line_start_position);

    std::string result(getline(layout_definition));

    layout_definition.seekg(old_pos);

    return result;
}

/****************************************************************************************************/

modal_dialog_t::modal_dialog_t() :
    display_options_m(dialog_display_s),
    parent_m(platform_display_type()),
    root_behavior_m(false)
{ }

/****************************************************************************************************/

platform_display_type modal_dialog_t::init(std::istream& layout, std::istream& sheet)
{
// TODO: ???    resource_context_t res_context(working_directory_m);

    vm_lookup_m.attach_to(sheet_m);
    vm_lookup_m.attach_to(sheet_m.machine_m);

    result_m = dialog_result_t();

    //
    // Parse the proprty model stream
    //

    try
    {
        parse( sheet, line_position_t( "Proprty model sheet definition" ), bind_to_sheet( sheet_m ) );
    }
    catch (const stream_error_t& error)
    {
        throw std::logic_error(format_stream_error(sheet, error));
    }
    catch (...)
    {
        throw; // here for completeness' sake
    }

    //
    // REVISIT (2006/09/28, fbrereto): The sheet initializers don't run until the first update().
    //                                 To keep them from blowing away your sets in a couple of
    //                                 lines we need to add an update before the first set()
    //                                 on the sheet (this will get fixed with the proprty model
    //                                 library rewrite so mark it with a revisit comment).
    //

    sheet_m.update();

    //
    // Set up the sheet with initial inputs, etc.
    //

    sheet_m.set(input_m);
    sheet_m.set(record_m);

    need_ui_m = false;

    sheet_m.update();

    //
    // Save off the contributing set for potential reset action later
    //

    contributing_m = sheet_m.contributing();

    //
    // Set up the callback functions now so the contributing mark is meaningful, then update again
    //

    try
    {
        name_t result_cell(static_name_t("result"));

        attach_view(assemblage_m, result_cell, *this, sheet_m);

        sheet_m.monitor_invariant_dependent(result_cell, boost::bind(&modal_dialog_t::monitor_invariant, boost::ref(*this), _1));
        sheet_m.monitor_contributing(result_cell, sheet_m.contributing(), boost::bind(&modal_dialog_t::monitor_record, boost::ref(*this), _1));
    }
    catch (...)
    {
        // result cell wasn't found. While this isn't a deal-breaker, it's not
        // going to do much in the way of getting results from this dialog.
    }

    sheet_m.update();

    if (display_options_m == dialog_never_display_s && need_ui_m)
        throw std::runtime_error("handle_dialog: Invalid command parameters and UI not permitted.");

    if ((display_options_m == dialog_no_display_s && need_ui_m) ||
        display_options_m == dialog_display_s)
    {
        line_position_t::getline_proc_t getline_proc(new line_position_t::getline_proc_impl_t(boost::bind(&mdi_error_getline, boost::ref(layout), _1, _2)));

        view_m.reset( make_view( static_name_t( "eve definition" ),
                                        getline_proc,
                                        layout,
                                        sheet_m,
                                        root_behavior_m,
                                        boost::bind(&modal_dialog_t::latch_callback, boost::ref(*this), _1, _2),
                                        size_normal_s,
                                        default_widget_factory_proc(),
                                        parent_m).release()
                                        );

        // Set up the view's sheet with display state values, etc.
        //
        view_m->layout_sheet_m.set(display_state_m);

        sheet_m.update();

        //
        // Show the GUI.
        //
        view_m->eve_m.evaluate(eve_t::evaluate_nested);
        view_m->show_window_m();
    }

    return view_m->root_display_m;
}

/****************************************************************************************************/

dialog_result_t modal_dialog_t::go()
{
    if ((display_options_m == dialog_no_display_s && need_ui_m) ||
        display_options_m == dialog_display_s)
    {
        platform_display_type dlg = view_m->root_display_m;
        dlg->Run();

#if ADOBE_PLATFORM_MAC

        HIViewRef                            cntl(view_m->root_display_m);
        WindowRef                            owner(::GetControlOwner(cntl));
        auto_resource< ::EventLoopTimerUPP > loop_upp(::NewEventLoopTimerUPP(purge_closed_windows));
        auto_resource< ::EventLoopTimerRef > idle_timer_ref;
        ::EventLoopTimerRef                  temp_timer_ref;

        if (::InstallEventLoopTimer(::GetMainEventLoop(),
                                    1,
                                    .01,
                                    loop_upp.get(),
                                    this,
                                    &temp_timer_ref) != noErr)
            throw std::runtime_error("InstallEventLoopTimer");

        idle_timer_ref.reset(temp_timer_ref);

        raw_key_handler_t keyboard_event_monitor;

        keyboard_event_monitor.window_m = owner;
        keyboard_event_monitor.handler_m.insert(kEventClassKeyboard, kEventRawKeyDown);
//        keyboard_event_monitor.handler_m.insert(kEventClassKeyboard, kEventRawKeyUp);
        keyboard_event_monitor.handler_m.install(::GetApplicationEventTarget());

        ::ShowWindow(owner);
        ::ActivateWindow(owner, true);
        ::BringToFront(owner);

        ::RunAppModalLoopForWindow(owner);

#elif ADOBE_PLATFORM_WIN

        HWND cntl(view_m->root_display_m);

        MSG  msg;

        while ( ::GetMessage( &msg, 0, 0, 0 ) )
        {
            try
            {
                bool special_key_handled(false);

                if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN ||
                    msg.message == WM_KEYUP   || msg.message == WM_SYSKEYUP)
                {
                    special_key_handled = keyboard_t::get().dispatch(key_type(msg.wParam),
                                                                     msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN,
                                                                     modifier_state(),
                                                                     any_regular_t(cntl));
                }

                if(special_key_handled == false && ::IsDialogMessage(cntl, &msg) == false)
                {
                    //
                    // Pass the message through to the application.
                    //
                    TranslateMessage( &msg );
                    DispatchMessage( &msg );
                }
            }
            catch ( const std::exception& error )
            {
                std::cerr << "Exception: " << error.what() << std::endl;
            }
            catch ( ... )
            {
                std::cerr << "Exception: Unknown" << std::endl;
            }

            end_dialog();
        }

#endif

        result_m.display_state_m = view_m->layout_sheet_m.contributing();

        view_m.reset(0);
    }

    return result_m;
}

/****************************************************************************************************/

void modal_dialog_t::latch_callback(name_t action, const any_regular_t& value)
try
{
    assert(view_m);
    assert(callback_m);

    if (action == static_name_t("reset"))
    {
        sheet_m.set(contributing_m);
        sheet_m.update();
    }
    else if (callback_m(action, value))
    {
        result_m.terminating_action_m = action;
        view_m->root_display_m->EndRun();
    }
}
catch(const std::exception& error)
{
    std::cerr << "Exception (modal_dialog_t::latch_callback) : " << error.what() << std::endl;
}
catch(...)
{
    std::cerr << "Unknown exception (modal_dialog_t::latch_callback)" << std::endl;
}

/****************************************************************************************************/

void modal_dialog_t::display(const model_type& value)
{
    result_m.command_m = value.cast<dictionary_t>();
}

/****************************************************************************************************/

void modal_dialog_t::monitor_record(const dictionary_t& record_info)
{
    result_m.record_m = record_info;
}

/****************************************************************************************************/

void modal_dialog_t::monitor_invariant(bool is_set)
{
    need_ui_m = !is_set;
}

/****************************************************************************************************/

} // namespace adobe

/****************************************************************************************************/
<commit_msg>Cruft removal.<commit_after>/*
    Copyright 2005-2007 Adobe Systems Incorporated
    Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
    or a copy at http://stlab.adobe.com/licenses.html)
*/

/****************************************************************************************************/

#define ADOBE_DLL_SAFE 0

#include <GG/Wnd.h>

#include <GG/adobe/config.hpp>
#include <GG/adobe/future/modal_dialog_interface.hpp>
#include <GG/adobe/adam_evaluate.hpp>
#include <GG/adobe/adam_parser.hpp>
#include <GG/adobe/future/assemblage.hpp>
#include <GG/adobe/future/resources.hpp>
#include <GG/adobe/future/widgets/headers/platform_window.hpp>
#include <GG/adobe/future/widgets/headers/widget_factory.hpp>
#include <GG/adobe/future/widgets/headers/widget_utils.hpp>
#include <GG/adobe/keyboard.hpp>

#include <GG/DrawUtil.h>
#include <GG/GUI.h>
#include <GG/StyleFactory.h>
#include <GG/TextControl.h>
#include <GG/Wnd.h>

/****************************************************************************************************/

namespace GG {

/****************************************************************************************************/

    const int Window::FRAME_WIDTH = 2;
    const Pt Window::BEVEL_OFFSET(X(Window::FRAME_WIDTH), Y(Window::FRAME_WIDTH));

    Window::Window(adobe::window_t& imp) :
        Wnd(X0, Y0, X1, Y1, imp.flags_m),
        m_imp(imp),
        m_title(0)
    {
        if (!m_imp.name_m.empty()) {
            m_title = adobe::implementation::Factory().NewTextControl(
                BEVEL_OFFSET.x, BEVEL_OFFSET.y - adobe::implementation::CharHeight(),
                m_imp.name_m, adobe::implementation::DefaultFont()
            );
            AttachChild(m_title);
        }
    }

    Pt Window::ClientUpperLeft() const
    { return UpperLeft() + BEVEL_OFFSET + Pt(X0, m_title ? m_title->Height() : Y0); }

    Pt Window::ClientLowerRight() const
    { return LowerRight() - BEVEL_OFFSET; }

    WndRegion Window::WindowRegion(const Pt& pt) const
    {
        enum {LEFT = 0, MIDDLE = 1, RIGHT = 2};
        enum {TOP = 0, BOTTOM = 2};

        // window regions look like this:
        // 0111112
        // 3444445   // 4 is client area, 0,2,6,8 are corners
        // 3444445
        // 6777778

        int x_pos = MIDDLE;   // default & typical case is that the mouse is over the (non-border) client area
        int y_pos = MIDDLE;

        Pt ul = UpperLeft() + BEVEL_OFFSET, lr = LowerRight() - BEVEL_OFFSET;

        if (pt.x < ul.x)
            x_pos = LEFT;
        else if (pt.x > lr.x)
            x_pos = RIGHT;

        if (pt.y < ul.y)
            y_pos = TOP;
        else if (pt.y > lr.y)
            y_pos = BOTTOM;

        return (Resizable() ? WndRegion(x_pos + 3 * y_pos) : WR_NONE);
    }

    void Window::SizeMove(const Pt& ul, const Pt& lr)
    {
        Wnd::SizeMove(ul, lr);

        Pt client_size = ClientSize();

        if (!m_imp.debounce_m && !m_imp.resize_proc_m.empty()) {
            m_imp.debounce_m = true;

            if (adobe::width(m_imp.place_data_m) != Value(client_size.x) ||
                adobe::height(m_imp.place_data_m) != Value(client_size.y)) {
                m_imp.resize_proc_m(Value(client_size.x), Value(client_size.y));

                adobe::width(m_imp.place_data_m) = Value(client_size.x);
                adobe::height(m_imp.place_data_m) = Value(client_size.y);
            }

            m_imp.debounce_m = false;
        }

        Pt new_title_size((LowerRight() - UpperLeft()).x - BEVEL_OFFSET.x * 2, m_title->Height());
        m_title->Resize(new_title_size);
    }

    void Window::Render()
    { BeveledRectangle(UpperLeft(), LowerRight(), CLR_GRAY, CLR_GRAY, true, BEVEL); }

    void Window::KeyPress(Key key, boost::uint32_t key_code_point, Flags<ModKey> mod_keys)
    {
        adobe::keyboard_t::get().dispatch(adobe::key_type(key, key_code_point),
                                          true,
                                          adobe::modifier_state(),
                                          adobe::any_regular_t(this));
    }

    void Window::KeyRelease(Key key, boost::uint32_t key_code_point, Flags<ModKey> mod_keys)
    {
        adobe::keyboard_t::get().dispatch(adobe::key_type(key, key_code_point),
                                          false,
                                          adobe::modifier_state(),
                                          adobe::any_regular_t(this));
    }

    void Window::SetEveModalDialog(adobe::modal_dialog_t* modal_dialog)
    { m_eve_modal_dialog.reset(modal_dialog); }

} // namespace GG

/****************************************************************************************************/

namespace adobe {

/****************************************************************************************************/

std::string getline(std::istream& stream)
{
    std::string result;

    result.reserve(128);

    while (true)
    {
        int c(stream.get());

        if (c == EOF || c == '\n')
        {
            break;
        }
        else if (c == '\r')
        {
            c = stream.get();

            if (c != '\n')
                stream.putback(c);

            break;
        }

        result += static_cast<char>(c);
    }

    return result;
}

/****************************************************************************************************/

std::string mdi_error_getline(std::istream& layout_definition, name_t, std::streampos line_start_position)
{
    std::streampos old_pos(layout_definition.tellg());

    layout_definition.clear();

    layout_definition.seekg(line_start_position);

    std::string result(getline(layout_definition));

    layout_definition.seekg(old_pos);

    return result;
}

/****************************************************************************************************/

modal_dialog_t::modal_dialog_t() :
    display_options_m(dialog_display_s),
    parent_m(platform_display_type()),
    root_behavior_m(false)
{ }

/****************************************************************************************************/

platform_display_type modal_dialog_t::init(std::istream& layout, std::istream& sheet)
{
// TODO: ???    resource_context_t res_context(working_directory_m);

    vm_lookup_m.attach_to(sheet_m);
    vm_lookup_m.attach_to(sheet_m.machine_m);

    result_m = dialog_result_t();

    //
    // Parse the proprty model stream
    //

    try
    {
        parse( sheet, line_position_t( "Proprty model sheet definition" ), bind_to_sheet( sheet_m ) );
    }
    catch (const stream_error_t& error)
    {
        throw std::logic_error(format_stream_error(sheet, error));
    }
    catch (...)
    {
        throw; // here for completeness' sake
    }

    //
    // REVISIT (2006/09/28, fbrereto): The sheet initializers don't run until the first update().
    //                                 To keep them from blowing away your sets in a couple of
    //                                 lines we need to add an update before the first set()
    //                                 on the sheet (this will get fixed with the proprty model
    //                                 library rewrite so mark it with a revisit comment).
    //

    sheet_m.update();

    //
    // Set up the sheet with initial inputs, etc.
    //

    sheet_m.set(input_m);
    sheet_m.set(record_m);

    need_ui_m = false;

    sheet_m.update();

    //
    // Save off the contributing set for potential reset action later
    //

    contributing_m = sheet_m.contributing();

    //
    // Set up the callback functions now so the contributing mark is meaningful, then update again
    //

    try
    {
        name_t result_cell(static_name_t("result"));

        attach_view(assemblage_m, result_cell, *this, sheet_m);

        sheet_m.monitor_invariant_dependent(result_cell, boost::bind(&modal_dialog_t::monitor_invariant, boost::ref(*this), _1));
        sheet_m.monitor_contributing(result_cell, sheet_m.contributing(), boost::bind(&modal_dialog_t::monitor_record, boost::ref(*this), _1));
    }
    catch (...)
    {
        // result cell wasn't found. While this isn't a deal-breaker, it's not
        // going to do much in the way of getting results from this dialog.
    }

    sheet_m.update();

    if (display_options_m == dialog_never_display_s && need_ui_m)
        throw std::runtime_error("handle_dialog: Invalid command parameters and UI not permitted.");

    if ((display_options_m == dialog_no_display_s && need_ui_m) ||
        display_options_m == dialog_display_s)
    {
        line_position_t::getline_proc_t getline_proc(new line_position_t::getline_proc_impl_t(boost::bind(&mdi_error_getline, boost::ref(layout), _1, _2)));

        view_m.reset( make_view( static_name_t( "eve definition" ),
                                        getline_proc,
                                        layout,
                                        sheet_m,
                                        root_behavior_m,
                                        boost::bind(&modal_dialog_t::latch_callback, boost::ref(*this), _1, _2),
                                        size_normal_s,
                                        default_widget_factory_proc(),
                                        parent_m).release()
                                        );

        // Set up the view's sheet with display state values, etc.
        //
        view_m->layout_sheet_m.set(display_state_m);

        sheet_m.update();

        //
        // Show the GUI.
        //
        view_m->eve_m.evaluate(eve_t::evaluate_nested);
        view_m->show_window_m();
    }

    return view_m->root_display_m;
}

/****************************************************************************************************/

dialog_result_t modal_dialog_t::go()
{
    if ((display_options_m == dialog_no_display_s && need_ui_m) ||
        display_options_m == dialog_display_s)
    {
        platform_display_type dlg = view_m->root_display_m;
        dlg->Run();
        result_m.display_state_m = view_m->layout_sheet_m.contributing();
        view_m.reset(0);
    }

    return result_m;
}

/****************************************************************************************************/

void modal_dialog_t::latch_callback(name_t action, const any_regular_t& value)
try
{
    assert(view_m);
    assert(callback_m);

    if (action == static_name_t("reset"))
    {
        sheet_m.set(contributing_m);
        sheet_m.update();
    }
    else if (callback_m(action, value))
    {
        result_m.terminating_action_m = action;
        view_m->root_display_m->EndRun();
    }
}
catch(const std::exception& error)
{
    std::cerr << "Exception (modal_dialog_t::latch_callback) : " << error.what() << std::endl;
}
catch(...)
{
    std::cerr << "Unknown exception (modal_dialog_t::latch_callback)" << std::endl;
}

/****************************************************************************************************/

void modal_dialog_t::display(const model_type& value)
{
    result_m.command_m = value.cast<dictionary_t>();
}

/****************************************************************************************************/

void modal_dialog_t::monitor_record(const dictionary_t& record_info)
{
    result_m.record_m = record_info;
}

/****************************************************************************************************/

void modal_dialog_t::monitor_invariant(bool is_set)
{
    need_ui_m = !is_set;
}

/****************************************************************************************************/

} // namespace adobe

/****************************************************************************************************/
<|endoftext|>