<commit_before>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "bin/directory.h"

#include <dirent.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>

#include "bin/file.h"
#include "bin/platform.h"

static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
  strncpy(dest, src, n);
  dest[n - 1] = '\0';
  return dest;
}

// Forward declarations.
static bool ListRecursively(const char* dir_name,
                            bool recursive,
                            DirectoryListing* listing);
static bool DeleteRecursively(const char* dir_name);

static bool ComputeFullPath(const char* dir_name,
                            char* path,
                            int* path_length) {
  char* abs_path;
  do {
    abs_path = realpath(dir_name, path);
  } while (abs_path == NULL && errno == EINTR);
  if (abs_path == NULL) {
    return false;
  }
  *path_length = strlen(path);
  size_t written = snprintf(path + *path_length,
                            PATH_MAX - *path_length,
                            "%s",
                            File::PathSeparator());
  if (written != strlen(File::PathSeparator())) {
    return false;
  }
  *path_length += written;
  return true;
}

static bool HandleDir(char* dir_name,
                      char* path,
                      int path_length,
                      bool recursive,
                      DirectoryListing *listing) {
  if (strcmp(dir_name, ".") != 0 &&
      strcmp(dir_name, "..") != 0) {
    size_t written = snprintf(path + path_length,
                              PATH_MAX - path_length,
                              "%s",
                              dir_name);
    if (written != strlen(dir_name)) {
      return false;
    }
    bool ok = listing->HandleDirectory(path);
    if (!ok) return ok;
    if (recursive) {
      return ListRecursively(path, recursive, listing);
    }
  }
  return true;
}

static bool HandleFile(char* file_name,
                       char* path,
                       int path_length,
                       DirectoryListing *listing) {
  // TODO(sgjesse): Pass flags to indicate whether file responses are
  // needed.
  size_t written = snprintf(path + path_length,
                            PATH_MAX - path_length,
                            "%s",
                            file_name);
  if (written != strlen(file_name)) {
    return false;
  }
  return listing->HandleFile(path);
}

static void PostError(DirectoryListing *listing,
                      const char* dir_name) {
  listing->HandleError(dir_name);
}

static bool ListRecursively(const char* dir_name,
                            bool recursive,
                            DirectoryListing *listing) {
  DIR* dir_pointer;
  do {
    dir_pointer = opendir(dir_name);
  } while (dir_pointer == NULL && errno == EINTR);
  if (dir_pointer == NULL) {
    PostError(listing, dir_name);
    return false;
  }

  // Compute full path for the directory currently being listed.  The
  // path buffer will be used to construct the current path in the
  // recursive traversal. path_length does not always equal
  // strlen(path) but indicates the current prefix of path that is the
  // path of the current directory in the traversal.
  char *path = static_cast<char*>(malloc(PATH_MAX));
  ASSERT(path != NULL);
  int path_length = 0;
  bool valid = ComputeFullPath(dir_name, path, &path_length);
  if (!valid) {
    free(path);
    PostError(listing, dir_name);
    return false;
  }

  // Iterated the directory and post the directories and files to the
  // ports.
  int read = 0;
  bool success = true;
  dirent entry;
  dirent* result;
  while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
                                              &entry,
                                              &result))) == 0 &&
         result != NULL) {
    switch (entry.d_type) {
      case DT_DIR:
        success = HandleDir(entry.d_name,
                            path,
                            path_length,
                            recursive,
                            listing) && success;
        break;
      case DT_REG:
        success = HandleFile(entry.d_name,
                             path,
                             path_length,
                             listing) && success;
        break;
      case DT_LNK:
      case DT_UNKNOWN: {
        // On some file systems the entry type is not determined by
        // readdir_r. For those and for links we use stat to determine
        // the actual entry type. Notice that stat returns the type of
        // the file pointed to.
        struct stat entry_info;
        size_t written = snprintf(path + path_length,
                                  PATH_MAX - path_length,
                                  "%s",
                                  entry.d_name);
        if (written != strlen(entry.d_name)) {
          success = false;
          break;
        }
        int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
        if (stat_success == -1) {
          success = false;
          PostError(listing, path);
          break;
        }
        if (S_ISDIR(entry_info.st_mode)) {
          success = HandleDir(entry.d_name,
                              path,
                              path_length,
                              recursive,
                              listing) && success;
        } else if (S_ISREG(entry_info.st_mode)) {
          success = HandleFile(entry.d_name,
                               path,
                               path_length,
                               listing) && success;
        }
        ASSERT(!S_ISLNK(entry_info.st_mode));
        break;
      }
      default:
        break;
    }
  }

  if (read != 0) {
    errno = read;
    success = false;
    PostError(listing, dir_name);
  }

  if (closedir(dir_pointer) == -1) {
    success = false;
    PostError(listing, dir_name);
  }
  free(path);

  return success;
}

static bool DeleteFile(char* file_name,
                       char* path,
                       int path_length) {
  size_t written = snprintf(path + path_length,
                            PATH_MAX - path_length,
                            "%s",
                            file_name);
  if (written != strlen(file_name)) {
    return false;
  }
  return (remove(path) == 0);
}

static bool DeleteDir(char* dir_name,
                      char* path,
                      int path_length) {
  if (strcmp(dir_name, ".") != 0 &&
      strcmp(dir_name, "..") != 0) {
    size_t written = snprintf(path + path_length,
                              PATH_MAX - path_length,
                              "%s",
                              dir_name);
    if (written != strlen(dir_name)) {
      return false;
    }
    return DeleteRecursively(path);
  }
  return true;
}

static bool DeleteRecursively(const char* dir_name) {
  // Do not recurse into links for deletion. Instead delete the link.
  struct stat st;
  if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) {
    return false;
  } else if (S_ISLNK(st.st_mode)) {
    return (remove(dir_name) == 0);
  }

  // Not a link. Attempt to open as a directory and recurse into the
  // directory.
  DIR* dir_pointer;
  do {
    dir_pointer = opendir(dir_name);
  } while (dir_pointer == NULL && errno == EINTR);

  if (dir_pointer == NULL) {
    return false;
  }

  // Compute full path for the directory currently being deleted.  The
  // path buffer will be used to construct the current path in the
  // recursive traversal. path_length does not always equal
  // strlen(path) but indicates the current prefix of path that is the
  // path of the current directory in the traversal.
  char *path = static_cast<char*>(malloc(PATH_MAX));
  ASSERT(path != NULL);
  int path_length = 0;
  bool valid = ComputeFullPath(dir_name, path, &path_length);
  if (!valid) {
    free(path);
    return false;
  }

  // Iterate the directory and delete all files and directories.
  int read = 0;
  bool success = true;
  dirent entry;
  dirent* result;
  while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
                                              &entry,
                                              &result))) == 0 &&
         result != NULL &&
         success) {
    switch (entry.d_type) {
      case DT_DIR:
        success = success && DeleteDir(entry.d_name, path, path_length);
        break;
      case DT_REG:
      case DT_LNK:
        // Treat all links as files. This will delete the link which
        // is what we want no matter if the link target is a file or a
        // directory.
        success = success && DeleteFile(entry.d_name, path, path_length);
        break;
      case DT_UNKNOWN: {
        // On some file systems the entry type is not determined by
        // readdir_r. For those we use lstat to determine the entry
        // type.
        struct stat entry_info;
        size_t written = snprintf(path + path_length,
                                  PATH_MAX - path_length,
                                  "%s",
                                  entry.d_name);
        if (written != strlen(entry.d_name)) {
          success = false;
          break;
        }
        int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
        if (lstat_success == -1) {
          success = false;
          break;
        }
        if (S_ISDIR(entry_info.st_mode)) {
          success = success && DeleteDir(entry.d_name, path, path_length);
        } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
          // Treat links as files. This will delete the link which is
          // what we want no matter if the link target is a file or a
          // directory.
          success = success && DeleteFile(entry.d_name, path, path_length);
        }
        break;
      }
      default:
        break;
    }
  }

  free(path);

  if ((read != 0) ||
      (closedir(dir_pointer) == -1) ||
      (remove(dir_name) == -1)) {
    return false;
  }

  return success;
}

bool Directory::List(const char* dir_name,
                     bool recursive,
                     DirectoryListing *listing) {
  bool completed = ListRecursively(dir_name, recursive, listing);
  return completed;
}

Directory::ExistsResult Directory::Exists(const char* dir_name) {
  struct stat entry_info;
  int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
  if (success == 0) {
    if (S_ISDIR(entry_info.st_mode)) {
      return EXISTS;
    } else {
      return DOES_NOT_EXIST;
    }
  } else {
    if (errno == EACCES ||
        errno == EBADF ||
        errno == EFAULT ||
        errno == ENOMEM ||
        errno == EOVERFLOW) {
      // Search permissions denied for one of the directories in the
      // path or a low level error occured. We do not know if the
      // directory exists.
      return UNKNOWN;
    }
    ASSERT(errno == ELOOP ||
           errno == ENAMETOOLONG ||
           errno == ENOENT ||
           errno == ENOTDIR);
    return DOES_NOT_EXIST;
  }
}

char* Directory::Current() {
  return getcwd(NULL, 0);
}

bool Directory::Create(const char* dir_name) {
  // Create the directory with the permissions specified by the
  // process umask.
  return (TEMP_FAILURE_RETRY(mkdir(dir_name, 0777)) == 0);
}

char* Directory::CreateTemp(const char* const_template) {
  // Returns a new, unused directory name, modifying the contents of
  // dir_template.  Creates the directory with the permissions specified
  // by the process umask.
  // The return value must be freed by the caller.
  char* path = static_cast<char*>(malloc(PATH_MAX + 1));
  SafeStrNCpy(path, const_template, PATH_MAX + 1);
  int path_length = strlen(path);
  if (path_length > 0) {
    if ((path)[path_length - 1] == '/') {
      snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX");
    } else {
      snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX");
    }
  } else {
    snprintf(path, PATH_MAX, "/tmp/temp_dir1_XXXXXX");
  }
  char* result;
  do {
    result = mkdtemp(path);
  } while (result == NULL && errno == EINTR);
  if (result == NULL) {
    free(path);
    return NULL;
  }
  return path;
}

bool Directory::Delete(const char* dir_name, bool recursive) {
  if (!recursive) {
    return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
  } else {
    return DeleteRecursively(dir_name);
  }
}

bool Directory::Rename(const char* path, const char* new_path) {
  ExistsResult exists = Exists(path);
  if (exists != EXISTS) return false;
  return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
}
<commit_msg>Make Directory::Current() work with unenhanced POSIX getcwd<commit_after>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "bin/directory.h"

#include <dirent.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>

#include "bin/file.h"
#include "bin/platform.h"

static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
  strncpy(dest, src, n);
  dest[n - 1] = '\0';
  return dest;
}

// Forward declarations.
static bool ListRecursively(const char* dir_name,
                            bool recursive,
                            DirectoryListing* listing);
static bool DeleteRecursively(const char* dir_name);

static bool ComputeFullPath(const char* dir_name,
                            char* path,
                            int* path_length) {
  char* abs_path;
  do {
    abs_path = realpath(dir_name, path);
  } while (abs_path == NULL && errno == EINTR);
  if (abs_path == NULL) {
    return false;
  }
  *path_length = strlen(path);
  size_t written = snprintf(path + *path_length,
                            PATH_MAX - *path_length,
                            "%s",
                            File::PathSeparator());
  if (written != strlen(File::PathSeparator())) {
    return false;
  }
  *path_length += written;
  return true;
}

static bool HandleDir(char* dir_name,
                      char* path,
                      int path_length,
                      bool recursive,
                      DirectoryListing *listing) {
  if (strcmp(dir_name, ".") != 0 &&
      strcmp(dir_name, "..") != 0) {
    size_t written = snprintf(path + path_length,
                              PATH_MAX - path_length,
                              "%s",
                              dir_name);
    if (written != strlen(dir_name)) {
      return false;
    }
    bool ok = listing->HandleDirectory(path);
    if (!ok) return ok;
    if (recursive) {
      return ListRecursively(path, recursive, listing);
    }
  }
  return true;
}

static bool HandleFile(char* file_name,
                       char* path,
                       int path_length,
                       DirectoryListing *listing) {
  // TODO(sgjesse): Pass flags to indicate whether file responses are
  // needed.
  size_t written = snprintf(path + path_length,
                            PATH_MAX - path_length,
                            "%s",
                            file_name);
  if (written != strlen(file_name)) {
    return false;
  }
  return listing->HandleFile(path);
}

static void PostError(DirectoryListing *listing,
                      const char* dir_name) {
  listing->HandleError(dir_name);
}

static bool ListRecursively(const char* dir_name,
                            bool recursive,
                            DirectoryListing *listing) {
  DIR* dir_pointer;
  do {
    dir_pointer = opendir(dir_name);
  } while (dir_pointer == NULL && errno == EINTR);
  if (dir_pointer == NULL) {
    PostError(listing, dir_name);
    return false;
  }

  // Compute full path for the directory currently being listed.  The
  // path buffer will be used to construct the current path in the
  // recursive traversal. path_length does not always equal
  // strlen(path) but indicates the current prefix of path that is the
  // path of the current directory in the traversal.
  char *path = static_cast<char*>(malloc(PATH_MAX));
  ASSERT(path != NULL);
  int path_length = 0;
  bool valid = ComputeFullPath(dir_name, path, &path_length);
  if (!valid) {
    free(path);
    PostError(listing, dir_name);
    return false;
  }

  // Iterated the directory and post the directories and files to the
  // ports.
  int read = 0;
  bool success = true;
  dirent entry;
  dirent* result;
  while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
                                              &entry,
                                              &result))) == 0 &&
         result != NULL) {
    switch (entry.d_type) {
      case DT_DIR:
        success = HandleDir(entry.d_name,
                            path,
                            path_length,
                            recursive,
                            listing) && success;
        break;
      case DT_REG:
        success = HandleFile(entry.d_name,
                             path,
                             path_length,
                             listing) && success;
        break;
      case DT_LNK:
      case DT_UNKNOWN: {
        // On some file systems the entry type is not determined by
        // readdir_r. For those and for links we use stat to determine
        // the actual entry type. Notice that stat returns the type of
        // the file pointed to.
        struct stat entry_info;
        size_t written = snprintf(path + path_length,
                                  PATH_MAX - path_length,
                                  "%s",
                                  entry.d_name);
        if (written != strlen(entry.d_name)) {
          success = false;
          break;
        }
        int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
        if (stat_success == -1) {
          success = false;
          PostError(listing, path);
          break;
        }
        if (S_ISDIR(entry_info.st_mode)) {
          success = HandleDir(entry.d_name,
                              path,
                              path_length,
                              recursive,
                              listing) && success;
        } else if (S_ISREG(entry_info.st_mode)) {
          success = HandleFile(entry.d_name,
                               path,
                               path_length,
                               listing) && success;
        }
        ASSERT(!S_ISLNK(entry_info.st_mode));
        break;
      }
      default:
        break;
    }
  }

  if (read != 0) {
    errno = read;
    success = false;
    PostError(listing, dir_name);
  }

  if (closedir(dir_pointer) == -1) {
    success = false;
    PostError(listing, dir_name);
  }
  free(path);

  return success;
}

static bool DeleteFile(char* file_name,
                       char* path,
                       int path_length) {
  size_t written = snprintf(path + path_length,
                            PATH_MAX - path_length,
                            "%s",
                            file_name);
  if (written != strlen(file_name)) {
    return false;
  }
  return (remove(path) == 0);
}

static bool DeleteDir(char* dir_name,
                      char* path,
                      int path_length) {
  if (strcmp(dir_name, ".") != 0 &&
      strcmp(dir_name, "..") != 0) {
    size_t written = snprintf(path + path_length,
                              PATH_MAX - path_length,
                              "%s",
                              dir_name);
    if (written != strlen(dir_name)) {
      return false;
    }
    return DeleteRecursively(path);
  }
  return true;
}

static bool DeleteRecursively(const char* dir_name) {
  // Do not recurse into links for deletion. Instead delete the link.
  struct stat st;
  if (TEMP_FAILURE_RETRY(lstat(dir_name, &st)) == -1) {
    return false;
  } else if (S_ISLNK(st.st_mode)) {
    return (remove(dir_name) == 0);
  }

  // Not a link. Attempt to open as a directory and recurse into the
  // directory.
  DIR* dir_pointer;
  do {
    dir_pointer = opendir(dir_name);
  } while (dir_pointer == NULL && errno == EINTR);

  if (dir_pointer == NULL) {
    return false;
  }

  // Compute full path for the directory currently being deleted.  The
  // path buffer will be used to construct the current path in the
  // recursive traversal. path_length does not always equal
  // strlen(path) but indicates the current prefix of path that is the
  // path of the current directory in the traversal.
  char *path = static_cast<char*>(malloc(PATH_MAX));
  ASSERT(path != NULL);
  int path_length = 0;
  bool valid = ComputeFullPath(dir_name, path, &path_length);
  if (!valid) {
    free(path);
    return false;
  }

  // Iterate the directory and delete all files and directories.
  int read = 0;
  bool success = true;
  dirent entry;
  dirent* result;
  while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
                                              &entry,
                                              &result))) == 0 &&
         result != NULL &&
         success) {
    switch (entry.d_type) {
      case DT_DIR:
        success = success && DeleteDir(entry.d_name, path, path_length);
        break;
      case DT_REG:
      case DT_LNK:
        // Treat all links as files. This will delete the link which
        // is what we want no matter if the link target is a file or a
        // directory.
        success = success && DeleteFile(entry.d_name, path, path_length);
        break;
      case DT_UNKNOWN: {
        // On some file systems the entry type is not determined by
        // readdir_r. For those we use lstat to determine the entry
        // type.
        struct stat entry_info;
        size_t written = snprintf(path + path_length,
                                  PATH_MAX - path_length,
                                  "%s",
                                  entry.d_name);
        if (written != strlen(entry.d_name)) {
          success = false;
          break;
        }
        int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
        if (lstat_success == -1) {
          success = false;
          break;
        }
        if (S_ISDIR(entry_info.st_mode)) {
          success = success && DeleteDir(entry.d_name, path, path_length);
        } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
          // Treat links as files. This will delete the link which is
          // what we want no matter if the link target is a file or a
          // directory.
          success = success && DeleteFile(entry.d_name, path, path_length);
        }
        break;
      }
      default:
        break;
    }
  }

  free(path);

  if ((read != 0) ||
      (closedir(dir_pointer) == -1) ||
      (remove(dir_name) == -1)) {
    return false;
  }

  return success;
}

bool Directory::List(const char* dir_name,
                     bool recursive,
                     DirectoryListing *listing) {
  bool completed = ListRecursively(dir_name, recursive, listing);
  return completed;
}

Directory::ExistsResult Directory::Exists(const char* dir_name) {
  struct stat entry_info;
  int success = TEMP_FAILURE_RETRY(stat(dir_name, &entry_info));
  if (success == 0) {
    if (S_ISDIR(entry_info.st_mode)) {
      return EXISTS;
    } else {
      return DOES_NOT_EXIST;
    }
  } else {
    if (errno == EACCES ||
        errno == EBADF ||
        errno == EFAULT ||
        errno == ENOMEM ||
        errno == EOVERFLOW) {
      // Search permissions denied for one of the directories in the
      // path or a low level error occured. We do not know if the
      // directory exists.
      return UNKNOWN;
    }
    ASSERT(errno == ELOOP ||
           errno == ENAMETOOLONG ||
           errno == ENOENT ||
           errno == ENOTDIR);
    return DOES_NOT_EXIST;
  }
}

char* Directory::Current() {
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS)

  // On targets that support it, let getcwd allocate the buffer
  // dynamically. (Not part of POSIX, but implemented on many platforms.)
  return getcwd(NULL, 0);

#else

  // POSIX getcwd requires a pre-allocated buffer.
  char buffer[PATH_MAX];
  if (NULL == getcwd(buffer, PATH_MAX)) {
    return NULL;
  }

  size_t length = strlen(buffer) + 1;
  char* result = reinterpret_cast<char*>(malloc(length));
  if (result == NULL) {
    return NULL;
  }

  strncpy(result, buffer, length);
  return result;

#endif
}

bool Directory::Create(const char* dir_name) {
  // Create the directory with the permissions specified by the
  // process umask.
  return (TEMP_FAILURE_RETRY(mkdir(dir_name, 0777)) == 0);
}

char* Directory::CreateTemp(const char* const_template) {
  // Returns a new, unused directory name, modifying the contents of
  // dir_template.  Creates the directory with the permissions specified
  // by the process umask.
  // The return value must be freed by the caller.
  char* path = static_cast<char*>(malloc(PATH_MAX + 1));
  SafeStrNCpy(path, const_template, PATH_MAX + 1);
  int path_length = strlen(path);
  if (path_length > 0) {
    if ((path)[path_length - 1] == '/') {
      snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX");
    } else {
      snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX");
    }
  } else {
    snprintf(path, PATH_MAX, "/tmp/temp_dir1_XXXXXX");
  }
  char* result;
  do {
    result = mkdtemp(path);
  } while (result == NULL && errno == EINTR);
  if (result == NULL) {
    free(path);
    return NULL;
  }
  return path;
}

bool Directory::Delete(const char* dir_name, bool recursive) {
  if (!recursive) {
    return (TEMP_FAILURE_RETRY(remove(dir_name)) == 0);
  } else {
    return DeleteRecursively(dir_name);
  }
}

bool Directory::Rename(const char* path, const char* new_path) {
  ExistsResult exists = Exists(path);
  if (exists != EXISTS) return false;
  return (TEMP_FAILURE_RETRY(rename(path, new_path)) == 0);
}
<|endoftext|>


<commit_before>#ifndef K3_COMMON
#define K3_COMMON

// Common contains common declarations and utilities for the K3 Runtime.

#include <list>
#include <vector>
#include <tuple>
#include <memory>
#include <map>
#include <set>
#include <string>

#include "boost/asio.hpp"
#include "boost/thread/mutex.hpp"
#include "boost/thread/externally_locked.hpp"
#include "boost/thread/lockable_adapter.hpp"
#include "boost/serialization/nvp.hpp"
#include "boost/serialization/array.hpp"
#include "boost/functional/hash.hpp"
#include "serialization/YAS.hpp"

#define _F(X) (std::forward<decltype(X)>(X))

namespace K3 {

using std::string;
using std::shared_ptr;
using std::get;
using std::make_shared;
using std::weak_ptr;
using std::list;
using std::map;
using std::vector;
using std::enable_shared_from_this;
using std::unique_ptr;
using std::make_unique;

#define K3_LOG_ID "K3"
#define USE_CUSTOM_HASHMAPS 1
#define HAS_LIBDYNAMIC 1
#define K3_INTERNAL_FORMAT CodecFormat::YASBinary

class TriggerStatistics {
 public:
  std::string trig_id;
  int total_count;
  std::chrono::nanoseconds total_time;
};

namespace asio = boost::asio;
typedef const boost::system::error_code& boost_error;

typedef int TriggerID;
typedef std::vector<char> Buffer;
class ProgramContext;
typedef std::function<shared_ptr<ProgramContext>()> ContextFactory;

struct Address {
 public:
  Address() : ip(0), port(0) {}
  Address(unsigned long i, unsigned short p) : ip(i), port(p) {}

  bool operator==(const Address& other) const {
    return (ip == other.ip) && (port == other.port);
  }
  bool operator!=(const Address& other) const {
    return (ip != other.ip) || (port != other.port);
  }
  bool operator<=(const Address& other) const {
    return std::tie(ip, port) <= std::tie(other.ip, other.port);
  }
  bool operator<(const Address& other) const {
    return std::tie(ip, port) < std::tie(other.ip, other.port);
  }
  bool operator>=(const Address& other) const {
    return std::tie(ip, port) >= std::tie(other.ip, other.port);
  }
  bool operator>(const Address& other) const {
    return std::tie(ip, port) > std::tie(other.ip, other.port);
  }

  string toString() const {
    auto p1 = asio::ip::address_v4(ip).to_string();
    auto p2 = std::to_string(port);
    return p1 + ":" + p2;
  }

  template <class archive>
  void serialize(archive& ar) const {
    const char* buf = reinterpret_cast<const char*>(&ip);
    ar.write(buf, sizeof(ip));
    ar& port;
  }

  template <class Archive>
  void serialize(Archive& ar) {
    char* buf = reinterpret_cast<char*>(&ip);
    ar.read(buf, sizeof(ip));
    ar& port;
  }

  template <class Archive>
  void serialize(Archive& ar, const unsigned int) {
    char* buf = reinterpret_cast<char*>(&ip);
    ar& boost::serialization::make_array(buf, sizeof(ip));
    ar& port;
  }

  unsigned long ip;
  unsigned short port;
};

class unit_t {
 public:
  template <class archive>
  void serialize(archive&, const unsigned int) {}

  template <class archive>
  void serialize(archive&) {}

  bool operator==(const unit_t&) const { return true; }
  bool operator!=(const unit_t&) const { return false; }
  bool operator<(const unit_t&) const { return false; }
  bool operator>(const unit_t&) const { return false; }
};

typedef std::string Identifier;

inline Address make_address(const std::string& host, unsigned short port) {
  return Address(boost::asio::ip::address::from_string(host).to_v4().to_ulong(),
                 port);
}

inline Address make_address(unsigned long host, unsigned short port) {
  return Address(host, port);
}

inline std::string addressAsString(const Address& addr) {
  return addr.toString();
}

enum class CodecFormat { BoostBinary, CSV, PSV, YASBinary, Raw };
enum class StorageFormat { Binary, Text };
enum class IOMode { Read, Write };

IOMode getIOMode(const string& s);

static inline std::string currentTime() {
  std::chrono::nanoseconds ns =
      std::chrono::duration_cast<std::chrono::nanoseconds>(
          std::chrono::high_resolution_clock::now().time_since_epoch());
  return std::to_string(ns.count());
}

class EndOfProgramException : public std::runtime_error {
 public:
  EndOfProgramException() : runtime_error("Peer terminated.") {}
};

// Thread-safe map from Key to Val.
// Val should be a pointer type.
template <class Key, class Val>
class ConcurrentMap : public boost::basic_lockable_adapter<boost::mutex> {
 public:
  ConcurrentMap()
      : boost::basic_lockable_adapter<boost::mutex>(), map_(*this) {}

  void insert(const Key& key, Val v) {
    boost::strict_lock<ConcurrentMap<Key, Val>> lock(*this);
    map_.get(lock)[key] = v;
  }

  Val lookup(const Key& key) {
    boost::strict_lock<ConcurrentMap<Key, Val>> lock(*this);
    Val result;
    auto it = map_.get(lock).find(key);
    if (it != map_.get(lock).end()) {
      result = it->second;
    }
    return result;
  }

  void erase(const Key& key) {
    boost::strict_lock<ConcurrentMap<Key, Val>> lock(*this);
    map_.get(lock).erase(key);
    return;
  }

  int size() {
    boost::strict_lock<ConcurrentMap<Key, Val>> lock(*this);
    return map_.get(lock).size();
  }

 protected:
  boost::externally_locked<std::map<Key, Val>, ConcurrentMap<Key, Val>> map_;
};

class base_string;
typedef base_string string_impl;  // Toggle string implementations

}  // namespace K3

template <class T>
inline void hash_combine(std::size_t& seed, const T& v) {
  std::hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

// TODO(jbw) hash
#ifndef K3_R_elem
#define K3_R_elem

template <class _T0>
class R_elem {
 public:
  R_elem() {}
  R_elem(_T0 _elem) : elem(_elem) {}

  bool operator==(const R_elem& _r) const {
    if (elem == _r.elem) return true;
    return false;
  }

  bool operator!=(const R_elem& _r) const { return !(*this == _r); }

  bool operator<(const R_elem& _r) const { return elem < _r.elem; }

  template <class archive>
  void serialize(archive& _archive, const unsigned int) {
    _archive& BOOST_SERIALIZATION_NVP(elem);
  }

  template <class archive>
  void serialize(archive& _archive) {
    _archive& elem;
  }
  _T0 elem;
};
#endif  // K3_R_elem

#ifndef K3_R_i
#define K3_R_i
template <class _T0>
class R_i {
  public:
      R_i(): i()  {}
      R_i(const _T0& _i): i(_i)  {}
      R_i(_T0&& _i): i(std::move(_i))  {}
      bool operator==(const R_i<_T0>& __other) const {
        return i == __other.i;
      }
      bool operator!=(const R_i<_T0>& __other) const {
        return std::tie(i) != std::tie(__other.i);
      }
      bool operator<(const R_i<_T0>& __other) const {
        return std::tie(i) < std::tie(__other.i);
      }
      bool operator>(const R_i<_T0>& __other) const {
        return std::tie(i) > std::tie(__other.i);
      }
      bool operator<=(const R_i<_T0>& __other) const {
        return std::tie(i) <= std::tie(__other.i);
      }
      bool operator>=(const R_i<_T0>& __other) const {
        return std::tie(i) >= std::tie(__other.i);
      }
      template <class archive>
      void serialize(archive& _archive, const unsigned int _version)  {
        _archive & BOOST_SERIALIZATION_NVP(i);
      }
      template <class archive>
      void serialize(archive& _archive)  {
        _archive & i;
      }
      _T0 i;
};
#endif // K3_R_i

#ifndef K3_R_key_value
#define K3_R_key_value

template <class _T0, class _T1>
class R_key_value {
 public:
  typedef _T0 KeyType;
  typedef _T1 ValueType;
  R_key_value() : key(), value() {}
  template <class __T0, class __T1>
  R_key_value(__T0&& _key, __T1&& _value)
      : key(std::forward<__T0>(_key)), value(std::forward<__T1>(_value)) {}
  template <class archive>
  void serialize(archive& _archive) {
    _archive& key;
    _archive& value;
  }
  template <class archive>
  void serialize(archive& _archive, const unsigned int) {
    _archive& key;
    _archive& value;
  }
  bool operator==(const R_key_value<_T0, _T1>& __other) const {
    return key == (__other.key) && value == (__other.value);
  }
  bool operator!=(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) != std::tie(__other.key, __other.value);
  }
  bool operator<(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) < std::tie(__other.key, __other.value);
  }
  bool operator>(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) > std::tie(__other.key, __other.value);
  }
  bool operator<=(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) <= std::tie(__other.key, __other.value);
  }
  bool operator>=(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) >= std::tie(__other.key, __other.value);
  }
  _T0 key;
  _T1 value;
};
#endif  // K3_R_key_value

#ifndef K3_R_key_value_hash
#define K3_R_key_value_hash
namespace std {
template <class _T0, class _T1>
class hash<R_key_value<_T0, _T1>> {
 public:
  std::size_t operator()(const R_key_value<_T0, _T1>& r) const {
    std::size_t seed = 0;
    hash_combine(seed, r.key);
    hash_combine(seed, r.value);
    return seed;
  }
};
}  // namespace std
#endif

#endif
<commit_msg>Force forwarding deduction to use expression context for decltype.<commit_after>#ifndef K3_COMMON
#define K3_COMMON

// Common contains common declarations and utilities for the K3 Runtime.

#include <list>
#include <vector>
#include <tuple>
#include <memory>
#include <map>
#include <set>
#include <string>

#include "boost/asio.hpp"
#include "boost/thread/mutex.hpp"
#include "boost/thread/externally_locked.hpp"
#include "boost/thread/lockable_adapter.hpp"
#include "boost/serialization/nvp.hpp"
#include "boost/serialization/array.hpp"
#include "boost/functional/hash.hpp"
#include "serialization/YAS.hpp"

#define _F(X) (std::forward<decltype((X))>(X))

namespace K3 {

using std::string;
using std::shared_ptr;
using std::get;
using std::make_shared;
using std::weak_ptr;
using std::list;
using std::map;
using std::vector;
using std::enable_shared_from_this;
using std::unique_ptr;
using std::make_unique;

#define K3_LOG_ID "K3"
#define USE_CUSTOM_HASHMAPS 1
#define HAS_LIBDYNAMIC 1
#define K3_INTERNAL_FORMAT CodecFormat::YASBinary

class TriggerStatistics {
 public:
  std::string trig_id;
  int total_count;
  std::chrono::nanoseconds total_time;
};

namespace asio = boost::asio;
typedef const boost::system::error_code& boost_error;

typedef int TriggerID;
typedef std::vector<char> Buffer;
class ProgramContext;
typedef std::function<shared_ptr<ProgramContext>()> ContextFactory;

struct Address {
 public:
  Address() : ip(0), port(0) {}
  Address(unsigned long i, unsigned short p) : ip(i), port(p) {}

  bool operator==(const Address& other) const {
    return (ip == other.ip) && (port == other.port);
  }
  bool operator!=(const Address& other) const {
    return (ip != other.ip) || (port != other.port);
  }
  bool operator<=(const Address& other) const {
    return std::tie(ip, port) <= std::tie(other.ip, other.port);
  }
  bool operator<(const Address& other) const {
    return std::tie(ip, port) < std::tie(other.ip, other.port);
  }
  bool operator>=(const Address& other) const {
    return std::tie(ip, port) >= std::tie(other.ip, other.port);
  }
  bool operator>(const Address& other) const {
    return std::tie(ip, port) > std::tie(other.ip, other.port);
  }

  string toString() const {
    auto p1 = asio::ip::address_v4(ip).to_string();
    auto p2 = std::to_string(port);
    return p1 + ":" + p2;
  }

  template <class archive>
  void serialize(archive& ar) const {
    const char* buf = reinterpret_cast<const char*>(&ip);
    ar.write(buf, sizeof(ip));
    ar& port;
  }

  template <class Archive>
  void serialize(Archive& ar) {
    char* buf = reinterpret_cast<char*>(&ip);
    ar.read(buf, sizeof(ip));
    ar& port;
  }

  template <class Archive>
  void serialize(Archive& ar, const unsigned int) {
    char* buf = reinterpret_cast<char*>(&ip);
    ar& boost::serialization::make_array(buf, sizeof(ip));
    ar& port;
  }

  unsigned long ip;
  unsigned short port;
};

class unit_t {
 public:
  template <class archive>
  void serialize(archive&, const unsigned int) {}

  template <class archive>
  void serialize(archive&) {}

  bool operator==(const unit_t&) const { return true; }
  bool operator!=(const unit_t&) const { return false; }
  bool operator<(const unit_t&) const { return false; }
  bool operator>(const unit_t&) const { return false; }
};

typedef std::string Identifier;

inline Address make_address(const std::string& host, unsigned short port) {
  return Address(boost::asio::ip::address::from_string(host).to_v4().to_ulong(),
                 port);
}

inline Address make_address(unsigned long host, unsigned short port) {
  return Address(host, port);
}

inline std::string addressAsString(const Address& addr) {
  return addr.toString();
}

enum class CodecFormat { BoostBinary, CSV, PSV, YASBinary, Raw };
enum class StorageFormat { Binary, Text };
enum class IOMode { Read, Write };

IOMode getIOMode(const string& s);

static inline std::string currentTime() {
  std::chrono::nanoseconds ns =
      std::chrono::duration_cast<std::chrono::nanoseconds>(
          std::chrono::high_resolution_clock::now().time_since_epoch());
  return std::to_string(ns.count());
}

class EndOfProgramException : public std::runtime_error {
 public:
  EndOfProgramException() : runtime_error("Peer terminated.") {}
};

// Thread-safe map from Key to Val.
// Val should be a pointer type.
template <class Key, class Val>
class ConcurrentMap : public boost::basic_lockable_adapter<boost::mutex> {
 public:
  ConcurrentMap()
      : boost::basic_lockable_adapter<boost::mutex>(), map_(*this) {}

  void insert(const Key& key, Val v) {
    boost::strict_lock<ConcurrentMap<Key, Val>> lock(*this);
    map_.get(lock)[key] = v;
  }

  Val lookup(const Key& key) {
    boost::strict_lock<ConcurrentMap<Key, Val>> lock(*this);
    Val result;
    auto it = map_.get(lock).find(key);
    if (it != map_.get(lock).end()) {
      result = it->second;
    }
    return result;
  }

  void erase(const Key& key) {
    boost::strict_lock<ConcurrentMap<Key, Val>> lock(*this);
    map_.get(lock).erase(key);
    return;
  }

  int size() {
    boost::strict_lock<ConcurrentMap<Key, Val>> lock(*this);
    return map_.get(lock).size();
  }

 protected:
  boost::externally_locked<std::map<Key, Val>, ConcurrentMap<Key, Val>> map_;
};

class base_string;
typedef base_string string_impl;  // Toggle string implementations

}  // namespace K3

template <class T>
inline void hash_combine(std::size_t& seed, const T& v) {
  std::hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

// TODO(jbw) hash
#ifndef K3_R_elem
#define K3_R_elem

template <class _T0>
class R_elem {
 public:
  R_elem() {}
  R_elem(_T0 _elem) : elem(_elem) {}

  bool operator==(const R_elem& _r) const {
    if (elem == _r.elem) return true;
    return false;
  }

  bool operator!=(const R_elem& _r) const { return !(*this == _r); }

  bool operator<(const R_elem& _r) const { return elem < _r.elem; }

  template <class archive>
  void serialize(archive& _archive, const unsigned int) {
    _archive& BOOST_SERIALIZATION_NVP(elem);
  }

  template <class archive>
  void serialize(archive& _archive) {
    _archive& elem;
  }
  _T0 elem;
};
#endif  // K3_R_elem

#ifndef K3_R_i
#define K3_R_i
template <class _T0>
class R_i {
  public:
      R_i(): i()  {}
      R_i(const _T0& _i): i(_i)  {}
      R_i(_T0&& _i): i(std::move(_i))  {}
      bool operator==(const R_i<_T0>& __other) const {
        return i == __other.i;
      }
      bool operator!=(const R_i<_T0>& __other) const {
        return std::tie(i) != std::tie(__other.i);
      }
      bool operator<(const R_i<_T0>& __other) const {
        return std::tie(i) < std::tie(__other.i);
      }
      bool operator>(const R_i<_T0>& __other) const {
        return std::tie(i) > std::tie(__other.i);
      }
      bool operator<=(const R_i<_T0>& __other) const {
        return std::tie(i) <= std::tie(__other.i);
      }
      bool operator>=(const R_i<_T0>& __other) const {
        return std::tie(i) >= std::tie(__other.i);
      }
      template <class archive>
      void serialize(archive& _archive, const unsigned int _version)  {
        _archive & BOOST_SERIALIZATION_NVP(i);
      }
      template <class archive>
      void serialize(archive& _archive)  {
        _archive & i;
      }
      _T0 i;
};
#endif // K3_R_i

#ifndef K3_R_key_value
#define K3_R_key_value

template <class _T0, class _T1>
class R_key_value {
 public:
  typedef _T0 KeyType;
  typedef _T1 ValueType;
  R_key_value() : key(), value() {}
  template <class __T0, class __T1>
  R_key_value(__T0&& _key, __T1&& _value)
      : key(std::forward<__T0>(_key)), value(std::forward<__T1>(_value)) {}
  template <class archive>
  void serialize(archive& _archive) {
    _archive& key;
    _archive& value;
  }
  template <class archive>
  void serialize(archive& _archive, const unsigned int) {
    _archive& key;
    _archive& value;
  }
  bool operator==(const R_key_value<_T0, _T1>& __other) const {
    return key == (__other.key) && value == (__other.value);
  }
  bool operator!=(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) != std::tie(__other.key, __other.value);
  }
  bool operator<(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) < std::tie(__other.key, __other.value);
  }
  bool operator>(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) > std::tie(__other.key, __other.value);
  }
  bool operator<=(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) <= std::tie(__other.key, __other.value);
  }
  bool operator>=(const R_key_value<_T0, _T1>& __other) const {
    return std::tie(key, value) >= std::tie(__other.key, __other.value);
  }
  _T0 key;
  _T1 value;
};
#endif  // K3_R_key_value

#ifndef K3_R_key_value_hash
#define K3_R_key_value_hash
namespace std {
template <class _T0, class _T1>
class hash<R_key_value<_T0, _T1>> {
 public:
  std::size_t operator()(const R_key_value<_T0, _T1>& r) const {
    std::size_t seed = 0;
    hash_combine(seed, r.key);
    hash_combine(seed, r.value);
    return seed;
  }
};
}  // namespace std
#endif

#endif
<|endoftext|>


<commit_before>/***********************************************************************
 ssx/genv2.cpp - Walks the SSQLS v2 parse result, writing back out
 	the equivalent SSQLS v2 DSL code.  This is useful for testing that
	our parser has correctly understood a given piece of code.  It is
	also something like the preprocessor mode of a C++ compiler,
	emitting a digested version of its input.

 Copyright (c) 2009 by Warren Young.  Others may also hold copyrights
 on code in this file.  See the CREDITS.txt file in the top directory
 of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "genv2.h"

#include "parsev2.h"

#include <iostream>
#include <fstream>
#include <typeinfo>

using namespace std;

//// generate_ssqls2 ///////////////////////////////////////////////////
// 2 versions: second checks its arguments and opens the named file,
// calling the second to actually generate the SSQLS v2 output from
// the parse result only if we were given sane parameters.

static bool
generate_ssqls2(ofstream&, const ParseV2* pparse)
{
	for (ParseV2::LineListIt it = pparse->begin();
			it != pparse->end(); ++it) {
		cout << "TRACE: write " << typeid(*it).name() << " line." << endl;
	}

	return true;
}

bool
generate_ssqls2(const char* file_name, const ParseV2* pparse)
{
	if (pparse) {
		ofstream ofs(file_name);
		if (ofs) {
			cout << "TRACE: Generating SSQLS v2 file " << file_name <<
					" from " << (pparse->end() - pparse->begin()) <<
					" line parse result." << endl;
			return generate_ssqls2(ofs, pparse);
		}
		else {
			cerr << "Failed to open " << file_name << \
					" for writing for -o!" << endl;
			return false;
		}
	}
	else {
		cerr << "No parse result given to -o handler!" << endl;
		return false;
	}
}
<commit_msg>- ssqlsxlat -o option now accepts '-' argument, meaning stdout - SSQLS v2 generator is no longer hard-coded to send its output to cout   now that we can pass it an option to make this happen, for testing.<commit_after>/***********************************************************************
 ssx/genv2.cpp - Walks the SSQLS v2 parse result, writing back out
 	the equivalent SSQLS v2 DSL code.  This is useful for testing that
	our parser has correctly understood a given piece of code.  It is
	also something like the preprocessor mode of a C++ compiler,
	emitting a digested version of its input.

 Copyright (c) 2009 by Warren Young and (c) 2009-2010 by Educational
 Technology Resources, Inc.  Others may also hold copyrights on code
 in this file.  See the CREDITS.txt file in the top directory of the
 distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "genv2.h"

#include "parsev2.h"

#include <iostream>
#include <fstream>
#include <typeinfo>

using namespace std;

//// generate_ssqls2 ///////////////////////////////////////////////////
// 2 versions: second checks its arguments and opens the named file,
// calling the second to actually generate the SSQLS v2 output from
// the parse result only if we were given sane parameters.

static bool
generate_ssqls2(ostream& os, const ParseV2* pparse)
{
	ParseV2::LineListIt it;
	for (it = pparse->begin(); it != pparse->end(); ++it) {
		os << *it << endl;
	}

	return true;
}

bool
generate_ssqls2(const char* file_name, const ParseV2* pparse)
{
	if (pparse) {
		if (strcmp(file_name, "-") == 0) {
			return generate_ssqls2(cout, pparse);
		}
		else {
			ofstream ofs(file_name);
			if (ofs) {
				cout << "TRACE: Generating SSQLS v2 file " << file_name <<
						" from " << (pparse->end() - pparse->begin()) <<
						" line parse result." << endl;
				return generate_ssqls2(ofs, pparse);
			}
			else {
				cerr << "Failed to open " << file_name << \
						" for writing for -o!" << endl;
				return false;
			}
		}
	}
	else {
		cerr << "No parse result given to -o handler!" << endl;
		return false;
	}
}
<|endoftext|>


<commit_before>#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"

static SkShader* setgrad(const SkRect& r, SkColor c0, SkColor c1) {
    SkColor colors[] = { c0, c1 };
    SkPoint pts[] = { { r.fLeft, r.fTop }, { r.fRight, r.fTop } };
    return SkGradientShader::CreateLinear(pts, colors, NULL, 2,
                                          SkShader::kClamp_TileMode, NULL);
}

static void test_alphagradients(SkCanvas* canvas) {
    SkRect r;
    r.set(SkIntToScalar(10), SkIntToScalar(10),
          SkIntToScalar(410), SkIntToScalar(30));
    SkPaint p, p2;
    p2.setStyle(SkPaint::kStroke_Style);

    p.setShader(setgrad(r, 0xFF00FF00, 0x0000FF00))->unref();
    canvas->drawRect(r, p);
    canvas->drawRect(r, p2);

    r.offset(0, r.height() + SkIntToScalar(4));
    p.setShader(setgrad(r, 0xFF00FF00, 0x00000000))->unref();
    canvas->drawRect(r, p);
    canvas->drawRect(r, p2);

    r.offset(0, r.height() + SkIntToScalar(4));
    p.setShader(setgrad(r, 0xFF00FF00, 0x00FF0000))->unref();
    canvas->drawRect(r, p);
    canvas->drawRect(r, p2);
}

///////////////////////////////////////////////////////////////////////////////

struct GradData {
    int             fCount;
    const SkColor*  fColors;
    const SkScalar* fPos;
};

static const SkColor gColors[] = {
    SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
};
static const SkScalar gPos0[] = { 0, SK_Scalar1 };
static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
static const SkScalar gPos2[] = {
    0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
};

static const GradData gGradData[] = {
    { 2, gColors, NULL },
    { 2, gColors, gPos0 },
    { 2, gColors, gPos1 },
    { 5, gColors, NULL },
    { 5, gColors, gPos2 }
};

static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
                                          data.fCount, tm, mapper);
}

static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
                                          data.fPos, data.fCount, tm, mapper);
}

static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
                           SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
                                         data.fPos, data.fCount, mapper);
}

typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
                     SkShader::TileMode tm, SkUnitMapper* mapper);
static const GradMaker gGradMakers[] = {
    MakeLinear, MakeRadial, MakeSweep
};

///////////////////////////////////////////////////////////////////////////////

class GradientsView : public SkView {
public:
	GradientsView() {}

protected:
    // overrides from SkEventSink
    virtual bool onQuery(SkEvent* evt) {
        if (SampleCode::TitleQ(*evt)) {
            SampleCode::TitleR(evt, "Gradients");
            return true;
        }
        return this->INHERITED::onQuery(evt);
    }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFFDDDDDD);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkPoint pts[2] = {
            { 0, 0 },
            { SkIntToScalar(100), SkIntToScalar(100) }
        };
        SkShader::TileMode tm = SkShader::kClamp_TileMode;
        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setDither(true);

        canvas->save();
        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
            canvas->save();
            for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
                paint.setShader(shader);
                canvas->drawRect(r, paint);
                shader->unref();
                canvas->translate(0, SkIntToScalar(120));
            }
            canvas->restore();
            canvas->translate(SkIntToScalar(120), 0);
        }
        canvas->restore();

        canvas->translate(0, SkIntToScalar(370));
        test_alphagradients(canvas);
    }

private:
    typedef SkView INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

static SkView* MyFactory() { return new GradientsView; }
static SkViewRegister reg(MyFactory);

<commit_msg>update sample to use new two-point-radial gradients from senorblanco!!!<commit_after>#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"

static SkShader* setgrad(const SkRect& r, SkColor c0, SkColor c1) {
    SkColor colors[] = { c0, c1 };
    SkPoint pts[] = { { r.fLeft, r.fTop }, { r.fRight, r.fTop } };
    return SkGradientShader::CreateLinear(pts, colors, NULL, 2,
                                          SkShader::kClamp_TileMode, NULL);
}

static void test_alphagradients(SkCanvas* canvas) {
    SkRect r;
    r.set(SkIntToScalar(10), SkIntToScalar(10),
          SkIntToScalar(410), SkIntToScalar(30));
    SkPaint p, p2;
    p2.setStyle(SkPaint::kStroke_Style);

    p.setShader(setgrad(r, 0xFF00FF00, 0x0000FF00))->unref();
    canvas->drawRect(r, p);
    canvas->drawRect(r, p2);

    r.offset(0, r.height() + SkIntToScalar(4));
    p.setShader(setgrad(r, 0xFF00FF00, 0x00000000))->unref();
    canvas->drawRect(r, p);
    canvas->drawRect(r, p2);

    r.offset(0, r.height() + SkIntToScalar(4));
    p.setShader(setgrad(r, 0xFF00FF00, 0x00FF0000))->unref();
    canvas->drawRect(r, p);
    canvas->drawRect(r, p2);
}

///////////////////////////////////////////////////////////////////////////////

struct GradData {
    int             fCount;
    const SkColor*  fColors;
    const SkScalar* fPos;
};

static const SkColor gColors[] = {
    SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
};
static const SkScalar gPos0[] = { 0, SK_Scalar1 };
static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
static const SkScalar gPos2[] = {
    0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
};

static const GradData gGradData[] = {
    { 2, gColors, NULL },
    { 2, gColors, gPos0 },
    { 2, gColors, gPos1 },
    { 5, gColors, NULL },
    { 5, gColors, gPos2 }
};

static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
                                          data.fCount, tm, mapper);
}

static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
                                          data.fPos, data.fCount, tm, mapper);
}

static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
                           SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
                                         data.fPos, data.fCount, mapper);
}

static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
                           SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center0, center1;
    center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
    center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
                SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    return SkGradientShader::CreateTwoPointRadial(
                            center1, (pts[1].fX - pts[0].fX) / 7,
                            center0, (pts[1].fX - pts[0].fX) / 2,
                            data.fColors, data.fPos, data.fCount, tm, mapper);
}

typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
                     SkShader::TileMode tm, SkUnitMapper* mapper);
static const GradMaker gGradMakers[] = {
    MakeLinear, MakeRadial, MakeSweep, Make2Radial
};

///////////////////////////////////////////////////////////////////////////////

class GradientsView : public SkView {
public:
	GradientsView() {}

protected:
    // overrides from SkEventSink
    virtual bool onQuery(SkEvent* evt) {
        if (SampleCode::TitleQ(*evt)) {
            SampleCode::TitleR(evt, "Gradients");
            return true;
        }
        return this->INHERITED::onQuery(evt);
    }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFFDDDDDD);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkPoint pts[2] = {
            { 0, 0 },
            { SkIntToScalar(100), SkIntToScalar(100) }
        };
        SkShader::TileMode tm = SkShader::kClamp_TileMode;
        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setDither(true);

        canvas->save();
        canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
        for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
            canvas->save();
            for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
                paint.setShader(shader);
                canvas->drawRect(r, paint);
                shader->unref();
                canvas->translate(0, SkIntToScalar(120));
            }
            canvas->restore();
            canvas->translate(SkIntToScalar(120), 0);
        }
        canvas->restore();

        canvas->translate(0, SkIntToScalar(370));
     //   test_alphagradients(canvas);
    }

private:
    typedef SkView INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

static SkView* MyFactory() { return new GradientsView; }
static SkViewRegister reg(MyFactory);

<|endoftext|>


<commit_before>
/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkPaint.h"
#include "SkRandom.h"
#include "SkShader.h"
#include "SkView.h"

/**
 * Animated sample used to develop batched rect implementation in GrInOrderDrawBuffer.
 */
class ManyRectsView : public SampleView {
private:
    enum {
        N = 1000,
    };

public:
    ManyRectsView() {}

protected:
    virtual bool onQuery(SkEvent* evt) SK_OVERRIDE {
        if (SampleCode::TitleQ(*evt)) {
            SampleCode::TitleR(evt, "ManyRects");
            return true;
        }
        return this->INHERITED::onQuery(evt);
    }

    virtual void onDrawContent(SkCanvas* canvas) {
        SkISize dsize = canvas->getDeviceSize();
        SkRect canvasRect = SkRect::MakeWH(SkIntToScalar(dsize.fWidth),
                                           SkIntToScalar(dsize.fHeight));
        canvas->clear(0xFFF0E0F0);

        for (int i = 0; i < N; ++i) {
            SkRect rect = SkRect::MakeWH(SkIntToScalar(fRandom.nextRangeU(10, 100)),
                                         SkIntToScalar(fRandom.nextRangeU(10, 100)));
            int x = fRandom.nextRangeU(0, dsize.fWidth);
            int y = fRandom.nextRangeU(0, dsize.fHeight);
            canvas->save();

            canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
            // Rotation messes up the GPU batching because of the clip below. We don't notice
            // that the rect is inside the clip so the clip changes interrupt batching.
            if (false) {
                SkMatrix rotate;
                rotate.setRotate(fRandom.nextUScalar1() * 360,
                                 SkIntToScalar(x) + SkScalarHalf(rect.fRight),
                                 SkIntToScalar(y) + SkScalarHalf(rect.fBottom));
                canvas->concat(rotate);
            }
            SkRect clipRect = rect;
            // This clip will always contain the entire rect. It's here to give the GPU batching
            // code a little more challenge.
            clipRect.outset(10, 10);
            canvas->clipRect(clipRect);
            SkPaint paint;
            paint.setColor(fRandom.nextU());
            canvas->drawRect(rect, paint);
            canvas->restore();
        }
        this->inval(NULL);
    }

private:
    SkMWCRandom fRandom;
    typedef SampleView INHERITED;
};

//////////////////////////////////////////////////////////////////////////////

static SkView* MyFactory() { return new ManyRectsView; }
static SkViewRegister reg(MyFactory);
<commit_msg>Fix unused var warning-as-error<commit_after>
/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkPaint.h"
#include "SkRandom.h"
#include "SkShader.h"
#include "SkView.h"

/**
 * Animated sample used to develop batched rect implementation in GrInOrderDrawBuffer.
 */
class ManyRectsView : public SampleView {
private:
    enum {
        N = 1000,
    };

public:
    ManyRectsView() {}

protected:
    virtual bool onQuery(SkEvent* evt) SK_OVERRIDE {
        if (SampleCode::TitleQ(*evt)) {
            SampleCode::TitleR(evt, "ManyRects");
            return true;
        }
        return this->INHERITED::onQuery(evt);
    }

    virtual void onDrawContent(SkCanvas* canvas) {
        SkISize dsize = canvas->getDeviceSize();
        canvas->clear(0xFFF0E0F0);

        for (int i = 0; i < N; ++i) {
            SkRect rect = SkRect::MakeWH(SkIntToScalar(fRandom.nextRangeU(10, 100)),
                                         SkIntToScalar(fRandom.nextRangeU(10, 100)));
            int x = fRandom.nextRangeU(0, dsize.fWidth);
            int y = fRandom.nextRangeU(0, dsize.fHeight);
            canvas->save();

            canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
            // Rotation messes up the GPU batching because of the clip below. We don't notice
            // that the rect is inside the clip so the clip changes interrupt batching.
            if (false) {
                SkMatrix rotate;
                rotate.setRotate(fRandom.nextUScalar1() * 360,
                                 SkIntToScalar(x) + SkScalarHalf(rect.fRight),
                                 SkIntToScalar(y) + SkScalarHalf(rect.fBottom));
                canvas->concat(rotate);
            }
            SkRect clipRect = rect;
            // This clip will always contain the entire rect. It's here to give the GPU batching
            // code a little more challenge.
            clipRect.outset(10, 10);
            canvas->clipRect(clipRect);
            SkPaint paint;
            paint.setColor(fRandom.nextU());
            canvas->drawRect(rect, paint);
            canvas->restore();
        }
        this->inval(NULL);
    }

private:
    SkMWCRandom fRandom;
    typedef SampleView INHERITED;
};

//////////////////////////////////////////////////////////////////////////////

static SkView* MyFactory() { return new ManyRectsView; }
static SkViewRegister reg(MyFactory);
<|endoftext|>


<commit_before>// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <net.h>
#include <netaddress.h>
#include <random.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>

#include <algorithm>
#include <functional>
#include <vector>

static void EvictionProtectionCommon(
    benchmark::Bench& bench,
    int num_candidates,
    std::function<void(NodeEvictionCandidate&)> candidate_setup_fn)
{
    using Candidates = std::vector<NodeEvictionCandidate>;
    FastRandomContext random_context{true};
    bench.warmup(100).epochIterations(1100);

    Candidates candidates{GetRandomNodeEvictionCandidates(num_candidates, random_context)};
    for (auto& c : candidates) {
        candidate_setup_fn(c);
    }

    std::vector<Candidates> copies{
        static_cast<size_t>(bench.epochs() * bench.epochIterations()), candidates};
    size_t i{0};
    bench.run([&] {
        ProtectEvictionCandidatesByRatio(copies.at(i));
        ++i;
    });
}

/* Benchmarks */

static void EvictionProtection0Networks250Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        250 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_network = NET_IPV4;
        });
}

static void EvictionProtection1Networks250Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        250 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = false;
            if (c.id >= 130 && c.id < 240) { // 110 Tor
                c.m_network = NET_ONION;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

static void EvictionProtection2Networks250Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        250 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = false;
            if (c.id >= 90 && c.id < 160) { // 70 Tor
                c.m_network = NET_ONION;
            } else if (c.id >= 170 && c.id < 250) { // 80 I2P
                c.m_network = NET_I2P;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

static void EvictionProtection3Networks050Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        50 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = (c.id == 28 || c.id == 47); //  2 localhost
            if (c.id >= 30 && c.id < 47) {             // 17 I2P
                c.m_network = NET_I2P;
            } else if (c.id >= 24 && c.id < 28) { //  4 Tor
                c.m_network = NET_ONION;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

static void EvictionProtection3Networks100Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        100 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = (c.id >= 55 && c.id < 60); //  5 localhost
            if (c.id >= 70 && c.id < 80) {            // 10 I2P
                c.m_network = NET_I2P;
            } else if (c.id >= 80 && c.id < 96) { // 16 Tor
                c.m_network = NET_ONION;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

static void EvictionProtection3Networks250Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        250 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = (c.id >= 140 && c.id < 160); // 20 localhost
            if (c.id >= 170 && c.id < 180) {            // 10 I2P
                c.m_network = NET_I2P;
            } else if (c.id >= 190 && c.id < 240) { // 50 Tor
                c.m_network = NET_ONION;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

// Candidate numbers used for the benchmarks:
// -  50 candidates simulates a possible use of -maxconnections
// - 100 candidates approximates an average node with default settings
// - 250 candidates is the number of peers reported by operators of busy nodes

// No disadvantaged networks, with 250 eviction candidates.
BENCHMARK(EvictionProtection0Networks250Candidates);

// 1 disadvantaged network (Tor) with 250 eviction candidates.
BENCHMARK(EvictionProtection1Networks250Candidates);

// 2 disadvantaged networks (I2P, Tor) with 250 eviction candidates.
BENCHMARK(EvictionProtection2Networks250Candidates);

// 3 disadvantaged networks (I2P/localhost/Tor) with 50/100/250 eviction candidates.
BENCHMARK(EvictionProtection3Networks050Candidates);
BENCHMARK(EvictionProtection3Networks100Candidates);
BENCHMARK(EvictionProtection3Networks250Candidates);
<commit_msg>bench: make EvictionProtection.* work with any number of iterations<commit_after>// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bench/bench.h>
#include <net.h>
#include <netaddress.h>
#include <random.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>

#include <algorithm>
#include <functional>
#include <vector>

static void EvictionProtectionCommon(
    benchmark::Bench& bench,
    int num_candidates,
    std::function<void(NodeEvictionCandidate&)> candidate_setup_fn)
{
    using Candidates = std::vector<NodeEvictionCandidate>;
    FastRandomContext random_context{true};

    Candidates candidates{GetRandomNodeEvictionCandidates(num_candidates, random_context)};
    for (auto& c : candidates) {
        candidate_setup_fn(c);
    }

    bench.run([&] {
        // creating a copy has an overhead of about 3%, so it does not influence the benchmark results much.
        auto copy = candidates;
        ProtectEvictionCandidatesByRatio(copy);
    });
}

/* Benchmarks */

static void EvictionProtection0Networks250Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        250 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_network = NET_IPV4;
        });
}

static void EvictionProtection1Networks250Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        250 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = false;
            if (c.id >= 130 && c.id < 240) { // 110 Tor
                c.m_network = NET_ONION;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

static void EvictionProtection2Networks250Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        250 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = false;
            if (c.id >= 90 && c.id < 160) { // 70 Tor
                c.m_network = NET_ONION;
            } else if (c.id >= 170 && c.id < 250) { // 80 I2P
                c.m_network = NET_I2P;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

static void EvictionProtection3Networks050Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        50 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = (c.id == 28 || c.id == 47); //  2 localhost
            if (c.id >= 30 && c.id < 47) {             // 17 I2P
                c.m_network = NET_I2P;
            } else if (c.id >= 24 && c.id < 28) { //  4 Tor
                c.m_network = NET_ONION;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

static void EvictionProtection3Networks100Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        100 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = (c.id >= 55 && c.id < 60); //  5 localhost
            if (c.id >= 70 && c.id < 80) {            // 10 I2P
                c.m_network = NET_I2P;
            } else if (c.id >= 80 && c.id < 96) { // 16 Tor
                c.m_network = NET_ONION;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

static void EvictionProtection3Networks250Candidates(benchmark::Bench& bench)
{
    EvictionProtectionCommon(
        bench,
        250 /* num_candidates */,
        [](NodeEvictionCandidate& c) {
            c.nTimeConnected = c.id;
            c.m_is_local = (c.id >= 140 && c.id < 160); // 20 localhost
            if (c.id >= 170 && c.id < 180) {            // 10 I2P
                c.m_network = NET_I2P;
            } else if (c.id >= 190 && c.id < 240) { // 50 Tor
                c.m_network = NET_ONION;
            } else {
                c.m_network = NET_IPV4;
            }
        });
}

// Candidate numbers used for the benchmarks:
// -  50 candidates simulates a possible use of -maxconnections
// - 100 candidates approximates an average node with default settings
// - 250 candidates is the number of peers reported by operators of busy nodes

// No disadvantaged networks, with 250 eviction candidates.
BENCHMARK(EvictionProtection0Networks250Candidates);

// 1 disadvantaged network (Tor) with 250 eviction candidates.
BENCHMARK(EvictionProtection1Networks250Candidates);

// 2 disadvantaged networks (I2P, Tor) with 250 eviction candidates.
BENCHMARK(EvictionProtection2Networks250Candidates);

// 3 disadvantaged networks (I2P/localhost/Tor) with 50/100/250 eviction candidates.
BENCHMARK(EvictionProtection3Networks050Candidates);
BENCHMARK(EvictionProtection3Networks100Candidates);
BENCHMARK(EvictionProtection3Networks250Candidates);
<|endoftext|>


<commit_before>#include <vector>
#include <string>
#include <limits>
#include <memory>
#include <iostream>

#include <arpa/inet.h>

#include "caf/all.hpp"
#include "caf/io/all.hpp"

CAF_PUSH_WARNINGS
#include "message.pb.h"
CAF_POP_WARNINGS

using namespace std;
using namespace caf;
using namespace caf::io;

void print_on_exit(const actor& hdl, const std::string& name) {
  hdl->attach_functor([=](abstract_actor* ptr, uint32_t reason) {
    aout(ptr) << name << " exited with reason " << reason << endl;
  });
}

behavior sendWarning(event_based_actor* self) {
  auto count = make_shared<size_t>(0);
  return {
    on(atom("kickoff"), arg_match) >> [=](const actor& pong) {
//	  aout(self) << "client: send {" << to_string(atom("warning")::value) << ", " <<  1 << "}" << endl;
      self->send(pong, atom("warning"), 1);
      self->become (
        on(atom("ack"), arg_match) >> [=](int value) -> void {
          self->quit();
          return;
//          return make_message(atom("ping"), value + 1);
        }
      );
    }
  };
}

behavior ackMessage() {
  return {
    on(atom("warning"), arg_match) >> [](int value) {
      return make_message(atom("ack"), value);
    }
  };
}

/*
  **************************
  Protobuf broker implementation
  Works as a communication handling middleman for the server/client actors above
  Deserizalizes/serializes messages
  **************************
*/
void protobuf_io(broker* self, connection_handle hdl, const actor& buddy) {
  // monitor buddy to quit broker if buddy is done
  self->monitor(buddy);
  auto write = [=](const org::libcppa::WarnOrAck& p) {
    string buf = p.SerializeAsString();
    int32_t s = htonl(static_cast<int32_t>(buf.size()));
    self->write(hdl, sizeof(int32_t), &s);
    self->write(hdl, buf.size(), buf.data());
    self->flush(hdl);
  };
  // message handler
  message_handler default_bhvr = {
    [=](const connection_closed_msg&) {
      aout(self) << "connection closed" << endl;
      self->send_exit(buddy, exit_reason::remote_link_unreachable);
      self->quit(exit_reason::remote_link_unreachable);
    },
    on(atom("warning"), arg_match) >> [=](int i) {
      aout(self) << "Send: warning " << i << endl;
      org::libcppa::WarnOrAck p;
      p.mutable_warn()->set_id(i);
      write(p);
    },
    on(atom("ack"), arg_match) >> [=](int i) {
      aout(self) << "Send: ack " << i << endl;
      org::libcppa::WarnOrAck p;
      p.mutable_ack()->set_id(i);
      write(p);
    },
    [=](const down_msg& dm) {
      if (dm.source == buddy) {
        aout(self) << "our buddy is down" << endl;
        self->quit(dm.reason);
      }
    },
    others >> [=] {
      cout << "unexpected: " << to_string(self->current_message()) << endl;
    }
  };
  auto await_protobuf_data = message_handler {
    [=](const new_data_msg& msg) {
      org::libcppa::WarnOrAck p;
      p.ParseFromArray(msg.buf.data(), static_cast<int>(msg.buf.size()));
      if (p.has_warn()) {
        aout(self) << "Received: warning " << p.warn().id() << endl;
        self->send(buddy, atom("warning"), p.warn().id());
      }
      else if (p.has_ack()) {
        aout(self) << "Received: ack " << p.ack().id() << endl;
        self->send(buddy, atom("ack"), p.ack().id());
      }
      else {
        self->quit(exit_reason::user_shutdown);
        cerr << "neither Warning nor ACK!" << endl;
      }
      // receive next length prefix
      self->configure_read(hdl, receive_policy::exactly(sizeof(int32_t)));
      self->unbecome();
    }
  }.or_else(default_bhvr);
  auto await_length_prefix = message_handler {
    [=](const new_data_msg& msg) {
      int32_t num_bytes;
      memcpy(&num_bytes, msg.buf.data(), sizeof(int32_t));
      num_bytes = htonl(num_bytes);
      if (num_bytes < 0 || num_bytes > (1024 * 1024)) {
        aout(self) << "someone is trying something nasty" << endl;
        self->quit(exit_reason::user_shutdown);
        return;
      }
      // receive protobuf data
      auto nb = static_cast<size_t>(num_bytes);
      self->configure_read(hdl, receive_policy::exactly(nb));
      self->become(keep_behavior, await_protobuf_data);
    }
  }.or_else(default_bhvr);
  // initial setup
  self->configure_read(hdl, receive_policy::exactly(sizeof(int32_t)));
  self->become(await_length_prefix);
}

/*
 **************************
 Helper method for the server to handle connections;
 Starts the server broker with the received message handle if a client connects
 **************************
*/
behavior server(broker* self, actor buddy) {
  aout(self) << "server is running" << endl;
  return {
    [=](const new_connection_msg& msg) {
      aout(self) << "server accepted new connection" << endl;
      auto io_actor = self->fork(protobuf_io, msg.handle, buddy);
      print_on_exit(io_actor, "protobuf_io");
      // only accept 1 connection in our example
      self->quit();
    },
    others >> [=] {
      cout << "unexpected: " << to_string(self->current_message()) << endl;
    }
  };
}

optional<uint16_t> as_u16(const std::string& str) {
  return static_cast<uint16_t>(stoul(str));
}

int main(int argc, char** argv) {
// Parsing arguments
  message_builder{argv + 1, argv + argc}.apply({
    on("-s", as_u16) >> [&](uint16_t port) {
    // We are a server
      cout << "run in server mode" << endl;
      // spawn the actor that acks messages
      auto serv_actor = spawn(ackMessage);
      // spawn an IO server to handle communication and work with the broker later (uses the behavior server helper)
      auto sever_actor = spawn_io_server(server, port, serv_actor);
      print_on_exit(sever_actor, "server");
      print_on_exit(serv_actor, "exit ack");
    },
    on("-c", val<string>, as_u16) >> [&](const string& host, uint16_t port) {
      // spawn the actor that sends warnings
      auto client_actor = spawn(sendWarning);
      // spawn a broker to serialize and recognize messages
      auto io_actor = spawn_io_client(protobuf_io, host, port, client_actor);
      print_on_exit(io_actor, "protobuf_io");
      print_on_exit(client_actor, "exit warning");
      // Start the warning message actor by using a kickoff message event sent directly from main
      send_as(io_actor, client_actor, atom("kickoff"), io_actor);
    },
    others >> [] {
      cerr << "use with eihter '-s PORT' as server or "
          "'-c HOST PORT' as client"
           << endl;
    }
  });
  await_all_actors_done();
  shutdown();
}
<commit_msg>added more documentation<commit_after>#include <vector>
#include <string>
#include <limits>
#include <memory>
#include <iostream>

#include <arpa/inet.h>

#include "caf/all.hpp"
#include "caf/io/all.hpp"

CAF_PUSH_WARNINGS
#include "message.pb.h"
CAF_POP_WARNINGS

using namespace std;
using namespace caf;
using namespace caf::io;

void print_on_exit(const actor& hdl, const std::string& name) {
  hdl->attach_functor([=](abstract_actor* ptr, uint32_t reason) {
    aout(ptr) << name << " exited with reason " << reason << endl;
  });
}

/*
  **************************
  Client's behavior -- sends a warning after kickoff and quits
  after the warning has been acknowledged by the server
  **************************
*/
behavior sendWarning(event_based_actor* self) {
  auto count = make_shared<size_t>(0);
  return {
    on(atom("kickoff"), arg_match) >> [=](const actor& pong) {
//	  aout(self) << "client: send {" << to_string(atom("warning")::value) << ", " <<  1 << "}" << endl;
      self->send(pong, atom("warning"), 1);
      self->become (
        on(atom("ack"), arg_match) >> [=](int value) -> void {
          self->quit();
          return;
//          return make_message(atom("ping"), value + 1);
        }
      );
    }
  };
}

/*
  **************************
  Server's behavior -- gets the client's warning from the protobuf broker
  and responds with an "ack" message
  **************************
*/
behavior ackMessage() {
  return {
    on(atom("warning"), arg_match) >> [](int value) {
      return make_message(atom("ack"), value);
    }
  };
}

/*
  **************************
  Protobuf broker implementation
  Works as a communication handling middleman for the server/client actors above
  Deserizalizes/serializes messages
  **************************
*/
void protobuf_io(broker* self, connection_handle hdl, const actor& buddy) {
  // monitor buddy to quit broker if buddy is done
  self->monitor(buddy);
  auto write = [=](const org::libcppa::WarnOrAck& p) {
    string buf = p.SerializeAsString();
    int32_t s = htonl(static_cast<int32_t>(buf.size()));
    self->write(hdl, sizeof(int32_t), &s);
    self->write(hdl, buf.size(), buf.data());
    self->flush(hdl);
  };
  // message handler
  message_handler default_bhvr = {
    [=](const connection_closed_msg&) {
      aout(self) << "connection closed" << endl;
      self->send_exit(buddy, exit_reason::remote_link_unreachable);
      self->quit(exit_reason::remote_link_unreachable);
    },
    on(atom("warning"), arg_match) >> [=](int i) {
      aout(self) << "Send: warning " << i << endl;
      org::libcppa::WarnOrAck p;
      p.mutable_warn()->set_id(i);
      write(p);
    },
    on(atom("ack"), arg_match) >> [=](int i) {
      aout(self) << "Send: ack " << i << endl;
      org::libcppa::WarnOrAck p;
      p.mutable_ack()->set_id(i);
      write(p);
    },
    [=](const down_msg& dm) {
      if (dm.source == buddy) {
        aout(self) << "our buddy is down" << endl;
        self->quit(dm.reason);
      }
    },
    others >> [=] {
      cout << "unexpected: " << to_string(self->current_message()) << endl;
    }
  };
  auto await_protobuf_data = message_handler {
    [=](const new_data_msg& msg) {
      org::libcppa::WarnOrAck p;
      p.ParseFromArray(msg.buf.data(), static_cast<int>(msg.buf.size()));
      if (p.has_warn()) {
        aout(self) << "Received: warning " << p.warn().id() << endl;
        self->send(buddy, atom("warning"), p.warn().id());
      }
      else if (p.has_ack()) {
        aout(self) << "Received: ack " << p.ack().id() << endl;
        self->send(buddy, atom("ack"), p.ack().id());
      }
      else {
        self->quit(exit_reason::user_shutdown);
        cerr << "neither Warning nor ACK!" << endl;
      }
      // receive next length prefix
      self->configure_read(hdl, receive_policy::exactly(sizeof(int32_t)));
      self->unbecome();
    }
  }.or_else(default_bhvr);
  auto await_length_prefix = message_handler {
    [=](const new_data_msg& msg) {
      int32_t num_bytes;
      memcpy(&num_bytes, msg.buf.data(), sizeof(int32_t));
      num_bytes = htonl(num_bytes);
      if (num_bytes < 0 || num_bytes > (1024 * 1024)) {
        aout(self) << "someone is trying something nasty" << endl;
        self->quit(exit_reason::user_shutdown);
        return;
      }
      // receive protobuf data
      auto nb = static_cast<size_t>(num_bytes);
      self->configure_read(hdl, receive_policy::exactly(nb));
      self->become(keep_behavior, await_protobuf_data);
    }
  }.or_else(default_bhvr);
  // initial setup
  self->configure_read(hdl, receive_policy::exactly(sizeof(int32_t)));
  self->become(await_length_prefix);
}

/*
 **************************
 Helper method for the server to handle connections;
 Starts the server broker with the received message handle if a client connects
 **************************
*/
behavior server(broker* self, actor buddy) {
  aout(self) << "server is running" << endl;
  return {
    [=](const new_connection_msg& msg) {
      aout(self) << "server accepted new connection" << endl;
      auto io_actor = self->fork(protobuf_io, msg.handle, buddy);
      print_on_exit(io_actor, "protobuf_io");
      // only accept 1 connection in our example
      self->quit();
    },
    others >> [=] {
      cout << "unexpected: " << to_string(self->current_message()) << endl;
    }
  };
}

optional<uint16_t> as_u16(const std::string& str) {
  return static_cast<uint16_t>(stoul(str));
}

int main(int argc, char** argv) {
// Parsing arguments
  message_builder{argv + 1, argv + argc}.apply({
    on("-s", as_u16) >> [&](uint16_t port) {
    // We are a server
      cout << "run in server mode" << endl;
      // spawn the actor that acks messages
      auto serv_actor = spawn(ackMessage);
      // spawn an IO server to handle communication and work with the broker later (uses the behavior server helper)
      auto sever_actor = spawn_io_server(server, port, serv_actor);
      print_on_exit(sever_actor, "server");
      print_on_exit(serv_actor, "exit ack");
    },
    on("-c", val<string>, as_u16) >> [&](const string& host, uint16_t port) {
      // spawn the actor that sends warnings
      auto client_actor = spawn(sendWarning);
      // spawn a broker to serialize and recognize messages
      auto io_actor = spawn_io_client(protobuf_io, host, port, client_actor);
      print_on_exit(io_actor, "protobuf_io");
      print_on_exit(client_actor, "exit warning");
      // Start the warning message actor by using a kickoff message event sent directly from main
      send_as(io_actor, client_actor, atom("kickoff"), io_actor);
    },
    others >> [] {
      cerr << "use with eihter '-s PORT' as server or "
          "'-c HOST PORT' as client"
           << endl;
    }
  });
  await_all_actors_done();
  shutdown();
}
<|endoftext|>


<commit_before>#include "de_web_plugin_private.h"

/*! Inits the event queue.
 */
void DeRestPluginPrivate::initEventQueue()
{
    eventTimer = new QTimer(this);
    eventTimer->setSingleShot(true);
    eventTimer->setInterval(1);
    connect(eventTimer, SIGNAL(timeout()), this, SLOT(eventQueueTimerFired()));
}

/*! Handles one event and fires again if more are in the queue.
 */
void DeRestPluginPrivate::eventQueueTimerFired()
{
    DBG_Assert(!eventQueue.empty());

    const Event &e = eventQueue.front();

    if (e.resource() == RSensors)
    {
        handleSensorEvent(e);
    }
    else if (e.resource() == RLights)
    {
        handleLightEvent(e);
    }
    else if (e.resource() == RGroups)
    {
        handleGroupEvent(e);
    }

    emit eventNotify(e);

    if (e.deviceKey() != 0)
    {
        auto *device = DEV_GetDevice(m_devices, e.deviceKey());
        if (device)
        {
            device->handleEvent(e);
        }
    }

    handleRuleEvent(e);

    eventQueue.pop_front();

    if (!eventQueue.empty())
    {
        eventTimer->start();
    }
}

/*! Puts an event into the queue.
    \param event - the event
 */
void DeRestPluginPrivate::enqueueEvent(const Event &event)
{
    if (DBG_IsEnabled(DBG_INFO_L2) && event.what() && event.resource())
    {
        DBG_Printf(DBG_INFO_L2, "enqueue event %s for %s/%s\n", event.what(), event.resource(), qPrintable(event.id()));
    }

    RestNodeBase *restNode = nullptr;

    // workaround to attach DeviceKey to an event
    if (event.deviceKey() == 0 && (event.resource() == RSensors || event.resource() == RLights))
    {
        if (event.resource() == RSensors)
        {
            restNode = getSensorNodeForId(event.id());
            if (!restNode)
            {
                restNode = getSensorNodeForUniqueId(event.id());
            }
        }
        else if (event.resource() == RLights)
        {
            restNode = getLightNodeForId(event.id());
        }
    }

    if (restNode && restNode->address().ext() > 0)
    {
        Event e2 = event;
        e2.setDeviceKey(restNode->address().ext());
        eventQueue.push_back(e2);
    }
    else
    {
        eventQueue.push_back(event);
    }

    if (!eventTimer->isActive())
    {
        eventTimer->start();
    }
}
<commit_msg>DEV: Add workaround to forward device name to core<commit_after>#include "de_web_plugin.h"
#include "de_web_plugin_private.h"

/*! Inits the event queue.
 */
void DeRestPluginPrivate::initEventQueue()
{
    eventTimer = new QTimer(this);
    eventTimer->setSingleShot(true);
    eventTimer->setInterval(1);
    connect(eventTimer, SIGNAL(timeout()), this, SLOT(eventQueueTimerFired()));
}

/*! Handles one event and fires again if more are in the queue.
 */
void DeRestPluginPrivate::eventQueueTimerFired()
{
    DBG_Assert(!eventQueue.empty());

    const Event &e = eventQueue.front();

    if (e.resource() == RSensors)
    {
        handleSensorEvent(e);
    }
    else if (e.resource() == RLights)
    {
        handleLightEvent(e);
    }
    else if (e.resource() == RGroups)
    {
        handleGroupEvent(e);
    }

    emit eventNotify(e);

    if (e.deviceKey() != 0)
    {
        auto *device = DEV_GetDevice(m_devices, e.deviceKey());
        if (device)
        {
            device->handleEvent(e);

        }

        // hack to forward first sub device name to core to show it as node name
        if (device && e.what() == REventDDFInitResponse && e.num() > 0)
        {
            const auto subDevices = device->subDevices();
            if (!subDevices.empty())
            {
                const auto *i = subDevices.front()->item(RAttrName);
                if (i && !i->toString().isEmpty())
                {
                    emit q_ptr->nodeUpdated(e.deviceKey(), QLatin1String("name"), i->toString());
                }
            }
        }
    }

    handleRuleEvent(e);

    eventQueue.pop_front();

    if (!eventQueue.empty())
    {
        eventTimer->start();
    }
}

/*! Puts an event into the queue.
    \param event - the event
 */
void DeRestPluginPrivate::enqueueEvent(const Event &event)
{
    if (DBG_IsEnabled(DBG_INFO_L2) && event.what() && event.resource())
    {
        DBG_Printf(DBG_INFO_L2, "enqueue event %s for %s/%s\n", event.what(), event.resource(), qPrintable(event.id()));
    }

    RestNodeBase *restNode = nullptr;

    // workaround to attach DeviceKey to an event
    if (event.deviceKey() == 0 && (event.resource() == RSensors || event.resource() == RLights))
    {
        if (event.resource() == RSensors)
        {
            restNode = getSensorNodeForId(event.id());
            if (!restNode)
            {
                restNode = getSensorNodeForUniqueId(event.id());
            }
        }
        else if (event.resource() == RLights)
        {
            restNode = getLightNodeForId(event.id());
        }
    }

    if (restNode && restNode->address().ext() > 0)
    {
        Event e2 = event;
        e2.setDeviceKey(restNode->address().ext());
        eventQueue.push_back(e2);
    }
    else
    {
        eventQueue.push_back(event);
    }

    if (!eventTimer->isActive())
    {
        eventTimer->start();
    }
}
<|endoftext|>