<commit_before>/**
 * @license
 * Copyright 2018 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */

#include "egl_context_wrapper.h"

#include "utils.h"

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>

#include <iostream>
#include <vector>

namespace nodejsgl {

#if DEBUG
void LogExtensions(const char* extensions_name, const char* extensions) {
  std::string s(extensions);
  std::string delim = " ";
  size_t pos = 0;
  std::string token;
  std::cout << "---- " << extensions_name << "----" << std::endl;
  while ((pos = s.find(delim)) != std::string::npos) {
    token = s.substr(0, pos);
    std::cout << token << std::endl;
    s.erase(0, pos + delim.length());
  }
  std::cout << s;
  std::cout << "-------------------------" << std::endl;
}
#endif

EGLContextWrapper::EGLContextWrapper(napi_env env) {
  InitEGL(env);
  BindProcAddresses();
  BindExtensions();

#if DEBUG
  // LogExtensions("GL_EXTENSIONS",
  //               reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
#endif
}

void EGLContextWrapper::InitEGL(napi_env env) {
  // TODO(kreeger): Figure out how to make this work headless
  display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  if (display == EGL_NO_DISPLAY) {
    NAPI_THROW_ERROR(env, "No display");
    return;
  }

  EGLint major;
  EGLint minor;
  if (!eglInitialize(display, &major, &minor)) {
    NAPI_THROW_ERROR(env, "Could not initialize display");
    return;
  }

#if DEBUG
  // TODO(kreeger): Clean this up.
  // std::cerr << "major: " << major << std::endl;
  // std::cerr << "minor: " << minor << std::endl;
#endif

  extensions_wrapper = new EGLExtensionsWrapper(display);

  EGLint attrib_list[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
                          EGL_RED_SIZE,     8,
                          EGL_GREEN_SIZE,   8,
                          EGL_BLUE_SIZE,    8,
                          EGL_ALPHA_SIZE,   8,
                          EGL_DEPTH_SIZE,   24,
                          EGL_STENCIL_SIZE, 8,
                          EGL_NONE};

  EGLint num_config;
  if (!eglChooseConfig(display, attrib_list, &config, 1, &num_config)) {
    NAPI_THROW_ERROR(env, "Failed creating a config");
    return;
  }

  eglBindAPI(EGL_OPENGL_ES_API);
  if (eglGetError() != EGL_SUCCESS) {
    NAPI_THROW_ERROR(env, "Failed to set OpenGL ES API");
    return;
  }

#if DEBUG
  // LogExtensions("EGL_EXTENSIONS", eglQueryString(display, EGL_EXTENSIONS));
#endif

  // Append attributes based on available features
  std::vector<EGLint> context_attributes;

  context_attributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
  context_attributes.push_back(EGL_TRUE);

  // context_attributes.push_back(EGL_EXTENSIONS_ENABLED_ANGLE);
  // context_attributes.push_back(EGL_TRUE);

  context_attributes.push_back(EGL_CONTEXT_OPENGL_DEBUG);
#if DEBUG
  context_attributes.push_back(EGL_TRUE);
#else
  context_attributes.push_back(EGL_FALSE);
#endif

  context_attributes.push_back(EGL_NONE);

  context =
      eglCreateContext(display, config, nullptr, context_attributes.data());
  if (context == EGL_NO_CONTEXT) {
    NAPI_THROW_ERROR(env, "Could not create context");
    return;
  }

  EGLint surface_attribs[] = {EGL_WIDTH, (EGLint)1, EGL_HEIGHT, (EGLint)1,
                              EGL_NONE};
  surface = eglCreatePbufferSurface(display, config, surface_attribs);
  if (surface == EGL_NO_SURFACE) {
    NAPI_THROW_ERROR(env, "Could not create surface");
    return;
  }

  if (!eglMakeCurrent(display, surface, surface, context)) {
    NAPI_THROW_ERROR(env, "Could not make context current");
    return;
  }
}

void EGLContextWrapper::BindProcAddresses() {
  // Bind runtime function pointers.
  glActiveTexture = reinterpret_cast<PFNGLACTIVETEXTUREPROC>(
      eglGetProcAddress("glActiveTexture"));
  glAttachShader = reinterpret_cast<PFNGLATTACHSHADERPROC>(
      eglGetProcAddress("glAttachShader"));
  glBindBuffer =
      reinterpret_cast<PFNGLBINDBUFFERPROC>(eglGetProcAddress("glBindBuffer"));
  glBindFramebuffer = reinterpret_cast<PFNGLBINDFRAMEBUFFERPROC>(
      eglGetProcAddress("glBindFramebuffer"));
  glBindRenderbuffer = reinterpret_cast<PFNGLBINDRENDERBUFFERPROC>(
      eglGetProcAddress("glBindRenderbuffer"));
  glBindTexture = reinterpret_cast<PFNGLBINDTEXTUREPROC>(
      eglGetProcAddress("glBindTexture"));
  glBufferData =
      reinterpret_cast<PFNGLBUFFERDATAPROC>(eglGetProcAddress("glBufferData"));
  glCheckFramebufferStatus = reinterpret_cast<PFNGLCHECKFRAMEBUFFERSTATUSPROC>(
      eglGetProcAddress("glCheckFramebufferStatus"));
  glCompileShader = reinterpret_cast<PFNGLCOMPILESHADERPROC>(
      eglGetProcAddress("glCompileShader"));
  glCreateProgram = reinterpret_cast<PFNGLCREATEPROGRAMPROC>(
      eglGetProcAddress("glCreateProgram"));
  glCreateShader = reinterpret_cast<PFNGLCREATESHADERPROC>(
      eglGetProcAddress("glCreateShader"));
  glCullFace =
      reinterpret_cast<PFNGLCULLFACEPROC>(eglGetProcAddress("glCullFace"));
  glDeleteBuffers = reinterpret_cast<PFNGLDELETEBUFFERSPROC>(
      eglGetProcAddress("glDeleteBuffers"));
  glDeleteFramebuffers = reinterpret_cast<PFNGLDELETEFRAMEBUFFERSPROC>(
      eglGetProcAddress("glDeleteFramebuffers"));
  glDeleteProgram = reinterpret_cast<PFNGLDELETEPROGRAMPROC>(
      eglGetProcAddress("glDeleteProgram"));
  glDeleteShader = reinterpret_cast<PFNGLDELETESHADERPROC>(
      eglGetProcAddress("glDeleteShader"));
  glDeleteTextures = reinterpret_cast<PFNGLDELETETEXTURESPROC>(
      eglGetProcAddress("glDeleteTextures"));
  glDrawArrays =
      reinterpret_cast<PFNGLDRAWARRAYSPROC>(eglGetProcAddress("glDrawArrays"));
  glDrawElements = reinterpret_cast<PFNGLDRAWELEMENTSPROC>(
      eglGetProcAddress("glDrawElements"));
  glDisable =
      reinterpret_cast<PFNGLDISABLEPROC>(eglGetProcAddress("glDisable"));
  glDisableVertexAttribArray =
      reinterpret_cast<PFNGLDISABLEVERTEXATTRIBARRAYPROC>(
          eglGetProcAddress("glDisableVertexAttribArray"));
  glEnable = reinterpret_cast<PFNGLENABLEPROC>(eglGetProcAddress("glEnable"));
  glEnableVertexAttribArray =
      reinterpret_cast<PFNGLENABLEVERTEXATTRIBARRAYPROC>(
          eglGetProcAddress("glEnableVertexAttribArray"));
  glFinish = reinterpret_cast<PFNGLFINISHPROC>(eglGetProcAddress("glFinish"));
  glFlush = reinterpret_cast<PFNGLFLUSHPROC>(eglGetProcAddress("glFlush"));
  glFramebufferRenderbuffer =
      reinterpret_cast<PFNGLFRAMEBUFFERRENDERBUFFERPROC>(
          eglGetProcAddress("glFramebufferRenderbuffer"));
  glFramebufferTexture2D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DPROC>(
      eglGetProcAddress("glFramebufferTexture2D"));
  glGenBuffers =
      reinterpret_cast<PFNGLGENBUFFERSPROC>(eglGetProcAddress("glGenBuffers"));
  glGenFramebuffers = reinterpret_cast<PFNGLGENFRAMEBUFFERSPROC>(
      eglGetProcAddress("glGenFramebuffers"));
  glGenRenderbuffers = reinterpret_cast<PFNGLGENRENDERBUFFERSPROC>(
      eglGetProcAddress("glGenRenderbuffers"));
  glGetAttribLocation = reinterpret_cast<PFNGLGETATTRIBLOCATIONPROC>(
      eglGetProcAddress("glGetAttribLocation"));
  glGetError =
      reinterpret_cast<PFNGLGETERRORPROC>(eglGetProcAddress("glGetError"));
  glGetIntegerv = reinterpret_cast<PFNGLGETINTEGERVPROC>(
      eglGetProcAddress("glGetIntegerv"));
  glGenTextures = reinterpret_cast<PFNGLGENTEXTURESPROC>(
      eglGetProcAddress("glGenTextures"));
  glGetProgramiv = reinterpret_cast<PFNGLGETPROGRAMIVPROC>(
      eglGetProcAddress("glGetProgramiv"));
  glGetProgramInfoLog = reinterpret_cast<PFNGLGETPROGRAMINFOLOGPROC>(
      eglGetProcAddress("glGetProgramInfoLog"));
  glGetShaderiv = reinterpret_cast<PFNGLGETSHADERIVPROC>(
      eglGetProcAddress("glGetShaderiv"));
  glGetShaderInfoLog = reinterpret_cast<PFNGLGETSHADERINFOLOGPROC>(
      eglGetProcAddress("glGetShaderInfoLog"));
  glGetString =
      reinterpret_cast<PFNGLGETSTRINGPROC>(eglGetProcAddress("glGetString"));
  glGetUniformLocation = reinterpret_cast<PFNGLGETUNIFORMLOCATIONPROC>(
      eglGetProcAddress("glGetUniformLocation"));
  glLinkProgram = reinterpret_cast<PFNGLLINKPROGRAMPROC>(
      eglGetProcAddress("glLinkProgram"));
  glReadPixels =
      reinterpret_cast<PFNGLREADPIXELSPROC>(eglGetProcAddress("glReadPixels"));
  glRenderbufferStorage = reinterpret_cast<PFNGLRENDERBUFFERSTORAGEPROC>(
      eglGetProcAddress("glRenderbufferStorage"));
  glScissor =
      reinterpret_cast<PFNGLSCISSORPROC>(eglGetProcAddress("glScissor"));
  glShaderSource = reinterpret_cast<PFNGLSHADERSOURCEPROC>(
      eglGetProcAddress("glShaderSource"));
  glTexImage2D =
      reinterpret_cast<PFNGLTEXIMAGE2DPROC>(eglGetProcAddress("glTexImage2D"));
  glTexParameteri = reinterpret_cast<PFNGLTEXPARAMETERIPROC>(
      eglGetProcAddress("glTexParameteri"));
  glTexSubImage2D = reinterpret_cast<PFNGLTEXSUBIMAGE2DPROC>(
      eglGetProcAddress("glTexSubImage2D"));
  glUniform1i =
      reinterpret_cast<PFNGLUNIFORM1IPROC>(eglGetProcAddress("glUniform1i"));
  glUniform1f =
      reinterpret_cast<PFNGLUNIFORM1FPROC>(eglGetProcAddress("glUniform1f"));
  glUniform1fv =
      reinterpret_cast<PFNGLUNIFORM1FVPROC>(eglGetProcAddress("glUniform1fv"));
  glUniform2i =
      reinterpret_cast<PFNGLUNIFORM2IPROC>(eglGetProcAddress("glUniform2i"));
  glUniform4fv =
      reinterpret_cast<PFNGLUNIFORM4FVPROC>(eglGetProcAddress("glUniform4fv"));
  glUniform4i =
      reinterpret_cast<PFNGLUNIFORM4IPROC>(eglGetProcAddress("glUniform4i"));
  glUseProgram =
      reinterpret_cast<PFNGLUSEPROGRAMPROC>(eglGetProcAddress("glUseProgram"));
  glVertexAttribPointer = reinterpret_cast<PFNGLVERTEXATTRIBPOINTERPROC>(
      eglGetProcAddress("glVertexAttribPointer"));
  glViewport =
      reinterpret_cast<PFNGLVIEWPORTPROC>(eglGetProcAddress("glViewport"));

  // ANGLE specific
  glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
      eglGetProcAddress("glRequestExtensionANGLE"));
}

void EGLContextWrapper::BindExtensions() {
  //
  // TODO - write me/doc me.
  //

  // GLint num_extensions = 0;
  // this->glGetIntegerv(GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE, &num_extensions);
  // fprintf(stderr, "----> requestable extensions: %d\n", num_extensions);

  const char* extensions = reinterpret_cast<const char*>(
      this->glGetString(GL_REQUESTABLE_EXTENSIONS_ANGLE));

  std::string s(extensions);
  std::string delim = " ";
  size_t pos = 0;
  std::string token;
  std::cout << "---- GL_REQUESTABLE_EXTENSIONS_ANGLE ----" << std::endl;
  while ((pos = s.find(delim)) != std::string::npos) {
    token = s.substr(0, pos);
    std::cout << "Enabling: " << token << std::endl;
    glRequestExtensionANGLE(token.c_str());
    s.erase(0, pos + delim.length());
  }
  std::cout << s;
  std::cout << "-------------------------" << std::endl;
}

EGLContextWrapper::~EGLContextWrapper() {
  // TODO(kreeger): Close context attributes.
  // TODO(kreeger): Cleanup global objects.
  if (extensions_wrapper != nullptr) {
    delete extensions_wrapper;
  }
}

EGLContextWrapper* EGLContextWrapper::Create(napi_env env) {
  return new EGLContextWrapper(env);
}

}  // namespace nodejsgl
<commit_msg>Cleanup<commit_after>/**
 * @license
 * Copyright 2018 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */

#include "egl_context_wrapper.h"

#include "utils.h"

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>

#include <iostream>
#include <vector>

namespace nodejsgl {

#if DEBUG
void LogExtensions(const char* extensions_name, const char* extensions) {
  std::string s(extensions);
  std::string delim = " ";
  size_t pos = 0;
  std::string token;
  std::cout << "---- " << extensions_name << "----" << std::endl;
  while ((pos = s.find(delim)) != std::string::npos) {
    token = s.substr(0, pos);
    std::cout << token << std::endl;
    s.erase(0, pos + delim.length());
  }
  std::cout << s;
  std::cout << "-------------------------" << std::endl;
}
#endif

EGLContextWrapper::EGLContextWrapper(napi_env env) {
  InitEGL(env);
  BindProcAddresses();
  BindExtensions();

#if DEBUG
  // LogExtensions("GL_EXTENSIONS",
  //               reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
#endif
}

void EGLContextWrapper::InitEGL(napi_env env) {
  // TODO(kreeger): Figure out how to make this work headless
  display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  if (display == EGL_NO_DISPLAY) {
    NAPI_THROW_ERROR(env, "No display");
    return;
  }

  EGLint major;
  EGLint minor;
  if (!eglInitialize(display, &major, &minor)) {
    NAPI_THROW_ERROR(env, "Could not initialize display");
    return;
  }

#if DEBUG
  // TODO(kreeger): Clean this up.
  // std::cerr << "major: " << major << std::endl;
  // std::cerr << "minor: " << minor << std::endl;
#endif

  extensions_wrapper = new EGLExtensionsWrapper(display);

  EGLint attrib_list[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
                          EGL_RED_SIZE,     8,
                          EGL_GREEN_SIZE,   8,
                          EGL_BLUE_SIZE,    8,
                          EGL_ALPHA_SIZE,   8,
                          EGL_DEPTH_SIZE,   24,
                          EGL_STENCIL_SIZE, 8,
                          EGL_NONE};

  EGLint num_config;
  if (!eglChooseConfig(display, attrib_list, &config, 1, &num_config)) {
    NAPI_THROW_ERROR(env, "Failed creating a config");
    return;
  }

  eglBindAPI(EGL_OPENGL_ES_API);
  if (eglGetError() != EGL_SUCCESS) {
    NAPI_THROW_ERROR(env, "Failed to set OpenGL ES API");
    return;
  }

#if DEBUG
  // LogExtensions("EGL_EXTENSIONS", eglQueryString(display, EGL_EXTENSIONS));
#endif

  // Append attributes based on available features
  std::vector<EGLint> context_attributes;

  context_attributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
  context_attributes.push_back(EGL_TRUE);

  context_attributes.push_back(EGL_CONTEXT_OPENGL_DEBUG);
#if DEBUG
  context_attributes.push_back(EGL_TRUE);
#else
  context_attributes.push_back(EGL_FALSE);
#endif

  context_attributes.push_back(EGL_NONE);

  context =
      eglCreateContext(display, config, nullptr, context_attributes.data());
  if (context == EGL_NO_CONTEXT) {
    NAPI_THROW_ERROR(env, "Could not create context");
    return;
  }

  EGLint surface_attribs[] = {EGL_WIDTH, (EGLint)1, EGL_HEIGHT, (EGLint)1,
                              EGL_NONE};
  surface = eglCreatePbufferSurface(display, config, surface_attribs);
  if (surface == EGL_NO_SURFACE) {
    NAPI_THROW_ERROR(env, "Could not create surface");
    return;
  }

  if (!eglMakeCurrent(display, surface, surface, context)) {
    NAPI_THROW_ERROR(env, "Could not make context current");
    return;
  }
}

void EGLContextWrapper::BindProcAddresses() {
  // Bind runtime function pointers.
  glActiveTexture = reinterpret_cast<PFNGLACTIVETEXTUREPROC>(
      eglGetProcAddress("glActiveTexture"));
  glAttachShader = reinterpret_cast<PFNGLATTACHSHADERPROC>(
      eglGetProcAddress("glAttachShader"));
  glBindBuffer =
      reinterpret_cast<PFNGLBINDBUFFERPROC>(eglGetProcAddress("glBindBuffer"));
  glBindFramebuffer = reinterpret_cast<PFNGLBINDFRAMEBUFFERPROC>(
      eglGetProcAddress("glBindFramebuffer"));
  glBindRenderbuffer = reinterpret_cast<PFNGLBINDRENDERBUFFERPROC>(
      eglGetProcAddress("glBindRenderbuffer"));
  glBindTexture = reinterpret_cast<PFNGLBINDTEXTUREPROC>(
      eglGetProcAddress("glBindTexture"));
  glBufferData =
      reinterpret_cast<PFNGLBUFFERDATAPROC>(eglGetProcAddress("glBufferData"));
  glCheckFramebufferStatus = reinterpret_cast<PFNGLCHECKFRAMEBUFFERSTATUSPROC>(
      eglGetProcAddress("glCheckFramebufferStatus"));
  glCompileShader = reinterpret_cast<PFNGLCOMPILESHADERPROC>(
      eglGetProcAddress("glCompileShader"));
  glCreateProgram = reinterpret_cast<PFNGLCREATEPROGRAMPROC>(
      eglGetProcAddress("glCreateProgram"));
  glCreateShader = reinterpret_cast<PFNGLCREATESHADERPROC>(
      eglGetProcAddress("glCreateShader"));
  glCullFace =
      reinterpret_cast<PFNGLCULLFACEPROC>(eglGetProcAddress("glCullFace"));
  glDeleteBuffers = reinterpret_cast<PFNGLDELETEBUFFERSPROC>(
      eglGetProcAddress("glDeleteBuffers"));
  glDeleteFramebuffers = reinterpret_cast<PFNGLDELETEFRAMEBUFFERSPROC>(
      eglGetProcAddress("glDeleteFramebuffers"));
  glDeleteProgram = reinterpret_cast<PFNGLDELETEPROGRAMPROC>(
      eglGetProcAddress("glDeleteProgram"));
  glDeleteShader = reinterpret_cast<PFNGLDELETESHADERPROC>(
      eglGetProcAddress("glDeleteShader"));
  glDeleteTextures = reinterpret_cast<PFNGLDELETETEXTURESPROC>(
      eglGetProcAddress("glDeleteTextures"));
  glDrawArrays =
      reinterpret_cast<PFNGLDRAWARRAYSPROC>(eglGetProcAddress("glDrawArrays"));
  glDrawElements = reinterpret_cast<PFNGLDRAWELEMENTSPROC>(
      eglGetProcAddress("glDrawElements"));
  glDisable =
      reinterpret_cast<PFNGLDISABLEPROC>(eglGetProcAddress("glDisable"));
  glDisableVertexAttribArray =
      reinterpret_cast<PFNGLDISABLEVERTEXATTRIBARRAYPROC>(
          eglGetProcAddress("glDisableVertexAttribArray"));
  glEnable = reinterpret_cast<PFNGLENABLEPROC>(eglGetProcAddress("glEnable"));
  glEnableVertexAttribArray =
      reinterpret_cast<PFNGLENABLEVERTEXATTRIBARRAYPROC>(
          eglGetProcAddress("glEnableVertexAttribArray"));
  glFinish = reinterpret_cast<PFNGLFINISHPROC>(eglGetProcAddress("glFinish"));
  glFlush = reinterpret_cast<PFNGLFLUSHPROC>(eglGetProcAddress("glFlush"));
  glFramebufferRenderbuffer =
      reinterpret_cast<PFNGLFRAMEBUFFERRENDERBUFFERPROC>(
          eglGetProcAddress("glFramebufferRenderbuffer"));
  glFramebufferTexture2D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DPROC>(
      eglGetProcAddress("glFramebufferTexture2D"));
  glGenBuffers =
      reinterpret_cast<PFNGLGENBUFFERSPROC>(eglGetProcAddress("glGenBuffers"));
  glGenFramebuffers = reinterpret_cast<PFNGLGENFRAMEBUFFERSPROC>(
      eglGetProcAddress("glGenFramebuffers"));
  glGenRenderbuffers = reinterpret_cast<PFNGLGENRENDERBUFFERSPROC>(
      eglGetProcAddress("glGenRenderbuffers"));
  glGetAttribLocation = reinterpret_cast<PFNGLGETATTRIBLOCATIONPROC>(
      eglGetProcAddress("glGetAttribLocation"));
  glGetError =
      reinterpret_cast<PFNGLGETERRORPROC>(eglGetProcAddress("glGetError"));
  glGetIntegerv = reinterpret_cast<PFNGLGETINTEGERVPROC>(
      eglGetProcAddress("glGetIntegerv"));
  glGenTextures = reinterpret_cast<PFNGLGENTEXTURESPROC>(
      eglGetProcAddress("glGenTextures"));
  glGetProgramiv = reinterpret_cast<PFNGLGETPROGRAMIVPROC>(
      eglGetProcAddress("glGetProgramiv"));
  glGetProgramInfoLog = reinterpret_cast<PFNGLGETPROGRAMINFOLOGPROC>(
      eglGetProcAddress("glGetProgramInfoLog"));
  glGetShaderiv = reinterpret_cast<PFNGLGETSHADERIVPROC>(
      eglGetProcAddress("glGetShaderiv"));
  glGetShaderInfoLog = reinterpret_cast<PFNGLGETSHADERINFOLOGPROC>(
      eglGetProcAddress("glGetShaderInfoLog"));
  glGetString =
      reinterpret_cast<PFNGLGETSTRINGPROC>(eglGetProcAddress("glGetString"));
  glGetUniformLocation = reinterpret_cast<PFNGLGETUNIFORMLOCATIONPROC>(
      eglGetProcAddress("glGetUniformLocation"));
  glLinkProgram = reinterpret_cast<PFNGLLINKPROGRAMPROC>(
      eglGetProcAddress("glLinkProgram"));
  glReadPixels =
      reinterpret_cast<PFNGLREADPIXELSPROC>(eglGetProcAddress("glReadPixels"));
  glRenderbufferStorage = reinterpret_cast<PFNGLRENDERBUFFERSTORAGEPROC>(
      eglGetProcAddress("glRenderbufferStorage"));
  glScissor =
      reinterpret_cast<PFNGLSCISSORPROC>(eglGetProcAddress("glScissor"));
  glShaderSource = reinterpret_cast<PFNGLSHADERSOURCEPROC>(
      eglGetProcAddress("glShaderSource"));
  glTexImage2D =
      reinterpret_cast<PFNGLTEXIMAGE2DPROC>(eglGetProcAddress("glTexImage2D"));
  glTexParameteri = reinterpret_cast<PFNGLTEXPARAMETERIPROC>(
      eglGetProcAddress("glTexParameteri"));
  glTexSubImage2D = reinterpret_cast<PFNGLTEXSUBIMAGE2DPROC>(
      eglGetProcAddress("glTexSubImage2D"));
  glUniform1i =
      reinterpret_cast<PFNGLUNIFORM1IPROC>(eglGetProcAddress("glUniform1i"));
  glUniform1f =
      reinterpret_cast<PFNGLUNIFORM1FPROC>(eglGetProcAddress("glUniform1f"));
  glUniform1fv =
      reinterpret_cast<PFNGLUNIFORM1FVPROC>(eglGetProcAddress("glUniform1fv"));
  glUniform2i =
      reinterpret_cast<PFNGLUNIFORM2IPROC>(eglGetProcAddress("glUniform2i"));
  glUniform4fv =
      reinterpret_cast<PFNGLUNIFORM4FVPROC>(eglGetProcAddress("glUniform4fv"));
  glUniform4i =
      reinterpret_cast<PFNGLUNIFORM4IPROC>(eglGetProcAddress("glUniform4i"));
  glUseProgram =
      reinterpret_cast<PFNGLUSEPROGRAMPROC>(eglGetProcAddress("glUseProgram"));
  glVertexAttribPointer = reinterpret_cast<PFNGLVERTEXATTRIBPOINTERPROC>(
      eglGetProcAddress("glVertexAttribPointer"));
  glViewport =
      reinterpret_cast<PFNGLVIEWPORTPROC>(eglGetProcAddress("glViewport"));

  // ANGLE specific
  glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
      eglGetProcAddress("glRequestExtensionANGLE"));
}

void EGLContextWrapper::BindExtensions() {
  //
  // TODO - write me/doc me.
  //

  // GLint num_extensions = 0;
  // this->glGetIntegerv(GL_NUM_REQUESTABLE_EXTENSIONS_ANGLE, &num_extensions);
  // fprintf(stderr, "----> requestable extensions: %d\n", num_extensions);

  const char* extensions = reinterpret_cast<const char*>(
      this->glGetString(GL_REQUESTABLE_EXTENSIONS_ANGLE));

  std::string s(extensions);
  std::string delim = " ";
  size_t pos = 0;
  std::string token;
  std::cout << "---- GL_REQUESTABLE_EXTENSIONS_ANGLE ----" << std::endl;
  while ((pos = s.find(delim)) != std::string::npos) {
    token = s.substr(0, pos);
    std::cout << "Enabling: " << token << std::endl;
    glRequestExtensionANGLE(token.c_str());
    s.erase(0, pos + delim.length());
  }
  std::cout << s;
  std::cout << "-------------------------" << std::endl;
}

EGLContextWrapper::~EGLContextWrapper() {
  // TODO(kreeger): Close context attributes.
  // TODO(kreeger): Cleanup global objects.
  if (extensions_wrapper != nullptr) {
    delete extensions_wrapper;
  }
}

EGLContextWrapper* EGLContextWrapper::Create(napi_env env) {
  return new EGLContextWrapper(env);
}

}  // namespace nodejsgl
<|endoftext|>


<commit_before>
#include <node.h>
#include <node_buffer.h>
#include "database.h"

namespace bangdown {
static v8::Persistent<v8::FunctionTemplate> database_constructor;

Database::Database (char* name) : name(name) {
  db = NULL;
};

Database::~Database () {
  if (db != NULL)
    db->closedatabase();
    delete db;
  delete[] name;
};

database* Database::OpenDatabase (
  char* location
    ) {
  database* db;
  db = new database((char*)location);
  printf("%s Created\n", db->getdbname());
  return db;
}
void Database::Init () {
  v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(Database::New);
  NanAssignPersistent(v8::FunctionTemplate, database_constructor, tpl);
  tpl->SetClassName(NanSymbol("Database"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  NODE_SET_PROTOTYPE_METHOD(tpl, "new", Database::New);
  NODE_SET_PROTOTYPE_METHOD(tpl, "put", Database::Put);
}

NAN_METHOD(Database::New) {
  NanScope();

  if (args.Length() == 0)
    return NanThrowError("constructor requires at least a location argument");

  if (!args[0]->IsString())
    return NanThrowError("constructor requires a location string argument");

  char* name = NanFromV8String(args[0].As<v8::Object>(), Nan::UTF8, NULL, NULL, 0, v8::String::NO_OPTIONS);

  Database* obj = new Database(name);
  obj->Wrap(args.This());
  printf("NAME: %s \n", name);
//  NanReturnUndefined();
  NanReturnValue(args.This());
}

NAN_METHOD(Database::Put) {
    NanScope();

    char* location = NanFromV8String(args[0].As<v8::Object>(), Nan::UTF8, NULL, NULL, 0, v8::String::NO_OPTIONS);
    printf("Creating new db\n");
    database* db = new database((char*)location);
    printf("%s Created\n", db->getdbname());

    table *tbl = db->gettable((char*)"mytable2");
    connection *conn = tbl->getconnection();

    FDT ikey, ival, *out;

//    char* key = location;
//    char* val = location;

    ikey.data = location;
    ikey.length = strlen(location);
    ival.data = (void*)location;
    ival.length = strlen(location);
    int ret;
    ret=conn->put(&ikey, &ival, INSERT_UPDATE);
    printf("PUT Finished with %d\n",ret);
    out = conn->get(&ikey);
    printf("GET Finished\n");
    printf("GET ReturnValue(%s)\n", (char*)out->data);

//    key = null;
//    val = null;
    db->closedatabase();
    delete db;
    NanReturnUndefined();
}

  NAN_METHOD(Bang){
    NanScope();

    v8::Local<v8::String> name;
    if (args.Length() != 0 && args[0]->IsString())
      name = args[0].As<v8::String>();

    NanReturnValue(Database::NewInstance(name));
  }
v8::Handle<v8::Value> Database::NewInstance (v8::Local<v8::String> &name) {
  NanScope();

  v8::Local<v8::Object> instance;

  v8::Local<v8::FunctionTemplate> constructorHandle =
      NanPersistentToLocal(database_constructor);

  if (name.IsEmpty()) {
    instance = constructorHandle->GetFunction()->NewInstance(0, NULL);
  } else {
    v8::Handle<v8::Value> argv[] = { name };
    instance = constructorHandle->GetFunction()->NewInstance(1, argv);
  }

  return instance;
}
}
<commit_msg>Woot got local reference to Database class unwrapping from args.this finally<commit_after>
#include <node.h>
#include <node_buffer.h>
#include "database.h"

namespace bangdown {
static v8::Persistent<v8::FunctionTemplate> database_constructor;

Database::Database (char* name) : name(name) {
  db = NULL;
};

Database::~Database () {
  if (db != NULL)
    db->closedatabase();
    delete db;
  delete[] name;
};

database* Database::OpenDatabase (
  char* location
    ) {
  //database* db;
  db = new database((char*)location);
  printf("%s Created\n", db->getdbname());
  return db;
}
void Database::Init () {
  v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(Database::New);
  NanAssignPersistent(v8::FunctionTemplate, database_constructor, tpl);
  tpl->SetClassName(NanSymbol("Database"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  NODE_SET_PROTOTYPE_METHOD(tpl, "new", Database::New);
  NODE_SET_PROTOTYPE_METHOD(tpl, "put", Database::Put);
}

NAN_METHOD(Database::New) {
  NanScope();

  if (args.Length() == 0)
    return NanThrowError("constructor requires at least a location argument");

  if (!args[0]->IsString())
    return NanThrowError("constructor requires a location string argument");

  char* name = NanFromV8String(args[0].As<v8::Object>(), Nan::UTF8, NULL, NULL, 0, v8::String::NO_OPTIONS);

  Database* obj = new Database(name);
  obj->Wrap(args.This());
  printf("NAME: %s \n", name);
//  NanReturnUndefined();
  NanReturnValue(args.This());
}

NAN_METHOD(Database::Put) {
    NanScope();

    Database* _database = ObjectWrap::Unwrap<Database>(args.This());
    char* location = NanFromV8String(args[0].As<v8::Object>(), Nan::UTF8, NULL, NULL, 0, v8::String::NO_OPTIONS);
    printf("Creating new db\n");
    database* db = new database((char*)location);
    printf("%s Created\n", db->getdbname());

    table *tbl = db->gettable((char*)"mytable2");
    connection *conn = tbl->getconnection();

    FDT ikey, ival, *out;

//    char* key = location;
//    char* val = location;

    ikey.data = location;
    ikey.length = strlen(location);
    ival.data = (void*)location;
    ival.length = strlen(location);
    int ret;
    ret=conn->put(&ikey, &ival, INSERT_UPDATE);
    printf("PUT Finished with %d\n",ret);
    out = conn->get(&ikey);
    printf("GET Finished\n");
    printf("GET ReturnValue(%s)\n", (char*)out->data);

//    key = null;
//    val = null;
    db->closedatabase();
    delete db;
    NanReturnUndefined();
}

  NAN_METHOD(Bang){
    NanScope();

    v8::Local<v8::String> name;
    if (args.Length() != 0 && args[0]->IsString())
      name = args[0].As<v8::String>();

    NanReturnValue(Database::NewInstance(name));
  }
v8::Handle<v8::Value> Database::NewInstance (v8::Local<v8::String> &name) {
  NanScope();

  v8::Local<v8::Object> instance;

  v8::Local<v8::FunctionTemplate> constructorHandle =
      NanPersistentToLocal(database_constructor);

  if (name.IsEmpty()) {
    instance = constructorHandle->GetFunction()->NewInstance(0, NULL);
  } else {
    v8::Handle<v8::Value> argv[] = { name };
    instance = constructorHandle->GetFunction()->NewInstance(1, argv);
  }

  return instance;
}
}
<|endoftext|>


<commit_before>// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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.

#include "deps_log.h"

#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#include "graph.h"
#include "metrics.h"
#include "state.h"
#include "util.h"

namespace {
const char kFileSignature[] = "# ninja deps v%d\n";
const int kCurrentVersion = 1;
}  // anonymous namespace

DepsLog::~DepsLog() {
  Close();
}

bool DepsLog::OpenForWrite(const string& path, string* err) {
  file_ = fopen(path.c_str(), "ab");
  if (!file_) {
    *err = strerror(errno);
    return false;
  }
  SetCloseOnExec(fileno(file_));

  // Opening a file in append mode doesn't set the file pointer to the file's
  // end on Windows. Do that explicitly.
  fseek(file_, 0, SEEK_END);

  if (ftell(file_) == 0) {
    if (fprintf(file_, kFileSignature, kCurrentVersion) < 0) {
      *err = strerror(errno);
      return false;
    }
  }

  return true;
}

bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
                         const vector<Node*>& nodes) {
  return RecordDeps(node, mtime, nodes.size(),
                    nodes.empty() ? NULL : (Node**)&nodes.front());
}

bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
                         int node_count, Node** nodes) {
  // Track whether there's any new data to be recorded.
  bool made_change = false;

  // Assign ids to all nodes that are missing one.
  if (node->id() < 0) {
    RecordId(node);
    made_change = true;
  }
  for (int i = 0; i < node_count; ++i) {
    if (nodes[i]->id() < 0) {
      RecordId(nodes[i]);
      made_change = true;
    }
  }

  // See if the new data is different than the existing data, if any.
  if (!made_change) {
    Deps* deps = GetDeps(node);
    if (!deps ||
        deps->mtime != mtime ||
        deps->node_count != node_count) {
      made_change = true;
    } else {
      for (int i = 0; i < node_count; ++i) {
        if (deps->nodes[i] != nodes[i]) {
          made_change = true;
          break;
        }
      }
    }
  }

  // Don't write anything if there's no new info.
  if (!made_change)
    return true;

  uint16_t size = 4 * (1 + 1 + (uint16_t)node_count);
  size |= 0x8000;  // Deps record: set high bit.
  fwrite(&size, 2, 1, file_);
  int id = node->id();
  fwrite(&id, 4, 1, file_);
  int timestamp = mtime;
  fwrite(&timestamp, 4, 1, file_);
  for (int i = 0; i < node_count; ++i) {
    id = nodes[i]->id();
    fwrite(&id, 4, 1, file_);
  }

  return true;
}

void DepsLog::Close() {
  if (file_)
    fclose(file_);
  file_ = NULL;
}

bool DepsLog::Load(const string& path, State* state, string* err) {
  METRIC_RECORD(".ninja_deps load");
  char buf[32 << 10];
  FILE* f = fopen(path.c_str(), "rb");
  if (!f) {
    if (errno == ENOENT)
      return true;
    *err = strerror(errno);
    return false;
  }

  if (!fgets(buf, sizeof(buf), f)) {
    *err = strerror(errno);
    return false;
  }
  int version = 0;
  sscanf(buf, kFileSignature, &version);
  if (version != kCurrentVersion) {
    *err = "bad deps log signature or version; starting over";
    fclose(f);
    unlink(path.c_str());
    // Don't report this as a failure.  An empty deps log will cause
    // us to rebuild the outputs anyway.
    return true;
  }

  for (;;) {
    uint16_t size;
    if (fread(&size, 2, 1, f) < 1)
      break;
    bool is_deps = (size >> 15) != 0;
    size = size & 0x7FFF;

    if (fread(buf, size, 1, f) < 1)
      break;

    if (is_deps) {
      assert(size % 4 == 0);
      int* deps_data = reinterpret_cast<int*>(buf);
      int out_id = deps_data[0];
      int mtime = deps_data[1];
      deps_data += 2;
      int deps_count = (size / 4) - 2;

      Deps* deps = new Deps;
      deps->mtime = mtime;
      deps->node_count = deps_count;
      deps->nodes = new Node*[deps_count];
      for (int i = 0; i < deps_count; ++i) {
        assert(deps_data[i] < (int)nodes_.size());
        assert(nodes_[deps_data[i]]);
        deps->nodes[i] = nodes_[deps_data[i]];
      }

      if (out_id >= (int)deps_.size())
        deps_.resize(out_id + 1);
      if (deps_[out_id]) {
        ++dead_record_count_;
        delete deps_[out_id];
      }
      deps_[out_id] = deps;
    } else {
      StringPiece path(buf, size);
      Node* node = state->GetNode(path);
      assert(node->id() < 0);
      node->set_id(nodes_.size());
      nodes_.push_back(node);
    }
  }
  if (ferror(f)) {
    *err = strerror(ferror(f));
    return false;
  }
  fclose(f);
  return true;
}

DepsLog::Deps* DepsLog::GetDeps(Node* node) {
  if (node->id() < 0)
    return NULL;
  return deps_[node->id()];
}

bool DepsLog::Recompact(const string& path, string* err) {
  METRIC_RECORD(".ninja_deps recompact");
  printf("Recompacting deps...\n");

  string temp_path = path + ".recompact";
  DepsLog new_log;
  if (!new_log.OpenForWrite(temp_path, err))
    return false;

  // Clear all known ids so that new ones can be reassigned.
  for (vector<Node*>::iterator i = nodes_.begin();
       i != nodes_.end(); ++i) {
    (*i)->set_id(-1);
  }

  // Write out all deps again.
  for (int old_id = 0; old_id < (int)deps_.size(); ++old_id) {
    Deps* deps = deps_[old_id];
    if (!new_log.RecordDeps(nodes_[old_id], deps->mtime,
                            deps->node_count, deps->nodes)) {
      new_log.Close();
      return false;
    }
  }

  new_log.Close();

  if (unlink(path.c_str()) < 0) {
    *err = strerror(errno);
    return false;
  }

  if (rename(temp_path.c_str(), path.c_str()) < 0) {
    *err = strerror(errno);
    return false;
  }

  return true;
}

bool DepsLog::RecordId(Node* node) {
  uint16_t size = (uint16_t)node->path().size();
  fwrite(&size, 2, 1, file_);
  fwrite(node->path().data(), node->path().size(), 1, file_);

  node->set_id(nodes_.size());
  nodes_.push_back(node);

  return true;
}
<commit_msg>Write the depslog version in binary instead of text.<commit_after>// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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.

#include "deps_log.h"

#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#include "graph.h"
#include "metrics.h"
#include "state.h"
#include "util.h"

// The version is stored as 4 bytes after the signature and also serves as a
// byte order mark. Signature and version combined are 16 bytes long.
const char kFileSignature[] = "# ninjadeps\n";
const int kCurrentVersion = 1;

DepsLog::~DepsLog() {
  Close();
}

bool DepsLog::OpenForWrite(const string& path, string* err) {
  file_ = fopen(path.c_str(), "ab");
  if (!file_) {
    *err = strerror(errno);
    return false;
  }
  SetCloseOnExec(fileno(file_));

  // Opening a file in append mode doesn't set the file pointer to the file's
  // end on Windows. Do that explicitly.
  fseek(file_, 0, SEEK_END);

  if (ftell(file_) == 0) {
    if (fwrite(kFileSignature, sizeof(kFileSignature) - 1, 1, file_) < 1) {
      *err = strerror(errno);
      return false;
    }
    if (fwrite(&kCurrentVersion, 4, 1, file_) < 1) {
      *err = strerror(errno);
      return false;
    }
  }

  return true;
}

bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
                         const vector<Node*>& nodes) {
  return RecordDeps(node, mtime, nodes.size(),
                    nodes.empty() ? NULL : (Node**)&nodes.front());
}

bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
                         int node_count, Node** nodes) {
  // Track whether there's any new data to be recorded.
  bool made_change = false;

  // Assign ids to all nodes that are missing one.
  if (node->id() < 0) {
    RecordId(node);
    made_change = true;
  }
  for (int i = 0; i < node_count; ++i) {
    if (nodes[i]->id() < 0) {
      RecordId(nodes[i]);
      made_change = true;
    }
  }

  // See if the new data is different than the existing data, if any.
  if (!made_change) {
    Deps* deps = GetDeps(node);
    if (!deps ||
        deps->mtime != mtime ||
        deps->node_count != node_count) {
      made_change = true;
    } else {
      for (int i = 0; i < node_count; ++i) {
        if (deps->nodes[i] != nodes[i]) {
          made_change = true;
          break;
        }
      }
    }
  }

  // Don't write anything if there's no new info.
  if (!made_change)
    return true;

  uint16_t size = 4 * (1 + 1 + (uint16_t)node_count);
  size |= 0x8000;  // Deps record: set high bit.
  fwrite(&size, 2, 1, file_);
  int id = node->id();
  fwrite(&id, 4, 1, file_);
  int timestamp = mtime;
  fwrite(&timestamp, 4, 1, file_);
  for (int i = 0; i < node_count; ++i) {
    id = nodes[i]->id();
    fwrite(&id, 4, 1, file_);
  }

  return true;
}

void DepsLog::Close() {
  if (file_)
    fclose(file_);
  file_ = NULL;
}

bool DepsLog::Load(const string& path, State* state, string* err) {
  METRIC_RECORD(".ninja_deps load");
  char buf[32 << 10];
  FILE* f = fopen(path.c_str(), "rb");
  if (!f) {
    if (errno == ENOENT)
      return true;
    *err = strerror(errno);
    return false;
  }

  if (!fgets(buf, sizeof(buf), f)) {
    *err = strerror(errno);
    return false;
  }
  int version = 0;
  if (fread(&version, 4, 1, f) < 1) {
    *err = strerror(errno);
    return false;
  }
  if (version != kCurrentVersion) {
    *err = "bad deps log signature or version; starting over";
    fclose(f);
    unlink(path.c_str());
    // Don't report this as a failure.  An empty deps log will cause
    // us to rebuild the outputs anyway.
    return true;
  }

  for (;;) {
    uint16_t size;
    if (fread(&size, 2, 1, f) < 1)
      break;
    bool is_deps = (size >> 15) != 0;
    size = size & 0x7FFF;

    if (fread(buf, size, 1, f) < 1)
      break;

    if (is_deps) {
      assert(size % 4 == 0);
      int* deps_data = reinterpret_cast<int*>(buf);
      int out_id = deps_data[0];
      int mtime = deps_data[1];
      deps_data += 2;
      int deps_count = (size / 4) - 2;

      Deps* deps = new Deps;
      deps->mtime = mtime;
      deps->node_count = deps_count;
      deps->nodes = new Node*[deps_count];
      for (int i = 0; i < deps_count; ++i) {
        assert(deps_data[i] < (int)nodes_.size());
        assert(nodes_[deps_data[i]]);
        deps->nodes[i] = nodes_[deps_data[i]];
      }

      if (out_id >= (int)deps_.size())
        deps_.resize(out_id + 1);
      if (deps_[out_id]) {
        ++dead_record_count_;
        delete deps_[out_id];
      }
      deps_[out_id] = deps;
    } else {
      StringPiece path(buf, size);
      Node* node = state->GetNode(path);
      assert(node->id() < 0);
      node->set_id(nodes_.size());
      nodes_.push_back(node);
    }
  }
  if (ferror(f)) {
    *err = strerror(ferror(f));
    return false;
  }
  fclose(f);
  return true;
}

DepsLog::Deps* DepsLog::GetDeps(Node* node) {
  if (node->id() < 0)
    return NULL;
  return deps_[node->id()];
}

bool DepsLog::Recompact(const string& path, string* err) {
  METRIC_RECORD(".ninja_deps recompact");
  printf("Recompacting deps...\n");

  string temp_path = path + ".recompact";
  DepsLog new_log;
  if (!new_log.OpenForWrite(temp_path, err))
    return false;

  // Clear all known ids so that new ones can be reassigned.
  for (vector<Node*>::iterator i = nodes_.begin();
       i != nodes_.end(); ++i) {
    (*i)->set_id(-1);
  }

  // Write out all deps again.
  for (int old_id = 0; old_id < (int)deps_.size(); ++old_id) {
    Deps* deps = deps_[old_id];
    if (!new_log.RecordDeps(nodes_[old_id], deps->mtime,
                            deps->node_count, deps->nodes)) {
      new_log.Close();
      return false;
    }
  }

  new_log.Close();

  if (unlink(path.c_str()) < 0) {
    *err = strerror(errno);
    return false;
  }

  if (rename(temp_path.c_str(), path.c_str()) < 0) {
    *err = strerror(errno);
    return false;
  }

  return true;
}

bool DepsLog::RecordId(Node* node) {
  uint16_t size = (uint16_t)node->path().size();
  fwrite(&size, 2, 1, file_);
  fwrite(node->path().data(), node->path().size(), 1, file_);

  node->set_id(nodes_.size());
  nodes_.push_back(node);

  return true;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Jason White
 *
 * MIT License
 */

#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <algorithm>
#include <utility>

#include "dircache.h"
#include "glob.h"
#include "path.h"
#include "deps.h"

using path::Path;

bool operator<(const DirEntry& a, const DirEntry& b) {
    return std::tie(a.name, a.isDir) < std::tie(b.name, b.isDir);
}

namespace {

/**
 * Returns a list of the files in a directory.
 */
DirEntries dirEntries(const std::string& path) {

    DirEntries entries;

#ifdef _WIN32

    // TODO: Implement on Windows. We'll need to convert between UTF-8 and
    // UTF-16 when interacting with the Windows API.
#   error Not implemented yet.

#else // _WIN32

    DIR* dir = opendir(path.length() > 0 ? path.c_str() : ".");
    if (!dir) return entries; // TODO: Throw exception instead

    struct dirent* entry;
    struct stat statbuf;

    while ((entry = readdir(dir))) {
        if (strcmp(entry->d_name, "." ) == 0 ||
            strcmp(entry->d_name, "..") == 0) continue;

        // Directory entry type is unknown. The file system is not required to
        // provide this information. Thus, we need to figure it out by using
        // stat.
        if (entry->d_type == DT_UNKNOWN) {
            if (fstatat(dirfd(dir), entry->d_name, &statbuf, 0) == 0) {
                switch (statbuf.st_mode & S_IFMT) {
                    case S_IFIFO:  entry->d_type = DT_FIFO; break;
                    case S_IFCHR:  entry->d_type = DT_CHR;  break;
                    case S_IFDIR:  entry->d_type = DT_DIR;  break;
                    case S_IFBLK:  entry->d_type = DT_BLK;  break;
                    case S_IFREG:  entry->d_type = DT_REG;  break;
                    case S_IFLNK:  entry->d_type = DT_LNK;  break;
                    case S_IFSOCK: entry->d_type = DT_SOCK; break;
                }
            }
        }

        entries.push_back(DirEntry { entry->d_name, entry->d_type == DT_DIR });
    }

#endif // !_WIN32

    // Sort the entries. The order in which directories are listed is not
    // guaranteed to be deterministic.
    std::sort(entries.begin(), entries.end());

    return entries;
}

/**
 * Returns true if the given string contains a glob pattern.
 */
bool isGlobPattern(Path p) {
    for (size_t i = 0; i < p.length; ++i) {
        switch (p.path[i]) {
            case '?':
            case '*':
            case '[':
                return true;
        }
    }

    return false;
}

/**
 * Returns true if the given path element is a recursive glob pattern.
 */
bool isRecursiveGlob(Path p) {
    return p.length == 2 && p.path[0] == '*' && p.path[1] == '*';
}

struct GlobClosure {

    // Directory listing cache.
    DirCache* dirCache;

    // Root directory we are globbing from.
    Path root;

    Path pattern;

    // Next callback
    GlobCallback next;
    void* nextData;
};

void globCallback(Path path, bool isDir, void* data) {
    if (isDir) {
        const GlobClosure* c = (const GlobClosure*)data;
        c->dirCache->glob(c->root, path, c->pattern, c->next, c->nextData);
    }
}

}

/**
 * Helper function for listing a directory with the given pattern. If the
 * pattern is empty,
 */
void DirCache::glob(Path root, Path path, Path pattern,
          GlobCallback callback, void* data) {

    std::string buf(path.path, path.length);

    if (pattern.length == 0) {
        path::join(buf, pattern);
        callback(Path(buf.data(), buf.size()), true, data);
        return;
    }

    for (auto&& entry: dirEntries(root, path)) {
        if (globMatch(entry.name, pattern)) {
            path::join(buf, entry.name);

            callback(Path(buf.data(), buf.size()), entry.isDir, data);

            buf.assign(path.path, path.length);
        }
    }
}

/**
 * Helper function to recursively yield directories for the given path.
 */
void DirCache::globRecursive(Path root, std::string& path,
        GlobCallback callback, void* data) {

    size_t len = path.size();

    // "**" matches 0 or more directories and thus includes this one.
    callback(Path(path.data(), path.size()), true, data);

    for (auto&& entry: dirEntries(root, path)) {
        path::join(path, entry.name);

        callback(Path(path.data(), path.size()), entry.isDir, data);

        if (entry.isDir)
            globRecursive(root, path, callback, data);

        path.resize(len);
    }
}

/**
 * Glob a directory.
 */
void DirCache::glob(Path root, Path path, GlobCallback callback, void* data) {

    path::Split s = path::split(path);

    if (isGlobPattern(s.head)) {
        // Directory name contains a glob pattern

        GlobClosure c;
        c.dirCache = this;
        c.root = root;
        c.pattern = s.tail;
        c.next = callback;
        c.nextData = data;

        glob(root, s.head, &globCallback, &c);
    }
    else if (isRecursiveGlob(s.tail)) {
        std::string buf(s.head.path, s.head.length);
        globRecursive(root, buf, callback, data);
    }
    else if (isGlobPattern(s.tail)) {
        // Only base name contains a glob pattern.
        glob(root, s.head, s.tail, callback, data);
    }
    else {
        // No glob pattern in this path.
        if (s.tail.length) {
            // TODO: Only yield this path if the file exists.
            callback(path, false, data);
        }
        else {
            // TODO: Only yield this path if the directory exists.
            callback(s.head, true, data);
        }
    }
}

DirCache::DirCache(ImplicitDeps* deps) : _deps(deps) {}

const DirEntries& DirCache::dirEntries(Path root, Path dir) {
    std::string buf(root.path, root.length);
    path::join(buf, dir);
    return dirEntries(buf);
}

const DirEntries& DirCache::dirEntries(const std::string& path) {

    // TODO: Normalize the input path.

    // Did we already do the work?
    const auto it = cache.find(path);
    if (it != cache.end())
        return it->second;

    // TODO: Report dependency on this directory.
    if (_deps) _deps->addInput(path.data(), path.length());

    // List the directories, cache it, and return the cached list.
    return cache.insert(
            std::pair<std::string, DirEntries>(path, ::dirEntries(path))
            ).first->second;
}
<commit_msg>Clean up comments<commit_after>/**
 * Copyright (c) Jason White
 *
 * MIT License
 */

#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <algorithm>
#include <utility>

#include "dircache.h"
#include "glob.h"
#include "path.h"
#include "deps.h"

using path::Path;

bool operator<(const DirEntry& a, const DirEntry& b) {
    return std::tie(a.name, a.isDir) < std::tie(b.name, b.isDir);
}

namespace {

/**
 * Returns a list of the files in a directory.
 */
DirEntries dirEntries(const std::string& path) {

    DirEntries entries;

#ifdef _WIN32

    // TODO: Implement on Windows. We'll need to convert between UTF-8 and
    // UTF-16 when interacting with the Windows API.
#   error Not implemented yet.

#else // _WIN32

    DIR* dir = opendir(path.length() > 0 ? path.c_str() : ".");
    if (!dir) return entries; // TODO: Throw exception instead

    struct dirent* entry;
    struct stat statbuf;

    while ((entry = readdir(dir))) {
        if (strcmp(entry->d_name, "." ) == 0 ||
            strcmp(entry->d_name, "..") == 0) continue;

        if (entry->d_type == DT_UNKNOWN) {
            // Directory entry type is unknown. The file system is not required
            // to provide this information. Thus, we need to figure it out by
            // using stat.
            if (fstatat(dirfd(dir), entry->d_name, &statbuf, 0) == 0) {
                switch (statbuf.st_mode & S_IFMT) {
                    case S_IFIFO:  entry->d_type = DT_FIFO; break;
                    case S_IFCHR:  entry->d_type = DT_CHR;  break;
                    case S_IFDIR:  entry->d_type = DT_DIR;  break;
                    case S_IFBLK:  entry->d_type = DT_BLK;  break;
                    case S_IFREG:  entry->d_type = DT_REG;  break;
                    case S_IFLNK:  entry->d_type = DT_LNK;  break;
                    case S_IFSOCK: entry->d_type = DT_SOCK; break;
                }
            }
        }

        entries.push_back(DirEntry { entry->d_name, entry->d_type == DT_DIR });
    }

#endif // !_WIN32

    // Sort the entries. The order in which directories are listed is not
    // guaranteed to be deterministic.
    std::sort(entries.begin(), entries.end());

    return entries;
}

/**
 * Returns true if the given string contains a glob pattern.
 */
bool isGlobPattern(Path p) {
    for (size_t i = 0; i < p.length; ++i) {
        switch (p.path[i]) {
            case '?':
            case '*':
            case '[':
                return true;
        }
    }

    return false;
}

/**
 * Returns true if the given path element is a recursive glob pattern.
 */
bool isRecursiveGlob(Path p) {
    return p.length == 2 && p.path[0] == '*' && p.path[1] == '*';
}

struct GlobClosure {

    // Directory listing cache.
    DirCache* dirCache;

    // Root directory we are globbing from.
    Path root;

    Path pattern;

    // Next callback
    GlobCallback next;
    void* nextData;
};

void globCallback(Path path, bool isDir, void* data) {
    if (isDir) {
        const GlobClosure* c = (const GlobClosure*)data;
        c->dirCache->glob(c->root, path, c->pattern, c->next, c->nextData);
    }
}

}

/**
 * Helper function for listing a directory with the given pattern. If the
 * pattern is empty,
 */
void DirCache::glob(Path root, Path path, Path pattern,
          GlobCallback callback, void* data) {

    std::string buf(path.path, path.length);

    if (pattern.length == 0) {
        path::join(buf, pattern);
        callback(Path(buf.data(), buf.size()), true, data);
        return;
    }

    for (auto&& entry: dirEntries(root, path)) {
        if (globMatch(entry.name, pattern)) {
            path::join(buf, entry.name);

            callback(Path(buf.data(), buf.size()), entry.isDir, data);

            buf.assign(path.path, path.length);
        }
    }
}

/**
 * Helper function to recursively yield directories for the given path.
 */
void DirCache::globRecursive(Path root, std::string& path,
        GlobCallback callback, void* data) {

    size_t len = path.size();

    // "**" matches 0 or more directories and thus includes this one.
    callback(Path(path.data(), path.size()), true, data);

    for (auto&& entry: dirEntries(root, path)) {
        path::join(path, entry.name);

        callback(Path(path.data(), path.size()), entry.isDir, data);

        if (entry.isDir)
            globRecursive(root, path, callback, data);

        path.resize(len);
    }
}

/**
 * Glob a directory.
 */
void DirCache::glob(Path root, Path path, GlobCallback callback, void* data) {

    path::Split s = path::split(path);

    if (isGlobPattern(s.head)) {
        // Directory name contains a glob pattern

        GlobClosure c;
        c.dirCache = this;
        c.root = root;
        c.pattern = s.tail;
        c.next = callback;
        c.nextData = data;

        glob(root, s.head, &globCallback, &c);
    }
    else if (isRecursiveGlob(s.tail)) {
        std::string buf(s.head.path, s.head.length);
        globRecursive(root, buf, callback, data);
    }
    else if (isGlobPattern(s.tail)) {
        // Only base name contains a glob pattern.
        glob(root, s.head, s.tail, callback, data);
    }
    else {
        // No glob pattern in this path.
        if (s.tail.length) {
            // TODO: Only yield this path if the file exists.
            callback(path, false, data);
        }
        else {
            // TODO: Only yield this path if the directory exists.
            callback(s.head, true, data);
        }
    }
}

DirCache::DirCache(ImplicitDeps* deps) : _deps(deps) {}

const DirEntries& DirCache::dirEntries(Path root, Path dir) {
    std::string buf(root.path, root.length);
    path::join(buf, dir);
    return dirEntries(buf);
}

const DirEntries& DirCache::dirEntries(const std::string& path) {

    // TODO: Normalize the input path.

    // Did we already do the work?
    const auto it = cache.find(path);
    if (it != cache.end())
        return it->second;

    if (_deps) _deps->addInput(path.data(), path.length());

    // List the directories, cache it, and return the cached list.
    return cache.insert(
            std::pair<std::string, DirEntries>(path, ::dirEntries(path))
            ).first->second;
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2016 Joy Narical <jnarical@gmail.com> MIT license
//
// display.cpp
//

#include "display.hpp"
#include "strings.hpp"
#include "input.hpp"
#include "battlefield.hpp"
#include "powerup.hpp"
#include "player.hpp"
#include "item.hpp"
#include "monster.hpp"
#include "field.hpp"
#include "game.hpp"
#include <libtcod.hpp>
#include <cassert>
#include <iostream>

//horizontal wall
//std::string Display::HORIZ_WALL = "######################";
std::string Display::HORIZ_WALL = "";

Display::Display(Game * game) :
_game(game),
_frame(Frames::CURRENT)
{
    TCODSystem::setFps(MAX_FPS);
    TCODConsole::setCustomFont("courier12x12_aa_tc.png",TCOD_FONT_LAYOUT_TCOD);
	TCODConsole::initRoot(SCREEN_WIDTH,SCREEN_HEIGHT,GAME_TITLE.c_str(),false);
    TCOD_renderer_t ren = TCODSystem::getRenderer();
    if (ren == TCOD_RENDERER_SDL) std::cout << "SDL" << std::endl;

    TCODConsole::credits();
    TCODConsole::root->setDefaultBackground(TCODColor::black);
    TCODConsole::root->setDefaultForeground(TCODColor::red);

    for (uint8_t i=0; i<BF_SIZE+2; ++i) HORIZ_WALL+="#";

	// Make frame counters to zero for every event type
	uint8_t list_begin = static_cast<uint8_t>(Events::LVLUP);
	uint8_t list_end = static_cast<uint8_t>(Events::EVENTS_END);
	for (uint8_t event = list_begin; event < list_end; ++event)	_frameCounters[event] = 0;
}

void Display::ShowFrame()
{
    TCODConsole::root->clear();
	DrawBattlefield();
	DrawPlayerInfo();
	if (_game->GetPlayer()->HaveTarget()) DrawEnemyInfo();
    TCODConsole::flush();
}

void Display::DrawBattlefield()
{
    TCODConsole::root->print(BF_MARGIN, BF_ROW, HORIZ_WALL.c_str());
	for (uint8_t rowIndex = 1; rowIndex <= BF_SIZE; ++rowIndex)
	{
		TCODConsole::root->print(BF_MARGIN, BF_ROW + rowIndex, "#\n");
		for (uint8_t colIndex = 1; colIndex <= BF_SIZE; ++colIndex)
    		TCODConsole::root->print(BF_MARGIN + colIndex, BF_ROW + rowIndex, DrawField(rowIndex-1, colIndex-1));
		TCODConsole::root->print(BF_MARGIN + BF_SIZE + 1, BF_ROW + rowIndex, "#\n");
	}
    TCODConsole::root->print(BF_MARGIN, BF_ROW + BF_SIZE + 1, HORIZ_WALL.c_str());
}

void Display::DrawPlayerInfo()
{
	Player * plr_copy = nullptr;
	Monster * enemy_copy = nullptr;

	Player * plr = _game->GetPlayer();

	if (plr->HaveTarget())
	{
		plr_copy = _game->GetBattlefield()->GetPlayerCopy();
		enemy_copy = _game->GetBattlefield()->GetEnemyCopy();
	}

	Item *inv1 = plr->GetInventory(0);
	Item *inv2 = plr->GetInventory(1);
	Item *inv3 = plr->GetInventory(2);
	Item *inv4 = plr->GetInventory(3);
	Item *grnd = plr->GetPosition()->GetItem();
	Item *sel_item = plr->GetSelectedItem();

	if (plr_copy != nullptr && _frame == Frames::FUTURE)
		plr = plr_copy;
	else
		plr = _game->GetPlayer();

	std::string str_inv1 = (inv1 != nullptr ? "1. " + inv1->GetName() : "Empty slot");
	std::string str_inv2 = (inv2 != nullptr ? "2. " + inv2->GetName() : "Empty slot");
	std::string str_inv3 = (inv3 != nullptr ? "3. " + inv3->GetName() : "Empty slot");
	std::string str_inv4 = (inv4 != nullptr ? "4. " + inv4->GetName() : "Empty slot");
	std::string str_grnd = (grnd != nullptr ? GRND1 + grnd->GetName() + GRND2 : "");

	std::string name = plr->GetName();
	uint8_t level = plr->GetLevel();
	uint16_t damage = plr->GetDamage();
	uint16_t HP = plr->GetHP();
	uint16_t maxHP = plr->GetMaxHP();
	uint16_t mana = plr->GetMana();
	uint16_t maxMana = plr->GetMaxMana();
	uint16_t exp = plr->GetExp();
	uint16_t expMax = plr->GetExpMax();

	std::string healthBar = DrawBar(HP, maxHP);
	std::string manaBar = DrawBar(mana, maxMana);
	std::string expBar = DrawBar(exp, expMax);

    std::string exp_line = "Exp  "+std::to_string(exp)+" / "+std::to_string(expMax);
    TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 0, exp_line.c_str());
	//CheckEvent(MANA_PWRUP);
    std::string mana_line = "Mana  "+std::to_string(mana)+" / "+std::to_string(maxMana);
    TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 1, mana_line.c_str());
	//EndCheck();

	if (inv1 == sel_item && sel_item != nullptr)
	{
		//BoldOn();
		str_inv1 += INV;
	}
		TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 3, str_inv1.c_str());
		//BoldOff();

	if (inv2 == sel_item && sel_item != nullptr)
	{
		//BoldOn();
		str_inv2 += INV;
	}
		TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 4, str_inv2.c_str());
		//BoldOff();

	if (inv3 == sel_item && sel_item != nullptr)
	{
		//BoldOn();
		str_inv3 += INV;
	}
		TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 5, str_inv3.c_str());
		//BoldOff();

	if (inv4 == sel_item && sel_item != nullptr)
	{
		//BoldOn();
		str_inv4 += INV;
	}
		TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 6, str_inv4.c_str());
		//BoldOff();

	if (str_grnd != "")	TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 7, str_grnd.c_str());

	//CheckEvent(Events::LVLUP);
	std::string level_line = name + " - level " + std::to_string(level);
	TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 9, level_line.c_str());
	//EndCheck();
	//CheckEvent(HP_PWRUP);
	std::string health_line = " [+]  " + std::to_string(HP) + " / " + std::to_string(maxHP);
	TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 11, health_line.c_str());
	//EndCheck();
	//CheckEvent(DMG_PWRUP);
	std::string damage_line = " [*]    " + std::to_string(damage);
	TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 13, damage_line.c_str());
	//EndCheck();

	TCODConsole::root->print(BAR_MARGIN, PLAYER_ROW + 0, expBar.c_str());
	TCODConsole::root->print(BAR_MARGIN, PLAYER_ROW + 1, manaBar.c_str());
	TCODConsole::root->print(BAR_MARGIN, PLAYER_ROW + 11, healthBar.c_str());

	if (plr_copy != nullptr)
	{
		std::string prediction;
		if (plr_copy->IsAlive() && enemy_copy->IsAlive()) prediction = "SAFE";
		else if (plr_copy->IsDead() && enemy_copy->IsAlive()) prediction = "DEATH !!!";
		else if (plr_copy->IsAlive() && enemy_copy->IsDead()) prediction = "Victory!";
		TCODConsole::root->print(BAR_MARGIN, PLAYER_ROW + 13, prediction.c_str());
	}
}

void Display::DrawEnemyInfo()
{
	Monster * enemy = nullptr;
	if (_game->GetBattlefield()->GetEnemyCopy() != nullptr && _frame == Frames::FUTURE)
		enemy = _game->GetBattlefield()->GetEnemyCopy();

	else enemy = _game->GetPlayer()->GetTargetField()->GetEnemy();

	if (enemy != nullptr)
	{
		std::string name = enemy->GetName();
		uint8_t level = enemy->GetLevel();
		uint8_t damage = enemy->GetDamage();
		uint8_t HP = enemy->GetHP();
		uint8_t maxHP = enemy->GetMaxHP();
		std::string healthBar = DrawBar(HP, maxHP);

        std::string name_level_line = name + " - level " + std::to_string(level);
		TCODConsole::root->print(INFO_MARGIN, ENEMY_ROW + 0, name_level_line.c_str());

        std::string health_line = " [+]   " + std::to_string(HP) + " / " + std::to_string(maxHP);
		TCODConsole::root->print(INFO_MARGIN, ENEMY_ROW + 2, health_line.c_str());

        std::string damage_line = " [*]     " + std::to_string(damage);
		TCODConsole::root->print(INFO_MARGIN, ENEMY_ROW + 4, damage_line.c_str());

		TCODConsole::root->print(BAR_MARGIN, ENEMY_ROW + 2, healthBar.c_str());
	}
}

const char* Display::DrawField(uint8_t rowIndex, uint8_t colIndex) const
{
	Field *playerField = _game->GetPlayer()->GetPosition();
	Field *playerTarget = _game->GetPlayer()->GetTargetField();
	Field *field = _game->GetBattlefield()->GetField(rowIndex, colIndex);
    assert(field != nullptr);

	if (!field->IsVisible()) return ".\n";
	else
	{
		if (field->HaveEnemy())
	 	{
			if (field == playerTarget)
			{
				//BoldOn();
				//CheckEvent(MNSTR_HIT_1);
				//CheckEvent(MNSTR_HIT_2);
				if (field->GetEnemy()->GetLevel() == 10) return "Z\n";
				else return (std::to_string(field->GetEnemy()->GetLevel()) + "\n").c_str();
				//EndCheck();
				//BoldOff();
			}
			else
			{
				if (field->GetEnemy()->GetLevel() == 10) return "Z\n";
				else return (std::to_string(field->GetEnemy()->GetLevel()) + "\n").c_str();
			}
		}

		else if (field != playerField && field->HavePowerup())
		{
			switch (field->GetPowerup()->GetType())
			{
				case Powerups::HEALTH:
					return "+\n";
					break;

				case Powerups::MANA:
					return "x\n";
					break;

				case Powerups::DAMAGE:
					return "*\n";
			}
		}

		else if (field != playerField && field->HaveItem())
		{
			return "i\n";
		}

		else if (field == playerField && field->HaveItem())
		{
			// BoldOn();
			return "@\n";
			// BoldOff();
		}

		else if (field == playerField)
		{
			// CheckEvent(Events::LVLUP);
			// CheckEvent(PLR_HIT_1);
			// CheckEvent(PLR_HIT_2);
			return "@\n";
			// EndCheck();
		}

		else return " \n";
	}
    return "S\n";
}

void Display::ReduceCounters()
{
	uint8_t list_begin = static_cast<uint8_t>(Events::LVLUP);
	uint8_t list_end = static_cast<uint8_t>(Events::EVENTS_END);

	for (uint8_t event = list_begin; event < list_end; ++event)
		if (_frameCounters[event] > 0) --_frameCounters[event];
}

void Display::SwitchFrameType()
{
	_frame = (_frame == Frames::CURRENT ? Frames::FUTURE : Frames::CURRENT);
}

std::string Display::DrawBar(uint16_t current, uint16_t max) const
{
	uint16_t num;
	std::string result = "[";
	num = (current != 0 ? (uint16_t)( (double)current / max * BARWIDTH) : 0);
	for (uint16_t i = 0; i < num; ++i) result += '#';
	for (uint16_t i = 0; i < BARWIDTH - num; ++i) result += '.';
	result += ']';
	return result;
}

void Display::SendEvent(Events event)
{
    uint8_t num = static_cast<uint8_t>(event);
	_frameCounters[num] = EVENT_TIMERS[num];
}

void Display::CheckEvent(Events event)
{
/*	switch (event)
	{
		case Eve.ts::LVLUP:
		case HP_PWRUP:
		case MANA_PWRUP:
		case DMG_PWRUP:
			if (_frameCounters[event] > 0 && _frameCounters[event] % 2) BoldOn();
			break;
		case PLR_HIT//_1:
		case MNSTR_H//IT_1:
		case PLR_HIT_2:
		case MNSTR_HIT_2:
			if e\nf; //ameCounters[event] == 1) InvertOn()//;
			brea//k;

		case Events::EVENTS_END:;
	} */
}

void Display::ShowVictoryScreen()
{
/*	clear();
	TCODConsole::root->print(2,2,"Victory!");
	refresh(); */
}

void Display::ShowDefeatScreen()
{
/*	clear();
	TCODConsole::root->print(2,2,"DEFEAT !");
s	\nrfresh(); */
}<commit_msg>return default terminal.png font<commit_after>//
// Copyright (c) 2016 Joy Narical <jnarical@gmail.com> MIT license
//
// display.cpp
//

#include "display.hpp"
#include "strings.hpp"
#include "input.hpp"
#include "battlefield.hpp"
#include "powerup.hpp"
#include "player.hpp"
#include "item.hpp"
#include "monster.hpp"
#include "field.hpp"
#include "game.hpp"
#include <libtcod.hpp>
#include <cassert>
#include <iostream>

//horizontal wall
//std::string Display::HORIZ_WALL = "######################";
std::string Display::HORIZ_WALL = "";

Display::Display(Game * game) :
_game(game),
_frame(Frames::CURRENT)
{
    TCODSystem::setFps(MAX_FPS);
//    TCODConsole::setCustomFont("courier12x12_aa_tc.png",TCOD_FONT_LAYOUT_TCOD);
	TCODConsole::initRoot(SCREEN_WIDTH,SCREEN_HEIGHT,GAME_TITLE.c_str(),false);
    TCOD_renderer_t ren = TCODSystem::getRenderer();
    if (ren == TCOD_RENDERER_SDL) std::cout << "SDL" << std::endl;

    TCODConsole::credits();
    TCODConsole::root->setDefaultBackground(TCODColor::black);
    TCODConsole::root->setDefaultForeground(TCODColor::red);

    for (uint8_t i=0; i<BF_SIZE+2; ++i) HORIZ_WALL+="#";

	// Make frame counters to zero for every event type
	uint8_t list_begin = static_cast<uint8_t>(Events::LVLUP);
	uint8_t list_end = static_cast<uint8_t>(Events::EVENTS_END);
	for (uint8_t event = list_begin; event < list_end; ++event)	_frameCounters[event] = 0;
}

void Display::ShowFrame()
{
    TCODConsole::root->clear();
	DrawBattlefield();
	DrawPlayerInfo();
	if (_game->GetPlayer()->HaveTarget()) DrawEnemyInfo();
    TCODConsole::flush();
}

void Display::DrawBattlefield()
{
    TCODConsole::root->print(BF_MARGIN, BF_ROW, HORIZ_WALL.c_str());
	for (uint8_t rowIndex = 1; rowIndex <= BF_SIZE; ++rowIndex)
	{
		TCODConsole::root->print(BF_MARGIN, BF_ROW + rowIndex, "#\n");
		for (uint8_t colIndex = 1; colIndex <= BF_SIZE; ++colIndex)
    		TCODConsole::root->print(BF_MARGIN + colIndex, BF_ROW + rowIndex, DrawField(rowIndex-1, colIndex-1));
		TCODConsole::root->print(BF_MARGIN + BF_SIZE + 1, BF_ROW + rowIndex, "#\n");
	}
    TCODConsole::root->print(BF_MARGIN, BF_ROW + BF_SIZE + 1, HORIZ_WALL.c_str());
}

void Display::DrawPlayerInfo()
{
	Player * plr_copy = nullptr;
	Monster * enemy_copy = nullptr;

	Player * plr = _game->GetPlayer();

	if (plr->HaveTarget())
	{
		plr_copy = _game->GetBattlefield()->GetPlayerCopy();
		enemy_copy = _game->GetBattlefield()->GetEnemyCopy();
	}

	Item *inv1 = plr->GetInventory(0);
	Item *inv2 = plr->GetInventory(1);
	Item *inv3 = plr->GetInventory(2);
	Item *inv4 = plr->GetInventory(3);
	Item *grnd = plr->GetPosition()->GetItem();
	Item *sel_item = plr->GetSelectedItem();

	if (plr_copy != nullptr && _frame == Frames::FUTURE)
		plr = plr_copy;
	else
		plr = _game->GetPlayer();

	std::string str_inv1 = (inv1 != nullptr ? "1. " + inv1->GetName() : "Empty slot");
	std::string str_inv2 = (inv2 != nullptr ? "2. " + inv2->GetName() : "Empty slot");
	std::string str_inv3 = (inv3 != nullptr ? "3. " + inv3->GetName() : "Empty slot");
	std::string str_inv4 = (inv4 != nullptr ? "4. " + inv4->GetName() : "Empty slot");
	std::string str_grnd = (grnd != nullptr ? GRND1 + grnd->GetName() + GRND2 : "");

	std::string name = plr->GetName();
	uint8_t level = plr->GetLevel();
	uint16_t damage = plr->GetDamage();
	uint16_t HP = plr->GetHP();
	uint16_t maxHP = plr->GetMaxHP();
	uint16_t mana = plr->GetMana();
	uint16_t maxMana = plr->GetMaxMana();
	uint16_t exp = plr->GetExp();
	uint16_t expMax = plr->GetExpMax();

	std::string healthBar = DrawBar(HP, maxHP);
	std::string manaBar = DrawBar(mana, maxMana);
	std::string expBar = DrawBar(exp, expMax);

    std::string exp_line = "Exp  "+std::to_string(exp)+" / "+std::to_string(expMax);
    TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 0, exp_line.c_str());
	//CheckEvent(MANA_PWRUP);
    std::string mana_line = "Mana  "+std::to_string(mana)+" / "+std::to_string(maxMana);
    TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 1, mana_line.c_str());
	//EndCheck();

	if (inv1 == sel_item && sel_item != nullptr)
	{
		//BoldOn();
		str_inv1 += INV;
	}
		TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 3, str_inv1.c_str());
		//BoldOff();

	if (inv2 == sel_item && sel_item != nullptr)
	{
		//BoldOn();
		str_inv2 += INV;
	}
		TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 4, str_inv2.c_str());
		//BoldOff();

	if (inv3 == sel_item && sel_item != nullptr)
	{
		//BoldOn();
		str_inv3 += INV;
	}
		TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 5, str_inv3.c_str());
		//BoldOff();

	if (inv4 == sel_item && sel_item != nullptr)
	{
		//BoldOn();
		str_inv4 += INV;
	}
		TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 6, str_inv4.c_str());
		//BoldOff();

	if (str_grnd != "")	TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 7, str_grnd.c_str());

	//CheckEvent(Events::LVLUP);
	std::string level_line = name + " - level " + std::to_string(level);
	TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 9, level_line.c_str());
	//EndCheck();
	//CheckEvent(HP_PWRUP);
	std::string health_line = " [+]  " + std::to_string(HP) + " / " + std::to_string(maxHP);
	TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 11, health_line.c_str());
	//EndCheck();
	//CheckEvent(DMG_PWRUP);
	std::string damage_line = " [*]    " + std::to_string(damage);
	TCODConsole::root->print(INFO_MARGIN, PLAYER_ROW + 13, damage_line.c_str());
	//EndCheck();

	TCODConsole::root->print(BAR_MARGIN, PLAYER_ROW + 0, expBar.c_str());
	TCODConsole::root->print(BAR_MARGIN, PLAYER_ROW + 1, manaBar.c_str());
	TCODConsole::root->print(BAR_MARGIN, PLAYER_ROW + 11, healthBar.c_str());

	if (plr_copy != nullptr)
	{
		std::string prediction;
		if (plr_copy->IsAlive() && enemy_copy->IsAlive()) prediction = "SAFE";
		else if (plr_copy->IsDead() && enemy_copy->IsAlive()) prediction = "DEATH !!!";
		else if (plr_copy->IsAlive() && enemy_copy->IsDead()) prediction = "Victory!";
		TCODConsole::root->print(BAR_MARGIN, PLAYER_ROW + 13, prediction.c_str());
	}
}

void Display::DrawEnemyInfo()
{
	Monster * enemy = nullptr;
	if (_game->GetBattlefield()->GetEnemyCopy() != nullptr && _frame == Frames::FUTURE)
		enemy = _game->GetBattlefield()->GetEnemyCopy();

	else enemy = _game->GetPlayer()->GetTargetField()->GetEnemy();

	if (enemy != nullptr)
	{
		std::string name = enemy->GetName();
		uint8_t level = enemy->GetLevel();
		uint8_t damage = enemy->GetDamage();
		uint8_t HP = enemy->GetHP();
		uint8_t maxHP = enemy->GetMaxHP();
		std::string healthBar = DrawBar(HP, maxHP);

        std::string name_level_line = name + " - level " + std::to_string(level);
		TCODConsole::root->print(INFO_MARGIN, ENEMY_ROW + 0, name_level_line.c_str());

        std::string health_line = " [+]   " + std::to_string(HP) + " / " + std::to_string(maxHP);
		TCODConsole::root->print(INFO_MARGIN, ENEMY_ROW + 2, health_line.c_str());

        std::string damage_line = " [*]     " + std::to_string(damage);
		TCODConsole::root->print(INFO_MARGIN, ENEMY_ROW + 4, damage_line.c_str());

		TCODConsole::root->print(BAR_MARGIN, ENEMY_ROW + 2, healthBar.c_str());
	}
}

const char* Display::DrawField(uint8_t rowIndex, uint8_t colIndex) const
{
	Field *playerField = _game->GetPlayer()->GetPosition();
	Field *playerTarget = _game->GetPlayer()->GetTargetField();
	Field *field = _game->GetBattlefield()->GetField(rowIndex, colIndex);
    assert(field != nullptr);

	if (!field->IsVisible()) return ".\n";
	else
	{
		if (field->HaveEnemy())
	 	{
			if (field == playerTarget)
			{
				//BoldOn();
				//CheckEvent(MNSTR_HIT_1);
				//CheckEvent(MNSTR_HIT_2);
				if (field->GetEnemy()->GetLevel() == 10) return "Z\n";
				else return (std::to_string(field->GetEnemy()->GetLevel()) + "\n").c_str();
				//EndCheck();
				//BoldOff();
			}
			else
			{
				if (field->GetEnemy()->GetLevel() == 10) return "Z\n";
				else return (std::to_string(field->GetEnemy()->GetLevel()) + "\n").c_str();
			}
		}

		else if (field != playerField && field->HavePowerup())
		{
			switch (field->GetPowerup()->GetType())
			{
				case Powerups::HEALTH:
					return "+\n";
					break;

				case Powerups::MANA:
					return "x\n";
					break;

				case Powerups::DAMAGE:
					return "*\n";
			}
		}

		else if (field != playerField && field->HaveItem())
		{
			return "i\n";
		}

		else if (field == playerField && field->HaveItem())
		{
			// BoldOn();
			return "@\n";
			// BoldOff();
		}

		else if (field == playerField)
		{
			// CheckEvent(Events::LVLUP);
			// CheckEvent(PLR_HIT_1);
			// CheckEvent(PLR_HIT_2);
			return "@\n";
			// EndCheck();
		}

		else return " \n";
	}
    return "S\n";
}

void Display::ReduceCounters()
{
	uint8_t list_begin = static_cast<uint8_t>(Events::LVLUP);
	uint8_t list_end = static_cast<uint8_t>(Events::EVENTS_END);

	for (uint8_t event = list_begin; event < list_end; ++event)
		if (_frameCounters[event] > 0) --_frameCounters[event];
}

void Display::SwitchFrameType()
{
	_frame = (_frame == Frames::CURRENT ? Frames::FUTURE : Frames::CURRENT);
}

std::string Display::DrawBar(uint16_t current, uint16_t max) const
{
	uint16_t num;
	std::string result = "[";
	num = (current != 0 ? (uint16_t)( (double)current / max * BARWIDTH) : 0);
	for (uint16_t i = 0; i < num; ++i) result += '#';
	for (uint16_t i = 0; i < BARWIDTH - num; ++i) result += '.';
	result += ']';
	return result;
}

void Display::SendEvent(Events event)
{
    uint8_t num = static_cast<uint8_t>(event);
	_frameCounters[num] = EVENT_TIMERS[num];
}

void Display::CheckEvent(Events event)
{
/*	switch (event)
	{
		case Eve.ts::LVLUP:
		case HP_PWRUP:
		case MANA_PWRUP:
		case DMG_PWRUP:
			if (_frameCounters[event] > 0 && _frameCounters[event] % 2) BoldOn();
			break;
		case PLR_HIT//_1:
		case MNSTR_H//IT_1:
		case PLR_HIT_2:
		case MNSTR_HIT_2:
			if e\nf; //ameCounters[event] == 1) InvertOn()//;
			brea//k;

		case Events::EVENTS_END:;
	} */
}

void Display::ShowVictoryScreen()
{
/*	clear();
	TCODConsole::root->print(2,2,"Victory!");
	refresh(); */
}

void Display::ShowDefeatScreen()
{
/*	clear();
	TCODConsole::root->print(2,2,"DEFEAT !");
s	\nrfresh(); */
}<|endoftext|>


<commit_before>#include <memory>
#include <utility>
#include <vector>

#include "base_test.hpp"

#include "expression/binary_predicate_expression.hpp"
#include "expression/expression_functional.hpp"
#include "operators/get_table.hpp"
#include "operators/table_scan.hpp"
#include "scheduler/current_scheduler.hpp"
#include "scheduler/job_task.hpp"
#include "scheduler/node_queue_scheduler.hpp"
#include "scheduler/operator_task.hpp"
#include "scheduler/topology.hpp"
#include "storage/storage_manager.hpp"

using namespace opossum::expression_functional;  // NOLINT

namespace opossum {

class SchedulerTest : public BaseTest {
 protected:
  void stress_linear_dependencies(std::atomic_uint& counter) {
    auto task1 = std::make_shared<JobTask>([&]() {
      auto current_value = 0u;
      auto successful = counter.compare_exchange_strong(current_value, 1u);
      ASSERT_TRUE(successful);
    });
    auto task2 = std::make_shared<JobTask>([&]() {
      auto current_value = 1u;
      auto successful = counter.compare_exchange_strong(current_value, 2u);
      ASSERT_TRUE(successful);
    });
    auto task3 = std::make_shared<JobTask>([&]() {
      auto current_value = 2u;
      auto successful = counter.compare_exchange_strong(current_value, 3u);
      ASSERT_TRUE(successful);
    });

    task1->set_as_predecessor_of(task2);
    task2->set_as_predecessor_of(task3);

    task3->schedule();
    task1->schedule();
    task2->schedule();
  }

  void stress_multiple_dependencies(std::atomic_uint& counter) {
    auto task1 = std::make_shared<JobTask>([&]() { counter += 1u; });
    auto task2 = std::make_shared<JobTask>([&]() { counter += 2u; });
    auto task3 = std::make_shared<JobTask>([&]() {
      auto current_value = 3u;
      auto successful = counter.compare_exchange_strong(current_value, 4u);
      ASSERT_TRUE(successful);
    });

    task1->set_as_predecessor_of(task3);
    task2->set_as_predecessor_of(task3);

    task3->schedule();
    task1->schedule();
    task2->schedule();
  }

  void stress_diamond_dependencies(std::atomic_uint& counter) {
    auto task1 = std::make_shared<JobTask>([&]() {
      auto current_value = 0u;
      auto successful = counter.compare_exchange_strong(current_value, 1u);
      ASSERT_TRUE(successful);
    });
    auto task2 = std::make_shared<JobTask>([&]() { counter += 2u; });
    auto task3 = std::make_shared<JobTask>([&]() { counter += 3u; });
    auto task4 = std::make_shared<JobTask>([&]() {
      auto current_value = 6u;
      auto successful = counter.compare_exchange_strong(current_value, 7u);
      ASSERT_TRUE(successful);
    });

    task1->set_as_predecessor_of(task2);
    task1->set_as_predecessor_of(task3);
    task2->set_as_predecessor_of(task4);
    task3->set_as_predecessor_of(task4);

    task4->schedule();
    task3->schedule();
    task1->schedule();
    task2->schedule();
  }

  void increment_counter_in_subtasks(std::atomic_uint& counter) {
    std::vector<std::shared_ptr<AbstractTask>> tasks;
    for (size_t i = 0; i < 10; i++) {
      auto task = std::make_shared<JobTask>([&]() {
        std::vector<std::shared_ptr<AbstractTask>> jobs;
        for (size_t j = 0; j < 3; j++) {
          auto job = std::make_shared<JobTask>([&]() { counter++; });

          job->schedule();
          jobs.emplace_back(job);
        }

        CurrentScheduler::wait_for_tasks(jobs);
      });
      task->schedule();
      tasks.emplace_back(task);
    }
  }
};

/**
 * Schedule some tasks with subtasks, make sure all of them finish
 */
TEST_F(SchedulerTest, BasicTest) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  std::atomic_uint counter{0};

  increment_counter_in_subtasks(counter);

  CurrentScheduler::get()->finish();

  ASSERT_EQ(counter, 30u);

  CurrentScheduler::set(nullptr);
}

TEST_F(SchedulerTest, BasicTestWithoutScheduler) {
  std::atomic_uint counter{0};
  increment_counter_in_subtasks(counter);
  ASSERT_EQ(counter, 30u);
}

TEST_F(SchedulerTest, LinearDependenciesWithScheduler) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  std::atomic_uint counter{0u};

  stress_linear_dependencies(counter);

  CurrentScheduler::get()->finish();

  ASSERT_EQ(counter, 3u);
}

TEST_F(SchedulerTest, MultipleDependenciesWithScheduler) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  std::atomic_uint counter{0u};

  stress_multiple_dependencies(counter);

  CurrentScheduler::get()->finish();

  ASSERT_EQ(counter, 4u);
}

TEST_F(SchedulerTest, DiamondDependenciesWithScheduler) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  std::atomic_uint counter{0};

  stress_diamond_dependencies(counter);

  CurrentScheduler::get()->finish();

  ASSERT_EQ(counter, 7u);
}

TEST_F(SchedulerTest, LinearDependenciesWithoutScheduler) {
  std::atomic_uint counter{0u};
  stress_linear_dependencies(counter);
  ASSERT_EQ(counter, 3u);
}

TEST_F(SchedulerTest, MultipleDependenciesWithoutScheduler) {
  std::atomic_uint counter{0u};
  stress_multiple_dependencies(counter);
  ASSERT_EQ(counter, 4u);
}

TEST_F(SchedulerTest, DiamondDependenciesWithoutScheduler) {
  std::atomic_uint counter{0};
  stress_diamond_dependencies(counter);
  ASSERT_EQ(counter, 7u);
}

TEST_F(SchedulerTest, MultipleOperators) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  auto test_table = load_table("src/test/tables/int_float.tbl", 2);
  StorageManager::get().add_table("table", test_table);

  auto gt = std::make_shared<GetTable>("table");
  auto a = PQPColumnExpression::from_table(*test_table, ColumnID{0});
  auto ts = std::make_shared<TableScan>(gt, greater_than_equals_(a, 1234));

  auto gt_task = std::make_shared<OperatorTask>(gt, CleanupTemporaries::Yes);
  auto ts_task = std::make_shared<OperatorTask>(ts, CleanupTemporaries::Yes);
  gt_task->set_as_predecessor_of(ts_task);

  gt_task->schedule();
  ts_task->schedule();

  CurrentScheduler::get()->finish();

  auto expected_result = load_table("src/test/tables/int_float_filtered2.tbl", 1);
  EXPECT_TABLE_EQ_UNORDERED(ts->get_output(), expected_result);
}

TEST_F(SchedulerTest, VerifyTaskQueueSetup) {
  Topology::use_non_numa_topology(8);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());
  EXPECT_EQ(1, CurrentScheduler::get()->queues().size());

  Topology::use_fake_numa_topology(8);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());
  EXPECT_EQ(8, CurrentScheduler::get()->queues().size());

  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());
  EXPECT_EQ(2, CurrentScheduler::get()->queues().size());

  Topology::use_fake_numa_topology(8, 8);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());
  EXPECT_EQ(1, CurrentScheduler::get()->queues().size());

  CurrentScheduler::get()->finish();
}

TEST_F(SchedulerTest, SingleWorkerGuaranteeProgress) {
  Topology::use_default_topology(1);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  auto task_done = false;
  auto task = std::make_shared<JobTask>([&task_done]() {
    auto subtask = std::make_shared<JobTask>([&task_done]() { task_done = true; });

    subtask->schedule();
    CurrentScheduler::wait_for_tasks(std::vector<std::shared_ptr<AbstractTask>>{subtask});
  });

  task->schedule();
  CurrentScheduler::wait_for_tasks(std::vector<std::shared_ptr<AbstractTask>>{task});
  EXPECT_TRUE(task_done);

  CurrentScheduler::get()->finish();
}

}  // namespace opossum
<commit_msg>Only build a topology of at most 4 nodes, so that it works on 4-core-machines (#1339)<commit_after>#include <memory>
#include <utility>
#include <vector>

#include "base_test.hpp"

#include "expression/binary_predicate_expression.hpp"
#include "expression/expression_functional.hpp"
#include "operators/get_table.hpp"
#include "operators/table_scan.hpp"
#include "scheduler/current_scheduler.hpp"
#include "scheduler/job_task.hpp"
#include "scheduler/node_queue_scheduler.hpp"
#include "scheduler/operator_task.hpp"
#include "scheduler/topology.hpp"
#include "storage/storage_manager.hpp"

using namespace opossum::expression_functional;  // NOLINT

namespace opossum {

class SchedulerTest : public BaseTest {
 protected:
  void stress_linear_dependencies(std::atomic_uint& counter) {
    auto task1 = std::make_shared<JobTask>([&]() {
      auto current_value = 0u;
      auto successful = counter.compare_exchange_strong(current_value, 1u);
      ASSERT_TRUE(successful);
    });
    auto task2 = std::make_shared<JobTask>([&]() {
      auto current_value = 1u;
      auto successful = counter.compare_exchange_strong(current_value, 2u);
      ASSERT_TRUE(successful);
    });
    auto task3 = std::make_shared<JobTask>([&]() {
      auto current_value = 2u;
      auto successful = counter.compare_exchange_strong(current_value, 3u);
      ASSERT_TRUE(successful);
    });

    task1->set_as_predecessor_of(task2);
    task2->set_as_predecessor_of(task3);

    task3->schedule();
    task1->schedule();
    task2->schedule();
  }

  void stress_multiple_dependencies(std::atomic_uint& counter) {
    auto task1 = std::make_shared<JobTask>([&]() { counter += 1u; });
    auto task2 = std::make_shared<JobTask>([&]() { counter += 2u; });
    auto task3 = std::make_shared<JobTask>([&]() {
      auto current_value = 3u;
      auto successful = counter.compare_exchange_strong(current_value, 4u);
      ASSERT_TRUE(successful);
    });

    task1->set_as_predecessor_of(task3);
    task2->set_as_predecessor_of(task3);

    task3->schedule();
    task1->schedule();
    task2->schedule();
  }

  void stress_diamond_dependencies(std::atomic_uint& counter) {
    auto task1 = std::make_shared<JobTask>([&]() {
      auto current_value = 0u;
      auto successful = counter.compare_exchange_strong(current_value, 1u);
      ASSERT_TRUE(successful);
    });
    auto task2 = std::make_shared<JobTask>([&]() { counter += 2u; });
    auto task3 = std::make_shared<JobTask>([&]() { counter += 3u; });
    auto task4 = std::make_shared<JobTask>([&]() {
      auto current_value = 6u;
      auto successful = counter.compare_exchange_strong(current_value, 7u);
      ASSERT_TRUE(successful);
    });

    task1->set_as_predecessor_of(task2);
    task1->set_as_predecessor_of(task3);
    task2->set_as_predecessor_of(task4);
    task3->set_as_predecessor_of(task4);

    task4->schedule();
    task3->schedule();
    task1->schedule();
    task2->schedule();
  }

  void increment_counter_in_subtasks(std::atomic_uint& counter) {
    std::vector<std::shared_ptr<AbstractTask>> tasks;
    for (size_t i = 0; i < 10; i++) {
      auto task = std::make_shared<JobTask>([&]() {
        std::vector<std::shared_ptr<AbstractTask>> jobs;
        for (size_t j = 0; j < 3; j++) {
          auto job = std::make_shared<JobTask>([&]() { counter++; });

          job->schedule();
          jobs.emplace_back(job);
        }

        CurrentScheduler::wait_for_tasks(jobs);
      });
      task->schedule();
      tasks.emplace_back(task);
    }
  }
};

/**
 * Schedule some tasks with subtasks, make sure all of them finish
 */
TEST_F(SchedulerTest, BasicTest) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  std::atomic_uint counter{0};

  increment_counter_in_subtasks(counter);

  CurrentScheduler::get()->finish();

  ASSERT_EQ(counter, 30u);

  CurrentScheduler::set(nullptr);
}

TEST_F(SchedulerTest, BasicTestWithoutScheduler) {
  std::atomic_uint counter{0};
  increment_counter_in_subtasks(counter);
  ASSERT_EQ(counter, 30u);
}

TEST_F(SchedulerTest, LinearDependenciesWithScheduler) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  std::atomic_uint counter{0u};

  stress_linear_dependencies(counter);

  CurrentScheduler::get()->finish();

  ASSERT_EQ(counter, 3u);
}

TEST_F(SchedulerTest, MultipleDependenciesWithScheduler) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  std::atomic_uint counter{0u};

  stress_multiple_dependencies(counter);

  CurrentScheduler::get()->finish();

  ASSERT_EQ(counter, 4u);
}

TEST_F(SchedulerTest, DiamondDependenciesWithScheduler) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  std::atomic_uint counter{0};

  stress_diamond_dependencies(counter);

  CurrentScheduler::get()->finish();

  ASSERT_EQ(counter, 7u);
}

TEST_F(SchedulerTest, LinearDependenciesWithoutScheduler) {
  std::atomic_uint counter{0u};
  stress_linear_dependencies(counter);
  ASSERT_EQ(counter, 3u);
}

TEST_F(SchedulerTest, MultipleDependenciesWithoutScheduler) {
  std::atomic_uint counter{0u};
  stress_multiple_dependencies(counter);
  ASSERT_EQ(counter, 4u);
}

TEST_F(SchedulerTest, DiamondDependenciesWithoutScheduler) {
  std::atomic_uint counter{0};
  stress_diamond_dependencies(counter);
  ASSERT_EQ(counter, 7u);
}

TEST_F(SchedulerTest, MultipleOperators) {
  Topology::use_fake_numa_topology(8, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  auto test_table = load_table("src/test/tables/int_float.tbl", 2);
  StorageManager::get().add_table("table", test_table);

  auto gt = std::make_shared<GetTable>("table");
  auto a = PQPColumnExpression::from_table(*test_table, ColumnID{0});
  auto ts = std::make_shared<TableScan>(gt, greater_than_equals_(a, 1234));

  auto gt_task = std::make_shared<OperatorTask>(gt, CleanupTemporaries::Yes);
  auto ts_task = std::make_shared<OperatorTask>(ts, CleanupTemporaries::Yes);
  gt_task->set_as_predecessor_of(ts_task);

  gt_task->schedule();
  ts_task->schedule();

  CurrentScheduler::get()->finish();

  auto expected_result = load_table("src/test/tables/int_float_filtered2.tbl", 1);
  EXPECT_TABLE_EQ_UNORDERED(ts->get_output(), expected_result);
}

TEST_F(SchedulerTest, VerifyTaskQueueSetup) {
  Topology::use_non_numa_topology(4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());
  EXPECT_EQ(1, CurrentScheduler::get()->queues().size());

  Topology::use_fake_numa_topology(4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());
  EXPECT_EQ(4, CurrentScheduler::get()->queues().size());

  Topology::use_fake_numa_topology(4, 2);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());
  EXPECT_EQ(2, CurrentScheduler::get()->queues().size());

  Topology::use_fake_numa_topology(4, 4);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());
  EXPECT_EQ(1, CurrentScheduler::get()->queues().size());

  CurrentScheduler::get()->finish();
}

TEST_F(SchedulerTest, SingleWorkerGuaranteeProgress) {
  Topology::use_default_topology(1);
  CurrentScheduler::set(std::make_shared<NodeQueueScheduler>());

  auto task_done = false;
  auto task = std::make_shared<JobTask>([&task_done]() {
    auto subtask = std::make_shared<JobTask>([&task_done]() { task_done = true; });

    subtask->schedule();
    CurrentScheduler::wait_for_tasks(std::vector<std::shared_ptr<AbstractTask>>{subtask});
  });

  task->schedule();
  CurrentScheduler::wait_for_tasks(std::vector<std::shared_ptr<AbstractTask>>{task});
  EXPECT_TRUE(task_done);

  CurrentScheduler::get()->finish();
}

}  // namespace opossum
<|endoftext|>


<commit_before>#include <yuni/yuni.h>
#include <yuni/io/file.h>
#include <yuni/core/system/console.h>
#include <yuni/core/getopt.h>
#include "details/grammar/nany.h"
#include <iostream>
#include <vector>

using namespace Yuni;

#ifndef NANY_VERSION
#error define NANY_VERSION is missing
#endif

#define likely(X)    YUNI_LIKELY(X)
#define unlikely(X)  YUNI_UNLIKELY(X)

namespace {

bool printAST(const AnyString filename, bool unixcolors) {
	if (filename.empty())
		return false;
	ny::AST::Parser parser;
	bool success = parser.loadFromFile(filename);
	if (parser.root != nullptr) { // the AST might be empty
		Clob out;
		ny::AST::Node::Export(out, *parser.root, unixcolors);
		std::cout.write(out.c_str(), out.size());
	}
	return success;
}

int printVersion() {
	assert(strlen(YUNI_STRINGIZE(NANY_VERSION)) >= 5 and "empty version");
	std::cout << YUNI_STRINGIZE(NANY_VERSION) << '\n';
	return EXIT_SUCCESS;
}

} // namespace

int main(int argc, char** argv) {
	// all input filenames
	std::vector<String> filenames;
	// no colors
	bool noColors = false;
	// parse the command
	{
		// The command line options parser
		GetOpt::Parser options;
		// Input files
		options.add(filenames, 'i', "input", "Input files (or folders)");
		options.remainingArguments(filenames);
		// OUTPUT
		options.addParagraph("\nOutput\n");
		// --no-color
		options.addFlag(noColors, ' ', "no-color", "Disable color output");
		// HELP
		// help
		options.addParagraph("\nHelp\n");
		// version
		bool optVersion = false;
		options.addFlag(optVersion, ' ', "version", "Display the version of the compiler and exit");
		// Ask to the parser to parse the command line
		if (not options(argc, argv)) {
			// The program should not continue here
			// The user may have requested the help or an error has happened
			// If an error has happened, the exit status should be different from 0
			if (options.errors()) {
				std::cerr << "Abort due to error\n";
				return EXIT_FAILURE;
			}
			return EXIT_SUCCESS;
		}
		if (unlikely(optVersion))
			return printVersion();
		if (unlikely(filenames.empty())) {
			std::cerr << argv[0] << ": no input file\n";
			return EXIT_FAILURE;
		}
	}
	// colors
	bool withColors = ((not noColors) and System::Console::IsStdoutTTY());
	bool success = true;
	for (auto& path: filenames)
		success &= printAST(path, withColors);
	return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
<commit_msg>misc: coding style dump-ast<commit_after>#include <yuni/yuni.h>
#include <yuni/io/file.h>
#include <yuni/core/system/console.h>
#include <yuni/core/getopt.h>
#include "details/grammar/nany.h"
#include <iostream>
#include <vector>

using namespace Yuni;

#ifndef NANY_VERSION
#error define NANY_VERSION is missing
#endif

#define likely(X)    YUNI_LIKELY(X)
#define unlikely(X)  YUNI_UNLIKELY(X)

namespace {

bool printAST(const AnyString filename, bool unixcolors) {
	if (filename.empty())
		return false;
	ny::AST::Parser parser;
	bool success = parser.loadFromFile(filename);
	if (parser.root != nullptr) { // the AST might be empty
		Clob out;
		ny::AST::Node::Export(out, *parser.root, unixcolors);
		std::cout.write(out.c_str(), out.size());
	}
	return success;
}

int printVersion() {
	assert(strlen(YUNI_STRINGIZE(NANY_VERSION)) >= 5 and "empty version");
	std::cout << YUNI_STRINGIZE(NANY_VERSION) << '\n';
	return EXIT_SUCCESS;
}

} // namespace

int main(int argc, char** argv) {
	// all input filenames
	std::vector<String> filenames;
	// no colors
	bool noColors = false;
	// parse the command
	{
		// The command line options parser
		GetOpt::Parser options;
		// Input files
		options.add(filenames, 'i', "input", "Input files (or folders)");
		options.remainingArguments(filenames);
		// OUTPUT
		options.addParagraph("\nOutput\n");
		// --no-color
		options.addFlag(noColors, ' ', "no-color", "Disable color output");
		// HELP
		// help
		options.addParagraph("\nHelp\n");
		// version
		bool optVersion = false;
		options.addFlag(optVersion, ' ', "version", "Display the version of the compiler and exit");
		// Ask to the parser to parse the command line
		if (not options(argc, argv)) {
			// The program should not continue here
			// The user may have requested the help or an error has happened
			// If an error has happened, the exit status should be different from 0
			if (options.errors()) {
				std::cerr << "Abort due to error\n";
				return EXIT_FAILURE;
			}
			return EXIT_SUCCESS;
		}
		if (unlikely(optVersion))
			return printVersion();
		if (unlikely(filenames.empty())) {
			std::cerr << argv[0] << ": no input file\n";
			return EXIT_FAILURE;
		}
	}
	// colors
	bool withColors = ((not noColors) and System::Console::IsStdoutTTY());
	bool success = true;
	for (auto& path : filenames)
		success &= printAST(path, withColors);
	return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
<|endoftext|>