<commit_before>#include "llvm/Support/DebugCounter.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Options.h"

using namespace llvm;

namespace {
// This class overrides the default list implementation of printing so we
// can pretty print the list of debug counter options.  This type of
// dynamic option is pretty rare (basically this and pass lists).
class DebugCounterList : public cl::list<std::string, DebugCounter> {
private:
  using Base = cl::list<std::string, DebugCounter>;

public:
  template <class... Mods>
  explicit DebugCounterList(Mods &&... Ms) : Base(std::forward<Mods>(Ms)...) {}

private:
  void printOptionInfo(size_t GlobalWidth) const override {
    // This is a variant of from generic_parser_base::printOptionInfo.  Sadly,
    // it's not easy to make it more usable.  We could get it to print these as
    // options if we were a cl::opt and registered them, but lists don't have
    // options, nor does the parser for std::string.  The other mechanisms for
    // options are global and would pollute the global namespace with our
    // counters.  Rather than go that route, we have just overridden the
    // printing, which only a few things call anyway.
    outs() << "  -" << ArgStr;
    // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for
    // width, so we do the same.
    Option::printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6);
    const auto &CounterInstance = DebugCounter::instance();
    for (auto Name : CounterInstance) {
      const auto Info =
          CounterInstance.getCounterInfo(CounterInstance.getCounterId(Name));
      size_t NumSpaces = GlobalWidth - Info.first.size() - 8;
      outs() << "    =" << Info.first;
      outs().indent(NumSpaces) << " -   " << Info.second << '\n';
    }
  }
};
} // namespace

// Create our command line option.
static DebugCounterList DebugCounterOption(
    "debug-counter", cl::Hidden,
    cl::desc("Comma separated list of debug counter skip and count"),
    cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance()));

static ManagedStatic<DebugCounter> DC;

DebugCounter &DebugCounter::instance() { return *DC; }

// This is called by the command line parser when it sees a value for the
// debug-counter option defined above.
void DebugCounter::push_back(const std::string &Val) {
  if (Val.empty())
    return;
  // The strings should come in as counter=value
  auto CounterPair = StringRef(Val).split('=');
  if (CounterPair.second.empty()) {
    errs() << "DebugCounter Error: " << Val << " does not have an = in it\n";
    return;
  }
  // Now we have counter=value.
  // First, process value.
  int64_t CounterVal;
  if (CounterPair.second.getAsInteger(0, CounterVal)) {
    errs() << "DebugCounter Error: " << CounterPair.second
           << " is not a number\n";
    return;
  }
  // Now we need to see if this is the skip or the count, remove the suffix, and
  // add it to the counter values.
  if (CounterPair.first.endswith("-skip")) {
    auto CounterName = CounterPair.first.drop_back(5);
    unsigned CounterID = getCounterId(CounterName);
    if (!CounterID) {
      errs() << "DebugCounter Error: " << CounterName
             << " is not a registered counter\n";
      return;
    }
    enableAllCounters();
    Counters[CounterID].Skip = CounterVal;
    Counters[CounterID].IsSet = true;
  } else if (CounterPair.first.endswith("-count")) {
    auto CounterName = CounterPair.first.drop_back(6);
    unsigned CounterID = getCounterId(CounterName);
    if (!CounterID) {
      errs() << "DebugCounter Error: " << CounterName
             << " is not a registered counter\n";
      return;
    }
    enableAllCounters();
    Counters[CounterID].StopAfter = CounterVal;
    Counters[CounterID].IsSet = true;
  } else {
    errs() << "DebugCounter Error: " << CounterPair.first
           << " does not end with -skip or -count\n";
  }
}

void DebugCounter::print(raw_ostream &OS) const {
  OS << "Counters and values:\n";
  for (const auto &KV : Counters)
    OS << left_justify(RegisteredCounters[KV.first], 32) << ": {"
       << KV.second.Count << "," << KV.second.Skip << ","
       << KV.second.StopAfter << "}\n";
}

LLVM_DUMP_METHOD void DebugCounter::dump() const {
  print(dbgs());
}
<commit_msg>[DebugCounters] don't do redundant map lookups; NFC<commit_after>#include "llvm/Support/DebugCounter.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Options.h"

using namespace llvm;

namespace {
// This class overrides the default list implementation of printing so we
// can pretty print the list of debug counter options.  This type of
// dynamic option is pretty rare (basically this and pass lists).
class DebugCounterList : public cl::list<std::string, DebugCounter> {
private:
  using Base = cl::list<std::string, DebugCounter>;

public:
  template <class... Mods>
  explicit DebugCounterList(Mods &&... Ms) : Base(std::forward<Mods>(Ms)...) {}

private:
  void printOptionInfo(size_t GlobalWidth) const override {
    // This is a variant of from generic_parser_base::printOptionInfo.  Sadly,
    // it's not easy to make it more usable.  We could get it to print these as
    // options if we were a cl::opt and registered them, but lists don't have
    // options, nor does the parser for std::string.  The other mechanisms for
    // options are global and would pollute the global namespace with our
    // counters.  Rather than go that route, we have just overridden the
    // printing, which only a few things call anyway.
    outs() << "  -" << ArgStr;
    // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for
    // width, so we do the same.
    Option::printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6);
    const auto &CounterInstance = DebugCounter::instance();
    for (auto Name : CounterInstance) {
      const auto Info =
          CounterInstance.getCounterInfo(CounterInstance.getCounterId(Name));
      size_t NumSpaces = GlobalWidth - Info.first.size() - 8;
      outs() << "    =" << Info.first;
      outs().indent(NumSpaces) << " -   " << Info.second << '\n';
    }
  }
};
} // namespace

// Create our command line option.
static DebugCounterList DebugCounterOption(
    "debug-counter", cl::Hidden,
    cl::desc("Comma separated list of debug counter skip and count"),
    cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance()));

static ManagedStatic<DebugCounter> DC;

DebugCounter &DebugCounter::instance() { return *DC; }

// This is called by the command line parser when it sees a value for the
// debug-counter option defined above.
void DebugCounter::push_back(const std::string &Val) {
  if (Val.empty())
    return;
  // The strings should come in as counter=value
  auto CounterPair = StringRef(Val).split('=');
  if (CounterPair.second.empty()) {
    errs() << "DebugCounter Error: " << Val << " does not have an = in it\n";
    return;
  }
  // Now we have counter=value.
  // First, process value.
  int64_t CounterVal;
  if (CounterPair.second.getAsInteger(0, CounterVal)) {
    errs() << "DebugCounter Error: " << CounterPair.second
           << " is not a number\n";
    return;
  }
  // Now we need to see if this is the skip or the count, remove the suffix, and
  // add it to the counter values.
  if (CounterPair.first.endswith("-skip")) {
    auto CounterName = CounterPair.first.drop_back(5);
    unsigned CounterID = getCounterId(CounterName);
    if (!CounterID) {
      errs() << "DebugCounter Error: " << CounterName
             << " is not a registered counter\n";
      return;
    }
    enableAllCounters();

    CounterInfo &Counter = Counters[CounterID];
    Counter.Skip = CounterVal;
    Counter.IsSet = true;
  } else if (CounterPair.first.endswith("-count")) {
    auto CounterName = CounterPair.first.drop_back(6);
    unsigned CounterID = getCounterId(CounterName);
    if (!CounterID) {
      errs() << "DebugCounter Error: " << CounterName
             << " is not a registered counter\n";
      return;
    }
    enableAllCounters();

    CounterInfo &Counter = Counters[CounterID];
    Counter.StopAfter = CounterVal;
    Counter.IsSet = true;
  } else {
    errs() << "DebugCounter Error: " << CounterPair.first
           << " does not end with -skip or -count\n";
  }
}

void DebugCounter::print(raw_ostream &OS) const {
  OS << "Counters and values:\n";
  for (const auto &KV : Counters)
    OS << left_justify(RegisteredCounters[KV.first], 32) << ": {"
       << KV.second.Count << "," << KV.second.Skip << ","
       << KV.second.StopAfter << "}\n";
}

LLVM_DUMP_METHOD void DebugCounter::dump() const {
  print(dbgs());
}
<|endoftext|>


<commit_before>#include "NotifierTestHelper.h"
#include "NotifierTest.h"
#include <FileIO.h>
#include <Shotgun.h>
#include <Rifle.h>
#include <Alien.h>
#include <Vampire.h>
#include "Listener.h"
#include "Notifier.h"
#include <StopWatch.h>
#include <Result.h>

namespace {

   const std::string notifierQueue = "ipc:///tmp/RestartServicesQueue.ipc";
   const std::string notifierQueuePath = "/tmp/RestartServicesQueue.ipc";
   const std::string handshakeQueue = "ipc:///tmp/RestartServicesHandshakeQueue.ipc";
   const std::string handshakeQueuePath = "/tmp/RestartServicesHandshakeQueue.ipc";
   const std::string messageToSend = "Craig is cool";
   const std::vector<std::string> vectorToSend = {"Craig", "is", "cool"};
   enum SendMessageType {NONE = 0, MSG = 1, VECTOR = 2};
   SendMessageType SEND_MSG_TYPE = NONE;

   void HandleNotification(std::unique_ptr<Listener> const &listener, TestThreadData& threadData) {
      bool confirmed = false;
      std::vector<std::string> messagesReceived = listener->GetMessages();
      if (threadData.kExpectedFeedback > 0) {
         confirmed = listener->SendConfirmation();
         if (!confirmed) {
            ADD_FAILURE() << "Failed to send feedback, thread #" << std::this_thread::get_id();
         }
      }
      if (!messagesReceived.empty()) {
         UpdateThreadDataAfterReceivingMessage(threadData, messagesReceived);
      } else {
         UpdateThreadDataAfterReceivingMessage(threadData);
      }
   }

   void* ReceiverThread(void* args) {
      TestThreadData* tmpRawPtr = reinterpret_cast<TestThreadData*>(args);
      CHECK(tmpRawPtr != nullptr);
      TestThreadData threadData(*tmpRawPtr);
      std::shared_ptr<void*> raiiExitFlag(nullptr, [threadData](void*) {
         threadData.hasExited->store(true);
         LOG(INFO) << "exiting thread: " << threadData.hasExited->load();
      });

      auto listener = Listener::CreateListener(notifierQueue, handshakeQueue, "TestThread");
      if (listener.get() == nullptr) {
         ADD_FAILURE() << "Failed to create listener, thread #" << std::this_thread::get_id();
         return nullptr;
      }

      NotifyParentThatChildHasStarted(threadData);
      StopWatch timer;

      while (ParentHasNotSentExitSignal(threadData) && !MaxTimeoutHasOccurred(timer)) {
         if (listener->NotificationReceived()) {
            HandleNotification(listener, threadData);
         }
      }
      const bool timeout = MaxTimeoutHasOccurred(timer);
      LOG(INFO) << "Exiting loop. Parent stated: keep running: " << threadData.keepRunning->load() << ", timeout: " << timeout;
      if (timeout) {
         ADD_FAILURE() << "Receiver thread has timed out after " << kMaxWaitTimeInSec << " seconds.";
      }
      LOG(INFO) << threadData.print();
      return nullptr;
   }

   void* SenderThread(void* args) {
      TestThreadData* tmpRawPtr = reinterpret_cast<TestThreadData*>(args);
      CHECK(tmpRawPtr != nullptr);
      TestThreadData threadData(*tmpRawPtr);
      auto notifier = Notifier::CreateNotifier(notifierQueue, handshakeQueue, threadData.kExpectedFeedback);
      std::shared_ptr<void*> raiiExitFlag(nullptr, [threadData](void*) { threadData.hasExited->store(true); });
      const bool initialized = notifier.get() != nullptr;
      if (false == initialized) {
         ADD_FAILURE() << "Failed to initialize the Notifier";
         return nullptr;
      }
      NotifyParentThatChildHasStarted(threadData);

      while (ParentHasNotSentExitSignal(threadData)) {
         if (TimeToSendANotification(threadData)) {
            switch(SEND_MSG_TYPE) {
               case NONE:
                  EXPECT_EQ(notifier->Notify(), threadData.kExpectedFeedback);
                  break;
               case MSG:
                  EXPECT_EQ(notifier->Notify(messageToSend), threadData.kExpectedFeedback);
                  break;
               case VECTOR:
                  EXPECT_EQ(notifier->Notify(vectorToSend), threadData.kExpectedFeedback);
                  break;
            }
            ResetNotifyFlag(threadData);
         }
      }
      LOG(INFO) << threadData.print();
      return nullptr;
   }

   void CheckReturnedVector(const std::vector<TestThreadData>& threadDataVector) {
      for (unsigned int idx = 0; idx < vectorToSend.size(); idx++) {
         for (auto& threadData : threadDataVector) {
            EXPECT_EQ(vectorToSend.at(idx), threadData.messages->at(idx));
         }
      }
   }

   void SpawnSender_WaitForStartup(TestThreadData& senderData) {
      zthread_new(&SenderThread, reinterpret_cast<TestThreadData*>(&senderData));
      EXPECT_TRUE(SleepUntilCondition({{senderData.hasStarted}}));
      EXPECT_TRUE(FileIO::DoesFileExist(notifierQueuePath));
      EXPECT_TRUE(FileIO::DoesFileExist(handshakeQueuePath));
   }

   void SpawnReceiver_WaitForStartup(TestThreadData& receiverData) {
      zthread_new(&ReceiverThread, reinterpret_cast<TestThreadData*>(&receiverData));
      EXPECT_TRUE(SleepUntilCondition({{receiverData.hasStarted}}));
   }

   void ExchangeNotification(TestThreadData& senderData, TestThreadData& receiverData) {
      FireOffANotification(senderData);
      EXPECT_TRUE(SleepUntilCondition({{receiverData.received}}));
   }

   void ExchangeNotification2Receivers(TestThreadData& senderData,
                                       TestThreadData& receiver1ThreadData,
                                       TestThreadData& receiver2ThreadData) {
      FireOffANotification(senderData);
      EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.received}, {receiver2ThreadData.received}}));
   }

   void VerifySingleMessage(TestThreadData& receiverData) {
      ASSERT_EQ(receiverData.messages->size(), 1);
      EXPECT_EQ(receiverData.messages->at(0), messageToSend);
   }

   void Shutdown(std::vector<TestThreadData> threads) {
      ShutdownThreads(threads);
      for (auto& thread : threads) {
         EXPECT_TRUE(SleepUntilCondition({{thread.hasExited}}));
         EXPECT_TRUE(ThreadIsShutdown(thread));
      }
   }
} //namespace

TEST_F(NotifierTest, InitializationCreatesIPC) {
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));
   const size_t ignoredHandshakes = 0;
   auto notifier = Notifier::CreateNotifier(notifierQueue, handshakeQueue, ignoredHandshakes);
   EXPECT_NE(notifier.get(), nullptr);
   EXPECT_TRUE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_TRUE(FileIO::DoesFileExist(handshakeQueuePath));
}

TEST_F(NotifierTest, 1Message1Receiver_NoResponse_WithMessage) {
   SEND_MSG_TYPE = MSG;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);

   ExchangeNotification(senderData, receiver1ThreadData);

   VerifySingleMessage(receiver1ThreadData);

   Shutdown({senderData, receiver1ThreadData});
}

TEST_F(NotifierTest, 1Message1Receiver_NoResponse_NoMessage) {
   SEND_MSG_TYPE = NONE;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);

   ExchangeNotification(senderData, receiver1ThreadData);

   Shutdown({senderData, receiver1ThreadData});
}

TEST_F(NotifierTest, 1Message1Receiver_NoResponse_VectorMessage) {
   SEND_MSG_TYPE = VECTOR;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);

   ExchangeNotification(senderData, receiver1ThreadData);
   CheckReturnedVector({receiver1ThreadData});

   Shutdown({senderData, receiver1ThreadData});
}

TEST_F(NotifierTest, 1Message2Receivers_ExpectFeedback_NoMessage) {
   SEND_MSG_TYPE = NONE;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver1");
   TestThreadData receiver2ThreadData("receiver2");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   ExchangeNotification2Receivers(senderData, receiver1ThreadData, receiver2ThreadData);

   Shutdown({senderData, receiver2ThreadData, receiver1ThreadData});
}

TEST_F(NotifierTest, 1Message2Receivers_ExpectFeedback_SingleMessage) {
   SEND_MSG_TYPE = MSG;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver1");
   TestThreadData receiver2ThreadData("receiver2");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   // Spawn Receivers and wait for them to start up
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   ExchangeNotification2Receivers(senderData, receiver1ThreadData, receiver2ThreadData);
   VerifySingleMessage(receiver1ThreadData);
   VerifySingleMessage(receiver2ThreadData);

   Shutdown({senderData, receiver1ThreadData, receiver2ThreadData});
}

TEST_F(NotifierTest, 1Message2Receivers_ExpectFeedback_VectorMessage) {
   SEND_MSG_TYPE = VECTOR;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver1");
   TestThreadData receiver2ThreadData("receiver2");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   // Spawn Receivers and wait for them to start up
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   ExchangeNotification2Receivers(senderData, receiver1ThreadData, receiver2ThreadData);
   CheckReturnedVector({{receiver1ThreadData}});

   Shutdown({senderData, receiver1ThreadData, receiver2ThreadData});
}

TEST_F(NotifierTest, 2Messages2Receivers_RestartReceivers_ExpectFeedback_NoMessage) {
   SEND_MSG_TYPE = NONE;
   const size_t expectedFeedback = 2;
   const size_t sendFeedback = 1;
   TestThreadData senderData{"sender", expectedFeedback};
   TestThreadData receiver1ThreadData{"receiver1", sendFeedback};
   TestThreadData receiver2ThreadData{"receiver2", sendFeedback};
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   ExchangeNotification2Receivers(senderData, receiver2ThreadData, receiver2ThreadData);

   // Shutdown the receiver threads
   Shutdown({receiver1ThreadData, receiver2ThreadData});
   EXPECT_FALSE(ThreadIsShutdown(senderData));
   receiver1ThreadData.reset();
   receiver2ThreadData.reset();

   // Respawn the Receivers
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // Second Exchange
   ExchangeNotification2Receivers(senderData, receiver2ThreadData, receiver2ThreadData);

   // Shutdown everything
   Shutdown({senderData, receiver1ThreadData, receiver2ThreadData});
}

TEST_F(NotifierTest, 2Messages2Receivers_RestartReceivers_ExpectFeedback_SingleMessage) {
   SEND_MSG_TYPE = MSG;
   const size_t expectedFeedback = 2;
   const size_t sendFeedback = 1;
   TestThreadData senderData{"sender", expectedFeedback};
   TestThreadData receiver1ThreadData{"receiver1", sendFeedback};
   TestThreadData receiver2ThreadData{"receiver2", sendFeedback};
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   FireOffANotification(senderData);
   EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.received}, {receiver2ThreadData.received}}));
   EXPECT_TRUE(receiver1ThreadData.received->load());
   EXPECT_TRUE(receiver2ThreadData.received->load());
   EXPECT_EQ(1, receiver1ThreadData.messages->size());
   EXPECT_EQ(1, receiver2ThreadData.messages->size());
   ASSERT_EQ(messageToSend, receiver1ThreadData.messages->at(0));
   ASSERT_EQ(messageToSend, receiver2ThreadData.messages->at(0));

   // Shutdown the receiver threads
   ShutdownThreads({{receiver1ThreadData}, {receiver2ThreadData}});
   EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.hasExited}, {receiver2ThreadData.hasExited}}));
   ShutdownThreads({{receiver1ThreadData}, {receiver2ThreadData}});
   EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.hasExited}, {receiver2ThreadData.hasExited}}));
   EXPECT_TRUE(ThreadIsShutdown(receiver1ThreadData));
   EXPECT_TRUE(ThreadIsShutdown(receiver2ThreadData));
   EXPECT_FALSE(ThreadIsShutdown(senderData));
   receiver1ThreadData.reset();
   receiver2ThreadData.reset();

   // Respawn the Receivers
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // Second Exchange
   FireOffANotification(senderData);
   EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.received}, {receiver2ThreadData.received}}));
   EXPECT_TRUE(receiver1ThreadData.received->load());
   EXPECT_TRUE(receiver2ThreadData.received->load());
   EXPECT_EQ(1, receiver1ThreadData.messages->size());
   EXPECT_EQ(1, receiver2ThreadData.messages->size());
   ASSERT_EQ(messageToSend, receiver1ThreadData.messages->at(0));
   ASSERT_EQ(messageToSend, receiver2ThreadData.messages->at(0));

   // Shutdown everything
   ShutdownThreads({{senderData}, {receiver1ThreadData}, {receiver2ThreadData}});
   EXPECT_TRUE(SleepUntilCondition({{senderData.hasExited}}));
   EXPECT_TRUE(SleepUntilCondition({{senderData.hasExited}}));
   EXPECT_TRUE(SleepUntilCondition({{receiver2ThreadData.hasExited}}));
   EXPECT_TRUE(ThreadIsShutdown(receiver1ThreadData));
   EXPECT_TRUE(ThreadIsShutdown(receiver2ThreadData));
   EXPECT_TRUE(ThreadIsShutdown(senderData));
}

TEST_F(NotifierTest, 2Messages2Receivers_RestartReceivers_ExpectFeedback_VectorMessage) {
   SEND_MSG_TYPE = VECTOR;
   const size_t expectedFeedback = 2;
   const size_t sendFeedback = 1;
   TestThreadData senderData{"sender", expectedFeedback};
   TestThreadData receiver1ThreadData{"receiver1", sendFeedback};
   TestThreadData receiver2ThreadData{"receiver2", sendFeedback};
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   // Spawn 2 Listeners and wait for them to start up
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   FireOffANotification(senderData);
   EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.received}, {receiver2ThreadData.received}}));
   EXPECT_TRUE(receiver1ThreadData.received->load());
   EXPECT_TRUE(receiver2ThreadData.received->load());
   ASSERT_EQ(receiver1ThreadData.messages->size(), vectorToSend.size());
   ASSERT_EQ(receiver2ThreadData.messages->size(), vectorToSend.size());
   CheckReturnedVector({{receiver1ThreadData}, {receiver2ThreadData}});

   // Shutdown the receiver threads
   ShutdownThreads({{receiver1ThreadData}, {receiver2ThreadData}});
   EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.hasExited}, {receiver2ThreadData.hasExited}}));
   ShutdownThreads({{receiver1ThreadData}, {receiver2ThreadData}});
   EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.hasExited}, {receiver2ThreadData.hasExited}}));
   EXPECT_TRUE(ThreadIsShutdown(receiver1ThreadData));
   EXPECT_TRUE(ThreadIsShutdown(receiver2ThreadData));
   EXPECT_FALSE(ThreadIsShutdown(senderData));
   receiver1ThreadData.reset();
   receiver2ThreadData.reset();

   // Respawn the Receivers
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // Second Exchange
   FireOffANotification(senderData);
   EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.received}, {receiver2ThreadData.received}}));
   EXPECT_TRUE(receiver1ThreadData.received->load());
   EXPECT_TRUE(receiver2ThreadData.received->load());
   ASSERT_EQ(receiver1ThreadData.messages->size(), vectorToSend.size());
   ASSERT_EQ(receiver2ThreadData.messages->size(), vectorToSend.size());
   CheckReturnedVector({{receiver1ThreadData}, {receiver2ThreadData}});

   // Shutdown everything
   ShutdownThreads({{senderData}, {receiver1ThreadData}, {receiver2ThreadData}});
   EXPECT_TRUE(SleepUntilCondition({{senderData.hasExited}}));
   EXPECT_TRUE(SleepUntilCondition({{senderData.hasExited}}));
   EXPECT_TRUE(SleepUntilCondition({{receiver2ThreadData.hasExited}}));
   EXPECT_TRUE(ThreadIsShutdown(receiver1ThreadData));
   EXPECT_TRUE(ThreadIsShutdown(receiver2ThreadData));
   EXPECT_TRUE(ThreadIsShutdown(senderData));
}<commit_msg>Fully refactored tests<commit_after>#include "NotifierTestHelper.h"
#include "NotifierTest.h"
#include <FileIO.h>
#include <Shotgun.h>
#include <Rifle.h>
#include <Alien.h>
#include <Vampire.h>
#include "Listener.h"
#include "Notifier.h"
#include <StopWatch.h>
#include <Result.h>

namespace {

   const std::string notifierQueue = "ipc:///tmp/RestartServicesQueue.ipc";
   const std::string notifierQueuePath = "/tmp/RestartServicesQueue.ipc";
   const std::string handshakeQueue = "ipc:///tmp/RestartServicesHandshakeQueue.ipc";
   const std::string handshakeQueuePath = "/tmp/RestartServicesHandshakeQueue.ipc";
   const std::string messageToSend = "Craig is cool";
   const std::vector<std::string> vectorToSend = {"Craig", "is", "cool"};
   enum SendMessageType {NONE = 0, MSG = 1, VECTOR = 2};
   SendMessageType SEND_MSG_TYPE = NONE;

   void HandleNotification(std::unique_ptr<Listener> const &listener, TestThreadData& threadData) {
      bool confirmed = false;
      std::vector<std::string> messagesReceived = listener->GetMessages();
      if (threadData.kExpectedFeedback > 0) {
         confirmed = listener->SendConfirmation();
         if (!confirmed) {
            ADD_FAILURE() << "Failed to send feedback, thread #" << std::this_thread::get_id();
         }
      }
      if (!messagesReceived.empty()) {
         UpdateThreadDataAfterReceivingMessage(threadData, messagesReceived);
      } else {
         UpdateThreadDataAfterReceivingMessage(threadData);
      }
   }

   void* ReceiverThread(void* args) {
      TestThreadData* tmpRawPtr = reinterpret_cast<TestThreadData*>(args);
      CHECK(tmpRawPtr != nullptr);
      TestThreadData threadData(*tmpRawPtr);
      std::shared_ptr<void*> raiiExitFlag(nullptr, [threadData](void*) {
         threadData.hasExited->store(true);
         LOG(INFO) << "exiting thread: " << threadData.hasExited->load();
      });

      auto listener = Listener::CreateListener(notifierQueue, handshakeQueue, "TestThread");
      if (listener.get() == nullptr) {
         ADD_FAILURE() << "Failed to create listener, thread #" << std::this_thread::get_id();
         return nullptr;
      }

      NotifyParentThatChildHasStarted(threadData);
      StopWatch timer;

      while (ParentHasNotSentExitSignal(threadData) && !MaxTimeoutHasOccurred(timer)) {
         if (listener->NotificationReceived()) {
            HandleNotification(listener, threadData);
         }
      }
      const bool timeout = MaxTimeoutHasOccurred(timer);
      LOG(INFO) << "Exiting loop. Parent stated: keep running: " << threadData.keepRunning->load() << ", timeout: " << timeout;
      if (timeout) {
         ADD_FAILURE() << "Receiver thread has timed out after " << kMaxWaitTimeInSec << " seconds.";
      }
      LOG(INFO) << threadData.print();
      return nullptr;
   }

   void* SenderThread(void* args) {
      TestThreadData* tmpRawPtr = reinterpret_cast<TestThreadData*>(args);
      CHECK(tmpRawPtr != nullptr);
      TestThreadData threadData(*tmpRawPtr);
      auto notifier = Notifier::CreateNotifier(notifierQueue, handshakeQueue, threadData.kExpectedFeedback);
      std::shared_ptr<void*> raiiExitFlag(nullptr, [threadData](void*) { threadData.hasExited->store(true); });
      const bool initialized = notifier.get() != nullptr;
      if (false == initialized) {
         ADD_FAILURE() << "Failed to initialize the Notifier";
         return nullptr;
      }
      NotifyParentThatChildHasStarted(threadData);

      while (ParentHasNotSentExitSignal(threadData)) {
         if (TimeToSendANotification(threadData)) {
            switch(SEND_MSG_TYPE) {
               case NONE:
                  EXPECT_EQ(notifier->Notify(), threadData.kExpectedFeedback);
                  break;
               case MSG:
                  EXPECT_EQ(notifier->Notify(messageToSend), threadData.kExpectedFeedback);
                  break;
               case VECTOR:
                  EXPECT_EQ(notifier->Notify(vectorToSend), threadData.kExpectedFeedback);
                  break;
            }
            ResetNotifyFlag(threadData);
         }
      }
      LOG(INFO) << threadData.print();
      return nullptr;
   }

   void CheckReturnedVector(const std::vector<TestThreadData>& threadDataVector) {
      for (unsigned int idx = 0; idx < vectorToSend.size(); idx++) {
         for (auto& threadData : threadDataVector) {
            EXPECT_EQ(vectorToSend.at(idx), threadData.messages->at(idx));
         }
      }
   }

   void SpawnSender_WaitForStartup(TestThreadData& senderData) {
      zthread_new(&SenderThread, reinterpret_cast<TestThreadData*>(&senderData));
      EXPECT_TRUE(SleepUntilCondition({{senderData.hasStarted}}));
      EXPECT_TRUE(FileIO::DoesFileExist(notifierQueuePath));
      EXPECT_TRUE(FileIO::DoesFileExist(handshakeQueuePath));
   }

   void SpawnReceiver_WaitForStartup(TestThreadData& receiverData) {
      zthread_new(&ReceiverThread, reinterpret_cast<TestThreadData*>(&receiverData));
      EXPECT_TRUE(SleepUntilCondition({{receiverData.hasStarted}}));
   }

   void ExchangeNotification(TestThreadData& senderData, TestThreadData& receiverData) {
      FireOffANotification(senderData);
      EXPECT_TRUE(SleepUntilCondition({{receiverData.received}}));
   }

   void ExchangeNotification2Receivers(TestThreadData& senderData,
                                       TestThreadData& receiver1ThreadData,
                                       TestThreadData& receiver2ThreadData) {
      FireOffANotification(senderData);
      EXPECT_TRUE(SleepUntilCondition({{receiver1ThreadData.received}, {receiver2ThreadData.received}}));
   }

   void VerifySingleMessage(TestThreadData& receiverData) {
      ASSERT_EQ(receiverData.messages->size(), 1);
      EXPECT_EQ(receiverData.messages->at(0), messageToSend);
   }

   void Shutdown(std::vector<TestThreadData> threads) {
      ShutdownThreads(threads);
      for (auto& thread : threads) {
         EXPECT_TRUE(SleepUntilCondition({{thread.hasExited}}));
         EXPECT_TRUE(ThreadIsShutdown(thread));
      }
   }
} //namespace

TEST_F(NotifierTest, InitializationCreatesIPC) {
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));
   const size_t ignoredHandshakes = 0;
   auto notifier = Notifier::CreateNotifier(notifierQueue, handshakeQueue, ignoredHandshakes);
   EXPECT_NE(notifier.get(), nullptr);
   EXPECT_TRUE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_TRUE(FileIO::DoesFileExist(handshakeQueuePath));
}

TEST_F(NotifierTest, 1Message1Receiver_NoResponse_WithMessage) {
   SEND_MSG_TYPE = MSG;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);

   ExchangeNotification(senderData, receiver1ThreadData);

   VerifySingleMessage(receiver1ThreadData);

   Shutdown({senderData, receiver1ThreadData});
}

TEST_F(NotifierTest, 1Message1Receiver_NoResponse_NoMessage) {
   SEND_MSG_TYPE = NONE;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);

   ExchangeNotification(senderData, receiver1ThreadData);

   Shutdown({senderData, receiver1ThreadData});
}

TEST_F(NotifierTest, 1Message1Receiver_NoResponse_VectorMessage) {
   SEND_MSG_TYPE = VECTOR;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);

   ExchangeNotification(senderData, receiver1ThreadData);
   CheckReturnedVector({receiver1ThreadData});

   Shutdown({senderData, receiver1ThreadData});
}

TEST_F(NotifierTest, 1Message2Receivers_ExpectFeedback_NoMessage) {
   SEND_MSG_TYPE = NONE;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver1");
   TestThreadData receiver2ThreadData("receiver2");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   ExchangeNotification2Receivers(senderData, receiver1ThreadData, receiver2ThreadData);

   Shutdown({senderData, receiver2ThreadData, receiver1ThreadData});
}

TEST_F(NotifierTest, 1Message2Receivers_ExpectFeedback_SingleMessage) {
   SEND_MSG_TYPE = MSG;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver1");
   TestThreadData receiver2ThreadData("receiver2");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   // Spawn Receivers and wait for them to start up
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   ExchangeNotification2Receivers(senderData, receiver1ThreadData, receiver2ThreadData);
   VerifySingleMessage(receiver1ThreadData);
   VerifySingleMessage(receiver2ThreadData);

   Shutdown({senderData, receiver1ThreadData, receiver2ThreadData});
}

TEST_F(NotifierTest, 1Message2Receivers_ExpectFeedback_VectorMessage) {
   SEND_MSG_TYPE = VECTOR;
   TestThreadData senderData("sender");
   TestThreadData receiver1ThreadData("receiver1");
   TestThreadData receiver2ThreadData("receiver2");
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   // Spawn Receivers and wait for them to start up
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   ExchangeNotification2Receivers(senderData, receiver1ThreadData, receiver2ThreadData);
   CheckReturnedVector({{receiver1ThreadData}});

   Shutdown({senderData, receiver1ThreadData, receiver2ThreadData});
}

TEST_F(NotifierTest, 2Messages2Receivers_RestartReceivers_ExpectFeedback_NoMessage) {
   SEND_MSG_TYPE = NONE;
   const size_t expectedFeedback = 2;
   const size_t sendFeedback = 1;
   TestThreadData senderData{"sender", expectedFeedback};
   TestThreadData receiver1ThreadData{"receiver1", sendFeedback};
   TestThreadData receiver2ThreadData{"receiver2", sendFeedback};
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   ExchangeNotification2Receivers(senderData, receiver2ThreadData, receiver2ThreadData);

   // Shutdown the receiver threads
   Shutdown({receiver1ThreadData, receiver2ThreadData});
   EXPECT_FALSE(ThreadIsShutdown(senderData));
   receiver1ThreadData.reset();
   receiver2ThreadData.reset();

   // Respawn the Receivers
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // Second Exchange
   ExchangeNotification2Receivers(senderData, receiver2ThreadData, receiver2ThreadData);

   // Shutdown everything
   Shutdown({senderData, receiver1ThreadData, receiver2ThreadData});
}

TEST_F(NotifierTest, 2Messages2Receivers_RestartReceivers_ExpectFeedback_SingleMessage) {
   SEND_MSG_TYPE = MSG;
   const size_t expectedFeedback = 2;
   const size_t sendFeedback = 1;
   TestThreadData senderData{"sender", expectedFeedback};
   TestThreadData receiver1ThreadData{"receiver1", sendFeedback};
   TestThreadData receiver2ThreadData{"receiver2", sendFeedback};
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   ExchangeNotification2Receivers(senderData, receiver2ThreadData, receiver2ThreadData);
   VerifySingleMessage(receiver1ThreadData);
   VerifySingleMessage(receiver2ThreadData);

   // Shutdown the receiver threads
   Shutdown({receiver1ThreadData, receiver2ThreadData});
   EXPECT_FALSE(ThreadIsShutdown(senderData));
   receiver1ThreadData.reset();
   receiver2ThreadData.reset();

   // Respawn the Receivers
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // Second Exchange
   ExchangeNotification2Receivers(senderData, receiver2ThreadData, receiver2ThreadData);
   VerifySingleMessage(receiver1ThreadData);
   VerifySingleMessage(receiver2ThreadData);

   // Shutdown everything
   Shutdown({senderData, receiver1ThreadData, receiver2ThreadData});
}

TEST_F(NotifierTest, 2Messages2Receivers_RestartReceivers_ExpectFeedback_VectorMessage) {
   SEND_MSG_TYPE = VECTOR;
   const size_t expectedFeedback = 2;
   const size_t sendFeedback = 1;
   TestThreadData senderData{"sender", expectedFeedback};
   TestThreadData receiver1ThreadData{"receiver1", sendFeedback};
   TestThreadData receiver2ThreadData{"receiver2", sendFeedback};
   EXPECT_FALSE(FileIO::DoesFileExist(notifierQueuePath));
   EXPECT_FALSE(FileIO::DoesFileExist(handshakeQueuePath));

   SpawnSender_WaitForStartup(senderData);

   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // First Exchange
   ExchangeNotification2Receivers(senderData, receiver2ThreadData, receiver2ThreadData);
   CheckReturnedVector({receiver1ThreadData, receiver2ThreadData});

   // Shutdown the receiver threads
   Shutdown({receiver1ThreadData, receiver2ThreadData});
   EXPECT_FALSE(ThreadIsShutdown(senderData));
   receiver1ThreadData.reset();
   receiver2ThreadData.reset();

   // Respawn the Receivers
   SpawnReceiver_WaitForStartup(receiver1ThreadData);
   SpawnReceiver_WaitForStartup(receiver2ThreadData);

   // Second Exchange
   ExchangeNotification2Receivers(senderData, receiver2ThreadData, receiver2ThreadData);
   CheckReturnedVector({receiver1ThreadData, receiver2ThreadData});

   // Shutdown everything
   Shutdown({senderData, receiver1ThreadData, receiver2ThreadData});
}<|endoftext|>


<commit_before>#include <bluetoe/server.hpp>
#include <bluetoe/device.hpp>
#include <bluetoe/services/bas.hpp>
#include <bluetoe/services/dis.hpp>
#include <bluetoe/services/hid.hpp>

class keyboard_handler
{
public:
    int read_battery_level()
    {
        return 99;
    }

    std::uint8_t protocol_mode_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }

    std::uint8_t protocol_mode_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t report_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }

    std::uint8_t report_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t report_map_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)offset;
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t boot_input_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }

    std::uint8_t boot_input_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t boot_output_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }

    std::uint8_t boot_output_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t hid_information_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t control_point_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }
};

using battery_service = bluetoe::battery_level<
    bluetoe::bas::handler< keyboard_handler >
>;

static constexpr char manufacturer_name[] = "Torrox";
static constexpr char model_number[]      = "Model 1";

using device_info_service = bluetoe::device_information_service<
    bluetoe::dis::manufacturer_name< manufacturer_name >,
    bluetoe::dis::model_number< model_number >
>;

using hid_service = bluetoe::service<
    bluetoe::hid::service_uuid,
    bluetoe::characteristic<
        bluetoe::hid::protocol_mode_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::protocol_mode_write_handler >,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::protocol_mode_read_handler >,
        bluetoe::only_write_without_response
    >,
    bluetoe::characteristic<
        bluetoe::hid::report_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::report_write_handler >,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::report_read_handler >,
        bluetoe::write_without_response,
        bluetoe::notify
    >,
    bluetoe::characteristic<
        bluetoe::hid::report_map_uuid,
        bluetoe::mixin_read_blob_handler< keyboard_handler, &keyboard_handler::report_map_read_handler >
    >,
    bluetoe::characteristic<
        bluetoe::hid::boot_keyboard_input_report_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::boot_input_write_handler >,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::boot_input_read_handler >,
        bluetoe::notify
    >,
    bluetoe::characteristic<
        bluetoe::hid::boot_keyboard_output_report_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::boot_output_write_handler >,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::boot_output_read_handler >,
        bluetoe::write_without_response
    >,
    bluetoe::characteristic<
        bluetoe::hid::hid_information_uuid,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::hid_information_read_handler >
    >,
    bluetoe::characteristic<
        bluetoe::hid::hid_control_point_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::control_point_write_handler >,
        bluetoe::only_write_without_response
    >
>;

static const char name[] = "Bluetoe-Keyboard";

using keyboard = bluetoe::server<
    bluetoe::server_name< name >,
    bluetoe::appearance::keyboard,
    // by default, bluetoe would advertise all services
    bluetoe::list_of_16_bit_service_uuids<
        bluetoe::hid::service_uuid
    >,
    battery_service,
    device_info_service,
    hid_service,
    bluetoe::mixin< keyboard_handler >
>;

keyboard gatt;
bluetoe::device< keyboard > server;

int main()
{
    for ( ;; )
    {
        server.run( gatt );
    }
}
<commit_msg>use fixed_blob_value to implement report map characteristic<commit_after>#include <bluetoe/server.hpp>
#include <bluetoe/device.hpp>
#include <bluetoe/services/bas.hpp>
#include <bluetoe/services/dis.hpp>
#include <bluetoe/services/hid.hpp>

 // shamless stolen from the Nordic examples
static const std::uint8_t report_map_data[] =
{
    0x05, 0x01,       // Usage Page (Generic Desktop)
    0x09, 0x06,       // Usage (Keyboard)
    0xA1, 0x01,       // Collection (Application)
    0x05, 0x07,       // Usage Page (Key Codes)
    0x19, 0xe0,       // Usage Minimum (224)
    0x29, 0xe7,       // Usage Maximum (231)
    0x15, 0x00,       // Logical Minimum (0)
    0x25, 0x01,       // Logical Maximum (1)
    0x75, 0x01,       // Report Size (1)
    0x95, 0x08,       // Report Count (8)
    0x81, 0x02,       // Input (Data, Variable, Absolute)

    0x95, 0x01,       // Report Count (1)
    0x75, 0x08,       // Report Size (8)
    0x81, 0x01,       // Input (Constant) reserved byte(1)

    0x95, 0x05,       // Report Count (5)
    0x75, 0x01,       // Report Size (1)
    0x05, 0x08,       // Usage Page (Page# for LEDs)
    0x19, 0x01,       // Usage Minimum (1)
    0x29, 0x05,       // Usage Maximum (5)
    0x91, 0x02,       // Output (Data, Variable, Absolute), Led report
    0x95, 0x01,       // Report Count (1)
    0x75, 0x03,       // Report Size (3)
    0x91, 0x01,       // Output (Data, Variable, Absolute), Led report padding

    0x95, 0x06,       // Report Count (6)
    0x75, 0x08,       // Report Size (8)
    0x15, 0x00,       // Logical Minimum (0)
    0x25, 0x65,       // Logical Maximum (101)
    0x05, 0x07,       // Usage Page (Key codes)
    0x19, 0x00,       // Usage Minimum (0)
    0x29, 0x65,       // Usage Maximum (101)
    0x81, 0x00,       // Input (Data, Array) Key array(6 bytes)

    0x09, 0x05,       // Usage (Vendor Defined)
    0x15, 0x00,       // Logical Minimum (0)
    0x26, 0xFF, 0x00, // Logical Maximum (255)
    0x75, 0x08,       // Report Count (2)
    0x95, 0x02,       // Report Size (8 bit)
    0xB1, 0x02,       // Feature (Data, Variable, Absolute)

    0xC0              // End Collection (Application)
};

class keyboard_handler
{
public:
    int read_battery_level()
    {
        return 99;
    }

    std::uint8_t protocol_mode_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }

    std::uint8_t protocol_mode_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t report_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }

    std::uint8_t report_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t boot_input_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }

    std::uint8_t boot_input_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t boot_output_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }

    std::uint8_t boot_output_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t hid_information_read_handler( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
    {
        (void)read_size;
        (void)out_buffer;
        (void)out_size;
        return bluetoe::error_codes::success;
    }

    std::uint8_t control_point_write_handler( std::size_t write_size, const std::uint8_t* value )
    {
        (void)write_size;
        (void)value;
        return bluetoe::error_codes::success;
    }
};

using battery_service = bluetoe::battery_level<
    bluetoe::bas::handler< keyboard_handler >
>;

static constexpr char manufacturer_name[] = "Torrox";
static constexpr char model_number[]      = "Model 1";

using device_info_service = bluetoe::device_information_service<
    bluetoe::dis::manufacturer_name< manufacturer_name >,
    bluetoe::dis::model_number< model_number >
>;

using hid_service = bluetoe::service<
    bluetoe::hid::service_uuid,
    bluetoe::characteristic<
        bluetoe::hid::protocol_mode_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::protocol_mode_write_handler >,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::protocol_mode_read_handler >,
        bluetoe::only_write_without_response
    >,
    bluetoe::characteristic<
        bluetoe::hid::report_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::report_write_handler >,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::report_read_handler >,
        bluetoe::write_without_response,
        bluetoe::notify
    >,
    bluetoe::characteristic<
        bluetoe::hid::report_map_uuid,
        bluetoe::fixed_blob_value< report_map_data, sizeof( report_map_data ) >
    >,
    bluetoe::characteristic<
        bluetoe::hid::boot_keyboard_input_report_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::boot_input_write_handler >,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::boot_input_read_handler >,
        bluetoe::notify
    >,
    bluetoe::characteristic<
        bluetoe::hid::boot_keyboard_output_report_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::boot_output_write_handler >,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::boot_output_read_handler >,
        bluetoe::write_without_response
    >,
    bluetoe::characteristic<
        bluetoe::hid::hid_information_uuid,
        bluetoe::mixin_read_handler< keyboard_handler, &keyboard_handler::hid_information_read_handler >
    >,
    bluetoe::characteristic<
        bluetoe::hid::hid_control_point_uuid,
        bluetoe::mixin_write_handler< keyboard_handler, &keyboard_handler::control_point_write_handler >,
        bluetoe::only_write_without_response
    >
>;

static const char name[] = "Bluetoe-Keyboard";

using keyboard = bluetoe::server<
    bluetoe::server_name< name >,
    bluetoe::appearance::keyboard,
    // by default, bluetoe would advertise all services
    bluetoe::list_of_16_bit_service_uuids<
        bluetoe::hid::service_uuid
    >,
    battery_service,
    device_info_service,
    hid_service,
    bluetoe::mixin< keyboard_handler >
>;

keyboard gatt;
bluetoe::device< keyboard > server;

int main()
{
    for ( ;; )
    {
        server.run( gatt );
    }
}
<|endoftext|>


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

#include "hashtbl.hxx"

#define MAXFILT 200

struct LibExport
{
    char            *cExportName;       // zu exportierende Fkt.
    unsigned long   nOrdinal;           // Nummer der zu export. Fkt.
    bool            bByName;            // NONAME anhaengen
    bool            bExport;            // exportieren oder nicht ?
};

class ExportSet;
class LibDump
{
    ExportSet       *pBaseTab;          // Zugriff auf gemangelte Namen
    ExportSet       *pIndexTab;         // Zugriff auf die Ordinals
    char            *cBName;            // Name der Datenbasis
    char            *cAPrefix;          // Prefix fuer C-Fkts.
    char            *cLibName;          // Name der zu untersuchenden Lib
    char            *cFilterName;       // Name der Filterdatei
    char            *cModName;          // Modulname
    unsigned short  nBegin;             // Nummer des ersten Exports
    unsigned long   nBaseLines;         // Line in Datenbasis
    unsigned long   nFilterLines;       // Line in FilterTabelle
    char            **pFilterLines;     // Filtertabelle
    unsigned long   nDefStart;
    bool            bBase;              // Existenz der DatenBasis;
    bool            bAll;               // Alle Fkts exportieren
    bool            bDef;               // DefFile schreiben ( bei -E )

    bool            CheckDataBase();
    bool            CheckLibrary(char * cName);
    bool            ReadDataBase();
    bool            ReadFilter(char *);
    bool            PrintSym(char *, bool bName = true );
public:
                    LibDump( char *cFileName );
                    ~LibDump();
    bool            Dump();
    bool            SetFilter(char *cFilterName);
    void            SetBeginExport(unsigned short nVal){nBegin = nVal;}
    void            SetCExport( char* pName );
    bool            Filter(char *pName);
    bool            PrintDefFile();
    bool            PrintDataBase();
    static bool     DumpError(unsigned long nError);
};

<commit_msg>INTEGRATION: CWS warnings01 (1.1.146); FILE MERGED 2005/09/23 02:15:24 sb 1.1.146.2: RESYNC: (1.1-1.2); FILE MERGED 2005/09/02 14:57:36 sb 1.1.146.1: #i53898# Made code warning-free.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ldump.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 05:08:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "hashtbl.hxx"

#define MAXFILT 200

struct LibExport
{
    char            *cExportName;       // zu exportierende Fkt.
    unsigned long   nOrdinal;           // Nummer der zu export. Fkt.
    bool            bByName;            // NONAME anhaengen
    bool            bExport;            // exportieren oder nicht ?
};

class ExportSet;
class LibDump
{
    ExportSet       *pBaseTab;          // Zugriff auf gemangelte Namen
    ExportSet       *pIndexTab;         // Zugriff auf die Ordinals
    char            *cBName;            // Name der Datenbasis
    char            *cAPrefix;          // Prefix fuer C-Fkts.
    char            *cLibName;          // Name der zu untersuchenden Lib
    char            *cFilterName;       // Name der Filterdatei
    char            *cModName;          // Modulname
    unsigned short  nBegin;             // Nummer des ersten Exports
    unsigned long   nBaseLines;         // Line in Datenbasis
    unsigned long   nFilterLines;       // Line in FilterTabelle
    char            **pFilterLines;     // Filtertabelle
    unsigned long   nDefStart;
    bool            bBase;              // Existenz der DatenBasis;
    bool            bAll;               // Alle Fkts exportieren
    bool            bDef;               // DefFile schreiben ( bei -E )

    bool            CheckDataBase();
    bool            CheckLibrary(char * cName);
    bool            ReadDataBase();
    bool            ReadFilter(char *);
    bool            PrintSym(char *, bool bName = true );
public:
                    LibDump( char *cFileName );
                    ~LibDump();
    bool            Dump();
    bool            SetFilter(char *cFilterName);
    void            SetBeginExport(unsigned short nVal){nBegin = nVal;}
    void            SetCExport( char* pName );
    bool            Filter(char *pName);
    bool            PrintDefFile();
    bool            PrintDataBase();
    static void     DumpError(unsigned long nError);
};

<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */
#include "cvmfs_config.h"
#include "cache_tiered.h"

#include <string>
#include <vector>

#include "platform.h"

int TieredCacheManager::Open(const BlessedObject &object) {
  int fd = upper_->Open(object);
  if ((fd >= 0) || (fd != -ENOENT)) {return fd;}

  int fd2 = lower_->Open(object);
  if (fd2 < 0) {return fd;}  // NOTE: use error code from upper.

  // Lower cache hit; upper cache miss.  Copy object into the
  // upper cache.
  int64_t size = lower_->GetSize(fd2);
  if (size < 0) {
    lower_->Close(fd2);
    return fd;
  }

  void *txn = alloca(upper_->SizeOfTxn());
  if (upper_->StartTxn(object.id, size, txn) < 0) {
    lower_->Close(fd2);
    return fd;
  }
  upper_->CtrlTxn(object.info, 0, txn);

  std::vector<char> m_buffer;
  m_buffer.reserve(kCopyBufferSize);
  uint64_t remaining = size;
  uint64_t offset = 0;
  while (remaining > 0) {
    unsigned nbytes = remaining > kCopyBufferSize ? kCopyBufferSize : remaining;
    int64_t result = lower_->Pread(fd2, &m_buffer[0], nbytes, offset);
    // The file we are reading is supposed to be exactly `size` bytes.
    if ((result < 0) || (result != nbytes)) {
      lower_->Close(fd2);
      upper_->AbortTxn(txn);
      return fd;
    }
    result = upper_->Write(&m_buffer[0], nbytes, txn);
    if (result < 0) {
      lower_->Close(fd2);
      upper_->AbortTxn(txn);
      return fd;
    }
    offset += nbytes;
    remaining -= nbytes;
  }
  lower_->Close(fd2);
  int fd_return = upper_->OpenFromTxn(txn);
  if (fd_return < 0) {
    upper_->AbortTxn(txn);
    return fd;
  }
  if (upper_->CommitTxn(txn) < 0) {
    upper_->Close(fd_return);
    return fd;
  }
  return fd_return;
}

int TieredCacheManager::StartTxn(const shash::Any &id, uint64_t size, void *txn)
{
  int upper_result = upper_->StartTxn(id, size, txn);
  if (upper_result < 0) {
    return upper_result;
  }

  void *txn2 = static_cast<char *>(txn) + upper_->SizeOfTxn();
  int lower_result = lower_->StartTxn(id, size, txn2);
  if (lower_result < 0) {
    upper_->AbortTxn(txn);
  }
  return lower_result;
}

void TieredCacheManager::CtrlTxn(
  const ObjectInfo &object_info,
  const int flags,
  void *txn)
{
  upper_->CtrlTxn(object_info, flags, txn);
  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  lower_->CtrlTxn(object_info, flags, txn2);
}

int64_t TieredCacheManager::Write(const void *buf, uint64_t size, void *txn) {
  int upper_result = upper_->Write(buf, size, txn);
  if (upper_result < 0) { return upper_result; }

  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  return lower_->Write(buf, size, txn2);
}

int TieredCacheManager::Reset(void *txn) {
  int upper_result = upper_->Reset(txn);

  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  int lower_result = lower_->Reset(txn2);

  return (upper_result < 0) ? upper_result : lower_result;
}

int TieredCacheManager::AbortTxn(void *txn) {
  int upper_result = upper_->AbortTxn(txn);

  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  int lower_result = lower_->AbortTxn(txn2);

  return (upper_result < 0) ? upper_result : lower_result;
}

int TieredCacheManager::CommitTxn(void *txn) {
  int upper_result = upper_->CommitTxn(txn);

  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  int lower_result = lower_->CommitTxn(txn2);

  return (upper_result < 0) ? upper_result : lower_result;
}
<commit_msg>add missing include<commit_after>/**
 * This file is part of the CernVM File System.
 */
#include "cvmfs_config.h"
#include "cache_tiered.h"

#include <errno.h>

#include <string>
#include <vector>

#include "platform.h"

int TieredCacheManager::Open(const BlessedObject &object) {
  int fd = upper_->Open(object);
  if ((fd >= 0) || (fd != -ENOENT)) {return fd;}

  int fd2 = lower_->Open(object);
  if (fd2 < 0) {return fd;}  // NOTE: use error code from upper.

  // Lower cache hit; upper cache miss.  Copy object into the
  // upper cache.
  int64_t size = lower_->GetSize(fd2);
  if (size < 0) {
    lower_->Close(fd2);
    return fd;
  }

  void *txn = alloca(upper_->SizeOfTxn());
  if (upper_->StartTxn(object.id, size, txn) < 0) {
    lower_->Close(fd2);
    return fd;
  }
  upper_->CtrlTxn(object.info, 0, txn);

  std::vector<char> m_buffer;
  m_buffer.reserve(kCopyBufferSize);
  uint64_t remaining = size;
  uint64_t offset = 0;
  while (remaining > 0) {
    unsigned nbytes = remaining > kCopyBufferSize ? kCopyBufferSize : remaining;
    int64_t result = lower_->Pread(fd2, &m_buffer[0], nbytes, offset);
    // The file we are reading is supposed to be exactly `size` bytes.
    if ((result < 0) || (result != nbytes)) {
      lower_->Close(fd2);
      upper_->AbortTxn(txn);
      return fd;
    }
    result = upper_->Write(&m_buffer[0], nbytes, txn);
    if (result < 0) {
      lower_->Close(fd2);
      upper_->AbortTxn(txn);
      return fd;
    }
    offset += nbytes;
    remaining -= nbytes;
  }
  lower_->Close(fd2);
  int fd_return = upper_->OpenFromTxn(txn);
  if (fd_return < 0) {
    upper_->AbortTxn(txn);
    return fd;
  }
  if (upper_->CommitTxn(txn) < 0) {
    upper_->Close(fd_return);
    return fd;
  }
  return fd_return;
}

int TieredCacheManager::StartTxn(const shash::Any &id, uint64_t size, void *txn)
{
  int upper_result = upper_->StartTxn(id, size, txn);
  if (upper_result < 0) {
    return upper_result;
  }

  void *txn2 = static_cast<char *>(txn) + upper_->SizeOfTxn();
  int lower_result = lower_->StartTxn(id, size, txn2);
  if (lower_result < 0) {
    upper_->AbortTxn(txn);
  }
  return lower_result;
}

void TieredCacheManager::CtrlTxn(
  const ObjectInfo &object_info,
  const int flags,
  void *txn)
{
  upper_->CtrlTxn(object_info, flags, txn);
  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  lower_->CtrlTxn(object_info, flags, txn2);
}

int64_t TieredCacheManager::Write(const void *buf, uint64_t size, void *txn) {
  int upper_result = upper_->Write(buf, size, txn);
  if (upper_result < 0) { return upper_result; }

  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  return lower_->Write(buf, size, txn2);
}

int TieredCacheManager::Reset(void *txn) {
  int upper_result = upper_->Reset(txn);

  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  int lower_result = lower_->Reset(txn2);

  return (upper_result < 0) ? upper_result : lower_result;
}

int TieredCacheManager::AbortTxn(void *txn) {
  int upper_result = upper_->AbortTxn(txn);

  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  int lower_result = lower_->AbortTxn(txn2);

  return (upper_result < 0) ? upper_result : lower_result;
}

int TieredCacheManager::CommitTxn(void *txn) {
  int upper_result = upper_->CommitTxn(txn);

  void *txn2 = static_cast<char*>(txn) + upper_->SizeOfTxn();
  int lower_result = lower_->CommitTxn(txn2);

  return (upper_result < 0) ? upper_result : lower_result;
}
<|endoftext|>


<commit_before>// $Id: residue.C,v 1.7 2000/02/12 19:28:21 oliver Exp $

#include <BALL/KERNEL/residue.h>

#include <BALL/KERNEL/chain.h>
#include <BALL/KERNEL/protein.h>

using namespace std;

namespace BALL
{

	Residue::Residue()
		:	Fragment(),
			id_(BALL_RESIDUE_DEFAULT_ID),
			insertion_code_(BALL_RESIDUE_DEFAULT_INSERTION_CODE)
	{
	}

	Residue::Residue(const Residue& residue, bool deep)
		:	Fragment(residue, deep),
			id_(residue.id_),
			insertion_code_(residue.insertion_code_)
	{
	}

	Residue::Residue(const String& name, const String& id, char insertion_code)
		:	Fragment(name),
			id_(id),
			insertion_code_(insertion_code)
	{
	}

	Residue::~Residue()
	{
		destroy();
	}

	void Residue::clear()
	{
		Fragment::clear();

		clear_();
	}

	void Residue::destroy()
	{
		Fragment::destroy();

		clear_();
	}

	void Residue::persistentWrite(PersistenceManager& pm, const char* name) const
	{
		pm.writeObjectHeader(this, name);
			Fragment::persistentWrite(pm);
			pm.writePrimitive(id_, "id_");
			pm.writePrimitive(insertion_code_, "insertion_code_");
		pm.writeObjectTrailer(name);
	}

	void Residue::persistentRead(PersistenceManager& pm)
	{
		pm.checkObjectHeader(RTTI::getStreamName<Fragment>());
			Fragment::persistentRead(pm);
		pm.checkObjectTrailer(0);

		pm.readPrimitive(id_, "id_");
		pm.readPrimitive(insertion_code_, "insertion_code_");
	}

	void Residue::set(const Residue& residue, bool deep)
	{
		Fragment::set(residue, deep);

		id_ = residue.id_;
		insertion_code_ = residue.insertion_code_;
	}

	Residue& Residue::operator =(const Residue& residue)
	{
		set(residue);

		return *this;
	}

	void Residue::get(Residue& residue, bool deep) const
	{
		residue.set(*this, deep);
	}

	void Residue::swap(Residue& residue)
	{
		Fragment::swap(residue);

		id_.swap(residue.id_);

		char temp_insertion_code = insertion_code_;
		insertion_code_ = residue.insertion_code_;
		residue.insertion_code_ = temp_insertion_code;
	}

	Protein* Residue::getProtein()
	{
		for (Composite::AncestorIterator ancestor_it = beginAncestor(); !ancestor_it.isEnd(); ++ancestor_it)
		{
			if (RTTI::isKindOf<Protein>(*ancestor_it))
			{
				return (Protein *)&*ancestor_it;
			}
		}

		return 0;
	}

	const Protein *Residue::getProtein() const
	{
		return ((Residue *)this)->getProtein();
	}

	Chain* Residue::getChain()
	{
		for (Composite::AncestorIterator ancestor_it = beginAncestor(); !ancestor_it.isEnd(); ++ancestor_it)
		{
			if (RTTI::isKindOf<Chain>(*ancestor_it))
			{
				return (Chain *)&*ancestor_it;
			}
		}

		return 0;
	}

	const Chain *Residue::getChain() const
	{
		return ((Residue *)this)->getChain();
	}

	PDBAtom *Residue::getPDBAtom(Index index)
	{
		if (index < 0)
			throw Exception::IndexUnderflow(__FILE__, __LINE__, index);

		for (PDBAtomIterator protein_atom_iterator = beginPDBAtom();
				 !protein_atom_iterator.isEnd(); ++protein_atom_iterator)
		{
			if (index-- == 0)
			{
				return &(*protein_atom_iterator);
			}
		}

		return 0;
	}

	const PDBAtom* Residue::getPDBAtom(Index index) const
	{
		return ((Residue *)this)->getPDBAtom(index);
	}

	void Residue::setID(const String &id)
	{
		id_ = id;
	}

	String & Residue::getID()
	{
		return id_;
	}

	const String &Residue::getID() const
	{
		return id_;
	}

	void Residue::setInsertionCode(char insertion_code)
	{
		insertion_code_ = insertion_code;
	}

	char Residue::getInsertionCode() const
	{
		return insertion_code_;
	}

	Size Residue::countPDBAtoms() const
	{
		register Size size = 0;

		for (PDBAtomIterator protein_atom_iterator = beginPDBAtom();
				 !protein_atom_iterator.isEnd(); ++protein_atom_iterator)
		{
			++size;
		}

		return size;
	}

	void Residue::prepend(PDBAtom &protein_atom)
	{
		Fragment::prepend(protein_atom);
	}

	void Residue::append(PDBAtom& protein_atom)
	{
		Fragment::append(protein_atom);
	}

	void
	Residue::insert(PDBAtom& protein_atom)
	{
		Fragment::insert(protein_atom);
	}

	void Residue::insertBefore(PDBAtom& protein_atom, Composite& before)
	{
		Fragment::insertBefore(protein_atom, before);
	}

	void Residue::insertAfter(PDBAtom& protein_atom, Composite& after)
	{
		Fragment::insertAfter(protein_atom, after);
	}

	bool Residue::remove(PDBAtom& protein_atom)
	{
		return Fragment::remove(protein_atom);
	}

	void Residue::spliceBefore(Residue& residue)
	{
		Fragment::spliceBefore(residue);
	}

	void Residue::spliceAfter(Residue& residue)
	{
		Fragment::spliceAfter(residue);
	}

	void Residue::splice(Residue& residue)
	{
		Fragment::splice(residue);
	}

	bool Residue::isAminoAcid() const
	{
		return hasProperty(PROPERTY__AMINO_ACID);
	}

	bool Residue::isTerminal() const
	{
		return (isNTerminal() || isCTerminal());
	}

	bool Residue::isNTerminal() const
	{
		if (isAminoAcid() == true)
		{
			const Chain* chain = getChain();

			if (chain != 0)
			{
				ResidueConstIterator res_it = chain->beginResidue();
				for (; +res_it && &(*res_it) != this && !res_it->isAminoAcid(); ++res_it);

				return (&(*res_it) == this);
			}
		}

		return false;
	}

	bool Residue::isCTerminal() const
	{
		if (isAminoAcid() == true)
		{
			const Chain* chain = getChain();

			if (chain != 0)
			{
				ResidueConstIterator res_it = chain->rbeginResidue();
				for (; +res_it && &(*res_it) != this && !res_it->isAminoAcid(); --res_it);

				return (&(*res_it) == this);
			}
		}

		return false;
	}

	bool Residue::isValid() const
	{
		if (Fragment::isValid() == false
				|| id_.isValid() == false)
		{
			return false;
		}

		return true;
	}

	void Residue::dump(ostream& s, Size depth) const
	{
		BALL_DUMP_STREAM_PREFIX(s);

		Fragment::dump(s, depth);

		BALL_DUMP_DEPTH(s, depth);
		s << "  id: " << id_ << endl;

		BALL_DUMP_DEPTH(s, depth);
		s << "  insertion code: " << insertion_code_ << endl;

		BALL_DUMP_STREAM_SUFFIX(s);
	}

	void Residue::read(istream&  /* s */)
	{
		throw Exception::NotImplemented(__FILE__, __LINE__);
	}

	void Residue::write(ostream&  /*s */) const
	{
		throw Exception::NotImplemented(__FILE__, __LINE__);
	}

	void Residue::clear_()
	{
		id_ = BALL_RESIDUE_DEFAULT_ID;
		insertion_code_ = BALL_RESIDUE_DEFAULT_INSERTION_CODE;
	}

	String Residue::getFullName(Residue::FullNameType type) const
	{
		// retrieve the residue name and remove blanks
		String full_name = getName();
		full_name.trim();

		// if the variant extension should be added, do so
		if (type == ADD_VARIANT_EXTENSIONS)
		{
			String suffix = "-";
			if (isNTerminal())
			{
				suffix = "-N";
			}
			if (isCTerminal())
			{
				suffix = "-C";
			}
			if (isCTerminal() && isNTerminal())
			{
				suffix = "-M";
			}
			if (hasProperty(Residue::PROPERTY__HAS_SSBOND))
			{
				suffix += "S";
			}

			if (suffix != "-")
			{
				full_name += suffix;
			}
		}

		return full_name;
	}

} // namespace BALL
<commit_msg>added: getTorsionPhi/getTorsionPsi and hasTorsionPsi/hasTorsionPhi for the calculation of backbone torsion angles<commit_after>// $Id: residue.C,v 1.8 2000/03/25 22:46:15 oliver Exp $

#include <BALL/KERNEL/residue.h>

#include <BALL/KERNEL/chain.h>
#include <BALL/KERNEL/protein.h>
#include <BALL/STRUCTURE/geometricProperties.h>

using namespace std;

namespace BALL
{

	Residue::Residue()
		:	Fragment(),
			id_(BALL_RESIDUE_DEFAULT_ID),
			insertion_code_(BALL_RESIDUE_DEFAULT_INSERTION_CODE)
	{
	}

	Residue::Residue(const Residue& residue, bool deep)
		:	Fragment(residue, deep),
			id_(residue.id_),
			insertion_code_(residue.insertion_code_)
	{
	}

	Residue::Residue(const String& name, const String& id, char insertion_code)
		:	Fragment(name),
			id_(id),
			insertion_code_(insertion_code)
	{
	}

	Residue::~Residue()
	{
		destroy();
	}

	void Residue::clear()
	{
		Fragment::clear();

		clear_();
	}

	void Residue::destroy()
	{
		Fragment::destroy();

		clear_();
	}

	void Residue::persistentWrite(PersistenceManager& pm, const char* name) const
	{
		pm.writeObjectHeader(this, name);
			Fragment::persistentWrite(pm);
			pm.writePrimitive(id_, "id_");
			pm.writePrimitive(insertion_code_, "insertion_code_");
		pm.writeObjectTrailer(name);
	}

	void Residue::persistentRead(PersistenceManager& pm)
	{
		pm.checkObjectHeader(RTTI::getStreamName<Fragment>());
			Fragment::persistentRead(pm);
		pm.checkObjectTrailer(0);

		pm.readPrimitive(id_, "id_");
		pm.readPrimitive(insertion_code_, "insertion_code_");
	}

	void Residue::set(const Residue& residue, bool deep)
	{
		Fragment::set(residue, deep);

		id_ = residue.id_;
		insertion_code_ = residue.insertion_code_;
	}

	Residue& Residue::operator =(const Residue& residue)
	{
		set(residue);

		return *this;
	}

	void Residue::get(Residue& residue, bool deep) const
	{
		residue.set(*this, deep);
	}

	void Residue::swap(Residue& residue)
	{
		Fragment::swap(residue);

		id_.swap(residue.id_);

		char temp_insertion_code = insertion_code_;
		insertion_code_ = residue.insertion_code_;
		residue.insertion_code_ = temp_insertion_code;
	}

	bool Residue::hasTorsionPsi() const
	{
		// the torsion angle psi is not defined for
		// the C-terminus
		return !isCTerminal();
	}

	Angle Residue::getTorsionPsi() const
	{
		Angle result(0.0);
		if (hasTorsionPsi())
		{
			const Residue* next = getNext(RTTI::getDefault<Residue>());
			if (next != 0)
			{
				Atom* C = 0;
				Atom* N = 0;
				Atom* CA = 0;
				AtomIterator it;
				for (it = beginAtom(); +it; ++it)
				{
					if (it->getName() == "C")	C  = &*it;
					if (it->getName() == "CA") CA = &*it;
					if (it->getName() == "N")	N  = &*it;
				}

				Atom* next_N = 0;
				for (it = next->beginAtom(); +it; ++it)
				{
					if (it->getName() == "N")
					{
						next_N  = &*it;
						break;
					}
				}

				if ((N != 0) && (C != 0) && (CA != 0) && (next_N != 0))
				{
					result = calculateTorsionAngle(*N, *CA, *C, *next_N);
				}
				else
				{
					Log.error() << "Atoms not found:" << N << "/" << CA << "/" << C << "/" << next_N << endl;
				}
			}
			else
			{
				Log.error() << "No next residue!" << endl;
			}
		}

		return result;
	}

	bool Residue::hasTorsionPhi() const
	{
		// the torsion angle phi is not defined for
		// the C-terminus
		return !isNTerminal();
	}

	Angle Residue::getTorsionPhi() const
	{
		Angle result(0.0);
		if (hasTorsionPhi())
		{
			const Residue* previous = getPrevious(RTTI::getDefault<Residue>());
			if (previous != 0)
			{
				Atom* C = 0;
				Atom* N = 0;
				Atom* CA = 0;
				AtomIterator it;
				for (it = beginAtom(); +it; ++it)
				{
					if (it->getName() == "C")	 C  = &*it;
					if (it->getName() == "CA") CA = &*it;
					if (it->getName() == "N")  N  = &*it;
				}

				Atom* last_C = 0;
				for (it = previous->beginAtom(); +it; ++it)
				{
					if (it->getName() == "C")
					{
						last_C  = &*it;
						break;
					}
				}

				if ((N != 0) && (C != 0) && (CA != 0) && (last_C != 0))
				{
					result = calculateTorsionAngle(*last_C, *N, *CA, *C);
				}
				else
				{
					Log.error() << "Atoms not found:" << last_C << "/" << N << "/" << CA << "/" << C << endl;
				}
			}
			else
			{
				Log.error() << "No previous residue!" << endl;
			}
		}

		return result;
	}

	Protein* Residue::getProtein()
	{
		for (Composite::AncestorIterator ancestor_it = beginAncestor(); !ancestor_it.isEnd(); ++ancestor_it)
		{
			if (RTTI::isKindOf<Protein>(*ancestor_it))
			{
				return (Protein *)&*ancestor_it;
			}
		}

		return 0;
	}

	const Protein* Residue::getProtein() const
	{
		return ((Residue *)this)->getProtein();
	}

	Chain* Residue::getChain()
	{
		for (Composite::AncestorIterator ancestor_it = beginAncestor(); !ancestor_it.isEnd(); ++ancestor_it)
		{
			if (RTTI::isKindOf<Chain>(*ancestor_it))
			{
				return (Chain *)&*ancestor_it;
			}
		}

		return 0;
	}

	const Chain *Residue::getChain() const
	{
		return ((Residue *)this)->getChain();
	}

	PDBAtom *Residue::getPDBAtom(Index index)
	{
		if (index < 0)
			throw Exception::IndexUnderflow(__FILE__, __LINE__, index);

		for (PDBAtomIterator protein_atom_iterator = beginPDBAtom();
				 !protein_atom_iterator.isEnd(); ++protein_atom_iterator)
		{
			if (index-- == 0)
			{
				return &(*protein_atom_iterator);
			}
		}

		return 0;
	}

	const PDBAtom* Residue::getPDBAtom(Index index) const
	{
		return ((Residue *)this)->getPDBAtom(index);
	}

	void Residue::setID(const String &id)
	{
		id_ = id;
	}

	String & Residue::getID()
	{
		return id_;
	}

	const String &Residue::getID() const
	{
		return id_;
	}

	void Residue::setInsertionCode(char insertion_code)
	{
		insertion_code_ = insertion_code;
	}

	char Residue::getInsertionCode() const
	{
		return insertion_code_;
	}

	Size Residue::countPDBAtoms() const
	{
		register Size size = 0;

		for (PDBAtomIterator protein_atom_iterator = beginPDBAtom();
				 !protein_atom_iterator.isEnd(); ++protein_atom_iterator)
		{
			++size;
		}

		return size;
	}

	void Residue::prepend(PDBAtom &protein_atom)
	{
		Fragment::prepend(protein_atom);
	}

	void Residue::append(PDBAtom& protein_atom)
	{
		Fragment::append(protein_atom);
	}

	void
	Residue::insert(PDBAtom& protein_atom)
	{
		Fragment::insert(protein_atom);
	}

	void Residue::insertBefore(PDBAtom& protein_atom, Composite& before)
	{
		Fragment::insertBefore(protein_atom, before);
	}

	void Residue::insertAfter(PDBAtom& protein_atom, Composite& after)
	{
		Fragment::insertAfter(protein_atom, after);
	}

	bool Residue::remove(PDBAtom& protein_atom)
	{
		return Fragment::remove(protein_atom);
	}

	void Residue::spliceBefore(Residue& residue)
	{
		Fragment::spliceBefore(residue);
	}

	void Residue::spliceAfter(Residue& residue)
	{
		Fragment::spliceAfter(residue);
	}

	void Residue::splice(Residue& residue)
	{
		Fragment::splice(residue);
	}

	bool Residue::isAminoAcid() const
	{
		return hasProperty(PROPERTY__AMINO_ACID);
	}

	bool Residue::isTerminal() const
	{
		return (isNTerminal() || isCTerminal());
	}

	bool Residue::isNTerminal() const
	{
		if (isAminoAcid() == true)
		{
			const Chain* chain = getChain();

			if (chain != 0)
			{
				ResidueConstIterator res_it = chain->beginResidue();
				for (; +res_it && &(*res_it) != this && !res_it->isAminoAcid(); ++res_it);

				return (&(*res_it) == this);
			}
		}

		return false;
	}

	bool Residue::isCTerminal() const
	{
		if (isAminoAcid() == true)
		{
			const Chain* chain = getChain();

			if (chain != 0)
			{
				ResidueConstIterator res_it = chain->rbeginResidue();
				for (; +res_it && &(*res_it) != this && !res_it->isAminoAcid(); --res_it);

				return (&(*res_it) == this);
			}
		}

		return false;
	}

	bool Residue::isValid() const
	{
		if (Fragment::isValid() == false
				|| id_.isValid() == false)
		{
			return false;
		}

		return true;
	}

	void Residue::dump(ostream& s, Size depth) const
	{
		BALL_DUMP_STREAM_PREFIX(s);

		Fragment::dump(s, depth);

		BALL_DUMP_DEPTH(s, depth);
		s << "  id: " << id_ << endl;

		BALL_DUMP_DEPTH(s, depth);
		s << "  insertion code: " << insertion_code_ << endl;

		BALL_DUMP_STREAM_SUFFIX(s);
	}

	void Residue::read(istream&  /* s */)
	{
		throw Exception::NotImplemented(__FILE__, __LINE__);
	}

	void Residue::write(ostream&  /*s */) const
	{
		throw Exception::NotImplemented(__FILE__, __LINE__);
	}

	void Residue::clear_()
	{
		id_ = BALL_RESIDUE_DEFAULT_ID;
		insertion_code_ = BALL_RESIDUE_DEFAULT_INSERTION_CODE;
	}

	String Residue::getFullName(Residue::FullNameType type) const
	{
		// retrieve the residue name and remove blanks
		String full_name = getName();
		full_name.trim();

		// if the variant extension should be added, do so
		if (type == ADD_VARIANT_EXTENSIONS)
		{
			String suffix = "-";
			if (isNTerminal())
			{
				suffix = "-N";
			}
			if (isCTerminal())
			{
				suffix = "-C";
			}
			if (isCTerminal() && isNTerminal())
			{
				suffix = "-M";
			}
			if (hasProperty(Residue::PROPERTY__HAS_SSBOND))
			{
				suffix += "S";
			}

			if (suffix != "-")
			{
				full_name += suffix;
			}
		}

		return full_name;
	}

} // namespace BALL
<|endoftext|>


<commit_before>//This program created by love by Hadi - Copyright(c) by Hadi Abdi Khojasteh - Summer 2017. All right reserved. / Email: hkhojasteh@iasbs.ac.ir, info@hadiabdikhojasteh.ir / Website: iasbs.ac.ir/~hkhojasteh, hadiabdikhojasteh.ir

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/ml/ml.hpp>

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <math.h>
#include <time.h>

using namespace std;
using namespace cv;
using namespace cv::ml;

typedef tuple<char, uint32_t> enumerate;
struct IncGenerator {
	uint32_t current_;
	IncGenerator(uint32_t start) : current_(start) {}
	uint32_t operator() () { return current_++; }
};

vector<uint32_t> sample(Mat1d, uint32_t, uint32_t);
void lossFun(vector<enumerate> inputs, vector<enumerate> targets, Mat1d hprev);

uint32_t data_size, vocab_size;
Mat1d Wxh, Whh, Why, bh, by;							//model parameters

uint32_t main() {
	srand(time(NULL));

	vector<char> data;
	vector<char> chars;
	vector<enumerate> charenum;
	FILE* inputfile;
	string fileName = "input.txt";
	inputfile = fopen(fileName.c_str(), "r");

	uint32_t i = 0;
	while (!feof(inputfile)) {
		char inchar[1] = { 0 };
		fscanf(inputfile, "%c", inchar);
		data.push_back(inchar[0]);

		auto it = find_if(chars.begin(), chars.end(),
			[&](const char element) { return element == inchar[0]; });
		//If this is not in the char set
		if (it == end(chars)) {
			chars.push_back(inchar[0]);
			charenum.push_back(make_tuple(inchar[0], i));
			i++;
		}
	}
	fclose(inputfile);

	data_size = data.size();
	vocab_size = chars.size();
	printf("data has %d characters, %d unique.\n", data_size, vocab_size);
	vector<enumerate> char_to_ix = charenum;
	reverse(charenum.begin(), charenum.end());
	vector<enumerate> ix_to_char = charenum;

	//hyperparameters
	uint32_t hidden_size = 100;							//size of hidden layer of neurons
	uint32_t seq_length = 25;							//number of steps to unroll the RNN for
	double learning_rate = 1e-1;

	Wxh.create(hidden_size, vocab_size);				//Or: Mat mat(2, 4, CV_64FC1);
	Whh.create(hidden_size, hidden_size);
	Why.create(vocab_size, hidden_size);
	double mean = 0.0, stddev = 1.0 / 3.0;				//99.7% of values will be inside [-1, +1] interval
	randn(Wxh, Scalar(mean), Scalar(stddev));			//input to hidden
	randn(Whh, Scalar(mean), Scalar(stddev));			//hidden to hidden
	randn(Why, Scalar(mean), Scalar(stddev));			//hidden to output
	bh = Mat::zeros(hidden_size, 1, CV_32F);			//hidden bias
	by = Mat::zeros(vocab_size, 1, CV_32F);				//output bias

	uint32_t n = 0, p = 0;
	//Make an array of zeros with the same shape and type as a Ws array.
	Mat1d mWxh = Mat::zeros(Wxh.size(), Wxh.type());
	Mat1d mWhh = Mat::zeros(Whh.size(), Whh.type());
	Mat1d mWhy = Mat::zeros(Why.size(), Why.type());
	Mat1d mbh = Mat::zeros(bh.size(), bh.type());		//memory variables for Adagrad
	Mat1d mby = Mat::zeros(by.size(), by.type());		//memory variables for Adagrad
	//loss at iteration 0
	double smooth_loss = -log(1.0 / vocab_size) * seq_length;

	Mat1d loss, dWxh, dWhh, dWhy, dbh, dby, hprev;
	vector<enumerate> inputs, targets;
	for (uint32_t i = 0; i < 1000; i++) {
		//Prepare inputs (we're sweeping from left to right in steps seq_length long)
		if (p + seq_length + 1 >= data.size() || n == 0) {
			hprev = Mat::zeros(hidden_size, 1, CV_32F);	//reset RNN memory
			p = 0;										//go from start of data
		}

		inputs.clear();
		targets.clear();
		for (uint32_t i = 0; i < seq_length && p + i < char_to_ix.size(); i++) {
			inputs.push_back(char_to_ix[p + i]);
			targets.push_back(char_to_ix[p + 1 + i]);
		}

		//Sample from the model now and then
		if (n % 100 == 0) {
			vector<uint32_t> sampWords = sample(hprev, p + i, 200);
			for (uint32_t i = 0; i < sampWords.size(); i++) {
				printf("%c", get<0>(ix_to_char[sampWords[i]]));
			}
			printf("\n");
		}

		lossFun(inputs, targets, hprev);

		p += seq_length;								//move data pointer
		n += 1;											//iteration counter
	}
	return 0;
}

vector<uint32_t> sample(Mat1d h, uint32_t seed_ix, uint32_t n) {
	//sample a sequence of integers from the model h is memory state,
	//     seed_ix is seed letter for first time step
	Mat1d x = Mat::zeros(vocab_size, 1, CV_32F);
	x[seed_ix][0] = 1.0;
	vector<uint32_t> ixes;
	for (uint32_t i = 0; i < n; i++) {
		Mat1d t = (Wxh * x) + (Whh * h) + bh;
		Mat1d h = Mat::zeros(t.size(), t.type());
		for (uint32_t i = 0; i < t.rows; i++) {
			h[i][0] = tanh(t[i][0]);
		}
		Mat1d y = (Why * h) + by;
		Mat1d expy;
		exp(y, expy);
		Mat1d p = expy / sum(expy)[0];
		p = p.reshape(1, 1);

		//Generates a random sample from a given 1-D array
		default_random_engine generator;
		discrete_distribution<int> distribution(p.begin(), p.end());
		vector<double> indices(p.size().width);
		generate(indices.begin(), indices.end(), [&generator, &distribution]() { return distribution(generator); });
		vector<int> incNumbers(p.size().width);
		IncGenerator gi(0);
		generate(incNumbers.begin(), incNumbers.end(), gi);
		Mat1d x = Mat::zeros(vocab_size, 1, CV_32F);
		int randSelect = (uint32_t)rand() % vocab_size;
		x[randSelect][0] = 1.0;
		ixes.push_back(randSelect);
	}
	return ixes;
}

void lossFun(vector<enumerate> inputs, vector<enumerate> targets, Mat1d hprev) {
	//inputs, targets are both list of integers.
	//     hprev is Hx1 array of initial hidden state
	//     returns the loss, gradients on model parameters, and last hidden state
	Mat1d hs = hprev;
	double loss = 0.0;
	Mat1d ps;
	//forward pass
	for (uint32_t t = 0; t < inputs.size(); t++) {
		//encode in 1-of-k
		Mat1d xs = Mat::zeros(inputs.size(), vocab_size, CV_32F);
		xs[t][get<1>(inputs[t])] = 1;
		Mat1d val = (Wxh * xs.row(t).t());
		for (uint32_t i = 0; i < val.rows; i++) {
			hs[i][0] = tanh(val[i][0]);
			Mat1d temp = (Whh * hs[i - 1][0]);
			hs[i][0] += temp[i][0] + bh[i][0];				//hidden state
		}
		Mat1d ys = (Why * hs[t][0]) + by[t][0];				//unnormalized log probabilities for next chars
		//probabilities for next chars
		ps = Mat::zeros(ys.size(), ys.type());
		double sum = 0.0;
		for (uint32_t i = 0; i < ys.rows; i++) {
			sum += ps[t][i];
			ps[t][i] = exp(ys[t][i]);
		}
		for (uint32_t i = 0; i < ys.rows; i++) {
			ps[t][0] = ps[t][0] / sum;
		}
		loss += -log(ps[t][get<1>(targets[t])]);			//softmax (cross-entropy loss)
	}
	//backward pass: compute gradients going backwards
	Mat1d dWxh = Mat::zeros(Wxh.size(), Wxh.type());
	Mat1d dWhh = Mat::zeros(Whh.size(), Whh.type());
	Mat1d dWhy = Mat::zeros(Why.size(), Why.type());
	Mat1d dbh = Mat::zeros(bh.size(), bh.type());
	Mat1d dby = Mat::zeros(by.size(), by.type());
	Mat1d dhnext = Mat::zeros(hs.size(), hs.type());
	for (uint32_t t = inputs.size() - 1; t >= 0; t--){
		//backprop into y
		Mat1d dy = Mat::zeros(ps.size(), ps.type());
		dy[get<1>(targets[t])][0] -= 1;
		dWhy += dy * hs;
	}
}
<commit_msg>Remove check replicated chars in input file Bug fix for read target chars<commit_after>//This program created by love by Hadi - Copyright(c) by Hadi Abdi Khojasteh - Summer 2017. All right reserved. / Email: hkhojasteh@iasbs.ac.ir, info@hadiabdikhojasteh.ir / Website: iasbs.ac.ir/~hkhojasteh, hadiabdikhojasteh.ir

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/ml/ml.hpp>

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <math.h>
#include <time.h>

using namespace std;
using namespace cv;
using namespace cv::ml;

typedef tuple<char, uint32_t> enumerate;
struct IncGenerator {
	uint32_t current_;
	IncGenerator(uint32_t start) : current_(start) {}
	uint32_t operator() () { return current_++; }
};

vector<uint32_t> sample(Mat1d, uint32_t, uint32_t);
void lossFun(vector<enumerate> inputs, vector<enumerate> targets, Mat1d hprev);

uint32_t data_size, vocab_size;
Mat1d Wxh, Whh, Why, bh, by;							//model parameters

uint32_t main() {
	srand(time(NULL));

	vector<char> data;
	vector<char> chars;
	vector<enumerate> charenum;
	FILE* inputfile;
	string fileName = "input.txt";
	inputfile = fopen(fileName.c_str(), "r");

	uint32_t i = 0;
	while (!feof(inputfile)) {
		char inchar[1] = { 0 };
		fscanf(inputfile, "%c", inchar);
		data.push_back(inchar[0]);

		//auto it = find_if(chars.begin(), chars.end(),
		//	[&](const char element) { return element == inchar[0]; });
		//If this is not in the char set
		//if (it == end(chars)) {
			chars.push_back(inchar[0]);
			charenum.push_back(make_tuple(inchar[0], i));
			i++;
		//}
	}
	fclose(inputfile);

	data_size = data.size();
	vocab_size = chars.size();
	printf("data has %d characters, %d unique.\n", data_size, vocab_size);
	vector<enumerate> char_to_ix = charenum;
	reverse(charenum.begin(), charenum.end());
	vector<enumerate> ix_to_char = charenum;

	//hyperparameters
	uint32_t hidden_size = 100;							//size of hidden layer of neurons
	uint32_t seq_length = 25;							//number of steps to unroll the RNN for
	double learning_rate = 1e-1;

	Wxh.create(hidden_size, vocab_size);				//Or: Mat mat(2, 4, CV_64FC1);
	Whh.create(hidden_size, hidden_size);
	Why.create(vocab_size, hidden_size);
	double mean = 0.0, stddev = 1.0 / 3.0;				//99.7% of values will be inside [-1, +1] interval
	randn(Wxh, Scalar(mean), Scalar(stddev));			//input to hidden
	randn(Whh, Scalar(mean), Scalar(stddev));			//hidden to hidden
	randn(Why, Scalar(mean), Scalar(stddev));			//hidden to output
	bh = Mat::zeros(hidden_size, 1, CV_32F);			//hidden bias
	by = Mat::zeros(vocab_size, 1, CV_32F);				//output bias

	uint32_t n = 0, p = 0;
	//Make an array of zeros with the same shape and type as a Ws array.
	Mat1d mWxh = Mat::zeros(Wxh.size(), Wxh.type());
	Mat1d mWhh = Mat::zeros(Whh.size(), Whh.type());
	Mat1d mWhy = Mat::zeros(Why.size(), Why.type());
	Mat1d mbh = Mat::zeros(bh.size(), bh.type());		//memory variables for Adagrad
	Mat1d mby = Mat::zeros(by.size(), by.type());		//memory variables for Adagrad
	//loss at iteration 0
	double smooth_loss = -log(1.0 / vocab_size) * seq_length;

	Mat1d loss, dWxh, dWhh, dWhy, dbh, dby, hprev;
	vector<enumerate> inputs, targets;
	for (uint32_t i = 0; i < 1000; i++) {
		//Prepare inputs (we're sweeping from left to right in steps seq_length long)
		if (p + seq_length + 1 >= data.size() || n == 0) {
			hprev = Mat::zeros(hidden_size, 1, CV_32F);	//reset RNN memory
			p = 0;										//go from start of data
		}

		inputs.clear();
		targets.clear();
		for (uint32_t i = 0; i < seq_length && p + i < char_to_ix.size() - 1; i++) {
			inputs.push_back(char_to_ix[p + i]);
			targets.push_back(char_to_ix[p + 1 + i]);
		}

		//Sample from the model now and then
		if (n % 100 == 0) {
			vector<uint32_t> sampWords = sample(hprev, p + i, 200);
			for (uint32_t i = 0; i < sampWords.size(); i++) {
				printf("%c", get<0>(ix_to_char[sampWords[i]]));
			}
			printf("\n");
		}

		lossFun(inputs, targets, hprev);

		p += seq_length;								//move data pointer
		n += 1;											//iteration counter
	}
	return 0;
}

vector<uint32_t> sample(Mat1d h, uint32_t seed_ix, uint32_t n) {
	//sample a sequence of integers from the model h is memory state,
	//     seed_ix is seed letter for first time step
	Mat1d x = Mat::zeros(vocab_size, 1, CV_32F);
	x[seed_ix][0] = 1.0;
	vector<uint32_t> ixes;
	for (uint32_t i = 0; i < n; i++) {
		Mat1d t = (Wxh * x) + (Whh * h) + bh;
		Mat1d h = Mat::zeros(t.size(), t.type());
		for (uint32_t i = 0; i < t.rows; i++) {
			h[i][0] = tanh(t[i][0]);
		}
		Mat1d y = (Why * h) + by;
		Mat1d expy;
		exp(y, expy);
		Mat1d p = expy / sum(expy)[0];
		p = p.reshape(1, 1);

		//Generates a random sample from a given 1-D array
		default_random_engine generator;
		discrete_distribution<int> distribution(p.begin(), p.end());
		vector<double> indices(p.size().width);
		generate(indices.begin(), indices.end(), [&generator, &distribution]() { return distribution(generator); });
		vector<int> incNumbers(p.size().width);
		IncGenerator gi(0);
		generate(incNumbers.begin(), incNumbers.end(), gi);
		Mat1d x = Mat::zeros(vocab_size, 1, CV_32F);
		int randSelect = (uint32_t)rand() % vocab_size;
		x[randSelect][0] = 1.0;
		ixes.push_back(randSelect);
	}
	return ixes;
}

void lossFun(vector<enumerate> inputs, vector<enumerate> targets, Mat1d hprev) {
	//inputs, targets are both list of integers.
	//     hprev is Hx1 array of initial hidden state
	//     returns the loss, gradients on model parameters, and last hidden state
	Mat1d hs = hprev;
	double loss = 0.0;
	Mat1d ps;
	//forward pass
	for (uint32_t t = 0; t < inputs.size(); t++) {
		//encode in 1-of-k
		Mat1d xs = Mat::zeros(inputs.size(), vocab_size, CV_32F);
		xs[t][get<1>(inputs[t])] = 1;
		Mat1d val = (Wxh * xs.row(t).t());
		for (uint32_t i = 0; i < val.rows; i++) {
			hs[i][0] = tanh(val[i][0]);
			Mat1d temp = (Whh * hs[i - 1][0]);
			hs[i][0] += temp[i][0] + bh[i][0];				//hidden state
		}
		Mat1d ys = (Why * hs[t][0]) + by[t][0];				//unnormalized log probabilities for next chars
		//probabilities for next chars
		ps = Mat::zeros(ys.size(), ys.type());
		double sum = 0.0;
		for (uint32_t i = 0; i < ys.rows; i++) {
			sum += ps[t][i];
			ps[t][i] = exp(ys[t][i]);
		}
		for (uint32_t i = 0; i < ys.rows; i++) {
			ps[t][0] = ps[t][0] / sum;
		}
		loss += -log(ps[t][get<1>(targets[t])]);			//softmax (cross-entropy loss)
	}
	//backward pass: compute gradients going backwards
	Mat1d dWxh = Mat::zeros(Wxh.size(), Wxh.type());
	Mat1d dWhh = Mat::zeros(Whh.size(), Whh.type());
	Mat1d dWhy = Mat::zeros(Why.size(), Why.type());
	Mat1d dbh = Mat::zeros(bh.size(), bh.type());
	Mat1d dby = Mat::zeros(by.size(), by.type());
	Mat1d dhnext = Mat::zeros(hs.size(), hs.type());
	for (int32_t time = inputs.size() - 1; time >= 0; time--){
		//backprop into y
		cout << time;
		Mat1d dy = Mat::zeros(0, ps.cols, ps.type());
		dy.push_back(ps.row(time));
		dy[0][get<1>(targets[time])] -= 1;
		cout << dy << endl << endl ;
		dWhy += dy * hs;
	}
}
<|endoftext|>