<commit_before>/*
 * GLRenderTarget.cpp
 *
 * This file is part of the "LLGL" project (Copyright (c) 2015 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "GLRenderTarget.h"
#include "../RenderState/GLStateManager.h"
#include "../Ext/GLExtensions.h"
#include "../../CheckedCast.h"
#include "../../GLCommon/GLTypes.h"
#include "../../GLCommon/GLCore.h"
#include "../../../Core/Helper.h"

namespace LLGL
{

[[noreturn]]
static void DepthAttachmentFailed()
{
    throw std::runtime_error("attachment to render target failed, because render target already has a depth- or depth-stencil buffer");
}

GLRenderTarget::GLRenderTarget(const RenderTargetDescriptor& desc) :
    multiSamples_ { static_cast<GLsizei>(desc.multiSampling.SampleCount()) }
{
    if (HasMultiSampling() && !desc.customMultiSampling)
        CreateOnceFramebufferMS();
}

void GLRenderTarget::AttachDepthBuffer(const Gs::Vector2ui& size)
{
    AttachRenderbuffer(size, GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT);
    blitMask_ |= GL_DEPTH_BUFFER_BIT;
}

void GLRenderTarget::AttachStencilBuffer(const Gs::Vector2ui& size)
{
    AttachRenderbuffer(size, GL_STENCIL_INDEX, GL_STENCIL_ATTACHMENT);
    blitMask_ |= GL_STENCIL_BUFFER_BIT;
}

void GLRenderTarget::AttachDepthStencilBuffer(const Gs::Vector2ui& size)
{
    AttachRenderbuffer(size, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL_ATTACHMENT);
    blitMask_ |= (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}

static GLenum CheckDrawFramebufferStatus()
{
    return glCheckFramebufferStatus(GL_FRAMEBUFFER);
}

// Returns the GL internal format for the specified texture object
static GLint GetTexInternalFormat(const GLTexture& textureGL)
{
    GLint internalFormat = GL_RGBA;
    {
        GLStateManager::active->BindTexture(textureGL);
        glGetTexLevelParameteriv(GLTypes::Map(textureGL.GetType()), 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
    }
    return internalFormat;
}

void GLRenderTarget::AttachTexture(Texture& texture, const RenderTargetAttachmentDescriptor& attachmentDesc)
{
    /* Get OpenGL texture object */
    auto& textureGL = LLGL_CAST(GLTexture&, texture);
    auto textureID = textureGL.GetID();

    /* Apply resolution for MIP-map level */
    auto mipLevel = attachmentDesc.mipLevel;
    ApplyMipResolution(texture, mipLevel);

    /* Make color or depth-stencil attachment */
    const auto internalFormat   = GetTexInternalFormat(textureGL);
    const auto attachment       = MakeFramebufferAttachment(internalFormat);

    /* Attach texture to framebuffer */
    GLenum status = 0;

    framebuffer_.Bind();
    {
        switch (texture.GetType())
        {
            case TextureType::Texture1D:
                GLFramebuffer::AttachTexture1D(attachment, GL_TEXTURE_1D, textureID, mipLevel);
                break;
            case TextureType::Texture2D:
                GLFramebuffer::AttachTexture2D(attachment, GL_TEXTURE_2D, textureID, mipLevel);
                break;
            case TextureType::Texture3D:
                GLFramebuffer::AttachTexture3D(attachment, GL_TEXTURE_3D, textureID, mipLevel, attachmentDesc.layer);
                break;
            case TextureType::TextureCube:
                GLFramebuffer::AttachTexture2D(attachment, GLTypes::Map(attachmentDesc.cubeFace), textureID, mipLevel);
                break;
            case TextureType::Texture1DArray:
                GLFramebuffer::AttachTextureLayer(attachment, textureID, mipLevel, attachmentDesc.layer);
                break;
            case TextureType::Texture2DArray:
                GLFramebuffer::AttachTextureLayer(attachment, textureID, mipLevel, attachmentDesc.layer);
                break;
            case TextureType::TextureCubeArray:
                GLFramebuffer::AttachTextureLayer(attachment, textureID, mipLevel, attachmentDesc.layer * 6 + static_cast<int>(attachmentDesc.cubeFace));
                break;
            case TextureType::Texture2DMS:
                GLFramebuffer::AttachTexture2D(attachment, GL_TEXTURE_2D_MULTISAMPLE, textureID, 0);
                break;
            case TextureType::Texture2DMSArray:
                GLFramebuffer::AttachTexture3D(attachment, GL_TEXTURE_2D_MULTISAMPLE_ARRAY, textureID, 0, attachmentDesc.layer);
                break;
        }

        status = CheckDrawFramebufferStatus();

        /* Set draw buffers for this framebuffer if multi-sampling is disabled */
        if (!framebufferMS_)
            SetDrawBuffers();
    }
    framebuffer_.Unbind();

    CheckFramebufferStatus(status, "color attachment to framebuffer object (FBO)");

    /* Create renderbuffer for attachment if multi-sample framebuffer is used */
    if (framebufferMS_)
    {
        auto renderbuffer = MakeUnique<GLRenderbuffer>();
        {
            /* Setup renderbuffer storage by texture's internal format */
            InitRenderbufferStorage(*renderbuffer, static_cast<GLenum>(internalFormat));

            /* Attach renderbuffer to multi-sample framebuffer */
            framebufferMS_->Bind();
            {
                GLFramebuffer::AttachRenderbuffer(attachment, renderbuffer->GetID());
                status = CheckDrawFramebufferStatus();

                /* Set draw buffers for this framebuffer is multi-sampling is enabled */
                SetDrawBuffers();
            }
            framebufferMS_->Unbind();

            CheckFramebufferStatus(status, "color attachment to multi-sample framebuffer object (FBO)");
        }
        renderbuffersMS_.emplace_back(std::move(renderbuffer));
    }
}

void GLRenderTarget::DetachAll()
{
    /* Reset framebuffer and renderbuffer objects */
    ResetResolution();

    framebuffer_.Recreate();

    renderbuffer_.reset();

    if (framebufferMS_)
        framebufferMS_->Recreate();

    colorAttachments_.clear();
    renderbuffersMS_.clear();

    blitMask_ = 0;
}

/* ----- Extended Internal Functions ----- */

/*
Blit (or rather copy) each multi-sample attachment from the
multi-sample framebuffer (read) into the main framebuffer (draw)
*/
void GLRenderTarget::BlitOntoFrameBuffer()
{
    if (framebufferMS_)
    {
        framebuffer_.Bind(GLFramebufferTarget::DRAW_FRAMEBUFFER);
        framebufferMS_->Bind(GLFramebufferTarget::READ_FRAMEBUFFER);

        for (auto attachment : colorAttachments_)
        {
            glReadBuffer(attachment);
            glDrawBuffer(attachment);

            GLFramebuffer::Blit(GetResolution().Cast<int>(), blitMask_);
        }

        framebufferMS_->Unbind(GLFramebufferTarget::READ_FRAMEBUFFER);
        framebuffer_.Unbind(GLFramebufferTarget::DRAW_FRAMEBUFFER);
    }
}

/*
Blit (or rather copy) each multi-sample attachment from the
multi-sample framebuffer (read) into the back buffer (draw)
*/
void GLRenderTarget::BlitOntoScreen(std::size_t colorAttachmentIndex)
{
    if (colorAttachmentIndex < colorAttachments_.size())
    {
        GLStateManager::active->BindFramebuffer(GLFramebufferTarget::DRAW_FRAMEBUFFER, 0);
        GLStateManager::active->BindFramebuffer(GLFramebufferTarget::READ_FRAMEBUFFER, GetFramebuffer().GetID());
        {
            glReadBuffer(colorAttachments_[colorAttachmentIndex]);
            glDrawBuffer(GL_BACK);

            GLFramebuffer::Blit(GetResolution().Cast<int>(), blitMask_);
        }
        GLStateManager::active->BindFramebuffer(GLFramebufferTarget::READ_FRAMEBUFFER, 0);
    }
}

const GLFramebuffer& GLRenderTarget::GetFramebuffer() const
{
    return (framebufferMS_ != nullptr ? *framebufferMS_ : framebuffer_);
}

/*
 * ======= Private: =======
 */

void GLRenderTarget::InitRenderbufferStorage(GLRenderbuffer& renderbuffer, GLenum internalFormat)
{
    renderbuffer.Bind();
    {
        GLRenderbuffer::Storage(internalFormat, GetResolution().Cast<int>(), multiSamples_);
    }
    renderbuffer.Unbind();
}

GLenum GLRenderTarget::AttachDefaultRenderbuffer(GLFramebuffer& framebuffer, GLenum attachment)
{
    GLenum status = 0;

    framebuffer.Bind();
    {
        GLFramebuffer::AttachRenderbuffer(attachment, renderbuffer_->GetID());
        status = CheckDrawFramebufferStatus();
    }
    framebuffer.Unbind();

    return status;
}

void GLRenderTarget::AttachRenderbuffer(const Gs::Vector2ui& size, GLenum internalFormat, GLenum attachment)
{
    if (!HasDepthAttachment())
    {
        renderbuffer_ = MakeUnique<GLRenderbuffer>();

        /* Apply size to framebuffer resolution */
        ApplyResolution(size);

        /* Setup renderbuffer storage */
        InitRenderbufferStorage(*renderbuffer_, internalFormat);

        /* Attach renderbuffer to framebuffer (or multi-sample framebuffer if multi-sampling is used) */
        GLenum status = 0;

        if (framebufferMS_)
        {
            status = AttachDefaultRenderbuffer(*framebufferMS_, attachment);
            CheckFramebufferStatus(status, "depth- or depth-stencil attachment to multi-sample framebuffer object (FBO)");
        }
        else
        {
            status = AttachDefaultRenderbuffer(framebuffer_, attachment);
            CheckFramebufferStatus(status, "depth- or depth-stencil attachment to framebuffer object (FBO)");
        }
    }
    else
        DepthAttachmentFailed();
}

GLenum GLRenderTarget::MakeFramebufferAttachment(GLint internalFormat)
{
    if (internalFormat == GL_DEPTH_COMPONENT)
    {
        if (!HasDepthAttachment())
        {
            /* Add depth attachment and depth buffer bit to blit mask */
            blitMask_ |= GL_DEPTH_BUFFER_BIT;
            return GL_DEPTH_ATTACHMENT;
        }
        else
            DepthAttachmentFailed();
    }
    else if (internalFormat == GL_DEPTH_STENCIL)
    {
        if (!HasDepthAttachment())
        {
            /* Add depth-stencil attachment and depth-stencil buffer bit to blit mask */
            blitMask_ |= (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
            return GL_DEPTH_STENCIL_ATTACHMENT;
        }
        else
            DepthAttachmentFailed();
    }
    else
    {
        /* Add color attachment and color buffer bit to blit mask */
        blitMask_ |= GL_COLOR_BUFFER_BIT;
        const GLenum attachment = (GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(colorAttachments_.size()));
        colorAttachments_.push_back(attachment);
        return attachment;
    }
}

void GLRenderTarget::SetDrawBuffers()
{
    /*
    Tell OpenGL which buffers are to be written when drawing operations are performed.
    Each color attachment has its own draw buffer.
    */
    if (colorAttachments_.empty())
        glDrawBuffer(GL_NONE);
    else if (colorAttachments_.size() == 1)
        glDrawBuffer(colorAttachments_.front());
    else
        glDrawBuffers(static_cast<GLsizei>(colorAttachments_.size()), colorAttachments_.data());
}

void GLRenderTarget::CheckFramebufferStatus(GLenum status, const std::string& info)
{
    if (status != GL_FRAMEBUFFER_COMPLETE)
        throw std::runtime_error(info + " failed (error code = " + GLErrorToStr(status) + ")");
}

void GLRenderTarget::CreateOnceFramebufferMS()
{
    if (!framebufferMS_)
        framebufferMS_ = MakeUnique<GLFramebuffer>();
}

bool GLRenderTarget::HasMultiSampling() const
{
    return (multiSamples_ > 1);
}

bool GLRenderTarget::HasCustomMultiSampling() const
{
    return (framebufferMS_ == nullptr);
}

bool GLRenderTarget::HasDepthAttachment() const
{
    static const GLbitfield mask = (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    return ((blitMask_ & mask) != 0);
}

} // /namespace LLGL

// ================================================================================
<commit_msg>Fixed framebuffer attachment of Texture2DMSArray.<commit_after>/*
 * GLRenderTarget.cpp
 *
 * This file is part of the "LLGL" project (Copyright (c) 2015 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "GLRenderTarget.h"
#include "../RenderState/GLStateManager.h"
#include "../Ext/GLExtensions.h"
#include "../../CheckedCast.h"
#include "../../GLCommon/GLTypes.h"
#include "../../GLCommon/GLCore.h"
#include "../../../Core/Helper.h"

namespace LLGL
{

[[noreturn]]
static void DepthAttachmentFailed()
{
    throw std::runtime_error("attachment to render target failed, because render target already has a depth- or depth-stencil buffer");
}

GLRenderTarget::GLRenderTarget(const RenderTargetDescriptor& desc) :
    multiSamples_ { static_cast<GLsizei>(desc.multiSampling.SampleCount()) }
{
    if (HasMultiSampling() && !desc.customMultiSampling)
        CreateOnceFramebufferMS();
}

void GLRenderTarget::AttachDepthBuffer(const Gs::Vector2ui& size)
{
    AttachRenderbuffer(size, GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT);
    blitMask_ |= GL_DEPTH_BUFFER_BIT;
}

void GLRenderTarget::AttachStencilBuffer(const Gs::Vector2ui& size)
{
    AttachRenderbuffer(size, GL_STENCIL_INDEX, GL_STENCIL_ATTACHMENT);
    blitMask_ |= GL_STENCIL_BUFFER_BIT;
}

void GLRenderTarget::AttachDepthStencilBuffer(const Gs::Vector2ui& size)
{
    AttachRenderbuffer(size, GL_DEPTH_STENCIL, GL_DEPTH_STENCIL_ATTACHMENT);
    blitMask_ |= (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}

static GLenum CheckDrawFramebufferStatus()
{
    return glCheckFramebufferStatus(GL_FRAMEBUFFER);
}

// Returns the GL internal format for the specified texture object
static GLint GetTexInternalFormat(const GLTexture& textureGL)
{
    GLint internalFormat = GL_RGBA;
    {
        GLStateManager::active->BindTexture(textureGL);
        glGetTexLevelParameteriv(GLTypes::Map(textureGL.GetType()), 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat);
    }
    return internalFormat;
}

void GLRenderTarget::AttachTexture(Texture& texture, const RenderTargetAttachmentDescriptor& attachmentDesc)
{
    /* Get OpenGL texture object */
    auto& textureGL = LLGL_CAST(GLTexture&, texture);
    auto textureID = textureGL.GetID();

    /* Apply resolution for MIP-map level */
    auto mipLevel = attachmentDesc.mipLevel;
    ApplyMipResolution(texture, mipLevel);

    /* Make color or depth-stencil attachment */
    const auto internalFormat   = GetTexInternalFormat(textureGL);
    const auto attachment       = MakeFramebufferAttachment(internalFormat);

    /* Attach texture to framebuffer */
    GLenum status = 0;

    framebuffer_.Bind();
    {
        switch (texture.GetType())
        {
            case TextureType::Texture1D:
                GLFramebuffer::AttachTexture1D(attachment, GL_TEXTURE_1D, textureID, mipLevel);
                break;
            case TextureType::Texture2D:
                GLFramebuffer::AttachTexture2D(attachment, GL_TEXTURE_2D, textureID, mipLevel);
                break;
            case TextureType::Texture3D:
                GLFramebuffer::AttachTexture3D(attachment, GL_TEXTURE_3D, textureID, mipLevel, attachmentDesc.layer);
                break;
            case TextureType::TextureCube:
                GLFramebuffer::AttachTexture2D(attachment, GLTypes::Map(attachmentDesc.cubeFace), textureID, mipLevel);
                break;
            case TextureType::Texture1DArray:
                GLFramebuffer::AttachTextureLayer(attachment, textureID, mipLevel, attachmentDesc.layer);
                break;
            case TextureType::Texture2DArray:
                GLFramebuffer::AttachTextureLayer(attachment, textureID, mipLevel, attachmentDesc.layer);
                break;
            case TextureType::TextureCubeArray:
                GLFramebuffer::AttachTextureLayer(attachment, textureID, mipLevel, attachmentDesc.layer * 6 + static_cast<int>(attachmentDesc.cubeFace));
                break;
            case TextureType::Texture2DMS:
                GLFramebuffer::AttachTexture2D(attachment, GL_TEXTURE_2D_MULTISAMPLE, textureID, 0);
                break;
            case TextureType::Texture2DMSArray:
                GLFramebuffer::AttachTextureLayer(attachment, textureID, 0, attachmentDesc.layer);
                break;
        }

        status = CheckDrawFramebufferStatus();

        /* Set draw buffers for this framebuffer if multi-sampling is disabled */
        if (!framebufferMS_)
            SetDrawBuffers();
    }
    framebuffer_.Unbind();

    CheckFramebufferStatus(status, "color attachment to framebuffer object (FBO)");

    /* Create renderbuffer for attachment if multi-sample framebuffer is used */
    if (framebufferMS_)
    {
        auto renderbuffer = MakeUnique<GLRenderbuffer>();
        {
            /* Setup renderbuffer storage by texture's internal format */
            InitRenderbufferStorage(*renderbuffer, static_cast<GLenum>(internalFormat));

            /* Attach renderbuffer to multi-sample framebuffer */
            framebufferMS_->Bind();
            {
                GLFramebuffer::AttachRenderbuffer(attachment, renderbuffer->GetID());
                status = CheckDrawFramebufferStatus();

                /* Set draw buffers for this framebuffer is multi-sampling is enabled */
                SetDrawBuffers();
            }
            framebufferMS_->Unbind();

            CheckFramebufferStatus(status, "color attachment to multi-sample framebuffer object (FBO)");
        }
        renderbuffersMS_.emplace_back(std::move(renderbuffer));
    }
}

void GLRenderTarget::DetachAll()
{
    /* Reset framebuffer and renderbuffer objects */
    ResetResolution();

    framebuffer_.Recreate();

    renderbuffer_.reset();

    if (framebufferMS_)
        framebufferMS_->Recreate();

    colorAttachments_.clear();
    renderbuffersMS_.clear();

    blitMask_ = 0;
}

/* ----- Extended Internal Functions ----- */

/*
Blit (or rather copy) each multi-sample attachment from the
multi-sample framebuffer (read) into the main framebuffer (draw)
*/
void GLRenderTarget::BlitOntoFrameBuffer()
{
    if (framebufferMS_)
    {
        framebuffer_.Bind(GLFramebufferTarget::DRAW_FRAMEBUFFER);
        framebufferMS_->Bind(GLFramebufferTarget::READ_FRAMEBUFFER);

        for (auto attachment : colorAttachments_)
        {
            glReadBuffer(attachment);
            glDrawBuffer(attachment);

            GLFramebuffer::Blit(GetResolution().Cast<int>(), blitMask_);
        }

        framebufferMS_->Unbind(GLFramebufferTarget::READ_FRAMEBUFFER);
        framebuffer_.Unbind(GLFramebufferTarget::DRAW_FRAMEBUFFER);
    }
}

/*
Blit (or rather copy) each multi-sample attachment from the
multi-sample framebuffer (read) into the back buffer (draw)
*/
void GLRenderTarget::BlitOntoScreen(std::size_t colorAttachmentIndex)
{
    if (colorAttachmentIndex < colorAttachments_.size())
    {
        GLStateManager::active->BindFramebuffer(GLFramebufferTarget::DRAW_FRAMEBUFFER, 0);
        GLStateManager::active->BindFramebuffer(GLFramebufferTarget::READ_FRAMEBUFFER, GetFramebuffer().GetID());
        {
            glReadBuffer(colorAttachments_[colorAttachmentIndex]);
            glDrawBuffer(GL_BACK);

            GLFramebuffer::Blit(GetResolution().Cast<int>(), blitMask_);
        }
        GLStateManager::active->BindFramebuffer(GLFramebufferTarget::READ_FRAMEBUFFER, 0);
    }
}

const GLFramebuffer& GLRenderTarget::GetFramebuffer() const
{
    return (framebufferMS_ != nullptr ? *framebufferMS_ : framebuffer_);
}

/*
 * ======= Private: =======
 */

void GLRenderTarget::InitRenderbufferStorage(GLRenderbuffer& renderbuffer, GLenum internalFormat)
{
    renderbuffer.Bind();
    {
        GLRenderbuffer::Storage(internalFormat, GetResolution().Cast<int>(), multiSamples_);
    }
    renderbuffer.Unbind();
}

GLenum GLRenderTarget::AttachDefaultRenderbuffer(GLFramebuffer& framebuffer, GLenum attachment)
{
    GLenum status = 0;

    framebuffer.Bind();
    {
        GLFramebuffer::AttachRenderbuffer(attachment, renderbuffer_->GetID());
        status = CheckDrawFramebufferStatus();
    }
    framebuffer.Unbind();

    return status;
}

void GLRenderTarget::AttachRenderbuffer(const Gs::Vector2ui& size, GLenum internalFormat, GLenum attachment)
{
    if (!HasDepthAttachment())
    {
        renderbuffer_ = MakeUnique<GLRenderbuffer>();

        /* Apply size to framebuffer resolution */
        ApplyResolution(size);

        /* Setup renderbuffer storage */
        InitRenderbufferStorage(*renderbuffer_, internalFormat);

        /* Attach renderbuffer to framebuffer (or multi-sample framebuffer if multi-sampling is used) */
        GLenum status = 0;

        if (framebufferMS_)
        {
            status = AttachDefaultRenderbuffer(*framebufferMS_, attachment);
            CheckFramebufferStatus(status, "depth- or depth-stencil attachment to multi-sample framebuffer object (FBO)");
        }
        else
        {
            status = AttachDefaultRenderbuffer(framebuffer_, attachment);
            CheckFramebufferStatus(status, "depth- or depth-stencil attachment to framebuffer object (FBO)");
        }
    }
    else
        DepthAttachmentFailed();
}

GLenum GLRenderTarget::MakeFramebufferAttachment(GLint internalFormat)
{
    if (internalFormat == GL_DEPTH_COMPONENT)
    {
        if (!HasDepthAttachment())
        {
            /* Add depth attachment and depth buffer bit to blit mask */
            blitMask_ |= GL_DEPTH_BUFFER_BIT;
            return GL_DEPTH_ATTACHMENT;
        }
        else
            DepthAttachmentFailed();
    }
    else if (internalFormat == GL_DEPTH_STENCIL)
    {
        if (!HasDepthAttachment())
        {
            /* Add depth-stencil attachment and depth-stencil buffer bit to blit mask */
            blitMask_ |= (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
            return GL_DEPTH_STENCIL_ATTACHMENT;
        }
        else
            DepthAttachmentFailed();
    }
    else
    {
        /* Add color attachment and color buffer bit to blit mask */
        blitMask_ |= GL_COLOR_BUFFER_BIT;
        const GLenum attachment = (GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(colorAttachments_.size()));
        colorAttachments_.push_back(attachment);
        return attachment;
    }
}

void GLRenderTarget::SetDrawBuffers()
{
    /*
    Tell OpenGL which buffers are to be written when drawing operations are performed.
    Each color attachment has its own draw buffer.
    */
    if (colorAttachments_.empty())
        glDrawBuffer(GL_NONE);
    else if (colorAttachments_.size() == 1)
        glDrawBuffer(colorAttachments_.front());
    else
        glDrawBuffers(static_cast<GLsizei>(colorAttachments_.size()), colorAttachments_.data());
}

void GLRenderTarget::CheckFramebufferStatus(GLenum status, const std::string& info)
{
    if (status != GL_FRAMEBUFFER_COMPLETE)
        throw std::runtime_error(info + " failed (error code = " + GLErrorToStr(status) + ")");
}

void GLRenderTarget::CreateOnceFramebufferMS()
{
    if (!framebufferMS_)
        framebufferMS_ = MakeUnique<GLFramebuffer>();
}

bool GLRenderTarget::HasMultiSampling() const
{
    return (multiSamples_ > 1);
}

bool GLRenderTarget::HasCustomMultiSampling() const
{
    return (framebufferMS_ == nullptr);
}

bool GLRenderTarget::HasDepthAttachment() const
{
    static const GLbitfield mask = (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    return ((blitMask_ & mask) != 0);
}

} // /namespace LLGL

// ================================================================================
<|endoftext|>


<commit_before>// Copyright 2012 Luis Pedro Coelho <luis@luispedro.org>
// License: MIT (see COPYING.MIT file)
#include "base.h"
#include "_jpeg.h"

#include <stdio.h>
extern "C" {
#include <jpeglib.h>
}

namespace {
const size_t buffer_size = 4096;

struct jpeg_source_adaptor {
    jpeg_source_mgr mgr;
    byte_source* s;
    byte* buf;

    jpeg_source_adaptor(byte_source* s);

    ~jpeg_source_adaptor() {
        delete [] buf;
    }
};

struct jpeg_dst_adaptor {
    jpeg_destination_mgr mgr;
    byte_sink* s;
    byte* buf;

    jpeg_dst_adaptor(byte_sink* s);

    ~jpeg_dst_adaptor() {
        delete [] buf;
    }
};

void nop(j_decompress_ptr cinfo) { }
void nop_dst(j_compress_ptr cinfo) { }

boolean fill_input_buffer(j_decompress_ptr cinfo) {
    jpeg_source_adaptor* adaptor = reinterpret_cast<jpeg_source_adaptor*>(cinfo->src);
    adaptor->mgr.next_input_byte = adaptor->buf;
    adaptor->mgr.bytes_in_buffer = adaptor->s->read(adaptor->buf, buffer_size);
    return true;
}

void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
    if (num_bytes <= 0) return;
    jpeg_source_adaptor* adaptor = reinterpret_cast<jpeg_source_adaptor*>(cinfo->src);
    while (num_bytes > long(adaptor->mgr.bytes_in_buffer)) {
        num_bytes -= adaptor->mgr.bytes_in_buffer;
        fill_input_buffer(cinfo);
    }
    adaptor->mgr.next_input_byte += num_bytes;
    adaptor->mgr.bytes_in_buffer -= num_bytes;
}

boolean empty_output_buffer(j_compress_ptr cinfo) {
    jpeg_dst_adaptor* adaptor = reinterpret_cast<jpeg_dst_adaptor*>(cinfo->dest);
    adaptor->s->write(adaptor->buf, buffer_size);
    adaptor->mgr.next_output_byte = adaptor->buf;
    adaptor->mgr.free_in_buffer = buffer_size;
    return TRUE;
}

void flush_output_buffer(j_compress_ptr cinfo) {
    jpeg_dst_adaptor* adaptor = reinterpret_cast<jpeg_dst_adaptor*>(cinfo->dest);
    adaptor->s->write(adaptor->buf, adaptor->mgr.next_output_byte - adaptor->buf);
}

jpeg_source_adaptor::jpeg_source_adaptor(byte_source* s)
    :s(s)
    {
        buf = new byte[buffer_size];
        mgr.next_input_byte = buf;
        mgr.bytes_in_buffer = 0;

        mgr.init_source = nop;
        mgr.fill_input_buffer = fill_input_buffer;
        mgr.skip_input_data = skip_input_data;
        mgr.resync_to_restart = jpeg_resync_to_restart;
        mgr.term_source = nop;
    }

jpeg_dst_adaptor::jpeg_dst_adaptor(byte_sink* s)
    :s(s)
    {
        buf = new byte[buffer_size];

        mgr.next_output_byte = buf;
        mgr.free_in_buffer = buffer_size;

        mgr.init_destination = nop_dst;
        mgr.empty_output_buffer = empty_output_buffer;
        mgr.term_destination = flush_output_buffer;
    }
}

void JPEGFormat::read(byte_source* src, Image* output) {
    jpeg_source_adaptor adaptor(src);

    jpeg_decompress_struct cinfo;
    jpeg_create_decompress(&cinfo);

    // error management
    jpeg_error_mgr error;
    cinfo.err = jpeg_std_error(&error);

    // source
    cinfo.src = &adaptor.mgr;

    // now read the header & image data
    jpeg_read_header(&cinfo, TRUE);
    jpeg_start_decompress(&cinfo);
    const int h = cinfo.output_height;
    const int w = cinfo.output_width;
    const int d = cinfo.output_components;
    output->set_size(h, w, d);

    for (int r = 0; r != h; ++r) {
        byte* rowp = output->rowp_as<byte>(r);
        jpeg_read_scanlines(&cinfo, &rowp, 1);
    }
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
}

void JPEGFormat::write(Image* input, byte_sink* output) {
    jpeg_dst_adaptor adaptor(output);

    jpeg_compress_struct cinfo;
    jpeg_create_compress(&cinfo);

    // error management
    jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);
    cinfo.err->trace_level = 128;

    cinfo.dest = &adaptor.mgr;

    cinfo.image_height = input->dim(0);
    cinfo.image_width = input->dim(1);
    cinfo.input_components = (input->ndims() > 2 ? input->dim(2) : 1);
    switch (cinfo.input_components) {
        case 1:
            cinfo.in_color_space = JCS_GRAYSCALE;
            break;
        case 3:
            cinfo.in_color_space = JCS_RGB;
            break;
        default:
            throw CannotWriteError("unsupported image dimensions");
    }

    jpeg_set_defaults(&cinfo);
    jpeg_start_compress(&cinfo, TRUE);

    while (cinfo.next_scanline < cinfo.image_height) {
        JSAMPROW rowp = static_cast<JSAMPROW>(input->rowp_as<void>(cinfo.next_scanline));
        (void) jpeg_write_scanlines(&cinfo, &rowp, 1);
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
}

<commit_msg>ENH Add error checking<commit_after>// Copyright 2012 Luis Pedro Coelho <luis@luispedro.org>
// License: MIT (see COPYING.MIT file)
#include "base.h"
#include "_jpeg.h"

#include <stdio.h>
#include <setjmp.h>

extern "C" {
#include <jpeglib.h>
}

namespace {
const size_t buffer_size = 4096;

struct jpeg_source_adaptor {
    jpeg_source_mgr mgr;
    byte_source* s;
    byte* buf;

    jpeg_source_adaptor(byte_source* s);

    ~jpeg_source_adaptor() {
        delete [] buf;
    }
};

struct jpeg_dst_adaptor {
    jpeg_destination_mgr mgr;
    byte_sink* s;
    byte* buf;

    jpeg_dst_adaptor(byte_sink* s);

    ~jpeg_dst_adaptor() {
        delete [] buf;
    }
};

void nop(j_decompress_ptr cinfo) { }
void nop_dst(j_compress_ptr cinfo) { }

boolean fill_input_buffer(j_decompress_ptr cinfo) {
    jpeg_source_adaptor* adaptor = reinterpret_cast<jpeg_source_adaptor*>(cinfo->src);
    adaptor->mgr.next_input_byte = adaptor->buf;
    adaptor->mgr.bytes_in_buffer = adaptor->s->read(adaptor->buf, buffer_size);
    return true;
}

void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
    if (num_bytes <= 0) return;
    jpeg_source_adaptor* adaptor = reinterpret_cast<jpeg_source_adaptor*>(cinfo->src);
    while (num_bytes > long(adaptor->mgr.bytes_in_buffer)) {
        num_bytes -= adaptor->mgr.bytes_in_buffer;
        fill_input_buffer(cinfo);
    }
    adaptor->mgr.next_input_byte += num_bytes;
    adaptor->mgr.bytes_in_buffer -= num_bytes;
}

boolean empty_output_buffer(j_compress_ptr cinfo) {
    jpeg_dst_adaptor* adaptor = reinterpret_cast<jpeg_dst_adaptor*>(cinfo->dest);
    adaptor->s->write(adaptor->buf, buffer_size);
    adaptor->mgr.next_output_byte = adaptor->buf;
    adaptor->mgr.free_in_buffer = buffer_size;
    return TRUE;
}

void flush_output_buffer(j_compress_ptr cinfo) {
    jpeg_dst_adaptor* adaptor = reinterpret_cast<jpeg_dst_adaptor*>(cinfo->dest);
    adaptor->s->write(adaptor->buf, adaptor->mgr.next_output_byte - adaptor->buf);
}

jpeg_source_adaptor::jpeg_source_adaptor(byte_source* s)
    :s(s)
    {
        buf = new byte[buffer_size];
        mgr.next_input_byte = buf;
        mgr.bytes_in_buffer = 0;

        mgr.init_source = nop;
        mgr.fill_input_buffer = fill_input_buffer;
        mgr.skip_input_data = skip_input_data;
        mgr.resync_to_restart = jpeg_resync_to_restart;
        mgr.term_source = nop;
    }

jpeg_dst_adaptor::jpeg_dst_adaptor(byte_sink* s)
    :s(s)
    {
        buf = new byte[buffer_size];

        mgr.next_output_byte = buf;
        mgr.free_in_buffer = buffer_size;

        mgr.init_destination = nop_dst;
        mgr.empty_output_buffer = empty_output_buffer;
        mgr.term_destination = flush_output_buffer;
    }

struct jpeg_decompress_holder {
    jpeg_decompress_holder() { jpeg_create_decompress(&info); }
    ~jpeg_decompress_holder() { jpeg_destroy_decompress(&info); }

    jpeg_decompress_struct info;
};

struct jpeg_compress_holder {
    jpeg_compress_holder() { jpeg_create_compress(&info); }
    ~jpeg_compress_holder() { jpeg_destroy_compress(&info); }

    jpeg_compress_struct info;
};

struct error_mgr {
    error_mgr();

    struct jpeg_error_mgr pub;
    jmp_buf setjmp_buffer;
};

void err_long_jump(j_common_ptr cinfo) {
  error_mgr* err = reinterpret_cast<error_mgr*>(cinfo->err);
  longjmp(err->setjmp_buffer, 1);
}

error_mgr::error_mgr() {
    jpeg_std_error(&pub);
    pub.error_exit = err_long_jump;
}

inline
J_COLOR_SPACE color_space(int components) {
    if (components == 1) return JCS_GRAYSCALE;
    if (components == 3) return JCS_RGB;
    throw CannotWriteError("unsupported image dimensions");
}

} // namespace

void JPEGFormat::read(byte_source* src, Image* output) {
    jpeg_source_adaptor adaptor(src);
    jpeg_decompress_holder c;

    // error management
    error_mgr jerr;
    c.info.err = &jerr.pub;

    // source
    c.info.src = &adaptor.mgr;

    if (setjmp(jerr.setjmp_buffer)) {
        throw CannotReadError();
    }
    // now read the header & image data
    jpeg_read_header(&c.info, TRUE);
    jpeg_start_decompress(&c.info);
    const int h = c.info.output_height;
    const int w = c.info.output_width;
    const int d = c.info.output_components;
    output->set_size(h, w, d);

    for (int r = 0; r != h; ++r) {
        byte* rowp = output->rowp_as<byte>(r);
        jpeg_read_scanlines(&c.info, &rowp, 1);
    }
    jpeg_finish_decompress(&c.info);
}

void JPEGFormat::write(Image* input, byte_sink* output) {
    jpeg_dst_adaptor adaptor(output);
    jpeg_compress_holder c;

    // error management
    error_mgr jerr;
    c.info.err = &jerr.pub;
    c.info.dest = &adaptor.mgr;

    if (setjmp(jerr.setjmp_buffer)) {
        throw CannotWriteError();
    }

    c.info.image_height = input->dim(0);
    c.info.image_width = input->dim(1);
    c.info.input_components = (input->ndims() > 2 ? input->dim(2) : 1);
    c.info.in_color_space = color_space(c.info.input_components);

    jpeg_set_defaults(&c.info);
    jpeg_start_compress(&c.info, TRUE);

    while (c.info.next_scanline < c.info.image_height) {
        JSAMPROW rowp = static_cast<JSAMPROW>(input->rowp_as<void>(c.info.next_scanline));
        (void) jpeg_write_scanlines(&c.info, &rowp, 1);
    }
    jpeg_finish_compress(&c.info);
}

<|endoftext|>


<commit_before>
#include <gainput/gainput.h>

#ifdef GAINPUT_DEV
#include "GainputDev.h"
#include "GainputNetListener.h"
#include "GainputNetConnection.h"
#include "GainputMemoryStream.h"

namespace gainput
{

static NetListener* devListener = 0;
static NetConnection* devConnection = 0;
static const InputManager* inputManager = 0;
static Allocator* allocator = 0;
static Array<const InputMap*> devMaps(GetDefaultAllocator());

class DevUserButtonListener : public MappedInputListener
{
public:
	DevUserButtonListener(const InputMap* map) : map_(map) { }

	void OnUserButtonBool(UserButtonId userButton, bool oldValue, bool newValue)
	{
		if (!devConnection)
		{
			return;
		}

		Stream* stream = allocator->New<MemoryStream>(32);
		stream->Write(uint8_t(DevCmdUserButtonChanged));
		stream->Write(uint64_t(map_));
		stream->Write(uint32_t(userButton));
		stream->Write(uint8_t(0));
		stream->Write(uint8_t(newValue));
		stream->SeekBegin(0);
		devConnection->Send(*stream);
		allocator->Delete(stream);
	}

	void OnUserButtonFloat(UserButtonId userButton, float oldValue, float newValue)
	{
		if (!devConnection)
		{
			return;
		}

		Stream* stream = allocator->New<MemoryStream>(32);
		stream->Write(uint8_t(DevCmdUserButtonChanged));
		stream->Write(uint64_t(map_));
		stream->Write(uint32_t(userButton));
		stream->Write(uint8_t(1));
		stream->Write(newValue);
		stream->SeekBegin(0);
		devConnection->Send(*stream);
		allocator->Delete(stream);
	}

private:
	const InputMap* map_;
};

void
DevInit(const InputManager* manager)
{
	if (devListener)
	{
		return;
	}

	inputManager = manager;
	allocator = &manager->GetAllocator();

	NetAddress address("0.0.0.0", 1211);
	devListener = allocator->New<NetListener>(address);

	if (!devListener->Start(false))
	{
		GAINPUT_LOG("TOOL: Unable to listen\n");
	}

	GAINPUT_LOG("TOOL: Listening...\n");
}

void
DevUpdate()
{
	if (!devConnection)
	{
		devConnection = devListener->Accept();
		if (devConnection)
		{
			GAINPUT_LOG("TOOL: New connection\n");
			char buf[1024];
			devConnection->Receive(buf, 1024);
			GAINPUT_LOG("TOOL: Got: %s\n", buf);
			int count = 0;
			Stream* stream = allocator->New<MemoryStream>(1024);

			for (DeviceId deviceId = 0; deviceId < 1000; ++deviceId)
			{
				const InputDevice* device = inputManager->GetDevice(deviceId);
				if (!device)
				{
					break;
				}

				stream->Reset();
				stream->Write(uint8_t(DevCmdDevice));
				stream->Write(uint32_t(device->GetDeviceId()));
				char deviceName[64];
				snprintf(deviceName, 64, "%s%d", device->GetTypeName(), device->GetIndex());
				stream->Write(uint8_t(strlen(deviceName)));
				stream->Write(deviceName, strlen(deviceName));
				stream->SeekBegin(0);
				devConnection->Send(*stream);

				for (DeviceButtonId buttonId = 0; buttonId < 1000; ++buttonId)
				{
					if (device->IsValidButtonId(buttonId))
					{
						stream->Reset();
						stream->Write(uint8_t(DevCmdDeviceButton));
						uint32_t t = deviceId;
						stream->Write(t);
						t = buttonId;
						stream->Write(t);
						char buttonName[128];
						const size_t len= device->GetButtonName(buttonId, buttonName, 128);
						stream->Write(uint8_t(len));
						if (len)
							stream->Write(buttonName, len);
						stream->Write(uint8_t(device->GetButtonType(buttonId)));
						stream->SeekBegin(0);
						devConnection->Send(*stream);
						++count;
					}
				}
			}
			GAINPUT_LOG("TOOL: Sent %d device buttons.\n", count);

			count = 0;
			for (Array<const InputMap*>::const_iterator it = devMaps.begin();
					it != devMaps.end();
					++it)
			{
				const InputMap* map = *it;
				stream->Reset();
				stream->Write(uint8_t(DevCmdMap));
				stream->Write(uint64_t(map));
				stream->Write(uint8_t(strlen(map->GetName())));
				stream->Write(map->GetName(), strlen(map->GetName()));
				stream->SeekBegin(0);
				devConnection->Send(*stream);

				DeviceButtonSpec mappings[32];
				for (UserButtonId buttonId = 0; buttonId < 1000; ++buttonId)
				{
					if (map->IsMapped(buttonId))
					{
						const size_t n = map->GetMappings(buttonId, mappings, 32);
						for (size_t i = 0; i < n; ++i)
						{
							stream->Reset();
							stream->Write(uint8_t(DevCmdUserButton));
							stream->Write(uint64_t(map));
							stream->Write(uint32_t(buttonId));
							stream->Write(uint32_t(mappings[i].deviceId));
							stream->Write(uint32_t(mappings[i].buttonId));
							stream->SeekBegin(0);
							devConnection->Send(*stream);
							++count;
						}
					}
				}
			}
			GAINPUT_LOG("TOOL: Sent %d user buttons.\n", count);

			allocator->Delete(stream);
		}
	}

	if (!devConnection)
	{
		return;
	}

	const uint8_t cmd = DevCmdPing;
	if (!devConnection->IsConnected() || devConnection->Send(&cmd, sizeof(cmd)) == 0)
	{
		GAINPUT_LOG("TOOL: Disconnected\n");
		devConnection->Close();
		delete devConnection;
		devConnection = 0;
		return;
	}
}

void
DevNewMap(InputMap* inputMap)
{
	devMaps.push_back(inputMap);
	inputMap->AddListener(allocator->New<DevUserButtonListener>(inputMap));
	// TODO inform existing devConnection
}

}

#endif

<commit_msg>Added sending of current value to dev tool communication.<commit_after>
#include <gainput/gainput.h>

#ifdef GAINPUT_DEV
#include "GainputDev.h"
#include "GainputNetListener.h"
#include "GainputNetConnection.h"
#include "GainputMemoryStream.h"

namespace gainput
{

static NetListener* devListener = 0;
static NetConnection* devConnection = 0;
static const InputManager* inputManager = 0;
static Allocator* allocator = 0;
static Array<const InputMap*> devMaps(GetDefaultAllocator());

class DevUserButtonListener : public MappedInputListener
{
public:
	DevUserButtonListener(const InputMap* map) : map_(map) { }

	void OnUserButtonBool(UserButtonId userButton, bool oldValue, bool newValue)
	{
		if (!devConnection)
		{
			return;
		}

		Stream* stream = allocator->New<MemoryStream>(32);
		stream->Write(uint8_t(DevCmdUserButtonChanged));
		stream->Write(uint64_t(map_));
		stream->Write(uint32_t(userButton));
		stream->Write(uint8_t(0));
		stream->Write(uint8_t(newValue));
		stream->SeekBegin(0);
		devConnection->Send(*stream);
		allocator->Delete(stream);
	}

	void OnUserButtonFloat(UserButtonId userButton, float oldValue, float newValue)
	{
		if (!devConnection)
		{
			return;
		}

		Stream* stream = allocator->New<MemoryStream>(32);
		stream->Write(uint8_t(DevCmdUserButtonChanged));
		stream->Write(uint64_t(map_));
		stream->Write(uint32_t(userButton));
		stream->Write(uint8_t(1));
		stream->Write(newValue);
		stream->SeekBegin(0);
		devConnection->Send(*stream);
		allocator->Delete(stream);
	}

private:
	const InputMap* map_;
};

void
DevInit(const InputManager* manager)
{
	if (devListener)
	{
		return;
	}

	inputManager = manager;
	allocator = &manager->GetAllocator();

	NetAddress address("0.0.0.0", 1211);
	devListener = allocator->New<NetListener>(address);

	if (!devListener->Start(false))
	{
		GAINPUT_LOG("TOOL: Unable to listen\n");
	}

	GAINPUT_LOG("TOOL: Listening...\n");
}

void
DevUpdate()
{
	if (!devConnection)
	{
		devConnection = devListener->Accept();
		if (devConnection)
		{
			GAINPUT_LOG("TOOL: New connection\n");
			char buf[1024];
			devConnection->Receive(buf, 1024);
			GAINPUT_LOG("TOOL: Got: %s\n", buf);
			int count = 0;
			Stream* stream = allocator->New<MemoryStream>(1024);

			for (DeviceId deviceId = 0; deviceId < 1000; ++deviceId)
			{
				const InputDevice* device = inputManager->GetDevice(deviceId);
				if (!device)
				{
					break;
				}

				stream->Reset();
				stream->Write(uint8_t(DevCmdDevice));
				stream->Write(uint32_t(device->GetDeviceId()));
				char deviceName[64];
				snprintf(deviceName, 64, "%s%d", device->GetTypeName(), device->GetIndex());
				stream->Write(uint8_t(strlen(deviceName)));
				stream->Write(deviceName, strlen(deviceName));
				stream->SeekBegin(0);
				devConnection->Send(*stream);

				for (DeviceButtonId buttonId = 0; buttonId < 1000; ++buttonId)
				{
					if (device->IsValidButtonId(buttonId))
					{
						stream->Reset();
						stream->Write(uint8_t(DevCmdDeviceButton));
						uint32_t t = deviceId;
						stream->Write(t);
						t = buttonId;
						stream->Write(t);
						char buttonName[128];
						const size_t len= device->GetButtonName(buttonId, buttonName, 128);
						stream->Write(uint8_t(len));
						if (len)
							stream->Write(buttonName, len);
						stream->Write(uint8_t(device->GetButtonType(buttonId)));
						stream->SeekBegin(0);
						devConnection->Send(*stream);
						++count;
					}
				}
			}
			GAINPUT_LOG("TOOL: Sent %d device buttons.\n", count);

			count = 0;
			for (Array<const InputMap*>::const_iterator it = devMaps.begin();
					it != devMaps.end();
					++it)
			{
				const InputMap* map = *it;
				stream->Reset();
				stream->Write(uint8_t(DevCmdMap));
				stream->Write(uint64_t(map));
				stream->Write(uint8_t(strlen(map->GetName())));
				stream->Write(map->GetName(), strlen(map->GetName()));
				stream->SeekBegin(0);
				devConnection->Send(*stream);

				DeviceButtonSpec mappings[32];
				for (UserButtonId buttonId = 0; buttonId < 1000; ++buttonId)
				{
					if (map->IsMapped(buttonId))
					{
						const size_t n = map->GetMappings(buttonId, mappings, 32);
						for (size_t i = 0; i < n; ++i)
						{
							stream->Reset();
							stream->Write(uint8_t(DevCmdUserButton));
							stream->Write(uint64_t(map));
							stream->Write(uint32_t(buttonId));
							stream->Write(uint32_t(mappings[i].deviceId));
							stream->Write(uint32_t(mappings[i].buttonId));
							stream->Write(map->GetFloat(buttonId));
							stream->SeekBegin(0);
							devConnection->Send(*stream);
							++count;
						}
					}
				}
			}
			GAINPUT_LOG("TOOL: Sent %d user buttons.\n", count);

			allocator->Delete(stream);
		}
	}

	if (!devConnection)
	{
		return;
	}

	const uint8_t cmd = DevCmdPing;
	if (!devConnection->IsConnected() || devConnection->Send(&cmd, sizeof(cmd)) == 0)
	{
		GAINPUT_LOG("TOOL: Disconnected\n");
		devConnection->Close();
		delete devConnection;
		devConnection = 0;
		return;
	}
}

void
DevNewMap(InputMap* inputMap)
{
	devMaps.push_back(inputMap);
	inputMap->AddListener(allocator->New<DevUserButtonListener>(inputMap));
	// TODO inform existing devConnection
}

}

#endif

<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <cstddef>
#include <cstdint>
#include <vector>

#include "caf/serializer.hpp"

namespace caf {

/// Implements the serializer interface with a binary serialization protocol.
class binary_serializer final : public serializer {
public:
  // -- member types -----------------------------------------------------------

  using super = serializer;

  using buffer = std::vector<char>;

  // -- constructors, destructors, and assignment operators --------------------

  binary_serializer(actor_system& sys, buffer& buf);

  binary_serializer(execution_unit* ctx, buffer& buf);

  // -- overridden member functions --------------------------------------------

  /// Sets the write position to given offset.
  /// @pre `offset <= buf.size()`
  void seek(size_t offset);

  /// Jumps `num_bytes` forward. Resizes the buffer (filling it with zeros)
  /// when skipping past the end.
  void skip(size_t num_bytes);

  // -- overridden member functions --------------------------------------------

  error begin_object(uint16_t& typenr, std::string& name) override;

  error end_object() override;

  error begin_sequence(size_t& list_size) override;

  error end_sequence() override;

  error apply_raw(size_t num_bytes, void* data) override;

protected:
  error apply_impl(int8_t&) override;

  error apply_impl(uint8_t&) override;

  error apply_impl(int16_t&) override;

  error apply_impl(uint16_t&) override;

  error apply_impl(int32_t&) override;

  error apply_impl(uint32_t&) override;

  error apply_impl(int64_t&) override;

  error apply_impl(uint64_t&) override;

  error apply_impl(float&) override;

  error apply_impl(double&) override;

  error apply_impl(long double&) override;

  error apply_impl(std::string&) override;

  error apply_impl(std::u16string&) override;

  error apply_impl(std::u32string&) override;

private:
  buffer& buf_;
  buffer::iterator write_pos_;
};

} // namespace caf
<commit_msg>Add getter for the byte buffer<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include <cstddef>
#include <cstdint>
#include <vector>

#include "caf/serializer.hpp"

namespace caf {

/// Implements the serializer interface with a binary serialization protocol.
class binary_serializer final : public serializer {
public:
  // -- member types -----------------------------------------------------------

  using super = serializer;

  using buffer = std::vector<char>;

  // -- constructors, destructors, and assignment operators --------------------

  binary_serializer(actor_system& sys, buffer& buf);

  binary_serializer(execution_unit* ctx, buffer& buf);

  // -- overridden member functions --------------------------------------------

  /// Sets the write position to given offset.
  /// @pre `offset <= buf.size()`
  void seek(size_t offset);

  /// Jumps `num_bytes` forward. Resizes the buffer (filling it with zeros)
  /// when skipping past the end.
  void skip(size_t num_bytes);

  // -- overridden member functions --------------------------------------------

  error begin_object(uint16_t& typenr, std::string& name) override;

  error end_object() override;

  error begin_sequence(size_t& list_size) override;

  error end_sequence() override;

  error apply_raw(size_t num_bytes, void* data) override;

  // -- properties -------------------------------------------------------------

  buffer& buf() {
    return buf_;
  }

  const buffer& buf() const {
    return buf_;
  }

protected:
  error apply_impl(int8_t&) override;

  error apply_impl(uint8_t&) override;

  error apply_impl(int16_t&) override;

  error apply_impl(uint16_t&) override;

  error apply_impl(int32_t&) override;

  error apply_impl(uint32_t&) override;

  error apply_impl(int64_t&) override;

  error apply_impl(uint64_t&) override;

  error apply_impl(float&) override;

  error apply_impl(double&) override;

  error apply_impl(long double&) override;

  error apply_impl(std::string&) override;

  error apply_impl(std::u16string&) override;

  error apply_impl(std::u32string&) override;

private:
  buffer& buf_;
  buffer::iterator write_pos_;
};

} // namespace caf
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/monitorable_actor.hpp"

#include "caf/sec.hpp"
#include "caf/logger.hpp"
#include "caf/actor_cast.hpp"
#include "caf/actor_system.hpp"
#include "caf/message_handler.hpp"
#include "caf/system_messages.hpp"
#include "caf/default_attachable.hpp"

#include "caf/detail/sync_request_bouncer.hpp"

#include "caf/scheduler/abstract_coordinator.hpp"

namespace caf {

const char* monitorable_actor::name() const {
  return "monitorable_actor";
}

void monitorable_actor::attach(attachable_ptr ptr) {
  CAF_LOG_TRACE("");
  CAF_ASSERT(ptr != nullptr);
  error fail_state;
  auto attached = exclusive_critical_section([&] {
    if (getf(is_terminated_flag)) {
      fail_state = fail_state_;
      return false;
    }
    attach_impl(ptr);
    return true;
  });
  CAF_LOG_DEBUG("cannot attach functor to terminated actor: call immediately");
  if (!attached)
    ptr->actor_exited(fail_state, nullptr);
}

size_t monitorable_actor::detach(const attachable::token& what) {
  CAF_LOG_TRACE("");
  std::unique_lock<std::mutex> guard{mtx_};
  return detach_impl(what);
}

void monitorable_actor::unlink_from(const actor_addr& x) {
  auto ptr = actor_cast<strong_actor_ptr>(x);
  if (ptr != nullptr) {
    if (ptr->get() != this)
      remove_link(ptr->get());
  } else {
    default_attachable::observe_token tk{x, default_attachable::link};
    exclusive_critical_section([&] {
      detach_impl(tk, true);
    });
  }
}

bool monitorable_actor::cleanup(error&& reason, execution_unit* host) {
  CAF_LOG_TRACE(CAF_ARG(reason));
  attachable_ptr head;
  bool set_fail_state = exclusive_critical_section([&]() -> bool {
    if (!getf(is_cleaned_up_flag)) {
      // local actors pass fail_state_ as first argument
      if (&fail_state_ != &reason)
        fail_state_ = std::move(reason);
      attachables_head_.swap(head);
      flags(flags() | is_terminated_flag | is_cleaned_up_flag);
      on_cleanup();
      return true;
    }
    return false;
  });
  if (!set_fail_state)
    return false;
  CAF_LOG_INFO("cleanup" << CAF_ARG(id())
               << CAF_ARG(node()) << CAF_ARG(reason));
  // send exit messages
  for (attachable* i = head.get(); i != nullptr; i = i->next.get())
    i->actor_exited(reason, host);
  // tell printer to purge its state for us if we ever used aout()
  if (getf(abstract_actor::has_used_aout_flag)) {
    auto pr = home_system().scheduler().printer();
    pr->enqueue(make_mailbox_element(nullptr, make_message_id(), {},
                                      delete_atom::value, id()),
                nullptr);
  }
  return true;
}

void monitorable_actor::on_cleanup() {
  // nop
}

void monitorable_actor::bounce(mailbox_element_ptr& what) {
  error err;
  shared_critical_section([&] {
    err = fail_state_;
  });
  bounce(what, err);
}

void monitorable_actor::bounce(mailbox_element_ptr& what, const error& err) {
  // make sure that a request always gets a response;
  // the exit reason reflects the first actor on the
  // forwarding chain that is out of service
  detail::sync_request_bouncer rb{err};
  rb(*what);
}

monitorable_actor::monitorable_actor(actor_config& cfg) : abstract_actor(cfg) {
  // nop
}

void monitorable_actor::add_link(abstract_actor* x) {
  // Add backlink on `x` first and add the local attachable only on success.
  CAF_LOG_TRACE(CAF_ARG(x));
  CAF_ASSERT(x != nullptr);
  error fail_state;
  bool send_exit_immediately = false;
  auto tmp = default_attachable::make_link(address(), x->address());
  joined_exclusive_critical_section(this, x, [&] {
    if (getf(is_terminated_flag)) {
      fail_state = fail_state_;
      send_exit_immediately = true;
    } else if (x->add_backlink(this)) {
      attach_impl(tmp);
    }
  });
  if (send_exit_immediately)
    x->enqueue(nullptr, invalid_message_id,
                 make_message(exit_msg{address(), fail_state}), nullptr);
}

void monitorable_actor::remove_link(abstract_actor* x) {
  CAF_LOG_TRACE(CAF_ARG(x));
  default_attachable::observe_token tk{x->address(), default_attachable::link};
  joined_exclusive_critical_section(this, x, [&] {
    x->remove_backlink(this);
    detach_impl(tk, true);
  });
}

bool monitorable_actor::add_backlink(abstract_actor* x) {
  // Called in an exclusive critical section.
  CAF_LOG_TRACE(CAF_ARG(x));
  CAF_ASSERT(x);
  error fail_state;
  bool send_exit_immediately = false;
  default_attachable::observe_token tk{x->address(),
                                       default_attachable::link};
  auto tmp = default_attachable::make_link(address(), x->address());
  auto success = false;
  if (getf(is_terminated_flag)) {
    fail_state = fail_state_;
    send_exit_immediately = true;
  } else if (detach_impl(tk, true, true) == 0) {
    attach_impl(tmp);
    success = true;
  }
  if (send_exit_immediately)
    x->enqueue(nullptr, invalid_message_id,
               make_message(exit_msg{address(), fail_state}), nullptr);
  return success;
}

bool monitorable_actor::remove_backlink(abstract_actor* x) {
  // Called in an exclusive critical section.
  CAF_LOG_TRACE(CAF_ARG(x));
  default_attachable::observe_token tk{x->address(), default_attachable::link};
  return detach_impl(tk, true) > 0;
}

error monitorable_actor::fail_state() const {
  std::unique_lock<std::mutex> guard{mtx_};
  return fail_state_;
}

size_t monitorable_actor::detach_impl(const attachable::token& what,
                                      bool stop_on_hit, bool dry_run) {
  CAF_LOG_TRACE(CAF_ARG(stop_on_hit) << CAF_ARG(dry_run));
  size_t count = 0;
  auto i = &attachables_head_;
  while (*i != nullptr) {
    if ((*i)->matches(what)) {
      ++count;
      if (!dry_run) {
        CAF_LOG_DEBUG("removed element");
        attachable_ptr next;
        next.swap((*i)->next);
        (*i).swap(next);
      } else {
        i = &((*i)->next);
      }
      if (stop_on_hit)
        return count;
    } else {
      i = &((*i)->next);
    }
  }
  return count;
}

bool monitorable_actor::handle_system_message(mailbox_element& x,
                                              execution_unit* ctx,
                                              bool trap_exit) {
  auto& msg = x.content();
  if (!trap_exit && msg.size() == 1 && msg.match_element<exit_msg>(0)) {
    // exits for non-normal exit reasons
    auto& em = msg.get_mutable_as<exit_msg>(0);
    if (em.reason)
      cleanup(std::move(em.reason), ctx);
    return true;
  }
  if (msg.size() > 1 && msg.match_element<sys_atom>(0)) {
    if (!x.sender)
      return true;
    error err;
    mailbox_element_ptr res;
    msg.apply(
      [&](sys_atom, get_atom, std::string& what) {
        CAF_LOG_TRACE(CAF_ARG(what));
        if (what != "info") {
          err = sec::unsupported_sys_key;
          return;
        }
        res = make_mailbox_element(ctrl(), x.mid.response_id(), {},
                                    ok_atom::value, std::move(what),
                                    strong_actor_ptr{ctrl()}, name());
      }
    );
    if (!res && !err)
      err = sec::unsupported_sys_message;
    if (err && x.mid.is_request())
      res = make_mailbox_element(ctrl(), x.mid.response_id(),
                                  {}, std::move(err));
    if (res) {
      auto s = actor_cast<strong_actor_ptr>(x.sender);
      if (s)
        s->enqueue(std::move(res), ctx);
    }
    return true;
  }
  return false;
}

} // namespace caf
<commit_msg>Demote logging in cleanup to DEBUG<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/monitorable_actor.hpp"

#include "caf/sec.hpp"
#include "caf/logger.hpp"
#include "caf/actor_cast.hpp"
#include "caf/actor_system.hpp"
#include "caf/message_handler.hpp"
#include "caf/system_messages.hpp"
#include "caf/default_attachable.hpp"

#include "caf/detail/sync_request_bouncer.hpp"

#include "caf/scheduler/abstract_coordinator.hpp"

namespace caf {

const char* monitorable_actor::name() const {
  return "monitorable_actor";
}

void monitorable_actor::attach(attachable_ptr ptr) {
  CAF_LOG_TRACE("");
  CAF_ASSERT(ptr != nullptr);
  error fail_state;
  auto attached = exclusive_critical_section([&] {
    if (getf(is_terminated_flag)) {
      fail_state = fail_state_;
      return false;
    }
    attach_impl(ptr);
    return true;
  });
  CAF_LOG_DEBUG("cannot attach functor to terminated actor: call immediately");
  if (!attached)
    ptr->actor_exited(fail_state, nullptr);
}

size_t monitorable_actor::detach(const attachable::token& what) {
  CAF_LOG_TRACE("");
  std::unique_lock<std::mutex> guard{mtx_};
  return detach_impl(what);
}

void monitorable_actor::unlink_from(const actor_addr& x) {
  auto ptr = actor_cast<strong_actor_ptr>(x);
  if (ptr != nullptr) {
    if (ptr->get() != this)
      remove_link(ptr->get());
  } else {
    default_attachable::observe_token tk{x, default_attachable::link};
    exclusive_critical_section([&] {
      detach_impl(tk, true);
    });
  }
}

bool monitorable_actor::cleanup(error&& reason, execution_unit* host) {
  CAF_LOG_TRACE(CAF_ARG(reason));
  attachable_ptr head;
  bool set_fail_state = exclusive_critical_section([&]() -> bool {
    if (!getf(is_cleaned_up_flag)) {
      // local actors pass fail_state_ as first argument
      if (&fail_state_ != &reason)
        fail_state_ = std::move(reason);
      attachables_head_.swap(head);
      flags(flags() | is_terminated_flag | is_cleaned_up_flag);
      on_cleanup();
      return true;
    }
    return false;
  });
  if (!set_fail_state)
    return false;
  CAF_LOG_DEBUG("cleanup" << CAF_ARG(id())
                << CAF_ARG(node()) << CAF_ARG(reason));
  // send exit messages
  for (attachable* i = head.get(); i != nullptr; i = i->next.get())
    i->actor_exited(reason, host);
  // tell printer to purge its state for us if we ever used aout()
  if (getf(abstract_actor::has_used_aout_flag)) {
    auto pr = home_system().scheduler().printer();
    pr->enqueue(make_mailbox_element(nullptr, make_message_id(), {},
                                      delete_atom::value, id()),
                nullptr);
  }
  return true;
}

void monitorable_actor::on_cleanup() {
  // nop
}

void monitorable_actor::bounce(mailbox_element_ptr& what) {
  error err;
  shared_critical_section([&] {
    err = fail_state_;
  });
  bounce(what, err);
}

void monitorable_actor::bounce(mailbox_element_ptr& what, const error& err) {
  // make sure that a request always gets a response;
  // the exit reason reflects the first actor on the
  // forwarding chain that is out of service
  detail::sync_request_bouncer rb{err};
  rb(*what);
}

monitorable_actor::monitorable_actor(actor_config& cfg) : abstract_actor(cfg) {
  // nop
}

void monitorable_actor::add_link(abstract_actor* x) {
  // Add backlink on `x` first and add the local attachable only on success.
  CAF_LOG_TRACE(CAF_ARG(x));
  CAF_ASSERT(x != nullptr);
  error fail_state;
  bool send_exit_immediately = false;
  auto tmp = default_attachable::make_link(address(), x->address());
  joined_exclusive_critical_section(this, x, [&] {
    if (getf(is_terminated_flag)) {
      fail_state = fail_state_;
      send_exit_immediately = true;
    } else if (x->add_backlink(this)) {
      attach_impl(tmp);
    }
  });
  if (send_exit_immediately)
    x->enqueue(nullptr, invalid_message_id,
                 make_message(exit_msg{address(), fail_state}), nullptr);
}

void monitorable_actor::remove_link(abstract_actor* x) {
  CAF_LOG_TRACE(CAF_ARG(x));
  default_attachable::observe_token tk{x->address(), default_attachable::link};
  joined_exclusive_critical_section(this, x, [&] {
    x->remove_backlink(this);
    detach_impl(tk, true);
  });
}

bool monitorable_actor::add_backlink(abstract_actor* x) {
  // Called in an exclusive critical section.
  CAF_LOG_TRACE(CAF_ARG(x));
  CAF_ASSERT(x);
  error fail_state;
  bool send_exit_immediately = false;
  default_attachable::observe_token tk{x->address(),
                                       default_attachable::link};
  auto tmp = default_attachable::make_link(address(), x->address());
  auto success = false;
  if (getf(is_terminated_flag)) {
    fail_state = fail_state_;
    send_exit_immediately = true;
  } else if (detach_impl(tk, true, true) == 0) {
    attach_impl(tmp);
    success = true;
  }
  if (send_exit_immediately)
    x->enqueue(nullptr, invalid_message_id,
               make_message(exit_msg{address(), fail_state}), nullptr);
  return success;
}

bool monitorable_actor::remove_backlink(abstract_actor* x) {
  // Called in an exclusive critical section.
  CAF_LOG_TRACE(CAF_ARG(x));
  default_attachable::observe_token tk{x->address(), default_attachable::link};
  return detach_impl(tk, true) > 0;
}

error monitorable_actor::fail_state() const {
  std::unique_lock<std::mutex> guard{mtx_};
  return fail_state_;
}

size_t monitorable_actor::detach_impl(const attachable::token& what,
                                      bool stop_on_hit, bool dry_run) {
  CAF_LOG_TRACE(CAF_ARG(stop_on_hit) << CAF_ARG(dry_run));
  size_t count = 0;
  auto i = &attachables_head_;
  while (*i != nullptr) {
    if ((*i)->matches(what)) {
      ++count;
      if (!dry_run) {
        CAF_LOG_DEBUG("removed element");
        attachable_ptr next;
        next.swap((*i)->next);
        (*i).swap(next);
      } else {
        i = &((*i)->next);
      }
      if (stop_on_hit)
        return count;
    } else {
      i = &((*i)->next);
    }
  }
  return count;
}

bool monitorable_actor::handle_system_message(mailbox_element& x,
                                              execution_unit* ctx,
                                              bool trap_exit) {
  auto& msg = x.content();
  if (!trap_exit && msg.size() == 1 && msg.match_element<exit_msg>(0)) {
    // exits for non-normal exit reasons
    auto& em = msg.get_mutable_as<exit_msg>(0);
    if (em.reason)
      cleanup(std::move(em.reason), ctx);
    return true;
  }
  if (msg.size() > 1 && msg.match_element<sys_atom>(0)) {
    if (!x.sender)
      return true;
    error err;
    mailbox_element_ptr res;
    msg.apply(
      [&](sys_atom, get_atom, std::string& what) {
        CAF_LOG_TRACE(CAF_ARG(what));
        if (what != "info") {
          err = sec::unsupported_sys_key;
          return;
        }
        res = make_mailbox_element(ctrl(), x.mid.response_id(), {},
                                    ok_atom::value, std::move(what),
                                    strong_actor_ptr{ctrl()}, name());
      }
    );
    if (!res && !err)
      err = sec::unsupported_sys_message;
    if (err && x.mid.is_request())
      res = make_mailbox_element(ctrl(), x.mid.response_id(),
                                  {}, std::move(err));
    if (res) {
      auto s = actor_cast<strong_actor_ptr>(x.sender);
      if (s)
        s->enqueue(std::move(res), ctx);
    }
    return true;
  }
  return false;
}

} // namespace caf
<|endoftext|>


<commit_before>/*
    kopetepasswordwidget.cpp - widget for modifying a Kopete::Password

    Copyright (c) 2003 by Richard Smith          <kde@metafoo.co.uk>

    Kopete    (c) 2003 by the Kopete developers  <kopete-devel@kde.org>

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

#include "kopetepasswordwidget.h"
#include "kopetepassword.h"

#include <klineedit.h>

#include <qcheckbox.h>

Kopete::UI::PasswordWidget::PasswordWidget( QWidget *parent )
	    : QWidget( parent )//, d( new Private )
{
	    setupUi( this );
}

Kopete::UI::PasswordWidget::PasswordWidget( Kopete::Password *from, QWidget *parent )
	: QWidget( parent )//, d( new Private )
{
	setupUi( this );

	load( from );
}

Kopete::UI::PasswordWidget::~PasswordWidget()
{
//	delete d;
}

void Kopete::UI::PasswordWidget::load( Kopete::Password *source )
{
	disconnect( mRemembered, SIGNAL( stateChanged( int ) ), this, SLOT( slotRememberChanged() ) );
	disconnect( mPassword, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
	disconnect( mRemembered, SIGNAL( stateChanged( int ) ), this, SIGNAL( changed() ) );

	if ( source && source->remembered() )
	{
		mRemembered->setTristate();
		mRemembered->setCheckState( Qt::Checked );
		source->requestWithoutPrompt( this, SLOT( receivePassword( const QString & ) ) );
	}
	else
	{
		mRemembered->setTristate( false );
		mRemembered->setCheckState( Qt::Unchecked );
	}

	mPassword->setEnabled( false );
    mPassword->setPasswordMode(true);

	connect( mRemembered, SIGNAL( stateChanged( int ) ), this, SLOT( slotRememberChanged() ) );
	connect( mPassword, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
	connect( mRemembered, SIGNAL( stateChanged( int ) ), this, SIGNAL( changed() ) );

	emit changed();
}

void Kopete::UI::PasswordWidget::slotRememberChanged()
{
	mRemembered->setTristate( false );
	mPassword->setEnabled( mRemembered->isChecked() );
}

void Kopete::UI::PasswordWidget::receivePassword( const QString &pwd )
{
	// pwd == null could mean user declined to open wallet
	// don't uncheck the remembered field in this case.
	if ( !pwd.isNull() && mRemembered->checkState() == Qt::PartiallyChecked )
	{
		mRemembered->setChecked( true );
		setPassword( pwd );
	}
}

void Kopete::UI::PasswordWidget::save( Kopete::Password *target )
{
	if ( !target || mRemembered->checkState() == Qt::PartiallyChecked )
		return;

	if ( mRemembered->isChecked() )
		target->set( password() );
	else
		target->set();
}

bool Kopete::UI::PasswordWidget::validate()
{
#ifdef __GNUC__
#warning  TODO do something interesting or remove the function
#endif
	return true;
}

QString Kopete::UI::PasswordWidget::password() const
{
	return mPassword->text();
}

bool Kopete::UI::PasswordWidget::remember() const
{
	return mRemembered->checkState() == Qt::Checked;
}

void Kopete::UI::PasswordWidget::setPassword( const QString &pass )
{
	// switch out of 'waiting for wallet' mode if we're in it
	mRemembered->setTristate( false );

	// fill in the password text
	mPassword->clear();
	mPassword->setText( pass );
	mPassword->setEnabled( remember() );
}

#include "kopetepasswordwidget.moc"

// vim: set noet ts=4 sts=4 sw=4:
<commit_msg>- also set password mode when a new account is created - fix enabled state<commit_after>/*
    kopetepasswordwidget.cpp - widget for modifying a Kopete::Password

    Copyright (c) 2003 by Richard Smith          <kde@metafoo.co.uk>

    Kopete    (c) 2003 by the Kopete developers  <kopete-devel@kde.org>

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

#include "kopetepasswordwidget.h"
#include "kopetepassword.h"

#include <klineedit.h>

#include <qcheckbox.h>

Kopete::UI::PasswordWidget::PasswordWidget( QWidget *parent )
	    : QWidget( parent )//, d( new Private )
{
	setupUi( this );
	mPassword->setPasswordMode(true);
}

Kopete::UI::PasswordWidget::PasswordWidget( Kopete::Password *from, QWidget *parent )
	: QWidget( parent )//, d( new Private )
{
	setupUi( this );
	mPassword->setPasswordMode(true);

	load( from );
}

Kopete::UI::PasswordWidget::~PasswordWidget()
{
//	delete d;
}

void Kopete::UI::PasswordWidget::load( Kopete::Password *source )
{
	disconnect( mRemembered, SIGNAL( stateChanged( int ) ), this, SLOT( slotRememberChanged() ) );
	disconnect( mPassword, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
	disconnect( mRemembered, SIGNAL( stateChanged( int ) ), this, SIGNAL( changed() ) );

	if ( source && source->remembered() )
	{
		mRemembered->setTristate();
		mRemembered->setCheckState( Qt::Checked );
		mPassword->setEnabled( true );
		source->requestWithoutPrompt( this, SLOT( receivePassword( const QString & ) ) );
	}
	else
	{
		mRemembered->setTristate( false );
		mRemembered->setCheckState( Qt::Unchecked );
		mPassword->setEnabled( false );
	}

	connect( mRemembered, SIGNAL( stateChanged( int ) ), this, SLOT( slotRememberChanged() ) );
	connect( mPassword, SIGNAL( textChanged( const QString & ) ), this, SIGNAL( changed() ) );
	connect( mRemembered, SIGNAL( stateChanged( int ) ), this, SIGNAL( changed() ) );

	emit changed();
}

void Kopete::UI::PasswordWidget::slotRememberChanged()
{
	mRemembered->setTristate( false );
	mPassword->setEnabled( mRemembered->isChecked() );
}

void Kopete::UI::PasswordWidget::receivePassword( const QString &pwd )
{
	// pwd == null could mean user declined to open wallet
	// don't uncheck the remembered field in this case.
	if ( !pwd.isNull() && mRemembered->checkState() == Qt::PartiallyChecked )
	{
		mRemembered->setChecked( true );
		setPassword( pwd );
	}
}

void Kopete::UI::PasswordWidget::save( Kopete::Password *target )
{
	if ( !target || mRemembered->checkState() == Qt::PartiallyChecked )
		return;

	if ( mRemembered->isChecked() )
		target->set( password() );
	else
		target->set();
}

bool Kopete::UI::PasswordWidget::validate()
{
#ifdef __GNUC__
#warning  TODO do something interesting or remove the function
#endif
	return true;
}

QString Kopete::UI::PasswordWidget::password() const
{
	return mPassword->text();
}

bool Kopete::UI::PasswordWidget::remember() const
{
	return mRemembered->checkState() == Qt::Checked;
}

void Kopete::UI::PasswordWidget::setPassword( const QString &pass )
{
	// switch out of 'waiting for wallet' mode if we're in it
	mRemembered->setTristate( false );

	// fill in the password text
	mPassword->clear();
	mPassword->setText( pass );
	mPassword->setEnabled( remember() );
}

#include "kopetepasswordwidget.moc"

// vim: set noet ts=4 sts=4 sw=4:
<|endoftext|>


<commit_before>/**
 * @file		soloader.hpp
 * @brief		shared library loader
 * @author		Byunghun Hwang<bhhwang@nsynapse.com>
 * @date 		2015. 8. 12
 * @details	dependent shared library loader(multiple independent)
 */

#ifndef _COSSB_SOLOADER_HPP_
#define _COSSB_SOLOADER_HPP_

#include <dlfcn.h>
#include <string>
#include "util/format.h"
#include <iostream>

using namespace std;

namespace cossb {
namespace base {

template<class T>
class soloader {
public:
	soloader(const char* so_file):_so(so_file) {
		string sopath = fmt::format("./{}",_so);

		cout << "load " << sopath << endl;
		_handle = dlopen(sopath.c_str(), RTLD_NOW|RTLD_GLOBAL);
	}

	virtual ~soloader() {
		cout << "unload" << endl;
		if(_handle){
			dlclose(_handle);
			_handle = nullptr;
		}
	}

	T* load() {

		if(_handle)
		{
			typedef T* create_t();
			create_t* pfcreate = (create_t*)dlsym(_handle, "create");

			if(pfcreate)
				return pfcreate();
		}

		return nullptr;
	}

private:
	void* _handle = nullptr;
	string _so;
};

} /* namespace base */
} /* namespace cossb */

#endif /* _COSSB_SOLOADER_HPP_ */
<commit_msg>remove soloder, it changes to the libadopter<commit_after><|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <functional>

template <class T, class... Args>
T& back_insert(T& reference, Args&&... args) {
	// Allocate more space (reserve is inefficient)
	size_t old_size = reference.size();
	reference.resize(old_size + sizeof...(args));
	reference.resize(old_size);

	(reference.emplace_back(std::forward<Args>(args)), ...);
	return reference;
}

template <class T, class C>
constexpr typename T::const_iterator binary_find(const T& x, const C& val) {
	auto beg = x.begin(), end = x.end();
	while (beg != end) {
		auto mid = beg + ((end - beg) >> 1);
		if (*mid < val)
			beg = ++mid;
		else
			end = mid;
	}
	return (beg != x.end() && *beg == val ? beg : x.end());
}

template <class T, class C, class Comp>
constexpr typename T::const_iterator binary_find(const T& x, const C& val,
                                                 Comp&& comp) {
	auto beg = x.begin(), end = x.end();
	while (beg != end) {
		auto mid = beg + ((end - beg) >> 1);
		if (comp(*mid, val))
			beg = ++mid;
		else
			end = mid;
	}
	return (beg != x.end() && !comp(*beg, val) && !comp(val, *beg) ? beg
	                                                               : x.end());
}

template <class T, typename B, class C>
constexpr typename T::const_iterator
binary_find_by(const T& x, B T::value_type::*field, const C& val) {
	auto beg = x.begin(), end = x.end();
	while (beg != end) {
		auto mid = beg + ((end - beg) >> 1);
		if ((*mid).*field < val)
			beg = ++mid;
		else
			end = mid;
	}
	return (beg != x.end() && (*beg).*field == val ? beg : x.end());
}

template <class T, typename B, class C, class Comp>
constexpr typename T::const_iterator
binary_find_by(const T& x, B T::value_type::*field, const C& val, Comp&& comp) {
	auto beg = x.begin(), end = x.end();
	while (beg != end) {
		auto mid = beg + ((end - beg) >> 1);
		if (comp((*mid).*field, val))
			beg = ++mid;
		else
			end = mid;
	}
	return (beg != x.end() && (*beg).*field == val ? beg : x.end());
}

// Aliases - take container instead of range
template <class A, class B>
inline bool binary_search(const A& a, B&& val) {
	return std::binary_search(a.begin(), a.end(), std::forward<B>(val));
}

template <class A, class B>
inline auto lower_bound(const A& a, B&& val) -> decltype(a.begin()) {
	return std::lower_bound(a.begin(), a.end(), std::forward<B>(val));
}

template <class A, class B>
inline auto upper_bound(const A& a, B&& val) -> decltype(a.begin()) {
	return std::upper_bound(a.begin(), a.end(), std::forward<B>(val));
}

template <class A>
inline void sort(A& a) {
	std::sort(a.begin(), a.end());
}

template <class A, class Func>
inline void sort(A& a, Func&& func) {
	std::sort(a.begin(), a.end(), std::forward<Func>(func));
}

template <class T>
constexpr bool is_sorted(T& collection) {
	auto b = begin(collection);
	auto e = end(collection);
	if (b == e)
		return true;

	auto prev = b;
	while (++b != e) {
		if (not std::less<>()(*prev, *b))
			return false;

		prev = b;
	}

	return true;
}

template <class A, class... Option>
constexpr bool is_one_of(A&& val, Option&&... option) {
	return ((val == option) or ...);
}

template <class...>
constexpr bool is_pair = false;

template <class A, class B>
constexpr bool is_pair<std::pair<A, B>> = true;

template <class T>
class reverse_view {
	T range_;

public:
	reverse_view(T&& range) : range_(std::forward<T>(range)) {}

	auto begin() const { return range_.rbegin(); }

	auto end() const { return range_.rend(); }
};

template <class T>
reverse_view(T &&)->reverse_view<T>;
<commit_msg>utilities.hh: fixed is_sorted()<commit_after>#pragma once

#include <algorithm>
#include <functional>

template <class T, class... Args>
T& back_insert(T& reference, Args&&... args) {
	// Allocate more space (reserve is inefficient)
	size_t old_size = reference.size();
	reference.resize(old_size + sizeof...(args));
	reference.resize(old_size);

	(reference.emplace_back(std::forward<Args>(args)), ...);
	return reference;
}

template <class T, class C>
constexpr typename T::const_iterator binary_find(const T& x, const C& val) {
	auto beg = x.begin(), end = x.end();
	while (beg != end) {
		auto mid = beg + ((end - beg) >> 1);
		if (*mid < val)
			beg = ++mid;
		else
			end = mid;
	}
	return (beg != x.end() && *beg == val ? beg : x.end());
}

template <class T, class C, class Comp>
constexpr typename T::const_iterator binary_find(const T& x, const C& val,
                                                 Comp&& comp) {
	auto beg = x.begin(), end = x.end();
	while (beg != end) {
		auto mid = beg + ((end - beg) >> 1);
		if (comp(*mid, val))
			beg = ++mid;
		else
			end = mid;
	}
	return (beg != x.end() && !comp(*beg, val) && !comp(val, *beg) ? beg
	                                                               : x.end());
}

template <class T, typename B, class C>
constexpr typename T::const_iterator
binary_find_by(const T& x, B T::value_type::*field, const C& val) {
	auto beg = x.begin(), end = x.end();
	while (beg != end) {
		auto mid = beg + ((end - beg) >> 1);
		if ((*mid).*field < val)
			beg = ++mid;
		else
			end = mid;
	}
	return (beg != x.end() && (*beg).*field == val ? beg : x.end());
}

template <class T, typename B, class C, class Comp>
constexpr typename T::const_iterator
binary_find_by(const T& x, B T::value_type::*field, const C& val, Comp&& comp) {
	auto beg = x.begin(), end = x.end();
	while (beg != end) {
		auto mid = beg + ((end - beg) >> 1);
		if (comp((*mid).*field, val))
			beg = ++mid;
		else
			end = mid;
	}
	return (beg != x.end() && (*beg).*field == val ? beg : x.end());
}

// Aliases - take container instead of range
template <class A, class B>
inline bool binary_search(const A& a, B&& val) {
	return std::binary_search(a.begin(), a.end(), std::forward<B>(val));
}

template <class A, class B>
inline auto lower_bound(const A& a, B&& val) -> decltype(a.begin()) {
	return std::lower_bound(a.begin(), a.end(), std::forward<B>(val));
}

template <class A, class B>
inline auto upper_bound(const A& a, B&& val) -> decltype(a.begin()) {
	return std::upper_bound(a.begin(), a.end(), std::forward<B>(val));
}

template <class A>
inline void sort(A& a) {
	std::sort(a.begin(), a.end());
}

template <class A, class Func>
inline void sort(A& a, Func&& func) {
	std::sort(a.begin(), a.end(), std::forward<Func>(func));
}

template <class T>
constexpr bool is_sorted(const T& collection) {
	auto b = begin(collection);
	auto e = end(collection);
	if (b == e)
		return true;

	auto prev = b;
	while (++b != e) {
		if (not std::less<>()(*prev, *b))
			return false;

		prev = b;
	}

	return true;
}

template <class A, class... Option>
constexpr bool is_one_of(A&& val, Option&&... option) {
	return ((val == option) or ...);
}

template <class...>
constexpr bool is_pair = false;

template <class A, class B>
constexpr bool is_pair<std::pair<A, B>> = true;

template <class T>
class reverse_view {
	T range_;

public:
	reverse_view(T&& range) : range_(std::forward<T>(range)) {}

	auto begin() const { return range_.rbegin(); }

	auto end() const { return range_.rend(); }
};

template <class T>
reverse_view(T &&)->reverse_view<T>;
<|endoftext|>


<commit_before>#ifndef QUEUES_H_INCLUDED
#define QUEUES_H_INCLUDED

#include <wiz/global.h>
#include <wiz/wizardError.h>
#include <wiz/newarrays.h>

/// #define QUEUES_DEBUG

namespace wiz{
class QueueEmptyError : public wiz::Error
{
public:
    QueueEmptyError() : wiz::Error( "queueEmptyError" )
    {

    }
};
class QueueFullError : public wiz::Error
{
public:
    QueueFullError() : wiz::Error( "queueFullError" )
    {

    }
};

// check array Queue, array stack?
template <typename T>
class Queue //: public wizObject
{
private:
    class Element
    {
    public:
        Element* next;
        T data;
    public:
        explicit Element( const T d = T() )
        {
            data = d;
            next =  nullptr;
        }
    };
private:
    Element* Head; //
    Element* Rear; //
public:
    explicit Queue() : Head( nullptr ), Rear( nullptr ) { Head = new Element(); Rear = Head; }

    virtual ~Queue(){
        clear();
        delete Head; Head = Rear = nullptr;
    }
    void clear()
    {
        while( !isEmpty() ){
           deleteq();
        }
     }
    bool isEmpty() const
    {
        return nullptr == Head->next; /// size == 0, empty..
    }
    bool empty() const { return isEmpty(); }
    //
    void addq( const T& p ) /// push
    {
        Element* temp = new Element(p); //
        //
        Rear->next = temp;//
        temp->next = nullptr;// auto look def of Element
        Rear = Rear->next; //
    }//
    void push( const T& p ) { addq( p ); }
    T deleteq(){ /// pop
        if( isEmpty() )
        {
            throw QueueEmptyError();
        }
        //
        Element* temp = Head->next;//
        Head->next = temp->next;
        //Rear 처리
        if( nullptr == Head->next )
            Rear = Head;
        T returnTemp = temp->data;
        delete temp;
        return returnTemp;
    }
    T pop() { return deleteq(); }
    Queue& operator<<( const T& p ){
        addq( p ); //
        return *this;
    }
private:
    void copy( const Queue<T>& q )
    {
        //this->clear();

        Element* qTemp = q.Head->next;

        while( qTemp != nullptr )
        {
            addq( qTemp->data );
            qTemp = qTemp->next;
        }
    }
public:
    //
    Queue( const Queue<T>& q ) : Head( nullptr ), Rear( nullptr )
    {// clear();
        Head = new Element(); Rear = Head;
        copy( q );
    }
    Queue& operator=( const Queue<T>& q )
    {
        if( Head == q.Head ) { return *this; }

        clear();

        // head, rear reser..!!
        copy( q );

        return *this;
    }
    Queue( Queue<T>&& q )
    {
        Head->next = q.Head->next;
        Rear = q.Rear;

        /// do-empty..
        q.Head->next = nullptr;
        q.Rear = q.Head;
    }
    Queue<T>& operator=( Queue<T>&& q )
    {
        if( Head == q.Head ) { return *this; }
        this->clear();
        Head->next = q.Head->next;
        Rear = q.Rear;

q.Head->next = nullptr;
q.Rear = q.Head;
return *this;
	}
};

// Queue using Array
template <class T>
class ArrayQueue
{
public:
	ArrayQueue(const ArrayQueue<T>& aq)
		:que(aq.que), start(aq.start), num(aq.num)
	{
		//
	}
	ArrayQueue(ArrayQueue<T>&& aq)
	{
		que = std::move(aq.que);
		start = aq.start;
		num = aq.num;

		aq.que = Array<T>(2);
		aq.start = 0;
		aq.num = 0;
	}
	ArrayQueue<T>& operator=(ArrayQueue<T>&& aq)
	{
		if (que == aq.que) { return *this; }
		this->que.DoEmpty();
		que = std::move(aq.que);
		start = aq.start;
		num = aq.num;

		aq.que = Array<T>(2);
		aq.start = 0;
		aq.num = 0;
		return *this;
	}
	ArrayQueue<T>& operator=(const ArrayQueue<T>& aq)
	{
		if (que == aq.que) { return *this; }
		que.DoEmpty();
		this->que = aq.que;
		this->start = aq.start;
		this->num = aq.num;
		return *this;
	}
private:
	Array<T> que;
	int start;
	int num;
public:
	explicit ArrayQueue(const int max = 2) : start(0), num(0)
	{
#ifdef QUEUES_DEBUG
		// max > 0
		wiz::checkUnderError(0, max, 1);
#endif
		que = Array<T>(max);
	}
	virtual ~ArrayQueue()
	{
	}
public:
	const T& operator[](const int idx) const
	{
		return que[(start + idx) & (que.size() - 1)];
	}
	T& operator[](const int idx)
	{
		return que[(start + idx) & (que.size() - 1)];
	}
public:
	void push(const ArrayQueue<T>& val) {
		if (val.empty()) { return; }
		int newSize = this->que.size();

		while (newSize - num < val.size()) {
			newSize = newSize * 2;
		}
		if (newSize != this->que.size()) {
			// expand array queue.
			ArrayQueue<T> temp(newSize);
			temp.start = 0;
			//
			for (int i = 0; i < this->size(); ++i) {
				temp[i] = std::move((*this)[i]);
			}

			const int iend = val.num;
			for (int i = 0; i < iend; ++i) {
				temp[i + this->num] = val[i];
			}

			temp.num = this->num + val.num;
			*this = std::move(temp);
		}
		else {
			for (int i = 0; i < val.size(); ++i) {
				this->push(val.que[i]);
			}
		}
	}
	void push(ArrayQueue<T>&& val) { // chk..
		if (val.empty()) { return; }
		int newSize = this->que.size();

		while (newSize - num < val.size()) {
			newSize = newSize * 2;
		}
		if (newSize != this->que.size()) {
			// expand array queue.
			ArrayQueue temp(newSize);
			temp.start = 0;
			//
			for (int i = 0; i < this->size(); ++i) {
				temp[i] = std::move((*this)[i]);
			}

			const int iend = val.num;
			for (int i = 0; i < iend; ++i) {
				temp[i + this->num] = std::move(val[i]);
			}

			temp.num = this->num + val.num;
			*this = std::move(temp);
		}
		else {
			for (int i = 0; i < val.size(); ++i) {
				this->push(std::move(val[i]));
			}
		}
	}
    void push( const T& val )
    {
        if( isFull() )
        {
            // expand array queue.
            ArrayQueue temp( que.size() * 2 );
            //
			for (int i = 0; i < que.size(); ++i) {
				temp[i] = std::move(que[(start + i) & (que.size()-1)]);
			}
			temp.start = 0;
			temp.num = que.size();

            *this = std::move( temp );
        }
        que[(start+num) & (que.size()-1)] = val;
        num++;
    }

	void push(T&& val)
	{
		if (isFull())
		{
			// expand array queue.
			ArrayQueue temp(que.size() * 2);
			//
			for (int i = 0; i < que.size(); ++i) {
				temp[i] = std::move(que[(start + i) & (que.size()-1)]);
			}
			temp.start = 0;
			temp.num = que.size();

			*this = std::move(temp);
		}
		que[(start + num) & (que.size()-1)] = std::move(val);
		num++;
	}

	void pop(T* t = nullptr) {
		if (isEmpty()) { throw QueueEmptyError(); }

		T temp = std::move(que[start]);

		//que[start] = T();

		start = (start + 1) & (que.size() - 1); // % que.size(), 2^n.
		num--;

		if (nullptr != t) {
			*t = move(temp);
		}
	}

	T pop_back()
	{
		if (isEmpty()) { throw QueueEmptyError(); }
		T temp = std::move((*this)[num - 1]);

		//(*this)[num - 1] = T();

		num--;

		return temp;
	}

    bool isFull()const
    {
        return num >= ( que.size() );
    }

    bool isEmpty()const
    {
        return 0 == num;
    }
    int size()const{ return num; }
    bool empty()const { return isEmpty(); }
    int getNumMax()const { return que.size(); }
    int getNum()const { return num; }
    Array<T> toArray()const
    {
        Array<T> temp;

        if( num > 0 )
        {
            temp = Array<T>( num );
            int count=0;

            for( int i=0; i < num; i++ )
            {
                temp[i] = que[ ( start + i ) % (que.size()) ];
            }
        }

        return temp;
    }

    ArrayQueue<T>& operator<<( const T& data )
    {
        push( data );

        return *this;
    }
};

}
#endif // QUEUES_H_INCLUDED
<commit_msg>Delete QUEUES.H<commit_after><|endoftext|>