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

//
// Zip / Unzip file using ijar zip implementation.
//
// Note that this Zip implementation intentionally don't compute CRC-32
// because it is useless computation for jar because Java doesn't care.
// CRC-32 of all files in the zip file will be set to 0.
//

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <memory>

#include "third_party/ijar/zip.h"

namespace devtools_ijar {

#define SYSCALL(expr)  do { \
                         if ((expr) < 0) { \
                           perror(#expr); \
                           abort(); \
                         } \
                       } while (0)

//
// A ZipExtractorProcessor that extract all files in the ZIP file.
//
class UnzipProcessor : public ZipExtractorProcessor {
 public:
  // Create a processor who will extract the files into output_root
  // if "extract" is set to true and will print the list of files and
  // their unix modes if "verbose" is set to true.
  UnzipProcessor(const char *output_root, bool verbose, bool extract)
    : output_root_(output_root), verbose_(verbose), extract_(extract) {}
  virtual ~UnzipProcessor() {}

  virtual void Process(const char* filename, const u4 attr,
                       const u1* data, const size_t size);
  virtual bool Accept(const char* filename, const u4 attr) {
    return true;
  }

 private:
  const char *output_root_;
  const bool verbose_;
  const bool extract_;
};

// Concatene 2 path, path1 and path2, using / as a directory separator and
// puting the result in "out". "size" specify the size of the output buffer
void concat_path(char* out, const size_t size,
                 const char *path1, const char *path2) {
  int len1 = strlen(path1);
  int l = len1;
  strncpy(out, path1, size-1);
  out[size-1] = 0;
  if (l < size - 1 && path1[len1] != '/' && path2[0] != '/') {
    out[l] = '/';
    l++;
    out[l] = 0;
  }
  if (l < size - 1) {
    strncat(out, path2, size - 1 - l);
  }
}

// Do a recursive mkdir of all folders of path except the last path
// segment (if path ends with a / then the last path segment is empty).
// All folders are created using "mode" for creation mode.
void mkdirs(const char *path, mode_t mode) {
  char path_[PATH_MAX];
  struct stat statst;
  strncpy(path_, path, PATH_MAX);
  path_[PATH_MAX-1] = 0;
  char *pointer = path_;
  while ((pointer = strchr(pointer, '/')) != NULL) {
    if (path_ != pointer) {  // skip leading slash
      *pointer = 0;
      if (stat(path_, &statst) != 0) {
        if (mkdir(path_, mode) < 0) {
          fprintf(stderr, "Cannot create folder %s: %s\n",
                  path_, strerror(errno));
          abort();
        }
      }
      *pointer = '/';
    }
    pointer++;
  }
}

void UnzipProcessor::Process(const char* filename, const u4 attr,
                             const u1* data, const size_t size) {
  mode_t mode = zipattr_to_mode(attr);
  mode_t perm = mode & 0777;
  bool isdir = (mode & S_IFDIR) != 0;
  if (verbose_) {
    printf("%c %o %s\n", isdir ? 'd' : 'f', perm, filename);
  }
  if (extract_) {
    char path[PATH_MAX];
    int fd;
    concat_path(path, PATH_MAX, output_root_, filename);
    mkdirs(path, perm);
    if (!isdir) {
      fd = open(path, O_CREAT | O_WRONLY, perm);
      if (fd < 0) {
        fprintf(stderr, "Cannot open file %s for writing: %s\n",
                path, strerror(errno));
        abort();
      }
      SYSCALL(write(fd, data, size));
      SYSCALL(close(fd));
    }
  }
}

// Get the basename of path and store it in output. output_size
// is the size of the output buffer.
void basename(const char *path, char *output, size_t output_size) {
  const char *pointer = strrchr(path, '/');
  if (pointer == NULL) {
    pointer = path;
  } else {
    pointer++;  // Skip the leading slash.
  }
  strncpy(output, pointer, output_size);
  output[output_size-1] = 0;
}

// Execute the extraction (or just listing if just v is provided)
int extract(char *zipfile, bool verbose, bool extract) {
  char output_root[PATH_MAX];
  getcwd(output_root, PATH_MAX);

  UnzipProcessor processor(output_root, verbose, extract);
  std::unique_ptr<ZipExtractor> extractor(ZipExtractor::Create(zipfile,
                                                               &processor));
  if (extractor.get() == NULL) {
    fprintf(stderr, "Unable to open zip file %s: %s.\n", zipfile,
            strerror(errno));
    return -1;
  }

  if (extractor->ProcessAll() < 0) {
    fprintf(stderr, "%s.\n", extractor->GetError());
    return -1;
  }
  return 0;
}

// Execute the create operation
int create(char *zipfile, char **files, bool flatten, bool verbose) {
  struct stat statst;
  u8 size = ZipBuilder::EstimateSize(files);
  if (size == 0) {
    return -1;
  }
  std::unique_ptr<ZipBuilder> builder(ZipBuilder::Create(zipfile, size));
  if (builder.get() == NULL) {
    fprintf(stderr, "Unable to create zip file %s: %s.\n",
            zipfile, strerror(errno));
    return -1;
  }
  for (int i = 0; files[i] != NULL; i++) {
    stat(files[i], &statst);
    char path[PATH_MAX];
    bool isdir = (statst.st_mode & S_IFDIR) != 0;

    if (flatten && isdir) {
      continue;
    }

    // Compute the path, flattening it if requested
    if (flatten) {
      basename(files[i], path, PATH_MAX);
    } else {
      strncpy(path, files[i], PATH_MAX);
      path[PATH_MAX-1] = 0;
      size_t len = strlen(path);
      if (isdir && len < PATH_MAX - 1) {
        // Add the trailing slash for folders
        path[len] = '/';
        path[len+1] = 0;
      }
    }

    if (verbose) {
      mode_t perm = statst.st_mode & 0777;
      printf("%c %o %s\n", isdir ? 'd' : 'f', perm, path);
    }

    u1 *buffer = builder->NewFile(path, mode_to_zipattr(statst.st_mode));
    if (isdir) {
      builder->FinishFile(0);
    } else {
      // mmap the input file and memcpy
      int fd = open(files[i], O_RDONLY);
      if (fd < 0) {
        fprintf(stderr, "Can't open file %s for reading: %s.\n",
                files[i], strerror(errno));
        return -1;
      }
      void *data = mmap(NULL, statst.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
      if (data == MAP_FAILED) {
        fprintf(stderr, "Can't mmap file %s for reading: %s.\n",
                files[i], strerror(errno));
        return -1;
      }
      memcpy(buffer, data, statst.st_size);
      munmap(data, statst.st_size);
      builder->FinishFile(statst.st_size);
    }
  }
  if (builder->Finish() < 0) {
    fprintf(stderr, "%s\n", builder->GetError());
    return -1;
  }
  return 0;
}

}  // namespace devtools_ijar

//
// main method
//
static void usage(char *progname) {
  fprintf(stderr, "Usage: %s [vxc[f]] x.zip [file1...filen]\n", progname);
  fprintf(stderr, "  v verbose - list all file in x.zip\n");
  fprintf(stderr, "  x extract - extract file in x.zip in current directory\n");
  fprintf(stderr, "  c create  - add files to x.zip\n");
  fprintf(stderr, "  f flatten - flatten files to use with create operation\n");
  fprintf(stderr, "x and c cannot be used in the same command-line.\n");
  exit(1);
}

int main(int argc, char **argv) {
  bool extract = false;
  bool verbose = false;
  bool create = false;
  bool flatten = false;

  if (argc < 3) {
    usage(argv[0]);
  }

  for (int i = 0; argv[1][i] != 0; i++) {
    switch (argv[1][i]) {
    case 'x':
      extract = true;
      break;
    case 'v':
      verbose = true;
      break;
    case 'c':
      create = true;
      break;
    case 'f':
      flatten = true;
      break;
    default:
      usage(argv[0]);
    }
  }
  if (create) {
    if (extract) {
      usage(argv[0]);
    }
    // Create a zip
    return devtools_ijar::create(argv[2], argv+3, flatten, verbose);
  } else {
    if (flatten) {
      usage(argv[0]);
    }
    // Extraction / list mode
    return devtools_ijar::extract(argv[2], verbose, extract);
  }
}
<commit_msg>Ijar's zipper: fallback when external attributes is unset<commit_after>// Copyright 2015 Google Inc. All rights reserved.
//
// Author: Alan Donovan <adonovan@google.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//
// Zip / Unzip file using ijar zip implementation.
//
// Note that this Zip implementation intentionally don't compute CRC-32
// because it is useless computation for jar because Java doesn't care.
// CRC-32 of all files in the zip file will be set to 0.
//

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <memory>

#include "third_party/ijar/zip.h"

namespace devtools_ijar {

#define SYSCALL(expr)  do { \
                         if ((expr) < 0) { \
                           perror(#expr); \
                           abort(); \
                         } \
                       } while (0)

//
// A ZipExtractorProcessor that extract all files in the ZIP file.
//
class UnzipProcessor : public ZipExtractorProcessor {
 public:
  // Create a processor who will extract the files into output_root
  // if "extract" is set to true and will print the list of files and
  // their unix modes if "verbose" is set to true.
  UnzipProcessor(const char *output_root, bool verbose, bool extract)
    : output_root_(output_root), verbose_(verbose), extract_(extract) {}
  virtual ~UnzipProcessor() {}

  virtual void Process(const char* filename, const u4 attr,
                       const u1* data, const size_t size);
  virtual bool Accept(const char* filename, const u4 attr) {
    return true;
  }

 private:
  const char *output_root_;
  const bool verbose_;
  const bool extract_;
};

// Concatene 2 path, path1 and path2, using / as a directory separator and
// puting the result in "out". "size" specify the size of the output buffer
void concat_path(char* out, const size_t size,
                 const char *path1, const char *path2) {
  int len1 = strlen(path1);
  int l = len1;
  strncpy(out, path1, size-1);
  out[size-1] = 0;
  if (l < size - 1 && path1[len1] != '/' && path2[0] != '/') {
    out[l] = '/';
    l++;
    out[l] = 0;
  }
  if (l < size - 1) {
    strncat(out, path2, size - 1 - l);
  }
}

// Do a recursive mkdir of all folders of path except the last path
// segment (if path ends with a / then the last path segment is empty).
// All folders are created using "mode" for creation mode.
void mkdirs(const char *path, mode_t mode) {
  char path_[PATH_MAX];
  struct stat statst;
  strncpy(path_, path, PATH_MAX);
  path_[PATH_MAX-1] = 0;
  char *pointer = path_;
  while ((pointer = strchr(pointer, '/')) != NULL) {
    if (path_ != pointer) {  // skip leading slash
      *pointer = 0;
      if (stat(path_, &statst) != 0) {
        if (mkdir(path_, mode) < 0) {
          fprintf(stderr, "Cannot create folder %s: %s\n",
                  path_, strerror(errno));
          abort();
        }
      }
      *pointer = '/';
    }
    pointer++;
  }
}

void UnzipProcessor::Process(const char* filename, const u4 attr,
                             const u1* data, const size_t size) {
  mode_t mode = zipattr_to_mode(attr);
  mode_t perm = mode & 0777;
  bool isdir = (mode & S_IFDIR) != 0;
  if (attr == 0) {
    // Fallback when the external attribute is not set.
    isdir = filename[strlen(filename)-1] == '/';
    perm = 0777;
  }
  if (verbose_) {
    printf("%c %o %s\n", isdir ? 'd' : 'f', perm, filename);
  }
  if (extract_) {
    char path[PATH_MAX];
    int fd;
    concat_path(path, PATH_MAX, output_root_, filename);
    mkdirs(path, perm);
    if (!isdir) {
      fd = open(path, O_CREAT | O_WRONLY, perm);
      if (fd < 0) {
        fprintf(stderr, "Cannot open file %s for writing: %s\n",
                path, strerror(errno));
        abort();
      }
      SYSCALL(write(fd, data, size));
      SYSCALL(close(fd));
    }
  }
}

// Get the basename of path and store it in output. output_size
// is the size of the output buffer.
void basename(const char *path, char *output, size_t output_size) {
  const char *pointer = strrchr(path, '/');
  if (pointer == NULL) {
    pointer = path;
  } else {
    pointer++;  // Skip the leading slash.
  }
  strncpy(output, pointer, output_size);
  output[output_size-1] = 0;
}

// Execute the extraction (or just listing if just v is provided)
int extract(char *zipfile, bool verbose, bool extract) {
  char output_root[PATH_MAX];
  getcwd(output_root, PATH_MAX);

  UnzipProcessor processor(output_root, verbose, extract);
  std::unique_ptr<ZipExtractor> extractor(ZipExtractor::Create(zipfile,
                                                               &processor));
  if (extractor.get() == NULL) {
    fprintf(stderr, "Unable to open zip file %s: %s.\n", zipfile,
            strerror(errno));
    return -1;
  }

  if (extractor->ProcessAll() < 0) {
    fprintf(stderr, "%s.\n", extractor->GetError());
    return -1;
  }
  return 0;
}

// Execute the create operation
int create(char *zipfile, char **files, bool flatten, bool verbose) {
  struct stat statst;
  u8 size = ZipBuilder::EstimateSize(files);
  if (size == 0) {
    return -1;
  }
  std::unique_ptr<ZipBuilder> builder(ZipBuilder::Create(zipfile, size));
  if (builder.get() == NULL) {
    fprintf(stderr, "Unable to create zip file %s: %s.\n",
            zipfile, strerror(errno));
    return -1;
  }
  for (int i = 0; files[i] != NULL; i++) {
    stat(files[i], &statst);
    char path[PATH_MAX];
    bool isdir = (statst.st_mode & S_IFDIR) != 0;

    if (flatten && isdir) {
      continue;
    }

    // Compute the path, flattening it if requested
    if (flatten) {
      basename(files[i], path, PATH_MAX);
    } else {
      strncpy(path, files[i], PATH_MAX);
      path[PATH_MAX-1] = 0;
      size_t len = strlen(path);
      if (isdir && len < PATH_MAX - 1) {
        // Add the trailing slash for folders
        path[len] = '/';
        path[len+1] = 0;
      }
    }

    if (verbose) {
      mode_t perm = statst.st_mode & 0777;
      printf("%c %o %s\n", isdir ? 'd' : 'f', perm, path);
    }

    u1 *buffer = builder->NewFile(path, mode_to_zipattr(statst.st_mode));
    if (isdir) {
      builder->FinishFile(0);
    } else {
      // mmap the input file and memcpy
      int fd = open(files[i], O_RDONLY);
      if (fd < 0) {
        fprintf(stderr, "Can't open file %s for reading: %s.\n",
                files[i], strerror(errno));
        return -1;
      }
      void *data = mmap(NULL, statst.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
      if (data == MAP_FAILED) {
        fprintf(stderr, "Can't mmap file %s for reading: %s.\n",
                files[i], strerror(errno));
        return -1;
      }
      memcpy(buffer, data, statst.st_size);
      munmap(data, statst.st_size);
      builder->FinishFile(statst.st_size);
    }
  }
  if (builder->Finish() < 0) {
    fprintf(stderr, "%s\n", builder->GetError());
    return -1;
  }
  return 0;
}

}  // namespace devtools_ijar

//
// main method
//
static void usage(char *progname) {
  fprintf(stderr, "Usage: %s [vxc[f]] x.zip [file1...filen]\n", progname);
  fprintf(stderr, "  v verbose - list all file in x.zip\n");
  fprintf(stderr, "  x extract - extract file in x.zip in current directory\n");
  fprintf(stderr, "  c create  - add files to x.zip\n");
  fprintf(stderr, "  f flatten - flatten files to use with create operation\n");
  fprintf(stderr, "x and c cannot be used in the same command-line.\n");
  exit(1);
}

int main(int argc, char **argv) {
  bool extract = false;
  bool verbose = false;
  bool create = false;
  bool flatten = false;

  if (argc < 3) {
    usage(argv[0]);
  }

  for (int i = 0; argv[1][i] != 0; i++) {
    switch (argv[1][i]) {
    case 'x':
      extract = true;
      break;
    case 'v':
      verbose = true;
      break;
    case 'c':
      create = true;
      break;
    case 'f':
      flatten = true;
      break;
    default:
      usage(argv[0]);
    }
  }
  if (create) {
    if (extract) {
      usage(argv[0]);
    }
    // Create a zip
    return devtools_ijar::create(argv[2], argv+3, flatten, verbose);
  } else {
    if (flatten) {
      usage(argv[0]);
    }
    // Extraction / list mode
    return devtools_ijar::extract(argv[2], verbose, extract);
  }
}
<|endoftext|>


<commit_before>//===--- Action.cpp - Abstract compilation steps --------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Driver/Action.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Regex.h"
#include <cassert>
using namespace clang::driver;
using namespace llvm::opt;

Action::~Action() {}

const char *Action::getClassName(ActionClass AC) {
  switch (AC) {
  case InputClass: return "input";
  case BindArchClass: return "bind-arch";
  case OffloadClass:
    return "offload";
  case PreprocessJobClass: return "preprocessor";
  case PrecompileJobClass: return "precompiler";
  case AnalyzeJobClass: return "analyzer";
  case MigrateJobClass: return "migrator";
  case CompileJobClass: return "compiler";
  case BackendJobClass: return "backend";
  case AssembleJobClass: return "assembler";
  case LinkJobClass: return "linker";
  case LipoJobClass: return "lipo";
  case DsymutilJobClass: return "dsymutil";
  case VerifyDebugInfoJobClass: return "verify-debug-info";
  case VerifyPCHJobClass: return "verify-pch";
  case OffloadBundlingJobClass:
    return "clang-offload-bundler";
  case OffloadUnbundlingJobClass:
    return "clang-offload-unbundler";
  }

  llvm_unreachable("invalid class");
}

void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) {
  // Offload action set its own kinds on their dependences.
  if (Kind == OffloadClass)
    return;
  // Unbundling actions use the host kinds.
  if (Kind == OffloadUnbundlingJobClass)
    return;

  assert((OffloadingDeviceKind == OKind || OffloadingDeviceKind == OFK_None) &&
         "Setting device kind to a different device??");
  assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??");
  OffloadingDeviceKind = OKind;
  OffloadingArch = OArch;

  for (auto *A : Inputs)
    A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch);
}

void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) {
  // Offload action set its own kinds on their dependences.
  if (Kind == OffloadClass)
    return;

  assert(OffloadingDeviceKind == OFK_None &&
         "Setting a host kind in a device action.");
  ActiveOffloadKindMask |= OKinds;
  OffloadingArch = OArch;

  for (auto *A : Inputs)
    A->propagateHostOffloadInfo(ActiveOffloadKindMask, OArch);
}

void Action::propagateOffloadInfo(const Action *A) {
  if (unsigned HK = A->getOffloadingHostActiveKinds())
    propagateHostOffloadInfo(HK, A->getOffloadingArch());
  else
    propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(),
                               A->getOffloadingArch());
}

std::string Action::getOffloadingKindPrefix() const {
  switch (OffloadingDeviceKind) {
  case OFK_None:
    break;
  case OFK_Host:
    llvm_unreachable("Host kind is not an offloading device kind.");
    break;
  case OFK_Cuda:
    return "device-cuda";
  case OFK_OpenMP:
    return "device-openmp";

    // TODO: Add other programming models here.
  }

  if (!ActiveOffloadKindMask)
    return "";

  std::string Res("host");
  if (ActiveOffloadKindMask & OFK_Cuda)
    Res += "-cuda";
  if (ActiveOffloadKindMask & OFK_OpenMP)
    Res += "-openmp";

  // TODO: Add other programming models here.

  return Res;
}

/// Return a string that can be used as prefix in order to generate unique files
/// for each offloading kind.
std::string
Action::GetOffloadingFileNamePrefix(OffloadKind Kind,
                                    llvm::StringRef NormalizedTriple,
                                    bool CreatePrefixForHost) {
  // Don't generate prefix for host actions unless required.
  if (!CreatePrefixForHost && (Kind == OFK_None || Kind == OFK_Host))
    return "";

  std::string Res("-");
  Res += GetOffloadKindName(Kind);
  Res += "-";
  Res += NormalizedTriple;
  return Res;
}

/// Return a string with the offload kind name. If that is not defined, we
/// assume 'host'.
llvm::StringRef Action::GetOffloadKindName(OffloadKind Kind) {
  switch (Kind) {
  case OFK_None:
  case OFK_Host:
    return "host";
  case OFK_Cuda:
    return "cuda";
  case OFK_OpenMP:
    return "openmp";

    // TODO: Add other programming models here.
  }
}

void InputAction::anchor() {}

InputAction::InputAction(const Arg &_Input, types::ID _Type)
  : Action(InputClass, _Type), Input(_Input) {
}

void BindArchAction::anchor() {}

BindArchAction::BindArchAction(Action *Input, llvm::StringRef ArchName)
    : Action(BindArchClass, Input), ArchName(ArchName) {}

void OffloadAction::anchor() {}

OffloadAction::OffloadAction(const HostDependence &HDep)
    : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) {
  OffloadingArch = HDep.getBoundArch();
  ActiveOffloadKindMask = HDep.getOffloadKinds();
  HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
                                             HDep.getBoundArch());
}

OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty)
    : Action(OffloadClass, DDeps.getActions(), Ty),
      DevToolChains(DDeps.getToolChains()) {
  auto &OKinds = DDeps.getOffloadKinds();
  auto &BArchs = DDeps.getBoundArchs();

  // If all inputs agree on the same kind, use it also for this action.
  if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); }))
    OffloadingDeviceKind = OKinds.front();

  // If we have a single dependency, inherit the architecture from it.
  if (OKinds.size() == 1)
    OffloadingArch = BArchs.front();

  // Propagate info to the dependencies.
  for (unsigned i = 0, e = getInputs().size(); i != e; ++i)
    getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i]);
}

OffloadAction::OffloadAction(const HostDependence &HDep,
                             const DeviceDependences &DDeps)
    : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()),
      DevToolChains(DDeps.getToolChains()) {
  // We use the kinds of the host dependence for this action.
  OffloadingArch = HDep.getBoundArch();
  ActiveOffloadKindMask = HDep.getOffloadKinds();
  HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
                                             HDep.getBoundArch());

  // Add device inputs and propagate info to the device actions. Do work only if
  // we have dependencies.
  for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i)
    if (auto *A = DDeps.getActions()[i]) {
      getInputs().push_back(A);
      A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i],
                                    DDeps.getBoundArchs()[i]);
    }
}

void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const {
  if (!HostTC)
    return;
  assert(!getInputs().empty() && "No dependencies for offload action??");
  auto *A = getInputs().front();
  Work(A, HostTC, A->getOffloadingArch());
}

void OffloadAction::doOnEachDeviceDependence(
    const OffloadActionWorkTy &Work) const {
  auto I = getInputs().begin();
  auto E = getInputs().end();
  if (I == E)
    return;

  // We expect to have the same number of input dependences and device tool
  // chains, except if we also have a host dependence. In that case we have one
  // more dependence than we have device tool chains.
  assert(getInputs().size() == DevToolChains.size() + (HostTC ? 1 : 0) &&
         "Sizes of action dependences and toolchains are not consistent!");

  // Skip host action
  if (HostTC)
    ++I;

  auto TI = DevToolChains.begin();
  for (; I != E; ++I, ++TI)
    Work(*I, *TI, (*I)->getOffloadingArch());
}

void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const {
  doOnHostDependence(Work);
  doOnEachDeviceDependence(Work);
}

void OffloadAction::doOnEachDependence(bool IsHostDependence,
                                       const OffloadActionWorkTy &Work) const {
  if (IsHostDependence)
    doOnHostDependence(Work);
  else
    doOnEachDeviceDependence(Work);
}

bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; }

Action *OffloadAction::getHostDependence() const {
  assert(hasHostDependence() && "Host dependence does not exist!");
  assert(!getInputs().empty() && "No dependencies for offload action??");
  return HostTC ? getInputs().front() : nullptr;
}

bool OffloadAction::hasSingleDeviceDependence(
    bool DoNotConsiderHostActions) const {
  if (DoNotConsiderHostActions)
    return getInputs().size() == (HostTC ? 2 : 1);
  return !HostTC && getInputs().size() == 1;
}

Action *
OffloadAction::getSingleDeviceDependence(bool DoNotConsiderHostActions) const {
  assert(hasSingleDeviceDependence(DoNotConsiderHostActions) &&
         "Single device dependence does not exist!");
  // The previous assert ensures the number of entries in getInputs() is
  // consistent with what we are doing here.
  return HostTC ? getInputs()[1] : getInputs().front();
}

void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
                                           const char *BoundArch,
                                           OffloadKind OKind) {
  DeviceActions.push_back(&A);
  DeviceToolChains.push_back(&TC);
  DeviceBoundArchs.push_back(BoundArch);
  DeviceOffloadKinds.push_back(OKind);
}

OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC,
                                              const char *BoundArch,
                                              const DeviceDependences &DDeps)
    : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch) {
  for (auto K : DDeps.getOffloadKinds())
    HostOffloadKinds |= K;
}

void JobAction::anchor() {}

JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
    : Action(Kind, Input, Type) {}

JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
  : Action(Kind, Inputs, Type) {
}

void PreprocessJobAction::anchor() {}

PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
    : JobAction(PreprocessJobClass, Input, OutputType) {}

void PrecompileJobAction::anchor() {}

PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
    : JobAction(PrecompileJobClass, Input, OutputType) {}

void AnalyzeJobAction::anchor() {}

AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
    : JobAction(AnalyzeJobClass, Input, OutputType) {}

void MigrateJobAction::anchor() {}

MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
    : JobAction(MigrateJobClass, Input, OutputType) {}

void CompileJobAction::anchor() {}

CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
    : JobAction(CompileJobClass, Input, OutputType) {}

void BackendJobAction::anchor() {}

BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType)
    : JobAction(BackendJobClass, Input, OutputType) {}

void AssembleJobAction::anchor() {}

AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
    : JobAction(AssembleJobClass, Input, OutputType) {}

void LinkJobAction::anchor() {}

LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(LinkJobClass, Inputs, Type) {
}

void LipoJobAction::anchor() {}

LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(LipoJobClass, Inputs, Type) {
}

void DsymutilJobAction::anchor() {}

DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(DsymutilJobClass, Inputs, Type) {
}

void VerifyJobAction::anchor() {}

VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,
                                 types::ID Type)
    : JobAction(Kind, Input, Type) {
  assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
         "ActionClass is not a valid VerifyJobAction");
}

void VerifyDebugInfoJobAction::anchor() {}

VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
                                                   types::ID Type)
    : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {}

void VerifyPCHJobAction::anchor() {}

VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
    : VerifyJobAction(VerifyPCHJobClass, Input, Type) {}

void OffloadBundlingJobAction::anchor() {}

OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs)
    : JobAction(OffloadBundlingJobClass, Inputs, Inputs.front()->getType()) {}

void OffloadUnbundlingJobAction::anchor() {}

OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input)
    : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {}
<commit_msg>Fix MSVC "not all control paths return a value" warning<commit_after>//===--- Action.cpp - Abstract compilation steps --------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Driver/Action.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Regex.h"
#include <cassert>
using namespace clang::driver;
using namespace llvm::opt;

Action::~Action() {}

const char *Action::getClassName(ActionClass AC) {
  switch (AC) {
  case InputClass: return "input";
  case BindArchClass: return "bind-arch";
  case OffloadClass:
    return "offload";
  case PreprocessJobClass: return "preprocessor";
  case PrecompileJobClass: return "precompiler";
  case AnalyzeJobClass: return "analyzer";
  case MigrateJobClass: return "migrator";
  case CompileJobClass: return "compiler";
  case BackendJobClass: return "backend";
  case AssembleJobClass: return "assembler";
  case LinkJobClass: return "linker";
  case LipoJobClass: return "lipo";
  case DsymutilJobClass: return "dsymutil";
  case VerifyDebugInfoJobClass: return "verify-debug-info";
  case VerifyPCHJobClass: return "verify-pch";
  case OffloadBundlingJobClass:
    return "clang-offload-bundler";
  case OffloadUnbundlingJobClass:
    return "clang-offload-unbundler";
  }

  llvm_unreachable("invalid class");
}

void Action::propagateDeviceOffloadInfo(OffloadKind OKind, const char *OArch) {
  // Offload action set its own kinds on their dependences.
  if (Kind == OffloadClass)
    return;
  // Unbundling actions use the host kinds.
  if (Kind == OffloadUnbundlingJobClass)
    return;

  assert((OffloadingDeviceKind == OKind || OffloadingDeviceKind == OFK_None) &&
         "Setting device kind to a different device??");
  assert(!ActiveOffloadKindMask && "Setting a device kind in a host action??");
  OffloadingDeviceKind = OKind;
  OffloadingArch = OArch;

  for (auto *A : Inputs)
    A->propagateDeviceOffloadInfo(OffloadingDeviceKind, OArch);
}

void Action::propagateHostOffloadInfo(unsigned OKinds, const char *OArch) {
  // Offload action set its own kinds on their dependences.
  if (Kind == OffloadClass)
    return;

  assert(OffloadingDeviceKind == OFK_None &&
         "Setting a host kind in a device action.");
  ActiveOffloadKindMask |= OKinds;
  OffloadingArch = OArch;

  for (auto *A : Inputs)
    A->propagateHostOffloadInfo(ActiveOffloadKindMask, OArch);
}

void Action::propagateOffloadInfo(const Action *A) {
  if (unsigned HK = A->getOffloadingHostActiveKinds())
    propagateHostOffloadInfo(HK, A->getOffloadingArch());
  else
    propagateDeviceOffloadInfo(A->getOffloadingDeviceKind(),
                               A->getOffloadingArch());
}

std::string Action::getOffloadingKindPrefix() const {
  switch (OffloadingDeviceKind) {
  case OFK_None:
    break;
  case OFK_Host:
    llvm_unreachable("Host kind is not an offloading device kind.");
    break;
  case OFK_Cuda:
    return "device-cuda";
  case OFK_OpenMP:
    return "device-openmp";

    // TODO: Add other programming models here.
  }

  if (!ActiveOffloadKindMask)
    return "";

  std::string Res("host");
  if (ActiveOffloadKindMask & OFK_Cuda)
    Res += "-cuda";
  if (ActiveOffloadKindMask & OFK_OpenMP)
    Res += "-openmp";

  // TODO: Add other programming models here.

  return Res;
}

/// Return a string that can be used as prefix in order to generate unique files
/// for each offloading kind.
std::string
Action::GetOffloadingFileNamePrefix(OffloadKind Kind,
                                    llvm::StringRef NormalizedTriple,
                                    bool CreatePrefixForHost) {
  // Don't generate prefix for host actions unless required.
  if (!CreatePrefixForHost && (Kind == OFK_None || Kind == OFK_Host))
    return "";

  std::string Res("-");
  Res += GetOffloadKindName(Kind);
  Res += "-";
  Res += NormalizedTriple;
  return Res;
}

/// Return a string with the offload kind name. If that is not defined, we
/// assume 'host'.
llvm::StringRef Action::GetOffloadKindName(OffloadKind Kind) {
  switch (Kind) {
  case OFK_None:
  case OFK_Host:
    return "host";
  case OFK_Cuda:
    return "cuda";
  case OFK_OpenMP:
    return "openmp";

    // TODO: Add other programming models here.
  }

  llvm_unreachable("invalid offload kind");
}

void InputAction::anchor() {}

InputAction::InputAction(const Arg &_Input, types::ID _Type)
  : Action(InputClass, _Type), Input(_Input) {
}

void BindArchAction::anchor() {}

BindArchAction::BindArchAction(Action *Input, llvm::StringRef ArchName)
    : Action(BindArchClass, Input), ArchName(ArchName) {}

void OffloadAction::anchor() {}

OffloadAction::OffloadAction(const HostDependence &HDep)
    : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()) {
  OffloadingArch = HDep.getBoundArch();
  ActiveOffloadKindMask = HDep.getOffloadKinds();
  HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
                                             HDep.getBoundArch());
}

OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty)
    : Action(OffloadClass, DDeps.getActions(), Ty),
      DevToolChains(DDeps.getToolChains()) {
  auto &OKinds = DDeps.getOffloadKinds();
  auto &BArchs = DDeps.getBoundArchs();

  // If all inputs agree on the same kind, use it also for this action.
  if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); }))
    OffloadingDeviceKind = OKinds.front();

  // If we have a single dependency, inherit the architecture from it.
  if (OKinds.size() == 1)
    OffloadingArch = BArchs.front();

  // Propagate info to the dependencies.
  for (unsigned i = 0, e = getInputs().size(); i != e; ++i)
    getInputs()[i]->propagateDeviceOffloadInfo(OKinds[i], BArchs[i]);
}

OffloadAction::OffloadAction(const HostDependence &HDep,
                             const DeviceDependences &DDeps)
    : Action(OffloadClass, HDep.getAction()), HostTC(HDep.getToolChain()),
      DevToolChains(DDeps.getToolChains()) {
  // We use the kinds of the host dependence for this action.
  OffloadingArch = HDep.getBoundArch();
  ActiveOffloadKindMask = HDep.getOffloadKinds();
  HDep.getAction()->propagateHostOffloadInfo(HDep.getOffloadKinds(),
                                             HDep.getBoundArch());

  // Add device inputs and propagate info to the device actions. Do work only if
  // we have dependencies.
  for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i)
    if (auto *A = DDeps.getActions()[i]) {
      getInputs().push_back(A);
      A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i],
                                    DDeps.getBoundArchs()[i]);
    }
}

void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const {
  if (!HostTC)
    return;
  assert(!getInputs().empty() && "No dependencies for offload action??");
  auto *A = getInputs().front();
  Work(A, HostTC, A->getOffloadingArch());
}

void OffloadAction::doOnEachDeviceDependence(
    const OffloadActionWorkTy &Work) const {
  auto I = getInputs().begin();
  auto E = getInputs().end();
  if (I == E)
    return;

  // We expect to have the same number of input dependences and device tool
  // chains, except if we also have a host dependence. In that case we have one
  // more dependence than we have device tool chains.
  assert(getInputs().size() == DevToolChains.size() + (HostTC ? 1 : 0) &&
         "Sizes of action dependences and toolchains are not consistent!");

  // Skip host action
  if (HostTC)
    ++I;

  auto TI = DevToolChains.begin();
  for (; I != E; ++I, ++TI)
    Work(*I, *TI, (*I)->getOffloadingArch());
}

void OffloadAction::doOnEachDependence(const OffloadActionWorkTy &Work) const {
  doOnHostDependence(Work);
  doOnEachDeviceDependence(Work);
}

void OffloadAction::doOnEachDependence(bool IsHostDependence,
                                       const OffloadActionWorkTy &Work) const {
  if (IsHostDependence)
    doOnHostDependence(Work);
  else
    doOnEachDeviceDependence(Work);
}

bool OffloadAction::hasHostDependence() const { return HostTC != nullptr; }

Action *OffloadAction::getHostDependence() const {
  assert(hasHostDependence() && "Host dependence does not exist!");
  assert(!getInputs().empty() && "No dependencies for offload action??");
  return HostTC ? getInputs().front() : nullptr;
}

bool OffloadAction::hasSingleDeviceDependence(
    bool DoNotConsiderHostActions) const {
  if (DoNotConsiderHostActions)
    return getInputs().size() == (HostTC ? 2 : 1);
  return !HostTC && getInputs().size() == 1;
}

Action *
OffloadAction::getSingleDeviceDependence(bool DoNotConsiderHostActions) const {
  assert(hasSingleDeviceDependence(DoNotConsiderHostActions) &&
         "Single device dependence does not exist!");
  // The previous assert ensures the number of entries in getInputs() is
  // consistent with what we are doing here.
  return HostTC ? getInputs()[1] : getInputs().front();
}

void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
                                           const char *BoundArch,
                                           OffloadKind OKind) {
  DeviceActions.push_back(&A);
  DeviceToolChains.push_back(&TC);
  DeviceBoundArchs.push_back(BoundArch);
  DeviceOffloadKinds.push_back(OKind);
}

OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC,
                                              const char *BoundArch,
                                              const DeviceDependences &DDeps)
    : HostAction(A), HostToolChain(TC), HostBoundArch(BoundArch) {
  for (auto K : DDeps.getOffloadKinds())
    HostOffloadKinds |= K;
}

void JobAction::anchor() {}

JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
    : Action(Kind, Input, Type) {}

JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
  : Action(Kind, Inputs, Type) {
}

void PreprocessJobAction::anchor() {}

PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
    : JobAction(PreprocessJobClass, Input, OutputType) {}

void PrecompileJobAction::anchor() {}

PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
    : JobAction(PrecompileJobClass, Input, OutputType) {}

void AnalyzeJobAction::anchor() {}

AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
    : JobAction(AnalyzeJobClass, Input, OutputType) {}

void MigrateJobAction::anchor() {}

MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
    : JobAction(MigrateJobClass, Input, OutputType) {}

void CompileJobAction::anchor() {}

CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
    : JobAction(CompileJobClass, Input, OutputType) {}

void BackendJobAction::anchor() {}

BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType)
    : JobAction(BackendJobClass, Input, OutputType) {}

void AssembleJobAction::anchor() {}

AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
    : JobAction(AssembleJobClass, Input, OutputType) {}

void LinkJobAction::anchor() {}

LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(LinkJobClass, Inputs, Type) {
}

void LipoJobAction::anchor() {}

LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(LipoJobClass, Inputs, Type) {
}

void DsymutilJobAction::anchor() {}

DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
  : JobAction(DsymutilJobClass, Inputs, Type) {
}

void VerifyJobAction::anchor() {}

VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,
                                 types::ID Type)
    : JobAction(Kind, Input, Type) {
  assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
         "ActionClass is not a valid VerifyJobAction");
}

void VerifyDebugInfoJobAction::anchor() {}

VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
                                                   types::ID Type)
    : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {}

void VerifyPCHJobAction::anchor() {}

VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
    : VerifyJobAction(VerifyPCHJobClass, Input, Type) {}

void OffloadBundlingJobAction::anchor() {}

OffloadBundlingJobAction::OffloadBundlingJobAction(ActionList &Inputs)
    : JobAction(OffloadBundlingJobClass, Inputs, Inputs.front()->getType()) {}

void OffloadUnbundlingJobAction::anchor() {}

OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input)
    : JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {}
<|endoftext|>


<commit_before>#include <GL/glut.h>
#include <cmath>

#define PI 3.14159265359

using namespace std;

int deg = 0;

void radioactive();
void rotate();
void init();

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(500,500);
	glutInitWindowPosition(0,0);
	glutCreateWindow("Radioactive");
	glutIdleFunc(rotate);
	glutDisplayFunc(radioactive);
	init();
	glutMainLoop();
}

void init()
{
	glClearColor(1.0 ,1.0 ,0.0 ,0.0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
}

void radioactive()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f((deg/360.0), 0.0, 0.0);
	glRotatef(deg, 0.0, 0.0, 1.0);

	for (double d = 0.0; d < 2.0*PI; d += 2*PI/3.0)
	{
		glBegin(GL_TRIANGLE_FAN);
			glVertex2d(0.0,0.0);
			for (double dis = -PI/6; dis < PI/6; dis += 0.1)
			{
				glVertex2d(cos(d + dis), sin(d + dis));
			}
		glEnd();
	}

	glLoadIdentity();
	glutSwapBuffers();
}

void rotate()
{
	deg = (deg < 360) ? deg + 1 : 0;
	glutPostRedisplay();
}
<commit_msg>-pi/6 -> 0<commit_after>#include <GL/glut.h>
#include <cmath>

#define PI 3.14159265359

using namespace std;

int deg = 0;

void radioactive();
void rotate();
void init();

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(500,500);
	glutInitWindowPosition(0,0);
	glutCreateWindow("Radioactive");
	glutIdleFunc(rotate);
	glutDisplayFunc(radioactive);
	init();
	glutMainLoop();
}

void init()
{
	glClearColor(1.0 ,1.0 ,0.0 ,0.0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
}

void radioactive()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f((deg/360.0), 0.0, 0.0);
	glRotatef(deg, 0.0, 0.0, 1.0);

	for (double d = 0.0; d < 2.0*PI; d += 2*PI/3.0)
	{
		glBegin(GL_TRIANGLE_FAN);
			glVertex2d(0.0,0.0);
			for (double dis = 0.0; dis < 2*PI/6; dis += 0.1)
			{
				glVertex2d(cos(d + dis), sin(d + dis));
			}
		glEnd();
	}

	glLoadIdentity();
	glutSwapBuffers();
}

void rotate()
{
	deg = (deg < 360) ? deg + 1 : 0;
	glutPostRedisplay();
}
<|endoftext|>


<commit_before>/*!
@file

@copyright Edouard Alligand and Joel Falcou 2015-2017
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_BRIGAND_ADAPTED_INTEGRAL_LIST_HPP
#define BOOST_BRIGAND_ADAPTED_INTEGRAL_LIST_HPP

#include <brigand/algorithms/transform.hpp>
#include <brigand/types/integral_constant.hpp>

namespace brigand
{

template <typename T>
struct make_integral : brigand::integral_constant<typename T::value_type, T::value>
{
};

template <typename L>
using as_integral_list = transform<L, make_integral<brigand::_1>>;
}
#endif
<commit_msg>Delete integral_list.hpp<commit_after><|endoftext|>


<commit_before>#include<iostream>
#include<math.h>
#include "CudaLE.h"

using namespace CudaLE;

// const CoordinateType type = COORD_CYLINDRICAL;

// typedef UnaryOp<Id, double> Var;

int main ()
{
    // Var _x(1), _y(2);
    // (_sin(_1) + _2)::op_type myF = MakeFunc(_sin(_1) + _2);
    auto myF = _sin(_1) + _2;
    auto myG = _1 * 4.0 - 2.0 *_2;
    // std::cout << sin(2.0) + 3.0 << std::endl;
    // std::cout << (_log(_1) * _exp(_2) + _3)(2.0, -1, 1.0) << std::endl;
    std::cout << _sin(_pow<2>(_1) + _2)(2.0, 3.0) << std::endl;
    std::cout << myG(4.0, 2.0) << std::endl;
    return 0;
}
<commit_msg>Added some tests and playing around with various stuff<commit_after>#include<iostream>
#include<math.h>
#include "CudaLE.h"

using namespace CudaLE;

// const CoordinateType type = COORD_CYLINDRICAL;

// typedef UnaryOp<Id, double> Var;
template <typename T>
struct ScaleFunc
{
    T h;
    ScaleFunc (T func) : h(func) {}
    double operator() (double x1, double x2) {
        return h(x1, x2);
    }
}; // ----- end of class Scales -----

template <typename T>
ScaleFunc<T> MakeScaleFunc(T func) {
    return ScaleFunc<T>(func);
}

template <typename T1, typename T2, typename T3>
struct Scales
{
    T1 h1;
    T2 h2;
    T3 h3;
    Scales(T1 f1, T2 f2, T3 f3) : h1(f1), h2(f2), h3(f3) {}
    template <int i>
    double h (double x1, double x2) {
        if (1 == i) return h1(x1, x2);
        else if (2 == i) return h2(x1, x2);
        else if (3 == i) return h3(x1, x2);
        else return 1.0;
    }
}; // ----- end of class Scales -----

template <typename T1, typename T2, typename T3>
Scales<T1, T2, T3> MakeScales(T1 f1, T2 f2, T3 f3) {
    return Scales<T1, T2, T3>(f1, f2, f3);
}

static auto myScalesCart = MakeScales(ConstOp(1.0), ConstOp(1.0), ConstOp(1.0));

int main ()
{
    // Var _x(1), _y(2);
    // (_sin(_1) + _2)::op_type myF = MakeFunc(_sin(_1) + _2);
    auto myF = _sin(_1) + _2;
    auto myG = _1 * 4.0 - 2.0 *_2;
    auto myH = _1 / 4.0 - 2.0 /_2;
    auto myComb = myF * myG;
    auto myCart = ConstOp(1.0);
    auto myScalesSpherical = MakeScales(ConstOp(1.0), _1, _1 * _sin(_2));

    std::cout << myScalesCart.h<2>(2.0,324.0) << std::endl;
    std::cout << myScalesSpherical.h<3>(23.0,2.0) << std::endl;
    std::cout << (myScalesSpherical.h3 * myScalesCart.h2)(23.1, 3.0) << std::endl;

    auto myScale1 = MakeScaleFunc(myF);
    // std::cout << sin(2.0) + 3.0 << std::endl;
    // std::cout << (_log(_1) * _exp(_2) + _3)(2.0, -1, 1.0) << std::endl;
    std::cout << myF(2.0, 2.0) << std::endl;
    std::cout << myG(2.0, 2.0) << std::endl;
    std::cout << myComb(2.0, 2.0) << std::endl;
    std::cout << myScale1(2.0, 2.0) << std::endl;
    std::cout << myCart(1.0, 2.0, 10.0) << std::endl;
    return 0;
}
<|endoftext|>


<commit_before>#include "Entity.hpp"
#include "EntityScheme.hpp"
#include "EntityManager.hpp"
#include "EntitySchemeManager.hpp"
#include "EntityCallback.hpp"
#include "EntityFieldType.hpp"
#include "Action.hpp"
#include "ClientRepo.hpp"
#include "../inanity/script/np/Any.hpp"
#include "../inanity/script/np/State.hpp"
#include "../inanity/MemoryFile.hpp"
#include "../inanity/Exception.hpp"

BEGIN_INANITY_OIL

Entity::Entity(ptr<EntityManager> manager, const EntityId& id)
: manager(manager), id(id)
{
	manager->OnNewEntity(id, this);
}

Entity::~Entity()
{
	manager->OnFreeEntity(id);
}

ptr<EntityManager> Entity::GetManager() const
{
	return manager;
}

EntityId Entity::GetId() const
{
	return id;
}

ptr<EntityScheme> Entity::GetScheme() const
{
	return scheme;
}

void Entity::SetScheme(ptr<EntityScheme> scheme)
{
	this->scheme = scheme;
}

void Entity::OnNewCallback(EntityCallback* callback)
{
	callbacks.push_back(callback);
}

void Entity::OnFreeCallback(EntityCallback* callback)
{
	for(size_t i = 0; i < callbacks.size(); ++i)
		if(callbacks[i] == callback)
		{
			callbacks.erase(callbacks.begin() + i);
			return;
		}

	THROW("Entity callback already freed");
}

ptr<File> Entity::GetFullTagKey(const EntityTagId& tagId) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + EntityTagId::size));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 't';
	memcpy(keyData + EntityId::size + 1, tagId.data, EntityTagId::size);
	return key;
}

ptr<File> Entity::GetFullFieldKey(const String& fieldId) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + fieldId.length()));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 'f';
	memcpy(keyData + EntityId::size + 1, fieldId.c_str(), fieldId.length());

	return key;
}

ptr<File> Entity::GetFullDataKey(const void* nameData, size_t nameSize) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + nameSize));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 'd';
	memcpy(keyData + EntityId::size + 1, nameData, nameSize);

	return key;
}

void Entity::OnChange(const void* keyData, size_t keySize, ptr<File> value)
{
	// if this is a main entity key (scheme key)
	if(!keySize)
	{
		// value should be entity scheme id and has appropriate size
		// if it not, think like there is no scheme
		ptr<EntityScheme> newScheme;
		if(value && value->GetSize() == EntitySchemeId::size)
			newScheme = manager->GetSchemeManager()->TryGet(EntitySchemeId::FromData(value->GetData()));

		// if scheme doesn't match
		if(scheme != newScheme)
		{
			// remember it
			scheme = newScheme;
			// fire callbacks
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireScheme(scheme);
		}

		return;
	}

	if(!scheme)
		return;

	// the rest is entity's tags, fields or data
	switch(*(const char*)keyData)
	{
	case 't':
		{
			if(keySize != EntityTagId::size + 1)
				break;
			EntityTagId tagId = EntityTagId::FromData((const char*)keyData + 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireTag(tagId, value);
		}
		break;
	case 'f':
		{
			String fieldId((const char*)keyData + 1, keySize - 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireField(fieldId, value);
		}
		break;
	case 'd':
		{
			ptr<File> key = MemoryFile::CreateViaCopy((const char*)keyData + 1, keySize - 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireData(key, value);
		}
		break;
	}
}

ptr<File> Entity::ReadTag(const EntityTagId& tagId) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullTagKey(tagId));
}

void Entity::WriteTag(ptr<Action> action, const EntityTagId& tagId, ptr<File> tagData)
{
	if(!scheme)
		return;

	action->AddChange(GetFullTagKey(tagId), tagData);
}

ptr<File> Entity::RawReadField(const String& fieldId) const
{
	return manager->GetRepo()->GetValue(GetFullFieldKey(fieldId));
}

void Entity::RawWriteField(ptr<Action> action, const String& fieldId, ptr<File> value)
{
	action->AddChange(GetFullFieldKey(fieldId), value);
}

void Entity::EnumerateFields(FieldEnumerator* enumerator)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyValueEnumerator
	{
	private:
		FieldEnumerator* enumerator;

	public:
		Enumerator(FieldEnumerator* enumerator)
		: enumerator(enumerator) {}

		bool OnKeyValue(ptr<File> key, ptr<File> value)
		{
			enumerator->OnField(
				String(
					(const char*)key->GetData() + EntityId::size + 1,
					key->GetSize() - EntityId::size - 1),
				value);
			return true;
		}
	};

	ptr<MemoryFile> prefix = NEW(MemoryFile(EntityId::size + 1));
	char* prefixData = (char*)prefix->GetData();
	memcpy(prefixData, id.data, EntityId::size);
	prefixData[EntityId::size] = 'f';

	manager->GetRepo()->EnumerateKeyValues(prefix, &Enumerator(enumerator));
}

ptr<Script::Any> Entity::ReadField(const String& fieldId) const
{
	if(!scheme)
		return nullptr;

	const EntityScheme::Fields& fields = scheme->GetFields();
	EntityScheme::Fields::const_iterator i = fields.find(fieldId);
	if(i == fields.end())
		return nullptr;

	return i->second.type->TryConvertToScript(
		manager,
		Script::Np::State::GetCurrent(),
		RawReadField(fieldId));
}

void Entity::WriteField(ptr<Action> action, const String& fieldId, ptr<Script::Any> value)
{
	if(!scheme)
		return;

	const EntityScheme::Fields& fields = scheme->GetFields();
	EntityScheme::Fields::const_iterator i = fields.find(fieldId);
	if(i == fields.end())
		return;

	ptr<File> fileValue = i->second.type->TryConvertFromScript(value.FastCast<Script::Np::Any>());
	if(!fileValue)
		return;

	RawWriteField(action, fieldId, fileValue);
}

ptr<File> Entity::RawReadData(const void* nameData, size_t nameSize) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullDataKey(nameData, nameSize));
}

void Entity::RawWriteData(ptr<Action> action, const void* nameData, size_t nameSize, ptr<File> value)
{
	if(!scheme)
		return;

	action->AddChange(GetFullDataKey(nameData, nameSize), value);
}

void Entity::EnumerateData(DataEnumerator* enumerator)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyValueEnumerator
	{
	private:
		DataEnumerator* enumerator;

	public:
		Enumerator(DataEnumerator* enumerator)
		: enumerator(enumerator) {}

		bool OnKeyValue(ptr<File> key, ptr<File> value)
		{
			enumerator->OnData(key->SliceFrom(EntityId::size + 1), value);
			return true;
		}
	};

	ptr<MemoryFile> prefix = NEW(MemoryFile(EntityId::size + 1));
	char* prefixData = (char*)prefix->GetData();
	memcpy(prefixData, id.data, EntityId::size);
	prefixData[EntityId::size] = 'd';

	manager->GetRepo()->EnumerateKeyValues(prefix, &Enumerator(enumerator));
}

ptr<File> Entity::ReadData(ptr<File> name) const
{
	return RawReadData(name->GetData(), name->GetSize());
}

void Entity::WriteData(ptr<Action> action, ptr<File> name, ptr<File> value)
{
	RawWriteData(action, name->GetData(), name->GetSize(), value);
}

void Entity::Delete(ptr<Action> action)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyEnumerator
	{
	private:
		ptr<Action> action;

	public:
		Enumerator(ptr<Action> action)
		: action(action) {}

		bool OnKey(ptr<File> key)
		{
			action->AddChange(key, nullptr);
			return true;
		}
	};

	manager->GetRepo()->EnumerateKeys(id.ToFile(), &Enumerator(action));
}

ptr<EntityCallback> Entity::AddCallback(ptr<Script::Any> callback)
{
	return NEW(EntityCallback(this, callback.FastCast<Script::Np::Any>()));
}

END_INANITY_OIL
<commit_msg>allow null name when writing or reading entity data<commit_after>#include "Entity.hpp"
#include "EntityScheme.hpp"
#include "EntityManager.hpp"
#include "EntitySchemeManager.hpp"
#include "EntityCallback.hpp"
#include "EntityFieldType.hpp"
#include "Action.hpp"
#include "ClientRepo.hpp"
#include "../inanity/script/np/Any.hpp"
#include "../inanity/script/np/State.hpp"
#include "../inanity/MemoryFile.hpp"
#include "../inanity/Exception.hpp"

BEGIN_INANITY_OIL

Entity::Entity(ptr<EntityManager> manager, const EntityId& id)
: manager(manager), id(id)
{
	manager->OnNewEntity(id, this);
}

Entity::~Entity()
{
	manager->OnFreeEntity(id);
}

ptr<EntityManager> Entity::GetManager() const
{
	return manager;
}

EntityId Entity::GetId() const
{
	return id;
}

ptr<EntityScheme> Entity::GetScheme() const
{
	return scheme;
}

void Entity::SetScheme(ptr<EntityScheme> scheme)
{
	this->scheme = scheme;
}

void Entity::OnNewCallback(EntityCallback* callback)
{
	callbacks.push_back(callback);
}

void Entity::OnFreeCallback(EntityCallback* callback)
{
	for(size_t i = 0; i < callbacks.size(); ++i)
		if(callbacks[i] == callback)
		{
			callbacks.erase(callbacks.begin() + i);
			return;
		}

	THROW("Entity callback already freed");
}

ptr<File> Entity::GetFullTagKey(const EntityTagId& tagId) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + EntityTagId::size));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 't';
	memcpy(keyData + EntityId::size + 1, tagId.data, EntityTagId::size);
	return key;
}

ptr<File> Entity::GetFullFieldKey(const String& fieldId) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + fieldId.length()));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 'f';
	memcpy(keyData + EntityId::size + 1, fieldId.c_str(), fieldId.length());

	return key;
}

ptr<File> Entity::GetFullDataKey(const void* nameData, size_t nameSize) const
{
	ptr<MemoryFile> key = NEW(MemoryFile(EntityId::size + 1 + nameSize));
	char* keyData = (char*)key->GetData();
	memcpy(keyData, id.data, EntityId::size);
	keyData[EntityId::size] = 'd';
	memcpy(keyData + EntityId::size + 1, nameData, nameSize);

	return key;
}

void Entity::OnChange(const void* keyData, size_t keySize, ptr<File> value)
{
	// if this is a main entity key (scheme key)
	if(!keySize)
	{
		// value should be entity scheme id and has appropriate size
		// if it not, think like there is no scheme
		ptr<EntityScheme> newScheme;
		if(value && value->GetSize() == EntitySchemeId::size)
			newScheme = manager->GetSchemeManager()->TryGet(EntitySchemeId::FromData(value->GetData()));

		// if scheme doesn't match
		if(scheme != newScheme)
		{
			// remember it
			scheme = newScheme;
			// fire callbacks
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireScheme(scheme);
		}

		return;
	}

	if(!scheme)
		return;

	// the rest is entity's tags, fields or data
	switch(*(const char*)keyData)
	{
	case 't':
		{
			if(keySize != EntityTagId::size + 1)
				break;
			EntityTagId tagId = EntityTagId::FromData((const char*)keyData + 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireTag(tagId, value);
		}
		break;
	case 'f':
		{
			String fieldId((const char*)keyData + 1, keySize - 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireField(fieldId, value);
		}
		break;
	case 'd':
		{
			ptr<File> key = MemoryFile::CreateViaCopy((const char*)keyData + 1, keySize - 1);
			for(size_t i = 0; i < callbacks.size(); ++i)
				callbacks[i]->FireData(key, value);
		}
		break;
	}
}

ptr<File> Entity::ReadTag(const EntityTagId& tagId) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullTagKey(tagId));
}

void Entity::WriteTag(ptr<Action> action, const EntityTagId& tagId, ptr<File> tagData)
{
	if(!scheme)
		return;

	action->AddChange(GetFullTagKey(tagId), tagData);
}

ptr<File> Entity::RawReadField(const String& fieldId) const
{
	return manager->GetRepo()->GetValue(GetFullFieldKey(fieldId));
}

void Entity::RawWriteField(ptr<Action> action, const String& fieldId, ptr<File> value)
{
	action->AddChange(GetFullFieldKey(fieldId), value);
}

void Entity::EnumerateFields(FieldEnumerator* enumerator)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyValueEnumerator
	{
	private:
		FieldEnumerator* enumerator;

	public:
		Enumerator(FieldEnumerator* enumerator)
		: enumerator(enumerator) {}

		bool OnKeyValue(ptr<File> key, ptr<File> value)
		{
			enumerator->OnField(
				String(
					(const char*)key->GetData() + EntityId::size + 1,
					key->GetSize() - EntityId::size - 1),
				value);
			return true;
		}
	};

	ptr<MemoryFile> prefix = NEW(MemoryFile(EntityId::size + 1));
	char* prefixData = (char*)prefix->GetData();
	memcpy(prefixData, id.data, EntityId::size);
	prefixData[EntityId::size] = 'f';

	manager->GetRepo()->EnumerateKeyValues(prefix, &Enumerator(enumerator));
}

ptr<Script::Any> Entity::ReadField(const String& fieldId) const
{
	if(!scheme)
		return nullptr;

	const EntityScheme::Fields& fields = scheme->GetFields();
	EntityScheme::Fields::const_iterator i = fields.find(fieldId);
	if(i == fields.end())
		return nullptr;

	return i->second.type->TryConvertToScript(
		manager,
		Script::Np::State::GetCurrent(),
		RawReadField(fieldId));
}

void Entity::WriteField(ptr<Action> action, const String& fieldId, ptr<Script::Any> value)
{
	if(!scheme)
		return;

	const EntityScheme::Fields& fields = scheme->GetFields();
	EntityScheme::Fields::const_iterator i = fields.find(fieldId);
	if(i == fields.end())
		return;

	ptr<File> fileValue = i->second.type->TryConvertFromScript(value.FastCast<Script::Np::Any>());
	if(!fileValue)
		return;

	RawWriteField(action, fieldId, fileValue);
}

ptr<File> Entity::RawReadData(const void* nameData, size_t nameSize) const
{
	if(!scheme)
		return nullptr;

	return manager->GetRepo()->GetValue(GetFullDataKey(nameData, nameSize));
}

void Entity::RawWriteData(ptr<Action> action, const void* nameData, size_t nameSize, ptr<File> value)
{
	if(!scheme)
		return;

	action->AddChange(GetFullDataKey(nameData, nameSize), value);
}

void Entity::EnumerateData(DataEnumerator* enumerator)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyValueEnumerator
	{
	private:
		DataEnumerator* enumerator;

	public:
		Enumerator(DataEnumerator* enumerator)
		: enumerator(enumerator) {}

		bool OnKeyValue(ptr<File> key, ptr<File> value)
		{
			enumerator->OnData(key->SliceFrom(EntityId::size + 1), value);
			return true;
		}
	};

	ptr<MemoryFile> prefix = NEW(MemoryFile(EntityId::size + 1));
	char* prefixData = (char*)prefix->GetData();
	memcpy(prefixData, id.data, EntityId::size);
	prefixData[EntityId::size] = 'd';

	manager->GetRepo()->EnumerateKeyValues(prefix, &Enumerator(enumerator));
}

ptr<File> Entity::ReadData(ptr<File> name) const
{
	return RawReadData(name ? name->GetData() : nullptr, name ? name->GetSize() : 0);
}

void Entity::WriteData(ptr<Action> action, ptr<File> name, ptr<File> value)
{
	RawWriteData(action, name ? name->GetData() : nullptr, name ? name->GetSize() : 0, value);
}

void Entity::Delete(ptr<Action> action)
{
	if(!scheme)
		return;

	class Enumerator : public ClientRepo::KeyEnumerator
	{
	private:
		ptr<Action> action;

	public:
		Enumerator(ptr<Action> action)
		: action(action) {}

		bool OnKey(ptr<File> key)
		{
			action->AddChange(key, nullptr);
			return true;
		}
	};

	manager->GetRepo()->EnumerateKeys(id.ToFile(), &Enumerator(action));
}

ptr<EntityCallback> Entity::AddCallback(ptr<Script::Any> callback)
{
	return NEW(EntityCallback(this, callback.FastCast<Script::Np::Any>()));
}

END_INANITY_OIL
<|endoftext|>


<commit_before>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

/**************************************************************************
  EventNotify.cc

  Generic event notify mechanism among threads.
**************************************************************************/

#include "EventNotify.h"
#include "ink_hrtime.h"

#ifdef HAVE_EVENTFD
#include <sys/eventfd.h>
#include <sys/fcntl.h>
#include <sys/epoll.h>
#endif

EventNotify::EventNotify()
{
#ifdef HAVE_EVENTFD
  int ret;
  struct epoll_event ev;

  m_event_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
  if (m_event_fd < 0) {
    // EFD_NONBLOCK/EFD_CLOEXEC invalid in <= Linux 2.6.27
    m_event_fd = eventfd(0, 0);

    fcntl(m_event_fd, F_SETFD, FD_CLOEXEC);
    fcntl(m_event_fd, F_SETFL, O_NONBLOCK);
  }
  ink_release_assert(m_event_fd != -1);

  ev.events = EPOLLIN;
  ev.data.fd = m_event_fd;

  m_epoll_fd = epoll_create(1);
  ink_release_assert(m_epoll_fd != -1);

  ret = epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_event_fd, &ev);
  ink_release_assert(ret != -1);
#else
  ink_cond_init(&m_cond);
  ink_mutex_init(&m_mutex, NULL);
#endif
}

void
EventNotify::signal(void)
{
#ifdef HAVE_EVENTFD
  uint64_t value = 1;
  //
  // If the addition would cause the counter’s value of eventfd
  // to exceed the maximum, write() will fail with the errno EAGAIN,
  // which is acceptable as the receiver will be notified eventually.
  //
  write(m_event_fd, &value, sizeof(uint64_t));
#else
  ink_cond_signal(&m_cond);
#endif
}

int
EventNotify::wait(void)
{
#ifdef HAVE_EVENTFD
  ssize_t nr, nr_fd;
  uint64_t value = 0;
  struct epoll_event ev;

  do {
    nr_fd = epoll_wait(m_epoll_fd, &ev, 1, -1);
  } while (nr_fd == -1 && errno == EINTR);

  if (nr_fd == -1)
    return errno;

  nr = read(m_event_fd, &value, sizeof(uint64_t));
  if (nr == sizeof(uint64_t))
    return 0;
  else
    return errno;
#else
  ink_cond_wait(&m_cond, &m_mutex);
  return 0;
#endif
}

int
EventNotify::timedwait(int timeout) // milliseconds
{
#ifdef HAVE_EVENTFD
  ssize_t nr, nr_fd = 0;
  uint64_t value = 0;
  struct epoll_event ev;

  //
  // When timeout < 0, epoll_wait() will wait indefinitely, but
  // pthread_cond_timedwait() will return ETIMEDOUT immediately.
  // We should keep compatible with pthread_cond_timedwait() here.
  //
  if (timeout < 0)
    return ETIMEDOUT;

  do {
    nr_fd = epoll_wait(m_epoll_fd, &ev, 1, timeout);
  } while (nr_fd == -1 && errno == EINTR);

  if (nr_fd == 0)
    return ETIMEDOUT;
  else if (nr_fd == -1)
    return errno;

  nr = read(m_event_fd, &value, sizeof(uint64_t));
  if (nr == sizeof(uint64_t))
    return 0;
  else
    return errno;
#else
  ink_timestruc abstime;
  ink_hrtime curtime;

  curtime = ink_get_hrtime_internal() + timeout * HRTIME_MSECOND;
  abstime = ink_based_hrtime_to_timespec(curtime);

  return ink_cond_timedwait(&m_cond, &m_mutex, &abstime);
#endif
}

void
EventNotify::lock(void)
{
#ifdef HAVE_EVENTFD
  // do nothing
#else
  ink_mutex_acquire(&m_mutex);
#endif
}

bool
EventNotify::trylock(void)
{
#ifdef HAVE_EVENTFD
  return true;
#else
  return ink_mutex_try_acquire(&m_mutex);
#endif
}

void
EventNotify::unlock(void)
{
#ifdef HAVE_EVENTFD
  // do nothing
#else
  ink_mutex_release(&m_mutex);
#endif
}

EventNotify::~EventNotify()
{
#ifdef HAVE_EVENTFD
  close(m_event_fd);
  close(m_epoll_fd);
#else
  ink_cond_destroy(&m_cond);
  ink_mutex_destroy(&m_mutex);
#endif
}
<commit_msg>Fix a compiler on new EventNofity code, detected with -Werror<commit_after>/** @file

  A brief file description

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */

/**************************************************************************
  EventNotify.cc

  Generic event notify mechanism among threads.
**************************************************************************/

#include "EventNotify.h"
#include "ink_hrtime.h"
#include "ink_defs.h"

#ifdef HAVE_EVENTFD
#include <sys/eventfd.h>
#include <sys/fcntl.h>
#include <sys/epoll.h>
#endif

EventNotify::EventNotify()
{
#ifdef HAVE_EVENTFD
  int ret;
  struct epoll_event ev;

  m_event_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
  if (m_event_fd < 0) {
    // EFD_NONBLOCK/EFD_CLOEXEC invalid in <= Linux 2.6.27
    m_event_fd = eventfd(0, 0);

    fcntl(m_event_fd, F_SETFD, FD_CLOEXEC);
    fcntl(m_event_fd, F_SETFL, O_NONBLOCK);
  }
  ink_release_assert(m_event_fd != -1);

  ev.events = EPOLLIN;
  ev.data.fd = m_event_fd;

  m_epoll_fd = epoll_create(1);
  ink_release_assert(m_epoll_fd != -1);

  ret = epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_event_fd, &ev);
  ink_release_assert(ret != -1);
#else
  ink_cond_init(&m_cond);
  ink_mutex_init(&m_mutex, NULL);
#endif
}

void
EventNotify::signal(void)
{
#ifdef HAVE_EVENTFD
  uint64_t value = 1;
  //
  // If the addition would cause the counter’s value of eventfd
  // to exceed the maximum, write() will fail with the errno EAGAIN,
  // which is acceptable as the receiver will be notified eventually.
  //
  ATS_UNUSED_RETURN(write(m_event_fd, &value, sizeof(uint64_t)));
#else
  ink_cond_signal(&m_cond);
#endif
}

int
EventNotify::wait(void)
{
#ifdef HAVE_EVENTFD
  ssize_t nr, nr_fd;
  uint64_t value = 0;
  struct epoll_event ev;

  do {
    nr_fd = epoll_wait(m_epoll_fd, &ev, 1, -1);
  } while (nr_fd == -1 && errno == EINTR);

  if (nr_fd == -1)
    return errno;

  nr = read(m_event_fd, &value, sizeof(uint64_t));
  if (nr == sizeof(uint64_t))
    return 0;
  else
    return errno;
#else
  ink_cond_wait(&m_cond, &m_mutex);
  return 0;
#endif
}

int
EventNotify::timedwait(int timeout) // milliseconds
{
#ifdef HAVE_EVENTFD
  ssize_t nr, nr_fd = 0;
  uint64_t value = 0;
  struct epoll_event ev;

  //
  // When timeout < 0, epoll_wait() will wait indefinitely, but
  // pthread_cond_timedwait() will return ETIMEDOUT immediately.
  // We should keep compatible with pthread_cond_timedwait() here.
  //
  if (timeout < 0)
    return ETIMEDOUT;

  do {
    nr_fd = epoll_wait(m_epoll_fd, &ev, 1, timeout);
  } while (nr_fd == -1 && errno == EINTR);

  if (nr_fd == 0)
    return ETIMEDOUT;
  else if (nr_fd == -1)
    return errno;

  nr = read(m_event_fd, &value, sizeof(uint64_t));
  if (nr == sizeof(uint64_t))
    return 0;
  else
    return errno;
#else
  ink_timestruc abstime;
  ink_hrtime curtime;

  curtime = ink_get_hrtime_internal() + timeout * HRTIME_MSECOND;
  abstime = ink_based_hrtime_to_timespec(curtime);

  return ink_cond_timedwait(&m_cond, &m_mutex, &abstime);
#endif
}

void
EventNotify::lock(void)
{
#ifdef HAVE_EVENTFD
  // do nothing
#else
  ink_mutex_acquire(&m_mutex);
#endif
}

bool
EventNotify::trylock(void)
{
#ifdef HAVE_EVENTFD
  return true;
#else
  return ink_mutex_try_acquire(&m_mutex);
#endif
}

void
EventNotify::unlock(void)
{
#ifdef HAVE_EVENTFD
  // do nothing
#else
  ink_mutex_release(&m_mutex);
#endif
}

EventNotify::~EventNotify()
{
#ifdef HAVE_EVENTFD
  close(m_event_fd);
  close(m_epoll_fd);
#else
  ink_cond_destroy(&m_cond);
  ink_mutex_destroy(&m_mutex);
#endif
}
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <algorithm>
#include <iomanip>
#include <sstream>

std::string hexToByte(const std::string& hexString);
std::string byteToHex(const std::string& byteString);

std::string fixedXor(std::string first, const std::string& second);

std::string base64Encode(const std::string& byteString);
std::string base64Decode(const std::string& encoded);

<commit_msg>Removed unnecessary includes<commit_after>#pragma once

#include <string>

std::string hexToByte(const std::string& hexString);
std::string byteToHex(const std::string& byteString);

std::string fixedXor(std::string first, const std::string& second);

std::string base64Encode(const std::string& byteString);
std::string base64Decode(const std::string& encoded);

<|endoftext|>


<commit_before>// (C) 2014 Arek Olek

#pragma once

#include <iostream>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

struct graph_writer {
  bool labels;
  graph_writer(bool l) : labels(l) {}
  virtual void operator()(std::ostream& out) const {
    if(labels) {
      out << "node [shape=circle color=burlywood style=filled]" << std::endl;
      out << "edge [style=dashed color=burlywood penwidth=4 weight=0.3]" << std::endl;
    } else {
      out << "node [shape=point color=burlywood style=filled label=\"\" width=0.05]" << std::endl;
      out << "edge [style=dashed color=burlywood]" << std::endl;
    }
  }
};

template <class Graph>
class node_writer {
public:
  node_writer(Graph const& t) : T(t) {}
  template <class V>
  void operator()(std::ostream& out, const V& v) const {
    if(out_degree(v, T) == 1)
      out << "[shape=square color=forestgreen]";
    if(out_degree(v, T) > 2)
      out << "[color=brown1]";
  }
private:
  Graph const& T;
};

template <class Graph>
node_writer<Graph> make_node_writer(Graph t) {
  return node_writer<Graph>(t);
}

template<class Graph, class Tree>
class edge_writer {
public:
  edge_writer(Graph const& g, Tree const& t) : G(g), T(t) {}
  template <class E>
  void operator()(std::ostream& out, const E& e) const {
    if(edge(source(e, G), target(e, G), T).second)
      out << "[style=solid]";
  }
private:
  Graph const& G;
  Tree const& T;
};

template<class Graph, class Tree>
edge_writer<Graph, Tree> make_edge_writer(Graph g, Tree t) {
  return edge_writer<Graph, Tree>(g, t);
}

template<class Graph, class Tree>
void show(std::string file, Graph const & g, Tree const & t) {
  std::ofstream f(file);
  write_graphviz(f, g,
    make_node_writer(t),
    make_edge_writer(g, t),
    graph_writer(num_vertices(g) < 30));
  f.close();
}

template<class Graph>
void show(std::string file, Graph const & g) {
  std::ofstream f(file);
  write_graphviz(f, g,
    boost::default_writer(),
    boost::default_writer(),
    graph_writer(false));
  f.close();
}
<commit_msg>i don't need virtual<commit_after>// (C) 2014 Arek Olek

#pragma once

#include <iostream>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

struct graph_writer {
  bool labels;
  graph_writer(bool l) : labels(l) {}
  void operator()(std::ostream& out) const {
    if(labels) {
      out << "node [shape=circle color=burlywood style=filled]" << std::endl;
      out << "edge [style=dashed color=burlywood penwidth=4 weight=0.3]" << std::endl;
    } else {
      out << "node [shape=point color=burlywood style=filled label=\"\" width=0.05]" << std::endl;
      out << "edge [style=dashed color=burlywood]" << std::endl;
    }
  }
};

template <class Graph>
class node_writer {
public:
  node_writer(Graph const& t) : T(t) {}
  template <class V>
  void operator()(std::ostream& out, const V& v) const {
    if(out_degree(v, T) == 1)
      out << "[shape=square color=forestgreen]";
    if(out_degree(v, T) > 2)
      out << "[color=brown1]";
  }
private:
  Graph const& T;
};

template <class Graph>
node_writer<Graph> make_node_writer(Graph t) {
  return node_writer<Graph>(t);
}

template<class Graph, class Tree>
class edge_writer {
public:
  edge_writer(Graph const& g, Tree const& t) : G(g), T(t) {}
  template <class E>
  void operator()(std::ostream& out, const E& e) const {
    if(edge(source(e, G), target(e, G), T).second)
      out << "[style=solid]";
  }
private:
  Graph const& G;
  Tree const& T;
};

template<class Graph, class Tree>
edge_writer<Graph, Tree> make_edge_writer(Graph g, Tree t) {
  return edge_writer<Graph, Tree>(g, t);
}

template<class Graph, class Tree>
void show(std::string file, Graph const & g, Tree const & t) {
  std::ofstream f(file);
  write_graphviz(f, g,
    make_node_writer(t),
    make_edge_writer(g, t),
    graph_writer(num_vertices(g) < 30));
  f.close();
}

template<class Graph>
void show(std::string file, Graph const & g) {
  std::ofstream f(file);
  write_graphviz(f, g,
    boost::default_writer(),
    boost::default_writer(),
    graph_writer(false));
  f.close();
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.h"
#include "webrtc/voice_engine/test/auto_test/voe_standard_test.h"

class TestRtpObserver : public webrtc::VoERTPObserver {
 public:
  TestRtpObserver();
  virtual ~TestRtpObserver();
  virtual void OnIncomingCSRCChanged(int channel,
                                     unsigned int CSRC,
                                     bool added);
  virtual void OnIncomingSSRCChanged(int channel,
                                     unsigned int SSRC);
  void Reset();
 public:
  unsigned int ssrc_[2];
  unsigned int csrc_[2][2];  // Stores 2 CSRCs for each channel.
  bool added_[2][2];
  int size_[2];
};

TestRtpObserver::TestRtpObserver() {
  Reset();
}

TestRtpObserver::~TestRtpObserver() {
}

void TestRtpObserver::Reset() {
  for (int i = 0; i < 2; i++) {
    ssrc_[i] = 0;
    csrc_[i][0] = 0;
    csrc_[i][1] = 0;
    added_[i][0] = false;
    added_[i][1] = false;
    size_[i] = 0;
  }
}

void TestRtpObserver::OnIncomingCSRCChanged(int channel,
                                            unsigned int CSRC,
                                            bool added) {
  char msg[128];
  sprintf(msg, "=> OnIncomingCSRCChanged(channel=%d, CSRC=%u, added=%d)\n",
          channel, CSRC, added);
  TEST_LOG("%s", msg);

  if (channel > 1)
    return;  // Not enough memory.

  csrc_[channel][size_[channel]] = CSRC;
  added_[channel][size_[channel]] = added;

  size_[channel]++;
  if (size_[channel] == 2)
    size_[channel] = 0;
}

void TestRtpObserver::OnIncomingSSRCChanged(int channel,
                                            unsigned int SSRC) {
  char msg[128];
  sprintf(msg, "\n=> OnIncomingSSRCChanged(channel=%d, SSRC=%u)\n", channel,
          SSRC);
  TEST_LOG("%s", msg);

  ssrc_[channel] = SSRC;
}

class RtcpAppHandler : public webrtc::VoERTCPObserver {
 public:
  RtcpAppHandler() : length_in_bytes_(0), sub_type_(0), name_(0) {}
  void OnApplicationDataReceived(int channel,
                                 unsigned char sub_type,
                                 unsigned int name,
                                 const unsigned char* data,
                                 unsigned short length_in_bytes);
  void Reset();
  ~RtcpAppHandler() {}
  unsigned short length_in_bytes_;
  unsigned char data_[256];
  unsigned char sub_type_;
  unsigned int name_;
};

static const char* const RTCP_CNAME = "Whatever";

class RtpRtcpTest : public AfterStreamingFixture {
 protected:
  void SetUp() {
    // We need a second channel for this test, so set it up.
    second_channel_ = voe_base_->CreateChannel();
    EXPECT_GE(second_channel_, 0);

    transport_ = new LoopBackTransport(voe_network_);
    EXPECT_EQ(0, voe_network_->RegisterExternalTransport(second_channel_,
                                                         *transport_));

    EXPECT_EQ(0, voe_base_->StartReceive(second_channel_));
    EXPECT_EQ(0, voe_base_->StartPlayout(second_channel_));
    EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(second_channel_, 5678));
    EXPECT_EQ(0, voe_base_->StartSend(second_channel_));

    // We'll set up the RTCP CNAME and SSRC to something arbitrary here.
    voe_rtp_rtcp_->SetRTCP_CNAME(channel_, RTCP_CNAME);
  }

  void TearDown() {
    EXPECT_EQ(0, voe_network_->DeRegisterExternalTransport(second_channel_));
    voe_base_->DeleteChannel(second_channel_);
    delete transport_;
  }

  int second_channel_;
  LoopBackTransport* transport_;
};

void RtcpAppHandler::OnApplicationDataReceived(
    const int /*channel*/, unsigned char sub_type,
    unsigned int name, const unsigned char* data,
    unsigned short length_in_bytes) {
  length_in_bytes_ = length_in_bytes;
  memcpy(data_, &data[0], length_in_bytes);
  sub_type_ = sub_type;
  name_ = name;
}

void RtcpAppHandler::Reset() {
  length_in_bytes_ = 0;
  memset(data_, 0, sizeof(data_));
  sub_type_ = 0;
  name_ = 0;
}

TEST_F(RtpRtcpTest, RemoteRtcpCnameHasPropagatedToRemoteSide) {
  if (!FLAGS_include_timing_dependent_tests) {
    TEST_LOG("Skipping test - running in slow execution environment...\n");
    return;
  }

  // We need to sleep a bit here for the name to propagate. For instance,
  // 200 milliseconds is not enough, so we'll go with one second here.
  Sleep(1000);

  char char_buffer[256];
  voe_rtp_rtcp_->GetRemoteRTCP_CNAME(channel_, char_buffer);
  EXPECT_STREQ(RTCP_CNAME, char_buffer);
}

TEST_F(RtpRtcpTest, SSRCPropagatesCorrectly) {
  unsigned int local_ssrc = 1234;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, local_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  Sleep(1000);

  unsigned int ssrc;
  EXPECT_EQ(0, voe_rtp_rtcp_->GetLocalSSRC(channel_, ssrc));
  EXPECT_EQ(local_ssrc, ssrc);

  EXPECT_EQ(0, voe_rtp_rtcp_->GetRemoteSSRC(channel_, ssrc));
  EXPECT_EQ(local_ssrc, ssrc);
}

TEST_F(RtpRtcpTest, RtcpApplicationDefinedPacketsCanBeSentAndReceived) {
  RtcpAppHandler rtcp_app_handler;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTCPObserver(
      channel_, rtcp_app_handler));

  // Send data aligned to 32 bytes.
  const char* data = "application-dependent data------";
  unsigned short data_length = strlen(data);
  unsigned int data_name = 0x41424344;  // 'ABCD' in ascii
  unsigned char data_subtype = 1;

  EXPECT_EQ(0, voe_rtp_rtcp_->SendApplicationDefinedRTCPPacket(
      channel_, data_subtype, data_name, data, data_length));

  // Ensure the RTP-RTCP process gets scheduled.
  Sleep(1000);

  // Ensure we received the data in the callback.
  ASSERT_EQ(data_length, rtcp_app_handler.length_in_bytes_);
  EXPECT_EQ(0, memcmp(data, rtcp_app_handler.data_, data_length));
  EXPECT_EQ(data_name, rtcp_app_handler.name_);
  EXPECT_EQ(data_subtype, rtcp_app_handler.sub_type_);

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTCPObserver(channel_));
}

TEST_F(RtpRtcpTest, DisabledRtcpObserverDoesNotReceiveData) {
  RtcpAppHandler rtcp_app_handler;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTCPObserver(
      channel_, rtcp_app_handler));

  // Put observer in a known state before de-registering.
  rtcp_app_handler.Reset();

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTCPObserver(channel_));

  const char* data = "whatever";
  EXPECT_EQ(0, voe_rtp_rtcp_->SendApplicationDefinedRTCPPacket(
      channel_, 1, 0x41424344, data, strlen(data)));

  // Ensure the RTP-RTCP process gets scheduled.
  Sleep(1000);

  // Ensure we received no data.
  EXPECT_EQ(0u, rtcp_app_handler.name_);
  EXPECT_EQ(0u, rtcp_app_handler.sub_type_);
}

TEST_F(RtpRtcpTest, InsertExtraRTPPacketDealsWithInvalidArguments) {
  const char payload_data[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };

  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      -1, 0, false, payload_data, 8)) <<
          "Should reject: invalid channel.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      channel_, -1, false, payload_data, 8)) <<
          "Should reject: invalid payload type.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      channel_, 128, false, payload_data, 8)) <<
          "Should reject: invalid payload type.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, 99, false, NULL, 8)) <<
            "Should reject: bad pointer.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, 99, false, payload_data, 1500 - 28 + 1)) <<
            "Should reject: invalid size.";
}

TEST_F(RtpRtcpTest, CanTransmitExtraRtpPacketsWithoutError) {
  const char payload_data[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };

  for (int i = 0; i < 128; ++i) {
    // Try both with and without the marker bit set
    EXPECT_EQ(0, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, i, false, payload_data, 8));
    EXPECT_EQ(0, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, i, true, payload_data, 8));
  }
}

// TODO(xians, phoglund): Re-enable when issue 372 is resolved.
TEST_F(RtpRtcpTest, DISABLED_CanCreateRtpDumpFilesWithoutError) {
  // Create two RTP dump files (3 seconds long). You can verify these after
  // the test using rtpplay or NetEqRTPplay if you like.
  std::string output_path = webrtc::test::OutputPath();
  std::string incoming_filename = output_path + "dump_in_3sec.rtp";
  std::string outgoing_filename = output_path + "dump_out_3sec.rtp";

  EXPECT_EQ(0, voe_rtp_rtcp_->StartRTPDump(
      channel_, incoming_filename.c_str(), webrtc::kRtpIncoming));
  EXPECT_EQ(0, voe_rtp_rtcp_->StartRTPDump(
      channel_, outgoing_filename.c_str(), webrtc::kRtpOutgoing));

  Sleep(3000);

  EXPECT_EQ(0, voe_rtp_rtcp_->StopRTPDump(channel_, webrtc::kRtpIncoming));
  EXPECT_EQ(0, voe_rtp_rtcp_->StopRTPDump(channel_, webrtc::kRtpOutgoing));
}

TEST_F(RtpRtcpTest, ObserverGetsNotifiedOnSsrcChange) {
  TestRtpObserver rtcp_observer;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTPObserver(
      channel_, rtcp_observer));
  rtcp_observer.Reset();

  unsigned int new_ssrc = 7777;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, new_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  Sleep(500);

  // Verify we got the new SSRC.
  EXPECT_EQ(new_ssrc, rtcp_observer.ssrc_[0]);

  // Now try another SSRC.
  unsigned int newer_ssrc = 1717;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, newer_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  Sleep(500);

  EXPECT_EQ(newer_ssrc, rtcp_observer.ssrc_[0]);

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTPObserver(channel_));
}
<commit_msg>Disabled SsrcPropagatesCorrectly on Linux.<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.h"
#include "webrtc/voice_engine/test/auto_test/voe_standard_test.h"

class TestRtpObserver : public webrtc::VoERTPObserver {
 public:
  TestRtpObserver();
  virtual ~TestRtpObserver();
  virtual void OnIncomingCSRCChanged(int channel,
                                     unsigned int CSRC,
                                     bool added);
  virtual void OnIncomingSSRCChanged(int channel,
                                     unsigned int SSRC);
  void Reset();
 public:
  unsigned int ssrc_[2];
  unsigned int csrc_[2][2];  // Stores 2 CSRCs for each channel.
  bool added_[2][2];
  int size_[2];
};

TestRtpObserver::TestRtpObserver() {
  Reset();
}

TestRtpObserver::~TestRtpObserver() {
}

void TestRtpObserver::Reset() {
  for (int i = 0; i < 2; i++) {
    ssrc_[i] = 0;
    csrc_[i][0] = 0;
    csrc_[i][1] = 0;
    added_[i][0] = false;
    added_[i][1] = false;
    size_[i] = 0;
  }
}

void TestRtpObserver::OnIncomingCSRCChanged(int channel,
                                            unsigned int CSRC,
                                            bool added) {
  char msg[128];
  sprintf(msg, "=> OnIncomingCSRCChanged(channel=%d, CSRC=%u, added=%d)\n",
          channel, CSRC, added);
  TEST_LOG("%s", msg);

  if (channel > 1)
    return;  // Not enough memory.

  csrc_[channel][size_[channel]] = CSRC;
  added_[channel][size_[channel]] = added;

  size_[channel]++;
  if (size_[channel] == 2)
    size_[channel] = 0;
}

void TestRtpObserver::OnIncomingSSRCChanged(int channel,
                                            unsigned int SSRC) {
  char msg[128];
  sprintf(msg, "\n=> OnIncomingSSRCChanged(channel=%d, SSRC=%u)\n", channel,
          SSRC);
  TEST_LOG("%s", msg);

  ssrc_[channel] = SSRC;
}

class RtcpAppHandler : public webrtc::VoERTCPObserver {
 public:
  RtcpAppHandler() : length_in_bytes_(0), sub_type_(0), name_(0) {}
  void OnApplicationDataReceived(int channel,
                                 unsigned char sub_type,
                                 unsigned int name,
                                 const unsigned char* data,
                                 unsigned short length_in_bytes);
  void Reset();
  ~RtcpAppHandler() {}
  unsigned short length_in_bytes_;
  unsigned char data_[256];
  unsigned char sub_type_;
  unsigned int name_;
};

static const char* const RTCP_CNAME = "Whatever";

class RtpRtcpTest : public AfterStreamingFixture {
 protected:
  void SetUp() {
    // We need a second channel for this test, so set it up.
    second_channel_ = voe_base_->CreateChannel();
    EXPECT_GE(second_channel_, 0);

    transport_ = new LoopBackTransport(voe_network_);
    EXPECT_EQ(0, voe_network_->RegisterExternalTransport(second_channel_,
                                                         *transport_));

    EXPECT_EQ(0, voe_base_->StartReceive(second_channel_));
    EXPECT_EQ(0, voe_base_->StartPlayout(second_channel_));
    EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(second_channel_, 5678));
    EXPECT_EQ(0, voe_base_->StartSend(second_channel_));

    // We'll set up the RTCP CNAME and SSRC to something arbitrary here.
    voe_rtp_rtcp_->SetRTCP_CNAME(channel_, RTCP_CNAME);
  }

  void TearDown() {
    EXPECT_EQ(0, voe_network_->DeRegisterExternalTransport(second_channel_));
    voe_base_->DeleteChannel(second_channel_);
    delete transport_;
  }

  int second_channel_;
  LoopBackTransport* transport_;
};

void RtcpAppHandler::OnApplicationDataReceived(
    const int /*channel*/, unsigned char sub_type,
    unsigned int name, const unsigned char* data,
    unsigned short length_in_bytes) {
  length_in_bytes_ = length_in_bytes;
  memcpy(data_, &data[0], length_in_bytes);
  sub_type_ = sub_type;
  name_ = name;
}

void RtcpAppHandler::Reset() {
  length_in_bytes_ = 0;
  memset(data_, 0, sizeof(data_));
  sub_type_ = 0;
  name_ = 0;
}

TEST_F(RtpRtcpTest, RemoteRtcpCnameHasPropagatedToRemoteSide) {
  if (!FLAGS_include_timing_dependent_tests) {
    TEST_LOG("Skipping test - running in slow execution environment...\n");
    return;
  }

  // We need to sleep a bit here for the name to propagate. For instance,
  // 200 milliseconds is not enough, so we'll go with one second here.
  Sleep(1000);

  char char_buffer[256];
  voe_rtp_rtcp_->GetRemoteRTCP_CNAME(channel_, char_buffer);
  EXPECT_STREQ(RTCP_CNAME, char_buffer);
}

// Flakily hangs on Linux. code.google.com/p/webrtc/issues/detail?id=2178.
TEST_F(RtpRtcpTest, DISABLED_ON_LINUX(SSRCPropagatesCorrectly)) {
  unsigned int local_ssrc = 1234;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, local_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  Sleep(1000);

  unsigned int ssrc;
  EXPECT_EQ(0, voe_rtp_rtcp_->GetLocalSSRC(channel_, ssrc));
  EXPECT_EQ(local_ssrc, ssrc);

  EXPECT_EQ(0, voe_rtp_rtcp_->GetRemoteSSRC(channel_, ssrc));
  EXPECT_EQ(local_ssrc, ssrc);
}

TEST_F(RtpRtcpTest, RtcpApplicationDefinedPacketsCanBeSentAndReceived) {
  RtcpAppHandler rtcp_app_handler;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTCPObserver(
      channel_, rtcp_app_handler));

  // Send data aligned to 32 bytes.
  const char* data = "application-dependent data------";
  unsigned short data_length = strlen(data);
  unsigned int data_name = 0x41424344;  // 'ABCD' in ascii
  unsigned char data_subtype = 1;

  EXPECT_EQ(0, voe_rtp_rtcp_->SendApplicationDefinedRTCPPacket(
      channel_, data_subtype, data_name, data, data_length));

  // Ensure the RTP-RTCP process gets scheduled.
  Sleep(1000);

  // Ensure we received the data in the callback.
  ASSERT_EQ(data_length, rtcp_app_handler.length_in_bytes_);
  EXPECT_EQ(0, memcmp(data, rtcp_app_handler.data_, data_length));
  EXPECT_EQ(data_name, rtcp_app_handler.name_);
  EXPECT_EQ(data_subtype, rtcp_app_handler.sub_type_);

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTCPObserver(channel_));
}

TEST_F(RtpRtcpTest, DisabledRtcpObserverDoesNotReceiveData) {
  RtcpAppHandler rtcp_app_handler;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTCPObserver(
      channel_, rtcp_app_handler));

  // Put observer in a known state before de-registering.
  rtcp_app_handler.Reset();

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTCPObserver(channel_));

  const char* data = "whatever";
  EXPECT_EQ(0, voe_rtp_rtcp_->SendApplicationDefinedRTCPPacket(
      channel_, 1, 0x41424344, data, strlen(data)));

  // Ensure the RTP-RTCP process gets scheduled.
  Sleep(1000);

  // Ensure we received no data.
  EXPECT_EQ(0u, rtcp_app_handler.name_);
  EXPECT_EQ(0u, rtcp_app_handler.sub_type_);
}

TEST_F(RtpRtcpTest, InsertExtraRTPPacketDealsWithInvalidArguments) {
  const char payload_data[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };

  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      -1, 0, false, payload_data, 8)) <<
          "Should reject: invalid channel.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      channel_, -1, false, payload_data, 8)) <<
          "Should reject: invalid payload type.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      channel_, 128, false, payload_data, 8)) <<
          "Should reject: invalid payload type.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, 99, false, NULL, 8)) <<
            "Should reject: bad pointer.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, 99, false, payload_data, 1500 - 28 + 1)) <<
            "Should reject: invalid size.";
}

TEST_F(RtpRtcpTest, CanTransmitExtraRtpPacketsWithoutError) {
  const char payload_data[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };

  for (int i = 0; i < 128; ++i) {
    // Try both with and without the marker bit set
    EXPECT_EQ(0, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, i, false, payload_data, 8));
    EXPECT_EQ(0, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, i, true, payload_data, 8));
  }
}

// TODO(xians, phoglund): Re-enable when issue 372 is resolved.
TEST_F(RtpRtcpTest, DISABLED_CanCreateRtpDumpFilesWithoutError) {
  // Create two RTP dump files (3 seconds long). You can verify these after
  // the test using rtpplay or NetEqRTPplay if you like.
  std::string output_path = webrtc::test::OutputPath();
  std::string incoming_filename = output_path + "dump_in_3sec.rtp";
  std::string outgoing_filename = output_path + "dump_out_3sec.rtp";

  EXPECT_EQ(0, voe_rtp_rtcp_->StartRTPDump(
      channel_, incoming_filename.c_str(), webrtc::kRtpIncoming));
  EXPECT_EQ(0, voe_rtp_rtcp_->StartRTPDump(
      channel_, outgoing_filename.c_str(), webrtc::kRtpOutgoing));

  Sleep(3000);

  EXPECT_EQ(0, voe_rtp_rtcp_->StopRTPDump(channel_, webrtc::kRtpIncoming));
  EXPECT_EQ(0, voe_rtp_rtcp_->StopRTPDump(channel_, webrtc::kRtpOutgoing));
}

TEST_F(RtpRtcpTest, ObserverGetsNotifiedOnSsrcChange) {
  TestRtpObserver rtcp_observer;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTPObserver(
      channel_, rtcp_observer));
  rtcp_observer.Reset();

  unsigned int new_ssrc = 7777;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, new_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  Sleep(500);

  // Verify we got the new SSRC.
  EXPECT_EQ(new_ssrc, rtcp_observer.ssrc_[0]);

  // Now try another SSRC.
  unsigned int newer_ssrc = 1717;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, newer_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  Sleep(500);

  EXPECT_EQ(newer_ssrc, rtcp_observer.ssrc_[0]);

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTPObserver(channel_));
}
<|endoftext|>