<commit_before>#include <nan.h>
#include <string>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include "sass_context_wrapper.h"

using namespace v8;
using namespace std;

void WorkOnContext(uv_work_t* req) {
  sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data);
  if (ctx_w->ctx) {
    sass_context* ctx = static_cast<sass_context*>(ctx_w->ctx);
    sass_compile(ctx);
  } else if (ctx_w->fctx) {
    sass_file_context* ctx = static_cast<sass_file_context*>(ctx_w->fctx);
    sass_compile_file(ctx);
  }
}

void extractOptions(_NAN_METHOD_ARGS, void* cptr, sass_context_wrapper* ctx_w, bool isFile) {
  char *source;
  char* pathOrData;
  char* imagePath;
  int output_style;
  int source_comments;
  String::AsciiValue astr(args[0]);

  String::AsciiValue bstr(args[1]);
  imagePath = new char[strlen(*bstr)+1];
  strcpy(imagePath, *bstr);

  if (ctx_w) {
    // async (callback) style
    Local<Function> callback = Local<Function>::Cast(args[2]);
    Local<Function> errorCallback = Local<Function>::Cast(args[3]);
    if (isFile) {
      ctx_w->fctx = (sass_file_context*) cptr;
    } else {
      ctx_w->ctx = (sass_context*) cptr;
    }
    ctx_w->request.data = ctx_w;
    ctx_w->callback = new NanCallback(callback);
    ctx_w->errorCallback = new NanCallback(errorCallback);
    output_style = args[5]->Int32Value();
    source_comments = args[6]->Int32Value();
    String::AsciiValue cstr(args[4]);
    pathOrData = new char[strlen(*cstr)+1];
    strcpy(pathOrData, *cstr);
  } else {
    // synchronous style
    output_style = args[3]->Int32Value();
    source_comments = args[4]->Int32Value();
    String::AsciiValue cstr(args[2]);
    pathOrData = new char[strlen(*cstr)+1];
    strcpy(pathOrData, *cstr);
  }

  if (isFile) {
    sass_file_context *ctx = (sass_file_context*)cptr;
    char *filename = new char[strlen(*astr)+1];
    strcpy(filename, *astr);
    ctx->input_path = filename;
    ctx->options.image_path = imagePath;
    ctx->options.output_style = output_style;
    ctx->options.source_comments = source_comments;
    ctx->options.include_paths = pathOrData;
    if (source_comments == SASS_SOURCE_COMMENTS_MAP) {
      String::AsciiValue dstr(args[7]);
      ctx->source_map_file = new char[strlen(*dstr)+1];
      strcpy(ctx->source_map_file, *dstr);
    }
  } else {
    sass_context *ctx = (sass_context*)cptr;
    source = new char[strlen(*astr)+1];
    strcpy(source, *astr);
    ctx->source_string = source;
    ctx->options.image_path = imagePath;
    ctx->options.output_style = output_style;
    ctx->options.source_comments = source_comments;
    ctx->options.include_paths = pathOrData;
  }
}

void MakeCallback(uv_work_t* req) {
    NanScope();
  TryCatch try_catch;
  sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data);
  Handle<Value> val, err;
  const unsigned argc = 2;
  int error_status = ctx_w->ctx ? ctx_w->ctx->error_status : ctx_w->fctx->error_status;

  if (error_status == 0) {
    // if no error, do callback(null, result)
    Handle<Value> source_map;
    if (ctx_w->fctx && ctx_w->fctx->options.source_comments == SASS_SOURCE_COMMENTS_MAP) {
      source_map = String::New(ctx_w->fctx->source_map_string);
    } else {
      source_map = Null();
    }

    val = ctx_w->ctx ? NanNewLocal(String::New(ctx_w->ctx->output_string)) : NanNewLocal(String::New(ctx_w->fctx->output_string));
    Local<Value> argv[argc] = {
      NanNewLocal(val),
      NanNewLocal(source_map),
    };
    ctx_w->callback->Call(argc, argv);
  } else {
    // if error, do callback(error)
    err = ctx_w->ctx ? NanNewLocal(String::New(ctx_w->ctx->error_message)) : NanNewLocal(String::New(ctx_w->fctx->error_message));
    Local<Value> argv[argc] = {
      NanNewLocal(err),
      NanNewLocal(Integer::New(error_status))
    };
    ctx_w->errorCallback->Call(argc, argv);
  }
  if (try_catch.HasCaught()) {
    node::FatalException(try_catch);
  }
  if (ctx_w->ctx) {
    delete ctx_w->ctx->source_string;
  } else {
    delete ctx_w->fctx->input_path;
  }
  sass_free_context_wrapper(ctx_w);
}

NAN_METHOD(Render) {
  NanScope();
  sass_context* ctx = sass_new_context();
  sass_context_wrapper* ctx_w = sass_new_context_wrapper();
  ctx_w->ctx = ctx;
  extractOptions(args, ctx, ctx_w, false);

  int status = uv_queue_work(uv_default_loop(), &ctx_w->request, WorkOnContext, (uv_after_work_cb)MakeCallback);
  assert(status == 0);

  NanReturnUndefined();
}

NAN_METHOD(RenderSync) {
  NanScope();
  sass_context* ctx = sass_new_context();
  extractOptions(args, ctx, NULL, false);

  sass_compile(ctx);

  delete ctx->source_string;
  ctx->source_string = NULL;
  delete ctx->options.include_paths;
  ctx->options.include_paths = NULL;

  if (ctx->error_status == 0) {
    Local<Value> output = NanNewLocal(String::New(ctx->output_string));
    sass_free_context(ctx);
    NanReturnValue(output);
  }

  Local<String> error = String::New(ctx->error_message);

  sass_free_context(ctx);
  NanThrowError(error);
  NanReturnUndefined();
}

NAN_METHOD(RenderFile) {
  NanScope();
  sass_file_context* fctx = sass_new_file_context();
  sass_context_wrapper* ctx_w = sass_new_context_wrapper();
  ctx_w->fctx = fctx;
  extractOptions(args, fctx, ctx_w, true);

  int status = uv_queue_work(uv_default_loop(), &ctx_w->request, WorkOnContext, (uv_after_work_cb)MakeCallback);
  assert(status == 0);

  NanReturnUndefined();
}

NAN_METHOD(RenderFileSync) {
  NanScope();
  sass_file_context* ctx = sass_new_file_context();
  extractOptions(args, ctx, NULL, true);

  sass_compile_file(ctx);

  delete ctx->input_path;
  ctx->input_path = NULL;
  delete ctx->options.include_paths;
  ctx->options.include_paths = NULL;

  if (ctx->error_status == 0) {
    Local<Value> output = NanNewLocal(String::New(ctx->output_string));
    sass_free_file_context(ctx);

    NanReturnValue(output);
  }
  Local<String> error = String::New(ctx->error_message);
  sass_free_file_context(ctx);

  NanThrowError(error);
  NanReturnUndefined();
}

void RegisterModule(v8::Handle<v8::Object> target) {
  NODE_SET_METHOD(target, "render", Render);
  NODE_SET_METHOD(target, "renderSync", RenderSync);
  NODE_SET_METHOD(target, "renderFile", RenderFile);
  NODE_SET_METHOD(target, "renderFileSync", RenderFileSync);
}

NODE_MODULE(binding, RegisterModule);
<commit_msg>Fixed a strcpy error in binding.cpp<commit_after>#include <nan.h>
#include <string>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include "sass_context_wrapper.h"

using namespace v8;
using namespace std;

void WorkOnContext(uv_work_t* req) {
  sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data);
  if (ctx_w->ctx) {
    sass_context* ctx = static_cast<sass_context*>(ctx_w->ctx);
    sass_compile(ctx);
  } else if (ctx_w->fctx) {
    sass_file_context* ctx = static_cast<sass_file_context*>(ctx_w->fctx);
    sass_compile_file(ctx);
  }
}

void extractOptions(_NAN_METHOD_ARGS, void* cptr, sass_context_wrapper* ctx_w, bool isFile) {
  char *source;
  char* pathOrData;
  char* imagePath;
  int output_style;
  int source_comments;
  String::AsciiValue astr(args[0]);

  String::AsciiValue bstr(args[1]);
  imagePath = new char[strlen(*bstr)+1];
  strcpy(imagePath, *bstr);

  if (ctx_w) {
    // async (callback) style
    Local<Function> callback = Local<Function>::Cast(args[2]);
    Local<Function> errorCallback = Local<Function>::Cast(args[3]);
    if (isFile) {
      ctx_w->fctx = (sass_file_context*) cptr;
    } else {
      ctx_w->ctx = (sass_context*) cptr;
    }
    ctx_w->request.data = ctx_w;
    ctx_w->callback = new NanCallback(callback);
    ctx_w->errorCallback = new NanCallback(errorCallback);
    output_style = args[5]->Int32Value();
    source_comments = args[6]->Int32Value();
    String::AsciiValue cstr(args[4]);
    pathOrData = new char[strlen(*cstr)+1];
    strcpy(pathOrData, *cstr);
  } else {
    // synchronous style
    output_style = args[3]->Int32Value();
    source_comments = args[4]->Int32Value();
    String::AsciiValue cstr(args[2]);
    pathOrData = new char[strlen(*cstr)+1];
    strcpy(pathOrData, *cstr);
  }

  if (isFile) {
    sass_file_context *ctx = (sass_file_context*)cptr;
    char *filename = new char[strlen(*astr)+1];
    strcpy(filename, *astr);
    ctx->input_path = filename;
    ctx->options.image_path = imagePath;
    ctx->options.output_style = output_style;
    ctx->options.source_comments = source_comments;
    ctx->options.include_paths = pathOrData;
    if (source_comments == SASS_SOURCE_COMMENTS_MAP) {
      String::AsciiValue dstr(args[7]);
      ctx->source_map_file = new char[strlen(*dstr)+1];
      ctx->source_map_file = *dstr;
    }
  } else {
    sass_context *ctx = (sass_context*)cptr;
    source = new char[strlen(*astr)+1];
    strcpy(source, *astr);
    ctx->source_string = source;
    ctx->options.image_path = imagePath;
    ctx->options.output_style = output_style;
    ctx->options.source_comments = source_comments;
    ctx->options.include_paths = pathOrData;
  }
}

void MakeCallback(uv_work_t* req) {
    NanScope();
  TryCatch try_catch;
  sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data);
  Handle<Value> val, err;
  const unsigned argc = 2;
  int error_status = ctx_w->ctx ? ctx_w->ctx->error_status : ctx_w->fctx->error_status;

  if (error_status == 0) {
    // if no error, do callback(null, result)
    Handle<Value> source_map;
    if (ctx_w->fctx && ctx_w->fctx->options.source_comments == SASS_SOURCE_COMMENTS_MAP) {
      source_map = String::New(ctx_w->fctx->source_map_string);
    } else {
      source_map = Null();
    }

    val = ctx_w->ctx ? NanNewLocal(String::New(ctx_w->ctx->output_string)) : NanNewLocal(String::New(ctx_w->fctx->output_string));
    Local<Value> argv[argc] = {
      NanNewLocal(val),
      NanNewLocal(source_map),
    };
    ctx_w->callback->Call(argc, argv);
  } else {
    // if error, do callback(error)
    err = ctx_w->ctx ? NanNewLocal(String::New(ctx_w->ctx->error_message)) : NanNewLocal(String::New(ctx_w->fctx->error_message));
    Local<Value> argv[argc] = {
      NanNewLocal(err),
      NanNewLocal(Integer::New(error_status))
    };
    ctx_w->errorCallback->Call(argc, argv);
  }
  if (try_catch.HasCaught()) {
    node::FatalException(try_catch);
  }
  if (ctx_w->ctx) {
    delete ctx_w->ctx->source_string;
  } else {
    delete ctx_w->fctx->input_path;
  }
  sass_free_context_wrapper(ctx_w);
}

NAN_METHOD(Render) {
  NanScope();
  sass_context* ctx = sass_new_context();
  sass_context_wrapper* ctx_w = sass_new_context_wrapper();
  ctx_w->ctx = ctx;
  extractOptions(args, ctx, ctx_w, false);

  int status = uv_queue_work(uv_default_loop(), &ctx_w->request, WorkOnContext, (uv_after_work_cb)MakeCallback);
  assert(status == 0);

  NanReturnUndefined();
}

NAN_METHOD(RenderSync) {
  NanScope();
  sass_context* ctx = sass_new_context();
  extractOptions(args, ctx, NULL, false);

  sass_compile(ctx);

  delete ctx->source_string;
  ctx->source_string = NULL;
  delete ctx->options.include_paths;
  ctx->options.include_paths = NULL;

  if (ctx->error_status == 0) {
    Local<Value> output = NanNewLocal(String::New(ctx->output_string));
    sass_free_context(ctx);
    NanReturnValue(output);
  }

  Local<String> error = String::New(ctx->error_message);

  sass_free_context(ctx);
  NanThrowError(error);
  NanReturnUndefined();
}

NAN_METHOD(RenderFile) {
  NanScope();
  sass_file_context* fctx = sass_new_file_context();
  sass_context_wrapper* ctx_w = sass_new_context_wrapper();
  ctx_w->fctx = fctx;
  extractOptions(args, fctx, ctx_w, true);

  int status = uv_queue_work(uv_default_loop(), &ctx_w->request, WorkOnContext, (uv_after_work_cb)MakeCallback);
  assert(status == 0);

  NanReturnUndefined();
}

NAN_METHOD(RenderFileSync) {
  NanScope();
  sass_file_context* ctx = sass_new_file_context();
  extractOptions(args, ctx, NULL, true);

  sass_compile_file(ctx);

  delete ctx->input_path;
  ctx->input_path = NULL;
  delete ctx->options.include_paths;
  ctx->options.include_paths = NULL;

  if (ctx->error_status == 0) {
    Local<Value> output = NanNewLocal(String::New(ctx->output_string));
    sass_free_file_context(ctx);

    NanReturnValue(output);
  }
  Local<String> error = String::New(ctx->error_message);
  sass_free_file_context(ctx);

  NanThrowError(error);
  NanReturnUndefined();
}

void RegisterModule(v8::Handle<v8::Object> target) {
  NODE_SET_METHOD(target, "render", Render);
  NODE_SET_METHOD(target, "renderSync", RenderSync);
  NODE_SET_METHOD(target, "renderFile", RenderFile);
  NODE_SET_METHOD(target, "renderFileSync", RenderFileSync);
}

NODE_MODULE(binding, RegisterModule);
<|endoftext|>


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

#include "backend/vulkan/RenderPassVk.h"

#include "backend/vulkan/FencedDeleter.h"
#include "backend/vulkan/TextureVk.h"
#include "backend/vulkan/VulkanBackend.h"

namespace backend { namespace vulkan {

    namespace {
        VkAttachmentLoadOp VulkanAttachmentLoadOp(nxt::LoadOp op) {
            switch (op) {
                case nxt::LoadOp::Load:
                    return VK_ATTACHMENT_LOAD_OP_LOAD;
                case nxt::LoadOp::Clear:
                    return VK_ATTACHMENT_LOAD_OP_CLEAR;
                default:
                    UNREACHABLE();
            }
        }
    }  // anonymous namespace

    RenderPass::RenderPass(RenderPassBuilder* builder)
        : RenderPassBase(builder), mDevice(ToBackend(builder->GetDevice())) {
        // For now we only support single pass render passes.
        ASSERT(GetSubpassCount() == 1);
        ASSERT(GetAttachmentCount() <= kMaxColorAttachments + 1);

        const auto& subpass = GetSubpassInfo(0);

        // The Vulkan subpasses want to know the layout of the attachments with VkAttachmentRef.
        // Precompute them as they must be pointer-chained in VkSubpassDescription
        std::array<VkAttachmentReference, kMaxColorAttachments + 1> attachmentRefs;
        attachmentRefs.fill(VkAttachmentReference{VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED});

        for (uint32_t i : IterateBitSet(subpass.colorAttachmentsSet)) {
            attachmentRefs[i].attachment = subpass.colorAttachments[i];
            attachmentRefs[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
        }
        if (subpass.depthStencilAttachment) {
            attachmentRefs[kMaxColorAttachments].attachment = subpass.depthStencilAttachment;
            attachmentRefs[kMaxColorAttachments].layout =
                VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
        }

        // Create the VkSubpassDescription that will be chained in the VkRenderPassCreateInfo
        VkSubpassDescription subpassDesc;
        subpassDesc.flags = 0;
        subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
        subpassDesc.inputAttachmentCount = 0;
        subpassDesc.pInputAttachments = nullptr;
        subpassDesc.colorAttachmentCount = kMaxColorAttachments;
        subpassDesc.pColorAttachments = attachmentRefs.data();
        subpassDesc.pResolveAttachments = nullptr;
        subpassDesc.pDepthStencilAttachment = &attachmentRefs[kMaxColorAttachments];
        subpassDesc.preserveAttachmentCount = 0;
        subpassDesc.pPreserveAttachments = nullptr;

        // Create the VkAttachmentDescriptions that will be chained in the VkRenderPassCreateInfo
        std::array<VkAttachmentDescription, kMaxColorAttachments + 1> attachmentDescs = {};
        for (uint32_t i = 0; i < GetAttachmentCount(); ++i) {
            const auto& attachment = GetAttachmentInfo(i);
            auto& attachmentDesc = attachmentDescs[i];

            attachmentDesc.flags = 0;
            attachmentDesc.format = VulkanImageFormat(attachment.format);
            attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
            if (TextureFormatHasDepthOrStencil(attachment.format)) {
                attachmentDesc.loadOp = VulkanAttachmentLoadOp(attachment.depthLoadOp);
                attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
                attachmentDesc.stencilLoadOp = VulkanAttachmentLoadOp(attachment.stencilLoadOp);
                attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;

                attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
                attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
            } else {
                attachmentDesc.loadOp = VulkanAttachmentLoadOp(attachment.colorLoadOp);
                attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;

                attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
                attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
            }
        }

        // Chain everything in VkRenderPassCreateInfo
        VkRenderPassCreateInfo createInfo;
        createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
        createInfo.pNext = nullptr;
        createInfo.flags = 0;
        createInfo.attachmentCount = GetAttachmentCount();
        createInfo.pAttachments = attachmentDescs.data();
        createInfo.subpassCount = 1;
        createInfo.pSubpasses = &subpassDesc;
        createInfo.dependencyCount = 0;
        createInfo.pDependencies = nullptr;

        // Create the render pass from the zillion parameters
        if (mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
            VK_SUCCESS) {
            ASSERT(false);
        }
    }

    RenderPass::~RenderPass() {
        if (mHandle != VK_NULL_HANDLE) {
            mDevice->GetFencedDeleter()->DeleteWhenUnused(mHandle);
            mHandle = VK_NULL_HANDLE;
        }
    }

    VkRenderPass RenderPass::GetHandle() const {
        return mHandle;
    }

}}  // namespace backend::vulkan
<commit_msg>RenderPassVk: Set the correct number of color attachments<commit_after>// Copyright 2018 The NXT Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "backend/vulkan/RenderPassVk.h"

#include "backend/vulkan/FencedDeleter.h"
#include "backend/vulkan/TextureVk.h"
#include "backend/vulkan/VulkanBackend.h"

namespace backend { namespace vulkan {

    namespace {
        VkAttachmentLoadOp VulkanAttachmentLoadOp(nxt::LoadOp op) {
            switch (op) {
                case nxt::LoadOp::Load:
                    return VK_ATTACHMENT_LOAD_OP_LOAD;
                case nxt::LoadOp::Clear:
                    return VK_ATTACHMENT_LOAD_OP_CLEAR;
                default:
                    UNREACHABLE();
            }
        }
    }  // anonymous namespace

    RenderPass::RenderPass(RenderPassBuilder* builder)
        : RenderPassBase(builder), mDevice(ToBackend(builder->GetDevice())) {
        // For now we only support single pass render passes.
        ASSERT(GetSubpassCount() == 1);
        ASSERT(GetAttachmentCount() <= kMaxColorAttachments + 1);

        const auto& subpass = GetSubpassInfo(0);

        // The Vulkan subpasses want to know the layout of the attachments with VkAttachmentRef.
        // Precompute them as they must be pointer-chained in VkSubpassDescription
        std::array<VkAttachmentReference, kMaxColorAttachments + 1> attachmentRefs;
        attachmentRefs.fill(VkAttachmentReference{VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED});

        for (uint32_t i : IterateBitSet(subpass.colorAttachmentsSet)) {
            attachmentRefs[i].attachment = subpass.colorAttachments[i];
            attachmentRefs[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

            // TODO(cwallez@chromium.org): need validation rule that attachments are packed
            ASSERT(i == 0 || subpass.colorAttachmentsSet[i - 1]);
        }
        if (subpass.depthStencilAttachment) {
            attachmentRefs[kMaxColorAttachments].attachment = subpass.depthStencilAttachment;
            attachmentRefs[kMaxColorAttachments].layout =
                VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
        }

        // Create the VkSubpassDescription that will be chained in the VkRenderPassCreateInfo
        VkSubpassDescription subpassDesc;
        subpassDesc.flags = 0;
        subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
        subpassDesc.inputAttachmentCount = 0;
        subpassDesc.pInputAttachments = nullptr;
        subpassDesc.colorAttachmentCount =
            static_cast<uint32_t>(subpass.colorAttachmentsSet.count());
        subpassDesc.pColorAttachments = attachmentRefs.data();
        subpassDesc.pResolveAttachments = nullptr;
        subpassDesc.pDepthStencilAttachment = &attachmentRefs[kMaxColorAttachments];
        subpassDesc.preserveAttachmentCount = 0;
        subpassDesc.pPreserveAttachments = nullptr;

        // Create the VkAttachmentDescriptions that will be chained in the VkRenderPassCreateInfo
        std::array<VkAttachmentDescription, kMaxColorAttachments + 1> attachmentDescs = {};
        for (uint32_t i = 0; i < GetAttachmentCount(); ++i) {
            const auto& attachment = GetAttachmentInfo(i);
            auto& attachmentDesc = attachmentDescs[i];

            attachmentDesc.flags = 0;
            attachmentDesc.format = VulkanImageFormat(attachment.format);
            attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
            if (TextureFormatHasDepthOrStencil(attachment.format)) {
                attachmentDesc.loadOp = VulkanAttachmentLoadOp(attachment.depthLoadOp);
                attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
                attachmentDesc.stencilLoadOp = VulkanAttachmentLoadOp(attachment.stencilLoadOp);
                attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;

                attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
                attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
            } else {
                attachmentDesc.loadOp = VulkanAttachmentLoadOp(attachment.colorLoadOp);
                attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;

                attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
                attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
            }
        }

        // Chain everything in VkRenderPassCreateInfo
        VkRenderPassCreateInfo createInfo;
        createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
        createInfo.pNext = nullptr;
        createInfo.flags = 0;
        createInfo.attachmentCount = GetAttachmentCount();
        createInfo.pAttachments = attachmentDescs.data();
        createInfo.subpassCount = 1;
        createInfo.pSubpasses = &subpassDesc;
        createInfo.dependencyCount = 0;
        createInfo.pDependencies = nullptr;

        // Create the render pass from the zillion parameters
        if (mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
            VK_SUCCESS) {
            ASSERT(false);
        }
    }

    RenderPass::~RenderPass() {
        if (mHandle != VK_NULL_HANDLE) {
            mDevice->GetFencedDeleter()->DeleteWhenUnused(mHandle);
            mHandle = VK_NULL_HANDLE;
        }
    }

    VkRenderPass RenderPass::GetHandle() const {
        return mHandle;
    }

}}  // namespace backend::vulkan
<|endoftext|>


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

#include "CppExportPlugin.h"
#include "exporter/CppExporter.h"

#include "VisualizationBase/src/items/Item.h"
#include "SelfTest/src/TestManager.h"
#include "Core/src/Profiler.h"

namespace CppExport {

bool CppExportPlugin::initialize(Core::EnvisionManager&)
{
	Interaction::ActionRegistry::instance()->registerInputHandler("GenericHandler.TestCppExport", testExport);

	return true;
}

void CppExportPlugin::unload()
{
}

void CppExportPlugin::selfTest(QString testid)
{
	if (testid.isEmpty()) SelfTest::TestManager<CppExportPlugin>::runAllTests().printResultStatistics();
	else SelfTest::TestManager<CppExportPlugin>::runTest(testid).printResultStatistics();
}

bool CppExportPlugin::testExport(Visualization::Item *target, QKeySequence, Interaction::ActionRegistry::InputState)
{
	auto n = target;
	while (n && ! n->node()) n = n->parent();

	if (n)
		if (n->node())
		{
			Core::Profiler::start(true, "Cpp Export", "cpp-export.prof");
			CppExport::CppExporter::exportTree(n->node()->manager(), "cpp_export");
			Core::Profiler::stop("Cpp Export");
			return true;
		}

	return false;
}

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

#include "CppExportPlugin.h"
#include "exporter/CppExporter.h"

#include "VisualizationBase/src/items/Item.h"
#include "SelfTest/src/TestManager.h"
#include "Core/src/Profiler.h"

namespace CppExport {

bool CppExportPlugin::initialize(Core::EnvisionManager&)
{
	Interaction::ActionRegistry::instance()->registerInputHandler("GenericHandler.TestCppExport", testExport);

	return true;
}

void CppExportPlugin::unload()
{
}

void CppExportPlugin::selfTest(QString testid)
{
	if (testid.isEmpty()) SelfTest::TestManager<CppExportPlugin>::runAllTests().printResultStatistics();
	else SelfTest::TestManager<CppExportPlugin>::runTest(testid).printResultStatistics();
}

bool CppExportPlugin::testExport(Visualization::Item *target, QKeySequence, Interaction::ActionRegistry::InputState)
{
	auto n = target;
	while (n && ! n->node()) n = n->parent();

	if (n)
		if (n->node())
		{
			Core::Profiler::start(true, "Cpp Export", "cpp-export.prof");
			CppExport::CppExporter::exportTree(n->node()->manager(), "exported");
			Core::Profiler::stop("Cpp Export");
			return true;
		}

	return false;
}

}
<|endoftext|>


<commit_before>#include <Automaton.h>
#include "Atm_command.h"

ATM_CLASSNAME & ATM_CLASSNAME::begin( Stream * stream, char buffer[], int size )
{
  const static state_t state_table[] PROGMEM = {
  /*                  ON_ENTER    ON_LOOP    ON_EXIT  EVT_INPUT   EVT_OEL   ELSE */
  /* IDLE     */            -1,        -1,        -1,  READCHAR,       -1,    -1,
  /* READCHAR */  ACT_READCHAR,        -1,        -1,  READCHAR,     SEND,    -1,
  /* SEND     */      ACT_SEND,        -1,        -1,        -1,       -1,  IDLE,
  };
  table( state_table, ELSE );
  _stream = stream;
  _buffer = buffer;
  _bufsize = size;
  _bufptr = 0;
  _sep = " ";
  _eol = '\n';
  _lastch = '\0';
  return *this;
}

ATM_CLASSNAME & ATM_CLASSNAME::onCmd( void (*callback)( ATM_CLASSNAME * cmd ) )
{
  _callback = callback;
  return *this;
}

ATM_CLASSNAME & ATM_CLASSNAME::separator( const char sep[] )
{
  _sep = sep;
  return *this;
}

char * ATM_CLASSNAME::arg( int id ) {

  int cnt = 0;
  int i;
  if ( id == 0 ) return _buffer;
  for ( i = 0; i < _bufptr; i++ ) {
    if ( _buffer[i] == '\0' ) {
      if ( ++cnt == id ) {
        i++;
        break;
      }
    }
  }
  return &_buffer[i];
}

int ATM_CLASSNAME::command( int id, const char * cmdlist ) {

  int cnt = 0;
  char * pamem = arg( id );
  char * pa = pamem;
  const char * pc = cmdlist;
  while ( pc[0] != '\0' ) {
    while ( pc[0] != '\0' && pc[0] == pa[0] ) {
      pc++;
      pa++;
    }
    if ( pa[0] == '\0' )
      return cnt;
    if ( pc[0] == ' ' )
      cnt++;
    pa = pamem;
    pc++;
  }
  return -1;
}

int ATM_CLASSNAME::event( int id )
{
  switch ( id ) {
    case EVT_INPUT :
      return _stream->available();
    case EVT_EOL :
      return _buffer[_bufptr-1] == _eol || _bufptr >= _bufsize;
  }
  return 0;
}

void ATM_CLASSNAME::action( int id )
{
  switch ( id ) {
  	case ACT_READCHAR :
      if ( _stream->available() ) {
        char ch = _stream->read();
        if ( strchr( _sep, ch ) == NULL ) {
          _buffer[_bufptr++] = ch;
          _lastch = ch;
        } else {
          if ( _lastch != '\0' )
            _buffer[_bufptr++] = '\0';
          _lastch = '\0';
        }
      }
      return;
    case ACT_SEND :
      _buffer[--_bufptr] = '\0';
      (*_callback)( this );
      _lastch = '\0';
      _bufptr = 0;
  	  return;
   }
}

<commit_msg>Fixed typo<commit_after>#include <Automaton.h>
#include "Atm_command.h"

ATM_CLASSNAME & ATM_CLASSNAME::begin( Stream * stream, char buffer[], int size )
{
  const static state_t state_table[] PROGMEM = {
  /*                  ON_ENTER    ON_LOOP    ON_EXIT  EVT_INPUT   EVT_EOL   ELSE */
  /* IDLE     */            -1,        -1,        -1,  READCHAR,       -1,    -1,
  /* READCHAR */  ACT_READCHAR,        -1,        -1,  READCHAR,     SEND,    -1,
  /* SEND     */      ACT_SEND,        -1,        -1,        -1,       -1,  IDLE,
  };
  table( state_table, ELSE );
  _stream = stream;
  _buffer = buffer;
  _bufsize = size;
  _bufptr = 0;
  _sep = " ";
  _eol = '\n';
  _lastch = '\0';
  return *this;
}

ATM_CLASSNAME & ATM_CLASSNAME::onCmd( void (*callback)( ATM_CLASSNAME * cmd ) )
{
  _callback = callback;
  return *this;
}

ATM_CLASSNAME & ATM_CLASSNAME::separator( const char sep[] )
{
  _sep = sep;
  return *this;
}

char * ATM_CLASSNAME::arg( int id ) {

  int cnt = 0;
  int i;
  if ( id == 0 ) return _buffer;
  for ( i = 0; i < _bufptr; i++ ) {
    if ( _buffer[i] == '\0' ) {
      if ( ++cnt == id ) {
        i++;
        break;
      }
    }
  }
  return &_buffer[i];
}

int ATM_CLASSNAME::command( int id, const char * cmdlist ) {

  int cnt = 0;
  char * pamem = arg( id );
  char * pa = pamem;
  const char * pc = cmdlist;
  while ( pc[0] != '\0' ) {
    while ( pc[0] != '\0' && pc[0] == pa[0] ) {
      pc++;
      pa++;
    }
    if ( pa[0] == '\0' )
      return cnt;
    if ( pc[0] == ' ' )
      cnt++;
    pa = pamem;
    pc++;
  }
  return -1;
}

int ATM_CLASSNAME::event( int id )
{
  switch ( id ) {
    case EVT_INPUT :
      return _stream->available();
    case EVT_EOL :
      return _buffer[_bufptr-1] == _eol || _bufptr >= _bufsize;
  }
  return 0;
}

void ATM_CLASSNAME::action( int id )
{
  switch ( id ) {
  	case ACT_READCHAR :
      if ( _stream->available() ) {
        char ch = _stream->read();
        if ( strchr( _sep, ch ) == NULL ) {
          _buffer[_bufptr++] = ch;
          _lastch = ch;
        } else {
          if ( _lastch != '\0' )
            _buffer[_bufptr++] = '\0';
          _lastch = '\0';
        }
      }
      return;
    case ACT_SEND :
      _buffer[--_bufptr] = '\0';
      (*_callback)( this );
      _lastch = '\0';
      _bufptr = 0;
  	  return;
   }
}

<|endoftext|>


<commit_before>#pragma once

#include "blackhole/detail/stream/stream.hpp"
#include "blackhole/utils/underlying.hpp"

namespace blackhole {

namespace defaults {

enum class severity {
    debug,
    notice,
    info,
    warning,
    error
};

void
map_severity(aux::attachable_ostringstream& stream, const severity& level) {
    static const char* describe[] = {
        "DEBUG",
        "NOTICE",
        "INFO",
        "WARNING",
        "ERROR"
    };

    typedef blackhole::aux::underlying_type<severity>::type level_type;

    auto value = static_cast<level_type>(level);
    if(value < static_cast<level_type>(sizeof(describe) / sizeof(describe[0])) && value > 0) {
        stream << describe[value];
    } else {
        stream << value;
    }
}

} // namespace defaults

} // namespace blackhole
<commit_msg>[Bug Fix] Fix linker error.<commit_after>#pragma once

#include "blackhole/detail/stream/stream.hpp"
#include "blackhole/utils/underlying.hpp"

namespace blackhole {

namespace defaults {

enum class severity {
    debug,
    notice,
    info,
    warning,
    error
};

inline
void
map_severity(aux::attachable_ostringstream& stream, const severity& level) {
    static const char* describe[] = {
        "DEBUG",
        "NOTICE",
        "INFO",
        "WARNING",
        "ERROR"
    };

    typedef blackhole::aux::underlying_type<severity>::type level_type;

    auto value = static_cast<level_type>(level);
    if(value < static_cast<level_type>(sizeof(describe) / sizeof(describe[0])) && value > 0) {
        stream << describe[value];
    } else {
        stream << value;
    }
}

} // namespace defaults

} // namespace blackhole
<|endoftext|>


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

#include <bonefish/broker/wamp_broker.hpp>
#include <bonefish/broker/wamp_broker_subscriptions.hpp>
#include <bonefish/broker/wamp_broker_topic.hpp>
#include <bonefish/messages/wamp_error_message.hpp>
#include <bonefish/messages/wamp_event_message.hpp>
#include <bonefish/messages/wamp_publish_message.hpp>
#include <bonefish/messages/wamp_published_message.hpp>
#include <bonefish/messages/wamp_subscribe_message.hpp>
#include <bonefish/messages/wamp_subscribed_message.hpp>
#include <bonefish/messages/wamp_unsubscribe_message.hpp>
#include <bonefish/messages/wamp_unsubscribed_message.hpp>
#include <bonefish/session/wamp_session.hpp>
#include <bonefish/trace/trace.hpp>
#include <bonefish/transport/wamp_transport.hpp>

namespace bonefish {

wamp_broker::wamp_broker(const std::string& realm)
    : m_realm(realm)
    , m_publication_id_generator()
    , m_subscription_id_generator()
    , m_sessions()
    , m_session_subscriptions()
    , m_topic_subscriptions()
    , m_subscription_topics()
{
}

wamp_broker::~wamp_broker()
{
}

void wamp_broker::attach_session(const std::shared_ptr<wamp_session>& session)
{
    BONEFISH_TRACE("attach session: %1%", *session);
    auto result = m_sessions.insert(
            std::make_pair(session->get_session_id(), std::move(session)));
    if (!result.second) {
        throw std::logic_error("broker session already registered");
    }
}

void wamp_broker::detach_session(const wamp_session_id& session_id)
{
    auto session_itr = m_sessions.find(session_id);
    if (session_itr == m_sessions.end()) {
        throw std::logic_error("broker session does not exist");
    }

    BONEFISH_TRACE("detach session: %1%", session_itr->second.get());
    auto session_subscriptions_itr = m_session_subscriptions.find(session_id);
    if (session_subscriptions_itr != m_session_subscriptions.end()) {
        BONEFISH_TRACE("cleaning up session subscriptions");
        for (const auto& subscription_id : session_subscriptions_itr->second) {
            auto subscription_topics_itr = m_subscription_topics.find(subscription_id);
            if (subscription_topics_itr == m_subscription_topics.end()) {
                BONEFISH_TRACE("error: broker subscription topics are out of sync");
                continue;
            }

            std::string topic = subscription_topics_itr->second->get_topic();
            BONEFISH_TRACE("cleaning up subscription topic");
            subscription_topics_itr->second->remove_session(session_itr->second);
            if (subscription_topics_itr->second->get_sessions().size() == 0) {
                m_subscription_topics.erase(subscription_id);
            }

            auto topic_subscriptions_itr = m_topic_subscriptions.find(topic);
            if (topic_subscriptions_itr == m_topic_subscriptions.end()) {
                BONEFISH_TRACE("error: broker topic subscriptions are out of sync");
                continue;
            }

            BONEFISH_TRACE("cleaning up topic subscriptions");
            topic_subscriptions_itr->second->remove_subscription(subscription_id);
            if (topic_subscriptions_itr->second->get_subscriptions().size() == 0) {
                m_topic_subscriptions.erase(topic);
            }
        }

        m_session_subscriptions.erase(session_subscriptions_itr);
    }

    m_sessions.erase(session_itr);
}

void wamp_broker::process_publish_message(const wamp_session_id& session_id,
        wamp_publish_message* publish_message)
{
    auto session_itr = m_sessions.find(session_id);
    if (session_itr == m_sessions.end()) {
        throw std::logic_error("broker session does not exist");
    }

    BONEFISH_TRACE("%1%, %2%", *session_itr->second % *publish_message);
    const std::string topic = publish_message->get_topic();
    const wamp_publication_id publication_id = m_publication_id_generator.generate();

    // Since a publish message fans out to potentially numerous event messages
    // we cannot need to be a bit smarter with how we deal with passing zone
    // ownership. For all but the last subscription we make a deep copy of the
    // transient fields for the event messages. When we reach the last subscription
    // it is then safe to just pass ownership of the zone.
    auto topic_subscriptions_itr = m_topic_subscriptions.find(topic);
    if (topic_subscriptions_itr != m_topic_subscriptions.end()) {
        const auto& subscriptions = topic_subscriptions_itr->second->get_subscriptions();
        std::size_t num_subscriptions = subscriptions.size();
        std::size_t current_subscription = 0;

        for (const auto& subscription : subscriptions) {
            const auto& subscription_id = subscription.first;
            const auto& session = subscription.second;

            std::unique_ptr<wamp_event_message> event_message;
            if (++current_subscription < num_subscriptions) {
                event_message.reset(new wamp_event_message());
                event_message->set_subscription_id(subscription_id);
                event_message->set_publication_id(publication_id);
                event_message->set_arguments(
                    msgpack::object(publish_message->get_arguments(), event_message->get_zone()));
                event_message->set_arguments_kw(
                    msgpack::object(publish_message->get_arguments_kw(), event_message->get_zone()));
            } else {
                event_message.reset(new wamp_event_message(publish_message->release_zone()));
                event_message->set_subscription_id(subscription_id);
                event_message->set_publication_id(publication_id);
                event_message->set_arguments(publish_message->get_arguments());
                event_message->set_arguments_kw(publish_message->get_arguments_kw());
            }

            BONEFISH_TRACE("%1%, %2%", *session % *event_message);
            session->get_transport()->send_message(std::move(*event_message));
        }
    }

    // TODO: Publish acknowledgements require support for publish options which
    //       we currently do not yet have working.
    //
    //std::unique_ptr<wamp_published_message> published_message(new wamp_published_message);
    //published_message->set_request_id(publish_message->get_request_id());
    //published_message->set_publication_id(publication_id);
    //session_itr->second->get_transport()->send_message(published_message.get());
}

void wamp_broker::process_subscribe_message(const wamp_session_id& session_id,
        wamp_subscribe_message* subscribe_message)
{
    auto session_itr = m_sessions.find(session_id);
    if (session_itr == m_sessions.end()) {
        throw std::logic_error("broker session does not exist");
    }

    BONEFISH_TRACE("%1%, %2%", *session_itr->second % *subscribe_message);
    wamp_subscription_id subscription_id = m_subscription_id_generator.generate();
    auto& session = session_itr->second;
    {
        auto result = m_topic_subscriptions.insert(
                std::make_pair(subscribe_message->get_topic(), nullptr));

        if (result.second) {
            result.first->second.reset(new wamp_broker_subscriptions());
        }
        result.first->second->add_subscription(subscription_id, session);
    }

    {
        auto result = m_subscription_topics.insert(std::make_pair(subscription_id, nullptr));
        if (result.second) {
            result.first->second.reset(new wamp_broker_topic(subscribe_message->get_topic()));
            result.first->second->add_session(session);
        } else {
            result.first->second->add_session(session);
        }
    }

    m_session_subscriptions[session_id].insert(subscription_id);

    std::unique_ptr<wamp_subscribed_message> subscribed_message(
            new wamp_subscribed_message(subscribe_message->release_zone()));
    subscribed_message->set_request_id(subscribe_message->get_request_id());
    subscribed_message->set_subscription_id(subscription_id);

    BONEFISH_TRACE("%1%, %2%", *session % *subscribed_message);
    session->get_transport()->send_message(std::move(*subscribed_message));
}

void wamp_broker::process_unsubscribe_message(const wamp_session_id& session_id,
        wamp_unsubscribe_message* unsubscribe_message)
{
    auto session_itr = m_sessions.find(session_id);
    if (session_itr == m_sessions.end()) {
        throw std::logic_error("broker session does not exist");
    }

    BONEFISH_TRACE("%1%, %2%", *session_itr->second % *unsubscribe_message);
    auto session_subscriptions_itr = m_session_subscriptions.find(session_id);
    if (session_subscriptions_itr == m_session_subscriptions.end()) {
        send_error(session_itr->second->get_transport(), unsubscribe_message->get_type(),
                unsubscribe_message->get_request_id(), std::string("wamp.error.no_subscriptions_for_session"));
        return;
    }

    const wamp_subscription_id& subscription_id = unsubscribe_message->get_subscription_id();
    if (session_subscriptions_itr->second.erase(subscription_id) == 0) {
        send_error(session_itr->second->get_transport(), unsubscribe_message->get_type(),
                unsubscribe_message->get_request_id(), std::string("wamp.error.no_such_subscription"));
        return;
    }

    auto subscription_topics_itr = m_subscription_topics.find(subscription_id);
    if (subscription_topics_itr == m_subscription_topics.end()) {
        BONEFISH_TRACE("error: broker subscription topics are out of sync");
    } else {
        std::string topic = subscription_topics_itr->second->get_topic();
        subscription_topics_itr->second->remove_session(session_itr->second);
        if (subscription_topics_itr->second->get_sessions().size() == 0) {
            m_subscription_topics.erase(subscription_id);
        }

        auto topic_subscriptions_itr = m_topic_subscriptions.find(topic);
        if (topic_subscriptions_itr == m_topic_subscriptions.end()) {
            BONEFISH_TRACE("error: broker topic subscription out of sync");
        } else {
            topic_subscriptions_itr->second->remove_subscription(subscription_id);
            if (topic_subscriptions_itr->second->get_subscriptions().size() == 0) {
                m_topic_subscriptions.erase(topic);
            }
        }
    }

    std::unique_ptr<wamp_unsubscribed_message> unsubscribed_message(
            new wamp_unsubscribed_message(unsubscribe_message->release_zone()));
    unsubscribed_message->set_request_id(unsubscribe_message->get_request_id());

    BONEFISH_TRACE("%1%, %2%", *session_itr->second % *unsubscribed_message);
    session_itr->second->get_transport()->send_message(std::move(*unsubscribed_message));
}

void wamp_broker::send_error(const std::unique_ptr<wamp_transport>& transport,
        const wamp_message_type request_type, const wamp_request_id& request_id,
        const std::string& error) const
{
    std::unique_ptr<wamp_error_message> error_message(new wamp_error_message);
    error_message->set_request_type(request_type);
    error_message->set_request_id(request_id);
    error_message->set_error(error);

    BONEFISH_TRACE("%1%", *error_message);
    transport->send_message(std::move(*error_message));
}

} // namespace bonefish
<commit_msg>Fix github issue #43<commit_after>/**
 *  Copyright (C) 2015 Topology LP
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <bonefish/broker/wamp_broker.hpp>
#include <bonefish/broker/wamp_broker_subscriptions.hpp>
#include <bonefish/broker/wamp_broker_topic.hpp>
#include <bonefish/messages/wamp_error_message.hpp>
#include <bonefish/messages/wamp_event_message.hpp>
#include <bonefish/messages/wamp_publish_message.hpp>
#include <bonefish/messages/wamp_published_message.hpp>
#include <bonefish/messages/wamp_subscribe_message.hpp>
#include <bonefish/messages/wamp_subscribed_message.hpp>
#include <bonefish/messages/wamp_unsubscribe_message.hpp>
#include <bonefish/messages/wamp_unsubscribed_message.hpp>
#include <bonefish/session/wamp_session.hpp>
#include <bonefish/trace/trace.hpp>
#include <bonefish/transport/wamp_transport.hpp>

namespace bonefish {

wamp_broker::wamp_broker(const std::string& realm)
    : m_realm(realm)
    , m_publication_id_generator()
    , m_subscription_id_generator()
    , m_sessions()
    , m_session_subscriptions()
    , m_topic_subscriptions()
    , m_subscription_topics()
{
}

wamp_broker::~wamp_broker()
{
}

void wamp_broker::attach_session(const std::shared_ptr<wamp_session>& session)
{
    BONEFISH_TRACE("attach session: %1%", *session);
    auto result = m_sessions.insert(
            std::make_pair(session->get_session_id(), std::move(session)));
    if (!result.second) {
        throw std::logic_error("broker session already registered");
    }
}

void wamp_broker::detach_session(const wamp_session_id& session_id)
{
    auto session_itr = m_sessions.find(session_id);
    if (session_itr == m_sessions.end()) {
        throw std::logic_error("broker session does not exist");
    }

    BONEFISH_TRACE("detach session: %1%", session_itr->second.get());
    auto session_subscriptions_itr = m_session_subscriptions.find(session_id);
    if (session_subscriptions_itr != m_session_subscriptions.end()) {
        BONEFISH_TRACE("cleaning up session subscriptions");
        for (const auto& subscription_id : session_subscriptions_itr->second) {
            auto subscription_topics_itr = m_subscription_topics.find(subscription_id);
            if (subscription_topics_itr == m_subscription_topics.end()) {
                BONEFISH_TRACE("error: broker subscription topics are out of sync");
                continue;
            }

            std::string topic = subscription_topics_itr->second->get_topic();
            BONEFISH_TRACE("cleaning up subscription topic");
            subscription_topics_itr->second->remove_session(session_itr->second);
            if (subscription_topics_itr->second->get_sessions().size() == 0) {
                m_subscription_topics.erase(subscription_id);
            }

            auto topic_subscriptions_itr = m_topic_subscriptions.find(topic);
            if (topic_subscriptions_itr == m_topic_subscriptions.end()) {
                BONEFISH_TRACE("error: broker topic subscriptions are out of sync");
                continue;
            }

            BONEFISH_TRACE("cleaning up topic subscriptions");
            topic_subscriptions_itr->second->remove_subscription(subscription_id);
            if (topic_subscriptions_itr->second->get_subscriptions().size() == 0) {
                m_topic_subscriptions.erase(topic);
            }
        }

        m_session_subscriptions.erase(session_subscriptions_itr);
    }

    m_sessions.erase(session_itr);
}

void wamp_broker::process_publish_message(const wamp_session_id& session_id,
        wamp_publish_message* publish_message)
{
    auto session_itr = m_sessions.find(session_id);
    if (session_itr == m_sessions.end()) {
        throw std::logic_error("broker session does not exist");
    }

    BONEFISH_TRACE("%1%, %2%", *session_itr->second % *publish_message);
    const std::string topic = publish_message->get_topic();
    const wamp_publication_id publication_id = m_publication_id_generator.generate();

    // Since a publish message fans out to potentially numerous event messages
    // we cannot need to be a bit smarter with how we deal with passing zone
    // ownership. For all but the last subscription we make a deep copy of the
    // transient fields for the event messages. When we reach the last subscription
    // it is then safe to just pass ownership of the zone.
    auto topic_subscriptions_itr = m_topic_subscriptions.find(topic);
    if (topic_subscriptions_itr != m_topic_subscriptions.end()) {
        // Fix github issue #43 = work on a COPY of member subscriptions to avoid iterator
        // invalidation should  session->get_transport()->send_message() failure close & remove the session.
        const auto subscriptions = topic_subscriptions_itr->second->get_subscriptions();
        std::size_t num_subscriptions = subscriptions.size();
        std::size_t current_subscription = 0;

        for (const auto& subscription : subscriptions) {
            const auto& subscription_id = subscription.first;
            const auto& session = subscription.second;

            std::unique_ptr<wamp_event_message> event_message;
            if (++current_subscription < num_subscriptions) {
                event_message.reset(new wamp_event_message());
                event_message->set_subscription_id(subscription_id);
                event_message->set_publication_id(publication_id);
                event_message->set_arguments(
                    msgpack::object(publish_message->get_arguments(), event_message->get_zone()));
                event_message->set_arguments_kw(
                    msgpack::object(publish_message->get_arguments_kw(), event_message->get_zone()));
            } else {
                event_message.reset(new wamp_event_message(publish_message->release_zone()));
                event_message->set_subscription_id(subscription_id);
                event_message->set_publication_id(publication_id);
                event_message->set_arguments(publish_message->get_arguments());
                event_message->set_arguments_kw(publish_message->get_arguments_kw());
            }

            BONEFISH_TRACE("%1%, %2%", *session % *event_message);
            session->get_transport()->send_message(std::move(*event_message));
        }
    }

    // TODO: Publish acknowledgements require support for publish options which
    //       we currently do not yet have working.
    //
    //std::unique_ptr<wamp_published_message> published_message(new wamp_published_message);
    //published_message->set_request_id(publish_message->get_request_id());
    //published_message->set_publication_id(publication_id);
    //session_itr->second->get_transport()->send_message(published_message.get());
}

void wamp_broker::process_subscribe_message(const wamp_session_id& session_id,
        wamp_subscribe_message* subscribe_message)
{
    auto session_itr = m_sessions.find(session_id);
    if (session_itr == m_sessions.end()) {
        throw std::logic_error("broker session does not exist");
    }

    BONEFISH_TRACE("%1%, %2%", *session_itr->second % *subscribe_message);
    wamp_subscription_id subscription_id = m_subscription_id_generator.generate();
    auto& session = session_itr->second;
    {
        auto result = m_topic_subscriptions.insert(
                std::make_pair(subscribe_message->get_topic(), nullptr));

        if (result.second) {
            result.first->second.reset(new wamp_broker_subscriptions());
        }
        result.first->second->add_subscription(subscription_id, session);
    }

    {
        auto result = m_subscription_topics.insert(std::make_pair(subscription_id, nullptr));
        if (result.second) {
            result.first->second.reset(new wamp_broker_topic(subscribe_message->get_topic()));
            result.first->second->add_session(session);
        } else {
            result.first->second->add_session(session);
        }
    }

    m_session_subscriptions[session_id].insert(subscription_id);

    std::unique_ptr<wamp_subscribed_message> subscribed_message(
            new wamp_subscribed_message(subscribe_message->release_zone()));
    subscribed_message->set_request_id(subscribe_message->get_request_id());
    subscribed_message->set_subscription_id(subscription_id);

    BONEFISH_TRACE("%1%, %2%", *session % *subscribed_message);
    session->get_transport()->send_message(std::move(*subscribed_message));
}

void wamp_broker::process_unsubscribe_message(const wamp_session_id& session_id,
        wamp_unsubscribe_message* unsubscribe_message)
{
    auto session_itr = m_sessions.find(session_id);
    if (session_itr == m_sessions.end()) {
        throw std::logic_error("broker session does not exist");
    }

    BONEFISH_TRACE("%1%, %2%", *session_itr->second % *unsubscribe_message);
    auto session_subscriptions_itr = m_session_subscriptions.find(session_id);
    if (session_subscriptions_itr == m_session_subscriptions.end()) {
        send_error(session_itr->second->get_transport(), unsubscribe_message->get_type(),
                unsubscribe_message->get_request_id(), std::string("wamp.error.no_subscriptions_for_session"));
        return;
    }

    const wamp_subscription_id& subscription_id = unsubscribe_message->get_subscription_id();
    if (session_subscriptions_itr->second.erase(subscription_id) == 0) {
        send_error(session_itr->second->get_transport(), unsubscribe_message->get_type(),
                unsubscribe_message->get_request_id(), std::string("wamp.error.no_such_subscription"));
        return;
    }

    auto subscription_topics_itr = m_subscription_topics.find(subscription_id);
    if (subscription_topics_itr == m_subscription_topics.end()) {
        BONEFISH_TRACE("error: broker subscription topics are out of sync");
    } else {
        std::string topic = subscription_topics_itr->second->get_topic();
        subscription_topics_itr->second->remove_session(session_itr->second);
        if (subscription_topics_itr->second->get_sessions().size() == 0) {
            m_subscription_topics.erase(subscription_id);
        }

        auto topic_subscriptions_itr = m_topic_subscriptions.find(topic);
        if (topic_subscriptions_itr == m_topic_subscriptions.end()) {
            BONEFISH_TRACE("error: broker topic subscription out of sync");
        } else {
            topic_subscriptions_itr->second->remove_subscription(subscription_id);
            if (topic_subscriptions_itr->second->get_subscriptions().size() == 0) {
                m_topic_subscriptions.erase(topic);
            }
        }
    }

    std::unique_ptr<wamp_unsubscribed_message> unsubscribed_message(
            new wamp_unsubscribed_message(unsubscribe_message->release_zone()));
    unsubscribed_message->set_request_id(unsubscribe_message->get_request_id());

    BONEFISH_TRACE("%1%, %2%", *session_itr->second % *unsubscribed_message);
    session_itr->second->get_transport()->send_message(std::move(*unsubscribed_message));
}

void wamp_broker::send_error(const std::unique_ptr<wamp_transport>& transport,
        const wamp_message_type request_type, const wamp_request_id& request_id,
        const std::string& error) const
{
    std::unique_ptr<wamp_error_message> error_message(new wamp_error_message);
    error_message->set_request_type(request_type);
    error_message->set_request_id(request_id);
    error_message->set_error(error);

    BONEFISH_TRACE("%1%", *error_message);
    transport->send_message(std::move(*error_message));
}

} // namespace bonefish
<|endoftext|>


<commit_before><commit_msg>Add an important reminder to the socket file.<commit_after><|endoftext|>


<commit_before>/*
 * DeleteLink.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 *
 * Author: Linas Vepstas <linasvepstas@gmail.com>  January 2009
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atomspace/AtomTable.h>
#include <opencog/atomutils/FindUtils.h>

#include "DeleteLink.h"

using namespace opencog;

void DeleteLink::init(void)
{
	// The handleset must contain a variable in it, somewhere.
	// If it doesn't, then the entire handleset should be deleted
	// (removed from the atomspace). We can't do this at constructor
	// time, because we don't know the atomspace yet.  So we hack
	// around this by throwing at constructor time.
	//
	FreeLink::init();
	if (0 == _vars.varseq.size())
		// throw DeleteException();
		throw InvalidParamException(TRACE_INFO,
			"Cannot create a fully grounded DeleteLink!");
}

#if 0
/*****
Well, we cannot really implement this here; but this is what
it should actually do.  We can't implement it here, because
fully-grounded DeleteLink's cannot exist.
****/
Handle DeleteLink::execute(AtomSpace * as) const
{
	const HandleSeq& oset = _outgoing;
	for (const Handle& h : oset)
	{
		Type t = h->getType();
		if (VARIABLE_NODE != t)
			as->removeAtom(h, true);
	}
	return Handle::UNDEFINED;
}
#endif

DeleteLink::DeleteLink(const HandleSeq& oset,
                       TruthValuePtr tv, AttentionValuePtr av)
	: FreeLink(DELETE_LINK, oset, tv, av)
{
	init();
}

DeleteLink::DeleteLink(Link &l)
	: FreeLink(l)
{
	// Type must be as expected
	Type tscope = l.getType();
	if (not classserver().isA(tscope, DELETE_LINK))
	{
		const std::string& tname = classserver().getTypeName(tscope);
		throw InvalidParamException(TRACE_INFO,
			"Expecting a DeleteLink, got %s", tname.c_str());
	}

	init();
}

/* ===================== END OF FILE ===================== */
<commit_msg>Remove un-needed includes<commit_after>/*
 * DeleteLink.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 *
 * Author: Linas Vepstas <linasvepstas@gmail.com>  January 2009
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atomutils/FindUtils.h>

#include "DeleteLink.h"

using namespace opencog;

void DeleteLink::init(void)
{
	// The handleset must contain a variable in it, somewhere.
	// If it doesn't, then the entire handleset should be deleted
	// (removed from the atomspace). We can't do this at constructor
	// time, because we don't know the atomspace yet.  So we hack
	// around this by throwing at constructor time.
	//
	FreeLink::init();
	if (0 == _vars.varseq.size())
		// throw DeleteException();
		throw InvalidParamException(TRACE_INFO,
			"Cannot create a fully grounded DeleteLink!");
}

#if 0
/*****
Well, we cannot really implement this here; but this is what
it should actually do.  We can't implement it here, because
fully-grounded DeleteLink's cannot exist.
****/
Handle DeleteLink::execute(AtomSpace * as) const
{
	const HandleSeq& oset = _outgoing;
	for (const Handle& h : oset)
	{
		Type t = h->getType();
		if (VARIABLE_NODE != t)
			as->removeAtom(h, true);
	}
	return Handle::UNDEFINED;
}
#endif

DeleteLink::DeleteLink(const HandleSeq& oset,
                       TruthValuePtr tv, AttentionValuePtr av)
	: FreeLink(DELETE_LINK, oset, tv, av)
{
	init();
}

DeleteLink::DeleteLink(Link &l)
	: FreeLink(l)
{
	// Type must be as expected
	Type tscope = l.getType();
	if (not classserver().isA(tscope, DELETE_LINK))
	{
		const std::string& tname = classserver().getTypeName(tscope);
		throw InvalidParamException(TRACE_INFO,
			"Expecting a DeleteLink, got %s", tname.c_str());
	}

	init();
}

/* ===================== END OF FILE ===================== */
<|endoftext|>


<commit_before>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>

#include <libclientserver.h>

ClientUnix::ClientUnix(const std::string path)
{
	Init();
	m_fd = -1;
	m_path = path;
	m_connected = false;
}

ClientUnix::~ClientUnix()
{
	Disconnect();
}

void ClientUnix::Connect()
{
	m_quit = false;
	Thread::Start();
}

bool ClientUnix::IsConnected()
{
	return m_connected;
}

void ClientUnix::Disconnect()
{
	m_quit = true;
	ScopedReadLock rlock(&m_WriterLock);
	if (m_fd >= 0)
	{
		if (shutdown(m_fd, SHUT_WR) < 0)
			abort();	//FIXME: This can be a valid error case
	}

	Thread::Stop();
}

bool ClientUnix::DoSendRequest(Request *request, const struct timespec *Timeout)
{
	std::string str = "REQUEST " + request->Encode() + "\n";
	return SendLine(&str, Timeout);
}

bool ClientUnix::DoSendCommand(Request *request, const struct timespec *Timeout)
{
	std::string str = "COMMAND " + request->Encode() + "\n";
	return SendLine(&str, Timeout);
}

bool ClientUnix::SendLine(const std::string *str, const struct timespec *Timeout)
{
	ScopedLock lock1(&m_WriterMutex);
	if (IsConnected() == false)
		return false;

	ScopedReadLock rlock(&m_WriterLock);
	printf("Writing(%d): %s\n", m_fd, str->c_str());
	int err = write(m_fd, str->c_str(), str->size());
	//FIXME: Deal with partial write
	if (err == (int) str->length())
		return true;

	RaiseOnSendError(errno, Errno::ToStr());
	return false;
}

void ClientUnix::Run()
{
	struct sockaddr_un addr;
	size_t addr_len = sizeof(addr);

	while(m_quit == false)
	{
		ReadBuffer Buffer(1024 * 2048);
		int fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if (fd < 0)
		{
			RaiseOnConnectError(errno, Errno::ToStr());
			Time::Sleep(&m_ReConnectTimeout);
			if (close(fd) < 0)
				abort();
			continue;
		}

		memset(&addr, addr_len, 0);

		addr.sun_family = AF_UNIX;
		snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", m_path.c_str());

		if (connect(fd, (struct sockaddr *) &addr, addr_len) < 0)
		{
			RaiseOnConnectError(errno, Errno::ToStr());
			if (close(fd) < 0)
				abort();

			Time::Sleep(&m_ReConnectTimeout);
			continue;
		}

		m_fd = fd;	//Allow write to access this now that we are connected
		m_connected = true;
		RaiseOnConnect();

		//Read Responses / Events / Etc....
		//FIXME: Need converted to non-blocking or a dead connection / server stops the disconnect from working!
		while(m_quit == false && m_fd >= 0)
		{
			int ret = Buffer.Read(m_fd);
			if (ret <= 0)
			{
				m_connected = false;
				RaiseOnDisconnect(ret, Errno::ToStr(ret));
				ScopedWriteLock wlock(&m_WriterLock);	//We need to protect m_fd from the writer side while we close it
				if (close(m_fd) < 0)
					abort();
				m_fd = -1;
				break;
			}

			//Read Line at a time
			std::string line;
			bool HasLine = Buffer.GetLine(&line);
			while(HasLine == true)
			{
				RaiseOnData(&line);
				HasLine = Buffer.GetLine(&line);
			}
		}
	} //m_quit == false
}

<commit_msg>Fix Client Refusing the disconnect<commit_after>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>

#include <libclientserver.h>

ClientUnix::ClientUnix(const std::string path)
{
	Init();
	m_fd = -1;
	m_path = path;
	m_connected = false;
}

ClientUnix::~ClientUnix()
{
	Disconnect();
}

void ClientUnix::Connect()
{
	m_quit = false;
	Thread::Start();
}

bool ClientUnix::IsConnected()
{
	return m_connected;
}

void ClientUnix::Disconnect()
{
	m_quit = true;
	ScopedReadLock rlock(&m_WriterLock);
	if (m_fd >= 0)
	{
		if (shutdown(m_fd, SHUT_WR) < 0)
			abort();	//FIXME: This can be a valid error case
	}
	rlock.Unlock();

	Thread::Stop();
}

bool ClientUnix::DoSendRequest(Request *request, const struct timespec *Timeout)
{
	std::string str = "REQUEST " + request->Encode() + "\n";
	return SendLine(&str, Timeout);
}

bool ClientUnix::DoSendCommand(Request *request, const struct timespec *Timeout)
{
	std::string str = "COMMAND " + request->Encode() + "\n";
	return SendLine(&str, Timeout);
}

bool ClientUnix::SendLine(const std::string *str, const struct timespec *Timeout)
{
	ScopedLock lock1(&m_WriterMutex);
	if (IsConnected() == false)
		return false;

	ScopedReadLock rlock(&m_WriterLock);
	printf("Writing(%d): %s\n", m_fd, str->c_str());
	int err = write(m_fd, str->c_str(), str->size());
	//FIXME: Deal with partial write
	if (err == (int) str->length())
		return true;

	RaiseOnSendError(errno, Errno::ToStr());
	return false;
}

void ClientUnix::Run()
{
	struct sockaddr_un addr;
	size_t addr_len = sizeof(addr);

	while(m_quit == false)
	{
		ReadBuffer Buffer(1024 * 2048);
		int fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if (fd < 0)
		{
			RaiseOnConnectError(errno, Errno::ToStr());
			Time::Sleep(&m_ReConnectTimeout);
			if (close(fd) < 0)
				abort();
			continue;
		}

		memset(&addr, addr_len, 0);

		addr.sun_family = AF_UNIX;
		snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", m_path.c_str());

		if (connect(fd, (struct sockaddr *) &addr, addr_len) < 0)
		{
			RaiseOnConnectError(errno, Errno::ToStr());
			if (close(fd) < 0)
				abort();

			Time::Sleep(&m_ReConnectTimeout);
			continue;
		}

		m_fd = fd;	//Allow write to access this now that we are connected
		m_connected = true;
		RaiseOnConnect();

		//Read Responses / Events / Etc....
		//FIXME: Need converted to non-blocking or a dead connection / server stops the disconnect from working!
		while(m_quit == false && m_fd >= 0)
		{
			int ret = Buffer.Read(m_fd);
			if (ret <= 0)
			{
				m_connected = false;
				RaiseOnDisconnect(ret, Errno::ToStr(ret));
				ScopedWriteLock wlock(&m_WriterLock);	//We need to protect m_fd from the writer side while we close it
				if (close(m_fd) < 0)
					abort();
				m_fd = -1;
				break;
			}

			//Read Line at a time
			std::string line;
			bool HasLine = Buffer.GetLine(&line);
			while(HasLine == true)
			{
				RaiseOnData(&line);
				HasLine = Buffer.GetLine(&line);
			}
		}
	} //m_quit == false
}

<|endoftext|>


<commit_before>#include "ClueWidget.h"

#include "Colors.h"

#include <QDebug>

namespace cygnus {

static constexpr int kPixelDelta = 5;

ClueWidget::ClueWidget(QWidget *parent) : QListWidget(parent) {
  setMinimumWidth(200);
}

void ClueWidget::modifySize(int delta) {
  qDebug() << "Changing size by" << delta;
  for (uint32_t i = 0, e = count(); i < e; ++i) {
    QFont font = item(i)->font();
    font.setPointSize(font.pointSize() + delta);
    item(i)->setFont(font);
  }
  qApp->processEvents();
}

void ClueWidget::mousePressEvent(QMouseEvent *event) {
  if (event->button() == Qt::LeftButton) {
    mousePressed_ = true;
  }
  QListWidget::mousePressEvent(event);
}

void ClueWidget::mouseMoveEvent(QMouseEvent *event) {
  if (!mousePressed_) {
    // Disable click and drag.
    QListWidget::mouseMoveEvent(event);
  }
}

void ClueWidget::mouseReleaseEvent(QMouseEvent *event) {
  if (event->button() == Qt::LeftButton) {
    mousePressed_ = false;
  }
  QListWidget::mouseReleaseEvent(event);
}

void ClueWidget::setPrimary() {
  setStyleSheet(QString("QListView::item:selected { background: %1 }")
                    .arg(Colors::colorToString(Colors::PRIMARY_HIGHLIGHT)));
}

void ClueWidget::setSecondary() {
  setStyleSheet(QString("QListView::item:selected { background: %1 }")
                    .arg(Colors::colorToString(Colors::SECONDARY_HIGHLIGHT)));
}

} // namespace cygnus
<commit_msg>Cleanup.<commit_after>#include "ClueWidget.h"

#include "Colors.h"

#include <QDebug>

namespace cygnus {

static constexpr int kPixelDelta = 5;

ClueWidget::ClueWidget(QWidget *parent) : QListWidget(parent) {
  setMinimumWidth(200);
}

void ClueWidget::modifySize(int delta) {
  qDebug() << "Changing size by" << delta;
  for (uint32_t i = 0, e = count(); i < e; ++i) {
    QFont font = item(i)->font();
    font.setPointSize(font.pointSize() + delta);
    item(i)->setFont(font);
  }
}

void ClueWidget::mousePressEvent(QMouseEvent *event) {
  if (event->button() == Qt::LeftButton) {
    mousePressed_ = true;
  }
  QListWidget::mousePressEvent(event);
}

void ClueWidget::mouseMoveEvent(QMouseEvent *event) {
  if (!mousePressed_) {
    // Disable click and drag.
    QListWidget::mouseMoveEvent(event);
  }
}

void ClueWidget::mouseReleaseEvent(QMouseEvent *event) {
  if (event->button() == Qt::LeftButton) {
    mousePressed_ = false;
  }
  QListWidget::mouseReleaseEvent(event);
}

void ClueWidget::setPrimary() {
  setStyleSheet(QString("QListView::item:selected { background: %1 }")
                    .arg(Colors::colorToString(Colors::PRIMARY_HIGHLIGHT)));
}

void ClueWidget::setSecondary() {
  setStyleSheet(QString("QListView::item:selected { background: %1 }")
                    .arg(Colors::colorToString(Colors::SECONDARY_HIGHLIGHT)));
}

} // namespace cygnus
<|endoftext|>


<commit_before>///
/// @file  P2.cpp
/// @brief 2nd partial sieve function.
///        P2(x, y) counts the numbers <= x that have exactly 2 prime
///        factors each exceeding the a-th prime.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <primesieve.hpp>
#include <aligned_vector.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {
namespace P2 {

/// @return previous_prime or -1 if old <= 2
inline int64_t get_previous_prime(primesieve::iterator* iter, int64_t old)
{
  return (old > 2) ? iter->previous_prime() : -1;
}

/// For each prime calculate its first multiple >= low
vector<int64_t> generate_next_multiples(int64_t low, int64_t size, vector<int32_t>& primes)
{
  vector<int64_t> next;

  next.reserve(size);
  next.push_back(0);

  for (int64_t b = 1; b < size; b++)
  {
    int64_t prime = primes[b];
    int64_t next_multiple = ceil_div(low, prime) * prime;
    next_multiple += prime * (~next_multiple & 1);
    next_multiple = max(prime * prime, next_multiple);
    next.push_back(next_multiple);
  }

  return next;
}

template <typename T>
T P2_thread(T x,
            int64_t y,
            int64_t segment_size,
            int64_t segments_per_thread,
            int64_t thread_num,
            int64_t low,
            int64_t limit,
            int64_t& pix,
            int64_t& pix_count,
            vector<int32_t>& primes)
{
  pix = 0;
  pix_count = 0;
  low += thread_num * segments_per_thread * segment_size;
  limit = min(low + segments_per_thread * segment_size, limit);
  int64_t size = pi_bsearch(primes, isqrt(limit)) + 1;
  int64_t start = (int64_t) max((int64_t) (x / limit + 1), y);
  int64_t stop  = (int64_t) min(x / low, isqrt(x));
  T P2_thread = 0;

  // P2_thread = \sum_{i=pi[start]}^{pi[stop]} pi(x / primes[i]) - pi(low - 1)
  // We use a reverse prime iterator to calculate P2_thread
  primesieve::iterator iter(stop + 1, start);
  int64_t previous_prime = get_previous_prime(&iter, stop + 1);
  int64_t xp = (int64_t) (x / previous_prime);

  vector<int64_t> next = generate_next_multiples(low, size, primes);
  BitSieve sieve(segment_size);

  // segmented sieve of Eratosthenes
  for (; low < limit; low += segment_size)
  {
    // current segment = interval [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t sqrt = isqrt(high - 1);
    int64_t j = 0;

    sieve.fill(low, high);

    // cross-off multiples
    for (int64_t i = 2; i < size && primes[i] <= sqrt; i++)
    {
      int64_t k;
      int64_t p2 = primes[i] * 2;
      for (k = next[i]; k < high; k += p2)
        sieve.unset(k - low);
      next[i] = k;
    }

    while (previous_prime >= start && xp < high)
    {
      pix += sieve.count(j, xp - low);
      j = xp - low + 1;
      pix_count++;
      P2_thread += pix;
      previous_prime = get_previous_prime(&iter, previous_prime);
      xp = (int64_t) (x / previous_prime);
    }

    pix += sieve.count(j, (high - 1) - low);
  }

  return P2_thread;
}

void balanceLoad(int64_t* segments_per_thread, double seconds1, double time1)
{
  double time2 = get_wtime();
  double seconds = time2 - seconds1;
  double time = time2 - time1;
  double increase_threshold = in_between(0.3, time / 100, 20);

  if (seconds < increase_threshold)
    *segments_per_thread += *segments_per_thread * 3;
  else if (*segments_per_thread >= 4)
    *segments_per_thread -= *segments_per_thread / 4;
}

/// P2(x, y) counts the numbers <= x that have exactly 2 prime
/// factors each exceeding the a-th prime, a = pi(y).
/// Space complexity: O((x / y)^(1/2)).
///
template <typename T>
T P2(T x, int64_t y, int threads)
{
  T a = pi_legendre(y, 1);
  T b = pi_legendre((int64_t) isqrt(x), 1);

  if (x < 4 || a >= b)
    return 0;

  if (print_status())
  {
    cout << endl;
    cout << "=== P2(x, y) ===" << endl;
    cout << "Computation of the 2nd partial sieve function" << endl;
  }

  double time = get_wtime();
  int64_t low = 2;
  int64_t limit = (int64_t)(x / max<int64_t>(1, y));
  int64_t segment_size = max<int64_t>(1 << 12, isqrt(limit));
  int64_t segments_per_thread = 1;
  threads = validate_threads(threads, limit);

  vector<int32_t> primes = generate_primes(isqrt(limit));
  aligned_vector<int64_t> pix(threads);
  aligned_vector<int64_t> pix_counts(threads);

  // \sum_{i=a+1}^{b} pi(x / primes[i]) - (i - 1)
  // initialize with \sum_{i=a+1}^{b} -i + 1
  T sum = (a - 2) * (a + 1) / 2 - (b - 2) * (b + 1) / 2;
  T pix_total = 0;

  while (low < limit)
  {
    int64_t segments = ceil_div(limit - low, segment_size);
    threads = in_between(1, threads, segments);
    segments_per_thread = in_between(1, segments_per_thread, ceil_div(segments, threads));
    double seconds = get_wtime();

    #pragma omp parallel for \
        num_threads(threads) reduction(+: sum)
    for (int i = 0; i < threads; i++)
      sum += P2_thread(x, y, segment_size, segments_per_thread, i,
         low, limit, pix[i], pix_counts[i], primes);

    low += segments_per_thread * threads * segment_size;
    balanceLoad(&segments_per_thread, seconds, time);

    // Add missing sum contributions in order
    for (int i = 0; i < threads; i++)
    {
      sum += pix_total * pix_counts[i];
      pix_total += pix[i];
    }

    if (print_status())
      cout << "\rStatus: " << get_percent(low, limit) << '%' << flush;
  }

  if (print_status())
    print_result("P2", sum, time);

  return sum;
}

} // namespace P2
} // namespace

namespace primecount {

int64_t P2(int64_t x, int64_t y, int threads)
{
  return P2::P2(x, y, threads);
}

#ifdef HAVE_INT128_T

int128_t P2(int128_t x, int64_t y, int threads)
{
  return P2::P2(x, y, threads);
}

#endif

/// P2_lehmer(x, a) counts the numbers <= x that have exactly 2 prime
/// factors each exceeding the a-th prime. This implementation is
/// optimized for small values of a < pi(x^(1/3)) which requires
/// sieving up to a large limit (x / primes[a]). Sieving is done in
/// parallel using primesieve (segmented sieve of Eratosthenes).
/// Space complexity: O(pi(sqrt(x))).
///
int64_t P2_lehmer(int64_t x, int64_t a, int threads)
{
  if (print_status())
  {
    cout << endl;
    cout << "=== P2_lehmer(x, a) ===" << endl;
    cout << "Computation of the 2nd partial sieve function" << endl;
  }

  double time = get_wtime();
  vector<int32_t> primes = generate_primes(isqrt(x));
  vector<int64_t> counts(primes.size());

  int64_t b = pi_bsearch(primes, isqrt(x));
  int64_t sum = 0;
  int64_t pix = 0;

  #pragma omp parallel for schedule(dynamic) \
      num_threads(validate_threads(threads, b, 1000))
  for (int64_t i = b; i > a; i--)
  {
    int64_t prev = (i == b) ? 0 : x / primes[i + 1] + 1;
    int64_t xi = x / primes[i];
    counts[i] = primesieve::count_primes(prev, xi);
  }

  for (int64_t i = b; i > a; i--)
  {
    pix += counts[i];
    sum += pix - (i - 1);
  }

  if (print_status())
    print_result("P2", sum, time);

  return sum;
}

} // namespace primecount
<commit_msg>tune P2(x, a) load balancer<commit_after>///
/// @file  P2.cpp
/// @brief 2nd partial sieve function.
///        P2(x, y) counts the numbers <= x that have exactly 2 prime
///        factors each exceeding the a-th prime.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <primesieve.hpp>
#include <aligned_vector.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {
namespace P2 {

/// @return previous_prime or -1 if old <= 2
inline int64_t get_previous_prime(primesieve::iterator* iter, int64_t old)
{
  return (old > 2) ? iter->previous_prime() : -1;
}

/// For each prime calculate its first multiple >= low
vector<int64_t> generate_next_multiples(int64_t low, int64_t size, vector<int32_t>& primes)
{
  vector<int64_t> next;

  next.reserve(size);
  next.push_back(0);

  for (int64_t b = 1; b < size; b++)
  {
    int64_t prime = primes[b];
    int64_t next_multiple = ceil_div(low, prime) * prime;
    next_multiple += prime * (~next_multiple & 1);
    next_multiple = max(prime * prime, next_multiple);
    next.push_back(next_multiple);
  }

  return next;
}

template <typename T>
T P2_thread(T x,
            int64_t y,
            int64_t segment_size,
            int64_t segments_per_thread,
            int64_t thread_num,
            int64_t low,
            int64_t limit,
            int64_t& pix,
            int64_t& pix_count,
            vector<int32_t>& primes)
{
  pix = 0;
  pix_count = 0;
  low += thread_num * segments_per_thread * segment_size;
  limit = min(low + segments_per_thread * segment_size, limit);
  int64_t size = pi_bsearch(primes, isqrt(limit)) + 1;
  int64_t start = (int64_t) max((int64_t) (x / limit + 1), y);
  int64_t stop  = (int64_t) min(x / low, isqrt(x));
  T P2_thread = 0;

  // P2_thread = \sum_{i=pi[start]}^{pi[stop]} pi(x / primes[i]) - pi(low - 1)
  // We use a reverse prime iterator to calculate P2_thread
  primesieve::iterator iter(stop + 1, start);
  int64_t previous_prime = get_previous_prime(&iter, stop + 1);
  int64_t xp = (int64_t) (x / previous_prime);

  vector<int64_t> next = generate_next_multiples(low, size, primes);
  BitSieve sieve(segment_size);

  // segmented sieve of Eratosthenes
  for (; low < limit; low += segment_size)
  {
    // current segment = interval [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t sqrt = isqrt(high - 1);
    int64_t j = 0;

    sieve.fill(low, high);

    // cross-off multiples
    for (int64_t i = 2; i < size && primes[i] <= sqrt; i++)
    {
      int64_t k;
      int64_t p2 = primes[i] * 2;
      for (k = next[i]; k < high; k += p2)
        sieve.unset(k - low);
      next[i] = k;
    }

    while (previous_prime >= start && xp < high)
    {
      pix += sieve.count(j, xp - low);
      j = xp - low + 1;
      pix_count++;
      P2_thread += pix;
      previous_prime = get_previous_prime(&iter, previous_prime);
      xp = (int64_t) (x / previous_prime);
    }

    pix += sieve.count(j, (high - 1) - low);
  }

  return P2_thread;
}

void balanceLoad(int64_t* segments_per_thread, double seconds1, double time1)
{
  double time2 = get_wtime();
  double seconds = time2 - seconds1;
  double time = time2 - time1;
  double increase_threshold = in_between(0.5, time / 10, 20);

  if (seconds < increase_threshold)
    *segments_per_thread += *segments_per_thread * 3;
  else if (*segments_per_thread >= 4)
    *segments_per_thread -= *segments_per_thread / 4;
}

/// P2(x, y) counts the numbers <= x that have exactly 2 prime
/// factors each exceeding the a-th prime, a = pi(y).
/// Space complexity: O((x / y)^(1/2)).
///
template <typename T>
T P2(T x, int64_t y, int threads)
{
  T a = pi_legendre(y, 1);
  T b = pi_legendre((int64_t) isqrt(x), 1);

  if (x < 4 || a >= b)
    return 0;

  if (print_status())
  {
    cout << endl;
    cout << "=== P2(x, y) ===" << endl;
    cout << "Computation of the 2nd partial sieve function" << endl;
  }

  double time = get_wtime();
  int64_t low = 2;
  int64_t limit = (int64_t)(x / max<int64_t>(1, y));
  int64_t segment_size = max<int64_t>(1 << 12, isqrt(limit));
  int64_t segments_per_thread = 1;
  threads = validate_threads(threads, limit);

  vector<int32_t> primes = generate_primes(isqrt(limit));
  aligned_vector<int64_t> pix(threads);
  aligned_vector<int64_t> pix_counts(threads);

  // \sum_{i=a+1}^{b} pi(x / primes[i]) - (i - 1)
  // initialize with \sum_{i=a+1}^{b} -i + 1
  T sum = (a - 2) * (a + 1) / 2 - (b - 2) * (b + 1) / 2;
  T pix_total = 0;

  while (low < limit)
  {
    int64_t segments = ceil_div(limit - low, segment_size);
    threads = in_between(1, threads, segments);
    segments_per_thread = in_between(1, segments_per_thread, ceil_div(segments, threads));
    double seconds = get_wtime();

    #pragma omp parallel for \
        num_threads(threads) reduction(+: sum)
    for (int i = 0; i < threads; i++)
      sum += P2_thread(x, y, segment_size, segments_per_thread, i,
         low, limit, pix[i], pix_counts[i], primes);

    low += segments_per_thread * threads * segment_size;
    balanceLoad(&segments_per_thread, seconds, time);

    // Add missing sum contributions in order
    for (int i = 0; i < threads; i++)
    {
      sum += pix_total * pix_counts[i];
      pix_total += pix[i];
    }

    if (print_status())
      cout << "\rStatus: " << get_percent(low, limit) << '%' << flush;
  }

  if (print_status())
    print_result("P2", sum, time);

  return sum;
}

} // namespace P2
} // namespace

namespace primecount {

int64_t P2(int64_t x, int64_t y, int threads)
{
  return P2::P2(x, y, threads);
}

#ifdef HAVE_INT128_T

int128_t P2(int128_t x, int64_t y, int threads)
{
  return P2::P2(x, y, threads);
}

#endif

/// P2_lehmer(x, a) counts the numbers <= x that have exactly 2 prime
/// factors each exceeding the a-th prime. This implementation is
/// optimized for small values of a < pi(x^(1/3)) which requires
/// sieving up to a large limit (x / primes[a]). Sieving is done in
/// parallel using primesieve (segmented sieve of Eratosthenes).
/// Space complexity: O(pi(sqrt(x))).
///
int64_t P2_lehmer(int64_t x, int64_t a, int threads)
{
  if (print_status())
  {
    cout << endl;
    cout << "=== P2_lehmer(x, a) ===" << endl;
    cout << "Computation of the 2nd partial sieve function" << endl;
  }

  double time = get_wtime();
  vector<int32_t> primes = generate_primes(isqrt(x));
  vector<int64_t> counts(primes.size());

  int64_t b = pi_bsearch(primes, isqrt(x));
  int64_t sum = 0;
  int64_t pix = 0;

  #pragma omp parallel for schedule(dynamic) \
      num_threads(validate_threads(threads, b, 1000))
  for (int64_t i = b; i > a; i--)
  {
    int64_t prev = (i == b) ? 0 : x / primes[i + 1] + 1;
    int64_t xi = x / primes[i];
    counts[i] = primesieve::count_primes(prev, xi);
  }

  for (int64_t i = b; i > a; i--)
  {
    pix += counts[i];
    sum += pix - (i - 1);
  }

  if (print_status())
    print_result("P2", sum, time);

  return sum;
}

} // namespace primecount
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include <iostream>
#include <string>
#include <type_traits>

#include <tao/pegtl.hpp>
#include <tao/pegtl/contrib/parse_tree.hpp>

using namespace TAO_PEGTL_NAMESPACE;  // NOLINT

namespace example
{
   // the grammar

   // clang-format off
   struct integer : plus< digit > {};
   struct variable : identifier {};

   struct plus : pad< one< '+' >, space > {};
   struct minus : pad< one< '-' >, space > {};
   struct multiply : pad< one< '*' >, space > {};
   struct divide : pad< one< '/' >, space > {};

   struct open_bracket : seq< one< '(' >, star< space > > {};
   struct close_bracket : seq< star< space >, one< ')' > > {};

   struct expression;
   struct bracketed : if_must< open_bracket, expression, close_bracket > {};
   struct value : sor< integer, variable, bracketed >{};
   struct product : list_must< value, sor< multiply, divide > > {};
   struct expression : list_must< product, sor< plus, minus > > {};

   struct grammar : seq< expression, eof > {};

   // after a node is stored successfully, you can add an optional transformer like this:
   struct rearrange : std::true_type
   {
      // recursively rearrange nodes. the basic principle is:
      //
      // from:          PROD/EXPR
      //                /   |   \          (LHS... may be one or more children, followed by OP,)
      //             LHS... OP   RHS       (which is one operator, and RHS, which is a single child)
      //
      // to:               OP
      //                  /  \             (OP now has two children, the original PROD/EXPR and RHS)
      //         PROD/EXPR    RHS          (Note that PROD/EXPR has two fewer children now)
      //             |
      //            LHS...
      //
      // if only one child is left for LHS..., replace the PROD/EXPR with the child directly.
      // otherwise, perform the above transformation, then apply it recursively until LHS...
      // becomes a single child, which then replaces the parent node and the recursion ends.
      template< typename... States >
      static void transform( std::unique_ptr< parse_tree::node >& n, States&&... st )
      {
         if( n->children.size() == 1 ) {
            n = std::move( n->children.back() );
         }
         else {
            n->remove_content();
            auto& c = n->children;
            auto r = std::move( c.back() );
            c.pop_back();
            auto o = std::move( c.back() );
            c.pop_back();
            o->children.emplace_back( std::move( n ) );
            o->children.emplace_back( std::move( r ) );
            n = std::move( o );
            transform( n->children.front(), st... );
         }
      }
   };

   // select which rules in the grammar will produce parse tree nodes:

   template< typename Rule >
   using selector = parse_tree::selector<
      Rule,
      parse_tree::apply_store_content::to<
         integer,
         variable >,
      parse_tree::apply_remove_content::to<
         plus,
         minus,
         multiply,
         divide >,
      parse_tree::apply< rearrange >::to<
         product,
         expression > >;

   // debugging/show result:

   void print_node( const parse_tree::node& n, const std::string& s = "" )
   {
      // detect the root node:
      if( n.is_root() ) {
         std::cout << "ROOT" << std::endl;
      }
      else {
         if( n.has_content() ) {
            std::cout << s << n.name() << " \"" << n.string_view() << "\" at " << n.begin() << " to " << n.end() << std::endl;
         }
         else {
            std::cout << s << n.name() << " at " << n.begin() << std::endl;
         }
      }
      // print all child nodes
      if( !n.children.empty() ) {
         const auto s2 = s + "  ";
         for( auto& up : n.children ) {
            print_node( *up, s2 );
         }
      }
   }

}  // namespace example

int main( int argc, char** argv )
{
   for( int i = 1; i < argc; ++i ) {
      try {
         argv_input in( argv, i );
         if( const auto root = parse_tree::parse< example::grammar, example::selector >( in ) ) {
            example::print_node( *root );
         }
         else {
            std::cout << "PARSE FAILED" << std::endl;
         }
      }
      catch( const std::exception& e ) {
         std::cout << "PARSE FAILED WITH EXCEPTION: " << e.what() << std::endl;
      }
   }
   return 0;
}
<commit_msg>Add missing 'clang-format on'<commit_after>// Copyright (c) 2017-2019 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#include <iostream>
#include <string>
#include <type_traits>

#include <tao/pegtl.hpp>
#include <tao/pegtl/contrib/parse_tree.hpp>

using namespace TAO_PEGTL_NAMESPACE;  // NOLINT

namespace example
{
   // the grammar

   // clang-format off
   struct integer : plus< digit > {};
   struct variable : identifier {};

   struct plus : pad< one< '+' >, space > {};
   struct minus : pad< one< '-' >, space > {};
   struct multiply : pad< one< '*' >, space > {};
   struct divide : pad< one< '/' >, space > {};

   struct open_bracket : seq< one< '(' >, star< space > > {};
   struct close_bracket : seq< star< space >, one< ')' > > {};

   struct expression;
   struct bracketed : if_must< open_bracket, expression, close_bracket > {};
   struct value : sor< integer, variable, bracketed >{};
   struct product : list_must< value, sor< multiply, divide > > {};
   struct expression : list_must< product, sor< plus, minus > > {};

   struct grammar : seq< expression, eof > {};
   // clang-format on

   // after a node is stored successfully, you can add an optional transformer like this:
   struct rearrange : std::true_type
   {
      // recursively rearrange nodes. the basic principle is:
      //
      // from:          PROD/EXPR
      //                /   |   \          (LHS... may be one or more children, followed by OP,)
      //             LHS... OP   RHS       (which is one operator, and RHS, which is a single child)
      //
      // to:               OP
      //                  /  \             (OP now has two children, the original PROD/EXPR and RHS)
      //         PROD/EXPR    RHS          (Note that PROD/EXPR has two fewer children now)
      //             |
      //            LHS...
      //
      // if only one child is left for LHS..., replace the PROD/EXPR with the child directly.
      // otherwise, perform the above transformation, then apply it recursively until LHS...
      // becomes a single child, which then replaces the parent node and the recursion ends.
      template< typename... States >
      static void transform( std::unique_ptr< parse_tree::node >& n, States&&... st )
      {
         if( n->children.size() == 1 ) {
            n = std::move( n->children.back() );
         }
         else {
            n->remove_content();
            auto& c = n->children;
            auto r = std::move( c.back() );
            c.pop_back();
            auto o = std::move( c.back() );
            c.pop_back();
            o->children.emplace_back( std::move( n ) );
            o->children.emplace_back( std::move( r ) );
            n = std::move( o );
            transform( n->children.front(), st... );
         }
      }
   };

   // select which rules in the grammar will produce parse tree nodes:

   template< typename Rule >
   using selector = parse_tree::selector<
      Rule,
      parse_tree::apply_store_content::to<
         integer,
         variable >,
      parse_tree::apply_remove_content::to<
         plus,
         minus,
         multiply,
         divide >,
      parse_tree::apply< rearrange >::to<
         product,
         expression > >;

   // debugging/show result:

   void print_node( const parse_tree::node& n, const std::string& s = "" )
   {
      // detect the root node:
      if( n.is_root() ) {
         std::cout << "ROOT" << std::endl;
      }
      else {
         if( n.has_content() ) {
            std::cout << s << n.name() << " \"" << n.string_view() << "\" at " << n.begin() << " to " << n.end() << std::endl;
         }
         else {
            std::cout << s << n.name() << " at " << n.begin() << std::endl;
         }
      }
      // print all child nodes
      if( !n.children.empty() ) {
         const auto s2 = s + "  ";
         for( auto& up : n.children ) {
            print_node( *up, s2 );
         }
      }
   }

}  // namespace example

int main( int argc, char** argv )
{
   for( int i = 1; i < argc; ++i ) {
      try {
         argv_input in( argv, i );
         if( const auto root = parse_tree::parse< example::grammar, example::selector >( in ) ) {
            example::print_node( *root );
         }
         else {
            std::cout << "PARSE FAILED" << std::endl;
         }
      }
      catch( const std::exception& e ) {
         std::cout << "PARSE FAILED WITH EXCEPTION: " << e.what() << std::endl;
      }
   }
   return 0;
}
<|endoftext|>