<commit_before>/*
 * Copyright (C) 2017 Ben Smith
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 */
#include "host-ui.h"

#include "host.h"
#include "host-gl.h"
#include "imgui.h"

/* Much cribbed from imgui_impl_sdl_gl3.cpp. */

struct HostUI {
  HostUI(SDL_Window*);
  ~HostUI();

  Result init();
  Result init_gl();
  void init_font();
  void event(union SDL_Event*);
  void upload_frame_buffer(FrameBuffer*);
  void render_draw_lists(ImDrawData*);
  void begin_frame();
  void end_frame();

  static void render_draw_lists_thunk(ImDrawData*);
  static void set_clipboard_text(void* user_data, const char* text);
  static const char* get_clipboard_text(void* user_data);

  SDL_Window* window;
  f64 time_sec;
  f32 mouse_wheel;
  f32 mouse_pressed[3];
  f32 proj_matrix[9];
  GLuint font_texture;
  GLuint vao;
  GLuint vbo;
  GLuint ebo;
  GLuint program;
  GLint uProjMatrix;
  GLint uSampler;

  // Global so it can be accessed by render_draw_lists callback, which has no
  // user_data pointer.
  static HostUI* s_ui;
};

HostUI* HostUI::s_ui;

HostUI::HostUI(SDL_Window* window)
    : window(window),
      time_sec(0),
      mouse_wheel(0),
      font_texture(0),
      vao(0),
      vbo(0),
      ebo(0),
      program(0),
      uProjMatrix(0),
      uSampler(0) {
  s_ui = this;
}

HostUI::~HostUI() {
  s_ui = nullptr;
}

Result HostUI::init() {
  if (!SUCCESS(init_gl())) {
    return ERROR;
  }

  init_font();

  ImGuiIO& io = ImGui::GetIO();
  io.DisplaySize.x = 0;
  io.DisplaySize.y = 0;
  io.KeyMap[ImGuiKey_Tab] = SDLK_TAB;
  io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
  io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
  io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
  io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
  io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
  io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
  io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
  io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
  io.KeyMap[ImGuiKey_Delete] = SDLK_DELETE;
  io.KeyMap[ImGuiKey_Backspace] = SDLK_BACKSPACE;
  io.KeyMap[ImGuiKey_Enter] = SDLK_RETURN;
  io.KeyMap[ImGuiKey_Escape] = SDLK_ESCAPE;
  io.KeyMap[ImGuiKey_A] = SDLK_a;
  io.KeyMap[ImGuiKey_C] = SDLK_c;
  io.KeyMap[ImGuiKey_V] = SDLK_v;
  io.KeyMap[ImGuiKey_X] = SDLK_x;
  io.KeyMap[ImGuiKey_Y] = SDLK_y;
  io.KeyMap[ImGuiKey_Z] = SDLK_z;

  io.RenderDrawListsFn = render_draw_lists_thunk;
  io.SetClipboardTextFn = set_clipboard_text;
  io.GetClipboardTextFn = get_clipboard_text;
  io.ClipboardUserData = nullptr;
  return OK;
}

Result HostUI::init_gl() {
  static const char* s_vertex_shader =
      "attribute vec2 aPos;\n"
      "attribute vec2 aUV;\n"
      "attribute vec4 aColor;\n"
      "varying vec2 vUV;\n"
      "varying vec4 vColor;\n"
      "uniform mat3 uProjMatrix;\n"
      "void main(void) {\n"
      "  gl_Position = vec4(uProjMatrix * vec3(aPos, 1.0), 1.0);\n"
      "  vUV = aUV;\n"
      "  vColor = aColor;\n"
      "}\n";

  static const char* s_fragment_shader =
      "varying vec2 vUV;\n"
      "varying vec4 vColor;\n"
      "uniform sampler2D uSampler;\n"
      "void main(void) {\n"
      "  gl_FragColor = vColor * texture2D(uSampler, vUV);\n"
      "}\n";

  glGenBuffers(1, &vbo);
  glGenBuffers(1, &ebo);

  GLuint vs, fs;
  if (!SUCCESS(host_gl_shader(GL_VERTEX_SHADER, s_vertex_shader, &vs)) ||
      !SUCCESS(host_gl_shader(GL_FRAGMENT_SHADER, s_fragment_shader, &fs)) ||
      !SUCCESS(host_gl_program(vs, fs, &program))) {
    return ERROR;
  }

  GLint aPos = glGetAttribLocation(program, "aPos");
  GLint aUV = glGetAttribLocation(program, "aUV");
  GLint aColor = glGetAttribLocation(program, "aColor");
  uProjMatrix = glGetUniformLocation(program, "uProjMatrix");
  uSampler = glGetUniformLocation(program, "uSampler");

  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glEnableVertexAttribArray(aPos);
  glEnableVertexAttribArray(aUV);
  glEnableVertexAttribArray(aColor);
  glVertexAttribPointer(aPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert),
                        (void*)offsetof(ImDrawVert, pos));
  glVertexAttribPointer(aUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert),
                        (void*)offsetof(ImDrawVert, uv));
  glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, GL_TRUE,
                        sizeof(ImDrawVert), (void*)offsetof(ImDrawVert, col));

  return OK;
}

void HostUI::init_font() {
  ImGuiIO& io = ImGui::GetIO();

  // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be
  // compatible with user's existing shader.
  unsigned char* pixels;
  int width, height;
  io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);

  // Upload texture to graphics system
  glGenTextures(1, &font_texture);
  glBindTexture(GL_TEXTURE_2D, font_texture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
               GL_UNSIGNED_BYTE, pixels);

  // Store our identifier
  io.Fonts->TexID = (void*)(intptr_t)font_texture;
}

void HostUI::event(union SDL_Event* event) {
  ImGuiIO& io = ImGui::GetIO();
  switch (event->type) {
    case SDL_WINDOWEVENT:
      switch (event->window.event) {
        case SDL_WINDOWEVENT_RESIZED: {
          ImGuiIO& io = ImGui::GetIO();

          f32 w = event->window.data1;
          f32 h = event->window.data2;
          int display_w, display_h;
          SDL_GL_GetDrawableSize(window, &display_w, &display_h);
          io.DisplaySize = ImVec2(w, h);
          io.DisplayFramebufferScale =
              ImVec2(w > 0 ? (display_w / w) : 0, h > 0 ? (display_h / h) : 0);

          memset(proj_matrix, 0, sizeof(proj_matrix));
          proj_matrix[0] = 2.0f / w;
          proj_matrix[4] = -2.0f / h;
          proj_matrix[6] = -1.0f;
          proj_matrix[7] = 1.0f;
          proj_matrix[8] = 1.0f;
          break;
        }
      }
      break;
    case SDL_MOUSEWHEEL:
      if (event->wheel.y > 0) mouse_wheel = 1;
      if (event->wheel.y < 0) mouse_wheel = -1;
      break;
    case SDL_MOUSEBUTTONDOWN:
      if (event->button.button == SDL_BUTTON_LEFT) mouse_pressed[0] = true;
      if (event->button.button == SDL_BUTTON_RIGHT) mouse_pressed[1] = true;
      if (event->button.button == SDL_BUTTON_MIDDLE) mouse_pressed[2] = true;
      break;
    case SDL_TEXTINPUT:
      io.AddInputCharactersUTF8(event->text.text);
      break;
    case SDL_KEYDOWN:
    case SDL_KEYUP: {
      int key = event->key.keysym.sym & ~SDLK_SCANCODE_MASK;
      io.KeysDown[key] = (event->type == SDL_KEYDOWN);
      io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
      io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
      io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
      io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
      break;
    }
  }
}

void HostUI::begin_frame() {
  ImGuiIO& io = ImGui::GetIO();

  // Setup time step
  f64 now_sec = SDL_GetTicks() / 1000.0;
  io.DeltaTime = (f32)(time_sec ? now_sec - time_sec : 1.0 / 60.0);
  time_sec = now_sec;

  // Setup inputs (we already got mouse wheel, keyboard keys & characters from
  // SDL_PollEvent())
  int mx, my;
  Uint32 mouse_mask = SDL_GetMouseState(&mx, &my);
  if (SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_FOCUS) {
    // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen,
    // etc.)
    io.MousePos = ImVec2((f32)mx, (f32)my);
  } else {
    io.MousePos = ImVec2(-1, -1);
  }

  // If a mouse press event came, always pass it as "mouse held this frame", so
  // we don't miss click-release events that are shorter than 1 frame.
  io.MouseDown[0] =
      mouse_pressed[0] || (mouse_mask & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
  io.MouseDown[1] =
      mouse_pressed[1] || (mouse_mask & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
  io.MouseDown[2] =
      mouse_pressed[2] || (mouse_mask & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
  mouse_pressed[0] = mouse_pressed[1] = mouse_pressed[2] = false;

  io.MouseWheel = mouse_wheel;
  mouse_wheel = 0.0f;

  SDL_ShowCursor(io.MouseDrawCursor ? 0 : 1);
  ImGui::NewFrame();
}

void HostUI::end_frame() {
  ImGuiIO& io = ImGui::GetIO();
  glViewport(0, 0, io.DisplaySize.x, io.DisplaySize.y);
  glClearColor(0.1f, 0.1f, 0.1f, 1);
  glClear(GL_COLOR_BUFFER_BIT);
  ImGui::Render();
  SDL_GL_SwapWindow(window);
}

void HostUI::render_draw_lists_thunk(ImDrawData* draw_data) {
  s_ui->render_draw_lists(draw_data);
}

void HostUI::render_draw_lists(ImDrawData* draw_data) {
  ImGuiIO& io = ImGui::GetIO();
  int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
  int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
  if (fb_width == 0 || fb_height == 0) {
    return;
  }

  draw_data->ScaleClipRects(io.DisplayFramebufferScale);

  glEnable(GL_BLEND);
  glBlendEquation(GL_FUNC_ADD);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glDisable(GL_CULL_FACE);
  glDisable(GL_DEPTH_TEST);
  glEnable(GL_SCISSOR_TEST);
  glActiveTexture(GL_TEXTURE0);

  glUseProgram(program);
  glUniform1i(uSampler, 0);
  glUniformMatrix3fv(uProjMatrix, 1, GL_FALSE, proj_matrix);
  glBindVertexArray(vao);

  for (int n = 0; n < draw_data->CmdListsCount; n++) {
    const ImDrawList* cmd_list = draw_data->CmdLists[n];
    const ImDrawIdx* idx_buffer_offset = 0;

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER,
                 (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert),
                 (GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                 (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx),
                 (GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);

    for (int i = 0; i < cmd_list->CmdBuffer.Size; i++) {
      const ImDrawCmd* cmd = &cmd_list->CmdBuffer[i];
      if (cmd->UserCallback) {
        cmd->UserCallback(cmd_list, cmd);
      } else {
        glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)cmd->TextureId);
        glScissor((int)cmd->ClipRect.x, (int)(fb_height - cmd->ClipRect.w),
                  (int)(cmd->ClipRect.z - cmd->ClipRect.x),
                  (int)(cmd->ClipRect.w - cmd->ClipRect.y));
        glDrawElements(
            GL_TRIANGLES, (GLsizei)cmd->ElemCount,
            sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
            idx_buffer_offset);
      }
      idx_buffer_offset += cmd->ElemCount;
    }
  }

  glDisable(GL_SCISSOR_TEST);
  glDisable(GL_BLEND);
}

void HostUI::set_clipboard_text(void* user_data, const char* text) {
  SDL_SetClipboardText(text);
}

const char* HostUI::get_clipboard_text(void* user_data) {
  return SDL_GetClipboardText();
}

HostUI* host_ui_new(struct SDL_Window* window) {
  HostUI* ui = new HostUI(window);
  if (!SUCCESS(ui->init())) {
    delete ui;
    return nullptr;
  }

  return ui;
}

void host_ui_delete(struct HostUI* ui) {
  delete ui;
}

void host_ui_event(struct HostUI* ui, union SDL_Event* event) {
  ui->event(event);
}

void host_ui_begin_frame(HostUI* ui, HostTexture* fb_texture) {
  ui->begin_frame();
}

void host_ui_end_frame(HostUI* ui) {
  ui->end_frame();
}
<commit_msg>Fix build on AppVeyor<commit_after>/*
 * Copyright (C) 2017 Ben Smith
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 */
#include "host-ui.h"

#include "host.h"
#include "host-gl.h"
#include "imgui.h"

/* This seems to be defined by MSVC. */
#undef ERROR

/* Much cribbed from imgui_impl_sdl_gl3.cpp. */

struct HostUI {
  HostUI(SDL_Window*);
  ~HostUI();

  Result init();
  Result init_gl();
  void init_font();
  void event(union SDL_Event*);
  void upload_frame_buffer(FrameBuffer*);
  void render_draw_lists(ImDrawData*);
  void begin_frame();
  void end_frame();

  static void render_draw_lists_thunk(ImDrawData*);
  static void set_clipboard_text(void* user_data, const char* text);
  static const char* get_clipboard_text(void* user_data);

  SDL_Window* window;
  f64 time_sec;
  f32 mouse_wheel;
  f32 mouse_pressed[3];
  f32 proj_matrix[9];
  GLuint font_texture;
  GLuint vao;
  GLuint vbo;
  GLuint ebo;
  GLuint program;
  GLint uProjMatrix;
  GLint uSampler;

  // Global so it can be accessed by render_draw_lists callback, which has no
  // user_data pointer.
  static HostUI* s_ui;
};

HostUI* HostUI::s_ui;

HostUI::HostUI(SDL_Window* window)
    : window(window),
      time_sec(0),
      mouse_wheel(0),
      font_texture(0),
      vao(0),
      vbo(0),
      ebo(0),
      program(0),
      uProjMatrix(0),
      uSampler(0) {
  s_ui = this;
}

HostUI::~HostUI() {
  s_ui = nullptr;
}

Result HostUI::init() {
  if (!SUCCESS(init_gl())) {
    return ERROR;
  }

  init_font();

  ImGuiIO& io = ImGui::GetIO();
  io.DisplaySize.x = 0;
  io.DisplaySize.y = 0;
  io.KeyMap[ImGuiKey_Tab] = SDLK_TAB;
  io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
  io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
  io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
  io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
  io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
  io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
  io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
  io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
  io.KeyMap[ImGuiKey_Delete] = SDLK_DELETE;
  io.KeyMap[ImGuiKey_Backspace] = SDLK_BACKSPACE;
  io.KeyMap[ImGuiKey_Enter] = SDLK_RETURN;
  io.KeyMap[ImGuiKey_Escape] = SDLK_ESCAPE;
  io.KeyMap[ImGuiKey_A] = SDLK_a;
  io.KeyMap[ImGuiKey_C] = SDLK_c;
  io.KeyMap[ImGuiKey_V] = SDLK_v;
  io.KeyMap[ImGuiKey_X] = SDLK_x;
  io.KeyMap[ImGuiKey_Y] = SDLK_y;
  io.KeyMap[ImGuiKey_Z] = SDLK_z;

  io.RenderDrawListsFn = render_draw_lists_thunk;
  io.SetClipboardTextFn = set_clipboard_text;
  io.GetClipboardTextFn = get_clipboard_text;
  io.ClipboardUserData = nullptr;
  return OK;
}

Result HostUI::init_gl() {
  static const char* s_vertex_shader =
      "attribute vec2 aPos;\n"
      "attribute vec2 aUV;\n"
      "attribute vec4 aColor;\n"
      "varying vec2 vUV;\n"
      "varying vec4 vColor;\n"
      "uniform mat3 uProjMatrix;\n"
      "void main(void) {\n"
      "  gl_Position = vec4(uProjMatrix * vec3(aPos, 1.0), 1.0);\n"
      "  vUV = aUV;\n"
      "  vColor = aColor;\n"
      "}\n";

  static const char* s_fragment_shader =
      "varying vec2 vUV;\n"
      "varying vec4 vColor;\n"
      "uniform sampler2D uSampler;\n"
      "void main(void) {\n"
      "  gl_FragColor = vColor * texture2D(uSampler, vUV);\n"
      "}\n";

  glGenBuffers(1, &vbo);
  glGenBuffers(1, &ebo);

  GLuint vs, fs;
  if (!SUCCESS(host_gl_shader(GL_VERTEX_SHADER, s_vertex_shader, &vs)) ||
      !SUCCESS(host_gl_shader(GL_FRAGMENT_SHADER, s_fragment_shader, &fs)) ||
      !SUCCESS(host_gl_program(vs, fs, &program))) {
    return ERROR;
  }

  GLint aPos = glGetAttribLocation(program, "aPos");
  GLint aUV = glGetAttribLocation(program, "aUV");
  GLint aColor = glGetAttribLocation(program, "aColor");
  uProjMatrix = glGetUniformLocation(program, "uProjMatrix");
  uSampler = glGetUniformLocation(program, "uSampler");

  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glEnableVertexAttribArray(aPos);
  glEnableVertexAttribArray(aUV);
  glEnableVertexAttribArray(aColor);
  glVertexAttribPointer(aPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert),
                        (void*)offsetof(ImDrawVert, pos));
  glVertexAttribPointer(aUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert),
                        (void*)offsetof(ImDrawVert, uv));
  glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, GL_TRUE,
                        sizeof(ImDrawVert), (void*)offsetof(ImDrawVert, col));

  return OK;
}

void HostUI::init_font() {
  ImGuiIO& io = ImGui::GetIO();

  // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be
  // compatible with user's existing shader.
  unsigned char* pixels;
  int width, height;
  io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);

  // Upload texture to graphics system
  glGenTextures(1, &font_texture);
  glBindTexture(GL_TEXTURE_2D, font_texture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
               GL_UNSIGNED_BYTE, pixels);

  // Store our identifier
  io.Fonts->TexID = (void*)(intptr_t)font_texture;
}

void HostUI::event(union SDL_Event* event) {
  ImGuiIO& io = ImGui::GetIO();
  switch (event->type) {
    case SDL_WINDOWEVENT:
      switch (event->window.event) {
        case SDL_WINDOWEVENT_RESIZED: {
          ImGuiIO& io = ImGui::GetIO();

          f32 w = event->window.data1;
          f32 h = event->window.data2;
          int display_w, display_h;
          SDL_GL_GetDrawableSize(window, &display_w, &display_h);
          io.DisplaySize = ImVec2(w, h);
          io.DisplayFramebufferScale =
              ImVec2(w > 0 ? (display_w / w) : 0, h > 0 ? (display_h / h) : 0);

          memset(proj_matrix, 0, sizeof(proj_matrix));
          proj_matrix[0] = 2.0f / w;
          proj_matrix[4] = -2.0f / h;
          proj_matrix[6] = -1.0f;
          proj_matrix[7] = 1.0f;
          proj_matrix[8] = 1.0f;
          break;
        }
      }
      break;
    case SDL_MOUSEWHEEL:
      if (event->wheel.y > 0) mouse_wheel = 1;
      if (event->wheel.y < 0) mouse_wheel = -1;
      break;
    case SDL_MOUSEBUTTONDOWN:
      if (event->button.button == SDL_BUTTON_LEFT) mouse_pressed[0] = true;
      if (event->button.button == SDL_BUTTON_RIGHT) mouse_pressed[1] = true;
      if (event->button.button == SDL_BUTTON_MIDDLE) mouse_pressed[2] = true;
      break;
    case SDL_TEXTINPUT:
      io.AddInputCharactersUTF8(event->text.text);
      break;
    case SDL_KEYDOWN:
    case SDL_KEYUP: {
      int key = event->key.keysym.sym & ~SDLK_SCANCODE_MASK;
      io.KeysDown[key] = (event->type == SDL_KEYDOWN);
      io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
      io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
      io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
      io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
      break;
    }
  }
}

void HostUI::begin_frame() {
  ImGuiIO& io = ImGui::GetIO();

  // Setup time step
  f64 now_sec = SDL_GetTicks() / 1000.0;
  io.DeltaTime = (f32)(time_sec ? now_sec - time_sec : 1.0 / 60.0);
  time_sec = now_sec;

  // Setup inputs (we already got mouse wheel, keyboard keys & characters from
  // SDL_PollEvent())
  int mx, my;
  Uint32 mouse_mask = SDL_GetMouseState(&mx, &my);
  if (SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_FOCUS) {
    // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen,
    // etc.)
    io.MousePos = ImVec2((f32)mx, (f32)my);
  } else {
    io.MousePos = ImVec2(-1, -1);
  }

  // If a mouse press event came, always pass it as "mouse held this frame", so
  // we don't miss click-release events that are shorter than 1 frame.
  io.MouseDown[0] =
      mouse_pressed[0] || (mouse_mask & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
  io.MouseDown[1] =
      mouse_pressed[1] || (mouse_mask & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
  io.MouseDown[2] =
      mouse_pressed[2] || (mouse_mask & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
  mouse_pressed[0] = mouse_pressed[1] = mouse_pressed[2] = false;

  io.MouseWheel = mouse_wheel;
  mouse_wheel = 0.0f;

  SDL_ShowCursor(io.MouseDrawCursor ? 0 : 1);
  ImGui::NewFrame();
}

void HostUI::end_frame() {
  ImGuiIO& io = ImGui::GetIO();
  glViewport(0, 0, io.DisplaySize.x, io.DisplaySize.y);
  glClearColor(0.1f, 0.1f, 0.1f, 1);
  glClear(GL_COLOR_BUFFER_BIT);
  ImGui::Render();
  SDL_GL_SwapWindow(window);
}

void HostUI::render_draw_lists_thunk(ImDrawData* draw_data) {
  s_ui->render_draw_lists(draw_data);
}

void HostUI::render_draw_lists(ImDrawData* draw_data) {
  ImGuiIO& io = ImGui::GetIO();
  int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
  int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
  if (fb_width == 0 || fb_height == 0) {
    return;
  }

  draw_data->ScaleClipRects(io.DisplayFramebufferScale);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glDisable(GL_CULL_FACE);
  glDisable(GL_DEPTH_TEST);
  glEnable(GL_SCISSOR_TEST);

  glUseProgram(program);
  glUniform1i(uSampler, 0);
  glUniformMatrix3fv(uProjMatrix, 1, GL_FALSE, proj_matrix);
  glBindVertexArray(vao);

  for (int n = 0; n < draw_data->CmdListsCount; n++) {
    const ImDrawList* cmd_list = draw_data->CmdLists[n];
    const ImDrawIdx* idx_buffer_offset = 0;

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER,
                 (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert),
                 (GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                 (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx),
                 (GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);

    for (int i = 0; i < cmd_list->CmdBuffer.Size; i++) {
      const ImDrawCmd* cmd = &cmd_list->CmdBuffer[i];
      if (cmd->UserCallback) {
        cmd->UserCallback(cmd_list, cmd);
      } else {
        glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)cmd->TextureId);
        glScissor((int)cmd->ClipRect.x, (int)(fb_height - cmd->ClipRect.w),
                  (int)(cmd->ClipRect.z - cmd->ClipRect.x),
                  (int)(cmd->ClipRect.w - cmd->ClipRect.y));
        glDrawElements(
            GL_TRIANGLES, (GLsizei)cmd->ElemCount,
            sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT,
            idx_buffer_offset);
      }
      idx_buffer_offset += cmd->ElemCount;
    }
  }

  glDisable(GL_SCISSOR_TEST);
  glDisable(GL_BLEND);
}

void HostUI::set_clipboard_text(void* user_data, const char* text) {
  SDL_SetClipboardText(text);
}

const char* HostUI::get_clipboard_text(void* user_data) {
  return SDL_GetClipboardText();
}

HostUI* host_ui_new(struct SDL_Window* window) {
  HostUI* ui = new HostUI(window);
  if (!SUCCESS(ui->init())) {
    delete ui;
    return nullptr;
  }

  return ui;
}

void host_ui_delete(struct HostUI* ui) {
  delete ui;
}

void host_ui_event(struct HostUI* ui, union SDL_Event* event) {
  ui->event(event);
}

void host_ui_begin_frame(HostUI* ui, HostTexture* fb_texture) {
  ui->begin_frame();
}

void host_ui_end_frame(HostUI* ui) {
  ui->end_frame();
}
<|endoftext|>


<commit_before>/* This is free and unencumbered software released into the public domain. */

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

#include "cpr/vector.h"

#include <cerrno>    /* for errno */
#include <cstdlib>   /* for std::calloc(), std::free() */
#include <new>       /* for std::bad_alloc */
#include <stdexcept> /* for std::out_of_range */
#include <vector>    /* for std::vector */

struct cpr_vector : public std::vector<void*> {
  // TODO
};

extern const size_t cpr_vector_sizeof = sizeof(cpr_vector);

cpr_vector*
cpr_vector_alloc(void) {
  return reinterpret_cast<cpr_vector*>(std::calloc(1, sizeof(cpr_vector)));
}

void
cpr_vector_free(cpr_vector* const vector) {
  std::free(vector);
}

void
cpr_vector_init(cpr_vector* const vector) {
  new(vector) cpr_vector(); // TODO: handle exceptions?
}

void
cpr_vector_dispose(cpr_vector* const vector) {
  vector->~cpr_vector(); /* guaranteed to never throw an exception */
}

bool
cpr_vector_empty(const cpr_vector* const vector) {
  return vector->empty(); /* guaranteed to never throw an exception */
}

size_t
cpr_vector_size(const cpr_vector* const vector) {
  return vector->size(); /* guaranteed to never throw an exception */
}

void*
cpr_vector_at(const cpr_vector* const vector,
              const size_t position) {
  try {
    return vector->at(position);
  }
  catch (const std::out_of_range& error) {
    errno = EDOM; /* out of domain */
    return nullptr;
  }
}

void
cpr_vector_clear(cpr_vector* const vector) {
  vector->clear(); /* guaranteed to never throw an exception */
}

void
cpr_vector_push_back(cpr_vector* const vector,
                     const void* const element) {
  try {
    vector->push_back(const_cast<void*>(element));
  }
  catch (const std::bad_alloc& error) {
    errno = ENOMEM; /* out of memory */
  }
}

void
cpr_vector_pop_back(cpr_vector* const vector) {
  if (vector->empty()) {
    /* Invoking #pop_back() on an empty vector is defined to result in
     * undefined behavior. We'd rather avoid undefined behavior, so we'll
     * just fail gracefully instead. */
    errno = EFAULT; /* bad address */
    return;
  }
  vector->pop_back(); /* guaranteed to never throw an exception */
}
<commit_msg>Changed from using raw errno value macros to the std::errc enum.<commit_after>/* This is free and unencumbered software released into the public domain. */

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

#include "cpr/vector.h"

#include <cerrno>       /* for errno */
#include <cstdlib>      /* for std::calloc(), std::free() */
#include <new>          /* for std::bad_alloc */
#include <stdexcept>    /* for std::out_of_range */
#include <system_error> /* for std::errc */
#include <vector>       /* for std::vector */

struct cpr_vector : public std::vector<void*> {};

extern const size_t cpr_vector_sizeof = sizeof(cpr_vector);

cpr_vector*
cpr_vector_alloc(void) {
  return reinterpret_cast<cpr_vector*>(std::calloc(1, sizeof(cpr_vector)));
}

void
cpr_vector_free(cpr_vector* const vector) {
  std::free(vector);
}

void
cpr_vector_init(cpr_vector* const vector) {
  new(vector) cpr_vector(); // TODO: handle exceptions?
}

void
cpr_vector_dispose(cpr_vector* const vector) {
  vector->~cpr_vector(); /* guaranteed to never throw an exception */
}

bool
cpr_vector_empty(const cpr_vector* const vector) {
  return vector->empty(); /* guaranteed to never throw an exception */
}

size_t
cpr_vector_size(const cpr_vector* const vector) {
  return vector->size(); /* guaranteed to never throw an exception */
}

void*
cpr_vector_at(const cpr_vector* const vector,
              const size_t position) {
  try {
    return vector->at(position);
  }
  catch (const std::out_of_range& error) {
    errno = static_cast<int>(std::errc::argument_out_of_domain); /* EDOM */
    return nullptr;
  }
}

void
cpr_vector_clear(cpr_vector* const vector) {
  vector->clear(); /* guaranteed to never throw an exception */
}

void
cpr_vector_push_back(cpr_vector* const vector,
                     const void* const element) {
  try {
    vector->push_back(const_cast<void*>(element));
  }
  catch (const std::bad_alloc& error) {
    errno = static_cast<int>(std::errc::not_enough_memory); /* ENOMEM */
  }
}

void
cpr_vector_pop_back(cpr_vector* const vector) {
  if (vector->empty()) {
    /* Invoking #pop_back() on an empty vector is defined to result in
     * undefined behavior. We'd rather avoid undefined behavior, so we'll
     * just fail gracefully instead. */
    errno = static_cast<int>(std::errc::bad_address); /* EFAULT */
    return;
  }
  vector->pop_back(); /* guaranteed to never throw an exception */
}
<|endoftext|>


<commit_before>#include <ghost.h>
#include <ghost_util.h>
#include <ghost_vec.h>
#include <cmath>
#include <cstdio>
#include "ghost_complex.h"
#include <omp.h>

template <typename v_t> void ghost_normalizeVector_tmpl(ghost_vec_t *vec)
{
	v_t s;
	ghost_vec_dotprod_tmpl<v_t>(vec,vec,&s);
	s = (v_t)sqrt(s);
	s = (v_t)(((v_t)1.)/s);
	ghost_vec_scale_tmpl<v_t>(vec,&s);

#ifdef OPENCL
	vec->CLupload(vec);
#endif
#ifdef CUDA
	vec->CUupload(vec);
#endif
}

template <typename v_t> void ghost_vec_dotprod_tmpl(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{
	v_t sum = 0;
	ghost_vidx_t i;
	ghost_vidx_t nr = MIN(vec->traits->nrows,vec2->traits->nrows);

	int nthreads;
#pragma omp parallel
	nthreads = omp_get_num_threads();

	v_t partsums[nthreads];
	for (i=0; i<nthreads; i++) partsums[i] = (v_t)0.;

#pragma omp parallel for
	for (i=0; i<nr; i++) {
		partsums[omp_get_thread_num()] += ((v_t *)(vec->val))[i]*((v_t *)(vec2->val))[i];
	}

	for (i=0; i<nthreads; i++) sum += partsums[i];

	*(v_t *)res = sum;
}

template <typename v_t> void ghost_vec_axpy_tmpl(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{
	ghost_vidx_t i;
	v_t s = *(v_t *)scale;
	ghost_vidx_t nr = MIN(vec->traits->nrows,vec2->traits->nrows);

#pragma omp parallel for
	for (i=0; i<nr; i++) {
		((v_t *)(vec->val))[i] += ((v_t *)(vec2->val))[i] * s;
	}
}

template<typename v_t> void ghost_vec_scale_tmpl(ghost_vec_t *vec, void *scale)
{
	ghost_vidx_t i;
	v_t s = *(v_t *)scale;

#pragma omp parallel for
	for (i=0; i<vec->traits->nrows; i++) {
		((v_t *)(vec->val))[i] *= s;
	}
}

template <typename v_t> void ghost_vec_fromRand_tmpl(ghost_vec_t *vec, ghost_context_t * ctx)
{
	DEBUG_LOG(1,"Filling vector with random values");
	if (ctx)
		getNrowsFromContext(vec,ctx);

	vec->val = ghost_malloc(vec->traits->nvecs*vec->traits->nrowspadded*ghost_sizeofDataType(vec->traits->datatype));
	int i;

#pragma omp parallel for schedule(runtime)
	for (i=0; i<vec->traits->nrows; i++) {
		((v_t *)(vec->val))[i] = (v_t)(rand()*1./RAND_MAX); // TODO imag
	}
}

template<typename v_t> int ghost_vecEquals_tmpl(ghost_vec_t *a, ghost_vec_t *b)
{
	double tol = 1e-5; // TODO as argument?
	int i;
	for (i=0; i<a->traits->nrows; i++) {
			if (fabs(real((std::complex<double>)VAL(a,i) - (std::complex<double>)VAL(b,i))) > tol ||
					fabs(imag((std::complex<double>)VAL(a,i) - (std::complex<double>)VAL(b,i))) > tol)
				return 0;
	}
	return 1;
}

extern "C" void d_ghost_normalizeVector(ghost_vec_t *vec)
{ return ghost_normalizeVector_tmpl< double >(vec); }

extern "C" void s_ghost_normalizeVector(ghost_vec_t *vec)
{ return ghost_normalizeVector_tmpl< float >(vec); }

extern "C" void z_ghost_normalizeVector(ghost_vec_t *vec)
{ return ghost_normalizeVector_tmpl< ghost_complex<double> >(vec); }

extern "C" void c_ghost_normalizeVector(ghost_vec_t *vec)
{ return ghost_normalizeVector_tmpl< ghost_complex<float> >(vec); }

extern "C" void d_ghost_vec_dotprod(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{ return ghost_vec_dotprod_tmpl< double >(vec,vec2,res); }

extern "C" void s_ghost_vec_dotprod(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{ return ghost_vec_dotprod_tmpl< float >(vec,vec2,res); }

extern "C" void z_ghost_vec_dotprod(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{ return ghost_vec_dotprod_tmpl< ghost_complex<double> >(vec,vec2,res); }

extern "C" void c_ghost_vec_dotprod(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{ return ghost_vec_dotprod_tmpl< ghost_complex<float> >(vec,vec2,res); }

extern "C" void d_ghost_vec_scale(ghost_vec_t *vec, void *scale)
{ return ghost_vec_scale_tmpl< double >(vec, scale); }

extern "C" void s_ghost_vec_scale(ghost_vec_t *vec, void *scale)
{ return ghost_vec_scale_tmpl< float  >(vec, scale); }

extern "C" void z_ghost_vec_scale(ghost_vec_t *vec, void *scale)
{ return ghost_vec_scale_tmpl< ghost_complex<double> >(vec, scale); }

extern "C" void c_ghost_vec_scale(ghost_vec_t *vec, void *scale)
{ return ghost_vec_scale_tmpl< ghost_complex<float> >(vec, scale); }

extern "C" void d_ghost_vec_axpy(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{ return ghost_vec_axpy_tmpl< double >(vec, vec2, scale); }

extern "C" void s_ghost_vec_axpy(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{ return ghost_vec_axpy_tmpl< float >(vec, vec2, scale); }

extern "C" void z_ghost_vec_axpy(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{ return ghost_vec_axpy_tmpl< ghost_complex<double> >(vec, vec2, scale); }

extern "C" void c_ghost_vec_axpy(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{ return ghost_vec_axpy_tmpl< ghost_complex<float> >(vec, vec2, scale); }

extern "C" void d_ghost_vec_fromRand(ghost_vec_t *vec, ghost_context_t *ctx)
{ return ghost_vec_fromRand_tmpl< double >(vec,ctx); }

extern "C" void s_ghost_vec_fromRand(ghost_vec_t *vec, ghost_context_t *ctx)
{ return ghost_vec_fromRand_tmpl< float >(vec,ctx); }

extern "C" void z_ghost_vec_fromRand(ghost_vec_t *vec, ghost_context_t *ctx)
{ return ghost_vec_fromRand_tmpl< ghost_complex<double> >(vec,ctx); }

extern "C" void c_ghost_vec_fromRand(ghost_vec_t *vec, ghost_context_t *ctx)
{ return ghost_vec_fromRand_tmpl< ghost_complex<float> >(vec,ctx); }

extern "C" int d_ghost_vecEquals(ghost_vec_t *vec, ghost_vec_t *vec2)
{ return ghost_vecEquals_tmpl< double >(vec,vec2); }

extern "C" int s_ghost_vecEquals(ghost_vec_t *vec, ghost_vec_t *vec2)
{ return ghost_vecEquals_tmpl< float >(vec,vec2); }

extern "C" int z_ghost_vecEquals(ghost_vec_t *vec, ghost_vec_t *vec2)
{ return ghost_vecEquals_tmpl< ghost_complex<double> >(vec,vec2); }

extern "C" int c_ghost_vecEquals(ghost_vec_t *vec, ghost_vec_t *vec2)
{ return ghost_vecEquals_tmpl< ghost_complex<float> >(vec,vec2); }
<commit_msg>un-parallelized random vector creation because it led to non-random vectors<commit_after>#include <ghost.h>
#include <ghost_util.h>
#include <ghost_vec.h>
#include <cmath>
#include <cstdio>
#include "ghost_complex.h"
#include <omp.h>

template <typename v_t> void ghost_normalizeVector_tmpl(ghost_vec_t *vec)
{
	v_t s;
	ghost_vec_dotprod_tmpl<v_t>(vec,vec,&s);
	s = (v_t)sqrt(s);
	s = (v_t)(((v_t)1.)/s);
	ghost_vec_scale_tmpl<v_t>(vec,&s);

#ifdef OPENCL
	vec->CLupload(vec);
#endif
#ifdef CUDA
	vec->CUupload(vec);
#endif
}

template <typename v_t> void ghost_vec_dotprod_tmpl(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{
	v_t sum = 0;
	ghost_vidx_t i;
	ghost_vidx_t nr = MIN(vec->traits->nrows,vec2->traits->nrows);

	int nthreads;
#pragma omp parallel
	nthreads = omp_get_num_threads();

	v_t partsums[nthreads];
	for (i=0; i<nthreads; i++) partsums[i] = (v_t)0.;

#pragma omp parallel for
	for (i=0; i<nr; i++) {
		partsums[omp_get_thread_num()] += ((v_t *)(vec->val))[i]*((v_t *)(vec2->val))[i];
	}

	for (i=0; i<nthreads; i++) sum += partsums[i];

	*(v_t *)res = sum;
}

template <typename v_t> void ghost_vec_axpy_tmpl(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{
	ghost_vidx_t i;
	v_t s = *(v_t *)scale;
	ghost_vidx_t nr = MIN(vec->traits->nrows,vec2->traits->nrows);

#pragma omp parallel for
	for (i=0; i<nr; i++) {
		((v_t *)(vec->val))[i] += ((v_t *)(vec2->val))[i] * s;
	}
}

template<typename v_t> void ghost_vec_scale_tmpl(ghost_vec_t *vec, void *scale)
{
	ghost_vidx_t i;
	v_t s = *(v_t *)scale;

#pragma omp parallel for
	for (i=0; i<vec->traits->nrows; i++) {
		((v_t *)(vec->val))[i] *= s;
	}
}

template <typename v_t> void ghost_vec_fromRand_tmpl(ghost_vec_t *vec, ghost_context_t * ctx)
{
	DEBUG_LOG(1,"Filling vector with random values");
	if (ctx)
		getNrowsFromContext(vec,ctx);

	vec->val = ghost_malloc(vec->traits->nvecs*vec->traits->nrowspadded*ghost_sizeofDataType(vec->traits->datatype));
	int i;

// TODO fuse loops but preserve randomness

#pragma omp parallel for schedule(runtime)
	for (i=0; i<vec->traits->nrows; i++) {
		((v_t *)(vec->val))[i] = (v_t)0;
	}

	for (i=0; i<vec->traits->nrows; i++) {
		((v_t *)(vec->val))[i] = (v_t)(rand()*1./RAND_MAX); // TODO imag
	}
}

template<typename v_t> int ghost_vecEquals_tmpl(ghost_vec_t *a, ghost_vec_t *b)
{
	double tol = 1e-5; // TODO as argument?
	int i;
	for (i=0; i<a->traits->nrows; i++) {
			if (fabs(real((std::complex<double>)VAL(a,i) - (std::complex<double>)VAL(b,i))) > tol ||
					fabs(imag((std::complex<double>)VAL(a,i) - (std::complex<double>)VAL(b,i))) > tol)
				return 0;
	}
	return 1;
}

extern "C" void d_ghost_normalizeVector(ghost_vec_t *vec)
{ return ghost_normalizeVector_tmpl< double >(vec); }

extern "C" void s_ghost_normalizeVector(ghost_vec_t *vec)
{ return ghost_normalizeVector_tmpl< float >(vec); }

extern "C" void z_ghost_normalizeVector(ghost_vec_t *vec)
{ return ghost_normalizeVector_tmpl< ghost_complex<double> >(vec); }

extern "C" void c_ghost_normalizeVector(ghost_vec_t *vec)
{ return ghost_normalizeVector_tmpl< ghost_complex<float> >(vec); }

extern "C" void d_ghost_vec_dotprod(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{ return ghost_vec_dotprod_tmpl< double >(vec,vec2,res); }

extern "C" void s_ghost_vec_dotprod(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{ return ghost_vec_dotprod_tmpl< float >(vec,vec2,res); }

extern "C" void z_ghost_vec_dotprod(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{ return ghost_vec_dotprod_tmpl< ghost_complex<double> >(vec,vec2,res); }

extern "C" void c_ghost_vec_dotprod(ghost_vec_t *vec, ghost_vec_t *vec2, void *res)
{ return ghost_vec_dotprod_tmpl< ghost_complex<float> >(vec,vec2,res); }

extern "C" void d_ghost_vec_scale(ghost_vec_t *vec, void *scale)
{ return ghost_vec_scale_tmpl< double >(vec, scale); }

extern "C" void s_ghost_vec_scale(ghost_vec_t *vec, void *scale)
{ return ghost_vec_scale_tmpl< float  >(vec, scale); }

extern "C" void z_ghost_vec_scale(ghost_vec_t *vec, void *scale)
{ return ghost_vec_scale_tmpl< ghost_complex<double> >(vec, scale); }

extern "C" void c_ghost_vec_scale(ghost_vec_t *vec, void *scale)
{ return ghost_vec_scale_tmpl< ghost_complex<float> >(vec, scale); }

extern "C" void d_ghost_vec_axpy(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{ return ghost_vec_axpy_tmpl< double >(vec, vec2, scale); }

extern "C" void s_ghost_vec_axpy(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{ return ghost_vec_axpy_tmpl< float >(vec, vec2, scale); }

extern "C" void z_ghost_vec_axpy(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{ return ghost_vec_axpy_tmpl< ghost_complex<double> >(vec, vec2, scale); }

extern "C" void c_ghost_vec_axpy(ghost_vec_t *vec, ghost_vec_t *vec2, void *scale)
{ return ghost_vec_axpy_tmpl< ghost_complex<float> >(vec, vec2, scale); }

extern "C" void d_ghost_vec_fromRand(ghost_vec_t *vec, ghost_context_t *ctx)
{ return ghost_vec_fromRand_tmpl< double >(vec,ctx); }

extern "C" void s_ghost_vec_fromRand(ghost_vec_t *vec, ghost_context_t *ctx)
{ return ghost_vec_fromRand_tmpl< float >(vec,ctx); }

extern "C" void z_ghost_vec_fromRand(ghost_vec_t *vec, ghost_context_t *ctx)
{ return ghost_vec_fromRand_tmpl< ghost_complex<double> >(vec,ctx); }

extern "C" void c_ghost_vec_fromRand(ghost_vec_t *vec, ghost_context_t *ctx)
{ return ghost_vec_fromRand_tmpl< ghost_complex<float> >(vec,ctx); }

extern "C" int d_ghost_vecEquals(ghost_vec_t *vec, ghost_vec_t *vec2)
{ return ghost_vecEquals_tmpl< double >(vec,vec2); }

extern "C" int s_ghost_vecEquals(ghost_vec_t *vec, ghost_vec_t *vec2)
{ return ghost_vecEquals_tmpl< float >(vec,vec2); }

extern "C" int z_ghost_vecEquals(ghost_vec_t *vec, ghost_vec_t *vec2)
{ return ghost_vecEquals_tmpl< ghost_complex<double> >(vec,vec2); }

extern "C" int c_ghost_vecEquals(ghost_vec_t *vec, ghost_vec_t *vec2)
{ return ghost_vecEquals_tmpl< ghost_complex<float> >(vec,vec2); }
<|endoftext|>


<commit_before>/*
  High_Temp.cpp

  2014 Copyright (c) Seeed Technology Inc.  All right reserved.

  Loovee
  2013-4-14

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

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

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

#include <Arduino.h>
#include "High_Temp_MCP320x.h"

HighTempMCP320x::HighTempMCP320x(int _spiCS, int _pinTmp, int _pinThmc) : HighTemp(_pinTmp, _pinThmc)
{
    spiChipSelect = _spiCS;
    adc = MCP3208(spiChipSelect);
}

int HighTempMCP320x::getAnalog(int pin)
{
    return adc.analogRead(pin);
}
<commit_msg>Add missing call to begin() for MCP3208 object<commit_after>/*
  High_Temp.cpp

  2014 Copyright (c) Seeed Technology Inc.  All right reserved.

  Loovee
  2013-4-14

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

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

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

#include <Arduino.h>
#include "High_Temp_MCP320x.h"

HighTempMCP320x::HighTempMCP320x(int _spiCS, int _pinTmp, int _pinThmc) : HighTemp(_pinTmp, _pinThmc)
{
    adc = MCP3208(_spiCS);
    adc.begin();
}

int HighTempMCP320x::getAnalog(int pin)
{
    return adc.analogRead(pin);
}
<|endoftext|>


<commit_before>#ifndef YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP
#define YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP

#include <yamail/resource_pool/error.hpp>
#include <yamail/resource_pool/detail/idle.hpp>
#include <yamail/resource_pool/async/detail/queue.hpp>
#include <boost/asio/spawn.hpp>
#include <type_traits>

namespace yamail {
namespace resource_pool {
namespace async {

struct stats {
    std::size_t size;
    std::size_t available;
    std::size_t used;
    std::size_t queue_size;
};

namespace detail {

template <class Value, class Mutex, class IoService, class Queue>
class pool_impl : boost::noncopyable {
public:
    using value_type = Value;
    using io_service_t = IoService;
    using idle = resource_pool::detail::idle<value_type>;
    using list = std::list<idle>;
    using list_iterator = typename list::iterator;
    using callback = std::function<void (const boost::system::error_code&, list_iterator)>;
    using queue_type = Queue;

    pool_impl(std::size_t capacity,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : _capacity(assert_capacity(capacity)),
              _idle_timeout(idle_timeout),
              _callbacks(std::make_shared<queue_type>(queue_capacity)) {

        for (std::size_t i = 0; i < _capacity; ++i) {
            _wasted.emplace_back(idle());
        }
    }

    template <class Generator>
    pool_impl(Generator&& gen_value,
              std::size_t capacity,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : _capacity(assert_capacity(capacity)),
              _idle_timeout(idle_timeout),
              _callbacks(std::make_shared<queue_type>(queue_capacity)) {

        const auto drop_time = time_traits::add(time_traits::now(), _idle_timeout);
        for (std::size_t i = 0; i < _capacity; ++i) {
            _available.emplace_back(gen_value(), drop_time);
        }
    }

    template <class Iter>
    pool_impl(Iter first, Iter last,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : pool_impl([&]{ return std::move(*first++); },
                    std::distance(first, last),
                    queue_capacity,
                    idle_timeout) {
    }

    std::size_t capacity() const { return _capacity; }
    std::size_t size() const;
    std::size_t available() const;
    std::size_t used() const;
    async::stats stats() const;

    const queue_type& queue() const { return *_callbacks; }

    template <class Callback>
    void get(io_service_t& io_service, Callback call, time_traits::duration wait_duration = time_traits::duration(0));
    void recycle(list_iterator res_it);
    void waste(list_iterator res_it);
    void disable();

    static std::size_t assert_capacity(std::size_t value);

private:
    using mutex_t = Mutex;
    using unique_lock = std::unique_lock<mutex_t>;
    using lock_guard = std::lock_guard<mutex_t>;

    mutable mutex_t _mutex;
    list _available;
    list _used;
    list _wasted;
    const std::size_t _capacity;
    const time_traits::duration _idle_timeout;
    std::shared_ptr<queue_type> _callbacks;
    bool _disabled = false;

    std::size_t size_unsafe() const { return _available.size() + _used.size(); }
    bool fit_capacity() const { return size_unsafe() < _capacity; }
    template <class Callback>
    bool reserve_resource(io_service_t& io_service, unique_lock& lock, Callback call);
    template <class Callback>
    bool alloc_resource(io_service_t& io_service, unique_lock& lock, Callback call);
    template <class Serve>
    void perform_one_request(unique_lock& lock, Serve&& serve);
};

template <class V, class M, class I, class Q>
std::size_t pool_impl<V, M, I, Q>::size() const {
    const lock_guard lock(_mutex);
    return size_unsafe();
}

template <class V, class M, class I, class Q>
std::size_t pool_impl<V, M, I, Q>::available() const {
    const lock_guard lock(_mutex);
    return _available.size();
}

template <class V, class M, class I, class Q>
std::size_t pool_impl<V, M, I, Q>::used() const {
    const lock_guard lock(_mutex);
    return _used.size();
}

template <class V, class M, class I, class Q>
async::stats pool_impl<V, M, I, Q>::stats() const {
    const lock_guard lock(_mutex);
    return async::stats {size_unsafe(), _available.size(), _used.size(), _callbacks->size()};
}

template <class V, class M, class I, class Q>
void pool_impl<V, M, I, Q>::recycle(list_iterator res_it) {
    res_it->drop_time = time_traits::add(time_traits::now(), _idle_timeout);
    unique_lock lock(_mutex);
    _available.splice(_available.end(), _used, res_it);
    perform_one_request(lock, [&] (io_service_t& ios, const callback& call) { return alloc_resource(ios, lock, call); });
}

template <class V, class M, class I, class Q>
void pool_impl<V, M, I, Q>::waste(list_iterator res_it) {
    res_it->value.reset();
    unique_lock lock(_mutex);
    _wasted.splice(_wasted.end(), _used, res_it);
    perform_one_request(lock, [&] (io_service_t& ios, const callback& call) { return reserve_resource(ios, lock, call); });
}

template <class V, class M, class I, class Q>
template <class Callback>
void pool_impl<V, M, I, Q>::get(io_service_t& io_service, Callback call, time_traits::duration wait_duration) {
    using boost::asio::asio_handler_invoke;
    unique_lock lock(_mutex);
    if (_disabled) {
        lock.unlock();
        io_service.post([call] () mutable {
            asio_handler_invoke([=] () mutable { call(make_error_code(error::disabled), list_iterator()); }, &call);
        });
    } else if (alloc_resource(io_service, lock, call)) {
        return;
    } else if (fit_capacity()) {
        reserve_resource(io_service, lock, call);
    } else {
        lock.unlock();
        if (wait_duration.count() == 0) {
            io_service.post([call] () mutable {
                asio_handler_invoke([=] () mutable { call(make_error_code(error::get_resource_timeout), list_iterator()); }, &call);
            });
        } else {
            const auto expired = [call] () mutable {
                asio_handler_invoke([=] () mutable { call(make_error_code(error::get_resource_timeout), list_iterator()); }, &call);
            };
            const bool pushed = _callbacks->push(io_service, call, expired, wait_duration);
            if (!pushed) {
                io_service.post([call] () mutable {
                    asio_handler_invoke([=] () mutable { call(make_error_code(error::request_queue_overflow), list_iterator()); }, &call);
                });
            }
        }
    }
}

template <class V, class M, class I, class Q>
void pool_impl<V, M, I, Q>::disable() {
    using boost::asio::asio_handler_invoke;
    const lock_guard lock(_mutex);
    _disabled = true;
    while (true) {
        io_service_t* io_service;
        callback call;
        if (!_callbacks->pop(io_service, call)) {
            break;
        }
        io_service->post([call] {
            asio_handler_invoke([=] () mutable { call(make_error_code(error::disabled), list_iterator()); }, &call);
        });
    }
}

template <class V, class M, class I, class Q>
std::size_t pool_impl<V, M, I, Q>::assert_capacity(std::size_t value) {
    if (value == 0) {
        throw error::zero_pool_capacity();
    }
    return value;
}

template <class V, class M, class I, class Q>
template <class Callback>
bool pool_impl<V, M, I, Q>::alloc_resource(io_service_t& io_service, unique_lock& lock, Callback call) {
    using boost::asio::asio_handler_invoke;
    while (!_available.empty()) {
        const list_iterator res_it = _available.begin();
        if (res_it->drop_time <= time_traits::now()) {
            res_it->value.reset();
            _wasted.splice(_wasted.end(), _available, res_it);
            continue;
        }
        _used.splice(_used.end(), _available, res_it);
        lock.unlock();
        io_service.post([call, res_it] () mutable {
            asio_handler_invoke([=] () mutable { call(boost::system::error_code(), res_it); }, &call);
        });
        return true;
    }
    return false;
}

template <class V, class M, class I, class Q>
template <class Callback>
bool pool_impl<V, M, I, Q>::reserve_resource(io_service_t& io_service, unique_lock& lock, Callback call) {
    using boost::asio::asio_handler_invoke;
    const list_iterator res_it = _wasted.begin();
    _used.splice(_used.end(), _wasted, res_it);
    lock.unlock();
    io_service.post([call, res_it] () mutable {
        asio_handler_invoke([=] () mutable { call(boost::system::error_code(), res_it); }, &call);
    });
    return true;
}

template <class V, class M, class I, class Q>
template <class Serve>
void pool_impl<V, M, I, Q>::perform_one_request(unique_lock& lock, Serve&& serve) {
    io_service_t* io_service;
    callback call;
    if (_callbacks->pop(io_service, call)) {
        if (!serve(*io_service, call)) {
            reserve_resource(*io_service, lock, call);
        }
    }
}

// Helper template to deduce the true type of a handler, capture a local copy
// of the handler, and then create an async_result for the handler.
template <typename Handler, typename Signature>
struct async_result_init
{
    explicit async_result_init(Handler orig_handler)
    : handler(std::move(orig_handler)),
      result(handler)
    {
    }

    using handler_type = typename ::boost::asio::handler_type<Handler, Signature>::type;
    handler_type handler;
    ::boost::asio::async_result<handler_type> result;
};

template <typename Handler, typename Signature>
using async_return_type = typename ::boost::asio::async_result<
        typename ::boost::asio::handler_type<Handler, Signature>::type
    >::type;

} // namespace detail
} // namespace async
} // namespace resource_pool
} // namespace yamail

#endif // YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP
<commit_msg>Fix signed to unsigned clang warning<commit_after>#ifndef YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP
#define YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP

#include <yamail/resource_pool/error.hpp>
#include <yamail/resource_pool/detail/idle.hpp>
#include <yamail/resource_pool/async/detail/queue.hpp>
#include <boost/asio/spawn.hpp>
#include <type_traits>

namespace yamail {
namespace resource_pool {
namespace async {

struct stats {
    std::size_t size;
    std::size_t available;
    std::size_t used;
    std::size_t queue_size;
};

namespace detail {

template <class Value, class Mutex, class IoService, class Queue>
class pool_impl : boost::noncopyable {
public:
    using value_type = Value;
    using io_service_t = IoService;
    using idle = resource_pool::detail::idle<value_type>;
    using list = std::list<idle>;
    using list_iterator = typename list::iterator;
    using callback = std::function<void (const boost::system::error_code&, list_iterator)>;
    using queue_type = Queue;

    pool_impl(std::size_t capacity,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : _capacity(assert_capacity(capacity)),
              _idle_timeout(idle_timeout),
              _callbacks(std::make_shared<queue_type>(queue_capacity)) {

        for (std::size_t i = 0; i < _capacity; ++i) {
            _wasted.emplace_back(idle());
        }
    }

    template <class Generator>
    pool_impl(Generator&& gen_value,
              std::size_t capacity,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : _capacity(assert_capacity(capacity)),
              _idle_timeout(idle_timeout),
              _callbacks(std::make_shared<queue_type>(queue_capacity)) {

        const auto drop_time = time_traits::add(time_traits::now(), _idle_timeout);
        for (std::size_t i = 0; i < _capacity; ++i) {
            _available.emplace_back(gen_value(), drop_time);
        }
    }

    template <class Iter>
    pool_impl(Iter first, Iter last,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : pool_impl([&]{ return std::move(*first++); },
                    static_cast<std::size_t>(std::distance(first, last)),
                    queue_capacity,
                    idle_timeout) {
    }

    std::size_t capacity() const { return _capacity; }
    std::size_t size() const;
    std::size_t available() const;
    std::size_t used() const;
    async::stats stats() const;

    const queue_type& queue() const { return *_callbacks; }

    template <class Callback>
    void get(io_service_t& io_service, Callback call, time_traits::duration wait_duration = time_traits::duration(0));
    void recycle(list_iterator res_it);
    void waste(list_iterator res_it);
    void disable();

    static std::size_t assert_capacity(std::size_t value);

private:
    using mutex_t = Mutex;
    using unique_lock = std::unique_lock<mutex_t>;
    using lock_guard = std::lock_guard<mutex_t>;

    mutable mutex_t _mutex;
    list _available;
    list _used;
    list _wasted;
    const std::size_t _capacity;
    const time_traits::duration _idle_timeout;
    std::shared_ptr<queue_type> _callbacks;
    bool _disabled = false;

    std::size_t size_unsafe() const { return _available.size() + _used.size(); }
    bool fit_capacity() const { return size_unsafe() < _capacity; }
    template <class Callback>
    bool reserve_resource(io_service_t& io_service, unique_lock& lock, Callback call);
    template <class Callback>
    bool alloc_resource(io_service_t& io_service, unique_lock& lock, Callback call);
    template <class Serve>
    void perform_one_request(unique_lock& lock, Serve&& serve);
};

template <class V, class M, class I, class Q>
std::size_t pool_impl<V, M, I, Q>::size() const {
    const lock_guard lock(_mutex);
    return size_unsafe();
}

template <class V, class M, class I, class Q>
std::size_t pool_impl<V, M, I, Q>::available() const {
    const lock_guard lock(_mutex);
    return _available.size();
}

template <class V, class M, class I, class Q>
std::size_t pool_impl<V, M, I, Q>::used() const {
    const lock_guard lock(_mutex);
    return _used.size();
}

template <class V, class M, class I, class Q>
async::stats pool_impl<V, M, I, Q>::stats() const {
    const lock_guard lock(_mutex);
    return async::stats {size_unsafe(), _available.size(), _used.size(), _callbacks->size()};
}

template <class V, class M, class I, class Q>
void pool_impl<V, M, I, Q>::recycle(list_iterator res_it) {
    res_it->drop_time = time_traits::add(time_traits::now(), _idle_timeout);
    unique_lock lock(_mutex);
    _available.splice(_available.end(), _used, res_it);
    perform_one_request(lock, [&] (io_service_t& ios, const callback& call) { return alloc_resource(ios, lock, call); });
}

template <class V, class M, class I, class Q>
void pool_impl<V, M, I, Q>::waste(list_iterator res_it) {
    res_it->value.reset();
    unique_lock lock(_mutex);
    _wasted.splice(_wasted.end(), _used, res_it);
    perform_one_request(lock, [&] (io_service_t& ios, const callback& call) { return reserve_resource(ios, lock, call); });
}

template <class V, class M, class I, class Q>
template <class Callback>
void pool_impl<V, M, I, Q>::get(io_service_t& io_service, Callback call, time_traits::duration wait_duration) {
    using boost::asio::asio_handler_invoke;
    unique_lock lock(_mutex);
    if (_disabled) {
        lock.unlock();
        io_service.post([call] () mutable {
            asio_handler_invoke([=] () mutable { call(make_error_code(error::disabled), list_iterator()); }, &call);
        });
    } else if (alloc_resource(io_service, lock, call)) {
        return;
    } else if (fit_capacity()) {
        reserve_resource(io_service, lock, call);
    } else {
        lock.unlock();
        if (wait_duration.count() == 0) {
            io_service.post([call] () mutable {
                asio_handler_invoke([=] () mutable { call(make_error_code(error::get_resource_timeout), list_iterator()); }, &call);
            });
        } else {
            const auto expired = [call] () mutable {
                asio_handler_invoke([=] () mutable { call(make_error_code(error::get_resource_timeout), list_iterator()); }, &call);
            };
            const bool pushed = _callbacks->push(io_service, call, expired, wait_duration);
            if (!pushed) {
                io_service.post([call] () mutable {
                    asio_handler_invoke([=] () mutable { call(make_error_code(error::request_queue_overflow), list_iterator()); }, &call);
                });
            }
        }
    }
}

template <class V, class M, class I, class Q>
void pool_impl<V, M, I, Q>::disable() {
    using boost::asio::asio_handler_invoke;
    const lock_guard lock(_mutex);
    _disabled = true;
    while (true) {
        io_service_t* io_service;
        callback call;
        if (!_callbacks->pop(io_service, call)) {
            break;
        }
        io_service->post([call] {
            asio_handler_invoke([=] () mutable { call(make_error_code(error::disabled), list_iterator()); }, &call);
        });
    }
}

template <class V, class M, class I, class Q>
std::size_t pool_impl<V, M, I, Q>::assert_capacity(std::size_t value) {
    if (value == 0) {
        throw error::zero_pool_capacity();
    }
    return value;
}

template <class V, class M, class I, class Q>
template <class Callback>
bool pool_impl<V, M, I, Q>::alloc_resource(io_service_t& io_service, unique_lock& lock, Callback call) {
    using boost::asio::asio_handler_invoke;
    while (!_available.empty()) {
        const list_iterator res_it = _available.begin();
        if (res_it->drop_time <= time_traits::now()) {
            res_it->value.reset();
            _wasted.splice(_wasted.end(), _available, res_it);
            continue;
        }
        _used.splice(_used.end(), _available, res_it);
        lock.unlock();
        io_service.post([call, res_it] () mutable {
            asio_handler_invoke([=] () mutable { call(boost::system::error_code(), res_it); }, &call);
        });
        return true;
    }
    return false;
}

template <class V, class M, class I, class Q>
template <class Callback>
bool pool_impl<V, M, I, Q>::reserve_resource(io_service_t& io_service, unique_lock& lock, Callback call) {
    using boost::asio::asio_handler_invoke;
    const list_iterator res_it = _wasted.begin();
    _used.splice(_used.end(), _wasted, res_it);
    lock.unlock();
    io_service.post([call, res_it] () mutable {
        asio_handler_invoke([=] () mutable { call(boost::system::error_code(), res_it); }, &call);
    });
    return true;
}

template <class V, class M, class I, class Q>
template <class Serve>
void pool_impl<V, M, I, Q>::perform_one_request(unique_lock& lock, Serve&& serve) {
    io_service_t* io_service;
    callback call;
    if (_callbacks->pop(io_service, call)) {
        if (!serve(*io_service, call)) {
            reserve_resource(*io_service, lock, call);
        }
    }
}

// Helper template to deduce the true type of a handler, capture a local copy
// of the handler, and then create an async_result for the handler.
template <typename Handler, typename Signature>
struct async_result_init
{
    explicit async_result_init(Handler orig_handler)
    : handler(std::move(orig_handler)),
      result(handler)
    {
    }

    using handler_type = typename ::boost::asio::handler_type<Handler, Signature>::type;
    handler_type handler;
    ::boost::asio::async_result<handler_type> result;
};

template <typename Handler, typename Signature>
using async_return_type = typename ::boost::asio::async_result<
        typename ::boost::asio::handler_type<Handler, Signature>::type
    >::type;

} // namespace detail
} // namespace async
} // namespace resource_pool
} // namespace yamail

#endif // YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP
<|endoftext|>


<commit_before>#ifndef YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP
#define YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP

#include <yamail/resource_pool/error.hpp>
#include <yamail/resource_pool/detail/idle.hpp>
#include <yamail/resource_pool/async/detail/queue.hpp>
#include <boost/asio/spawn.hpp>
#include <type_traits>

namespace yamail {
namespace resource_pool {
namespace async {

struct stats {
    std::size_t size;
    std::size_t available;
    std::size_t used;
    std::size_t queue_size;
};

namespace detail {

template <class Value, class IoService, class Queue>
class pool_impl : boost::noncopyable {
public:
    typedef Value value_type;
    typedef IoService io_service_t;
    typedef resource_pool::detail::idle<value_type> idle;
    typedef std::list<idle> list;
    typedef typename list::iterator list_iterator;
    typedef std::function<void (const boost::system::error_code&, list_iterator)> callback;
    typedef Queue queue_type;

    pool_impl(io_service_t& io_service,
              std::size_t capacity,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : _io_service(io_service),
              _capacity(assert_capacity(capacity)),
              _idle_timeout(idle_timeout),
              _callbacks(std::make_shared<queue_type>(_io_service, queue_capacity)) {

        for (std::size_t i = 0; i < _capacity; ++i) {
            _wasted.emplace_back(idle());
        }
    }

    template <class Generator>
    pool_impl(io_service_t& io_service,
              Generator&& gen_value,
              std::size_t capacity,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : _io_service(io_service),
              _capacity(assert_capacity(capacity)),
              _idle_timeout(idle_timeout),
              _callbacks(std::make_shared<queue_type>(_io_service, queue_capacity)) {

        const auto drop_time = time_traits::add(time_traits::now(), _idle_timeout);
        for (std::size_t i = 0; i < _capacity; ++i) {
            _available.emplace_back(gen_value(), drop_time);
        }
    }

    template <class Iter>
    pool_impl(io_service_t& io_service,
              Iter first, Iter last,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : pool_impl(io_service,
                    [&]{ return std::move(*first++); },
                    std::distance(first, last),
                    queue_capacity,
                    idle_timeout) {
    }

    std::size_t capacity() const { return _capacity; }
    std::size_t size() const;
    std::size_t available() const;
    std::size_t used() const;
    async::stats stats() const;

    const queue_type& queue() const { return *_callbacks; }

    template <class Callback>
    void async_call(Callback&& call) {
        _io_service.post(std::forward<Callback>(call));
    }

    template <class Callback>
    void get(Callback call, time_traits::duration wait_duration = time_traits::duration(0));
    void recycle(list_iterator res_it);
    void waste(list_iterator res_it);
    void disable();

    static std::size_t assert_capacity(std::size_t value);

private:
    typedef std::unique_lock<std::mutex> unique_lock;
    typedef std::lock_guard<std::mutex> lock_guard;
    typedef bool (pool_impl::*serve_request_t)(unique_lock&, const callback&);

    mutable std::mutex _mutex;
    list _available;
    list _used;
    list _wasted;
    io_service_t& _io_service;
    const std::size_t _capacity;
    const time_traits::duration _idle_timeout;
    std::shared_ptr<queue_type> _callbacks;
    bool _disabled = false;

    std::size_t size_unsafe() const { return _available.size() + _used.size(); }
    bool fit_capacity() const { return size_unsafe() < _capacity; }
    template <class Callback>
    bool reserve_resource(unique_lock& lock, Callback call);
    template <class Callback>
    bool alloc_resource(unique_lock& lock, Callback call);
    void perform_one_request(unique_lock& lock, serve_request_t serve);
};

template <class V, class I, class Q>
std::size_t pool_impl<V, I, Q>::size() const {
    const lock_guard lock(_mutex);
    return size_unsafe();
}

template <class V, class I, class Q>
std::size_t pool_impl<V, I, Q>::available() const {
    const lock_guard lock(_mutex);
    return _available.size();
}

template <class V, class I, class Q>
std::size_t pool_impl<V, I, Q>::used() const {
    const lock_guard lock(_mutex);
    return _used.size();
}

template <class V, class I, class Q>
async::stats pool_impl<V, I, Q>::stats() const {
    const lock_guard lock(_mutex);
    return async::stats {size_unsafe(), _available.size(), _used.size(), _callbacks->size()};
}

template <class V, class I, class Q>
void pool_impl<V, I, Q>::recycle(list_iterator res_it) {
    res_it->drop_time = time_traits::add(time_traits::now(), _idle_timeout);
    unique_lock lock(_mutex);
    _used.splice(_available.end(), _available, res_it);
    perform_one_request(lock, &pool_impl::alloc_resource);
}

template <class V, class I, class Q>
void pool_impl<V, I, Q>::waste(list_iterator res_it) {
    res_it->value.reset();
    unique_lock lock(_mutex);
    _used.splice(_wasted.end(), _wasted, res_it);
    perform_one_request(lock, &pool_impl::reserve_resource);
}

template <class V, class I, class Q>
template <class Callback>
void pool_impl<V, I, Q>::get(Callback call, time_traits::duration wait_duration) {
    unique_lock lock(_mutex);
    if (_disabled) {
        lock.unlock();
        async_call([call] () mutable {
            call(make_error_code(error::disabled), list_iterator());
        });
    } else if (alloc_resource(lock, call)) {
        return;
    } else if (fit_capacity()) {
        reserve_resource(lock, call);
    } else {
        lock.unlock();
        if (wait_duration.count() == 0) {
            async_call([call] () mutable {
                call(make_error_code(error::get_resource_timeout), list_iterator());
            });
        } else {
            const auto expired = [call] () mutable {
                call(make_error_code(error::get_resource_timeout), list_iterator());
            };
            const bool pushed = _callbacks->push(call, expired, wait_duration);
            if (!pushed) {
                async_call([call] () mutable {
                    call(make_error_code(error::request_queue_overflow), list_iterator());
                });
            }
        }
    }
}

template <class V, class I, class Q>
void pool_impl<V, I, Q>::disable() {
    const lock_guard lock(_mutex);
    _disabled = true;
    while (true) {
        callback call;
        if (!_callbacks->pop(call)) {
            break;
        }
        async_call([call] {
            call(make_error_code(error::disabled), list_iterator());
        });
    }
}

template <class V, class I, class Q>
std::size_t pool_impl<V, I, Q>::assert_capacity(std::size_t value) {
    if (value == 0) {
        throw error::zero_pool_capacity();
    }
    return value;
}

template <class V, class I, class Q>
template <class Callback>
bool pool_impl<V, I, Q>::alloc_resource(unique_lock& lock, Callback call) {
    while (!_available.empty()) {
        const list_iterator res_it = _available.begin();
        if (res_it->drop_time <= time_traits::now()) {
            res_it->value.reset();
            _available.splice(_wasted.end(), _wasted, res_it);
            continue;
        }
        _available.splice(_used.end(), _used, res_it);
        lock.unlock();
        async_call([call, res_it] () mutable {
            call(boost::system::error_code(), res_it);
        });
        return true;
    }
    return false;
}

template <class V, class I, class Q>
template <class Callback>
bool pool_impl<V, I, Q>::reserve_resource(unique_lock& lock, Callback call) {
    const list_iterator res_it = _wasted.begin();
    _wasted.splice(_used.end(), _used, res_it);
    lock.unlock();
    async_call([call, res_it] () mutable {
        call(boost::system::error_code(), res_it);
    });
    return true;
}

template <class V, class I, class Q>
void pool_impl<V, I, Q>::perform_one_request(unique_lock& lock, serve_request_t serve) {
    callback call;
    if (_callbacks->pop(call)) {
        if (!(this->*serve)(lock, call)) {
            reserve_resource(lock, call);
        }
    }
}

// Helper template to deduce the true type of a handler, capture a local copy
// of the handler, and then create an async_result for the handler.
template <typename Handler, typename Signature>
struct async_result_init
{
    explicit async_result_init(Handler orig_handler)
    : handler(std::move(orig_handler)),
      result(handler)
    {
    }

    using handler_type = typename ::boost::asio::handler_type<Handler, Signature>::type;
    handler_type handler;
    ::boost::asio::async_result<handler_type> result;
};

template <typename Handler, typename Signature>
using async_return_type = typename ::boost::asio::async_result<
      typename ::boost::asio::handler_type<Handler, Signature>::type
    >::type;

} // namespace detail
} // namespace async
} // namespace resource_pool
} // namespace yamail

#endif // YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP
<commit_msg>Fix splice usage<commit_after>#ifndef YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP
#define YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP

#include <yamail/resource_pool/error.hpp>
#include <yamail/resource_pool/detail/idle.hpp>
#include <yamail/resource_pool/async/detail/queue.hpp>
#include <boost/asio/spawn.hpp>
#include <type_traits>

namespace yamail {
namespace resource_pool {
namespace async {

struct stats {
    std::size_t size;
    std::size_t available;
    std::size_t used;
    std::size_t queue_size;
};

namespace detail {

template <class Value, class IoService, class Queue>
class pool_impl : boost::noncopyable {
public:
    typedef Value value_type;
    typedef IoService io_service_t;
    typedef resource_pool::detail::idle<value_type> idle;
    typedef std::list<idle> list;
    typedef typename list::iterator list_iterator;
    typedef std::function<void (const boost::system::error_code&, list_iterator)> callback;
    typedef Queue queue_type;

    pool_impl(io_service_t& io_service,
              std::size_t capacity,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : _io_service(io_service),
              _capacity(assert_capacity(capacity)),
              _idle_timeout(idle_timeout),
              _callbacks(std::make_shared<queue_type>(_io_service, queue_capacity)) {

        for (std::size_t i = 0; i < _capacity; ++i) {
            _wasted.emplace_back(idle());
        }
    }

    template <class Generator>
    pool_impl(io_service_t& io_service,
              Generator&& gen_value,
              std::size_t capacity,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : _io_service(io_service),
              _capacity(assert_capacity(capacity)),
              _idle_timeout(idle_timeout),
              _callbacks(std::make_shared<queue_type>(_io_service, queue_capacity)) {

        const auto drop_time = time_traits::add(time_traits::now(), _idle_timeout);
        for (std::size_t i = 0; i < _capacity; ++i) {
            _available.emplace_back(gen_value(), drop_time);
        }
    }

    template <class Iter>
    pool_impl(io_service_t& io_service,
              Iter first, Iter last,
              std::size_t queue_capacity,
              time_traits::duration idle_timeout)
            : pool_impl(io_service,
                    [&]{ return std::move(*first++); },
                    std::distance(first, last),
                    queue_capacity,
                    idle_timeout) {
    }

    std::size_t capacity() const { return _capacity; }
    std::size_t size() const;
    std::size_t available() const;
    std::size_t used() const;
    async::stats stats() const;

    const queue_type& queue() const { return *_callbacks; }

    template <class Callback>
    void async_call(Callback&& call) {
        _io_service.post(std::forward<Callback>(call));
    }

    template <class Callback>
    void get(Callback call, time_traits::duration wait_duration = time_traits::duration(0));
    void recycle(list_iterator res_it);
    void waste(list_iterator res_it);
    void disable();

    static std::size_t assert_capacity(std::size_t value);

private:
    typedef std::unique_lock<std::mutex> unique_lock;
    typedef std::lock_guard<std::mutex> lock_guard;
    typedef bool (pool_impl::*serve_request_t)(unique_lock&, const callback&);

    mutable std::mutex _mutex;
    list _available;
    list _used;
    list _wasted;
    io_service_t& _io_service;
    const std::size_t _capacity;
    const time_traits::duration _idle_timeout;
    std::shared_ptr<queue_type> _callbacks;
    bool _disabled = false;

    std::size_t size_unsafe() const { return _available.size() + _used.size(); }
    bool fit_capacity() const { return size_unsafe() < _capacity; }
    template <class Callback>
    bool reserve_resource(unique_lock& lock, Callback call);
    template <class Callback>
    bool alloc_resource(unique_lock& lock, Callback call);
    void perform_one_request(unique_lock& lock, serve_request_t serve);
};

template <class V, class I, class Q>
std::size_t pool_impl<V, I, Q>::size() const {
    const lock_guard lock(_mutex);
    return size_unsafe();
}

template <class V, class I, class Q>
std::size_t pool_impl<V, I, Q>::available() const {
    const lock_guard lock(_mutex);
    return _available.size();
}

template <class V, class I, class Q>
std::size_t pool_impl<V, I, Q>::used() const {
    const lock_guard lock(_mutex);
    return _used.size();
}

template <class V, class I, class Q>
async::stats pool_impl<V, I, Q>::stats() const {
    const lock_guard lock(_mutex);
    return async::stats {size_unsafe(), _available.size(), _used.size(), _callbacks->size()};
}

template <class V, class I, class Q>
void pool_impl<V, I, Q>::recycle(list_iterator res_it) {
    res_it->drop_time = time_traits::add(time_traits::now(), _idle_timeout);
    unique_lock lock(_mutex);
    _available.splice(_available.end(), _used, res_it);
    perform_one_request(lock, &pool_impl::alloc_resource);
}

template <class V, class I, class Q>
void pool_impl<V, I, Q>::waste(list_iterator res_it) {
    res_it->value.reset();
    unique_lock lock(_mutex);
    _wasted.splice(_wasted.end(), _used, res_it);
    perform_one_request(lock, &pool_impl::reserve_resource);
}

template <class V, class I, class Q>
template <class Callback>
void pool_impl<V, I, Q>::get(Callback call, time_traits::duration wait_duration) {
    unique_lock lock(_mutex);
    if (_disabled) {
        lock.unlock();
        async_call([call] () mutable {
            call(make_error_code(error::disabled), list_iterator());
        });
    } else if (alloc_resource(lock, call)) {
        return;
    } else if (fit_capacity()) {
        reserve_resource(lock, call);
    } else {
        lock.unlock();
        if (wait_duration.count() == 0) {
            async_call([call] () mutable {
                call(make_error_code(error::get_resource_timeout), list_iterator());
            });
        } else {
            const auto expired = [call] () mutable {
                call(make_error_code(error::get_resource_timeout), list_iterator());
            };
            const bool pushed = _callbacks->push(call, expired, wait_duration);
            if (!pushed) {
                async_call([call] () mutable {
                    call(make_error_code(error::request_queue_overflow), list_iterator());
                });
            }
        }
    }
}

template <class V, class I, class Q>
void pool_impl<V, I, Q>::disable() {
    const lock_guard lock(_mutex);
    _disabled = true;
    while (true) {
        callback call;
        if (!_callbacks->pop(call)) {
            break;
        }
        async_call([call] {
            call(make_error_code(error::disabled), list_iterator());
        });
    }
}

template <class V, class I, class Q>
std::size_t pool_impl<V, I, Q>::assert_capacity(std::size_t value) {
    if (value == 0) {
        throw error::zero_pool_capacity();
    }
    return value;
}

template <class V, class I, class Q>
template <class Callback>
bool pool_impl<V, I, Q>::alloc_resource(unique_lock& lock, Callback call) {
    while (!_available.empty()) {
        const list_iterator res_it = _available.begin();
        if (res_it->drop_time <= time_traits::now()) {
            res_it->value.reset();
            _wasted.splice(_wasted.end(), _available, res_it);
            continue;
        }
        _used.splice(_used.end(), _available, res_it);
        lock.unlock();
        async_call([call, res_it] () mutable {
            call(boost::system::error_code(), res_it);
        });
        return true;
    }
    return false;
}

template <class V, class I, class Q>
template <class Callback>
bool pool_impl<V, I, Q>::reserve_resource(unique_lock& lock, Callback call) {
    const list_iterator res_it = _wasted.begin();
    _used.splice(_used.end(), _wasted, res_it);
    lock.unlock();
    async_call([call, res_it] () mutable {
        call(boost::system::error_code(), res_it);
    });
    return true;
}

template <class V, class I, class Q>
void pool_impl<V, I, Q>::perform_one_request(unique_lock& lock, serve_request_t serve) {
    callback call;
    if (_callbacks->pop(call)) {
        if (!(this->*serve)(lock, call)) {
            reserve_resource(lock, call);
        }
    }
}

// Helper template to deduce the true type of a handler, capture a local copy
// of the handler, and then create an async_result for the handler.
template <typename Handler, typename Signature>
struct async_result_init
{
    explicit async_result_init(Handler orig_handler)
    : handler(std::move(orig_handler)),
      result(handler)
    {
    }

    using handler_type = typename ::boost::asio::handler_type<Handler, Signature>::type;
    handler_type handler;
    ::boost::asio::async_result<handler_type> result;
};

template <typename Handler, typename Signature>
using async_return_type = typename ::boost::asio::async_result<
      typename ::boost::asio::handler_type<Handler, Signature>::type
    >::type;

} // namespace detail
} // namespace async
} // namespace resource_pool
} // namespace yamail

#endif // YAMAIL_RESOURCE_POOL_ASYNC_DETAIL_POOL_IMPL_HPP
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkSQLDatabase.cxx

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

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

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkSQLDatabase.h"
#include "vtkSQLiteDatabase.h"
#include "vtkPostgreSQLDatabase.h"
#include "vtkMySQLDatabase.h"

#include "vtkObjectFactory.h"

#include <vtksys/SystemTools.hxx>
#include <vtksys/RegularExpression.hxx>

vtkCxxRevisionMacro(vtkSQLDatabase, "1.2");

// ----------------------------------------------------------------------
vtkSQLDatabase::vtkSQLDatabase()
{
}

// ----------------------------------------------------------------------
vtkSQLDatabase::~vtkSQLDatabase()
{
}

// ----------------------------------------------------------------------
void vtkSQLDatabase::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

// ----------------------------------------------------------------------
vtkSQLDatabase* vtkSQLDatabase::CreateFromURL( const char* URL )
{
  vtkstd::string protocol( 0 );
  vtkstd::string dataglom( 0 );

  if ( ! vtksys::SystemTools::ParseURLProtocol( URL, protocol, dataglom ) )
    {
    vtkGenericWarningMacro( "Invalid URL: " << URL );
    return 0;
    }

  vtkSQLDatabase* db = 0;
  if ( protocol == "sqlite" )
    {
    vtkSQLiteDatabase* sdb = vtkSQLiteDatabase::New();
    if ( sdb )
      {
      sdb->SetFileName( dataglom.c_str() );
      }

    db = sdb;
    }
  else if ( protocol == "psql" )
    {
    db = vtkPostgreSQLDatabase::New();
    }
  else if ( protocol == "mysql" )
    {
    db = vtkMySQLDatabase::New();
    }
  else
    {
    vtkGenericWarningMacro( "Unsupported protocol: " << protocol.c_str() );
    return 0;
    }

  if ( db )
    {
    db->SetURL( URL );
    }
  else
    {
    vtkGenericWarningMacro( "Unable to instantiate a database" );
    }

  vtkGenericWarningMacro( "Unable to connect to URL: " << URL );
  return db;
}

<commit_msg>COMP: do not include vtkMySQLDatabase.h when it is not needed.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSQLDatabase.cxx

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

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

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkSQLDatabase.h"
#include "vtkSQLiteDatabase.h"

#ifdef VTK_USE_PSQL
#include "vtkPostgreSQLDatabase.h"
#endif // VTK_USE_PSQL

#ifdef VTK_USE_MYSQL
#include "vtkMySQLDatabase.h"
#endif // VTK_USE_MYSQL

#include "vtkObjectFactory.h"

#include <vtksys/SystemTools.hxx>
#include <vtksys/RegularExpression.hxx>

vtkCxxRevisionMacro(vtkSQLDatabase, "1.3");

// ----------------------------------------------------------------------
vtkSQLDatabase::vtkSQLDatabase()
{
}

// ----------------------------------------------------------------------
vtkSQLDatabase::~vtkSQLDatabase()
{
}

// ----------------------------------------------------------------------
void vtkSQLDatabase::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

// ----------------------------------------------------------------------
vtkSQLDatabase* vtkSQLDatabase::CreateFromURL( const char* URL )
{
  vtkstd::string protocol( 0 );
  vtkstd::string dataglom( 0 );

  if ( ! vtksys::SystemTools::ParseURLProtocol( URL, protocol, dataglom ) )
    {
    vtkGenericWarningMacro( "Invalid URL: " << URL );
    return 0;
    }

  vtkSQLDatabase* db = 0;
  if ( protocol == "sqlite" )
    {
    vtkSQLiteDatabase* sdb = vtkSQLiteDatabase::New();
    if ( sdb )
      {
      sdb->SetFileName( dataglom.c_str() );
      }

    db = sdb;
    }
  else if ( protocol == "psql" )
    {
    db = vtkPostgreSQLDatabase::New();
    }
  else if ( protocol == "mysql" )
    {
    db = vtkMySQLDatabase::New();
    }
  else
    {
    vtkGenericWarningMacro( "Unsupported protocol: " << protocol.c_str() );
    return 0;
    }

  if ( db )
    {
    db->SetURL( URL );
    }
  else
    {
    vtkGenericWarningMacro( "Unable to instantiate a database" );
    }

  vtkGenericWarningMacro( "Unable to connect to URL: " << URL );
  return db;
}

<|endoftext|>


<commit_before>#include "exec.h"

#include <stack>
#include <stdlib.h>

#include "bytecode.h"
#include "opcode.h"

class Executor {
public:
    Executor(const Bytecode::bytecode &obj);
    void exec();
private:
    const Bytecode obj;
    Bytecode::bytecode::size_type ip;
    std::stack<int> stack;
    std::vector<int> vars;

    void exec_PUSHI();
    void exec_ADDROF();
    void exec_LOADI();
    void exec_STOREI();
    void exec_NEGI();
    void exec_ADDI();
    void exec_SUBI();
    void exec_MULI();
    void exec_DIVI();
    void exec_CALL();
    void exec_JUMP();
    void exec_JZ();
};

Executor::Executor(const Bytecode::bytecode &obj)
  : obj(obj), ip(0)
{
}

void Executor::exec_PUSHI()
{
    int val = (obj.code[ip+1] << 24) | (obj.code[ip+2] << 16) | (obj.code[ip+3] << 8) | obj.code[ip+4];
    ip += 5;
    stack.push(val);
}

void Executor::exec_LOADI()
{
    ip++;
    unsigned int addr = stack.top(); stack.pop();
    stack.push(vars[addr]);
}

void Executor::exec_STOREI()
{
    ip++;
    unsigned int addr = stack.top(); stack.pop();
    int val = stack.top(); stack.pop();
    if (vars.size() < addr+1) {
        vars.resize(addr+1);
    }
    vars[addr] = val;
}

void Executor::exec_NEGI()
{
    ip++;
    int x = stack.top(); stack.pop();
    stack.push(-x);
}

void Executor::exec_ADDI()
{
    ip++;
    int b = stack.top(); stack.pop();
    int a = stack.top(); stack.pop();
    stack.push(a + b);
}

void Executor::exec_SUBI()
{
    ip++;
    int b = stack.top(); stack.pop();
    int a = stack.top(); stack.pop();
    stack.push(a - b);
}

void Executor::exec_MULI()
{
    ip++;
    int b = stack.top(); stack.pop();
    int a = stack.top(); stack.pop();
    stack.push(a * b);
}

void Executor::exec_DIVI()
{
    ip++;
    int b = stack.top(); stack.pop();
    int a = stack.top(); stack.pop();
    stack.push(a / b);
}

void Executor::exec_CALL()
{
    ip++;
    std::string func = obj.strtable[stack.top()]; stack.pop();
    if (func == "abs") {
        int x = stack.top(); stack.pop();
        stack.push(abs(x));
    } else if (func == "print") {
        int x = stack.top(); stack.pop();
        printf("%d\n", x);
    } else {
        abort();
    }
}

void Executor::exec_JUMP()
{
    int target = (obj.code[ip+1] << 24) | (obj.code[ip+2] << 16) | (obj.code[ip+3] << 8) | obj.code[ip+4];
    ip += 5;
    ip = target;
}

void Executor::exec_JZ()
{
    int target = (obj.code[ip+1] << 24) | (obj.code[ip+2] << 16) | (obj.code[ip+3] << 8) | obj.code[ip+4];
    ip += 5;
    int a = stack.top(); stack.pop();
    if (a == 0) {
        ip = target;
    }
}

void Executor::exec()
{
    while (ip < obj.code.size()) {
        switch (obj.code[ip]) {
            case PUSHI:  exec_PUSHI(); break;
            case LOADI:  exec_LOADI(); break;
            case STOREI: exec_STOREI(); break;
            case NEGI:   exec_NEGI(); break;
            case ADDI:   exec_ADDI(); break;
            case SUBI:   exec_SUBI(); break;
            case MULI:   exec_MULI(); break;
            case DIVI:   exec_DIVI(); break;
            case CALL:   exec_CALL(); break;
            case JUMP:   exec_JUMP(); break;
            case JZ:     exec_JZ(); break;
            default:
                printf("exec: Unexpected opcode: %d\n", obj.code[ip]);
                abort();
        }
    }
}

void exec(const Bytecode::bytecode &obj)
{
    Executor(obj).exec();
}
<commit_msg>send output to specific stream<commit_after>#include "exec.h"

#include <iostream>
#include <stack>
#include <stdlib.h>

#include "bytecode.h"
#include "opcode.h"

class Executor {
public:
    Executor(const Bytecode::bytecode &obj, std::ostream &out);
    void exec();
private:
    const Bytecode obj;
    std::ostream &out;
    Bytecode::bytecode::size_type ip;
    std::stack<int> stack;
    std::vector<int> vars;

    void exec_PUSHI();
    void exec_ADDROF();
    void exec_LOADI();
    void exec_STOREI();
    void exec_NEGI();
    void exec_ADDI();
    void exec_SUBI();
    void exec_MULI();
    void exec_DIVI();
    void exec_CALL();
    void exec_JUMP();
    void exec_JZ();
};

Executor::Executor(const Bytecode::bytecode &obj, std::ostream &out)
  : obj(obj), out(out), ip(0)
{
}

void Executor::exec_PUSHI()
{
    int val = (obj.code[ip+1] << 24) | (obj.code[ip+2] << 16) | (obj.code[ip+3] << 8) | obj.code[ip+4];
    ip += 5;
    stack.push(val);
}

void Executor::exec_LOADI()
{
    ip++;
    unsigned int addr = stack.top(); stack.pop();
    stack.push(vars[addr]);
}

void Executor::exec_STOREI()
{
    ip++;
    unsigned int addr = stack.top(); stack.pop();
    int val = stack.top(); stack.pop();
    if (vars.size() < addr+1) {
        vars.resize(addr+1);
    }
    vars[addr] = val;
}

void Executor::exec_NEGI()
{
    ip++;
    int x = stack.top(); stack.pop();
    stack.push(-x);
}

void Executor::exec_ADDI()
{
    ip++;
    int b = stack.top(); stack.pop();
    int a = stack.top(); stack.pop();
    stack.push(a + b);
}

void Executor::exec_SUBI()
{
    ip++;
    int b = stack.top(); stack.pop();
    int a = stack.top(); stack.pop();
    stack.push(a - b);
}

void Executor::exec_MULI()
{
    ip++;
    int b = stack.top(); stack.pop();
    int a = stack.top(); stack.pop();
    stack.push(a * b);
}

void Executor::exec_DIVI()
{
    ip++;
    int b = stack.top(); stack.pop();
    int a = stack.top(); stack.pop();
    stack.push(a / b);
}

void Executor::exec_CALL()
{
    ip++;
    std::string func = obj.strtable[stack.top()]; stack.pop();
    if (func == "abs") {
        int x = stack.top(); stack.pop();
        stack.push(abs(x));
    } else if (func == "print") {
        int x = stack.top(); stack.pop();
        out << x << std::endl;
    } else {
        abort();
    }
}

void Executor::exec_JUMP()
{
    int target = (obj.code[ip+1] << 24) | (obj.code[ip+2] << 16) | (obj.code[ip+3] << 8) | obj.code[ip+4];
    ip += 5;
    ip = target;
}

void Executor::exec_JZ()
{
    int target = (obj.code[ip+1] << 24) | (obj.code[ip+2] << 16) | (obj.code[ip+3] << 8) | obj.code[ip+4];
    ip += 5;
    int a = stack.top(); stack.pop();
    if (a == 0) {
        ip = target;
    }
}

void Executor::exec()
{
    while (ip < obj.code.size()) {
        switch (obj.code[ip]) {
            case PUSHI:  exec_PUSHI(); break;
            case LOADI:  exec_LOADI(); break;
            case STOREI: exec_STOREI(); break;
            case NEGI:   exec_NEGI(); break;
            case ADDI:   exec_ADDI(); break;
            case SUBI:   exec_SUBI(); break;
            case MULI:   exec_MULI(); break;
            case DIVI:   exec_DIVI(); break;
            case CALL:   exec_CALL(); break;
            case JUMP:   exec_JUMP(); break;
            case JZ:     exec_JZ(); break;
            default:
                printf("exec: Unexpected opcode: %d\n", obj.code[ip]);
                abort();
        }
    }
}

void exec(const Bytecode::bytecode &obj)
{
    Executor(obj, std::cout).exec();
}
<|endoftext|>