<commit_before>// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include "test.hpp"
#include "verify_analyze.hpp"
#include "verify_rule.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   void unit_test()
   {
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "c", result_type::success );
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "a", result_type::local_failure );
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "b", result_type::local_failure );
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "cc", result_type::success, 1 );
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "bc", result_type::local_failure );

      verify_analyze< rematch< alpha, digit > >( __LINE__, __FILE__, true, false );
      verify_analyze< rematch< opt< alpha >, digit > >( __LINE__, __FILE__, false, false );
      {
         struct foo
            : rematch< alnum, foo >
         {};
         verify_analyze< foo >( __LINE__, __FILE__, true, true );
      }
      {
         struct foo
            : rematch< alnum, alpha, foo >
         {};
         verify_analyze< foo >( __LINE__, __FILE__, true, true );
      }
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "1", result_type::success, 0 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "a%", result_type::local_failure, 2 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "12", result_type::success, 1 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "1c", result_type::success, 1 );

      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "1", result_type::success, 0 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "a%", result_type::local_failure, 2 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "12", result_type::success, 1 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "1c", result_type::success, 1 );

      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "1", result_type::success, 0 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "a%", result_type::local_failure, 2 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "12", result_type::success, 1 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "1c", result_type::success, 1 );

      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1", result_type::success );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "%", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a%", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "12", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1c", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "aa", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a1", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "%%", result_type::local_failure, 2 );

      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a%", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "12", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1c", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "aa", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a1", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "%%", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "aaa", result_type::local_failure, 3 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "aaa%", result_type::local_failure, 4 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "111", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "111%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a1a", result_type::local_failure, 3 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1a1", result_type::success, 0 );

      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo5", result_type::local_failure, 4 );

      verify_rule< rematch< plus< alnum >, success, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, success, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, success, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo5", result_type::local_failure, 4 );

      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, success > >( __LINE__, __FILE__, "foo", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, success > >( __LINE__, __FILE__, "foo%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, success > >( __LINE__, __FILE__, "foo5", result_type::local_failure, 4 );

      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, string< 'f', 'o', 'o' > > >( __LINE__, __FILE__, "foo", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, string< 'f', 'o', 'o' > > >( __LINE__, __FILE__, "foo%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, string< 'f', 'o', 'o' > > >( __LINE__, __FILE__, "foo5", result_type::local_failure, 4 );
   }

}  // namespace TAO_PEGTL_NAMESPACE

#include "main.hpp"
<commit_msg>More tests<commit_after>// Copyright (c) 2019-2020 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include "test.hpp"
#include "verify_analyze.hpp"
#include "verify_rule.hpp"

namespace TAO_PEGTL_NAMESPACE
{
   void unit_test()
   {
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "c", result_type::success );
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "a", result_type::local_failure );
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "b", result_type::local_failure );
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "cc", result_type::success, 1 );
      verify_rule< rematch< one< 'c' > > >( __LINE__, __FILE__, "bc", result_type::local_failure );

      verify_analyze< rematch< alpha, digit > >( __LINE__, __FILE__, true, false );
      verify_analyze< rematch< opt< alpha >, digit > >( __LINE__, __FILE__, false, false );
      {
         struct foo
            : rematch< foo, alnum >
         {};
         verify_analyze< foo >( __LINE__, __FILE__, false, true );
      }
      {
         struct foo
            : rematch< alnum, foo >
         {};
         verify_analyze< foo >( __LINE__, __FILE__, true, true );
      }
      {
         struct foo
            : rematch< alnum, alpha, foo >
         {};
         verify_analyze< foo >( __LINE__, __FILE__, true, true );
      }
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "1", result_type::success, 0 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "a%", result_type::local_failure, 2 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "12", result_type::success, 1 );
      verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "1c", result_type::success, 1 );

      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "1", result_type::success, 0 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "a%", result_type::local_failure, 2 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "12", result_type::success, 1 );
      verify_rule< rematch< alnum, digit, success > >( __LINE__, __FILE__, "1c", result_type::success, 1 );

      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "1", result_type::success, 0 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "a%", result_type::local_failure, 2 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "12", result_type::success, 1 );
      verify_rule< rematch< alnum, success, digit > >( __LINE__, __FILE__, "1c", result_type::success, 1 );

      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1", result_type::success );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "%", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a%", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "12", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "1c", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "aa", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "a1", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, digit > >( __LINE__, __FILE__, "%%", result_type::local_failure, 2 );

      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "%", result_type::local_failure, 1 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a%", result_type::local_failure );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "12", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1c", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "aa", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a1", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "%%", result_type::local_failure, 2 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "aaa", result_type::local_failure, 3 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "aaa%", result_type::local_failure, 4 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "111", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "111%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "a1a", result_type::local_failure, 3 );
      verify_rule< rematch< plus< alnum >, plus< digit > > >( __LINE__, __FILE__, "1a1", result_type::success, 0 );

      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo5", result_type::local_failure, 4 );

      verify_rule< rematch< plus< alnum >, success, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, success, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, success, seq< string< 'f', 'o', 'o' >, eof > > >( __LINE__, __FILE__, "foo5", result_type::local_failure, 4 );

      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, success > >( __LINE__, __FILE__, "foo", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, success > >( __LINE__, __FILE__, "foo%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, success > >( __LINE__, __FILE__, "foo5", result_type::local_failure, 4 );

      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, string< 'f', 'o', 'o' > > >( __LINE__, __FILE__, "foo", result_type::success, 0 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, string< 'f', 'o', 'o' > > >( __LINE__, __FILE__, "foo%", result_type::success, 1 );
      verify_rule< rematch< plus< alnum >, seq< string< 'f', 'o', 'o' >, eof >, string< 'f', 'o', 'o' > > >( __LINE__, __FILE__, "foo5", result_type::local_failure, 4 );
   }

}  // namespace TAO_PEGTL_NAMESPACE

#include "main.hpp"
<|endoftext|>


<commit_before>//-------------------------------------------------------------------------
//
// rewritersample.cpp: Source-to-source transformation sample with Clang,
// using Rewriter - the code rewriting interface.
//
// Eli Bendersky (eliben@gmail.com)
// This code is in the public domain
//
#include <cstdio>
#include <string>
#include <sstream>

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;
using namespace std;

// By implementing RecursiveASTVisitor, we can specify which AST nodes
// we're interested in by overriding relevant methods.
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> {
public:
  MyASTVisitor(Rewriter &R) : TheRewriter(R) {}

  bool VisitStmt(Stmt *s) {
    // Only care about If statements.
    if (isa<IfStmt>(s)) {
      IfStmt *IfStatement = cast<IfStmt>(s);
      Stmt *Then = IfStatement->getThen();

      TheRewriter.InsertText(Then->getLocStart(), "// the 'if' part\n", true,
                             true);

      Stmt *Else = IfStatement->getElse();
      if (Else)
        TheRewriter.InsertText(Else->getLocStart(), "// the 'else' part\n",
                               true, true);
    }

    return true;
  }

  bool VisitFunctionDecl(FunctionDecl *f) {
    // Only function definitions (with bodies), not declarations.
    if (f->hasBody()) {
      Stmt *FuncBody = f->getBody();

      // Type name as string
      QualType QT = f->getResultType();
      string TypeStr = QT.getAsString();

      // Function name
      DeclarationName DeclName = f->getNameInfo().getName();
      string FuncName = DeclName.getAsString();

      // Add comment before
      stringstream SSBefore;
      SSBefore << "// Begin function " << FuncName << " returning " << TypeStr
               << "\n";
      SourceLocation ST = f->getSourceRange().getBegin();
      TheRewriter.InsertText(ST, SSBefore.str(), true, true);

      // And after
      stringstream SSAfter;
      SSAfter << "\n// End function " << FuncName << "\n";
      ST = FuncBody->getLocEnd().getLocWithOffset(1);
      TheRewriter.InsertText(ST, SSAfter.str(), true, true);
    }

    return true;
  }

private:
  void AddBraces(Stmt *s);

  Rewriter &TheRewriter;
};

// Implementation of the ASTConsumer interface for reading an AST produced
// by the Clang parser.
class MyASTConsumer : public ASTConsumer {
public:
  MyASTConsumer(Rewriter &R) : Visitor(R) {}

  // Override the method that gets called for each parsed top-level
  // declaration.
  virtual bool HandleTopLevelDecl(DeclGroupRef DR) {
    for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b)
      // Traverse the declaration using our AST visitor.
      Visitor.TraverseDecl(*b);
    return true;
  }

private:
  MyASTVisitor Visitor;
};

int main(int argc, char *argv[]) {
  if (argc != 2) {
    llvm::errs() << "Usage: rewritersample <filename>\n";
    return 1;
  }

  // CompilerInstance will hold the instance of the Clang compiler for us,
  // managing the various objects needed to run the compiler.
  CompilerInstance TheCompInst;
  TheCompInst.createDiagnostics();

  // Initialize target info with the default triple for our platform.
  TargetOptions *TO = new TargetOptions;
  TO->Triple = llvm::sys::getDefaultTargetTriple();
  TargetInfo *TI =
      TargetInfo::CreateTargetInfo(TheCompInst.getDiagnostics(), TO);
  TheCompInst.setTarget(TI);

  TheCompInst.createFileManager();
  FileManager &FileMgr = TheCompInst.getFileManager();
  TheCompInst.createSourceManager(FileMgr);
  SourceManager &SourceMgr = TheCompInst.getSourceManager();
  TheCompInst.createPreprocessor();
  TheCompInst.createASTContext();

  // A Rewriter helps us manage the code rewriting task.
  Rewriter TheRewriter;
  TheRewriter.setSourceMgr(SourceMgr, TheCompInst.getLangOpts());

  //// Set the main file handled by the source manager to the input file.
  const FileEntry *FileIn = FileMgr.getFile(argv[1]);
  SourceMgr.createMainFileID(FileIn);
  TheCompInst.getDiagnosticClient().BeginSourceFile(
      TheCompInst.getLangOpts(), &TheCompInst.getPreprocessor());

  // Create an AST consumer instance which is going to get called by
  // ParseAST.
  MyASTConsumer TheConsumer(TheRewriter);

  // Parse the file to AST, registering our consumer as the AST consumer.
  ParseAST(TheCompInst.getPreprocessor(), &TheConsumer,
           TheCompInst.getASTContext());

  //// At this point the rewriter's buffer should be full with the rewritten
  //// file contents.
  const RewriteBuffer *RewriteBuf =
      TheRewriter.getRewriteBufferFor(SourceMgr.getMainFileID());
  llvm::outs() << string(RewriteBuf->begin(), RewriteBuf->end());

  return 0;
}
<commit_msg>Resilience in case of not finding the input file<commit_after>//-------------------------------------------------------------------------
//
// rewritersample.cpp: Source-to-source transformation sample with Clang,
// using Rewriter - the code rewriting interface.
//
// Eli Bendersky (eliben@gmail.com)
// This code is in the public domain
//
#include <cstdio>
#include <string>
#include <sstream>

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;
using namespace std;

// By implementing RecursiveASTVisitor, we can specify which AST nodes
// we're interested in by overriding relevant methods.
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> {
public:
  MyASTVisitor(Rewriter &R) : TheRewriter(R) {}

  bool VisitStmt(Stmt *s) {
    // Only care about If statements.
    if (isa<IfStmt>(s)) {
      IfStmt *IfStatement = cast<IfStmt>(s);
      Stmt *Then = IfStatement->getThen();

      TheRewriter.InsertText(Then->getLocStart(), "// the 'if' part\n", true,
                             true);

      Stmt *Else = IfStatement->getElse();
      if (Else)
        TheRewriter.InsertText(Else->getLocStart(), "// the 'else' part\n",
                               true, true);
    }

    return true;
  }

  bool VisitFunctionDecl(FunctionDecl *f) {
    // Only function definitions (with bodies), not declarations.
    if (f->hasBody()) {
      Stmt *FuncBody = f->getBody();

      // Type name as string
      QualType QT = f->getResultType();
      string TypeStr = QT.getAsString();

      // Function name
      DeclarationName DeclName = f->getNameInfo().getName();
      string FuncName = DeclName.getAsString();

      // Add comment before
      stringstream SSBefore;
      SSBefore << "// Begin function " << FuncName << " returning " << TypeStr
               << "\n";
      SourceLocation ST = f->getSourceRange().getBegin();
      TheRewriter.InsertText(ST, SSBefore.str(), true, true);

      // And after
      stringstream SSAfter;
      SSAfter << "\n// End function " << FuncName << "\n";
      ST = FuncBody->getLocEnd().getLocWithOffset(1);
      TheRewriter.InsertText(ST, SSAfter.str(), true, true);
    }

    return true;
  }

private:
  void AddBraces(Stmt *s);

  Rewriter &TheRewriter;
};

// Implementation of the ASTConsumer interface for reading an AST produced
// by the Clang parser.
class MyASTConsumer : public ASTConsumer {
public:
  MyASTConsumer(Rewriter &R) : Visitor(R) {}

  // Override the method that gets called for each parsed top-level
  // declaration.
  virtual bool HandleTopLevelDecl(DeclGroupRef DR) {
    for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b)
      // Traverse the declaration using our AST visitor.
      Visitor.TraverseDecl(*b);
    return true;
  }

private:
  MyASTVisitor Visitor;
};

int main(int argc, char *argv[]) {
  if (argc != 2) {
    llvm::errs() << "Usage: rewritersample <filename>\n";
    return 1;
  }

  // CompilerInstance will hold the instance of the Clang compiler for us,
  // managing the various objects needed to run the compiler.
  CompilerInstance TheCompInst;
  TheCompInst.createDiagnostics();

  // Initialize target info with the default triple for our platform.
  TargetOptions *TO = new TargetOptions;
  TO->Triple = llvm::sys::getDefaultTargetTriple();
  TargetInfo *TI =
      TargetInfo::CreateTargetInfo(TheCompInst.getDiagnostics(), TO);
  TheCompInst.setTarget(TI);

  TheCompInst.createFileManager();
  FileManager &FileMgr = TheCompInst.getFileManager();
  TheCompInst.createSourceManager(FileMgr);
  SourceManager &SourceMgr = TheCompInst.getSourceManager();
  TheCompInst.createPreprocessor();
  TheCompInst.createASTContext();

  // A Rewriter helps us manage the code rewriting task.
  Rewriter TheRewriter;
  TheRewriter.setSourceMgr(SourceMgr, TheCompInst.getLangOpts());

  //// Set the main file handled by the source manager to the input file.
  const FileEntry *FileIn = FileMgr.getFile(argv[1]);
  if (!FileIn) {
    llvm::errs() << "Input file does not exist!\n";
    return 1;
  }
  SourceMgr.createMainFileID(FileIn);
  TheCompInst.getDiagnosticClient().BeginSourceFile(
      TheCompInst.getLangOpts(), &TheCompInst.getPreprocessor());

  // Create an AST consumer instance which is going to get called by
  // ParseAST.
  MyASTConsumer TheConsumer(TheRewriter);

  // Parse the file to AST, registering our consumer as the AST consumer.
  ParseAST(TheCompInst.getPreprocessor(), &TheConsumer,
           TheCompInst.getASTContext());

  //// At this point the rewriter's buffer should be full with the rewritten
  //// file contents.
  const RewriteBuffer *RewriteBuf =
      TheRewriter.getRewriteBufferFor(SourceMgr.getMainFileID());
  llvm::outs() << string(RewriteBuf->begin(), RewriteBuf->end());

  return 0;
}
<|endoftext|>


<commit_before>#include "customizer.h"

#include <QtWidgets/QApplication>

#include <qrkernel/settingsManager.h>

using namespace interpreterCore;

QString Customizer::windowTitle() const
{
	return QObject::tr("Trik Studio") + " " + productVersion();
}

QIcon Customizer::applicationIcon() const
{
	return QIcon(":/icons/icon.png");
}

QImage Customizer::applicationLogo() const
{
	return QImage(":/icons/splashscreen.png");
}

QString Customizer::productVersion() const
{
	/// @todo other storage for it?
	return "3.0.0 α10";
}

QString Customizer::aboutText() const
{
	return "" + windowTitle() + "

http://robots.qreal.ru/";
}

QString Customizer::examplesDirectory() const
{
	return QApplication::applicationDirPath() + "/examples";
}

bool Customizer::showInterpeterButton() const
{
	return false;
}

void Customizer::customizeDocks(qReal::gui::MainWindowDockInterface *dockInterface)
{
	mDockInterface = dockInterface;
	dockInterface->logicalModelDock()->hide();
	dockInterface->tabifyDockWidget(dockInterface->graphicalModelDock(), dockInterface->propertyEditorDock());
	dockInterface->graphicalModelDock()->setWindowTitle(QObject::tr("Blocks"));
}

void Customizer::placeDevicesConfig(QWidget *devicesWidget)
{
	QDockWidget *devicesDock = produceDockWidget(QObject::tr("Configure devices"), devicesWidget);
	mDockInterface->addDockWidget(Qt::LeftDockWidgetArea, devicesDock);
}

void Customizer::placeWatchPlugins(QDockWidget *watchWindow, QWidget *graphicsWatch)
{
	mDockInterface->addDockWidget(Qt::LeftDockWidgetArea, watchWindow);
	watchWindow->setFloating(false);
	/// @todo: Restore plotter when everything will be fine...
	Q_UNUSED(graphicsWatch)
	// QDockWidget *graphWatchDock = produceDockWidget(QObject::tr("Sensors state"), graphicsWatch);
	// mDockInterface->addDockWidget(Qt::LeftDockWidgetArea, graphWatchDock);

	// mDockInterface->tabifyDockWidget(watchWindow, graphWatchDock);
}

QDockWidget *Customizer::produceDockWidget(QString const &title, QWidget *content) const
{
	QDockWidget *dock = new QDockWidget(title);
	dock->setWidget(content);
	return dock;
}

QString Customizer::userPaletteTitle() const
{
	return QObject::tr("Subprograms");
}

QString Customizer::userPaletteDescription() const
{
	return QObject::tr("The list of all declared subprograms in the project");
}
<commit_msg>Sensors plotter enabled back<commit_after>#include "customizer.h"

#include <QtWidgets/QApplication>

#include <qrkernel/settingsManager.h>

using namespace interpreterCore;

QString Customizer::windowTitle() const
{
	return QObject::tr("Trik Studio") + " " + productVersion();
}

QIcon Customizer::applicationIcon() const
{
	return QIcon(":/icons/icon.png");
}

QImage Customizer::applicationLogo() const
{
	return QImage(":/icons/splashscreen.png");
}

QString Customizer::productVersion() const
{
	/// @todo other storage for it?
	return "3.0.0 α10";
}

QString Customizer::aboutText() const
{
	return "" + windowTitle() + "

http://robots.qreal.ru/";
}

QString Customizer::examplesDirectory() const
{
	return QApplication::applicationDirPath() + "/examples";
}

bool Customizer::showInterpeterButton() const
{
	return false;
}

void Customizer::customizeDocks(qReal::gui::MainWindowDockInterface *dockInterface)
{
	mDockInterface = dockInterface;
	dockInterface->logicalModelDock()->hide();
	dockInterface->tabifyDockWidget(dockInterface->graphicalModelDock(), dockInterface->propertyEditorDock());
	dockInterface->graphicalModelDock()->setWindowTitle(QObject::tr("Blocks"));
}

void Customizer::placeDevicesConfig(QWidget *devicesWidget)
{
	QDockWidget *devicesDock = produceDockWidget(QObject::tr("Configure devices"), devicesWidget);
	mDockInterface->addDockWidget(Qt::LeftDockWidgetArea, devicesDock);
}

void Customizer::placeWatchPlugins(QDockWidget *watchWindow, QWidget *graphicsWatch)
{
	mDockInterface->addDockWidget(Qt::LeftDockWidgetArea, watchWindow);
	watchWindow->setFloating(false);

	QDockWidget *graphWatchDock = produceDockWidget(QObject::tr("Sensors state"), graphicsWatch);
	mDockInterface->addDockWidget(Qt::LeftDockWidgetArea, graphWatchDock);

	mDockInterface->tabifyDockWidget(watchWindow, graphWatchDock);
}

QDockWidget *Customizer::produceDockWidget(QString const &title, QWidget *content) const
{
	QDockWidget *dock = new QDockWidget(title);
	dock->setWidget(content);
	return dock;
}

QString Customizer::userPaletteTitle() const
{
	return QObject::tr("Subprograms");
}

QString Customizer::userPaletteDescription() const
{
	return QObject::tr("The list of all declared subprograms in the project");
}
<|endoftext|>


<commit_before>#include <main.h>
#include <pidData.h>

/* *** Circular buffer for PID samples queued for logging *** */
// Indexes into pidSamples; Marks index of next data point to transmit to audacy
volatile unsigned int pidSentDataPointer = 0;
// If sentDataPointer == dataPointer, buffer is empty
// If dataPointer == sentDataPointer - 1, buffer is full
volatile unsigned int pidDataPointer = 0; // Marks index of next place to read into
volatile unsigned int pidSamplesSent = 0;
volatile pidSample pidSamples[PID_BUFFER_SIZE + 10]; // Add some extra space on the end in case we overflow
volatile bool sampling = false;
elapsedMicros timeSinceLastRead;

volatile pidDumpPacket_t pidDumpPacket;
volatile uint32_t* pidDumpPacketUints = (uint32_t *) &(pidDumpPacket.header);

volatile uint16_t pidPacketChecksum = 0;
volatile unsigned int pidPacketBodyPointer = 0;
volatile bool pidPacketReady = false;

// Telemetry
volatile unsigned int pidSamplesRead = 0;
volatile unsigned int pidSamplesQueued = 0;

void write32WithChecksum(const uint16_t& in, volatile uint32_t& out, volatile uint16_t& pidBufferChecksum) {
    pidBufferChecksum += in;
    out = in;
}

// Checksum is updated as samples are pushed into this buffer
void writeExpandedPidSampleWithChecksum(const pidSample* in, volatile expandedPidSample* out, volatile uint16_t& pidBufferChecksum) {
    assert(sizeof(pidSample) * 2 == sizeof(expandedPidSample));
    assert(sizeof(pidSample) == 4 * 4 * 3);
    unsigned int num_uint32 = sizeof(pidSample) / 4;
    for (unsigned int i = 0; i < num_uint32; i++) {
        uint32_t num = ((uint32_t *) in)[i];
        ((uint32_t *) out)[2 * i] = num >> 16; // msb
        pidBufferChecksum += num >> 16;
        ((uint32_t *) out)[2 * i + 1] = num % (1 << 16); // lsb
        pidBufferChecksum += num % (1 << 16);
    }
}

void populateHeader() {
    write32WithChecksum(0, pidDumpPacket.p_x, pidPacketChecksum);
    write32WithChecksum(1, pidDumpPacket.i_x, pidPacketChecksum);
    write32WithChecksum(2, pidDumpPacket.d_x, pidPacketChecksum);
    write32WithChecksum(3, pidDumpPacket.p_y, pidPacketChecksum);
    write32WithChecksum(4, pidDumpPacket.i_y, pidPacketChecksum);
    write32WithChecksum(5, pidDumpPacket.d_y, pidPacketChecksum);
    write32WithChecksum(6, pidDumpPacket.last_x, pidPacketChecksum);
    write32WithChecksum(7, pidDumpPacket.last_y, pidPacketChecksum);
    write32WithChecksum(8, pidDumpPacket.set_x, pidPacketChecksum);
    write32WithChecksum(9, pidDumpPacket.set_y, pidPacketChecksum);
}

bool pidBufferEmpty() {
    return (pidSentDataPointer % PID_BUFFER_SIZE) == (pidDataPointer % PID_BUFFER_SIZE);
}

bool pidBufferFull() {
    return ((pidDataPointer + 1) % PID_BUFFER_SIZE) == (pidSentDataPointer % PID_BUFFER_SIZE);
}

// Runs in main's setup()
void pidDataSetup() {
    (void) assert(((unsigned int) pidDumpPacket.body) % 4 == 0);  // Check offset; Misaligned data may segfault at 0x20000000
    (void) assert(((unsigned int) pidSamples) % 4 == 0);
    debugPrintf("pidSamples location (we want this to be far from 0x2000000): %p to %p\n", pidSamples, pidSamples + PID_BUFFER_SIZE);
    debugPrintf("pidDumpPacket location (we want this to be far from 0x2000000): memory begins %p, samples %p to %p\n", &pidDumpPacket, pidDumpPacket.body, pidDumpPacket.abcdFooter + SpiSlave::ABCD_BUFFER_SIZE);
    pinMode(PID_DATA_READY_PIN, OUTPUT);
    for (int i = 0; i < 10; i++) {
        ((uint16_t *) &pidSamples[PID_BUFFER_SIZE])[i] = 0xbeef;
        ((uint16_t *) pidDumpPacket.abcdFooter)[SpiSlave::ABCD_BUFFER_SIZE + i] = 0xbeef;
    }
    for (int i = 0; i < SpiSlave::ABCD_BUFFER_SIZE; i++) {
        pidDumpPacket.abcdHeader[i] = 0xabcd;
        pidDumpPacket.abcdFooter[i] = 0xabcd;
    }
    assert ((uint32_t) pidSamples[PID_BUFFER_SIZE].sample.c == 0xbeefbeef);
}

/*void restartSamplingIfApplicable() {
    noInterrupts();
    if (pidBufferEmpty() && !sampling && !tryingToRestartSampling && !pidPacketReady) {
        // Start sampling again!
        pidPacketBodyPointer = 0;
        pidPacketChecksum = 0;
        tryingToRestartSampling = true;
    }
    interrupts();
}
*/

//void sentTriggerPacket() {
//}

/* *** Dequeues from pidSamples and moves samples into next packet *** */
void checkDataDump() {
    noInterrupts();
    unsigned int pidPacketBodyPointerSave = pidPacketBodyPointer;
    unsigned int pidPacketReadySave = pidPacketReady;
    if(!assert((pidPacketBodyPointerSave == PID_DATA_DUMP_SIZE) == pidPacketReadySave)) {
        // Likely a race condition
        debugPrintf("packetBodyPointer %d, ready? %d\n", pidPacketBodyPointerSave, pidPacketReadySave);
    }
    if (pidPacketReady) {
        interrupts();
        return;
    }
    noInterrupts();
    if ((pidPacketBodyPointer < PID_DATA_DUMP_SIZE) && !pidBufferEmpty()) {
        // Move a sample from large buffer to packet buffer
        if (pidPacketBodyPointer == 0) {
            populateHeader();
        }
        pidSample sample = pidSamples[pidSentDataPointer];
        writeExpandedPidSampleWithChecksum(&sample, &(pidDumpPacket.body[pidPacketBodyPointer]), pidPacketChecksum);
        pidPacketBodyPointer++;
        pidSentDataPointer++;
    }
    pidSentDataPointer = pidSentDataPointer % PID_BUFFER_SIZE;
    assert(pidPacketBodyPointer <= PID_DATA_DUMP_SIZE);
    if (pidPacketBodyPointer >= PID_DATA_DUMP_SIZE) {
        // Packet is ready!
        noInterrupts();
        assert((sizeof(pidSample) * 8) % 16 == 0);
        pidPacketReady = true;

        digitalWriteFast(PID_DATA_READY_PIN, HIGH);
    }

    interrupts();
}

// Enqueue pid sample for logging
void recordPid(const volatile pidSample& s) {
    if (pidBufferEmpty()) {
        sampling = true;
    }
    if (!sampling) {
        return;
    }
    ((pidSample *) pidSamples)[pidDataPointer] = s;
    pidDataPointer = (pidDataPointer + 1) % PID_BUFFER_SIZE;
    pidSamplesRead++;
    assert(pidDataPointer <= PID_BUFFER_SIZE);

    if (pidBufferFull()) {
        sampling = false;
    }
}

// Runs in main loop
void taskPidData() {
    if (!assert ((uint32_t) pidSamples[PID_BUFFER_SIZE].sample.c == 0xbeefbeef)) {
        debugPrintf("End of buf is %x\n", pidSamples[PID_BUFFER_SIZE].sample.c);
    }
    assert (pidDataPointer <= PID_BUFFER_SIZE);
    assert (!(sampling && (pidDataPointer >= PID_BUFFER_SIZE)));
    checkDataDump();
}

// Called from dma completion - clears packet buffer so we can prepare the next packet
void pidPacketSent() {
    digitalWrite(PID_DATA_READY_PIN, LOW);
    if ((assert(pidPacketReady))) {
        noInterrupts();
        pidPacketChecksum = 0;
        pidPacketBodyPointer = 0;
        pidPacketReady = false;
        pidSamplesSent += PID_DATA_DUMP_SIZE;
        interrupts();
    }
}

// Called from enterTracking
void enterPidData() {
    noInterrupts();
    pidPacketChecksum = 0;
    pidPacketReady = false;
    pidSentDataPointer = 0;
    pidDataPointer = 0;
    timeSinceLastRead = 0;
    pidPacketBodyPointer = 0;
    sampling = true;
    digitalWriteFast(PID_DATA_READY_PIN, LOW);
    interrupts();
}

// Called from leaveTracking
void leavePidData() {
    digitalWriteFast(PID_DATA_READY_PIN, LOW);
    noInterrupts();
    pidPacketReady = false;
    sampling = false;
    pidDataPointer = 0;
    interrupts();
}

void pidDataHeartbeat() {
    Serial.printf("PID front of buffer %d, back of buffer %d, packet ready? %d, chksum %d, packet pointer %d, sampling %d, packet %d, sent %d\n", pidDataPointer, pidSentDataPointer, pidPacketReady, pidPacketChecksum, pidPacketBodyPointer, sampling, pidPacketBodyPointer, pidSamplesSent);
}
<commit_msg>Updated pidData.cpp to insert dummy sample at discontinuities in logging<commit_after>#include <main.h>
#include <pidData.h>

/* *** Circular buffer for PID samples queued for logging *** */
// Indexes into pidSamples; Marks index of next data point to transmit to audacy
volatile unsigned int pidSentDataPointer = 0;
// If sentDataPointer == dataPointer, buffer is empty
// If dataPointer == sentDataPointer - 1, buffer is full
volatile unsigned int pidDataPointer = 0; // Marks index of next place to read into
volatile unsigned int pidSamplesSent = 0;
volatile pidSample pidSamples[PID_BUFFER_SIZE + 10]; // Add some extra space on the end in case we overflow
volatile bool sampling = false;
elapsedMicros timeSinceLastRead;

volatile pidDumpPacket_t pidDumpPacket;
volatile uint32_t* pidDumpPacketUints = (uint32_t *) &(pidDumpPacket.header);

volatile uint16_t pidPacketChecksum = 0;
volatile unsigned int pidPacketBodyPointer = 0;
volatile bool pidPacketReady = false;

// Telemetry
volatile unsigned int pidSamplesRead = 0;
volatile unsigned int pidSamplesQueued = 0;

void write32WithChecksum(const uint16_t& in, volatile uint32_t& out, volatile uint16_t& pidBufferChecksum) {
    pidBufferChecksum += in;
    out = in;
}

// Checksum is updated as samples are pushed into this buffer
void writeExpandedPidSampleWithChecksum(const pidSample* in, volatile expandedPidSample* out, volatile uint16_t& pidBufferChecksum) {
    assert(sizeof(pidSample) * 2 == sizeof(expandedPidSample));
    assert(sizeof(pidSample) == 4 * 4 * 3);
    unsigned int num_uint32 = sizeof(pidSample) / 4;
    for (unsigned int i = 0; i < num_uint32; i++) {
        uint32_t num = ((uint32_t *) in)[i];
        ((uint32_t *) out)[2 * i] = num >> 16; // msb
        pidBufferChecksum += num >> 16;
        ((uint32_t *) out)[2 * i + 1] = num % (1 << 16); // lsb
        pidBufferChecksum += num % (1 << 16);
    }
}

void populateHeader() {
    write32WithChecksum(0, pidDumpPacket.p_x, pidPacketChecksum);
    write32WithChecksum(1, pidDumpPacket.i_x, pidPacketChecksum);
    write32WithChecksum(2, pidDumpPacket.d_x, pidPacketChecksum);
    write32WithChecksum(3, pidDumpPacket.p_y, pidPacketChecksum);
    write32WithChecksum(4, pidDumpPacket.i_y, pidPacketChecksum);
    write32WithChecksum(5, pidDumpPacket.d_y, pidPacketChecksum);
    write32WithChecksum(6, pidDumpPacket.last_x, pidPacketChecksum);
    write32WithChecksum(7, pidDumpPacket.last_y, pidPacketChecksum);
    write32WithChecksum(8, pidDumpPacket.set_x, pidPacketChecksum);
    write32WithChecksum(9, pidDumpPacket.set_y, pidPacketChecksum);
}

bool pidBufferEmpty() {
    return (pidSentDataPointer % PID_BUFFER_SIZE) == (pidDataPointer % PID_BUFFER_SIZE);
}

bool pidBufferFull() {
    return ((pidDataPointer + 1) % PID_BUFFER_SIZE) == (pidSentDataPointer % PID_BUFFER_SIZE);
}
// Runs in main's setup()
void pidDataSetup() {
    (void) assert(((unsigned int) pidDumpPacket.body) % 4 == 0);  // Check offset; Misaligned data may segfault at 0x20000000
    (void) assert(((unsigned int) pidSamples) % 4 == 0);
    debugPrintf("pidSamples location (we want this to be far from 0x2000000): %p to %p\n", pidSamples, pidSamples + PID_BUFFER_SIZE);
    debugPrintf("pidDumpPacket location (we want this to be far from 0x2000000): memory begins %p, samples %p to %p\n", &pidDumpPacket, pidDumpPacket.body, pidDumpPacket.abcdFooter + SpiSlave::ABCD_BUFFER_SIZE);
    pinMode(PID_DATA_READY_PIN, OUTPUT);
    for (int i = 0; i < 10; i++) {
        ((uint16_t *) &pidSamples[PID_BUFFER_SIZE])[i] = 0xbeef;
        ((uint16_t *) pidDumpPacket.abcdFooter)[SpiSlave::ABCD_BUFFER_SIZE + i] = 0xbeef;
    }
    for (int i = 0; i < SpiSlave::ABCD_BUFFER_SIZE; i++) {
        pidDumpPacket.abcdHeader[i] = 0xabcd;
        pidDumpPacket.abcdFooter[i] = 0xabcd;
    }
    assert ((uint32_t) pidSamples[PID_BUFFER_SIZE].sample.c == 0xbeefbeef);
}

/*void restartSamplingIfApplicable() {
    noInterrupts();
    if (pidBufferEmpty() && !sampling && !tryingToRestartSampling && !pidPacketReady) {
        // Start sampling again!
        pidPacketBodyPointer = 0;
        pidPacketChecksum = 0;
        tryingToRestartSampling = true;
    }
    interrupts();
}
*/

//void sentTriggerPacket() {
//}

/* *** Dequeues from pidSamples and moves samples into next packet *** */
void checkDataDump() {
    noInterrupts();
    unsigned int pidPacketBodyPointerSave = pidPacketBodyPointer;
    unsigned int pidPacketReadySave = pidPacketReady;
    if(!assert((pidPacketBodyPointerSave == PID_DATA_DUMP_SIZE) == pidPacketReadySave)) {
        // Likely a race condition
        debugPrintf("packetBodyPointer %d, ready? %d\n", pidPacketBodyPointerSave, pidPacketReadySave);
    }
    if (pidPacketReady) {
        interrupts();
        return;
    }
    noInterrupts();
    if ((pidPacketBodyPointer < PID_DATA_DUMP_SIZE) && !pidBufferEmpty()) {
        // Move a sample from large buffer to packet buffer
        if (pidPacketBodyPointer == 0) {
            populateHeader();
        }
        pidSample sample = pidSamples[pidSentDataPointer];
        writeExpandedPidSampleWithChecksum(&sample, &(pidDumpPacket.body[pidPacketBodyPointer]), pidPacketChecksum);
        pidPacketBodyPointer++;
        pidSentDataPointer++;
    }
    pidSentDataPointer = pidSentDataPointer % PID_BUFFER_SIZE;
    assert(pidPacketBodyPointer <= PID_DATA_DUMP_SIZE);
    if (pidPacketBodyPointer >= PID_DATA_DUMP_SIZE) {
        // Packet is ready!
        noInterrupts();
        assert((sizeof(pidSample) * 8) % 16 == 0);
        pidPacketReady = true;

        digitalWriteFast(PID_DATA_READY_PIN, HIGH);
    }

    interrupts();
}

// Enqueue pid sample for logging
void recordPid(const volatile pidSample& s) {
    if (pidBufferEmpty() && !sampling) {
        //restart sampling once buffer has been cleared
        sampling = true;

        //insert a dummy sample into the stream to indicate the break in sampling
        pidSample fakeSample;
        fakeSample.sample.a = 0x10;
        fakeSample.sample.b = 0x11;
        fakeSample.sample.c = 0x12;
        fakeSample.sample.d = 0x13;
        fakeSample.incoherentOutput.a = 0x14;
        fakeSample.incoherentOutput.b = 0x14;
        fakeSample.incoherentOutput.c = 0x14;
        fakeSample.incoherentOutput.d = 0x14;
        fakeSample.out.x = 0x13;
        fakeSample.out.y = 0x12;
        fakeSample.out.useless1 = 0x11;
        fakeSample.out.useless2 = 0x10;
        ((pidSample *) pidSamples)[pidDataPointer] = fakeSample;
        pidDataPointer = (pidDataPointer + 1) % PID_BUFFER_SIZE;
        assert(pidDataPointer <= PID_BUFFER_SIZE);
        if (pidBufferFull()) {
            //buffer is full after one sample
            sampling = false;
        }
    }
    if (!sampling) {
        return;
    }
    ((pidSample *) pidSamples)[pidDataPointer] = s;
    pidDataPointer = (pidDataPointer + 1) % PID_BUFFER_SIZE;
    pidSamplesRead++;
    assert(pidDataPointer <= PID_BUFFER_SIZE);

    if (pidBufferFull()) {
        sampling = false;
    }
}

// Runs in main loop
void taskPidData() {
    if (!assert ((uint32_t) pidSamples[PID_BUFFER_SIZE].sample.c == 0xbeefbeef)) {
        debugPrintf("End of buf is %x\n", pidSamples[PID_BUFFER_SIZE].sample.c);
    }
    assert (pidDataPointer <= PID_BUFFER_SIZE);
    assert (!(sampling && (pidDataPointer >= PID_BUFFER_SIZE)));
    checkDataDump();
}

// Called from dma completion - clears packet buffer so we can prepare the next packet
void pidPacketSent() {
    digitalWrite(PID_DATA_READY_PIN, LOW);
    if ((assert(pidPacketReady))) {
        noInterrupts();
        pidPacketChecksum = 0;
        pidPacketBodyPointer = 0;
        pidPacketReady = false;
        pidSamplesSent += PID_DATA_DUMP_SIZE;
        interrupts();
    }
}

// Called from enterTracking
void enterPidData() {
    noInterrupts();
    pidPacketChecksum = 0;
    pidPacketReady = false;
    pidSentDataPointer = 0;
    pidDataPointer = 0;
    timeSinceLastRead = 0;
    pidPacketBodyPointer = 0;
    sampling = true;
    digitalWriteFast(PID_DATA_READY_PIN, LOW);
    interrupts();
}

// Called from leaveTracking
void leavePidData() {
    digitalWriteFast(PID_DATA_READY_PIN, LOW);
    noInterrupts();
    pidPacketReady = false;
    sampling = false;
    pidDataPointer = 0;
    interrupts();
}

void pidDataHeartbeat() {
    Serial.printf("PID front of buffer %d, back of buffer %d, packet ready? %d, chksum %d, packet pointer %d, sampling %d, packet %d, sent %d\n", pidDataPointer, pidSentDataPointer, pidPacketReady, pidPacketChecksum, pidPacketBodyPointer, sampling, pidPacketBodyPointer, pidSamplesSent);
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// main.cpp
// Sophia
// Blake Nelson
//
// Driver for the unit tests.
//
////////////////////////////////////////////////////////////////////////////////

#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>
#include <boost/test/included/unit_test_framework.hpp>
#include <boost/test/floating_point_comparison.hpp>

using boost::unit_test_framework::test_suite;

#include <iostream>
using namespace std;

#include <LibUtilities/BasicUtils/NekManager.hpp>
#include <LibUtilities/Foundations/Points.h>
#include <LibUtilities/Foundations/GaussPoints.h>
#include <LibUtilities/Foundations/PolyEPoints.h>
#include <LibUtilities/Foundations/Basis.h>
#include <LibUtilities/Foundations/NodalTriFekete.h>
#include <LibUtilities/Foundations/ManagerAccess.h>

using namespace Nektar;
using namespace Nektar::LibUtilities;

namespace Nektar
{
    namespace MyNewUnitTests
    {
        void simpleTest();
        void testPolyFunc();
    }
}

// The boost unit test framework provides the main function for us.
// All we need to do is provide a test suite.
test_suite* init_unit_test_suite( int, char* [] )
{
    test_suite* test= BOOST_TEST_SUITE( "Nektar++ Test Suite" );

    test->add(BOOST_TEST_CASE(&Nektar::MyNewUnitTests::simpleTest), 0);
    test->add(BOOST_TEST_CASE(&Nektar::MyNewUnitTests::testPolyFunc),0);

    return test;
}

namespace Nektar
{
    namespace MyNewUnitTests
    {
        void simpleTest()
        {
            int size = 10;

            //PointsKey gaussKey(size, eGaussLobattoLegendre);

            PointsKey gaussKey(size, eGaussGaussLegendre);
            PointsKey polyKey(size, ePolyEvenlySpaced);
            boost::shared_ptr<Points<double> > ptr = PointsManager()[gaussKey];
            boost::shared_ptr<NekMatrix<double> > mat = ptr->GetI(gaussKey);

            int m = mat->GetRows();
            int n = mat->GetColumns();
            cout << "(m, n) = (" << m << ", " << n << ")" <<  endl;

            BOOST_CHECK(mat->GetRows() == size); // Fails here
            BOOST_CHECK(mat->GetColumns() == size);

            Points<double> & points = *ptr;
            cout << "points.GetPointsDim()    = " << points.GetPointsDim() << endl;
            cout << "points.GetNumPoints()    = " << points.GetNumPoints() << endl;
            cout << "points.GetTotNumPoints() = " << points.GetTotNumPoints() << endl;
            double *z = points.GetZ();
            for( int i=0; i<size; ++i )
            {
                cout << "z[i] = " << z[i] <<  endl;
            }
            cout << endl;
            double *w = points.GetW();
            for( int i=0; i<size; ++i )
            {
                cout << "w[i] = " << w[i] <<  endl;
            }

            cout << "Happy Testing!" << endl;

        }

    }

    namespace TestUtilities
    {

        vector<double> generatePolynomial(int degree) {
            double a[] = {
                -1.3, 1.4, -1.5, 1.2, -1.3, 1.5, -0.1, 1.4, -3.2, 2.4, -1.0, 1.6, -1.3, 4.5,
                1.3, 1.9, 1.6, 1.3, 1.4, 1.7, 1.9, 0.3, 1.6, // 23
                1.2, 0.5, 1.0, 0.3, 0.5, 0.7, 0.4, 0.6 }; // 31
//             double a[] = {
//                 1, 1,  3,  3, 5, 5,  7, 7, 9,  9,
//                 11,11,13, 13,15,15, 17,17,19, 19,
//                 21,21,23, 23,25,25, 27,27,29, 29,
//                 31,31,33, 33,35,35, 37,37,39, 39,
//                 41,41,43, 43,45,45, 47,47,49, 49,
//                 51,51,53, 53,55,55, 57,57,59, 59,
//                 61
//             };

            vector<double> coefficients(a, a + degree + 1);
            return coefficients;
        }

        // Evaluates at x the polynomial that is given by the coefficents
        double evaluatePolynomial(double x, const vector<double> & coefficients) {
            int N = coefficients.size();
            double y = coefficients[N-1];
            for( int i = N-2; i >= 0; --i ) {
                y = coefficients[i] + x*y;
            }
            return y;
        }

        // Integrates the polynomial from [-1,1]
        double integrate(const vector<double> & coefficients) {
            int M = coefficients.size(), N = M - 1;
            double integral = 0;
            for( int n = 0; n <= N/2; ++n ) {
                integral += coefficients[2*n] / (2.0*n + 1.0);
//                 if( N == 4 ) {
//                     cout << "N/2 = " << N/2 << ", 2*n = " << 2*n << ", coefficients[2*n] = " << coefficients[2*n] << ", (2*n + 1) = " << (2*n + 1) << ", coefficients[2*n] / (2*n + 1) = " << coefficients[2*n] / (2*n + 1) << endl;
//                 }
            }
            return  2.0 * integral;
        }

        void printPolynomial(const vector<double> & a) {
            cout << a[0];
            if( a.size() > 1 ) {
                cout << " + " << a[1] << "x";
            }
            for( int n = 2; n < a.size(); ++n ) {
                cout << " + " << a[n] << "x^" << n;
            }
        }
    }
        namespace MyNewUnitTests
    {
        void testPolynomialOnWeights(const boost::shared_ptr<Points<double> > points, const vector<double> & polynomialCoefficients) {
            const double *z, *w;
            points->GetZW(z, w);
            int numPoints = points->GetNumPoints();

            for(int i = 0; i < polynomialCoefficients.size(); ++i) {
                vector<double> a( polynomialCoefficients.begin(), polynomialCoefficients.begin() + i + 1 );
                double analyticIntegral = TestUtilities::integrate(a);
                double numericIntegral = 0;
                for(int j = 0; j < numPoints; ++j) {
                    numericIntegral += w[j] * TestUtilities::evaluatePolynomial( z[j], a );
                }
                cout << "Points = " << numPoints << ", Polynomial degree = " << i << ", nCoef = " << a.size();
                cout << ", Integral = " << analyticIntegral << ", Computed area = " << numericIntegral;
//                 cout << ", P_" << i << " = "; TestUtilities::printPolynomial(a);
                cout << endl;

                BOOST_CHECK_CLOSE( numericIntegral, analyticIntegral, 1e-12 );
            }
        }
        const int MaxNumberOfPoints = 15;
//         const int MaxNumberOfPoints = 31;
        void testPolyFunc()
        {
//             int P[] = {2,4,8,12};
//             int N[] = {2,3,5,7};

            vector<double> coefficients;
            PointsType type;

            BOOST_CHECKPOINT("Testing eGaussGaussLegendre");
            type = eGaussGaussLegendre;
            for( int i = 1; i < MaxNumberOfPoints; ++i ) {
                int nPts = i, degree = 2*i - 1;
                coefficients = TestUtilities::generatePolynomial(degree);
                testPolynomialOnWeights( PointsManager()[PointsKey(nPts, type)], coefficients );
            }

            BOOST_CHECKPOINT("Testing eGaussLobattoLegendre");
            type = eGaussLobattoLegendre;
            for( int i = 1; i < MaxNumberOfPoints; ++i ) {
                int nPts = i, degree = 2*i - 3;
                coefficients = TestUtilities::generatePolynomial(degree);
                testPolynomialOnWeights( PointsManager()[PointsKey(nPts, type)], coefficients );
            }
        }
    }

}

/**
    $Log: main.cpp,v $
    Revision 1.2  2007/03/01 14:09:14  ehan
    *** empty log message ***

    Revision 1.1  2007/03/01 04:36:20  ehan
    Kdevelop for UnitTest

    Revision 1.1  2007/2/26 04:05:23  ehan
    Added the NewUnitTest project.

**/
<commit_msg>test passed eGaussRadauMLegendre, eGaussRadauPLegendre,         eGaussGaussLegendre, eGaussLobattoLegendre<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// main.cpp
// Sophia
// Blake Nelson
//
// Driver for the unit tests.
//
////////////////////////////////////////////////////////////////////////////////

#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>
#include <boost/test/included/unit_test_framework.hpp>
#include <boost/test/floating_point_comparison.hpp>

using boost::unit_test_framework::test_suite;

#include <iostream>
using namespace std;

#include <LibUtilities/BasicUtils/NekManager.hpp>
#include <LibUtilities/Foundations/Points.h>
#include <LibUtilities/Foundations/GaussPoints.h>
#include <LibUtilities/Foundations/PolyEPoints.h>
#include <LibUtilities/Foundations/Basis.h>
#include <LibUtilities/Foundations/NodalTriFekete.h>
#include <LibUtilities/Foundations/ManagerAccess.h>

using namespace Nektar;
using namespace Nektar::LibUtilities;

namespace Nektar
{
    namespace MyNewUnitTests
    {
        void simpleTest();
        void testPolyFunc();
    }
}

// The boost unit test framework provides the main function for us.
// All we need to do is provide a test suite.
test_suite* init_unit_test_suite( int, char* [] )
{
    test_suite* test= BOOST_TEST_SUITE( "Nektar++ Test Suite" );

    test->add(BOOST_TEST_CASE(&Nektar::MyNewUnitTests::simpleTest), 0);
    test->add(BOOST_TEST_CASE(&Nektar::MyNewUnitTests::testPolyFunc),0);

    return test;
}

namespace Nektar
{
    namespace MyNewUnitTests
    {
        void simpleTest()
        {
            int size = 10;

            //PointsKey gaussKey(size, eGaussLobattoLegendre);

            PointsKey gaussKey(size, eGaussGaussLegendre);
            PointsKey polyKey(size, ePolyEvenlySpaced);
            boost::shared_ptr<Points<double> > ptr = PointsManager()[gaussKey];
            boost::shared_ptr<NekMatrix<double> > mat = ptr->GetI(gaussKey);

            int m = mat->GetRows();
            int n = mat->GetColumns();
            cout << "(m, n) = (" << m << ", " << n << ")" <<  endl;

            BOOST_CHECK(mat->GetRows() == size); // Fails here
            BOOST_CHECK(mat->GetColumns() == size);

            Points<double> & points = *ptr;
            cout << "points.GetPointsDim()    = " << points.GetPointsDim() << endl;
            cout << "points.GetNumPoints()    = " << points.GetNumPoints() << endl;
            cout << "points.GetTotNumPoints() = " << points.GetTotNumPoints() << endl;
            double *z = points.GetZ();
            for( int i=0; i<size; ++i )
            {
                cout << "z[i] = " << z[i] <<  endl;
            }
            cout << endl;
            double *w = points.GetW();
            for( int i=0; i<size; ++i )
            {
                cout << "w[i] = " << w[i] <<  endl;
            }

            cout << "Happy Testing!" << endl;

        }

    }

    namespace TestUtilities
    {

        vector<double> generatePolynomial(int degree) {
            double a[] = {
                -1.3, 1.4, -1.5, 1.2, -1.3, 1.5, -0.1, 1.4, -3.2, 2.4, -1.0, 1.6, -1.3, 4.5,
                1.3, 1.9, 1.6, 1.3, 1.4, 1.7, 1.9, 0.3, 1.6, // 23
                1.2, 0.5, 1.0, 0.3, 0.5, 0.7, 0.4, 0.6 }; // 31
//             double a[] = {
//                 1, 1,  3,  3, 5, 5,  7, 7, 9,  9,
//                 11,11,13, 13,15,15, 17,17,19, 19,
//                 21,21,23, 23,25,25, 27,27,29, 29,
//                 31,31,33, 33,35,35, 37,37,39, 39,
//                 41,41,43, 43,45,45, 47,47,49, 49,
//                 51,51,53, 53,55,55, 57,57,59, 59,
//                 61
//             };

            vector<double> coefficients(a, a + degree + 1);
            return coefficients;
        }

        // Evaluates at x the polynomial that is given by the coefficents
        double evaluatePolynomial(double x, const vector<double> & coefficients) {
            int N = coefficients.size();
            double y = coefficients[N-1];
            for( int i = N-2; i >= 0; --i ) {
                y = coefficients[i] + x*y;
            }
            return y;
        }

        // Integrates the polynomial from [-1,1]
        double integrate(const vector<double> & coefficients) {
            int M = coefficients.size(), N = M - 1;
            double integral = 0;
            for( int n = 0; n <= N/2; ++n ) {
                integral += coefficients[2*n] / (2.0*n + 1.0);
//                 if( N == 4 ) {
//                     cout << "N/2 = " << N/2 << ", 2*n = " << 2*n << ", coefficients[2*n] = " << coefficients[2*n] << ", (2*n + 1) = " << (2*n + 1) << ", coefficients[2*n] / (2*n + 1) = " << coefficients[2*n] / (2*n + 1) << endl;
//                 }
            }
            return  2.0 * integral;
        }

        void printPolynomial(const vector<double> & a) {
            cout << a[0];
            if( a.size() > 1 ) {
                cout << " + " << a[1] << "x";
            }
            for( int n = 2; n < a.size(); ++n ) {
                cout << " + " << a[n] << "x^" << n;
            }
        }
    }
        namespace MyNewUnitTests
    {
        void testPolynomialOnWeights(const boost::shared_ptr<Points<double> > points, const vector<double> & polynomialCoefficients, bool isVerbose = false) {
            //bool isVerbose = false;

            const double *z, *w;
            points->GetZW(z, w);
            int numPoints = points->GetNumPoints();

            for(int i = 0; i < polynomialCoefficients.size(); ++i) {
                vector<double> a( polynomialCoefficients.begin(), polynomialCoefficients.begin() + i + 1 );
                double analyticIntegral = TestUtilities::integrate(a);
                double numericIntegral = 0;
                for(int j = 0; j < numPoints; ++j) {
                    numericIntegral += w[j] * TestUtilities::evaluatePolynomial( z[j], a );
                }
                if( isVerbose ) {
                    cout << "Points = " << numPoints << ", Polynomial degree = " << i << ", nCoef = " << a.size();
                    cout << ", Integral = " << analyticIntegral << ", Computed area = " << numericIntegral;
                    // cout << ", P_" << i << " = "; TestUtilities::printPolynomial(a);
                    cout << ", z[0] = " << z[0] << ", w[0] = " << w[0] << ", z[n-1] = " << z[numPoints-1] << ", w[n-1] = " << w[numPoints-1];
                    cout << endl;
                }

                //BOOST_CHECK_CLOSE( numericIntegral, analyticIntegral, 1e-12 );
                BOOST_CHECK_CLOSE( numericIntegral, analyticIntegral, 1e-11 );
            }

            if( isVerbose ) {
                cout << " End of the polynomial Unit Test" << endl;
            }
        }

        const int MaxNumberOfPoints = 15;

        void testPolyFunc()
        {
            vector<double> coefficients;
            PointsType type;
            const char * cp = "";

            type = eGaussGaussLegendre;
            cp = "Testing eGaussGaussLegendre";
            cout << cp << endl;
            BOOST_CHECKPOINT(cp);
            for( int i = 1; i < MaxNumberOfPoints; ++i ) {
                int nPts = i, n = nPts - 1, degree = 2*n + 1;
                coefficients = TestUtilities::generatePolynomial(degree);
                testPolynomialOnWeights( PointsManager()[PointsKey(nPts, type)], coefficients );
            }

            type = eGaussLobattoLegendre;
            cp = "Testing eGaussLobattoLegendre";
            cout << cp << endl;
            BOOST_CHECKPOINT(cp);
            for( int i = 1; i < MaxNumberOfPoints; ++i ) {
                int nPts = i, n = nPts - 1, degree = 2*n - 1;
                coefficients = TestUtilities::generatePolynomial(degree);
                testPolynomialOnWeights( PointsManager()[PointsKey(nPts, type)], coefficients );
            }

            type = eGaussRadauMLegendre;
            cp = "Testing eGaussRadauMLegendre";
            cout << cp << endl;
            BOOST_CHECKPOINT(cp);
            for( int i = 1; i< MaxNumberOfPoints; ++i) {
                int nPts = i, n = nPts - 1, degree = 2*n - 1;
                coefficients = TestUtilities::generatePolynomial(degree);
                testPolynomialOnWeights( PointsManager()[PointsKey(nPts, type)], coefficients );
            }

            type = eGaussRadauPLegendre;
            cp = "Testing eGaussRadauPLegendre";
            cout << cp << endl;
            BOOST_CHECKPOINT(cp);
            for( int i=1; i<MaxNumberOfPoints; ++i){
                int nPts = i, n = nPts - 1, degree = 2*n;
                coefficients = TestUtilities::generatePolynomial(degree);
                testPolynomialOnWeights( PointsManager()[PointsKey(nPts, type)], coefficients, true );
            }
        }
    }

}

//    enum PointsType
// 00075         {
// 00076             eNoPointsType,
// 00077             eGaussGaussLegendre,
// 00078             eGaussRadauMLegendre,
// 00079             eGaussRadauPLegendre,
// 00080             eGaussLobattoLegendre,
// 00081             eGaussGaussChebyshev,
// 00082             eGaussRadauMChebyshev,
// 00083             eGaussRadauPChebyshev,
// 00084             eGaussLobattoChebyshev,
// 00085             eGaussRadauMAlpha0Beta1,
// 00086             eGaussRadauMAlpha0Beta2,
// 00087             ePolyEvenlySpaced,
// 00088             eFourierEvenlySpaced,
// 00089             eNodalTriElec,
// 00090             eNodalTriFekete,
// 00091             eNodalTetElec,
// 00092             SIZE_PointsType
// 00093         };

/**
    $Log: main.cpp,v $
    Revision 1.4  2007/03/02 01:10:44  ehan
    fixed some bugs

    Revision 1.2  2007/03/01 14:09:14  ehan
    *** empty log message ***

    Revision 1.1  2007/03/01 04:36:20  ehan
    Kdevelop for UnitTest

    Revision 1.1  2007/2/26 04:05:23  ehan
    Added the NewUnitTest project.

**/
<|endoftext|>


<commit_before>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <asio.hpp>

#include <ctime>
#include <cstring>
#include <vector>
#include <functional>

#include "common.hxx"
#include "auth.hxx"
#include "service.hxx"
#include "realm.hxx"
#include "client.hxx"
#include "packets.hxx"

using namespace std;

Client::Client(const Realm* realm_,
               const asio::ip::udp::endpoint& ep)
: realm(realm_),
  endpoint(ep),
  online(false),
  lastContact(time(NULL)),
  advert(realm, endpoint),
  advertIterator(realm),
  isIteratingAdverts(false),
  advertIterationTimer(service)
{ }

Client::Client(const Client& that)
: realm(that.realm),
  endpoint(that.endpoint),
  online(that.online),
  lastContact(that.lastContact),
  advert(that.advert),
  advertIterator(that.advertIterator),
  isIteratingAdverts(that.isIteratingAdverts),
  advertIterationTimer(service)
{ }

bool Client::isOnline() const {
  return online && time(NULL) < lastContact + CONNECTION_TIMEOUT;
}

void Client::kill() {
  online = false;
}

const asio::ip::udp::endpoint& Client::getEndpoint() const {
  return endpoint;
}

void (Client::*const Client::messages[256])(const byte*, unsigned) = {
  &Client::connect,
  &Client::ping,
  &Client::proxy,
  &Client::post,
  &Client::list,
  &Client::sign,
  &Client::bye,
  //NULLs to end of array are implicit
};

#define READ(type,from) (*(reinterpret_cast<const type*>(from)))
#define WRITE(type,to) (*(reinterpret_cast<type*>(to)))

void Client::connect(const byte* dat, unsigned len) {
  contact();

  //Check length sanity
  if (len < 2*4 + HMAC_SIZE + 2 ||
      len > 2*4 + HMAC_SIZE + MAX_CLIENT_NAME_LENGTH + 1)
    return;

  //Ensure NUL-terminated
  if (dat[len-1]) return;

  unsigned id = READ(unsigned, dat);
  unsigned timestamp = READ(unsigned, dat+4);
  byte hmac[HMAC_SIZE];
  memcpy(hmac, dat+8, HMAC_SIZE);

  const char* name = (const char*)(dat+8+HMAC_SIZE);
  if (!*name) return; //Empty name

  if (authenticate(realm, id, timestamp, name, hmac)) {
    online = true;

    this->id = id;
    this->name = name;

    //Send response
    byte dontKnowWhoIAm = 1;
    ping(&dontKnowWhoIAm, 1);
  }
}

void Client::ping(const byte* dat, unsigned len) {
  contact();

  if (len == 1 && dat[0]) {
    //Client needs to know its external address/port
    vector<byte> response(1 + realm->addressSize + 2);
    response[0] = PAK_YOUARE;

    realm->encodeAddress(&response[1], endpoint.address());
    WRITE(unsigned short, &response[response.size()-2]) = endpoint.port();

    sendPacket(endpoint, &response[0], response.size());
  } else {
    //Just respond for the sake of two-way traffic
    byte response = PAK_PONG;
    sendPacket(endpoint, &response, 1);
  }
}

void Client::proxy(const byte* dat, unsigned len) {
  contact();
  //TODO
}

void Client::post(const byte* dat, unsigned len) {
  contact();

  if (len > MAX_ADVERTISEMENT_SIZE)
    return;

  advert.setData(dat, len);
}

void Client::list(const byte* dat, unsigned len) {
  contact();

  if (isIteratingAdverts) return;

  isIteratingAdverts = true;
  setIterationTimer();
}
void Client::sign(const byte* dat, unsigned len) {
  contact();
  //TODO
}

void Client::bye(const byte* dat, unsigned len) {
  contact();

  online = false;
}

void Client::contact() {
  lastContact = time(NULL);
}

//G++'s bind1st seems to be broken, as it tries to overload its operator() in a
//forbidden manner.
struct ClientTHBind1st {
  Client* that;
  void (*f)(Client*, const asio::error_code&);

  void operator()(const asio::error_code& code) {
    f(that, code);
  }
};

void Client::setIterationTimer() {
  advertIterationTimer.expires_from_now(boost::posix_time::milliseconds(512));
  ClientTHBind1st f;
  f.that = this;
  f.f = &Client::timerHandler_static;
  advertIterationTimer.async_wait(f);
}

void Client::timerHandler_static(Client* c, const asio::error_code& code) {
  c->timerHandler(code);
}

void Client::timerHandler(const asio::error_code&) {
  asio::ip::udp::endpoint from;
  vector<byte> pack(1 + realm->addressSize + 2);
  if (advertIterator.next(from, pack)) {
    pack[0] = PAK_FROMOTHER;
    realm->encodeAddress(&pack[1], from.address());
    WRITE(unsigned short, &pack[1+realm->addressSize]) = from.port();
    setIterationTimer();
  } else {
    isIteratingAdverts = false;
  }
}
<commit_msg>Fix Client::timerHandler() not actually sending the packet.<commit_after>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <asio.hpp>

#include <ctime>
#include <cstring>
#include <vector>
#include <functional>

#include "common.hxx"
#include "auth.hxx"
#include "service.hxx"
#include "realm.hxx"
#include "client.hxx"
#include "packets.hxx"

using namespace std;

Client::Client(const Realm* realm_,
               const asio::ip::udp::endpoint& ep)
: realm(realm_),
  endpoint(ep),
  online(false),
  lastContact(time(NULL)),
  advert(realm, endpoint),
  advertIterator(realm),
  isIteratingAdverts(false),
  advertIterationTimer(service)
{ }

Client::Client(const Client& that)
: realm(that.realm),
  endpoint(that.endpoint),
  online(that.online),
  lastContact(that.lastContact),
  advert(that.advert),
  advertIterator(that.advertIterator),
  isIteratingAdverts(that.isIteratingAdverts),
  advertIterationTimer(service)
{ }

bool Client::isOnline() const {
  return online && time(NULL) < lastContact + CONNECTION_TIMEOUT;
}

void Client::kill() {
  online = false;
}

const asio::ip::udp::endpoint& Client::getEndpoint() const {
  return endpoint;
}

void (Client::*const Client::messages[256])(const byte*, unsigned) = {
  &Client::connect,
  &Client::ping,
  &Client::proxy,
  &Client::post,
  &Client::list,
  &Client::sign,
  &Client::bye,
  //NULLs to end of array are implicit
};

#define READ(type,from) (*(reinterpret_cast<const type*>(from)))
#define WRITE(type,to) (*(reinterpret_cast<type*>(to)))

void Client::connect(const byte* dat, unsigned len) {
  contact();

  //Check length sanity
  if (len < 2*4 + HMAC_SIZE + 2 ||
      len > 2*4 + HMAC_SIZE + MAX_CLIENT_NAME_LENGTH + 1)
    return;

  //Ensure NUL-terminated
  if (dat[len-1]) return;

  unsigned id = READ(unsigned, dat);
  unsigned timestamp = READ(unsigned, dat+4);
  byte hmac[HMAC_SIZE];
  memcpy(hmac, dat+8, HMAC_SIZE);

  const char* name = (const char*)(dat+8+HMAC_SIZE);
  if (!*name) return; //Empty name

  if (authenticate(realm, id, timestamp, name, hmac)) {
    online = true;

    this->id = id;
    this->name = name;

    //Send response
    byte dontKnowWhoIAm = 1;
    ping(&dontKnowWhoIAm, 1);
  }
}

void Client::ping(const byte* dat, unsigned len) {
  contact();

  if (len == 1 && dat[0]) {
    //Client needs to know its external address/port
    vector<byte> response(1 + realm->addressSize + 2);
    response[0] = PAK_YOUARE;

    realm->encodeAddress(&response[1], endpoint.address());
    WRITE(unsigned short, &response[response.size()-2]) = endpoint.port();

    sendPacket(endpoint, &response[0], response.size());
  } else {
    //Just respond for the sake of two-way traffic
    byte response = PAK_PONG;
    sendPacket(endpoint, &response, 1);
  }
}

void Client::proxy(const byte* dat, unsigned len) {
  contact();
  //TODO
}

void Client::post(const byte* dat, unsigned len) {
  contact();

  if (len > MAX_ADVERTISEMENT_SIZE)
    return;

  advert.setData(dat, len);
}

void Client::list(const byte* dat, unsigned len) {
  contact();

  if (isIteratingAdverts) return;

  isIteratingAdverts = true;
  setIterationTimer();
}
void Client::sign(const byte* dat, unsigned len) {
  contact();
  //TODO
}

void Client::bye(const byte* dat, unsigned len) {
  contact();

  online = false;
}

void Client::contact() {
  lastContact = time(NULL);
}

//G++'s bind1st seems to be broken, as it tries to overload its operator() in a
//forbidden manner.
struct ClientTHBind1st {
  Client* that;
  void (*f)(Client*, const asio::error_code&);

  void operator()(const asio::error_code& code) {
    f(that, code);
  }
};

void Client::setIterationTimer() {
  advertIterationTimer.expires_from_now(boost::posix_time::milliseconds(512));
  ClientTHBind1st f;
  f.that = this;
  f.f = &Client::timerHandler_static;
  advertIterationTimer.async_wait(f);
}

void Client::timerHandler_static(Client* c, const asio::error_code& code) {
  c->timerHandler(code);
}

void Client::timerHandler(const asio::error_code&) {
  asio::ip::udp::endpoint from;
  vector<byte> pack(1 + realm->addressSize + 2);
  if (advertIterator.next(from, pack)) {
    pack[0] = PAK_FROMOTHER;
    realm->encodeAddress(&pack[1], from.address());
    WRITE(unsigned short, &pack[1+realm->addressSize]) = from.port();
    sendPacket(endpoint, &pack[0], pack.size());
    setIterationTimer();
  } else {
    isIteratingAdverts = false;
  }
}
<|endoftext|>


<commit_before>/*
 * Code Copyright 2011 Robert Hodgin ( http://roberthodgin.com ) and Andrew Bell ( http://drawnline.net )
 * Used with permission for the Cinder Project ( http://libcinder.org )
 */

#include "cinder/app/AppBasic.h"
#include "cinder/Rand.h"
#include "cinder/ImageIo.h"
#include "cinder/gl/gl.h"
#include "cinder/gl/Texture.h"
#include "cinder/gl/TextureFont.h"

#include <list>
#include <algorithm>

#include "Resources.h"
#include "WordNode.h"
#include "Dictionary.h"
#include "CenterState.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class VisualDictionaryApp : public AppBasic {
  public:
	void prepareSettings( Settings *settings );
	void layoutWords( vector<string> words, float radius );
	void setup();
	void initialize();
	void enableSelections() { mEnableSelections = true; }
	void mouseMove( MouseEvent event );
	void mouseDown( MouseEvent event );
	void keyDown( KeyEvent event );
	float getLayoutRadius(){ return getWindowHeight() * 0.415f; }

	void selectNode( list<WordNode>::iterator selectedWord );

	void update();
	void draw();

	list<WordNode>::iterator	getNodeAtPoint( const Vec2f &point );

	shared_ptr<Dictionary>		mDictionary;
	list<WordNode>				mNodes, mDyingNodes;
	list<WordNode>::iterator	mMouseOverNode;

	CenterState					mCenterState;

	gl::Texture					mBgTex;
	gl::Texture					mCircleTex;
	gl::Texture					mSmallCircleTex;

	bool						mEnableSelections;
	WordNode					mCurrentNode;
	float						mCurrentCircleRadius;
};

void VisualDictionaryApp::prepareSettings( Settings *settings )
{
	settings->setWindowSize( 800, 800 );
}

void VisualDictionaryApp::layoutWords( vector<string> words, float radius )
{
	int radiusDivisor = 26;//std::max<int>( 10, words.size() ); // don't let the circles get too small
	mCurrentCircleRadius = radius / radiusDivisor * M_PI;
	for( size_t w = 0; w < words.size(); ++w ) {
		int wordLength	= words[w].length();
		string s		= words[w];
		int charIndex	= (int)s[wordLength-1] - 97;
		float charPer	= charIndex/26.0f;
		float angle		= charPer * 2.0f * M_PI;
		//float angle = w / (float)words.size() * 2 * M_PI;
		Vec2f pos = getWindowCenter() + radius * Vec2f( cos( angle ), sin( angle ) );
		Color col(  CM_HSV, charPer, 0.875f, 1 );
		mNodes.push_back( WordNode( words[w] ) );
		mNodes.back().mPos = getWindowCenter() + radius * 0.5f * Vec2f( cos( angle ), sin( angle ) );
		mNodes.back().mColor = ColorA( col, 0.0f );
		mNodes.back().mRadiusDest = mCurrentCircleRadius;
		mNodes.back().mRadius = 0;

		timeline().apply( &mNodes.back().mRadius, mNodes.back().mRadiusDest, 0.4f, EaseOutAtan( 10 ) ).timelineEnd( -0.39f );
		timeline().apply( &mNodes.back().mPos, pos, 0.4f, EaseOutAtan( 10 ) ).timelineEnd( -0.39f );
		timeline().apply( &mNodes.back().mColor, ColorA( col, 1.0f ), 0.4f, EaseOutAtan( 10 ) ).timelineEnd( -0.39f );
	}
}

void VisualDictionaryApp::setup()
{
	mCenterState = CenterState( 140.0f );

	// load textures
	mBgTex = gl::Texture( loadImage( loadResource( RES_BACKGROUND_IMAGE ) ) );
	gl::Texture::Format fmt;
	fmt.enableMipmapping();
	mCircleTex = gl::Texture( loadImage( loadResource( RES_CIRCLE_IMAGE ) ), fmt );
	mSmallCircleTex = gl::Texture( loadImage( loadResource( RES_SMALL_CIRCLE_IMAGE ) ), fmt );

	// load the dictionary
	mDictionary = shared_ptr<Dictionary>( new Dictionary( loadResource( RES_DICTIONARY ) ) );

	// give the WordNodes their font
	WordNode::setFont( gl::TextureFont::create( Font( loadResource( RES_FONT ), 34 ), gl::TextureFont::Format().enableMipmapping( true ) ) );

	// give CenterState its font
	CenterState::setFont( gl::TextureFont::create( Font( loadResource( RES_FONT ), 150 ), gl::TextureFont::Format().enableMipmapping( true ) ) );

	initialize();
}

void VisualDictionaryApp::initialize()
{
	mNodes.clear();
	// make the first 26 nodes, one for each letter
	vector<string> initialWords;
	for( char c = 0; c < 26; ++c )
		initialWords.push_back( string( 1, (char)('a' + c) ) );

	layoutWords( initialWords, getLayoutRadius() );

	mCenterState.mCircles.clear();
	mCenterState.setWord( "" );

	// mark our currently highlighted node as "none"
	mMouseOverNode = mNodes.end();

	mEnableSelections = true;
}

list<WordNode>::iterator VisualDictionaryApp::getNodeAtPoint( const Vec2f &point )
{
	for( list<WordNode>::iterator nodeIt = mNodes.begin(); nodeIt != mNodes.end(); ++nodeIt ) {
		if( nodeIt->isPointInside( point ) )
			return nodeIt;
	}

	return mNodes.end();
}

void VisualDictionaryApp::keyDown( KeyEvent event )
{
	if( ! mEnableSelections )
		return;

	if( isalpha( event.getChar() ) ){
		// see if we can find a word that ends with this letter
		list<WordNode>::iterator foundWord = mNodes.end();
		for( foundWord = mNodes.begin(); foundWord != mNodes.end(); ++foundWord ) {
			if( foundWord->getWord()[foundWord->getWord().size()-1] == event.getChar() )
				break;
		}

		if( foundWord != mNodes.end() )
			selectNode( foundWord );
	} else {
		if( event.getCode() == KeyEvent::KEY_BACKSPACE ){
			initialize();
		}
	}
}

void VisualDictionaryApp::mouseDown( MouseEvent event )
{
	list<WordNode>::iterator clickedNode = getNodeAtPoint( event.getPos() );
	if( clickedNode != mNodes.end() ){
		selectNode( clickedNode );
	} else {
		if( ( event.getPos() - getWindowCenter() ).length() < 180.0f )
			initialize();
	}
}

void VisualDictionaryApp::mouseMove( MouseEvent event )
{
	if( ! mEnableSelections )
		return;

	list<WordNode>::iterator currentMouseOver = getNodeAtPoint( event.getPos() );

	if( currentMouseOver != mMouseOverNode ) {
		mMouseOverNode = currentMouseOver;

		// make all the circles not moused-over normal size, and the mouse-over big
		for( list<WordNode>::iterator nodeIt = mNodes.begin(); nodeIt != mNodes.end(); ++nodeIt ) {
			if( mMouseOverNode == nodeIt ){
				timeline().apply( &nodeIt->mRadius, mCurrentCircleRadius * 1.35f, 0.25f, EaseOutElastic( 2.0f, 1.2f ) );
			} else {
				timeline().apply( &nodeIt->mRadius, mCurrentCircleRadius, 0.5f, EaseOutAtan( 10 ) );
			}
		}
	}
}

void VisualDictionaryApp::selectNode( list<WordNode>::iterator selectedNode )
{
	// have all the nodes but this one disappear
	for( list<WordNode>::iterator nodeIt = mNodes.begin(); nodeIt != mNodes.end(); ++nodeIt ) {
		if( nodeIt != selectedNode ) {
			// copy this node to dying nodes and erase it from the current
			mDyingNodes.push_back( *nodeIt );
			timeline().apply( &mDyingNodes.back().mRadius, 0.0f, 0.5f, EaseInQuint() )
				.finishFn( bind( &WordNode::setShouldBeDeleted, &(mDyingNodes.back()) ) ); // when you're done, mark yourself for deletion
		}
	}

	mCurrentNode = *selectedNode;
	mCurrentNode.setSelected();
	mNodes.clear();

	Color c = Color( mCurrentNode.mColor().r, mCurrentNode.mColor().g, mCurrentNode.mColor().b );
	Vec2f dirToCenter = ( mCurrentNode.mPos() - getWindowCenter() ) * 0.5f;

	timeline().add( bind( &CenterState::addCircle, &mCenterState, mCurrentNode.getWord(), c, dirToCenter * 0.2f ), timeline().getCurrentTime() + 0.25f );

	// move the selected node towards the center

	timeline().apply( &mCurrentNode.mPos, getWindowCenter() + dirToCenter, 0.3f, EaseInQuint() );
	timeline().apply( &mCurrentNode.mColor, ColorA( mCurrentNode.mColor().r, mCurrentNode.mColor().g, mCurrentNode.mColor().b, 0.0f ), 0.3f, EaseInAtan( 10 ) );

	// now add all the descendants of the clicked node
	vector<string> children( mDictionary->getDescendants( mCurrentNode.getWord() ) );
	layoutWords( children, getLayoutRadius() );

	// mark our currently highlighted node as "none"
	mMouseOverNode = mNodes.end();

	// once everything is done animating, then we can allow selections, but for now, disable them
	mEnableSelections = false;
	std::function<void()> cueAction = bind( &VisualDictionaryApp::enableSelections, this );
	timeline().add( cueAction, timeline().getEndTime() - 2.0f );
}

void VisualDictionaryApp::update()
{
	if( mDictionary->isCompleteWord( mCurrentNode.getWord() ) ){
		mCenterState.update( mCurrentNode );
	}

	// erase any nodes which have been marked as ready to be deleted
	mDyingNodes.remove_if( bind( &WordNode::shouldBeDeleted, _1 ) );
}

void VisualDictionaryApp::draw()
{
	gl::clear( Color( 0, 0, 0 ) );
	gl::enableAlphaBlending();

	// draw background image
	gl::color( Color::white() );
	mBgTex.enableAndBind();
	gl::drawSolidRect( getWindowBounds() );

	mCircleTex.bind();

	// draw the center circles
	mCenterState.draw();

	// draw the dying nodes
	mSmallCircleTex.bind();
	for( list<WordNode>::const_iterator nodeIt = mDyingNodes.begin(); nodeIt != mDyingNodes.end(); ++nodeIt )
		nodeIt->draw();

	// draw all the non-mouseOver nodes
	for( list<WordNode>::const_iterator nodeIt = mNodes.begin(); nodeIt != mNodes.end(); ++nodeIt ){
		if( nodeIt != mMouseOverNode )
			nodeIt->draw();
	}

	// if there is a mouseOverNode, draw it last so it is 'above' the non-mouseOver nodes
	if( mMouseOverNode != mNodes.end() )
		mMouseOverNode->draw();

	// if there is a currentNode (previously selected), draw it
	if( ! mCurrentNode.getWord().empty() )
		mCurrentNode.draw();

	mSmallCircleTex.disable();
}

CINDER_APP_BASIC( VisualDictionaryApp, RendererGl )
<commit_msg>Fixed an issue with the timeline VisualDictionary sample, which did not compile in vs2010. Please check if this fix is compatible with MacOSX before merging it.<commit_after>/*
 * Code Copyright 2011 Robert Hodgin ( http://roberthodgin.com ) and Andrew Bell ( http://drawnline.net )
 * Used with permission for the Cinder Project ( http://libcinder.org )
 */

#include "cinder/app/AppBasic.h"
#include "cinder/Rand.h"
#include "cinder/ImageIo.h"
#include "cinder/gl/gl.h"
#include "cinder/gl/Texture.h"
#include "cinder/gl/TextureFont.h"

#include <list>
#include <algorithm>

#include "Resources.h"
#include "WordNode.h"
#include "Dictionary.h"
#include "CenterState.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class VisualDictionaryApp : public AppBasic {
  public:
	void prepareSettings( Settings *settings );
	void layoutWords( vector<string> words, float radius );
	void setup();
	void initialize();
	void enableSelections() { mEnableSelections = true; }
	void mouseMove( MouseEvent event );
	void mouseDown( MouseEvent event );
	void keyDown( KeyEvent event );
	float getLayoutRadius(){ return getWindowHeight() * 0.415f; }

	void selectNode( list<WordNode>::iterator selectedWord );

	void update();
	void draw();

	list<WordNode>::iterator	getNodeAtPoint( const Vec2f &point );

	shared_ptr<Dictionary>		mDictionary;
	list<WordNode>				mNodes, mDyingNodes;
	list<WordNode>::iterator	mMouseOverNode;

	CenterState					mCenterState;

	gl::Texture					mBgTex;
	gl::Texture					mCircleTex;
	gl::Texture					mSmallCircleTex;

	bool						mEnableSelections;
	WordNode					mCurrentNode;
	float						mCurrentCircleRadius;
};

void VisualDictionaryApp::prepareSettings( Settings *settings )
{
	settings->setWindowSize( 800, 800 );
}

void VisualDictionaryApp::layoutWords( vector<string> words, float radius )
{
	int radiusDivisor = 26;//std::max<int>( 10, words.size() ); // don't let the circles get too small
	mCurrentCircleRadius = radius / radiusDivisor * M_PI;
	for( size_t w = 0; w < words.size(); ++w ) {
		int wordLength	= words[w].length();
		string s		= words[w];
		int charIndex	= (int)s[wordLength-1] - 97;
		float charPer	= charIndex/26.0f;
		float angle		= charPer * 2.0f * M_PI;
		//float angle = w / (float)words.size() * 2 * M_PI;
		Vec2f pos = getWindowCenter() + radius * Vec2f( cos( angle ), sin( angle ) );
		Color col(  CM_HSV, charPer, 0.875f, 1 );
		mNodes.push_back( WordNode( words[w] ) );
		mNodes.back().mPos = getWindowCenter() + radius * 0.5f * Vec2f( cos( angle ), sin( angle ) );
		mNodes.back().mColor = ColorA( col, 0.0f );
		mNodes.back().mRadiusDest = mCurrentCircleRadius;
		mNodes.back().mRadius = 0;

		timeline().apply( &mNodes.back().mRadius, mNodes.back().mRadiusDest, 0.4f, EaseOutAtan( 10 ) ).timelineEnd( -0.39f );
		timeline().apply( &mNodes.back().mPos, pos, 0.4f, EaseOutAtan( 10 ) ).timelineEnd( -0.39f );
		timeline().apply( &mNodes.back().mColor, ColorA( col, 1.0f ), 0.4f, EaseOutAtan( 10 ) ).timelineEnd( -0.39f );
	}
}

void VisualDictionaryApp::setup()
{
	mCenterState = CenterState( 140.0f );

	// load textures
	mBgTex = gl::Texture( loadImage( loadResource( RES_BACKGROUND_IMAGE ) ) );
	gl::Texture::Format fmt;
	fmt.enableMipmapping();
	mCircleTex = gl::Texture( loadImage( loadResource( RES_CIRCLE_IMAGE ) ), fmt );
	mSmallCircleTex = gl::Texture( loadImage( loadResource( RES_SMALL_CIRCLE_IMAGE ) ), fmt );

	// load the dictionary
	mDictionary = shared_ptr<Dictionary>( new Dictionary( loadResource( RES_DICTIONARY ) ) );

	// give the WordNodes their font
	WordNode::setFont( gl::TextureFont::create( Font( loadResource( RES_FONT ), 34 ), gl::TextureFont::Format().enableMipmapping( true ) ) );

	// give CenterState its font
	CenterState::setFont( gl::TextureFont::create( Font( loadResource( RES_FONT ), 150 ), gl::TextureFont::Format().enableMipmapping( true ) ) );

	initialize();
}

void VisualDictionaryApp::initialize()
{
	mNodes.clear();
	// make the first 26 nodes, one for each letter
	vector<string> initialWords;
	for( char c = 0; c < 26; ++c )
		initialWords.push_back( string( 1, (char)('a' + c) ) );

	layoutWords( initialWords, getLayoutRadius() );

	mCenterState.mCircles.clear();
	mCenterState.setWord( "" );

	// mark our currently highlighted node as "none"
	mMouseOverNode = mNodes.end();

	mEnableSelections = true;
}

list<WordNode>::iterator VisualDictionaryApp::getNodeAtPoint( const Vec2f &point )
{
	for( list<WordNode>::iterator nodeIt = mNodes.begin(); nodeIt != mNodes.end(); ++nodeIt ) {
		if( nodeIt->isPointInside( point ) )
			return nodeIt;
	}

	return mNodes.end();
}

void VisualDictionaryApp::keyDown( KeyEvent event )
{
	if( ! mEnableSelections )
		return;

	if( isalpha( event.getChar() ) ){
		// see if we can find a word that ends with this letter
		list<WordNode>::iterator foundWord = mNodes.end();
		for( foundWord = mNodes.begin(); foundWord != mNodes.end(); ++foundWord ) {
			if( foundWord->getWord()[foundWord->getWord().size()-1] == event.getChar() )
				break;
		}

		if( foundWord != mNodes.end() )
			selectNode( foundWord );
	} else {
		if( event.getCode() == KeyEvent::KEY_BACKSPACE ){
			initialize();
		}
	}
}

void VisualDictionaryApp::mouseDown( MouseEvent event )
{
	list<WordNode>::iterator clickedNode = getNodeAtPoint( event.getPos() );
	if( clickedNode != mNodes.end() ){
		selectNode( clickedNode );
	} else {
		if( ( event.getPos() - getWindowCenter() ).length() < 180.0f )
			initialize();
	}
}

void VisualDictionaryApp::mouseMove( MouseEvent event )
{
	if( ! mEnableSelections )
		return;

	list<WordNode>::iterator currentMouseOver = getNodeAtPoint( event.getPos() );

	if( currentMouseOver != mMouseOverNode ) {
		mMouseOverNode = currentMouseOver;

		// make all the circles not moused-over normal size, and the mouse-over big
		for( list<WordNode>::iterator nodeIt = mNodes.begin(); nodeIt != mNodes.end(); ++nodeIt ) {
			if( mMouseOverNode == nodeIt ){
				timeline().apply( &nodeIt->mRadius, mCurrentCircleRadius * 1.35f, 0.25f, EaseOutElastic( 2.0f, 1.2f ) );
			} else {
				timeline().apply( &nodeIt->mRadius, mCurrentCircleRadius, 0.5f, EaseOutAtan( 10 ) );
			}
		}
	}
}

void VisualDictionaryApp::selectNode( list<WordNode>::iterator selectedNode )
{
	// have all the nodes but this one disappear
	for( list<WordNode>::iterator nodeIt = mNodes.begin(); nodeIt != mNodes.end(); ++nodeIt ) {
		if( nodeIt != selectedNode ) {
			// copy this node to dying nodes and erase it from the current
			mDyingNodes.push_back( *nodeIt );
			timeline().apply( &mDyingNodes.back().mRadius, 0.0f, 0.5f, EaseInQuint() )
				.finishFn( bind( &WordNode::setShouldBeDeleted, &(mDyingNodes.back()) ) ); // when you're done, mark yourself for deletion
		}
	}

	mCurrentNode = *selectedNode;
	mCurrentNode.setSelected();
	mNodes.clear();

	Color c = Color( mCurrentNode.mColor().r, mCurrentNode.mColor().g, mCurrentNode.mColor().b );
	Vec2f dirToCenter = ( mCurrentNode.mPos() - getWindowCenter() ) * 0.5f;

	timeline().add( bind( &CenterState::addCircle, &mCenterState, mCurrentNode.getWord(), c, dirToCenter * 0.2f ), timeline().getCurrentTime() + 0.25f );

	// move the selected node towards the center

	timeline().apply( &mCurrentNode.mPos, getWindowCenter() + dirToCenter, 0.3f, EaseInQuint() );
	timeline().apply( &mCurrentNode.mColor, ColorA( mCurrentNode.mColor().r, mCurrentNode.mColor().g, mCurrentNode.mColor().b, 0.0f ), 0.3f, EaseInAtan( 10 ) );

	// now add all the descendants of the clicked node
	vector<string> children( mDictionary->getDescendants( mCurrentNode.getWord() ) );
	layoutWords( children, getLayoutRadius() );

	// mark our currently highlighted node as "none"
	mMouseOverNode = mNodes.end();

	// once everything is done animating, then we can allow selections, but for now, disable them
	mEnableSelections = false;
	std::function<void()> cueAction = bind( &VisualDictionaryApp::enableSelections, this );
	timeline().add( cueAction, timeline().getEndTime() - 2.0f );
}

void VisualDictionaryApp::update()
{
	if( mDictionary->isCompleteWord( mCurrentNode.getWord() ) ){
		mCenterState.update( mCurrentNode );
	}

	// erase any nodes which have been marked as ready to be deleted
	mDyingNodes.remove_if( bind( &WordNode::shouldBeDeleted, std::placeholders::_1 ) );
}

void VisualDictionaryApp::draw()
{
	gl::clear( Color( 0, 0, 0 ) );
	gl::enableAlphaBlending();

	// draw background image
	gl::color( Color::white() );
	mBgTex.enableAndBind();
	gl::drawSolidRect( getWindowBounds() );

	mCircleTex.bind();

	// draw the center circles
	mCenterState.draw();

	// draw the dying nodes
	mSmallCircleTex.bind();
	for( list<WordNode>::const_iterator nodeIt = mDyingNodes.begin(); nodeIt != mDyingNodes.end(); ++nodeIt )
		nodeIt->draw();

	// draw all the non-mouseOver nodes
	for( list<WordNode>::const_iterator nodeIt = mNodes.begin(); nodeIt != mNodes.end(); ++nodeIt ){
		if( nodeIt != mMouseOverNode )
			nodeIt->draw();
	}

	// if there is a mouseOverNode, draw it last so it is 'above' the non-mouseOver nodes
	if( mMouseOverNode != mNodes.end() )
		mMouseOverNode->draw();

	// if there is a currentNode (previously selected), draw it
	if( ! mCurrentNode.getWord().empty() )
		mCurrentNode.draw();

	mSmallCircleTex.disable();
}

CINDER_APP_BASIC( VisualDictionaryApp, RendererGl )
<|endoftext|>