<commit_before>/******************************************************************************
** Copyright (c) 2013-2015, Intel Corporation                                **
** All rights reserved.                                                      **
**                                                                           **
** Redistribution and use in source and binary forms, with or without        **
** modification, are permitted provided that the following conditions        **
** are met:                                                                  **
** 1. Redistributions of source code must retain the above copyright         **
**    notice, this list of conditions and the following disclaimer.          **
** 2. Redistributions in binary form must reproduce the above copyright      **
**    notice, this list of conditions and the following disclaimer in the    **
**    documentation and/or other materials provided with the distribution.   **
** 3. Neither the name of the copyright holder nor the names of its          **
**    contributors may be used to endorse or promote products derived        **
**    from this software without specific prior written permission.          **
**                                                                           **
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       **
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         **
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR     **
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT      **
** HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    **
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED  **
** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR    **
** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    **
** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      **
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        **
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              **
******************************************************************************/
/* Hans Pabst (Intel Corp.)
******************************************************************************/
#include <libxsmm.h>

#if defined(LIBXSMM_OFFLOAD)
# pragma offload_attribute(push,target(mic))
#endif

#include <algorithm>
#include <stdexcept>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <vector>
#include <cmath>

#if defined(_OPENMP)
# include <omp.h>
#endif

#if defined(LIBXSMM_OFFLOAD)
# pragma offload_attribute(pop)
#endif

#if (0 < (LIBXSMM_ALIGNED_STORES))
# define SMM_ALIGNMENT LIBXSMM_ALIGNED_STORES
#else
# define SMM_ALIGNMENT LIBXSMM_ALIGNMENT
#endif

// make sure that stacksize is covering the problem size
#define SMM_MAX_PROBLEM_SIZE (1 * LIBXSMM_MAX_MNK)
// ensures sufficient parallel slack
#define SMM_MIN_NPARALLEL 210
// ensures amortized atomic overhead
#define SMM_MIN_NLOCAL 150
#define SMM_MAX_NLOCAL 250
// OpenMP schedule policy (and chunk size)
#define SMM_SCHEDULE static,1
// enable result validation
#define SMM_CHECK

template<typename T>
LIBXSMM_TARGET(mic) void nrand(T& a)
{
  static const double scale = 1.0 / RAND_MAX;
  a = static_cast<T>(scale * (2 * std::rand() - RAND_MAX));
}

template<typename T>
LIBXSMM_TARGET(mic) void add(T *LIBXSMM_RESTRICT dst, const T *LIBXSMM_RESTRICT c, int m, int n, int ldc)
{
#if (0 < LIBXSMM_ALIGNED_STORES)
  LIBXSMM_ASSUME_ALIGNED(c, SMM_ALIGNMENT);
#endif
  for (int i = 0; i < m; ++i) {
    for (int j = 0; j < n; ++j) {
#if (0 != LIBXSMM_ROW_MAJOR)
      const T value = c[i*ldc+j];
#else
      const T value = c[j*ldc+i];
#endif
#if defined(_OPENMP)
#     pragma omp atomic
#endif
#if (0 != LIBXSMM_ROW_MAJOR)
      dst[i*n+j] += value;
#else
      dst[j*m+i] += value;
#endif
    }
  }
}

template<typename T>
LIBXSMM_TARGET(mic) double max_diff(const T *LIBXSMM_RESTRICT result, const T *LIBXSMM_RESTRICT expect, int m, int n, int ldc)
{
  double diff = 0;
  for (int i = 0; i < m; ++i) {
    for (int j = 0; j < n; ++j) {
#if (0 != LIBXSMM_ROW_MAJOR)
      const int k = i * ldc + j;
#else
      const int k = j * ldc + i;
#endif
      diff = std::max(diff, std::abs(static_cast<double>(result[k]) - static_cast<double>(expect[k])));
    }
  }
  return diff;
}

int main(int argc, char* argv[])
{
  try {
    typedef double T;
    const int default_psize = (SMM_MIN_NPARALLEL) * (SMM_MIN_NLOCAL), default_batch = SMM_MAX_NLOCAL;
    const int m = 1 < argc ? std::atoi(argv[1]) : 23;
    const int s = 2 < argc ? (0 < std::atoi(argv[2]) ? std::atoi(argv[2]) : ('+' == *argv[2]
      ? (default_psize << std::strlen(argv[2])) : ('-' == *argv[2]
      ? (default_psize >> std::strlen(argv[2])) : default_psize))) : default_psize;
    const int t = 3 < argc ? (0 < std::atoi(argv[3]) ? std::atoi(argv[3]) : ('+' == *argv[3]
      ? (default_batch << std::strlen(argv[3])) : ('-' == *argv[3]
      ? (default_batch >> std::strlen(argv[3])) : -1))) : -1;
    const int n = 4 < argc ? std::atoi(argv[4]) : m;
    const int k = 5 < argc ? std::atoi(argv[5]) : m;

    if ((SMM_MAX_PROBLEM_SIZE) < (m * n * k)) {
      throw std::runtime_error("The size M x N x K is exceeding SMM_MAX_PROBLEM_SIZE!");
    }

#if (0 != LIBXSMM_ROW_MAJOR)
# if (0 < LIBXSMM_ALIGNED_STORES)
    const int ldc = LIBXSMM_ALIGN_VALUE(int, T, n, LIBXSMM_ALIGNED_STORES);
# else
    const int ldc = n;
# endif
    const int csize = m * ldc;
#else
# if (0 < LIBXSMM_ALIGNED_STORES)
    const int ldc = LIBXSMM_ALIGN_VALUE(int, T, m, LIBXSMM_ALIGNED_STORES);
# else
    const int ldc = m;
# endif
    const int csize = n * ldc;
#endif

    const int asize = m * k, bsize = k * n;
    std::vector<T> va(s * asize), vb(s * bsize), vc(csize);
    std::for_each(va.begin(), va.end(), nrand<T>);
    std::for_each(vb.begin(), vb.end(), nrand<T>);
    const T *const a = &va[0], *const b = &vb[0];
    T * /*const*/ c = &vc[0];

#if defined(LIBXSMM_OFFLOAD)
#   pragma offload target(mic) in(a: length(s * asize)) in(b: length(s * bsize)) out(c: length(csize))
#endif
    {
      const double mbytes = 1.0 * s * (asize + bsize) * sizeof(T) / (1024 * 1024);
#if defined(_OPENMP)
      const double nbytes = 1.0 * s * (csize) * sizeof(T) / (1024 * 1024);
      const double gflops = 2.0 * s * m * n * k * 1E-9;
      const int u = 0 < t ? t : std::max(SMM_MIN_NLOCAL, std::min(SMM_MAX_NLOCAL, s / std::max(SMM_MIN_NPARALLEL, s / default_batch)));
#else
      const int u = t;
#endif
#if defined(SMM_CHECK)
      std::vector<T> expect(csize);
#endif
      fprintf(stdout, "m=%i n=%i k=%i ldc=%i size=%i batch=%i memory=%.1f MB\n\n", m, n, k, ldc, s, u, mbytes);

      { // LAPACK/BLAS3 (fallback)
        fprintf(stdout, "LAPACK/BLAS...\n");
        std::fill_n(c, csize, 0);
#if defined(_OPENMP)
        const double start = omp_get_wtime();
#       pragma omp parallel for schedule(SMM_SCHEDULE)
#endif
        for (int i = 0; i < s; i += u) {
          LIBXSMM_ALIGNED(T tmp[SMM_MAX_PROBLEM_SIZE], SMM_ALIGNMENT);
          for (int j = 0; j < csize; ++j) tmp[j] = 0; // clear
          for (int j = 0; j < LIBXSMM_MIN(u, s - i); ++j) {
            libxsmm_blasmm(m, n, k, &a[0] + (i + j) * asize, &b[0] + (i + j) * bsize, tmp);
          }
          add(c, tmp, m, n, ldc); // atomic
        }
#if defined(_OPENMP)
        const double duration = omp_get_wtime() - start;
        if (0 < duration) {
          fprintf(stdout, "\tperformance: %.1f GFLOPS/s\n", gflops / duration);
          fprintf(stdout, "\tbandwidth: %.1f GB/s\n", (mbytes + nbytes) * 1E-3 / duration);
        }
        fprintf(stdout, "\tduration: %.1f s\n", duration);
#endif
#if defined(SMM_CHECK)
        std::copy(c, c + csize, expect.begin());
#endif
      }

      { // inline an optimized implementation
        fprintf(stdout, "Inlined...\n");
        std::fill_n(c, csize, 0);
#if defined(_OPENMP)
        const double start = omp_get_wtime();
#       pragma omp parallel for schedule(SMM_SCHEDULE)
#endif
        for (int i = 0; i < s; i += u) {
          LIBXSMM_ALIGNED(T tmp[SMM_MAX_PROBLEM_SIZE], SMM_ALIGNMENT);
          for (int j = 0; j < csize; ++j) tmp[j] = 0; // clear
          for (int j = 0; j < LIBXSMM_MIN(u, s - i); ++j) {
            libxsmm_imm(m, n, k, &a[0] + (i + j) * asize, &b[0] + (i + j) * bsize, tmp);
          }
          add(c, tmp, m, n, ldc); // atomic
        }
#if defined(_OPENMP)
        const double duration = omp_get_wtime() - start;
        if (0 < duration) {
          fprintf(stdout, "\tperformance: %.1f GFLOPS/s\n", gflops / duration);
          fprintf(stdout, "\tbandwidth: %.1f GB/s\n", (mbytes + nbytes) * 1E-3 / duration);
        }
        fprintf(stdout, "\tduration: %.1f s\n", duration);
#endif
#if defined(SMM_CHECK)
        fprintf(stdout, "\tdiff=%f\n", max_diff(c, &expect[0], m, n, ldc));
#endif
      }

      { // auto-dispatched
        fprintf(stdout, "Dispatched...\n");
        libxsmm_mm(m, n, k, &a[0], &b[0], &c[0]); // warmup/workaround
        std::fill_n(c, csize, 0);
#if defined(_OPENMP)
        const double start = omp_get_wtime();
#       pragma omp parallel for schedule(SMM_SCHEDULE)
#endif
        for (int i = 0; i < s; i += u) {
          LIBXSMM_ALIGNED(T tmp[SMM_MAX_PROBLEM_SIZE], SMM_ALIGNMENT);
          for (int j = 0; j < csize; ++j) tmp[j] = 0; // clear
          for (int j = 0; j < LIBXSMM_MIN(u, s - i); ++j) {
            libxsmm_mm(m, n, k, &a[0] + (i + j) * asize, &b[0] + (i + j) * bsize, tmp);
          }
          add(c, tmp, m, n, ldc); // atomic
        }
#if defined(_OPENMP)
        const double duration = omp_get_wtime() - start;
        if (0 < duration) {
          fprintf(stdout, "\tperformance: %.1f GFLOPS/s\n", gflops / duration);
          fprintf(stdout, "\tbandwidth: %.1f GB/s\n", (mbytes + nbytes) * 1E-3 / duration);
        }
        fprintf(stdout, "\tduration: %.1f s\n", duration);
#endif
#if defined(SMM_CHECK)
        fprintf(stdout, "\tdiff=%f\n", max_diff(c, &expect[0], m, n, ldc));
#endif
      }

      const libxsmm_mm_dispatch<T> xmm(m, n, k);
      if (xmm) { // specialized routine
        fprintf(stdout, "Specialized...\n");
        std::fill_n(c, csize, 0);
#if defined(_OPENMP)
        const double start = omp_get_wtime();
#       pragma omp parallel for schedule(SMM_SCHEDULE)
#endif
        for (int i = 0; i < s; i += u) {
          LIBXSMM_ALIGNED(T tmp[SMM_MAX_PROBLEM_SIZE], SMM_ALIGNMENT);
          for (int j = 0; j < csize; ++j) tmp[j] = 0; // clear
          for (int j = 0; j < LIBXSMM_MIN(u, s - i); ++j) {
            xmm(&a[0] + (i + j) * asize, &b[0] + (i + j) * bsize, tmp);
          }
          add(c, tmp, m, n, ldc); // atomic
        }
#if defined(_OPENMP)
        const double duration = omp_get_wtime() - start;
        if (0 < duration) {
          fprintf(stdout, "\tperformance: %.1f GFLOPS/s\n", gflops / duration);
          fprintf(stdout, "\tbandwidth: %.1f GB/s\n", (mbytes + nbytes) * 1E-3 / duration);
        }
        fprintf(stdout, "\tduration: %.1f s\n", duration);
#endif
#if defined(SMM_CHECK)
        fprintf(stdout, "\tdiff=%f\n", max_diff(c, &expect[0], m, n, ldc));
#endif
      }

      fprintf(stdout, "Finished\n");
    }
  }
  catch(const std::exception& e) {
    fprintf(stderr, "Error: %s\n", e.what());
    return EXIT_FAILURE;
  }
  catch(...) {
    fprintf(stderr, "Error: unknown exception caught!\n");
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}
<commit_msg>Fixed warmup.<commit_after>/******************************************************************************
** Copyright (c) 2013-2015, Intel Corporation                                **
** All rights reserved.                                                      **
**                                                                           **
** Redistribution and use in source and binary forms, with or without        **
** modification, are permitted provided that the following conditions        **
** are met:                                                                  **
** 1. Redistributions of source code must retain the above copyright         **
**    notice, this list of conditions and the following disclaimer.          **
** 2. Redistributions in binary form must reproduce the above copyright      **
**    notice, this list of conditions and the following disclaimer in the    **
**    documentation and/or other materials provided with the distribution.   **
** 3. Neither the name of the copyright holder nor the names of its          **
**    contributors may be used to endorse or promote products derived        **
**    from this software without specific prior written permission.          **
**                                                                           **
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       **
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         **
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR     **
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT      **
** HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    **
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED  **
** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR    **
** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    **
** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      **
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        **
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              **
******************************************************************************/
/* Hans Pabst (Intel Corp.)
******************************************************************************/
#include <libxsmm.h>

#if defined(LIBXSMM_OFFLOAD)
# pragma offload_attribute(push,target(mic))
#endif

#include <algorithm>
#include <stdexcept>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <vector>
#include <cmath>

#if defined(_OPENMP)
# include <omp.h>
#endif

#if defined(LIBXSMM_OFFLOAD)
# pragma offload_attribute(pop)
#endif

#if (0 < (LIBXSMM_ALIGNED_STORES))
# define SMM_ALIGNMENT LIBXSMM_ALIGNED_STORES
#else
# define SMM_ALIGNMENT LIBXSMM_ALIGNMENT
#endif

// make sure that stacksize is covering the problem size
#define SMM_MAX_PROBLEM_SIZE (1 * LIBXSMM_MAX_MNK)
// ensures sufficient parallel slack
#define SMM_MIN_NPARALLEL 210
// ensures amortized atomic overhead
#define SMM_MIN_NLOCAL 150
#define SMM_MAX_NLOCAL 250
// OpenMP schedule policy (and chunk size)
#define SMM_SCHEDULE static,1
// enable result validation
#define SMM_CHECK

template<typename T>
LIBXSMM_TARGET(mic) void nrand(T& a)
{
  static const double scale = 1.0 / RAND_MAX;
  a = static_cast<T>(scale * (2 * std::rand() - RAND_MAX));
}

template<typename T>
LIBXSMM_TARGET(mic) void add(T *LIBXSMM_RESTRICT dst, const T *LIBXSMM_RESTRICT c, int m, int n, int ldc)
{
#if (0 < LIBXSMM_ALIGNED_STORES)
  LIBXSMM_ASSUME_ALIGNED(c, SMM_ALIGNMENT);
#endif
  for (int i = 0; i < m; ++i) {
    for (int j = 0; j < n; ++j) {
#if (0 != LIBXSMM_ROW_MAJOR)
      const T value = c[i*ldc+j];
#else
      const T value = c[j*ldc+i];
#endif
#if defined(_OPENMP)
#     pragma omp atomic
#endif
#if (0 != LIBXSMM_ROW_MAJOR)
      dst[i*n+j] += value;
#else
      dst[j*m+i] += value;
#endif
    }
  }
}

template<typename T>
LIBXSMM_TARGET(mic) double max_diff(const T *LIBXSMM_RESTRICT result, const T *LIBXSMM_RESTRICT expect, int m, int n, int ldc)
{
  double diff = 0;
  for (int i = 0; i < m; ++i) {
    for (int j = 0; j < n; ++j) {
#if (0 != LIBXSMM_ROW_MAJOR)
      const int k = i * ldc + j;
#else
      const int k = j * ldc + i;
#endif
      diff = std::max(diff, std::abs(static_cast<double>(result[k]) - static_cast<double>(expect[k])));
    }
  }
  return diff;
}

int main(int argc, char* argv[])
{
  try {
    typedef double T;
    const int default_psize = (SMM_MIN_NPARALLEL) * (SMM_MIN_NLOCAL), default_batch = SMM_MAX_NLOCAL;
    const int m = 1 < argc ? std::atoi(argv[1]) : 23;
    const int s = 2 < argc ? (0 < std::atoi(argv[2]) ? std::atoi(argv[2]) : ('+' == *argv[2]
      ? (default_psize << std::strlen(argv[2])) : ('-' == *argv[2]
      ? (default_psize >> std::strlen(argv[2])) : default_psize))) : default_psize;
    const int t = 3 < argc ? (0 < std::atoi(argv[3]) ? std::atoi(argv[3]) : ('+' == *argv[3]
      ? (default_batch << std::strlen(argv[3])) : ('-' == *argv[3]
      ? (default_batch >> std::strlen(argv[3])) : -1))) : -1;
    const int n = 4 < argc ? std::atoi(argv[4]) : m;
    const int k = 5 < argc ? std::atoi(argv[5]) : m;

    if ((SMM_MAX_PROBLEM_SIZE) < (m * n * k)) {
      throw std::runtime_error("The size M x N x K is exceeding SMM_MAX_PROBLEM_SIZE!");
    }

#if (0 != LIBXSMM_ROW_MAJOR)
# if (0 < LIBXSMM_ALIGNED_STORES)
    const int ldc = LIBXSMM_ALIGN_VALUE(int, T, n, LIBXSMM_ALIGNED_STORES);
# else
    const int ldc = n;
# endif
    const int csize = m * ldc;
#else
# if (0 < LIBXSMM_ALIGNED_STORES)
    const int ldc = LIBXSMM_ALIGN_VALUE(int, T, m, LIBXSMM_ALIGNED_STORES);
# else
    const int ldc = m;
# endif
    const int csize = n * ldc;
#endif

    const int asize = m * k, bsize = k * n;
    std::vector<T> va(s * asize), vb(s * bsize), vc(csize);
    std::for_each(va.begin(), va.end(), nrand<T>);
    std::for_each(vb.begin(), vb.end(), nrand<T>);
    const T *const a = &va[0], *const b = &vb[0];
    T * /*const*/ c = &vc[0];

#if defined(LIBXSMM_OFFLOAD)
#   pragma offload target(mic) in(a: length(s * asize)) in(b: length(s * bsize)) out(c: length(csize))
#endif
    {
      const double mbytes = 1.0 * s * (asize + bsize) * sizeof(T) / (1024 * 1024);
#if defined(_OPENMP)
      const double nbytes = 1.0 * s * (csize) * sizeof(T) / (1024 * 1024);
      const double gflops = 2.0 * s * m * n * k * 1E-9;
      const int u = 0 < t ? t : std::max(SMM_MIN_NLOCAL, std::min(SMM_MAX_NLOCAL, s / std::max(SMM_MIN_NPARALLEL, s / default_batch)));
#else
      const int u = t;
#endif
#if defined(SMM_CHECK)
      std::vector<T> expect(csize);
#endif
      fprintf(stdout, "m=%i n=%i k=%i ldc=%i size=%i batch=%i memory=%.1f MB\n\n", m, n, k, ldc, s, u, mbytes);

      { // LAPACK/BLAS3 (fallback)
        fprintf(stdout, "LAPACK/BLAS...\n");
        std::fill_n(c, csize, 0);
#if defined(_OPENMP)
        const double start = omp_get_wtime();
#       pragma omp parallel for schedule(SMM_SCHEDULE)
#endif
        for (int i = 0; i < s; i += u) {
          LIBXSMM_ALIGNED(T tmp[SMM_MAX_PROBLEM_SIZE], SMM_ALIGNMENT);
          for (int j = 0; j < csize; ++j) tmp[j] = 0; // clear
          for (int j = 0; j < LIBXSMM_MIN(u, s - i); ++j) {
            libxsmm_blasmm(m, n, k, &a[0] + (i + j) * asize, &b[0] + (i + j) * bsize, tmp);
          }
          add(c, tmp, m, n, ldc); // atomic
        }
#if defined(_OPENMP)
        const double duration = omp_get_wtime() - start;
        if (0 < duration) {
          fprintf(stdout, "\tperformance: %.1f GFLOPS/s\n", gflops / duration);
          fprintf(stdout, "\tbandwidth: %.1f GB/s\n", (mbytes + nbytes) * 1E-3 / duration);
        }
        fprintf(stdout, "\tduration: %.1f s\n", duration);
#endif
#if defined(SMM_CHECK)
        std::copy(c, c + csize, expect.begin());
#endif
      }

      { // inline an optimized implementation
        fprintf(stdout, "Inlined...\n");
        std::fill_n(c, csize, 0);
#if defined(_OPENMP)
        const double start = omp_get_wtime();
#       pragma omp parallel for schedule(SMM_SCHEDULE)
#endif
        for (int i = 0; i < s; i += u) {
          LIBXSMM_ALIGNED(T tmp[SMM_MAX_PROBLEM_SIZE], SMM_ALIGNMENT);
          for (int j = 0; j < csize; ++j) tmp[j] = 0; // clear
          for (int j = 0; j < LIBXSMM_MIN(u, s - i); ++j) {
            libxsmm_imm(m, n, k, &a[0] + (i + j) * asize, &b[0] + (i + j) * bsize, tmp);
          }
          add(c, tmp, m, n, ldc); // atomic
        }
#if defined(_OPENMP)
        const double duration = omp_get_wtime() - start;
        if (0 < duration) {
          fprintf(stdout, "\tperformance: %.1f GFLOPS/s\n", gflops / duration);
          fprintf(stdout, "\tbandwidth: %.1f GB/s\n", (mbytes + nbytes) * 1E-3 / duration);
        }
        fprintf(stdout, "\tduration: %.1f s\n", duration);
#endif
#if defined(SMM_CHECK)
        fprintf(stdout, "\tdiff=%f\n", max_diff(c, &expect[0], m, n, ldc));
#endif
      }

      { // auto-dispatched
        fprintf(stdout, "Dispatched...\n");
        libxsmm_mm(1, 1, 1, &a[0], &b[0], &c[0]); // warmup/workaround
        std::fill_n(c, csize, 0);
#if defined(_OPENMP)
        const double start = omp_get_wtime();
#       pragma omp parallel for schedule(SMM_SCHEDULE)
#endif
        for (int i = 0; i < s; i += u) {
          LIBXSMM_ALIGNED(T tmp[SMM_MAX_PROBLEM_SIZE], SMM_ALIGNMENT);
          for (int j = 0; j < csize; ++j) tmp[j] = 0; // clear
          for (int j = 0; j < LIBXSMM_MIN(u, s - i); ++j) {
            libxsmm_mm(m, n, k, &a[0] + (i + j) * asize, &b[0] + (i + j) * bsize, tmp);
          }
          add(c, tmp, m, n, ldc); // atomic
        }
#if defined(_OPENMP)
        const double duration = omp_get_wtime() - start;
        if (0 < duration) {
          fprintf(stdout, "\tperformance: %.1f GFLOPS/s\n", gflops / duration);
          fprintf(stdout, "\tbandwidth: %.1f GB/s\n", (mbytes + nbytes) * 1E-3 / duration);
        }
        fprintf(stdout, "\tduration: %.1f s\n", duration);
#endif
#if defined(SMM_CHECK)
        fprintf(stdout, "\tdiff=%f\n", max_diff(c, &expect[0], m, n, ldc));
#endif
      }

      const libxsmm_mm_dispatch<T> xmm(m, n, k);
      if (xmm) { // specialized routine
        fprintf(stdout, "Specialized...\n");
        std::fill_n(c, csize, 0);
#if defined(_OPENMP)
        const double start = omp_get_wtime();
#       pragma omp parallel for schedule(SMM_SCHEDULE)
#endif
        for (int i = 0; i < s; i += u) {
          LIBXSMM_ALIGNED(T tmp[SMM_MAX_PROBLEM_SIZE], SMM_ALIGNMENT);
          for (int j = 0; j < csize; ++j) tmp[j] = 0; // clear
          for (int j = 0; j < LIBXSMM_MIN(u, s - i); ++j) {
            xmm(&a[0] + (i + j) * asize, &b[0] + (i + j) * bsize, tmp);
          }
          add(c, tmp, m, n, ldc); // atomic
        }
#if defined(_OPENMP)
        const double duration = omp_get_wtime() - start;
        if (0 < duration) {
          fprintf(stdout, "\tperformance: %.1f GFLOPS/s\n", gflops / duration);
          fprintf(stdout, "\tbandwidth: %.1f GB/s\n", (mbytes + nbytes) * 1E-3 / duration);
        }
        fprintf(stdout, "\tduration: %.1f s\n", duration);
#endif
#if defined(SMM_CHECK)
        fprintf(stdout, "\tdiff=%f\n", max_diff(c, &expect[0], m, n, ldc));
#endif
      }

      fprintf(stdout, "Finished\n");
    }
  }
  catch(const std::exception& e) {
    fprintf(stderr, "Error: %s\n", e.what());
    return EXIT_FAILURE;
  }
  catch(...) {
    fprintf(stderr, "Error: unknown exception caught!\n");
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImagingFactory.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkObjectFactory.h"
#include "vtkImagingFactory.h"
#include "vtkToolkits.h"
#include "vtkDebugLeaks.h"

#ifdef VTK_USE_OGLR
#include "vtkOpenGLImageMapper.h"
#include "vtkXOpenGLTextMapper.h"
#include "vtkOpenGLPolyDataMapper2D.h"
#endif

#if defined(VTK_MANGLE_MESA)
#include "vtkMesaImageMapper.h"
#include "vtkXMesaTextMapper.h"
#include "vtkMesaPolyDataMapper2D.h"
#endif

#ifdef _WIN32
#include "vtkOpenGLImageMapper.h"
#include "vtkWin32OpenGLTextMapper.h"
#include "vtkOpenGLPolyDataMapper2D.h"
#endif

#ifdef VTK_USE_CARBON
#include "vtkOpenGLImageMapper.h"
#include "vtkCarbonTextMapper.h"
#include "vtkOpenGLPolyDataMapper2D.h"
#endif
#ifdef VTK_USE_COCOA
#include "vtkOpenGLImageMapper.h"
#include "vtkCocoaTextMapper.h"
#include "vtkOpenGLPolyDataMapper2D.h"
#endif

#include "vtkCriticalSection.h"
static vtkSimpleCriticalSection vtkUseMesaClassesCriticalSection;
int vtkImagingFactory::UseMesaClasses = 0;

vtkCxxRevisionMacro(vtkImagingFactory, "1.24");
vtkStandardNewMacro(vtkImagingFactory);

const char *vtkImagingFactoryGetRenderLibrary()
{
  const char *temp;

  // first check the environment variable
  temp = getenv("VTK_RENDERER");

  // Backward compatibility
  if ( temp )
    {
    if (!strcmp("oglr",temp))
      {
      temp = "OpenGL";
      }
    else if (!strcmp("woglr",temp))
      {
      temp = "Win32OpenGL";
      }
    else if (strcmp("Mesa",temp) && strcmp("OpenGL",temp) &&
             strcmp("Win32OpenGL",temp))
      {
      vtkGenericWarningMacro(<<"VTK_RENDERER set to unsupported type:" << temp);
      temp = NULL;
      }
    }

  // if nothing is set then work down the list of possible renderers
  if ( !temp )
    {
#ifdef VTK_USE_OGLR
    temp = "OpenGL";
#endif
#ifdef _WIN32
    temp = "Win32OpenGL";
#endif
#ifdef VTK_USE_CARBON
    temp = "CarbonOpenGL";
#endif
#ifdef VTK_USE_COCOA
    temp = "CocoaOpenGL";
#endif
    }

  return temp;
}

vtkObject* vtkImagingFactory::CreateInstance(const char* vtkclassname )
{
  // first check the object factory
  vtkObject *ret = vtkObjectFactory::CreateInstance(vtkclassname);
  if (ret)
    {
    return ret;
    }
  // if the factory failed to create the object,
  // then destroy it now, as vtkDebugLeaks::ConstructClass was called
  // with vtkclassname, and not the real name of the class
#ifdef VTK_DEBUG_LEAKS
  vtkDebugLeaks::DestructClass(vtkclassname);
#endif

  const char *rl = vtkImagingFactoryGetRenderLibrary();

#ifdef VTK_USE_OGLR
  if (!strcmp("OpenGL",rl))
    {
    if(strcmp(vtkclassname, "vtkTextMapper") == 0)
      {
#if defined(VTK_MANGLE_MESA)
      if ( vtkImagingFactory::UseMesaClasses )
        {
        return vtkXMesaTextMapper::New();
        }
#endif
      return vtkXOpenGLTextMapper::New();
      }
    if(strcmp(vtkclassname, "vtkImageMapper") == 0)
      {
#if defined(VTK_MANGLE_MESA)
      if ( vtkImagingFactory::UseMesaClasses )
        {
        return vtkMesaImageMapper::New();
        }
#endif
      return vtkOpenGLImageMapper::New();
      }
    if(strcmp(vtkclassname, "vtkPolyDataMapper2D") == 0)
      {
#if defined(VTK_MANGLE_MESA)
      if ( vtkImagingFactory::UseMesaClasses )
        {
        return vtkMesaPolyDataMapper2D::New();
        }
#endif
      return vtkOpenGLPolyDataMapper2D::New();
      }
    }
#endif

#ifdef _WIN32
  if (!strcmp("Win32OpenGL",rl))
    {
    if(strcmp(vtkclassname, "vtkTextMapper") == 0)
      {
      return vtkWin32OpenGLTextMapper::New();
      }
    if(strcmp(vtkclassname, "vtkImageMapper") == 0)
      {
      return vtkOpenGLImageMapper::New();
      }
    if(strcmp(vtkclassname, "vtkPolyDataMapper2D") == 0)
      {
      return vtkOpenGLPolyDataMapper2D::New();
      }
    }
#endif

#ifdef VTK_USE_CARBON
  if (!strcmp("CarbonOpenGL",rl))
    {
    if(strcmp(vtkclassname, "vtkTextMapper") == 0)
      {
      return vtkCarbonTextMapper::New();
      }
    if(strcmp(vtkclassname, "vtkImageMapper") == 0)
      {
      return vtkOpenGLImageMapper::New();
      }
    if(strcmp(vtkclassname, "vtkPolyDataMapper2D") == 0)
      {
      return vtkOpenGLPolyDataMapper2D::New();
      }
    }
#endif
#ifdef VTK_USE_COCOA
  if (!strcmp("CocoaOpenGL",rl))
    {
    if(strcmp(vtkclassname, "vtkTextMapper") == 0)
      {
      return vtkCocoaTextMapper::New();
      }
    if(strcmp(vtkclassname, "vtkImageMapper") == 0)
      {
      return vtkOpenGLImageMapper::New();
      }
    if(strcmp(vtkclassname, "vtkPolyDataMapper2D") == 0)
      {
      return vtkOpenGLPolyDataMapper2D::New();
      }
    }
#endif

  return 0;
}

void vtkImagingFactory::SetUseMesaClasses(int use)
{
  vtkUseMesaClassesCriticalSection.Lock();
  vtkImagingFactory::UseMesaClasses = use;
  vtkUseMesaClassesCriticalSection.Unlock();
}

int vtkImagingFactory::GetUseMesaClasses()
{
  return vtkImagingFactory::UseMesaClasses;
}
<commit_msg>ENH: this is it, say good bye to all text mappers and replace them with vtkOpenGLFreeTypeTextMapper<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImagingFactory.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkObjectFactory.h"
#include "vtkImagingFactory.h"
#include "vtkToolkits.h"
#include "vtkDebugLeaks.h"

#ifdef VTK_USE_OGLR
#include "vtkOpenGLImageMapper.h"
#ifdef VTK_USE_FREETYPE
#include "vtkOpenGLFreeTypeTextMapper.h"
#else
#include "vtkXOpenGLTextMapper.h"
#endif
#include "vtkOpenGLPolyDataMapper2D.h"
#endif

#if defined(VTK_MANGLE_MESA)
#include "vtkMesaImageMapper.h"
#ifdef VTK_USE_FREETYPE
#include "vtkOpenGLFreeTypeTextMapper.h"
#else
#include "vtkXMesaTextMapper.h"
#endif
#include "vtkMesaPolyDataMapper2D.h"
#endif

#ifdef _WIN32
#include "vtkOpenGLImageMapper.h"
#ifdef VTK_USE_FREETYPE
#include "vtkOpenGLFreeTypeTextMapper.h"
#else
#include "vtkWin32OpenGLTextMapper.h"
#endif
#include "vtkOpenGLPolyDataMapper2D.h"
#else
#ifdef VTK_USE_QUARTZ
#include "vtkOpenGLImageMapper.h"
#include "vtkOpenGLPolyDataMapper2D.h"
#ifdef VTK_USE_FREETYPE
#include "vtkOpenGLFreeTypeTextMapper.h"
#else
#include "vtkQuartzTextMapper.h"
#endif
#include "vtkQuartzImageMapper.h"
#endif
#endif

#ifdef VTK_USE_CARBON
#include "vtkOpenGLImageMapper.h"
#ifdef VTK_USE_FREETYPE
#include "vtkOpenGLFreeTypeTextMapper.h"
#else
#include "vtkCarbonTextMapper.h"
#endif
#include "vtkOpenGLPolyDataMapper2D.h"
#endif
#ifdef VTK_USE_COCOA
#include "vtkOpenGLImageMapper.h"
#ifdef VTK_USE_FREETYPE
#include "vtkOpenGLFreeTypeTextMapper.h"
#else
#include "vtkCocoaTextMapper.h"
#endif
#include "vtkOpenGLPolyDataMapper2D.h"
#endif

#include "vtkCriticalSection.h"
static vtkSimpleCriticalSection vtkUseMesaClassesCriticalSection;
int vtkImagingFactory::UseMesaClasses = 0;

vtkCxxRevisionMacro(vtkImagingFactory, "1.25");
vtkStandardNewMacro(vtkImagingFactory);

const char *vtkImagingFactoryGetRenderLibrary()
{
  const char *temp;

  // first check the environment variable
  temp = getenv("VTK_RENDERER");

  // Backward compatibility
  if ( temp )
    {
    if (!strcmp("oglr",temp))
      {
      temp = "OpenGL";
      }
    else if (!strcmp("woglr",temp))
      {
      temp = "Win32OpenGL";
      }
    else if (strcmp("Mesa",temp) && strcmp("OpenGL",temp) &&
             strcmp("Win32OpenGL",temp))
      {
      vtkGenericWarningMacro(<<"VTK_RENDERER set to unsupported type:" << temp);
      temp = NULL;
      }
    }

  // if nothing is set then work down the list of possible renderers
  if ( !temp )
    {
#ifdef VTK_USE_OGLR
    temp = "OpenGL";
#endif
#ifdef _WIN32
    temp = "Win32OpenGL";
#endif
#ifdef VTK_USE_CARBON
    temp = "CarbonOpenGL";
#endif
#ifdef VTK_USE_COCOA
    temp = "CocoaOpenGL";
#endif
    }

  return temp;
}

vtkObject* vtkImagingFactory::CreateInstance(const char* vtkclassname )
{
  // first check the object factory
  vtkObject *ret = vtkObjectFactory::CreateInstance(vtkclassname);
  if (ret)
    {
    return ret;
    }
  // if the factory failed to create the object,
  // then destroy it now, as vtkDebugLeaks::ConstructClass was called
  // with vtkclassname, and not the real name of the class
#ifdef VTK_DEBUG_LEAKS
  vtkDebugLeaks::DestructClass(vtkclassname);
#endif

  const char *rl = vtkImagingFactoryGetRenderLibrary();

#ifdef VTK_USE_OGLR
  if (!strcmp("OpenGL",rl))
    {
    if(strcmp(vtkclassname, "vtkTextMapper") == 0)
      {
#if defined(VTK_MANGLE_MESA)
      if ( vtkImagingFactory::UseMesaClasses )
        {
#ifdef VTK_USE_FREETYPE
        return vtkOpenGLFreeTypeTextMapper::New();
#else
        return vtkXMesaTextMapper::New();
#endif
        }
#endif
#ifdef VTK_USE_FREETYPE
      return vtkOpenGLFreeTypeTextMapper::New();
#else
      return vtkXOpenGLTextMapper::New();
#endif
      }
    if(strcmp(vtkclassname, "vtkImageMapper") == 0)
      {
#if defined(VTK_MANGLE_MESA)
      if ( vtkImagingFactory::UseMesaClasses )
        {
        return vtkMesaImageMapper::New();
        }
#endif
      return vtkOpenGLImageMapper::New();
      }
    if(strcmp(vtkclassname, "vtkPolyDataMapper2D") == 0)
      {
#if defined(VTK_MANGLE_MESA)
      if ( vtkImagingFactory::UseMesaClasses )
        {
        return vtkMesaPolyDataMapper2D::New();
        }
#endif
      return vtkOpenGLPolyDataMapper2D::New();
      }
    }
#endif

#ifdef _WIN32
  if (!strcmp("Win32OpenGL",rl))
    {
    if(strcmp(vtkclassname, "vtkTextMapper") == 0)
      {
#ifdef VTK_USE_FREETYPE
      return vtkOpenGLFreeTypeTextMapper::New();
#else
      return vtkWin32OpenGLTextMapper::New();
#endif
      }
    if(strcmp(vtkclassname, "vtkImageMapper") == 0)
      {
      return vtkOpenGLImageMapper::New();
      }
    if(strcmp(vtkclassname, "vtkPolyDataMapper2D") == 0)
      {
      return vtkOpenGLPolyDataMapper2D::New();
      }
    }
#endif

#ifdef VTK_USE_CARBON
  if (!strcmp("CarbonOpenGL",rl))
    {
    if(strcmp(vtkclassname, "vtkTextMapper") == 0)
      {
#ifdef VTK_USE_FREETYPE
      return vtkOpenGLFreeTypeTextMapper::New();
#else
      return vtkCarbonTextMapper::New();
#endif
      }
    if(strcmp(vtkclassname, "vtkImageMapper") == 0)
      {
      return vtkOpenGLImageMapper::New();
      }
    if(strcmp(vtkclassname, "vtkPolyDataMapper2D") == 0)
      {
      return vtkOpenGLPolyDataMapper2D::New();
      }
    }
#endif
#ifdef VTK_USE_COCOA
  if (!strcmp("CocoaOpenGL",rl))
    {
    if(strcmp(vtkclassname, "vtkTextMapper") == 0)
      {
#ifdef VTK_USE_FREETYPE
        return vtkOpenGLFreeTypeTextMapper::New();
#else
      return vtkCocoaTextMapper::New();
#endif
      }
    if(strcmp(vtkclassname, "vtkImageMapper") == 0)
      {
      return vtkOpenGLImageMapper::New();
      }
    if(strcmp(vtkclassname, "vtkPolyDataMapper2D") == 0)
      {
      return vtkOpenGLPolyDataMapper2D::New();
      }
    }
#endif

  return 0;
}

void vtkImagingFactory::SetUseMesaClasses(int use)
{
  vtkUseMesaClassesCriticalSection.Lock();
  vtkImagingFactory::UseMesaClasses = use;
  vtkUseMesaClassesCriticalSection.Unlock();
}

int vtkImagingFactory::GetUseMesaClasses()
{
  return vtkImagingFactory::UseMesaClasses;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017, Respective Authors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#pragma once
#include <eos/chain/global_property_object.hpp>
#include <eos/chain/transaction.hpp>

#include <random>
#include <set>

namespace eos { namespace chain {
   using pending_transaction = static_variant<std::reference_wrapper<const SignedTransaction>, std::reference_wrapper<const GeneratedTransaction>>;

   struct thread_schedule {
      vector<pending_transaction> transactions;
   };

   using cycle_schedule = vector<thread_schedule>;

   /**
    *   @class block_schedule
    *   @brief represents a proposed order of execution for a generated block
    */
   struct block_schedule
   {
      typedef block_schedule (*factory)(const vector<pending_transaction>&, const global_property_object&);
      vector<cycle_schedule> cycles;

      // Algorithms

      /**
       * A greedy scheduler that attempts to make short threads to resolve scope contention before
       * falling back on cycles
       * @return the block scheduler
       */
      static block_schedule by_threading_conflicts(const vector<pending_transaction>& transactions, const global_property_object& properties);

      /**
       * A greedy scheduler that attempts uses future cycles to resolve scope contention
       * @return the block scheduler
       */
      static block_schedule by_cycling_conflicts(const vector<pending_transaction>& transactions, const global_property_object& properties);
   };

   struct scope_extracting_visitor : public fc::visitor<std::set<AccountName>> {
      template <typename T>
      std::set<AccountName> operator()(std::reference_wrapper<const T> trx) const {
         const auto& t = trx.get();
         std::set<AccountName> unique_names(t.scope.begin(), t.scope.end());
         for (const auto& m : t.messages) {
            unique_names.insert(m.code);
         }

         return unique_names;
      }
   };

} } // eos::chain

FC_REFLECT(eos::chain::thread_schedule, (transactions))
FC_REFLECT(eos::chain::block_schedule, (cycles))
<commit_msg>address the resolution regarding code accounts irrelevance to scheduling<commit_after>/*
 * Copyright (c) 2017, Respective Authors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#pragma once
#include <eos/chain/global_property_object.hpp>
#include <eos/chain/transaction.hpp>

#include <random>
#include <set>

namespace eos { namespace chain {
   using pending_transaction = static_variant<std::reference_wrapper<const SignedTransaction>, std::reference_wrapper<const GeneratedTransaction>>;

   struct thread_schedule {
      vector<pending_transaction> transactions;
   };

   using cycle_schedule = vector<thread_schedule>;

   /**
    *   @class block_schedule
    *   @brief represents a proposed order of execution for a generated block
    */
   struct block_schedule
   {
      typedef block_schedule (*factory)(const vector<pending_transaction>&, const global_property_object&);
      vector<cycle_schedule> cycles;

      // Algorithms

      /**
       * A greedy scheduler that attempts to make short threads to resolve scope contention before
       * falling back on cycles
       * @return the block scheduler
       */
      static block_schedule by_threading_conflicts(const vector<pending_transaction>& transactions, const global_property_object& properties);

      /**
       * A greedy scheduler that attempts uses future cycles to resolve scope contention
       * @return the block scheduler
       */
      static block_schedule by_cycling_conflicts(const vector<pending_transaction>& transactions, const global_property_object& properties);
   };

   struct scope_extracting_visitor : public fc::visitor<std::set<AccountName>> {
      template <typename T>
      std::set<AccountName> operator()(std::reference_wrapper<const T> trx) const {
         const auto& t = trx.get();
         std::set<AccountName> unique_names(t.scope.begin(), t.scope.end());
         return unique_names;
      }
   };

} } // eos::chain

FC_REFLECT(eos::chain::thread_schedule, (transactions))
FC_REFLECT(eos::chain::block_schedule, (cycles))
<|endoftext|>


<commit_before>#include "interfaz.h"

void Interfaz::vBienvenida()
{
	cout << "!Bienvenido al Sistema de Matricula!";
	Sleep(2500);
	system("cls");
}

char Interfaz::vMenuPrincipal()
{
	char ans;
	cout << "**************MENU PRINCIPAL**************" << endl;
	cout << "(1)--Informacion acerca de la Universidad" << endl;
	cout << "(2)--Lista de Escuelas" << endl;
	cout << "(3)--Lista de Cursos" << endl;
	cout << "(4)--Ajustes" << endl;
	cout << "(5)--Salir" << endl;
	cout << "******************************************" << endl;

	ans = _getch();

	while (ans < '1' || ans > '5')
	{
		cout << "Opcion Incorrecta. Try again " << endl;
		ans = _getch();
	}

	system("cls");
	return ans;
}

char Interfaz::vDatosPrimeraVez(Universidad* U)
{
	if (U->getNombre() == "Undefined")
	{
		cout << "!Hola!" << endl;
		cout << "Parece que es la primera vez que ingresas al sistema." << endl;
		cout << "?Deseas ingresar ahora los datos de la Universidad?";
		return vInfoConfirmacion();
	}
	return 0;
}

char Interfaz::vMenuAjustes(Universidad* U) //Estoy seguro que puede mejorarse mil veces
{
	char ans;

	if (U->getNombre() == "Undefined")
	{
		cout << "-(1)-Ingresar nombre de la Universidad" << endl;

		if (U->getNumero() == "Undefined")
			cout << "-(2)-Ingresar Numero de Telefono de la Universidad" << endl;
		else
			cout << "-(2)-Cambiar Numero de Telefono de la Universidad" << endl;
		if (U->getDireccion() == "Undefined")
			cout << "-(3)-Ingresar Direccion de la Universidad" << endl;
		else
			cout << "-(3)-Cambiar Direccion de la Universidad" << endl;

		cout << "-(4)-Salir" << endl;

		ans = _getch();

		while (ans < '1' || ans > '4')
		{
			cout << "Opcion Incorrecta. Try again " << endl;
			ans = _getch();
		}
	}
	else
	{
		if (U->getNumero() == "Undefined")
			cout << "-(1)-Ingresar Numero de Telefono de la Universidad" << endl;
		else
			cout << "-(1)-Cambiar Numero de Telefono de la Universidad" << endl;
		if (U->getDireccion() == "Undefined")
			cout << "-(2)-Ingresar Direccion de la Universidad" << endl;
		else
			cout << "-(2)-Cambiar Direccion de la Universidad" << endl;

		cout << "-(3)-Ingresar Escuela" << endl;
		cout << "-(4)-Ingresar Curso" << endl;
		cout << "-(5)-Eliminar Curso" << endl;
		cout << "-(6)-Salir" << endl;

		ans = _getch();

		while (ans < '1' || ans > '6')
		{
			cout << "Opcion Incorrecta. Try again " << endl;
			ans = _getch();
		}
	}

	system("cls");
	return ans;
}

void Interfaz::vIngresarNumero(Universidad* U)
{
	char ans;

	do
	{
		Sleep(500);
		cout << "Ingrese el numero de telefono -> "; string numero;
		std::cin >> numero; cin.ignore();

		while (chequeaNumero(numero) == false) //No le permite al usuario ingresar un algo que no sean numeros
		{
			cout << "Numero Invalido. Intente de nuevo";
			Sleep(800);
			system("cls");
			cout << string("Ingrese el numero de telefono -> "); cin.clear();
			std::cin >> numero; cin.ignore();
		}

		cout << endl << endl;
		cout << "Numero : " << "\"" << numero << "\" "; cout << "| es esta informacion correcta?";

		ans = vInfoConfirmacion();

		if (ans == 'S')
		{
			U->setTelefono(numero);
			msjPerfecto();
		}

	} while (ans == 'N');
}

void Interfaz::vIngresarDireccion(Universidad* U)
{
	char ans;

	do
	{
		Sleep(500);
		cout << "Ingrese la direccion -> "; string direccion; getline(std::cin, direccion); cout << endl << endl;
		cout << "Direccion : " << "\"" << direccion << "\" "; cout << "| es esta informacion correcta?";

		ans = vInfoConfirmacion();

		if (ans == 'S')
		{
			U->setDireccion(direccion);
			msjPerfecto();
		}

	} while (ans == 'N');
}

void Interfaz::vIngresarNombre(Universidad* U)
{
	char ans;
	do //Pide los datos al usuario y le da la opcion de cambiarlos las veces que quiera mientras no confirme su opcion
	{
		Sleep(500);
		cout << string("Ingrese el nombre de la Universidad -> "); string nombre; std::getline(std::cin, nombre); cout << endl << endl;

		cout << "Universidad : " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? (El nombre no se puede cambiar una vez confirmado)";

		ans = vInfoConfirmacion();

		while (nombre == "Undefined" || nombre == " " || nombre == "")
		{
			cout << "Nombre Invalido. Intente de nuevo -> ";
			Sleep(800);
			system("cls");
			cout << "Ingrese el nombre de la Universidad  -> "; std::getline(std::cin, nombre); cout << endl << endl;
		}

		if (ans == 'S') //Solo ingresa al nombre si el usuario confirma
		{
			U->setNombre(nombre);
			msjPerfecto();
		}

	} while (ans == 'N');
}

char Interfaz::vInfoConfirmacion()
{
	char ans;

	cout << endl << string(" SI (S) NO (N)") << endl;

	ans = toupper(_getch());

	while (ans != 'S' && ans != 'N') //Impide ingresar un valor diferente a S o N
	{
		ans = toupper(_getch());
	}

	system("cls");

	return ans;
}

void Interfaz::vIngresaEscuela(Universidad* U)
{
	string nombre;
	cout << "Ingrese el nombre de la escuela -> "; getline(cin, nombre); cout << endl;

	cout << "Escuela de : " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? (El nombre no se puede cambiar una vez confirmado)";

	char ans = vInfoConfirmacion();

	while (nombre == "Undefined" || nombre == " " || nombre == "")
	{
		cout << "Nombre Invalido. Intente de nuevo -> ";
		Sleep(800);
		system("cls");
		cout << "Ingrese el nombre de la escuela  -> "; std::getline(std::cin, nombre); cout << endl << endl;
	}

	Escuela* escu = new Escuela(nombre);

	U->getContenedorEscuelas()->insertaralInicio(escu);
	system("cls");
}

void Interfaz::vIngresaCurso(Universidad* U)
{

	cout << "Nombre de la Universidad: " << U->getNombre() << endl << endl;
	cout << U->getContenedorEscuelas()->toString('1') << endl;

	cout << "Digite las siglas de la Escuela a la que desea ingresar el curso -> ";
	string sigla; cin >> sigla;
	string aux;

	for (int i = 0; i < sigla.length(); i++)
	{
		aux += toupper(sigla[i]);
	}

	while (U->getContenedorEscuelas()->encuentraEscuela(aux) == false)
	{
		cin.clear();
		cout << "Escuela invalida. Favor digite una de las opciones dadas." << endl;
		cout << "-> ";
		cin >> sigla; aux = "";

		for (int i = 0; i < sigla.length(); i++)
		{
			aux += toupper(sigla[i]);
		}

	}

	system("cls");
	cin.ignore();
	string nombre;
	cout << "Ingrese el nombre del curso -> "; getline(cin, nombre); cout << endl;

	cout << "Curso: " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? ";

	char ans = vInfoConfirmacion();

	while (nombre == "Undefined" || nombre == " " || nombre == "")
	{
		cout << "Nombre Invalido. Intente de nuevo -> ";
		Sleep(800);
		system("cls");
		cout << "Ingrese el nombre del curso  -> "; std::getline(std::cin, nombre); cout << endl << endl;
	}

	Curso* cur = new Curso(nombre, U->getContenedorEscuelas()->retornaEscuelaEspecifica(aux)->getSiglaEscuela());

	U->getContenedorEscuelas()->retornaEscuelaEspecifica(aux)->insertarCurso(cur);

	msjPerfecto();

	system("cls");
}

void Interfaz::vEliminaCurso(Universidad *U) //debe implementarse mejor
{
	cout << U->getContenedorEscuelas()->toString('2') << endl;

	cout << "Ingrese el codigo del curso que desea eliminar -> "; string codigo, sigla, aux;

	cin >> aux;

	for (int i = 0; i < codigo.length(); i++)
	{
		codigo += toupper(aux[i]);
	}

	sigla = codigo.substr(0, 3);

	if (U->getContenedorEscuelas()->retornaEscuelaEspecifica(sigla)->retornaContenedorCursos()->eliminaCursoEspecifico(codigo))
		cout << "Curso eliminado con exito" << endl;
	else
		cout << "No se ha podido eliminar el curso." << endl;
}

bool Interfaz::chequeaNumero(string num)
{
	bool esNumero;

	for (size_t x = 0; x < num.length(); x++)
	{
		if (isdigit(num[x]))
			esNumero = true;
		else
		{
			esNumero = false;
			return esNumero;
		}
	}
	return esNumero;
}

void Interfaz::msjPerfecto()
{
	cout << endl << string("Perfecto!");
	Sleep(1500);
	system("cls");
}

void Interfaz::msjPausa()
{
	cout << "Presione cualquier tecla para continuar..." << endl;
	_getch();
}

void Interfaz::vtoString(Universidad* U) //Modificar para que sirva de informacion actual del sistema de matricula
{
	if (U->getNombre() == "Undefined" && U->getNumero() == "Undefined")
		cout << "Ups... parece que no se han ingresado todos los datos de la Universidad. Ve a Ajustes para agregarlos." << endl;
	else
		cout << U->toString() << endl;

	msjPausa();
	system("cls");
}

void Interfaz::vtoStringEscuelas(Universidad* U, char op)
{
	if (U->getNombre() == "Undefined")
		cout << "No se ha ingresado el nombre de la Universidad. Vaya a Ajustes." << endl;
	else
	{
		cout << "Nombre de la Universidad: " << U->getNombre() << endl << endl;
		cout << U->getContenedorEscuelas()->toString(op) << endl;
	}
	msjPausa();
	system("cls");
}

<commit_msg>Arregle una caballada ahi<commit_after>#include "interfaz.h"

void Interfaz::vBienvenida()
{
	cout << "!Bienvenido al Sistema de Matricula!";
	Sleep(2500);
	system("cls");
}

char Interfaz::vMenuPrincipal()
{
	char ans;
	cout << "**************MENU PRINCIPAL**************" << endl;
	cout << "(1)--Informacion acerca de la Universidad" << endl;
	cout << "(2)--Lista de Escuelas" << endl;
	cout << "(3)--Lista de Cursos" << endl;
	cout << "(4)--Ajustes" << endl;
	cout << "(5)--Salir" << endl;
	cout << "******************************************" << endl;

	ans = _getch();

	while (ans < '1' || ans > '5')
	{
		cout << "Opcion Incorrecta. Try again " << endl;
		ans = _getch();
	}

	system("cls");
	return ans;
}

char Interfaz::vDatosPrimeraVez(Universidad* U)
{
	if (U->getNombre() == "Undefined")
	{
		cout << "!Hola!" << endl;
		cout << "Parece que es la primera vez que ingresas al sistema." << endl;
		cout << "?Deseas ingresar ahora los datos de la Universidad?";
		return vInfoConfirmacion();
	}
	return 0;
}

char Interfaz::vMenuAjustes(Universidad* U) //Estoy seguro que puede mejorarse mil veces
{
	char ans;

	if (U->getNombre() == "Undefined")
	{
		cout << "-(1)-Ingresar nombre de la Universidad" << endl;

		if (U->getNumero() == "Undefined")
			cout << "-(2)-Ingresar Numero de Telefono de la Universidad" << endl;
		else
			cout << "-(2)-Cambiar Numero de Telefono de la Universidad" << endl;
		if (U->getDireccion() == "Undefined")
			cout << "-(3)-Ingresar Direccion de la Universidad" << endl;
		else
			cout << "-(3)-Cambiar Direccion de la Universidad" << endl;

		cout << "-(4)-Salir" << endl;

		ans = _getch();

		while (ans < '1' || ans > '4')
		{
			cout << "Opcion Incorrecta. Try again " << endl;
			ans = _getch();
		}
	}
	else
	{
		if (U->getNumero() == "Undefined")
			cout << "-(1)-Ingresar Numero de Telefono de la Universidad" << endl;
		else
			cout << "-(1)-Cambiar Numero de Telefono de la Universidad" << endl;
		if (U->getDireccion() == "Undefined")
			cout << "-(2)-Ingresar Direccion de la Universidad" << endl;
		else
			cout << "-(2)-Cambiar Direccion de la Universidad" << endl;

		cout << "-(3)-Ingresar Escuela" << endl;
		cout << "-(4)-Ingresar Curso" << endl;
		cout << "-(5)-Eliminar Curso" << endl;
		cout << "-(6)-Salir" << endl;

		ans = _getch();

		while (ans < '1' || ans > '6')
		{
			cout << "Opcion Incorrecta. Try again " << endl;
			ans = _getch();
		}
	}

	system("cls");
	return ans;
}

void Interfaz::vIngresarNumero(Universidad* U)
{
	char ans;

	do
	{
		Sleep(500);
		cout << "Ingrese el numero de telefono -> "; string numero;
		std::cin >> numero; cin.ignore();

		while (chequeaNumero(numero) == false) //No le permite al usuario ingresar un algo que no sean numeros
		{
			cout << "Numero Invalido. Intente de nuevo";
			Sleep(800);
			system("cls");
			cout << string("Ingrese el numero de telefono -> "); cin.clear();
			std::cin >> numero; cin.ignore();
		}

		cout << endl << endl;
		cout << "Numero : " << "\"" << numero << "\" "; cout << "| es esta informacion correcta?";

		ans = vInfoConfirmacion();

		if (ans == 'S')
		{
			U->setTelefono(numero);
			msjPerfecto();
		}

	} while (ans == 'N');
}

void Interfaz::vIngresarDireccion(Universidad* U)
{
	char ans;

	do
	{
		Sleep(500);
		cout << "Ingrese la direccion -> "; string direccion; getline(std::cin, direccion); cout << endl << endl;
		cout << "Direccion : " << "\"" << direccion << "\" "; cout << "| es esta informacion correcta?";

		ans = vInfoConfirmacion();

		if (ans == 'S')
		{
			U->setDireccion(direccion);
			msjPerfecto();
		}

	} while (ans == 'N');
}

void Interfaz::vIngresarNombre(Universidad* U)
{
	char ans;
	do //Pide los datos al usuario y le da la opcion de cambiarlos las veces que quiera mientras no confirme su opcion
	{
		Sleep(500);
		cout << string("Ingrese el nombre de la Universidad -> "); string nombre; std::getline(std::cin, nombre); cout << endl << endl;

		cout << "Universidad : " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? (El nombre no se puede cambiar una vez confirmado)";

		ans = vInfoConfirmacion();

		while (nombre == "Undefined" || nombre == " " || nombre == "")
		{
			cout << "Nombre Invalido. Intente de nuevo -> ";
			Sleep(800);
			system("cls");
			cout << "Ingrese el nombre de la Universidad  -> "; std::getline(std::cin, nombre); cout << endl << endl;
		}

		if (ans == 'S') //Solo ingresa al nombre si el usuario confirma
		{
			U->setNombre(nombre);
			msjPerfecto();
		}

	} while (ans == 'N');
}

char Interfaz::vInfoConfirmacion()
{
	char ans;

	cout << endl << string(" SI (S) NO (N)") << endl;

	ans = toupper(_getch());

	while (ans != 'S' && ans != 'N') //Impide ingresar un valor diferente a S o N
	{
		ans = toupper(_getch());
	}

	system("cls");

	return ans;
}

void Interfaz::vIngresaEscuela(Universidad* U)
{
	string nombre;
	cout << "Ingrese el nombre de la escuela -> "; getline(cin, nombre); cout << endl;

	cout << "Escuela de : " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? (El nombre no se puede cambiar una vez confirmado)";

	char ans = vInfoConfirmacion();

	while (nombre == "Undefined" || nombre == " " || nombre == "")
	{
		cout << "Nombre Invalido. Intente de nuevo -> ";
		Sleep(800);
		system("cls");
		cout << "Ingrese el nombre de la escuela  -> "; std::getline(std::cin, nombre); cout << endl << endl;
	}

	Escuela* escu = new Escuela(nombre);

	U->getContenedorEscuelas()->insertaralInicio(escu);
	system("cls");
}

void Interfaz::vIngresaCurso(Universidad* U)
{

	cout << "Nombre de la Universidad: " << U->getNombre() << endl << endl;
	cout << U->getContenedorEscuelas()->toString('1') << endl;

	cout << "Digite las siglas de la Escuela a la que desea ingresar el curso -> ";
	string sigla; cin >> sigla;
	string aux;

	for (int i = 0; i < sigla.length(); i++)
	{
		aux += toupper(sigla[i]);
	}

	while (U->getContenedorEscuelas()->encuentraEscuela(aux) == false)
	{
		cin.clear();
		cout << "Escuela invalida. Favor digite una de las opciones dadas." << endl;
		cout << "-> ";
		cin >> sigla; aux = "";

		for (int i = 0; i < sigla.length(); i++)
		{
			aux += toupper(sigla[i]);
		}

	}

	system("cls");
	cin.ignore();
	string nombre;
	cout << "Ingrese el nombre del curso -> "; getline(cin, nombre); cout << endl;

	cout << "Curso: " << "\"" << nombre << "\" "; cout << "| es esta informacion correcta? ";

	char ans = vInfoConfirmacion();

	while (nombre == "Undefined" || nombre == " " || nombre == "")
	{
		cout << "Nombre Invalido. Intente de nuevo -> ";
		Sleep(800);
		system("cls");
		cout << "Ingrese el nombre del curso  -> "; std::getline(std::cin, nombre); cout << endl << endl;
	}

	Curso* cur = new Curso(nombre, U->getContenedorEscuelas()->retornaEscuelaEspecifica(aux)->getSiglaEscuela());

	U->getContenedorEscuelas()->retornaEscuelaEspecifica(aux)->insertarCurso(cur);

	msjPerfecto();

	system("cls");
}

void Interfaz::vEliminaCurso(Universidad *U) //debe implementarse mejor
{
	cout << U->getContenedorEscuelas()->toString('2') << endl;

	cout << "Ingrese el codigo del curso que desea eliminar -> "; string codigo, sigla, aux;

	cin >> aux;

	for (int i = 0; i < aux.length(); i++)
	{
		codigo += toupper(aux[i]);
	}

	sigla = codigo.substr(0, 3);

	if (U->getContenedorEscuelas()->retornaEscuelaEspecifica(sigla)->retornaContenedorCursos()->eliminaCursoEspecifico(codigo))
		cout << "Curso eliminado con exito" << endl;
	else
		cout << "No se ha podido eliminar el curso." << endl;
}

bool Interfaz::chequeaNumero(string num)
{
	bool esNumero;

	for (size_t x = 0; x < num.length(); x++)
	{
		if (isdigit(num[x]))
			esNumero = true;
		else
		{
			esNumero = false;
			return esNumero;
		}
	}
	return esNumero;
}

void Interfaz::msjPerfecto()
{
	cout << endl << string("Perfecto!");
	Sleep(1500);
	system("cls");
}

void Interfaz::msjPausa()
{
	cout << "Presione cualquier tecla para continuar..." << endl;
	_getch();
}

void Interfaz::vtoString(Universidad* U) //Modificar para que sirva de informacion actual del sistema de matricula
{
	if (U->getNombre() == "Undefined" && U->getNumero() == "Undefined")
		cout << "Ups... parece que no se han ingresado todos los datos de la Universidad. Ve a Ajustes para agregarlos." << endl;
	else
		cout << U->toString() << endl;

	msjPausa();
	system("cls");
}

void Interfaz::vtoStringEscuelas(Universidad* U, char op)
{
	if (U->getNombre() == "Undefined")
		cout << "No se ha ingresado el nombre de la Universidad. Vaya a Ajustes." << endl;
	else
	{
		cout << "Nombre de la Universidad: " << U->getNombre() << endl << endl;
		cout << U->getContenedorEscuelas()->toString(op) << endl;
	}
	msjPausa();
	system("cls");
}

<|endoftext|>


<commit_before>//
// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include <string.h>
#include <cassert>
#include <vector>

#include "EGLWindow.h"
#include "OSWindow.h"

#ifdef _WIN32
#elif __linux__
#else
#error unsupported OS.
#endif

EGLPlatformParameters::EGLPlatformParameters()
    : renderer(EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE),
      majorVersion(EGL_DONT_CARE),
      minorVersion(EGL_DONT_CARE),
      deviceType(EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE)
{
}

EGLPlatformParameters::EGLPlatformParameters(EGLint renderer)
    : renderer(renderer),
      majorVersion(EGL_DONT_CARE),
      minorVersion(EGL_DONT_CARE),
      deviceType(EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE)
{
}

EGLPlatformParameters::EGLPlatformParameters(EGLint renderer, EGLint majorVersion, EGLint minorVersion, EGLint useWarp)
    : renderer(renderer),
      majorVersion(majorVersion),
      minorVersion(minorVersion),
      deviceType(useWarp)
{
}

EGLWindow::EGLWindow(size_t width, size_t height, EGLint glesMajorVersion, const EGLPlatformParameters &platform)
    : mSurface(EGL_NO_SURFACE),
      mContext(EGL_NO_CONTEXT),
      mDisplay(EGL_NO_DISPLAY),
      mClientVersion(glesMajorVersion),
      mPlatform(platform),
      mWidth(width),
      mHeight(height),
      mRedBits(-1),
      mGreenBits(-1),
      mBlueBits(-1),
      mAlphaBits(-1),
      mDepthBits(-1),
      mStencilBits(-1),
      mMultisample(false),
      mSwapInterval(-1)
{
}

EGLWindow::~EGLWindow()
{
    destroyGL();
}

void EGLWindow::swap()
{
    eglSwapBuffers(mDisplay, mSurface);
}

EGLConfig EGLWindow::getConfig() const
{
    return mConfig;
}

EGLDisplay EGLWindow::getDisplay() const
{
    return mDisplay;
}

EGLSurface EGLWindow::getSurface() const
{
    return mSurface;
}

EGLContext EGLWindow::getContext() const
{
    return mContext;
}

bool EGLWindow::initializeGL(OSWindow *osWindow)
{
    PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
    if (!eglGetPlatformDisplayEXT)
    {
        return false;
    }

    const EGLint displayAttributes[] =
    {
        EGL_PLATFORM_ANGLE_TYPE_ANGLE,              mPlatform.renderer,
        EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, mPlatform.majorVersion,
        EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, mPlatform.minorVersion,
        EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,       mPlatform.deviceType,
        EGL_NONE,
    };

    mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, osWindow->getNativeDisplay(), displayAttributes);
    if (mDisplay == EGL_NO_DISPLAY)
    {
        destroyGL();
        return false;
    }

    EGLint majorVersion, minorVersion;
    if (!eglInitialize(mDisplay, &majorVersion, &minorVersion))
    {
        destroyGL();
        return false;
    }

    eglBindAPI(EGL_OPENGL_ES_API);
    if (eglGetError() != EGL_SUCCESS)
    {
        destroyGL();
        return false;
    }

    const EGLint configAttributes[] =
    {
        EGL_RED_SIZE,       (mRedBits >= 0)     ? mRedBits     : EGL_DONT_CARE,
        EGL_GREEN_SIZE,     (mGreenBits >= 0)   ? mGreenBits   : EGL_DONT_CARE,
        EGL_BLUE_SIZE,      (mBlueBits >= 0)    ? mBlueBits    : EGL_DONT_CARE,
        EGL_ALPHA_SIZE,     (mAlphaBits >= 0)   ? mAlphaBits   : EGL_DONT_CARE,
        EGL_DEPTH_SIZE,     (mDepthBits >= 0)   ? mDepthBits   : EGL_DONT_CARE,
        EGL_STENCIL_SIZE,   (mStencilBits >= 0) ? mStencilBits : EGL_DONT_CARE,
        EGL_SAMPLE_BUFFERS, mMultisample ? 1 : 0,
        EGL_NONE
    };

    EGLint configCount;
    if (!eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount) || (configCount != 1))
    {
        destroyGL();
        return false;
    }

    eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &mRedBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &mGreenBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &mBlueBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &mBlueBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_DEPTH_SIZE, &mDepthBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_STENCIL_SIZE, &mStencilBits);

    std::vector<EGLint> surfaceAttributes;
    if (strstr(eglQueryString(mDisplay, EGL_EXTENSIONS), "EGL_NV_post_sub_buffer") != nullptr)
    {
        surfaceAttributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
        surfaceAttributes.push_back(EGL_TRUE);
    }

    surfaceAttributes.push_back(EGL_NONE);
    surfaceAttributes.push_back(EGL_NONE);

    mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(), &surfaceAttributes[0]);
    if (mSurface == EGL_NO_SURFACE)
    {
        eglGetError(); // Clear error and try again
        mSurface = eglCreateWindowSurface(mDisplay, mConfig, NULL, NULL);
    }

    if (eglGetError() != EGL_SUCCESS)
    {
        destroyGL();
        return false;
    }

    EGLint contextAttibutes[] =
    {
        EGL_CONTEXT_CLIENT_VERSION, mClientVersion,
        EGL_NONE
    };

    mContext = eglCreateContext(mDisplay, mConfig, NULL, contextAttibutes);
    if (eglGetError() != EGL_SUCCESS)
    {
        destroyGL();
        return false;
    }

    eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
    if (eglGetError() != EGL_SUCCESS)
    {
        destroyGL();
        return false;
    }

    if (mSwapInterval != -1)
    {
        eglSwapInterval(mDisplay, mSwapInterval);
    }

    return true;
}

void EGLWindow::destroyGL()
{
    if (mSurface != EGL_NO_SURFACE)
    {
        assert(mDisplay != EGL_NO_DISPLAY);
        eglDestroySurface(mDisplay, mSurface);
        mSurface = EGL_NO_SURFACE;
    }

    if (mContext != EGL_NO_CONTEXT)
    {
        assert(mDisplay != EGL_NO_DISPLAY);
        eglDestroyContext(mDisplay, mContext);
        mContext = EGL_NO_CONTEXT;
    }

    if (mDisplay != EGL_NO_DISPLAY)
    {
        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        eglTerminate(mDisplay);
        mDisplay = EGL_NO_DISPLAY;
    }
}

bool EGLWindow::isGLInitialized() const
{
    return mSurface != EGL_NO_SURFACE &&
           mContext != EGL_NO_CONTEXT &&
           mDisplay != EGL_NO_DISPLAY;
}
<commit_msg>EGLWindow: specify the device type only on d3d platform<commit_after>//
// Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include <string.h>
#include <cassert>
#include <vector>

#include "EGLWindow.h"
#include "OSWindow.h"

#ifdef _WIN32
#elif __linux__
#else
#error unsupported OS.
#endif

EGLPlatformParameters::EGLPlatformParameters()
    : renderer(EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE),
      majorVersion(EGL_DONT_CARE),
      minorVersion(EGL_DONT_CARE),
      deviceType(EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE)
{
}

EGLPlatformParameters::EGLPlatformParameters(EGLint renderer)
    : renderer(renderer),
      majorVersion(EGL_DONT_CARE),
      minorVersion(EGL_DONT_CARE),
      deviceType(EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE)
{
}

EGLPlatformParameters::EGLPlatformParameters(EGLint renderer, EGLint majorVersion, EGLint minorVersion, EGLint useWarp)
    : renderer(renderer),
      majorVersion(majorVersion),
      minorVersion(minorVersion),
      deviceType(useWarp)
{
}

EGLWindow::EGLWindow(size_t width, size_t height, EGLint glesMajorVersion, const EGLPlatformParameters &platform)
    : mSurface(EGL_NO_SURFACE),
      mContext(EGL_NO_CONTEXT),
      mDisplay(EGL_NO_DISPLAY),
      mClientVersion(glesMajorVersion),
      mPlatform(platform),
      mWidth(width),
      mHeight(height),
      mRedBits(-1),
      mGreenBits(-1),
      mBlueBits(-1),
      mAlphaBits(-1),
      mDepthBits(-1),
      mStencilBits(-1),
      mMultisample(false),
      mSwapInterval(-1)
{
}

EGLWindow::~EGLWindow()
{
    destroyGL();
}

void EGLWindow::swap()
{
    eglSwapBuffers(mDisplay, mSurface);
}

EGLConfig EGLWindow::getConfig() const
{
    return mConfig;
}

EGLDisplay EGLWindow::getDisplay() const
{
    return mDisplay;
}

EGLSurface EGLWindow::getSurface() const
{
    return mSurface;
}

EGLContext EGLWindow::getContext() const
{
    return mContext;
}

bool EGLWindow::initializeGL(OSWindow *osWindow)
{
    PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
    if (!eglGetPlatformDisplayEXT)
    {
        return false;
    }

    std::vector<EGLint> displayAttributes;
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
    displayAttributes.push_back(mPlatform.renderer);
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
    displayAttributes.push_back(mPlatform.majorVersion);
    displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
    displayAttributes.push_back(mPlatform.minorVersion);

    if (mPlatform.renderer == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE || mPlatform.renderer == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
    {
        displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
        displayAttributes.push_back(mPlatform.deviceType);
    }
    displayAttributes.push_back(EGL_NONE);

    mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, osWindow->getNativeDisplay(), displayAttributes.data());
    if (mDisplay == EGL_NO_DISPLAY)
    {
        destroyGL();
        return false;
    }

    EGLint majorVersion, minorVersion;
    if (!eglInitialize(mDisplay, &majorVersion, &minorVersion))
    {
        destroyGL();
        return false;
    }

    eglBindAPI(EGL_OPENGL_ES_API);
    if (eglGetError() != EGL_SUCCESS)
    {
        destroyGL();
        return false;
    }

    const EGLint configAttributes[] =
    {
        EGL_RED_SIZE,       (mRedBits >= 0)     ? mRedBits     : EGL_DONT_CARE,
        EGL_GREEN_SIZE,     (mGreenBits >= 0)   ? mGreenBits   : EGL_DONT_CARE,
        EGL_BLUE_SIZE,      (mBlueBits >= 0)    ? mBlueBits    : EGL_DONT_CARE,
        EGL_ALPHA_SIZE,     (mAlphaBits >= 0)   ? mAlphaBits   : EGL_DONT_CARE,
        EGL_DEPTH_SIZE,     (mDepthBits >= 0)   ? mDepthBits   : EGL_DONT_CARE,
        EGL_STENCIL_SIZE,   (mStencilBits >= 0) ? mStencilBits : EGL_DONT_CARE,
        EGL_SAMPLE_BUFFERS, mMultisample ? 1 : 0,
        EGL_NONE
    };

    EGLint configCount;
    if (!eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount) || (configCount != 1))
    {
        destroyGL();
        return false;
    }

    eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &mRedBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &mGreenBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &mBlueBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &mBlueBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_DEPTH_SIZE, &mDepthBits);
    eglGetConfigAttrib(mDisplay, mConfig, EGL_STENCIL_SIZE, &mStencilBits);

    std::vector<EGLint> surfaceAttributes;
    if (strstr(eglQueryString(mDisplay, EGL_EXTENSIONS), "EGL_NV_post_sub_buffer") != nullptr)
    {
        surfaceAttributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
        surfaceAttributes.push_back(EGL_TRUE);
    }

    surfaceAttributes.push_back(EGL_NONE);
    surfaceAttributes.push_back(EGL_NONE);

    mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(), &surfaceAttributes[0]);
    if (mSurface == EGL_NO_SURFACE)
    {
        eglGetError(); // Clear error and try again
        mSurface = eglCreateWindowSurface(mDisplay, mConfig, NULL, NULL);
    }

    if (eglGetError() != EGL_SUCCESS)
    {
        destroyGL();
        return false;
    }

    EGLint contextAttibutes[] =
    {
        EGL_CONTEXT_CLIENT_VERSION, mClientVersion,
        EGL_NONE
    };

    mContext = eglCreateContext(mDisplay, mConfig, NULL, contextAttibutes);
    if (eglGetError() != EGL_SUCCESS)
    {
        destroyGL();
        return false;
    }

    eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
    if (eglGetError() != EGL_SUCCESS)
    {
        destroyGL();
        return false;
    }

    if (mSwapInterval != -1)
    {
        eglSwapInterval(mDisplay, mSwapInterval);
    }

    return true;
}

void EGLWindow::destroyGL()
{
    if (mSurface != EGL_NO_SURFACE)
    {
        assert(mDisplay != EGL_NO_DISPLAY);
        eglDestroySurface(mDisplay, mSurface);
        mSurface = EGL_NO_SURFACE;
    }

    if (mContext != EGL_NO_CONTEXT)
    {
        assert(mDisplay != EGL_NO_DISPLAY);
        eglDestroyContext(mDisplay, mContext);
        mContext = EGL_NO_CONTEXT;
    }

    if (mDisplay != EGL_NO_DISPLAY)
    {
        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        eglTerminate(mDisplay);
        mDisplay = EGL_NO_DISPLAY;
    }
}

bool EGLWindow::isGLInitialized() const
{
    return mSurface != EGL_NO_SURFACE &&
           mContext != EGL_NO_CONTEXT &&
           mDisplay != EGL_NO_DISPLAY;
}
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2015 ETH Zurich Systems Group (http://www.systems.ethz.ch/) and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 *     Markus Pilman <mpilman@inf.ethz.ch>
 *     Simon Loesing <sloesing@inf.ethz.ch>
 *     Thomas Etter <etterth@gmail.com>
 *     Kevin Bocksrocker <kevin.bocksrocker@gmail.com>
 *     Lucas Braun <braunl@inf.ethz.ch>
 */

#pragma once

#include <tellstore/Record.hpp>

#include <commitmanager/SnapshotDescriptor.hpp>

#include <crossbow/byte_buffer.hpp>
#include <crossbow/enum_underlying.hpp>
#include <crossbow/logger.hpp>
#include <crossbow/non_copyable.hpp>

#include <cstddef>
#include <cstdint>
#include <memory>
#include <system_error>
#include <tuple>
#include <vector>

namespace tell {
namespace store {

class ScanQueryProcessor;

/**
 * @brief Iterator for iterating over the query data when the query type is a projection
 */
class ProjectionIterator {
public:
    ProjectionIterator()
            : mPos(nullptr) {
    }

    ProjectionIterator(const char* pos)
            : mPos(pos) {
    }

    ProjectionIterator& operator++() {
        mPos += ENTRY_SIZE;
        return *this;
    }

    ProjectionIterator operator++(int) {
        ProjectionIterator result(*this);
        operator++();
        return result;
    }

    bool operator==(const ProjectionIterator& rhs) const {
        return (mPos == rhs.mPos);
    }

    bool operator!=(const ProjectionIterator& rhs) const {
        return !operator==(rhs);
    }

    Record::id_t operator*() const {
        return *reinterpret_cast<const Record::id_t*>(mPos);
    }

private:
    static constexpr size_t ENTRY_SIZE = 2u;

    const char* mPos;
};

/**
 * @brief @brief Iterator for iterating over the query data when the query type is a aggregation
 */
class AggregationIterator {
public:
    AggregationIterator()
            : mPos(nullptr) {
    }

    AggregationIterator(const char* pos)
            : mPos(pos) {
    }

    AggregationIterator& operator++() {
        mPos += ENTRY_SIZE;
        return *this;
    }

    AggregationIterator operator++(int) {
        AggregationIterator result(*this);
        operator++();
        return result;
    }

    bool operator==(const AggregationIterator& rhs) const {
        return (mPos == rhs.mPos);
    }

    bool operator!=(const AggregationIterator& rhs) const {
        return !operator==(rhs);
    }

    std::tuple<Record::id_t, AggregationType> operator*() const {
        return std::make_tuple(*reinterpret_cast<const Record::id_t*>(mPos),
                *reinterpret_cast<const AggregationType*>(mPos + AGGREGATION_TYPE_OFFSET));
    }

private:
    static constexpr size_t ENTRY_SIZE = 4u;

    static constexpr size_t AGGREGATION_TYPE_OFFSET = 2u;

    const char* mPos;
};

/**
 * @brief Information about a scan query
 *
 * A query has the following form
 * - 4 bytes for the number of columns it has to check
 * - 4 bytes for the number of conjuncts in the query
 * - 4 bytes for the number of total scan partitions (or 0 if no partitioning)
 * - 4 bytes for the number of the scan partition (if partitioning)
 * - For each column:
 *   - 2 bytes: The column id (called field id in the Record class)
 *   - 2 bytes: The number of predicates it has on the column
 *   - 4 bytes: Padding
 *   - For each predicate:
 *     - 1 byte: The type of the predicate
 *     - 1 byte: Position in the AND-list of queries
 *     - 2 bytes: The data if its size is between 1 and 2 bytes long padding otherwise
 *     - 4 bytes: The data if its size is between 2 and 4 bytes long padding otherwise
 *     - The data if it is larger than 4 bytes or if it is variable size length (padded to 8 bytes)
 */
class ScanQuery {
public:
    ScanQuery(ScanQueryType queryType, std::unique_ptr<char[]> selectionData, size_t selectionLength,
            std::unique_ptr<char[]> queryData, size_t queryLength,
            std::unique_ptr<commitmanager::SnapshotDescriptor> snapshot, const Record& record);

    virtual ~ScanQuery();

    ScanQueryType queryType() const {
        return mQueryType;
    }

    const char* selection() const {
        return mSelectionData.get();
    }

    size_t selectionLength() const {
        return mSelectionLength;
    }

    ProjectionIterator projectionBegin() const {
        LOG_ASSERT(mQueryType == ScanQueryType::PROJECTION, "Query type not projection");
        return ProjectionIterator(mQueryData.get());
    }

    ProjectionIterator projectionEnd() const {
        LOG_ASSERT(mQueryType == ScanQueryType::PROJECTION, "Query type not projection");
        return ProjectionIterator(mQueryDataEnd);
    }

    AggregationIterator aggregationBegin() const {
        LOG_ASSERT(mQueryType == ScanQueryType::AGGREGATION, "Query type not aggregation");
        return AggregationIterator(mQueryData.get());
    }

    AggregationIterator aggregationEnd() const {
        LOG_ASSERT(mQueryType == ScanQueryType::AGGREGATION, "Query type not aggregation");
        return AggregationIterator(mQueryDataEnd);
    }

    const commitmanager::SnapshotDescriptor* snapshot() const {
        return mSnapshot.get();
    }

    const Record& record() const {
        return mRecord;
    }

    uint32_t minimumLength() const {
        return mMinimumLength;
    }

    /**
     * @brief Acquires a new buffer
     */
    virtual std::tuple<char*, uint32_t> acquireBuffer() = 0;

    /**
     * @brief Flushes the tuples in the buffer to the client
     *
     * @param start Begin pointer to the buffer containing the tuples
     * @param end End pointer to the buffer containing the tuples
     * @param ec Error in case the write fails
     */
    virtual void writeOngoing(const char* start, const char* end, std::error_code& ec) = 0;

    /**
     * @brief Writes the last tuples to the client
     *
     * The invoking scan processor can be marked as done.
     *
     * @param start Begin pointer to the buffer containing the tuples
     * @param end End pointer to the buffer containing the tuples
     * @param ec Error in case the write fails
     */
    virtual void writeLast(const char* start, const char* end, std::error_code& ec) = 0;

    /**
     * @brief Writes the last tuples to the client
     *
     * The invoking scan processor can be marked as done.
     *
     * @param ec Error in case the write fails
     */
    virtual void writeLast(std::error_code& ec) = 0;

    /**
     * @brief Create a new ScanQueryProcessor associated with this scan
     */
    virtual ScanQueryProcessor createProcessor() = 0;

private:
    /// The type of the scan query
    ScanQueryType mQueryType;

    /// The selection query
    std::unique_ptr<char[]> mSelectionData;

    /// Length of the selection query string
    size_t mSelectionLength;

    /// The query data
    /// This is null when the query type is a full scan, the projection query in case the query type is a projection or
    /// an aggregation query in case the query type is an aggregation.
    std::unique_ptr<char[]> mQueryData;

    /// Pointer to the end of the query data
    const char* mQueryDataEnd;

    /// Snapshot to check the validity of tuples against
    std::unique_ptr<commitmanager::SnapshotDescriptor> mSnapshot;

    /// Record containing the target schema
    Record mRecord;

    /// Minimum size a tuple requires (i.e. minimum static size)
    uint32_t mMinimumLength;
};

/**
 * @brief Processor building the tuples according to the data specified in the scan query
 *
 * Checks the validity of the tuple against a SnapshotDescriptor and writes all valid tuples into a buffer. Performs
 * projection or aggregation depending on the query type.
 */
class ScanQueryProcessor : crossbow::non_copyable {
public:
    static constexpr size_t TUPLE_OVERHEAD = sizeof(uint64_t);

    ScanQueryProcessor(ScanQuery* data)
            : mData(data),
              mBuffer(nullptr),
              mBufferWriter(static_cast<char*>(nullptr), 0),
              mTupleCount(0u) {
    }

    ~ScanQueryProcessor();

    ScanQueryProcessor(ScanQueryProcessor&& other);

    ScanQueryProcessor& operator=(ScanQueryProcessor&& other);

    const ScanQuery* data() const {
        return mData;
    }

    /**
     * @brief Process the tuple according to the query data associated with this processor
     *
     * @param record Record of the tuple
     * @param key Key of the tuple
     * @param length Length of the tuple
     * @param validFrom Valid-From version of the tuple
     * @param validTo Valid-To version of the tuple
     * @param fun Function to serialize the record
     */
    template <typename Fun>
    void writeRecord(uint64_t key, uint32_t length, uint64_t validFrom, uint64_t validTo, Fun fun);

    /**
     * @brief Initializes the aggregation tuple
     *
     * Reserves space for the aggregations in the buffer and initializes them to zero.
     */
    void initAggregationRecord();

//private:
    /**
     * @brief Ensures that the buffer can hold at least the number of bytes
     *
     * The buffer is written and a new buffer will beacquired in case there is no space left in the current buffer.
     *
     * @param Minimum size of the tuple to be written
     */
    void ensureBufferSpace(uint32_t length);

    /// Shared data holding information about the scan
    ScanQuery* mData;

    /// Start pointer of the current buffer
    char* mBuffer;

    /// Writer used to write the tuples into the buffer
    crossbow::buffer_writer mBufferWriter;

    /// Number of tuples written to the buffer
    uint16_t mTupleCount;
};

template <typename Fun>
void ScanQueryProcessor::writeRecord(uint64_t key, uint32_t length, uint64_t validFrom, uint64_t validTo, Fun fun) {
    auto snapshot = mData->snapshot();
    if (snapshot && !snapshot->inReadSet(validFrom, validTo)) {
        return;
    }

    if (mData->queryType() == ScanQueryType::AGGREGATION) {
        fun(mBuffer + 8);
    } else {
        ensureBufferSpace(length + TUPLE_OVERHEAD);

        // Write key
        mBufferWriter.write<uint64_t>(key);

        // Write complete tuple
        auto bytesWritten = fun(mBufferWriter.data());
        LOG_ASSERT(bytesWritten <= length, "Bytes written must be smaller than the length");

        mBufferWriter.advance(crossbow::align(bytesWritten, 8u));

        ++mTupleCount;
    }
}

} //namespace store
} //namespace tell
<commit_msg>Update documentation regarding partition shift<commit_after>/*
 * (C) Copyright 2015 ETH Zurich Systems Group (http://www.systems.ethz.ch/) and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 *     Markus Pilman <mpilman@inf.ethz.ch>
 *     Simon Loesing <sloesing@inf.ethz.ch>
 *     Thomas Etter <etterth@gmail.com>
 *     Kevin Bocksrocker <kevin.bocksrocker@gmail.com>
 *     Lucas Braun <braunl@inf.ethz.ch>
 */

#pragma once

#include <tellstore/Record.hpp>

#include <commitmanager/SnapshotDescriptor.hpp>

#include <crossbow/byte_buffer.hpp>
#include <crossbow/enum_underlying.hpp>
#include <crossbow/logger.hpp>
#include <crossbow/non_copyable.hpp>

#include <cstddef>
#include <cstdint>
#include <memory>
#include <system_error>
#include <tuple>
#include <vector>

namespace tell {
namespace store {

class ScanQueryProcessor;

/**
 * @brief Iterator for iterating over the query data when the query type is a projection
 */
class ProjectionIterator {
public:
    ProjectionIterator()
            : mPos(nullptr) {
    }

    ProjectionIterator(const char* pos)
            : mPos(pos) {
    }

    ProjectionIterator& operator++() {
        mPos += ENTRY_SIZE;
        return *this;
    }

    ProjectionIterator operator++(int) {
        ProjectionIterator result(*this);
        operator++();
        return result;
    }

    bool operator==(const ProjectionIterator& rhs) const {
        return (mPos == rhs.mPos);
    }

    bool operator!=(const ProjectionIterator& rhs) const {
        return !operator==(rhs);
    }

    Record::id_t operator*() const {
        return *reinterpret_cast<const Record::id_t*>(mPos);
    }

private:
    static constexpr size_t ENTRY_SIZE = 2u;

    const char* mPos;
};

/**
 * @brief @brief Iterator for iterating over the query data when the query type is a aggregation
 */
class AggregationIterator {
public:
    AggregationIterator()
            : mPos(nullptr) {
    }

    AggregationIterator(const char* pos)
            : mPos(pos) {
    }

    AggregationIterator& operator++() {
        mPos += ENTRY_SIZE;
        return *this;
    }

    AggregationIterator operator++(int) {
        AggregationIterator result(*this);
        operator++();
        return result;
    }

    bool operator==(const AggregationIterator& rhs) const {
        return (mPos == rhs.mPos);
    }

    bool operator!=(const AggregationIterator& rhs) const {
        return !operator==(rhs);
    }

    std::tuple<Record::id_t, AggregationType> operator*() const {
        return std::make_tuple(*reinterpret_cast<const Record::id_t*>(mPos),
                *reinterpret_cast<const AggregationType*>(mPos + AGGREGATION_TYPE_OFFSET));
    }

private:
    static constexpr size_t ENTRY_SIZE = 4u;

    static constexpr size_t AGGREGATION_TYPE_OFFSET = 2u;

    const char* mPos;
};

/**
 * @brief Information about a scan query
 *
 * A query has the following form
 * - 4 bytes for the number of columns it has to check
 * - 2 bytes for the number of conjuncts in the query
 * - 2 bytes for the number of bits to shift the key before partitioning
 * - 4 bytes for the number of total scan partitions (or 0 if no partitioning)
 * - 4 bytes for the number of the scan partition (if partitioning)
 * - For each column:
 *   - 2 bytes: The column id (called field id in the Record class)
 *   - 2 bytes: The number of predicates it has on the column
 *   - 4 bytes: Padding
 *   - For each predicate:
 *     - 1 byte: The type of the predicate
 *     - 1 byte: Position in the AND-list of queries
 *     - 2 bytes: The data if its size is between 1 and 2 bytes long padding otherwise
 *     - 4 bytes: The data if its size is between 2 and 4 bytes long padding otherwise
 *     - The data if it is larger than 4 bytes or if it is variable size length (padded to 8 bytes)
 */
class ScanQuery {
public:
    ScanQuery(ScanQueryType queryType, std::unique_ptr<char[]> selectionData, size_t selectionLength,
            std::unique_ptr<char[]> queryData, size_t queryLength,
            std::unique_ptr<commitmanager::SnapshotDescriptor> snapshot, const Record& record);

    virtual ~ScanQuery();

    ScanQueryType queryType() const {
        return mQueryType;
    }

    const char* selection() const {
        return mSelectionData.get();
    }

    size_t selectionLength() const {
        return mSelectionLength;
    }

    ProjectionIterator projectionBegin() const {
        LOG_ASSERT(mQueryType == ScanQueryType::PROJECTION, "Query type not projection");
        return ProjectionIterator(mQueryData.get());
    }

    ProjectionIterator projectionEnd() const {
        LOG_ASSERT(mQueryType == ScanQueryType::PROJECTION, "Query type not projection");
        return ProjectionIterator(mQueryDataEnd);
    }

    AggregationIterator aggregationBegin() const {
        LOG_ASSERT(mQueryType == ScanQueryType::AGGREGATION, "Query type not aggregation");
        return AggregationIterator(mQueryData.get());
    }

    AggregationIterator aggregationEnd() const {
        LOG_ASSERT(mQueryType == ScanQueryType::AGGREGATION, "Query type not aggregation");
        return AggregationIterator(mQueryDataEnd);
    }

    const commitmanager::SnapshotDescriptor* snapshot() const {
        return mSnapshot.get();
    }

    const Record& record() const {
        return mRecord;
    }

    uint32_t minimumLength() const {
        return mMinimumLength;
    }

    /**
     * @brief Acquires a new buffer
     */
    virtual std::tuple<char*, uint32_t> acquireBuffer() = 0;

    /**
     * @brief Flushes the tuples in the buffer to the client
     *
     * @param start Begin pointer to the buffer containing the tuples
     * @param end End pointer to the buffer containing the tuples
     * @param ec Error in case the write fails
     */
    virtual void writeOngoing(const char* start, const char* end, std::error_code& ec) = 0;

    /**
     * @brief Writes the last tuples to the client
     *
     * The invoking scan processor can be marked as done.
     *
     * @param start Begin pointer to the buffer containing the tuples
     * @param end End pointer to the buffer containing the tuples
     * @param ec Error in case the write fails
     */
    virtual void writeLast(const char* start, const char* end, std::error_code& ec) = 0;

    /**
     * @brief Writes the last tuples to the client
     *
     * The invoking scan processor can be marked as done.
     *
     * @param ec Error in case the write fails
     */
    virtual void writeLast(std::error_code& ec) = 0;

    /**
     * @brief Create a new ScanQueryProcessor associated with this scan
     */
    virtual ScanQueryProcessor createProcessor() = 0;

private:
    /// The type of the scan query
    ScanQueryType mQueryType;

    /// The selection query
    std::unique_ptr<char[]> mSelectionData;

    /// Length of the selection query string
    size_t mSelectionLength;

    /// The query data
    /// This is null when the query type is a full scan, the projection query in case the query type is a projection or
    /// an aggregation query in case the query type is an aggregation.
    std::unique_ptr<char[]> mQueryData;

    /// Pointer to the end of the query data
    const char* mQueryDataEnd;

    /// Snapshot to check the validity of tuples against
    std::unique_ptr<commitmanager::SnapshotDescriptor> mSnapshot;

    /// Record containing the target schema
    Record mRecord;

    /// Minimum size a tuple requires (i.e. minimum static size)
    uint32_t mMinimumLength;
};

/**
 * @brief Processor building the tuples according to the data specified in the scan query
 *
 * Checks the validity of the tuple against a SnapshotDescriptor and writes all valid tuples into a buffer. Performs
 * projection or aggregation depending on the query type.
 */
class ScanQueryProcessor : crossbow::non_copyable {
public:
    static constexpr size_t TUPLE_OVERHEAD = sizeof(uint64_t);

    ScanQueryProcessor(ScanQuery* data)
            : mData(data),
              mBuffer(nullptr),
              mBufferWriter(static_cast<char*>(nullptr), 0),
              mTupleCount(0u) {
    }

    ~ScanQueryProcessor();

    ScanQueryProcessor(ScanQueryProcessor&& other);

    ScanQueryProcessor& operator=(ScanQueryProcessor&& other);

    const ScanQuery* data() const {
        return mData;
    }

    /**
     * @brief Process the tuple according to the query data associated with this processor
     *
     * @param record Record of the tuple
     * @param key Key of the tuple
     * @param length Length of the tuple
     * @param validFrom Valid-From version of the tuple
     * @param validTo Valid-To version of the tuple
     * @param fun Function to serialize the record
     */
    template <typename Fun>
    void writeRecord(uint64_t key, uint32_t length, uint64_t validFrom, uint64_t validTo, Fun fun);

    /**
     * @brief Initializes the aggregation tuple
     *
     * Reserves space for the aggregations in the buffer and initializes them to zero.
     */
    void initAggregationRecord();

//private:
    /**
     * @brief Ensures that the buffer can hold at least the number of bytes
     *
     * The buffer is written and a new buffer will beacquired in case there is no space left in the current buffer.
     *
     * @param Minimum size of the tuple to be written
     */
    void ensureBufferSpace(uint32_t length);

    /// Shared data holding information about the scan
    ScanQuery* mData;

    /// Start pointer of the current buffer
    char* mBuffer;

    /// Writer used to write the tuples into the buffer
    crossbow::buffer_writer mBufferWriter;

    /// Number of tuples written to the buffer
    uint16_t mTupleCount;
};

template <typename Fun>
void ScanQueryProcessor::writeRecord(uint64_t key, uint32_t length, uint64_t validFrom, uint64_t validTo, Fun fun) {
    auto snapshot = mData->snapshot();
    if (snapshot && !snapshot->inReadSet(validFrom, validTo)) {
        return;
    }

    if (mData->queryType() == ScanQueryType::AGGREGATION) {
        fun(mBuffer + 8);
    } else {
        ensureBufferSpace(length + TUPLE_OVERHEAD);

        // Write key
        mBufferWriter.write<uint64_t>(key);

        // Write complete tuple
        auto bytesWritten = fun(mBufferWriter.data());
        LOG_ASSERT(bytesWritten <= length, "Bytes written must be smaller than the length");

        mBufferWriter.advance(crossbow::align(bytesWritten, 8u));

        ++mTupleCount;
    }
}

} //namespace store
} //namespace tell
<|endoftext|>