<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/TextureVk.h"

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

namespace backend { namespace vulkan {

    namespace {
        // Converts an NXT texture dimension to a Vulkan image type.
        // Note that in Vulkan dimensionality is only 1D, 2D, 3D. Arrays and cube maps are expressed
        // via the array size and a "cubemap compatible" flag.
        VkImageType VulkanImageType(nxt::TextureDimension dimension) {
            switch (dimension) {
                case nxt::TextureDimension::e2D:
                    return VK_IMAGE_TYPE_2D;
                default:
                    UNREACHABLE();
            }
        }

        // Converts an NXT texture dimension to a Vulkan image view type.
        // Contrary to image types, image view types include arrayness and cubemapness
        VkImageViewType VulkanImageViewType(nxt::TextureDimension dimension) {
            switch (dimension) {
                case nxt::TextureDimension::e2D:
                    return VK_IMAGE_VIEW_TYPE_2D;
                default:
                    UNREACHABLE();
            }
        }

        // Converts the NXT usage flags to Vulkan usage flags. Also needs the format to choose
        // between color and depth attachment usages.
        VkImageUsageFlags VulkanImageUsage(nxt::TextureUsageBit usage, nxt::TextureFormat format) {
            VkImageUsageFlags flags = 0;

            if (usage & nxt::TextureUsageBit::TransferSrc) {
                flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
            }
            if (usage & nxt::TextureUsageBit::TransferDst) {
                flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
            }
            if (usage & nxt::TextureUsageBit::Sampled) {
                flags |= VK_IMAGE_USAGE_SAMPLED_BIT;
            }
            if (usage & nxt::TextureUsageBit::Storage) {
                flags |= VK_IMAGE_USAGE_STORAGE_BIT;
            }
            if (usage & nxt::TextureUsageBit::OutputAttachment) {
                if (TextureFormatHasDepthOrStencil(format)) {
                    flags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
                } else {
                    flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
                }
            }

            return flags;
        }

        // Computes which vulkan access type could be required for the given NXT usage.
        VkAccessFlags VulkanAccessFlags(nxt::TextureUsageBit usage, nxt::TextureFormat format) {
            VkAccessFlags flags = 0;

            if (usage & nxt::TextureUsageBit::TransferSrc) {
                flags |= VK_ACCESS_TRANSFER_READ_BIT;
            }
            if (usage & nxt::TextureUsageBit::TransferDst) {
                flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
            }
            if (usage & nxt::TextureUsageBit::Sampled) {
                flags |= VK_ACCESS_SHADER_READ_BIT;
            }
            if (usage & nxt::TextureUsageBit::Storage) {
                flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
            }
            if (usage & nxt::TextureUsageBit::OutputAttachment) {
                if (TextureFormatHasDepthOrStencil(format)) {
                    flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
                             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
                } else {
                    flags |=
                        VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
                }
            }

            // TODO(cwallez@chromium.org): What about present? Does it require VK_MEMORY_READ_BIT?

            return flags;
        }

        // Chooses which Vulkan image layout should be used for the given NXT usage
        VkImageLayout VulkanImageLayout(nxt::TextureUsageBit usage, nxt::TextureFormat format) {
            if (usage == nxt::TextureUsageBit::None) {
                return VK_IMAGE_LAYOUT_UNDEFINED;
            }

            if (!nxt::HasZeroOrOneBits(usage)) {
                return VK_IMAGE_LAYOUT_GENERAL;
            }

            // Usage has a single bit so we can switch on its value directly.
            switch (usage) {
                case nxt::TextureUsageBit::TransferDst:
                    return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
                case nxt::TextureUsageBit::Sampled:
                    return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
                // Vulkan texture copy functions require the image to be in _one_  known layout.
                // Depending on whether parts of the texture have been transitioned to only
                // TransferSrc or a combination with something else, the texture could be in a
                // combination of GENERAL and TRANSFER_SRC_OPTIMAL. This would be a problem, so we
                // make TransferSrc use GENERAL.
                case nxt::TextureUsageBit::TransferSrc:
                // Writable storage textures must use general. If we could know the texture is read
                // only we could use SHADER_READ_ONLY_OPTIMAL
                case nxt::TextureUsageBit::Storage:
                case nxt::TextureUsageBit::Present:
                    return VK_IMAGE_LAYOUT_GENERAL;
                case nxt::TextureUsageBit::OutputAttachment:
                    if (TextureFormatHasDepthOrStencil(format)) {
                        return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
                    } else {
                        return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
                    }
                default:
                    UNREACHABLE();
            }
        }

        // Computes which Vulkan pipeline stage can access a texture in the given NXT usage
        VkPipelineStageFlags VulkanPipelineStage(nxt::TextureUsageBit usage,
                                                 nxt::TextureFormat format) {
            VkPipelineStageFlags flags = 0;

            if (usage == nxt::TextureUsageBit::None) {
                // This only happens when a texture is initially created (and for srcAccessMask) in
                // which case there is no need to wait on anything to stop accessing this texture.
                return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
            }
            if (usage & (nxt::TextureUsageBit::TransferSrc | nxt::TextureUsageBit::TransferDst)) {
                flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
            }
            if (usage & (nxt::TextureUsageBit::Sampled | nxt::TextureUsageBit::Storage)) {
                flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
                         VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
            }
            if (usage & nxt::TextureUsageBit::OutputAttachment) {
                if (TextureFormatHasDepthOrStencil(format)) {
                    flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
                             VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
                    // TODO(cwallez@chromium.org): This is missing the stage where the depth and
                    // stencil values are written, but it isn't clear which one it is.
                } else {
                    flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
                }
            }

            // TODO(cwallez@chromium.org) What about present?

            return flags;
        }

        // Computes which Vulkan texture aspects are relevant for the given NXT format
        VkImageAspectFlags VulkanAspectMask(nxt::TextureFormat format) {
            bool isDepth = TextureFormatHasDepth(format);
            bool isStencil = TextureFormatHasStencil(format);

            VkImageAspectFlags flags = 0;
            if (isDepth) {
                flags |= VK_IMAGE_ASPECT_DEPTH_BIT;
            }
            if (isStencil) {
                flags |= VK_IMAGE_ASPECT_STENCIL_BIT;
            }

            if (flags != 0) {
                return flags;
            }
            return VK_IMAGE_ASPECT_COLOR_BIT;
        }

    }  // namespace

    // Converts NXT texture format to Vulkan formats.
    VkFormat VulkanImageFormat(nxt::TextureFormat format) {
        switch (format) {
            case nxt::TextureFormat::R8G8B8A8Unorm:
                return VK_FORMAT_R8G8B8A8_UNORM;
            case nxt::TextureFormat::R8G8B8A8Uint:
                return VK_FORMAT_R8G8B8A8_UINT;
            case nxt::TextureFormat::B8G8R8A8Unorm:
                return VK_FORMAT_B8G8R8A8_UNORM;
            case nxt::TextureFormat::D32FloatS8Uint:
                return VK_FORMAT_D32_SFLOAT_S8_UINT;
            default:
                UNREACHABLE();
        }
    }

    Texture::Texture(TextureBuilder* builder) : TextureBase(builder) {
        Device* device = ToBackend(GetDevice());

        // Create the Vulkan image "container". We don't need to check that the format supports the
        // combination of sample, usage etc. because validation should have been done in the NXT
        // frontend already based on the minimum supported formats in the Vulkan spec
        VkImageCreateInfo createInfo;
        createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
        createInfo.pNext = nullptr;
        createInfo.flags = 0;
        createInfo.imageType = VulkanImageType(GetDimension());
        createInfo.format = VulkanImageFormat(GetFormat());
        createInfo.extent = VkExtent3D{GetWidth(), GetHeight(), GetDepth()};
        createInfo.mipLevels = GetNumMipLevels();
        createInfo.arrayLayers = 1;
        createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
        createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
        createInfo.usage = VulkanImageUsage(GetAllowedUsage(), GetFormat());
        createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
        createInfo.queueFamilyIndexCount = 0;
        createInfo.pQueueFamilyIndices = nullptr;
        createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

        if (device->fn.CreateImage(device->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
            VK_SUCCESS) {
            ASSERT(false);
        }

        // Create the image memory and associate it with the container
        VkMemoryRequirements requirements;
        device->fn.GetImageMemoryRequirements(device->GetVkDevice(), mHandle, &requirements);

        if (!device->GetMemoryAllocator()->Allocate(requirements, false, &mMemoryAllocation)) {
            ASSERT(false);
        }

        if (device->fn.BindImageMemory(device->GetVkDevice(), mHandle,
                                       mMemoryAllocation.GetMemory(),
                                       mMemoryAllocation.GetMemoryOffset()) != VK_SUCCESS) {
            ASSERT(false);
        }

        // Vulkan requires images to be transitioned to their first usage. Do the transition if the
        // texture has an initial usage.
        if (GetUsage() != nxt::TextureUsageBit::None) {
            TransitionUsageImpl(nxt::TextureUsageBit::None, GetUsage());
        }
    }

    Texture::Texture(TextureBuilder* builder, VkImage nativeImage)
        : TextureBase(builder), mHandle(nativeImage) {
    }

    Texture::~Texture() {
        Device* device = ToBackend(GetDevice());

        // We need to free both the memory allocation and the container. Memory should be freed
        // after the VkImage is destroyed and this is taken care of by the FencedDeleter.
        device->GetMemoryAllocator()->Free(&mMemoryAllocation);

        // If we own the resource, release it.
        if (mHandle != VK_NULL_HANDLE) {
            device->GetFencedDeleter()->DeleteWhenUnused(mHandle);
            mHandle = VK_NULL_HANDLE;
        }
    }

    VkImage Texture::GetHandle() const {
        return mHandle;
    }

    VkImageAspectFlags Texture::GetVkAspectMask() const {
        return VulkanAspectMask(GetFormat());
    }

    // Helper function to add a texture barrier to a command buffer. This is inefficient because we
    // should be coalescing barriers as much as possible.
    void Texture::RecordBarrier(VkCommandBuffer commands,
                                nxt::TextureUsageBit currentUsage,
                                nxt::TextureUsageBit targetUsage) const {
        nxt::TextureFormat format = GetFormat();
        VkPipelineStageFlags srcStages = VulkanPipelineStage(currentUsage, format);
        VkPipelineStageFlags dstStages = VulkanPipelineStage(targetUsage, format);

        VkImageMemoryBarrier barrier;
        barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
        barrier.pNext = nullptr;
        barrier.srcAccessMask = VulkanAccessFlags(currentUsage, format);
        barrier.dstAccessMask = VulkanAccessFlags(targetUsage, format);
        barrier.oldLayout = VulkanImageLayout(currentUsage, format);
        barrier.newLayout = VulkanImageLayout(targetUsage, format);
        barrier.srcQueueFamilyIndex = 0;
        barrier.dstQueueFamilyIndex = 0;
        barrier.image = mHandle;
        // This transitions the whole resource but assumes it is a 2D texture
        ASSERT(GetDimension() == nxt::TextureDimension::e2D);
        barrier.subresourceRange.aspectMask = VulkanAspectMask(format);
        barrier.subresourceRange.baseMipLevel = 0;
        barrier.subresourceRange.levelCount = GetNumMipLevels();
        barrier.subresourceRange.baseArrayLayer = 0;
        barrier.subresourceRange.layerCount = 1;

        ToBackend(GetDevice())
            ->fn.CmdPipelineBarrier(commands, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, 1,
                                    &barrier);
    }

    void Texture::TransitionUsageImpl(nxt::TextureUsageBit currentUsage,
                                      nxt::TextureUsageBit targetUsage) {
        VkCommandBuffer commands = ToBackend(GetDevice())->GetPendingCommandBuffer();
        RecordBarrier(commands, currentUsage, targetUsage);
    }

    TextureView::TextureView(TextureViewBuilder* builder) : TextureViewBase(builder) {
        Device* device = ToBackend(builder->GetDevice());

        VkImageViewCreateInfo createInfo;
        createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        createInfo.pNext = nullptr;
        createInfo.flags = 0;
        createInfo.image = ToBackend(GetTexture())->GetHandle();
        createInfo.viewType = VulkanImageViewType(GetTexture()->GetDimension());
        createInfo.format = VulkanImageFormat(GetTexture()->GetFormat());
        createInfo.components = VkComponentMapping{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
                                                   VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
        createInfo.subresourceRange.aspectMask = VulkanAspectMask(GetTexture()->GetFormat());
        createInfo.subresourceRange.baseMipLevel = 0;
        createInfo.subresourceRange.levelCount = GetTexture()->GetNumMipLevels();
        createInfo.subresourceRange.baseArrayLayer = 0;
        createInfo.subresourceRange.layerCount = 1;

        if (device->fn.CreateImageView(device->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
            VK_SUCCESS) {
            ASSERT(false);
        }
    }

    TextureView::~TextureView() {
        Device* device = ToBackend(GetTexture()->GetDevice());

        if (mHandle != VK_NULL_HANDLE) {
            device->GetFencedDeleter()->DeleteWhenUnused(mHandle);
            mHandle = VK_NULL_HANDLE;
        }
    }

    VkImageView TextureView::GetHandle() const {
        return mHandle;
    }

}}  // namespace backend::vulkan
<commit_msg>Vulkan: Fix texture synchronization for present<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/TextureVk.h"

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

namespace backend { namespace vulkan {

    namespace {
        // Converts an NXT texture dimension to a Vulkan image type.
        // Note that in Vulkan dimensionality is only 1D, 2D, 3D. Arrays and cube maps are expressed
        // via the array size and a "cubemap compatible" flag.
        VkImageType VulkanImageType(nxt::TextureDimension dimension) {
            switch (dimension) {
                case nxt::TextureDimension::e2D:
                    return VK_IMAGE_TYPE_2D;
                default:
                    UNREACHABLE();
            }
        }

        // Converts an NXT texture dimension to a Vulkan image view type.
        // Contrary to image types, image view types include arrayness and cubemapness
        VkImageViewType VulkanImageViewType(nxt::TextureDimension dimension) {
            switch (dimension) {
                case nxt::TextureDimension::e2D:
                    return VK_IMAGE_VIEW_TYPE_2D;
                default:
                    UNREACHABLE();
            }
        }

        // Converts the NXT usage flags to Vulkan usage flags. Also needs the format to choose
        // between color and depth attachment usages.
        VkImageUsageFlags VulkanImageUsage(nxt::TextureUsageBit usage, nxt::TextureFormat format) {
            VkImageUsageFlags flags = 0;

            if (usage & nxt::TextureUsageBit::TransferSrc) {
                flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
            }
            if (usage & nxt::TextureUsageBit::TransferDst) {
                flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
            }
            if (usage & nxt::TextureUsageBit::Sampled) {
                flags |= VK_IMAGE_USAGE_SAMPLED_BIT;
            }
            if (usage & nxt::TextureUsageBit::Storage) {
                flags |= VK_IMAGE_USAGE_STORAGE_BIT;
            }
            if (usage & nxt::TextureUsageBit::OutputAttachment) {
                if (TextureFormatHasDepthOrStencil(format)) {
                    flags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
                } else {
                    flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
                }
            }

            return flags;
        }

        // Computes which vulkan access type could be required for the given NXT usage.
        VkAccessFlags VulkanAccessFlags(nxt::TextureUsageBit usage, nxt::TextureFormat format) {
            VkAccessFlags flags = 0;

            if (usage & nxt::TextureUsageBit::TransferSrc) {
                flags |= VK_ACCESS_TRANSFER_READ_BIT;
            }
            if (usage & nxt::TextureUsageBit::TransferDst) {
                flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
            }
            if (usage & nxt::TextureUsageBit::Sampled) {
                flags |= VK_ACCESS_SHADER_READ_BIT;
            }
            if (usage & nxt::TextureUsageBit::Storage) {
                flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
            }
            if (usage & nxt::TextureUsageBit::OutputAttachment) {
                if (TextureFormatHasDepthOrStencil(format)) {
                    flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
                             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
                } else {
                    flags |=
                        VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
                }
            }
            if (usage & nxt::TextureUsageBit::Present) {
                // There is no access flag for present because the VK_KHR_SWAPCHAIN extension says
                // that vkQueuePresentKHR makes the memory of the image visible to the presentation
                // engine. There's also a note explicitly saying dstAccessMask should be 0. On the
                // other side srcAccessMask can also be 0 because synchronization is required to
                // happen with a semaphore instead.
                flags |= 0;
            }

            return flags;
        }

        // Chooses which Vulkan image layout should be used for the given NXT usage
        VkImageLayout VulkanImageLayout(nxt::TextureUsageBit usage, nxt::TextureFormat format) {
            if (usage == nxt::TextureUsageBit::None) {
                return VK_IMAGE_LAYOUT_UNDEFINED;
            }

            if (!nxt::HasZeroOrOneBits(usage)) {
                return VK_IMAGE_LAYOUT_GENERAL;
            }

            // Usage has a single bit so we can switch on its value directly.
            switch (usage) {
                case nxt::TextureUsageBit::TransferDst:
                    return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
                case nxt::TextureUsageBit::Sampled:
                    return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
                // Vulkan texture copy functions require the image to be in _one_  known layout.
                // Depending on whether parts of the texture have been transitioned to only
                // TransferSrc or a combination with something else, the texture could be in a
                // combination of GENERAL and TRANSFER_SRC_OPTIMAL. This would be a problem, so we
                // make TransferSrc use GENERAL.
                case nxt::TextureUsageBit::TransferSrc:
                // Writable storage textures must use general. If we could know the texture is read
                // only we could use SHADER_READ_ONLY_OPTIMAL
                case nxt::TextureUsageBit::Storage:
                    return VK_IMAGE_LAYOUT_GENERAL;
                case nxt::TextureUsageBit::OutputAttachment:
                    if (TextureFormatHasDepthOrStencil(format)) {
                        return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
                    } else {
                        return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
                    }
                case nxt::TextureUsageBit::Present:
                    return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
                default:
                    UNREACHABLE();
            }
        }

        // Computes which Vulkan pipeline stage can access a texture in the given NXT usage
        VkPipelineStageFlags VulkanPipelineStage(nxt::TextureUsageBit usage,
                                                 nxt::TextureFormat format) {
            VkPipelineStageFlags flags = 0;

            if (usage == nxt::TextureUsageBit::None) {
                // This only happens when a texture is initially created (and for srcAccessMask) in
                // which case there is no need to wait on anything to stop accessing this texture.
                return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
            }
            if (usage & (nxt::TextureUsageBit::TransferSrc | nxt::TextureUsageBit::TransferDst)) {
                flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
            }
            if (usage & (nxt::TextureUsageBit::Sampled | nxt::TextureUsageBit::Storage)) {
                flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
                         VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
            }
            if (usage & nxt::TextureUsageBit::OutputAttachment) {
                if (TextureFormatHasDepthOrStencil(format)) {
                    flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
                             VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
                    // TODO(cwallez@chromium.org): This is missing the stage where the depth and
                    // stencil values are written, but it isn't clear which one it is.
                } else {
                    flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
                }
            }
            if (usage & nxt::TextureUsageBit::Present) {
                // There is no pipeline stage for present but a pipeline stage is required so we use
                // "bottom of pipe" to block as little as possible and vkQueuePresentKHR will make
                // the memory visible to the presentation engine. The spec explicitly mentions that
                // "bottom of pipe" is ok. On the other direction, synchronization happens with a
                // semaphore so bottom of pipe is ok too (but maybe it could be "top of pipe" to
                // block less?)
                flags |= VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
            }

            // A zero value isn't a valid pipeline stage mask
            ASSERT(flags != 0);
            return flags;
        }

        // Computes which Vulkan texture aspects are relevant for the given NXT format
        VkImageAspectFlags VulkanAspectMask(nxt::TextureFormat format) {
            bool isDepth = TextureFormatHasDepth(format);
            bool isStencil = TextureFormatHasStencil(format);

            VkImageAspectFlags flags = 0;
            if (isDepth) {
                flags |= VK_IMAGE_ASPECT_DEPTH_BIT;
            }
            if (isStencil) {
                flags |= VK_IMAGE_ASPECT_STENCIL_BIT;
            }

            if (flags != 0) {
                return flags;
            }
            return VK_IMAGE_ASPECT_COLOR_BIT;
        }

    }  // namespace

    // Converts NXT texture format to Vulkan formats.
    VkFormat VulkanImageFormat(nxt::TextureFormat format) {
        switch (format) {
            case nxt::TextureFormat::R8G8B8A8Unorm:
                return VK_FORMAT_R8G8B8A8_UNORM;
            case nxt::TextureFormat::R8G8B8A8Uint:
                return VK_FORMAT_R8G8B8A8_UINT;
            case nxt::TextureFormat::B8G8R8A8Unorm:
                return VK_FORMAT_B8G8R8A8_UNORM;
            case nxt::TextureFormat::D32FloatS8Uint:
                return VK_FORMAT_D32_SFLOAT_S8_UINT;
            default:
                UNREACHABLE();
        }
    }

    Texture::Texture(TextureBuilder* builder) : TextureBase(builder) {
        Device* device = ToBackend(GetDevice());

        // Create the Vulkan image "container". We don't need to check that the format supports the
        // combination of sample, usage etc. because validation should have been done in the NXT
        // frontend already based on the minimum supported formats in the Vulkan spec
        VkImageCreateInfo createInfo;
        createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
        createInfo.pNext = nullptr;
        createInfo.flags = 0;
        createInfo.imageType = VulkanImageType(GetDimension());
        createInfo.format = VulkanImageFormat(GetFormat());
        createInfo.extent = VkExtent3D{GetWidth(), GetHeight(), GetDepth()};
        createInfo.mipLevels = GetNumMipLevels();
        createInfo.arrayLayers = 1;
        createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
        createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
        createInfo.usage = VulkanImageUsage(GetAllowedUsage(), GetFormat());
        createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
        createInfo.queueFamilyIndexCount = 0;
        createInfo.pQueueFamilyIndices = nullptr;
        createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

        if (device->fn.CreateImage(device->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
            VK_SUCCESS) {
            ASSERT(false);
        }

        // Create the image memory and associate it with the container
        VkMemoryRequirements requirements;
        device->fn.GetImageMemoryRequirements(device->GetVkDevice(), mHandle, &requirements);

        if (!device->GetMemoryAllocator()->Allocate(requirements, false, &mMemoryAllocation)) {
            ASSERT(false);
        }

        if (device->fn.BindImageMemory(device->GetVkDevice(), mHandle,
                                       mMemoryAllocation.GetMemory(),
                                       mMemoryAllocation.GetMemoryOffset()) != VK_SUCCESS) {
            ASSERT(false);
        }

        // Vulkan requires images to be transitioned to their first usage. Do the transition if the
        // texture has an initial usage.
        if (GetUsage() != nxt::TextureUsageBit::None) {
            TransitionUsageImpl(nxt::TextureUsageBit::None, GetUsage());
        }
    }

    Texture::Texture(TextureBuilder* builder, VkImage nativeImage)
        : TextureBase(builder), mHandle(nativeImage) {
    }

    Texture::~Texture() {
        Device* device = ToBackend(GetDevice());

        // We need to free both the memory allocation and the container. Memory should be freed
        // after the VkImage is destroyed and this is taken care of by the FencedDeleter.
        device->GetMemoryAllocator()->Free(&mMemoryAllocation);

        // If we own the resource, release it.
        if (mHandle != VK_NULL_HANDLE) {
            device->GetFencedDeleter()->DeleteWhenUnused(mHandle);
            mHandle = VK_NULL_HANDLE;
        }
    }

    VkImage Texture::GetHandle() const {
        return mHandle;
    }

    VkImageAspectFlags Texture::GetVkAspectMask() const {
        return VulkanAspectMask(GetFormat());
    }

    // Helper function to add a texture barrier to a command buffer. This is inefficient because we
    // should be coalescing barriers as much as possible.
    void Texture::RecordBarrier(VkCommandBuffer commands,
                                nxt::TextureUsageBit currentUsage,
                                nxt::TextureUsageBit targetUsage) const {
        nxt::TextureFormat format = GetFormat();
        VkPipelineStageFlags srcStages = VulkanPipelineStage(currentUsage, format);
        VkPipelineStageFlags dstStages = VulkanPipelineStage(targetUsage, format);

        VkImageMemoryBarrier barrier;
        barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
        barrier.pNext = nullptr;
        barrier.srcAccessMask = VulkanAccessFlags(currentUsage, format);
        barrier.dstAccessMask = VulkanAccessFlags(targetUsage, format);
        barrier.oldLayout = VulkanImageLayout(currentUsage, format);
        barrier.newLayout = VulkanImageLayout(targetUsage, format);
        barrier.srcQueueFamilyIndex = 0;
        barrier.dstQueueFamilyIndex = 0;
        barrier.image = mHandle;
        // This transitions the whole resource but assumes it is a 2D texture
        ASSERT(GetDimension() == nxt::TextureDimension::e2D);
        barrier.subresourceRange.aspectMask = VulkanAspectMask(format);
        barrier.subresourceRange.baseMipLevel = 0;
        barrier.subresourceRange.levelCount = GetNumMipLevels();
        barrier.subresourceRange.baseArrayLayer = 0;
        barrier.subresourceRange.layerCount = 1;

        ToBackend(GetDevice())
            ->fn.CmdPipelineBarrier(commands, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, 1,
                                    &barrier);
    }

    void Texture::TransitionUsageImpl(nxt::TextureUsageBit currentUsage,
                                      nxt::TextureUsageBit targetUsage) {
        VkCommandBuffer commands = ToBackend(GetDevice())->GetPendingCommandBuffer();
        RecordBarrier(commands, currentUsage, targetUsage);
    }

    TextureView::TextureView(TextureViewBuilder* builder) : TextureViewBase(builder) {
        Device* device = ToBackend(builder->GetDevice());

        VkImageViewCreateInfo createInfo;
        createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        createInfo.pNext = nullptr;
        createInfo.flags = 0;
        createInfo.image = ToBackend(GetTexture())->GetHandle();
        createInfo.viewType = VulkanImageViewType(GetTexture()->GetDimension());
        createInfo.format = VulkanImageFormat(GetTexture()->GetFormat());
        createInfo.components = VkComponentMapping{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
                                                   VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
        createInfo.subresourceRange.aspectMask = VulkanAspectMask(GetTexture()->GetFormat());
        createInfo.subresourceRange.baseMipLevel = 0;
        createInfo.subresourceRange.levelCount = GetTexture()->GetNumMipLevels();
        createInfo.subresourceRange.baseArrayLayer = 0;
        createInfo.subresourceRange.layerCount = 1;

        if (device->fn.CreateImageView(device->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
            VK_SUCCESS) {
            ASSERT(false);
        }
    }

    TextureView::~TextureView() {
        Device* device = ToBackend(GetTexture()->GetDevice());

        if (mHandle != VK_NULL_HANDLE) {
            device->GetFencedDeleter()->DeleteWhenUnused(mHandle);
            mHandle = VK_NULL_HANDLE;
        }
    }

    VkImageView TextureView::GetHandle() const {
        return mHandle;
    }

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


<commit_before>// mixing different itertools, there is nothing called iter::mixed()

#include "itertools.hpp"

#include "catch.hpp"

#include <iostream>
#include <vector>

class MyUnMovable {
    int val;
public:
    constexpr MyUnMovable(int val)
        : val{val}
    { }

    MyUnMovable(const MyUnMovable&) = delete;
    MyUnMovable& operator=(const MyUnMovable&) = delete;

    MyUnMovable(MyUnMovable&& other)
        : val{other.val}
    { }

    constexpr int get_val() const {
        return val;
    }
    void set_val(int val) {
        this->val = val;
    }

    bool operator==(const MyUnMovable& other) const {
        return this->val == other.val;
    }

    bool operator!=(const MyUnMovable& other) const {
        return !(*this == other);
    }
};

namespace {
    auto inc_ten = [](MyUnMovable& el) -> MyUnMovable& {
        int va = el.get_val();
        el.set_val(va + 10);
        return el;
    };
    auto dec_ten = [](MyUnMovable& el) -> MyUnMovable& {
        int va = el.get_val();
        el.set_val(va - 10);
        return el;
    };
}

TEST_CASE("filtering doesn't dereference multiple times", "[imap][filter]") {
    using iter::filter;
    using iter::imap;

    // source data
    std::array<MyUnMovable, 3> arr = {{{41}, {42}, {43}}};

    auto transformed1 = imap(inc_ten, arr);
    auto filtered = filter([](const MyUnMovable& el) {
        return 52 != el.get_val();
    }, transformed1);
    auto transformed2 = imap(dec_ten, filtered);

    std::vector<int> v;
    for (auto&& el : transformed2) {
        // I would use imap again instead of the loop if this wasn't an imap
        // test
        v.push_back(el.get_val());
    }

    std::vector<int> vc = {41, 43};

    REQUIRE( v == vc);

    constexpr std::array<MyUnMovable, 3> arrc = {{{41}, {52}, {43}}};
    REQUIRE( arr == arrc );
}

TEST_CASE("dropwhile doesn't dereference multiple times", "[imap][dropwhile]"){
    using iter::imap;
    using iter::dropwhile;
    // source data
    std::array<MyUnMovable, 3> arr = {{{41}, {42}, {43}}};

    auto transformed1 = imap(inc_ten, arr);
    auto filtered = dropwhile([](const MyUnMovable& el) {
        return 52 != el.get_val();
    }, transformed1);
    auto transformed2 = imap(dec_ten, filtered);

    std::vector<int> v;
    for (auto&& el : transformed2) {
        v.push_back(el.get_val());
    }

    std::vector<int> vc = {42, 43};

    constexpr std::array<MyUnMovable, 3> arrc = {{{51}, {42}, {43}}};
    REQUIRE( arr == arrc );
}
<commit_msg>tests dropwhile for multiple dereferencing<commit_after>// mixing different itertools, there is nothing called iter::mixed()

#include "itertools.hpp"

#include "catch.hpp"

#include <iostream>
#include <vector>

class MyUnMovable {
    int val;
public:
    constexpr MyUnMovable(int val)
        : val{val}
    { }

    MyUnMovable(const MyUnMovable&) = delete;
    MyUnMovable& operator=(const MyUnMovable&) = delete;

    MyUnMovable(MyUnMovable&& other)
        : val{other.val}
    { }

    constexpr int get_val() const {
        return val;
    }
    void set_val(int val) {
        this->val = val;
    }

    bool operator==(const MyUnMovable& other) const {
        return this->val == other.val;
    }

    bool operator!=(const MyUnMovable& other) const {
        return !(*this == other);
    }
};

namespace {
    auto inc_ten = [](MyUnMovable& el) -> MyUnMovable& {
        int va = el.get_val();
        el.set_val(va + 10);
        return el;
    };
    auto dec_ten = [](MyUnMovable& el) -> MyUnMovable& {
        int va = el.get_val();
        el.set_val(va - 10);
        return el;
    };
}

TEST_CASE("filtering doesn't dereference multiple times", "[imap][filter]") {
    using iter::filter;
    using iter::imap;

    // source data
    std::array<MyUnMovable, 3> arr = {{{41}, {42}, {43}}};

    auto transformed1 = imap(inc_ten, arr);
    auto filtered = filter([](const MyUnMovable& el) {
        return 52 != el.get_val();
    }, transformed1);
    auto transformed2 = imap(dec_ten, filtered);

    std::vector<int> v;
    for (auto&& el : transformed2) {
        // I would use imap again instead of the loop if this wasn't an imap
        // test
        v.push_back(el.get_val());
    }

    std::vector<int> vc = {41, 43};

    REQUIRE( v == vc);

    constexpr std::array<MyUnMovable, 3> arrc = {{{41}, {52}, {43}}};
    REQUIRE( arr == arrc );
}

TEST_CASE("dropwhile doesn't dereference multiple times", "[imap][dropwhile]"){
    using iter::imap;
    using iter::dropwhile;
    // source data
    std::array<MyUnMovable, 3> arr = {{{41}, {42}, {43}}};

    auto transformed1 = imap(inc_ten, arr);
    auto filtered = dropwhile([](const MyUnMovable& el) {
        return 52 != el.get_val();
    }, transformed1);
    auto transformed2 = imap(dec_ten, filtered);

    std::vector<int> v;
    for (auto&& el : transformed2) {
        v.push_back(el.get_val());
    }

    std::vector<int> vc = {42, 43};

    std::vector<int> vsc = {51, 42, 43};
    auto get_vals = imap([](const MyUnMovable& mv){return mv.get_val();}, arr);
    std::vector<int> vs(std::begin(get_vals), std::end(get_vals));
    REQUIRE( vs == vsc );
}
<|endoftext|>


<commit_before>#include <slice.hpp>

#include <vector>
#include <string>
#include <utility>

#include "helpers.hpp"
#include "catch.hpp"

using iter::slice;
using Vec = const std::vector<int>;

TEST_CASE("slice: take from beginning", "[slice]") {
    Vec ns = {10,11,12,13,14,15,16,17,18,19};
    auto sl = slice(ns, 5);

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {10,11,12,13,14};

    REQUIRE( v == vc );
}

TEST_CASE("slice: start and stop", "[slice]") {
    Vec ns = {10,11,12,13,14,15,16,17,18,19};
    auto sl = slice(ns, 2, 6);

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {12, 13, 14, 15};

    REQUIRE( v == vc );
}

TEST_CASE("slice: start, stop, step", "[slice]") {
    Vec ns = {10,11,12,13,14,15,16,17,18,19};
    auto sl = slice(ns, 2, 8, 2);

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {12,14,16};

    REQUIRE( v == vc );
}

TEST_CASE("slice: empty iterable", "[slice]") {
    Vec ns{};
    auto sl = slice(ns, 3);
    REQUIRE( std::begin(sl) == std::end(sl) );
}

TEST_CASE("slice: stop is beyond end of iterable", "[slice]") {
    Vec ns = {1, 2, 3};
    auto sl = slice(ns, 10);

    Vec v(std::begin(sl), std::end(sl));
    REQUIRE( v == ns );
}

TEST_CASE("slice: start is beyond end of iterable", "[slice]") {
    Vec ns = {1, 2, 3};
    auto sl = slice(ns, 5, 10);
    REQUIRE( std::begin(sl) == std::end(sl) );
}

TEST_CASE("slice: (stop - start) % step != 0", "[slice]") {
    Vec ns = {1, 2, 3, 4};
    auto sl = slice(ns, 0, 2, 3);
    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {1};

    REQUIRE( v == vc );
}

TEST_CASE("slice: invalid ranges give 0 size slices", "[slice]") {
    Vec ns = {1, 2, 3};
    SECTION("negative step") {
        auto sl = slice(ns, 1, 10, -1);
        REQUIRE( std::begin(sl) == std::end(sl) );
    }
    SECTION("stop < start") {
        auto sl = slice(ns, 2, 0, 3);
        REQUIRE( std::begin(sl) == std::end(sl) );
    }
}

TEST_CASE("slice: moves rvalues and binds to lvalues", "[slice]") {
    itertest::BasicIterable<int> bi{1, 2, 3, 4};
    slice(bi, 1, 3);
    REQUIRE_FALSE( bi.was_moved_from() );
    auto sl = slice(std::move(bi), 1, 3);
    REQUIRE( bi.was_moved_from() );

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {2, 3};

    REQUIRE( v == vc );
}

TEST_CASE("slice: with iterable doesn't move or copy elems", "[slice]") {
    constexpr std::array<itertest::SolidInt, 3> arr{{{6}, {7}, {8}}};
    for (auto&& i : slice(arr, 2)) {
        (void)i;
    }
}
<commit_msg>tests slice iterator requirements<commit_after>#include <slice.hpp>

#include <vector>
#include <string>
#include <utility>

#include "helpers.hpp"
#include "catch.hpp"

using iter::slice;
using Vec = const std::vector<int>;

TEST_CASE("slice: take from beginning", "[slice]") {
    Vec ns = {10,11,12,13,14,15,16,17,18,19};
    auto sl = slice(ns, 5);

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {10,11,12,13,14};

    REQUIRE( v == vc );
}

TEST_CASE("slice: start and stop", "[slice]") {
    Vec ns = {10,11,12,13,14,15,16,17,18,19};
    auto sl = slice(ns, 2, 6);

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {12, 13, 14, 15};

    REQUIRE( v == vc );
}

TEST_CASE("slice: start, stop, step", "[slice]") {
    Vec ns = {10,11,12,13,14,15,16,17,18,19};
    auto sl = slice(ns, 2, 8, 2);

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {12,14,16};

    REQUIRE( v == vc );
}

TEST_CASE("slice: empty iterable", "[slice]") {
    Vec ns{};
    auto sl = slice(ns, 3);
    REQUIRE( std::begin(sl) == std::end(sl) );
}

TEST_CASE("slice: stop is beyond end of iterable", "[slice]") {
    Vec ns = {1, 2, 3};
    auto sl = slice(ns, 10);

    Vec v(std::begin(sl), std::end(sl));
    REQUIRE( v == ns );
}

TEST_CASE("slice: start is beyond end of iterable", "[slice]") {
    Vec ns = {1, 2, 3};
    auto sl = slice(ns, 5, 10);
    REQUIRE( std::begin(sl) == std::end(sl) );
}

TEST_CASE("slice: (stop - start) % step != 0", "[slice]") {
    Vec ns = {1, 2, 3, 4};
    auto sl = slice(ns, 0, 2, 3);
    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {1};

    REQUIRE( v == vc );
}

TEST_CASE("slice: invalid ranges give 0 size slices", "[slice]") {
    Vec ns = {1, 2, 3};
    SECTION("negative step") {
        auto sl = slice(ns, 1, 10, -1);
        REQUIRE( std::begin(sl) == std::end(sl) );
    }
    SECTION("stop < start") {
        auto sl = slice(ns, 2, 0, 3);
        REQUIRE( std::begin(sl) == std::end(sl) );
    }
}

TEST_CASE("slice: moves rvalues and binds to lvalues", "[slice]") {
    itertest::BasicIterable<int> bi{1, 2, 3, 4};
    slice(bi, 1, 3);
    REQUIRE_FALSE( bi.was_moved_from() );
    auto sl = slice(std::move(bi), 1, 3);
    REQUIRE( bi.was_moved_from() );

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {2, 3};

    REQUIRE( v == vc );
}

TEST_CASE("slice: with iterable doesn't move or copy elems", "[slice]") {
    constexpr std::array<itertest::SolidInt, 3> arr{{{6}, {7}, {8}}};
    for (auto&& i : slice(arr, 2)) {
        (void)i;
    }
}

TEST_CASE("slice: iterator meets requirements", "[slice]") {
    std::string s{"abcdef"};
    auto c = slice(s, 1, 3);
    REQUIRE( itertest::IsIterator<decltype(std::begin(c))>::value );
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "OpenwireTempDestinationTest.h"

#include <decaf/lang/Thread.h>
#include <decaf/util/concurrent/Mutex.h>
#include <decaf/util/concurrent/CountDownLatch.h>
#include <decaf/util/UUID.h>
#include <decaf/util/ArrayList.h>
#include <activemq/exceptions/ActiveMQException.h>
#include <activemq/core/ActiveMQConnectionFactory.h>

using namespace std;
using namespace cms;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::test;
using namespace activemq::test::openwire;
using namespace activemq::util;
using namespace activemq::exceptions;
using namespace decaf;
using namespace decaf::util;
using namespace decaf::util::concurrent;
using namespace decaf::lang;

namespace activemq{
namespace test{
namespace openwire{

    class Requester : public cms::MessageListener,
                      public decaf::lang::Runnable {
    private:

        auto_ptr<CMSProvider> cmsProvider;
        auto_ptr<cms::MessageConsumer> tempTopicConsumer;

        unsigned int numReceived;
        unsigned int messageCount;

        decaf::util::concurrent::CountDownLatch ready;
        decaf::util::concurrent::CountDownLatch responses;

    public:

        Requester( const std::string& url,
                   const std::string& destination,
                   unsigned int messageCount )
        : messageCount( messageCount ), ready( 1 ), responses( messageCount ) {

            this->cmsProvider.reset( new CMSProvider( url ) );
            this->cmsProvider->setDestinationName( destination );

            this->cmsProvider->getProducer()->setDeliveryMode( DeliveryMode::NON_PERSISTENT );

            this->tempTopicConsumer.reset(
                cmsProvider->getSession()->createConsumer(
                    cmsProvider->getTempDestination() ) );
            this->tempTopicConsumer->setMessageListener( this );

            this->numReceived = 0;
        }

        virtual ~Requester() {}

        virtual unsigned int getNumReceived() const {
            return this->numReceived;
        }

        virtual void waitUnitReady() {
            this->ready.await();
        }

        virtual void awaitAllResponses() {
            this->responses.await( 2000 * this->messageCount );
        }

        virtual void run() {

            try {

                auto_ptr<cms::TextMessage> message(
                    this->cmsProvider->getSession()->createTextMessage() );
                message->setCMSReplyTo( this->cmsProvider->getTempDestination() );

                this->ready.countDown();

                for( unsigned int i = 0; i < messageCount; ++i ) {
                    this->cmsProvider->getProducer()->send( message.get() );
                }

            } catch( CMSException& e ) {
                e.printStackTrace();
            }
        }

        virtual void onMessage( const cms::Message* message ) {

            try {

                this->numReceived++;
                this->responses.countDown();

            } catch( CMSException& e ) {
                e.printStackTrace();
            }
        }
    };

    class Responder : public cms::MessageListener {
    private:

        auto_ptr<CMSProvider> cmsProvider;

        unsigned int numReceived;
        unsigned int messageCount;

        decaf::util::concurrent::CountDownLatch requests;

    public:

        Responder( const std::string& url,
                   const std::string& destination,
                   unsigned int messageCount )
        : messageCount( messageCount ), requests( messageCount ) {

            this->cmsProvider.reset( new CMSProvider( url ) );

            this->cmsProvider->setDestinationName( destination );
            this->cmsProvider->getNoDestProducer()->setDeliveryMode(
                DeliveryMode::NON_PERSISTENT );
            this->cmsProvider->getConsumer()->setMessageListener( this );

            this->numReceived = 0;
        }

        virtual ~Responder() {}

        virtual unsigned int getNumReceived() const {
            return this->numReceived;
        }

        virtual void awaitAllRequests() {
            this->requests.await( 2000 * this->messageCount );
        }

        virtual void onMessage( const cms::Message* message ) {

            try {

                if( message->getCMSReplyTo() != NULL ) {

                    auto_ptr<cms::Message> response(
                        cmsProvider->getSession()->createMessage() );

                    // Send it back to the replyTo Destination
                    this->cmsProvider->getNoDestProducer()->send(
                        message->getCMSReplyTo(), response.get() );

                    this->requests.countDown();
                }

                this->numReceived++;

            } catch( CMSException& e ) {
                e.printStackTrace();
            }
        }
    };

}}}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testBasics() {

    try{

        auto_ptr<cms::MessageConsumer> tempConsumer(
            cmsProvider->getSession()->createConsumer(
                cmsProvider->getTempDestination() ) );

        auto_ptr<TextMessage> message(
            cmsProvider->getSession()->createTextMessage() );

        // Fire a message to the temporary topic
        cmsProvider->getNoDestProducer()->send(
            cmsProvider->getTempDestination(), message.get() );

        auto_ptr<cms::Message> received( tempConsumer->receive( 3000 ) );

        CPPUNIT_ASSERT( received.get() != NULL );
    }
    AMQ_CATCH_RETHROW( ActiveMQException )
    AMQ_CATCHALL_THROW( ActiveMQException )
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTwoConnections() {

    std::string destination = "REQUEST-TOPIC";

    auto_ptr<Requester> requester(
        new Requester( cmsProvider->getBrokerURL(), destination, 10 ) );
    auto_ptr<Responder> responder(
        new Responder( cmsProvider->getBrokerURL(), destination, 10 ) );

    // Launch the Consumers in new Threads.
    Thread requestorThread( requester.get() );
    requestorThread.start();

    // Responder should get all its requests first
    responder->awaitAllRequests();

    // Now the Requester should get all its responses.
    requester->awaitAllResponses();

    // Check that the responder received all the required requests
    CPPUNIT_ASSERT( responder->getNumReceived() == 10 );

    // Check that the requester received all the required responses
    CPPUNIT_ASSERT( requester->getNumReceived() == 10 );

    // Shutdown the Requester.
    requestorThread.join();
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTempDestOnlyConsumedByLocalConn() {

    std::auto_ptr<ActiveMQConnectionFactory> factory(
        new ActiveMQConnectionFactory(cmsProvider->getBrokerURL()));
    factory->setAlwaysSyncSend(true);

    std::auto_ptr<Connection> tempConnection(factory->createConnection());
    tempConnection->start();
    std::auto_ptr<Session> tempSession(tempConnection->createSession());
    std::auto_ptr<TemporaryQueue> queue(tempSession->createTemporaryQueue());
    std::auto_ptr<MessageProducer> producer(tempSession->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(tempSession->createTextMessage("First"));
    producer->send(message.get());

    // temp destination should not be consume when using another connection
    std::auto_ptr<Connection> otherConnection(factory->createConnection());
    std::auto_ptr<Session> otherSession(otherConnection->createSession());
    std::auto_ptr<TemporaryQueue> otherQueue(otherSession->createTemporaryQueue());
    std::auto_ptr<MessageConsumer> consumer(otherSession->createConsumer(otherQueue.get()));
    std::auto_ptr<Message> msg(consumer->receive(3000));
    CPPUNIT_ASSERT(msg.get() == NULL);

    // should throw InvalidDestinationException when consuming a temp
    // destination from another connection
    CPPUNIT_ASSERT_THROW_MESSAGE(
        "Should throw a CMS InvalidDestinationException",
        otherSession->createConsumer(queue.get()),
        InvalidDestinationException);

    // should be able to consume temp destination from the same connection
    consumer.reset(tempSession->createConsumer(queue.get()));
    msg.reset(consumer->receive(3000));
    CPPUNIT_ASSERT(msg.get() != NULL);
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTempQueueHoldsMessagesWithConsumers() {

    std::auto_ptr<TemporaryQueue> queue(cmsProvider->getSession()->createTemporaryQueue());
    std::auto_ptr<MessageConsumer> consumer(cmsProvider->getSession()->createConsumer(queue.get()));
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(cmsProvider->getSession()->createTextMessage("Hello"));
    producer->send(message.get());

    std::auto_ptr<Message> message2(consumer->receive(3000));
    CPPUNIT_ASSERT(message2.get() != NULL);
    CPPUNIT_ASSERT_MESSAGE("Expected message to be a TextMessage", dynamic_cast<TextMessage*>(message2.get()) != NULL);
    CPPUNIT_ASSERT_MESSAGE(std::string("Expected message to be a '") + message->getText() + "'",
        dynamic_cast<TextMessage*>(message2.get())->getText() == message->getText());
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTempQueueHoldsMessagesWithoutConsumers() {

    std::auto_ptr<TemporaryQueue> queue(cmsProvider->getSession()->createTemporaryQueue());
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(cmsProvider->getSession()->createTextMessage("Hello"));
    producer->send(message.get());

    std::auto_ptr<MessageConsumer> consumer(cmsProvider->getSession()->createConsumer(queue.get()));
    std::auto_ptr<Message> message2(consumer->receive(3000));
    CPPUNIT_ASSERT(message2.get() != NULL);
    CPPUNIT_ASSERT_MESSAGE("Expected message to be a TextMessage", dynamic_cast<TextMessage*>(message2.get()) != NULL);
    CPPUNIT_ASSERT_MESSAGE(std::string("Expected message to be a '") + message->getText() + "'",
        dynamic_cast<TextMessage*>(message2.get())->getText() == message->getText());
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTmpQueueWorksUnderLoad() {

    int count = 500;
    int dataSize = 1024;

    ArrayList<Pointer<BytesMessage> > list(count);
    std::auto_ptr<TemporaryQueue> queue(cmsProvider->getSession()->createTemporaryQueue());
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);

    unsigned char data[1024];
    for (int i = 0; i < dataSize; ++i) {
        data[i] = 255;
    }

    for (int i = 0; i < count; i++) {
        Pointer<BytesMessage> message(cmsProvider->getSession()->createBytesMessage());
        message->writeBytes(data, 0, dataSize);
        message->setIntProperty("c", i);
        producer->send(message.get());
        list.add(message);
    }

    std::auto_ptr<MessageConsumer> consumer(cmsProvider->getSession()->createConsumer(queue.get()));
    for (int i = 0; i < count; i++) {
        Pointer<Message> message2(consumer->receive(2000));
        CPPUNIT_ASSERT(message2 != NULL);
        CPPUNIT_ASSERT_EQUAL(i, message2->getIntProperty("c"));
        CPPUNIT_ASSERT_MESSAGE("Expected message to be a BytesMessage", dynamic_cast<BytesMessage*>(message2.get()) != NULL);
    }

    list.clear();
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testPublishFailsForClosedConnection() {

    Pointer<ActiveMQConnectionFactory> factory(
        new ActiveMQConnectionFactory(cmsProvider->getBrokerURL()));
    factory->setAlwaysSyncSend(true);

    std::auto_ptr<Connection> tempConnection(factory->createConnection());
    tempConnection->start();

    std::auto_ptr<Session> tempSession(tempConnection->createSession());
    std::auto_ptr<TemporaryQueue> queue(tempSession->createTemporaryQueue());

    // This message delivery should work since the temp connection is still open.
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(cmsProvider->getSession()->createTextMessage("First"));
    producer->send(message.get());
    Thread::sleep(2000);

    // Closing the connection should destroy the temp queue that was created.
    tempConnection->close();
    Thread::sleep(5000);

    message.reset(cmsProvider->getSession()->createTextMessage("Hello"));

    CPPUNIT_ASSERT_THROW_MESSAGE(
        "Should throw a CMSException since temp destination should not exist anymore.",
        producer->send(message.get()),
        CMSException);
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testPublishFailsForDestoryedTempDestination() {

    Pointer<ActiveMQConnectionFactory> factory(
        new ActiveMQConnectionFactory(cmsProvider->getBrokerURL()));
    factory->setAlwaysSyncSend(true);

    std::auto_ptr<Connection> tempConnection(factory->createConnection());
    tempConnection->start();

    std::auto_ptr<Session> tempSession(tempConnection->createSession());
    std::auto_ptr<TemporaryQueue> queue(tempSession->createTemporaryQueue());

    // This message delivery should work since the temp connection is still open.
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(cmsProvider->getSession()->createTextMessage("First"));
    producer->send(message.get());
    Thread::sleep(2000);

    // deleting the Queue will cause sends to fail
    queue->destroy();
    Thread::sleep(5000); // Wait a little bit to let the delete take effect.

    message.reset(cmsProvider->getSession()->createTextMessage("Hello"));

    CPPUNIT_ASSERT_THROW_MESSAGE(
        "Should throw a CMSException since temp destination should not exist anymore.",
        producer->send(message.get()),
        CMSException);
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testDeleteDestinationWithSubscribersFails() {

    std::auto_ptr<TemporaryQueue> queue(cmsProvider->getSession()->createTemporaryQueue());
    std::auto_ptr<MessageConsumer> consumer(cmsProvider->getSession()->createConsumer(queue.get()));

    // This message delivery should NOT work since the temp connection is now closed.
    CPPUNIT_ASSERT_THROW_MESSAGE(
        "Should fail with CMSException as Subscribers are active",
        queue->destroy(),
        CMSException);
}
<commit_msg>Update the test now that we throw the correct CMS Exceptions<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "OpenwireTempDestinationTest.h"

#include <decaf/lang/Thread.h>
#include <decaf/util/concurrent/Mutex.h>
#include <decaf/util/concurrent/CountDownLatch.h>
#include <decaf/util/UUID.h>
#include <decaf/util/ArrayList.h>
#include <activemq/exceptions/ActiveMQException.h>
#include <activemq/core/ActiveMQConnectionFactory.h>

using namespace std;
using namespace cms;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::test;
using namespace activemq::test::openwire;
using namespace activemq::util;
using namespace activemq::exceptions;
using namespace decaf;
using namespace decaf::util;
using namespace decaf::util::concurrent;
using namespace decaf::lang;

namespace activemq{
namespace test{
namespace openwire{

    class Requester : public cms::MessageListener,
                      public decaf::lang::Runnable {
    private:

        auto_ptr<CMSProvider> cmsProvider;
        auto_ptr<cms::MessageConsumer> tempTopicConsumer;

        unsigned int numReceived;
        unsigned int messageCount;

        decaf::util::concurrent::CountDownLatch ready;
        decaf::util::concurrent::CountDownLatch responses;

    public:

        Requester( const std::string& url,
                   const std::string& destination,
                   unsigned int messageCount )
        : messageCount( messageCount ), ready( 1 ), responses( messageCount ) {

            this->cmsProvider.reset( new CMSProvider( url ) );
            this->cmsProvider->setDestinationName( destination );

            this->cmsProvider->getProducer()->setDeliveryMode( DeliveryMode::NON_PERSISTENT );

            this->tempTopicConsumer.reset(
                cmsProvider->getSession()->createConsumer(
                    cmsProvider->getTempDestination() ) );
            this->tempTopicConsumer->setMessageListener( this );

            this->numReceived = 0;
        }

        virtual ~Requester() {}

        virtual unsigned int getNumReceived() const {
            return this->numReceived;
        }

        virtual void waitUnitReady() {
            this->ready.await();
        }

        virtual void awaitAllResponses() {
            this->responses.await( 2000 * this->messageCount );
        }

        virtual void run() {

            try {

                auto_ptr<cms::TextMessage> message(
                    this->cmsProvider->getSession()->createTextMessage() );
                message->setCMSReplyTo( this->cmsProvider->getTempDestination() );

                this->ready.countDown();

                for( unsigned int i = 0; i < messageCount; ++i ) {
                    this->cmsProvider->getProducer()->send( message.get() );
                }

            } catch( CMSException& e ) {
                e.printStackTrace();
            }
        }

        virtual void onMessage( const cms::Message* message ) {

            try {

                this->numReceived++;
                this->responses.countDown();

            } catch( CMSException& e ) {
                e.printStackTrace();
            }
        }
    };

    class Responder : public cms::MessageListener {
    private:

        auto_ptr<CMSProvider> cmsProvider;

        unsigned int numReceived;
        unsigned int messageCount;

        decaf::util::concurrent::CountDownLatch requests;

    public:

        Responder( const std::string& url,
                   const std::string& destination,
                   unsigned int messageCount )
        : messageCount( messageCount ), requests( messageCount ) {

            this->cmsProvider.reset( new CMSProvider( url ) );

            this->cmsProvider->setDestinationName( destination );
            this->cmsProvider->getNoDestProducer()->setDeliveryMode(
                DeliveryMode::NON_PERSISTENT );
            this->cmsProvider->getConsumer()->setMessageListener( this );

            this->numReceived = 0;
        }

        virtual ~Responder() {}

        virtual unsigned int getNumReceived() const {
            return this->numReceived;
        }

        virtual void awaitAllRequests() {
            this->requests.await( 2000 * this->messageCount );
        }

        virtual void onMessage( const cms::Message* message ) {

            try {

                if( message->getCMSReplyTo() != NULL ) {

                    auto_ptr<cms::Message> response(
                        cmsProvider->getSession()->createMessage() );

                    // Send it back to the replyTo Destination
                    this->cmsProvider->getNoDestProducer()->send(
                        message->getCMSReplyTo(), response.get() );

                    this->requests.countDown();
                }

                this->numReceived++;

            } catch( CMSException& e ) {
                e.printStackTrace();
            }
        }
    };

}}}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testBasics() {

    try{

        auto_ptr<cms::MessageConsumer> tempConsumer(
            cmsProvider->getSession()->createConsumer(
                cmsProvider->getTempDestination() ) );

        auto_ptr<TextMessage> message(
            cmsProvider->getSession()->createTextMessage() );

        // Fire a message to the temporary topic
        cmsProvider->getNoDestProducer()->send(
            cmsProvider->getTempDestination(), message.get() );

        auto_ptr<cms::Message> received( tempConsumer->receive( 3000 ) );

        CPPUNIT_ASSERT( received.get() != NULL );
    }
    AMQ_CATCH_RETHROW( ActiveMQException )
    AMQ_CATCHALL_THROW( ActiveMQException )
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTwoConnections() {

    std::string destination = "REQUEST-TOPIC";

    auto_ptr<Requester> requester(
        new Requester( cmsProvider->getBrokerURL(), destination, 10 ) );
    auto_ptr<Responder> responder(
        new Responder( cmsProvider->getBrokerURL(), destination, 10 ) );

    // Launch the Consumers in new Threads.
    Thread requestorThread( requester.get() );
    requestorThread.start();

    // Responder should get all its requests first
    responder->awaitAllRequests();

    // Now the Requester should get all its responses.
    requester->awaitAllResponses();

    // Check that the responder received all the required requests
    CPPUNIT_ASSERT( responder->getNumReceived() == 10 );

    // Check that the requester received all the required responses
    CPPUNIT_ASSERT( requester->getNumReceived() == 10 );

    // Shutdown the Requester.
    requestorThread.join();
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTempDestOnlyConsumedByLocalConn() {

    std::auto_ptr<ActiveMQConnectionFactory> factory(
        new ActiveMQConnectionFactory(cmsProvider->getBrokerURL()));
    factory->setAlwaysSyncSend(true);

    std::auto_ptr<Connection> tempConnection(factory->createConnection());
    tempConnection->start();
    std::auto_ptr<Session> tempSession(tempConnection->createSession());
    std::auto_ptr<TemporaryQueue> queue(tempSession->createTemporaryQueue());
    std::auto_ptr<MessageProducer> producer(tempSession->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(tempSession->createTextMessage("First"));
    producer->send(message.get());

    // temp destination should not be consume when using another connection
    std::auto_ptr<Connection> otherConnection(factory->createConnection());
    std::auto_ptr<Session> otherSession(otherConnection->createSession());
    std::auto_ptr<TemporaryQueue> otherQueue(otherSession->createTemporaryQueue());
    std::auto_ptr<MessageConsumer> consumer(otherSession->createConsumer(otherQueue.get()));
    std::auto_ptr<Message> msg(consumer->receive(3000));
    CPPUNIT_ASSERT(msg.get() == NULL);

    // should throw InvalidDestinationException when consuming a temp
    // destination from another connection
    CPPUNIT_ASSERT_THROW_MESSAGE(
        "Should throw a CMS InvalidDestinationException",
        otherSession->createConsumer(queue.get()),
        InvalidDestinationException);

    // should be able to consume temp destination from the same connection
    consumer.reset(tempSession->createConsumer(queue.get()));
    msg.reset(consumer->receive(3000));
    CPPUNIT_ASSERT(msg.get() != NULL);
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTempQueueHoldsMessagesWithConsumers() {

    std::auto_ptr<TemporaryQueue> queue(cmsProvider->getSession()->createTemporaryQueue());
    std::auto_ptr<MessageConsumer> consumer(cmsProvider->getSession()->createConsumer(queue.get()));
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(cmsProvider->getSession()->createTextMessage("Hello"));
    producer->send(message.get());

    std::auto_ptr<Message> message2(consumer->receive(3000));
    CPPUNIT_ASSERT(message2.get() != NULL);
    CPPUNIT_ASSERT_MESSAGE("Expected message to be a TextMessage", dynamic_cast<TextMessage*>(message2.get()) != NULL);
    CPPUNIT_ASSERT_MESSAGE(std::string("Expected message to be a '") + message->getText() + "'",
        dynamic_cast<TextMessage*>(message2.get())->getText() == message->getText());
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTempQueueHoldsMessagesWithoutConsumers() {

    std::auto_ptr<TemporaryQueue> queue(cmsProvider->getSession()->createTemporaryQueue());
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(cmsProvider->getSession()->createTextMessage("Hello"));
    producer->send(message.get());

    std::auto_ptr<MessageConsumer> consumer(cmsProvider->getSession()->createConsumer(queue.get()));
    std::auto_ptr<Message> message2(consumer->receive(3000));
    CPPUNIT_ASSERT(message2.get() != NULL);
    CPPUNIT_ASSERT_MESSAGE("Expected message to be a TextMessage", dynamic_cast<TextMessage*>(message2.get()) != NULL);
    CPPUNIT_ASSERT_MESSAGE(std::string("Expected message to be a '") + message->getText() + "'",
        dynamic_cast<TextMessage*>(message2.get())->getText() == message->getText());
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testTmpQueueWorksUnderLoad() {

    int count = 500;
    int dataSize = 1024;

    ArrayList<Pointer<BytesMessage> > list(count);
    std::auto_ptr<TemporaryQueue> queue(cmsProvider->getSession()->createTemporaryQueue());
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);

    unsigned char data[1024];
    for (int i = 0; i < dataSize; ++i) {
        data[i] = 255;
    }

    for (int i = 0; i < count; i++) {
        Pointer<BytesMessage> message(cmsProvider->getSession()->createBytesMessage());
        message->writeBytes(data, 0, dataSize);
        message->setIntProperty("c", i);
        producer->send(message.get());
        list.add(message);
    }

    std::auto_ptr<MessageConsumer> consumer(cmsProvider->getSession()->createConsumer(queue.get()));
    for (int i = 0; i < count; i++) {
        Pointer<Message> message2(consumer->receive(2000));
        CPPUNIT_ASSERT(message2 != NULL);
        CPPUNIT_ASSERT_EQUAL(i, message2->getIntProperty("c"));
        CPPUNIT_ASSERT_MESSAGE("Expected message to be a BytesMessage", dynamic_cast<BytesMessage*>(message2.get()) != NULL);
    }

    list.clear();
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testPublishFailsForClosedConnection() {

    Pointer<ActiveMQConnectionFactory> factory(
        new ActiveMQConnectionFactory(cmsProvider->getBrokerURL()));
    factory->setAlwaysSyncSend(true);

    std::auto_ptr<Connection> tempConnection(factory->createConnection());
    tempConnection->start();

    std::auto_ptr<Session> tempSession(tempConnection->createSession());
    std::auto_ptr<TemporaryQueue> queue(tempSession->createTemporaryQueue());

    Thread::sleep(2000);

    // This message delivery should work since the temp connection is still open.
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(cmsProvider->getSession()->createTextMessage("First"));
    producer->send(message.get());
    Thread::sleep(2000);

    // Closing the connection should destroy the temp queue that was created.
    tempConnection->close();
    Thread::sleep(5000);

    message.reset(cmsProvider->getSession()->createTextMessage("Hello"));

    CPPUNIT_ASSERT_THROW_MESSAGE(
        "Should throw a InvalidDestinationException since temp destination should not exist anymore.",
        producer->send(message.get()),
        cms::InvalidDestinationException);
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testPublishFailsForDestoryedTempDestination() {

    Pointer<ActiveMQConnectionFactory> factory(
        new ActiveMQConnectionFactory(cmsProvider->getBrokerURL()));
    factory->setAlwaysSyncSend(true);

    std::auto_ptr<Connection> tempConnection(factory->createConnection());
    tempConnection->start();

    std::auto_ptr<Session> tempSession(tempConnection->createSession());
    std::auto_ptr<TemporaryQueue> queue(tempSession->createTemporaryQueue());

    Thread::sleep(2000);

    // This message delivery should work since the temp connection is still open.
    std::auto_ptr<MessageProducer> producer(cmsProvider->getSession()->createProducer(queue.get()));
    producer->setDeliveryMode(DeliveryMode::NON_PERSISTENT);
    std::auto_ptr<TextMessage> message(cmsProvider->getSession()->createTextMessage("First"));
    producer->send(message.get());
    Thread::sleep(2000);

    // deleting the Queue will cause sends to fail
    queue->destroy();
    Thread::sleep(5000); // Wait a little bit to let the delete take effect.

    message.reset(cmsProvider->getSession()->createTextMessage("Hello"));

    CPPUNIT_ASSERT_THROW_MESSAGE(
        "Should throw a InvalidDestinationException since temp destination should not exist anymore.",
        producer->send(message.get()),
        InvalidDestinationException);
}

///////////////////////////////////////////////////////////////////////////////
void OpenwireTempDestinationTest::testDeleteDestinationWithSubscribersFails() {

    std::auto_ptr<TemporaryQueue> queue(cmsProvider->getSession()->createTemporaryQueue());
    std::auto_ptr<MessageConsumer> consumer(cmsProvider->getSession()->createConsumer(queue.get()));

    // This message delivery should NOT work since the temp connection is now closed.
    CPPUNIT_ASSERT_THROW_MESSAGE(
        "Should fail with CMSException as Subscribers are active",
        queue->destroy(),
        CMSException);
}
<|endoftext|>


<commit_before>#include "main.h"

/* example constructor, sets some options */
Histogram::Histogram()
{
    // declare options, keep options as uppercase
    vector<string> temp;
    temp.push_back("INPUTFILE");
    temp.push_back("OUTPUTFILE");
	temp.push_back("BLOCKSIZE");
	temp.push_back("CHARSETSIZE");
	temp.push_back("SORTED");
	temp.push_back("SHOWFREQUENCY");
    set_opts(temp);

    // set default values, option must exist or error will printed
    set_opt_value("OUTPUTFILE", "histogram");
	set_opt_value("BLOCKSIZE", "1");
	set_opt_value("CHARSETSIZE", "256");
	set_opt_value("SORTED", "0");
	set_opt_value("SHOWFREQUENCY", "0");
}

/* helper function that doesn't really do anything */
void Histogram::test()
{
    cout << "example test" << endl;
}

/* I am overriding the default module function
 * for displaying the description text
 */
void Histogram::disp_desc()
{
	cout << "Module: attacks/histogram\n\tThis module aids in the generation of character distribution histograms.\n\tOutput is generated in a CSV format of \"VALUE,OCCURENCES;\"\n\tThe BLOCKSIZE option is used to generate a set of histograms, one for each character in a block.\n\tThe CHARSETSIZE option is used to set the maximum range of the histogram(s).\n\t" << endl;
    disp_opts();
    cout << endl;
}

int Histogram::run()
{
    // perform error checking on options first
    if (options["INPUTFILE"].empty()) {
        cout << "[-] Please specify an input file" << endl;
        return 1;
    }

    if (options["OUTPUTFILE"].empty()) {
        cout << "[-] Please specify an output file" << endl;
        return 2;
    }

	const int blockSize = stoi(options["BLOCKSIZE"]);
	const int charSetSize = stoi(options["CHARSETSIZE"]);

	if (blockSize < 1){
		cout << "[-] Block size should be greater than 0" << endl;
		return 3;
	}

	vector< vector<int> > charCounts;
	charCounts.resize(blockSize);
	for (unsigned int index = 0; index < charCounts.size(); index++){
		charCounts[index].resize(charSetSize);
	}

	ifstream in;
    ofstream out;
    string buff;

	if (process_input(&in, &charCounts, blockSize, charSetSize) != 0) {
		return 4;
	}

	vector<int> charTotal(blockSize), maxLength(blockSize), maxCount(blockSize);
	analyze_input(&charCounts, &charTotal, &maxLength, &maxCount);

	process_output(&out, &charCounts, &charTotal, &maxLength);

    cout << "[*] Closing files" << endl;
    in.close();
    out.close();

    return 0;
}

int Histogram::process_input(ifstream* in, vector< vector<int> >* charCounts, const int blockSize, const int charSetSize) {
	cout << "[*] Opening file: " << options["INPUTFILE"] << endl;
	in->open(options["INPUTFILE"]);

	cout << "[*] Processing input file..." << endl;
	char inChar;
	int blockIndex = 0, charIndex;
	while (!in->eof()) {
		in->get(inChar);
		charIndex = ((inChar < 0) ? (charSetSize + (int)inChar) : (int)inChar);
		if (inChar < 0 || inChar > charSetSize) {
			cout << "[-] Character set size option is smaller than actual size." << endl;
			return 4;
		}
		(*charCounts)[blockIndex][charIndex]++;
		blockIndex = (blockIndex + 1) % blockSize;
	}

	return 0;
}

int Histogram::analyze_input(vector< vector<int> >* charCounts, vector<int>* charTotal, vector<int>* maxLength, vector<int>* maxCount) {
	cout << "[*] Analyzing input..." << endl;

	for (unsigned int blockIndex = 0; blockIndex < charCounts->size(); blockIndex++) {
		for (unsigned int charIndex = 0; charIndex < (*charCounts)[blockIndex].size(); charIndex++) {
			int temp = (*charCounts)[blockIndex][charIndex];
			(*charTotal)[blockIndex] += temp;
			if (temp > (*maxCount)[blockIndex]) (*maxCount)[blockIndex] = temp;
		}

		int maxCtCopy = (*maxCount)[blockIndex];
		while (maxCtCopy /= 10) (*maxLength)[blockIndex]++;
	}

	return 0;
}

int Histogram::process_output(ofstream* out, vector< vector<int> >* charCounts, vector<int>* charTotal, vector<int>* maxLength) {
	vector<int> charIndexRef;
	charIndexRef.resize((*charCounts)[0].size());
	for (unsigned int charIndex = 0; charIndex < charIndexRef.size(); charIndex++) {
		charIndexRef[charIndex] = charIndex;
	}

	cout << "[*] Opening file: " << options["OUTPUTFILE"] << endl;
	out->open(options["OUTPUTFILE"]);

	cout << "[*] Writing output..." << endl;

	for (unsigned int blockIndex = 0; blockIndex < (*charCounts).size(); blockIndex++) {
		vector<int> charIndexTemp = charIndexRef;
		if (stoi(options["SORTED"]) != 0) {
			sort_arrays(&((*charCounts)[blockIndex]), &charIndexTemp);
		}

		(*out) << "Histogram for block index " << blockIndex << ": " << endl;

		for (unsigned int charIndex = 0; charIndex < (*charCounts)[blockIndex].size(); charIndex++) {
			if (stoi(options["SHOWFREQUENCY"]) == 0) {
				int numSpaces = 0, temp = (*charCounts)[blockIndex][charIndex];
				while (temp /= 10) numSpaces++;
				numSpaces = (*maxLength)[blockIndex] - numSpaces;
				(*out) << charIndexTemp[charIndex] << "," << string(numSpaces + 1, ' ') << (*charCounts)[blockIndex][charIndex] << "; \n";
			}
			else {
				float percent = ((float)(*charCounts)[blockIndex][charIndex] / (float)(*charTotal)[blockIndex]) * 100;
				(*out) << fixed << charIndexTemp[charIndex] << ", "<< percent << "; \n";
			}
		}
	}

	return 0;
}

int Histogram::sort_arrays(vector<int>* charCounts, vector<int>* charIndexArray) {
	for (unsigned int mainIndex = 0; mainIndex < (*charCounts).size(); mainIndex++) {
		int countValue = (*charCounts)[mainIndex],
			countIndex = (*charIndexArray)[mainIndex],
			swapIndex = mainIndex - 1;

		while (swapIndex >= 0 && (*charCounts)[swapIndex] < countValue) {
			(*charCounts)[swapIndex + 1] = (*charCounts)[swapIndex];
			(*charIndexArray)[swapIndex + 1] = (*charIndexArray)[swapIndex];
			swapIndex--;
		}

		(*charCounts)[swapIndex + 1] = countValue;
		(*charIndexArray)[swapIndex + 1] = countIndex;
	}

	return 0;
}
<commit_msg>Small fix with histogram generation, it used the incorrect variable during boundchecking<commit_after>#include "main.h"

/* example constructor, sets some options */
Histogram::Histogram()
{
    // declare options, keep options as uppercase
    vector<string> temp;
    temp.push_back("INPUTFILE");
    temp.push_back("OUTPUTFILE");
	temp.push_back("BLOCKSIZE");
	temp.push_back("CHARSETSIZE");
	temp.push_back("SORTED");
	temp.push_back("SHOWFREQUENCY");
    set_opts(temp);

    // set default values, option must exist or error will printed
    set_opt_value("OUTPUTFILE", "histogram");
	set_opt_value("BLOCKSIZE", "1");
	set_opt_value("CHARSETSIZE", "256");
	set_opt_value("SORTED", "0");
	set_opt_value("SHOWFREQUENCY", "0");
}

/* helper function that doesn't really do anything */
void Histogram::test()
{
    cout << "example test" << endl;
}

/* I am overriding the default module function
 * for displaying the description text
 */
void Histogram::disp_desc()
{
	cout << "Module: attacks/histogram\n\tThis module aids in the generation of character distribution histograms.\n\tOutput is generated in a CSV format of \"VALUE,OCCURENCES;\"\n\tThe BLOCKSIZE option is used to generate a set of histograms, one for each character in a block.\n\tThe CHARSETSIZE option is used to set the maximum range of the histogram(s).\n\t" << endl;
    disp_opts();
    cout << endl;
}

int Histogram::run()
{
    // perform error checking on options first
    if (options["INPUTFILE"].empty()) {
        cout << "[-] Please specify an input file" << endl;
        return 1;
    }

    if (options["OUTPUTFILE"].empty()) {
        cout << "[-] Please specify an output file" << endl;
        return 2;
    }

	const int blockSize = stoi(options["BLOCKSIZE"]);
	const int charSetSize = stoi(options["CHARSETSIZE"]);

	if (blockSize < 1){
		cout << "[-] Block size should be greater than 0" << endl;
		return 3;
	}

	vector< vector<int> > charCounts;
	charCounts.resize(blockSize);
	for (unsigned int index = 0; index < charCounts.size(); index++){
		charCounts[index].resize(charSetSize);
	}

	ifstream in;
    ofstream out;
    string buff;

	if (process_input(&in, &charCounts, blockSize, charSetSize) != 0) {
		return 4;
	}

	vector<int> charTotal(blockSize), maxLength(blockSize), maxCount(blockSize);
	analyze_input(&charCounts, &charTotal, &maxLength, &maxCount);

	process_output(&out, &charCounts, &charTotal, &maxLength);

    cout << "[*] Closing files" << endl;
    in.close();
    out.close();

    return 0;
}

int Histogram::process_input(ifstream* in, vector< vector<int> >* charCounts, const int blockSize, const int charSetSize) {
	cout << "[*] Opening file: " << options["INPUTFILE"] << endl;
	in->open(options["INPUTFILE"]);

	cout << "[*] Processing input file..." << endl;
	char inChar;
	int blockIndex = 0, charIndex;
	while (!in->eof()) {
		in->get(inChar);
		charIndex = ((inChar < 0) ? (charSetSize + (int)inChar) : (int)inChar);
		if (charIndex < 0 || charIndex > charSetSize) {
			cout << "[-] Character set size option is smaller than actual size." << endl;
			return 4;
		}
		(*charCounts)[blockIndex][charIndex]++;
		blockIndex = (blockIndex + 1) % blockSize;
	}

	return 0;
}

int Histogram::analyze_input(vector< vector<int> >* charCounts, vector<int>* charTotal, vector<int>* maxLength, vector<int>* maxCount) {
	cout << "[*] Analyzing input..." << endl;

	for (unsigned int blockIndex = 0; blockIndex < charCounts->size(); blockIndex++) {
		for (unsigned int charIndex = 0; charIndex < (*charCounts)[blockIndex].size(); charIndex++) {
			int temp = (*charCounts)[blockIndex][charIndex];
			(*charTotal)[blockIndex] += temp;
			if (temp > (*maxCount)[blockIndex]) (*maxCount)[blockIndex] = temp;
		}

		int maxCtCopy = (*maxCount)[blockIndex];
		while (maxCtCopy /= 10) (*maxLength)[blockIndex]++;
	}

	return 0;
}

int Histogram::process_output(ofstream* out, vector< vector<int> >* charCounts, vector<int>* charTotal, vector<int>* maxLength) {
	vector<int> charIndexRef;
	charIndexRef.resize((*charCounts)[0].size());
	for (unsigned int charIndex = 0; charIndex < charIndexRef.size(); charIndex++) {
		charIndexRef[charIndex] = charIndex;
	}

	cout << "[*] Opening file: " << options["OUTPUTFILE"] << endl;
	out->open(options["OUTPUTFILE"]);

	cout << "[*] Writing output..." << endl;

	for (unsigned int blockIndex = 0; blockIndex < (*charCounts).size(); blockIndex++) {
		vector<int> charIndexTemp = charIndexRef;
		if (stoi(options["SORTED"]) != 0) {
			sort_arrays(&((*charCounts)[blockIndex]), &charIndexTemp);
		}

		(*out) << "Histogram for block index " << blockIndex << ": " << endl;

		for (unsigned int charIndex = 0; charIndex < (*charCounts)[blockIndex].size(); charIndex++) {
			if (stoi(options["SHOWFREQUENCY"]) == 0) {
				int numSpaces = 0, temp = (*charCounts)[blockIndex][charIndex];
				while (temp /= 10) numSpaces++;
				numSpaces = (*maxLength)[blockIndex] - numSpaces;
				(*out) << charIndexTemp[charIndex] << "," << string(numSpaces + 1, ' ') << (*charCounts)[blockIndex][charIndex] << "; \n";
			}
			else {
				float percent = ((float)(*charCounts)[blockIndex][charIndex] / (float)(*charTotal)[blockIndex]) * 100;
				(*out) << fixed << charIndexTemp[charIndex] << ", "<< percent << "; \n";
			}
		}
	}

	return 0;
}

int Histogram::sort_arrays(vector<int>* charCounts, vector<int>* charIndexArray) {
	for (unsigned int mainIndex = 0; mainIndex < (*charCounts).size(); mainIndex++) {
		int countValue = (*charCounts)[mainIndex],
			countIndex = (*charIndexArray)[mainIndex],
			swapIndex = mainIndex - 1;

		while (swapIndex >= 0 && (*charCounts)[swapIndex] < countValue) {
			(*charCounts)[swapIndex + 1] = (*charCounts)[swapIndex];
			(*charIndexArray)[swapIndex + 1] = (*charIndexArray)[swapIndex];
			swapIndex--;
		}

		(*charCounts)[swapIndex + 1] = countValue;
		(*charIndexArray)[swapIndex + 1] = countIndex;
	}

	return 0;
}
<|endoftext|>


<commit_before>#include <slice.hpp>

#include <vector>
#include <string>
#include <utility>

#include "helpers.hpp"
#include "catch.hpp"

using iter::slice;
using Vec = const std::vector<int>;

TEST_CASE("slice: take from beginning", "[slice]") {
    Vec ns = {10,11,12,13,14,15,16,17,18,19};
    auto sl = slice(ns, 5);

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {10,11,12,13,14};

    REQUIRE( v == vc );
}
<commit_msg>tests slice with start and stop<commit_after>#include <slice.hpp>

#include <vector>
#include <string>
#include <utility>

#include "helpers.hpp"
#include "catch.hpp"

using iter::slice;
using Vec = const std::vector<int>;

TEST_CASE("slice: take from beginning", "[slice]") {
    Vec ns = {10,11,12,13,14,15,16,17,18,19};
    auto sl = slice(ns, 5);

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {10,11,12,13,14};

    REQUIRE( v == vc );
}

TEST_CASE("slice: start and stop", "[slice]") {
    Vec ns = {10,11,12,13,14,15,16,17,18,19};
    auto sl = slice(ns, 2, 6);

    Vec v(std::begin(sl), std::end(sl));
    Vec vc = {12, 13, 14, 15};

    REQUIRE( v == vc );
}
<|endoftext|>


<commit_before>#ifndef MODIFIERFILTER_HPP
#define MODIFIERFILTER_HPP

#include "FlagStatus.hpp"
#include "RemapFilterBase.hpp"

namespace org_pqrs_Karabiner {
  namespace RemapFilter {
    class ModifierFilter : public RemapFilterBase {
    public:
      ModifierFilter(unsigned int type) : RemapFilterBase(type) {}

      void initialize(const unsigned int* vec, size_t length) {
        {
          Vector_ModifierFlag v;
          targets_.push_back(v);
        }

        for (size_t i = 0; i < length - 1; i += 2) {
          AddDataType datatype(vec[i]);
          AddValue newval(vec[i + 1]);

          switch (datatype) {
            case BRIDGE_DATATYPE_MODIFIERFLAG:
              if (! targets_.empty()) {
                targets_.back().push_back(ModifierFlag(datatype, newval));
              }
              break;

            case BRIDGE_DATATYPE_MODIFIERFLAGS_END:
            {
              Vector_ModifierFlag v;
              targets_.push_back(v);
              break;
            }

            default:
              IOLOG_ERROR("ModifierFilter::add invalid datatype:%u\n", static_cast<unsigned int>(datatype));
              break;
          }
        }

        if (length % 2 > 0) {
          IOLOG_WARN("Invalid length(%d) in BRIDGE_FILTERTYPE_MODIFIER_*\n", static_cast<int>(length));
        }
      }

      bool isblocked(void) {
        if (get_type() == BRIDGE_FILTERTYPE_MODIFIER_NOT ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_ONLY ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_NOT ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_ONLY ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_NOT ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_ONLY) {

          bool isnot = (get_type() == BRIDGE_FILTERTYPE_MODIFIER_NOT ||
                        get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_NOT ||
                        get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_NOT);

          for (size_t i = 0; i < targets_.size(); ++i) {
            if (targets_[i].empty()) continue;

            if (get_type() == BRIDGE_FILTERTYPE_MODIFIER_NOT ||
                get_type() == BRIDGE_FILTERTYPE_MODIFIER_ONLY) {
              if (FlagStatus::globalFlagStatus().isOn(targets_[i])) {
                return isnot ? true : false;
              }
            }

            if (get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_NOT ||
                get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_ONLY) {
              if (FlagStatus::globalFlagStatus().isLocked(targets_[i])) {
                return isnot ? true : false;
              }
            }

            if (get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_NOT ||
                get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_ONLY) {
              if (FlagStatus::globalFlagStatus().isStuck(targets_[i])) {
                return isnot ? true : false;
              }
            }
          }

          return isnot ? false : true;
        }

        IOLOG_ERROR("ModifierFilter::isblocked unknown type_(%d)\n", get_type());
        return false;
      }

    private:
      Vector_Vector_ModifierFlag targets_;
    };
  }
}

#endif
<commit_msg>update error message<commit_after>#ifndef MODIFIERFILTER_HPP
#define MODIFIERFILTER_HPP

#include "FlagStatus.hpp"
#include "RemapFilterBase.hpp"

namespace org_pqrs_Karabiner {
  namespace RemapFilter {
    class ModifierFilter : public RemapFilterBase {
    public:
      ModifierFilter(unsigned int type) : RemapFilterBase(type) {}

      void initialize(const unsigned int* vec, size_t length) {
        {
          Vector_ModifierFlag v;
          targets_.push_back(v);
        }

        for (size_t i = 0; i < length - 1; i += 2) {
          AddDataType datatype(vec[i]);
          AddValue newval(vec[i + 1]);

          switch (datatype) {
            case BRIDGE_DATATYPE_MODIFIERFLAG:
              if (! targets_.empty()) {
                targets_.back().push_back(ModifierFlag(datatype, newval));
              }
              break;

            case BRIDGE_DATATYPE_MODIFIERFLAGS_END:
            {
              Vector_ModifierFlag v;
              targets_.push_back(v);
              break;
            }

            default:
              IOLOG_ERROR("ModifierFilter::add invalid datatype:%u\n", static_cast<unsigned int>(datatype));
              break;
          }
        }

        if (length % 2 > 0) {
          IOLOG_WARN("Invalid length(%d) in BRIDGE_FILTERTYPE_MODIFIER_*\n", static_cast<int>(length));
        }
      }

      bool isblocked(void) {
        if (get_type() == BRIDGE_FILTERTYPE_MODIFIER_NOT ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_ONLY ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_NOT ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_ONLY ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_NOT ||
            get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_ONLY) {

          bool isnot = (get_type() == BRIDGE_FILTERTYPE_MODIFIER_NOT ||
                        get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_NOT ||
                        get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_NOT);

          for (size_t i = 0; i < targets_.size(); ++i) {
            if (targets_[i].empty()) continue;

            if (get_type() == BRIDGE_FILTERTYPE_MODIFIER_NOT ||
                get_type() == BRIDGE_FILTERTYPE_MODIFIER_ONLY) {
              if (FlagStatus::globalFlagStatus().isOn(targets_[i])) {
                return isnot ? true : false;
              }
            }

            if (get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_NOT ||
                get_type() == BRIDGE_FILTERTYPE_MODIFIER_LOCKED_ONLY) {
              if (FlagStatus::globalFlagStatus().isLocked(targets_[i])) {
                return isnot ? true : false;
              }
            }

            if (get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_NOT ||
                get_type() == BRIDGE_FILTERTYPE_MODIFIER_STUCK_ONLY) {
              if (FlagStatus::globalFlagStatus().isStuck(targets_[i])) {
                return isnot ? true : false;
              }
            }
          }

          return isnot ? false : true;
        }

        IOLOG_ERROR("ModifierFilter::isblocked unknown type(%d)\n", get_type());
        return false;
      }

    private:
      Vector_Vector_ModifierFlag targets_;
    };
  }
}

#endif
<|endoftext|>