<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/image_transport_factory_android.h"

#include "base/memory/singleton.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"

namespace content {

namespace {

using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;

static ImageTransportFactoryAndroid* g_factory = NULL;

class DirectGLImageTransportFactory : public ImageTransportFactoryAndroid {
 public:
  DirectGLImageTransportFactory();
  virtual ~DirectGLImageTransportFactory();

  virtual uint32_t InsertSyncPoint() OVERRIDE { return 0; }
  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE {}
  virtual uint32_t CreateTexture() OVERRIDE {
    return context_->createTexture();
  }
  virtual void DeleteTexture(uint32_t id) OVERRIDE {
    context_->deleteTexture(id);
  }
  virtual void AcquireTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE {}
  virtual void ReleaseTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE {}
  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
    return context_.get();
  }
  virtual GLHelper* GetGLHelper() OVERRIDE { return NULL; }

 private:
  scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context_;

  DISALLOW_COPY_AND_ASSIGN(DirectGLImageTransportFactory);
};

DirectGLImageTransportFactory::DirectGLImageTransportFactory() {
  WebKit::WebGraphicsContext3D::Attributes attrs;
  attrs.shareResources = true;
  attrs.noAutomaticFlushes = true;
  context_.reset(webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl::
                     CreateViewContext(attrs, NULL));
}

DirectGLImageTransportFactory::~DirectGLImageTransportFactory() {
}

class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
 public:
  CmdBufferImageTransportFactory();
  virtual ~CmdBufferImageTransportFactory();

  virtual uint32_t InsertSyncPoint() OVERRIDE;
  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE;
  virtual uint32_t CreateTexture() OVERRIDE;
  virtual void DeleteTexture(uint32_t id) OVERRIDE;
  virtual void AcquireTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE;
  virtual void ReleaseTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE;
  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
    return context_.get();
  }
  virtual GLHelper* GetGLHelper() OVERRIDE;

 private:
  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
  scoped_ptr<GLHelper> gl_helper_;

  DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory);
};

CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
  WebKit::WebGraphicsContext3D::Attributes attrs;
  attrs.shareResources = true;
  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
  GURL url("chrome://gpu/ImageTransportFactoryAndroid");
  base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
  context_.reset(new WebGraphicsContext3DCommandBufferImpl(0, // offscreen
                                                           url,
                                                           factory,
                                                           swap_client));
  context_->InitializeWithDefaultBufferSizes(
      attrs,
      false,
      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE);
}

CmdBufferImageTransportFactory::~CmdBufferImageTransportFactory() {
}

uint32_t CmdBufferImageTransportFactory::InsertSyncPoint() {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return 0;
  }
  return context_->insertSyncPoint();
}

void CmdBufferImageTransportFactory::WaitSyncPoint(uint32_t sync_point) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->waitSyncPoint(sync_point);
}

uint32_t CmdBufferImageTransportFactory::CreateTexture() {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return false;
  }
  return context_->createTexture();
}

void CmdBufferImageTransportFactory::DeleteTexture(uint32_t id) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->deleteTexture(id);
}

void CmdBufferImageTransportFactory::AcquireTexture(
    uint32 texture_id, const signed char* mailbox_name) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->bindTexture(GL_TEXTURE_2D, texture_id);
  context_->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox_name);
  context_->flush();
}

void CmdBufferImageTransportFactory::ReleaseTexture(
    uint32 texture_id, const signed char* mailbox_name) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->bindTexture(GL_TEXTURE_2D, texture_id);
  context_->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox_name);
}

GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
  if (!gl_helper_)
    gl_helper_.reset(new GLHelper(context_.get()));

  return gl_helper_.get();
}

}  // anonymous namespace

// static
ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
  if (!g_factory) {
    if (CompositorImpl::UsesDirectGL())
      g_factory = new DirectGLImageTransportFactory();
    else
      g_factory = new CmdBufferImageTransportFactory();
  }

  return g_factory;
}

ImageTransportFactoryAndroid::ImageTransportFactoryAndroid() {
}

ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {
}

} // namespace content
<commit_msg>gpu: Label some more contexts<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/image_transport_factory_android.h"

#include "base/memory/singleton.h"
#include "base/strings/stringprintf.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"

namespace content {

namespace {

using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;

static ImageTransportFactoryAndroid* g_factory = NULL;

class DirectGLImageTransportFactory : public ImageTransportFactoryAndroid {
 public:
  DirectGLImageTransportFactory();
  virtual ~DirectGLImageTransportFactory();

  virtual uint32_t InsertSyncPoint() OVERRIDE { return 0; }
  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE {}
  virtual uint32_t CreateTexture() OVERRIDE {
    return context_->createTexture();
  }
  virtual void DeleteTexture(uint32_t id) OVERRIDE {
    context_->deleteTexture(id);
  }
  virtual void AcquireTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE {}
  virtual void ReleaseTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE {}
  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
    return context_.get();
  }
  virtual GLHelper* GetGLHelper() OVERRIDE { return NULL; }

 private:
  scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context_;

  DISALLOW_COPY_AND_ASSIGN(DirectGLImageTransportFactory);
};

DirectGLImageTransportFactory::DirectGLImageTransportFactory() {
  WebKit::WebGraphicsContext3D::Attributes attrs;
  attrs.shareResources = true;
  attrs.noAutomaticFlushes = true;
  context_.reset(webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl::
                     CreateViewContext(attrs, NULL));
  if (context_->makeContextCurrent())
    context_->pushGroupMarkerEXT(
        base::StringPrintf("DirectGLImageTransportFactory-%p", this).c_str());
}

DirectGLImageTransportFactory::~DirectGLImageTransportFactory() {
}

class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
 public:
  CmdBufferImageTransportFactory();
  virtual ~CmdBufferImageTransportFactory();

  virtual uint32_t InsertSyncPoint() OVERRIDE;
  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE;
  virtual uint32_t CreateTexture() OVERRIDE;
  virtual void DeleteTexture(uint32_t id) OVERRIDE;
  virtual void AcquireTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE;
  virtual void ReleaseTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE;
  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
    return context_.get();
  }
  virtual GLHelper* GetGLHelper() OVERRIDE;

 private:
  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
  scoped_ptr<GLHelper> gl_helper_;

  DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory);
};

CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
  WebKit::WebGraphicsContext3D::Attributes attrs;
  attrs.shareResources = true;
  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
  GURL url("chrome://gpu/ImageTransportFactoryAndroid");
  base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
  context_.reset(new WebGraphicsContext3DCommandBufferImpl(0, // offscreen
                                                           url,
                                                           factory,
                                                           swap_client));
  context_->InitializeWithDefaultBufferSizes(
      attrs,
      false,
      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE);

  if (context_->makeContextCurrent())
    context_->pushGroupMarkerEXT(
        base::StringPrintf("CmdBufferImageTransportFactory-%p", this).c_str());
}

CmdBufferImageTransportFactory::~CmdBufferImageTransportFactory() {
}

uint32_t CmdBufferImageTransportFactory::InsertSyncPoint() {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return 0;
  }
  return context_->insertSyncPoint();
}

void CmdBufferImageTransportFactory::WaitSyncPoint(uint32_t sync_point) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->waitSyncPoint(sync_point);
}

uint32_t CmdBufferImageTransportFactory::CreateTexture() {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return false;
  }
  return context_->createTexture();
}

void CmdBufferImageTransportFactory::DeleteTexture(uint32_t id) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->deleteTexture(id);
}

void CmdBufferImageTransportFactory::AcquireTexture(
    uint32 texture_id, const signed char* mailbox_name) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->bindTexture(GL_TEXTURE_2D, texture_id);
  context_->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox_name);
  context_->flush();
}

void CmdBufferImageTransportFactory::ReleaseTexture(
    uint32 texture_id, const signed char* mailbox_name) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->bindTexture(GL_TEXTURE_2D, texture_id);
  context_->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox_name);
}

GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
  if (!gl_helper_)
    gl_helper_.reset(new GLHelper(context_.get()));

  return gl_helper_.get();
}

}  // anonymous namespace

// static
ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
  if (!g_factory) {
    if (CompositorImpl::UsesDirectGL())
      g_factory = new DirectGLImageTransportFactory();
    else
      g_factory = new CmdBufferImageTransportFactory();
  }

  return g_factory;
}

ImageTransportFactoryAndroid::ImageTransportFactoryAndroid() {
}

ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {
}

} // namespace content
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qt5rendernodeinstanceserver.h"

#include <QQuickItem>
#include <QQuickView>

#include "servernodeinstance.h"
#include "childrenchangeeventfilter.h"
#include "propertyabstractcontainer.h"
#include "propertybindingcontainer.h"
#include "propertyvaluecontainer.h"
#include "instancecontainer.h"
#include "createinstancescommand.h"
#include "changefileurlcommand.h"
#include "clearscenecommand.h"
#include "reparentinstancescommand.h"
#include "changevaluescommand.h"
#include "changebindingscommand.h"
#include "changeidscommand.h"
#include "removeinstancescommand.h"
#include "nodeinstanceclientinterface.h"
#include "removepropertiescommand.h"
#include "valueschangedcommand.h"
#include "informationchangedcommand.h"
#include "pixmapchangedcommand.h"
#include "commondefines.h"
#include "changestatecommand.h"
#include "childrenchangedcommand.h"
#include "completecomponentcommand.h"
#include "componentcompletedcommand.h"
#include "createscenecommand.h"
#include "quickitemnodeinstance.h"
#include "removesharedmemorycommand.h"

#include "dummycontextobject.h"

#include <designersupport.h>

namespace QmlDesigner {

Qt5RenderNodeInstanceServer::Qt5RenderNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
    Qt5NodeInstanceServer(nodeInstanceClient)
{
    Internal::QuickItemNodeInstance::createEffectItem(true);
}

void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
    static bool inFunction = false;
    if (!inFunction) {
        inFunction = true;

        DesignerSupport::polishItems(quickView());

        if (quickView() && nodeInstanceClient()->bytesToWrite() < 10000) {
            foreach (QQuickItem *item, allItems()) {
                if (item) {
                    if (hasInstanceForObject(item)
                            && DesignerSupport::isDirty(item, DesignerSupport::ContentUpdateMask)) {
                        m_dirtyInstanceSet.insert(instanceForObject(item));
                    } else if (DesignerSupport::isDirty(item, DesignerSupport::AllMask)) {
                        ServerNodeInstance ancestorInstance = findNodeInstanceForItem(item->parentItem());
                        if (ancestorInstance.isValid())
                            m_dirtyInstanceSet.insert(ancestorInstance);
                    }
                    DesignerSupport::updateDirtyNode(item);
                }
            }

            clearChangedPropertyList();

            if (!m_dirtyInstanceSet.isEmpty()) {
                nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(m_dirtyInstanceSet.toList()));
                m_dirtyInstanceSet.clear();
            }

            resetAllItems();

            slowDownRenderTimer();
            nodeInstanceClient()->flush();
            nodeInstanceClient()->synchronizeWithClientProcess();
        }

        inFunction = false;
    }
}

ServerNodeInstance Qt5RenderNodeInstanceServer::findNodeInstanceForItem(QQuickItem *item) const
{
    if (item) {
        if (hasInstanceForObject(item))
            return instanceForObject(item);
        else if (item->parentItem())
            return findNodeInstanceForItem(item->parentItem());
    }

    return ServerNodeInstance();
}

void Qt5RenderNodeInstanceServer::createScene(const CreateSceneCommand &command)
{
    Qt5NodeInstanceServer::createScene(command);

    QList<ServerNodeInstance> instanceList;
    foreach (const InstanceContainer &container, command.instances()) {
        ServerNodeInstance instance = instanceForId(container.instanceId());
        if (instance.isValid()) {
            instanceList.append(instance);
        }
    }

    nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList));
}

void Qt5RenderNodeInstanceServer::clearScene(const ClearSceneCommand &command)
{
    Qt5NodeInstanceServer::clearScene(command);

    m_dirtyInstanceSet.clear();
}

void Qt5RenderNodeInstanceServer::completeComponent(const CompleteComponentCommand &command)
{
    Qt5NodeInstanceServer::completeComponent(command);

    QList<ServerNodeInstance> instanceList;
    foreach (qint32 instanceId, command.instances()) {
        ServerNodeInstance instance = instanceForId(instanceId);
        if (instance.isValid()) {
            instanceList.append(instance);
            m_dirtyInstanceSet.insert(instance);
        }
    }

    nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList));
}

void QmlDesigner::Qt5RenderNodeInstanceServer::removeSharedMemory(const QmlDesigner::RemoveSharedMemoryCommand &command)
{
    if (command.typeName() == "Image")
        ImageContainer::removeSharedMemorys(command.keyNumbers());
}

} // namespace QmlDesigner
<commit_msg>QmlDesigner: Fix rendering rendering of items<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qt5rendernodeinstanceserver.h"

#include <QQuickItem>
#include <QQuickView>

#include "servernodeinstance.h"
#include "childrenchangeeventfilter.h"
#include "propertyabstractcontainer.h"
#include "propertybindingcontainer.h"
#include "propertyvaluecontainer.h"
#include "instancecontainer.h"
#include "createinstancescommand.h"
#include "changefileurlcommand.h"
#include "clearscenecommand.h"
#include "reparentinstancescommand.h"
#include "changevaluescommand.h"
#include "changebindingscommand.h"
#include "changeidscommand.h"
#include "removeinstancescommand.h"
#include "nodeinstanceclientinterface.h"
#include "removepropertiescommand.h"
#include "valueschangedcommand.h"
#include "informationchangedcommand.h"
#include "pixmapchangedcommand.h"
#include "commondefines.h"
#include "changestatecommand.h"
#include "childrenchangedcommand.h"
#include "completecomponentcommand.h"
#include "componentcompletedcommand.h"
#include "createscenecommand.h"
#include "quickitemnodeinstance.h"
#include "removesharedmemorycommand.h"

#include "dummycontextobject.h"

#include <designersupport.h>

namespace QmlDesigner {

Qt5RenderNodeInstanceServer::Qt5RenderNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
    Qt5NodeInstanceServer(nodeInstanceClient)
{
    Internal::QuickItemNodeInstance::createEffectItem(true);
}

void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
    static bool inFunction = false;
    if (!inFunction) {
        inFunction = true;

        DesignerSupport::polishItems(quickView());

        if (quickView() && nodeInstanceClient()->bytesToWrite() < 10000) {
            foreach (QQuickItem *item, allItems()) {
                if (item) {
                    if (hasInstanceForObject(item)) {
                            if (DesignerSupport::isDirty(item, DesignerSupport::ContentUpdateMask))
                                m_dirtyInstanceSet.insert(instanceForObject(item));
                    } else if (DesignerSupport::isDirty(item, DesignerSupport::AllMask)) {
                        ServerNodeInstance ancestorInstance = findNodeInstanceForItem(item->parentItem());
                        if (ancestorInstance.isValid())
                            m_dirtyInstanceSet.insert(ancestorInstance);
                    }
                    DesignerSupport::updateDirtyNode(item);
                }
            }

            clearChangedPropertyList();

            if (!m_dirtyInstanceSet.isEmpty()) {
                nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(m_dirtyInstanceSet.toList()));
                m_dirtyInstanceSet.clear();
            }

            resetAllItems();

            slowDownRenderTimer();
            nodeInstanceClient()->flush();
            nodeInstanceClient()->synchronizeWithClientProcess();
        }

        inFunction = false;
    }
}

ServerNodeInstance Qt5RenderNodeInstanceServer::findNodeInstanceForItem(QQuickItem *item) const
{
    if (item) {
        if (hasInstanceForObject(item))
            return instanceForObject(item);
        else if (item->parentItem())
            return findNodeInstanceForItem(item->parentItem());
    }

    return ServerNodeInstance();
}

void Qt5RenderNodeInstanceServer::createScene(const CreateSceneCommand &command)
{
    Qt5NodeInstanceServer::createScene(command);

    QList<ServerNodeInstance> instanceList;
    foreach (const InstanceContainer &container, command.instances()) {
        ServerNodeInstance instance = instanceForId(container.instanceId());
        if (instance.isValid()) {
            instanceList.append(instance);
        }
    }

    nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList));
}

void Qt5RenderNodeInstanceServer::clearScene(const ClearSceneCommand &command)
{
    Qt5NodeInstanceServer::clearScene(command);

    m_dirtyInstanceSet.clear();
}

void Qt5RenderNodeInstanceServer::completeComponent(const CompleteComponentCommand &command)
{
    Qt5NodeInstanceServer::completeComponent(command);

    QList<ServerNodeInstance> instanceList;
    foreach (qint32 instanceId, command.instances()) {
        ServerNodeInstance instance = instanceForId(instanceId);
        if (instance.isValid()) {
            instanceList.append(instance);
            m_dirtyInstanceSet.insert(instance);
        }
    }

    nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList));
}

void QmlDesigner::Qt5RenderNodeInstanceServer::removeSharedMemory(const QmlDesigner::RemoveSharedMemoryCommand &command)
{
    if (command.typeName() == "Image")
        ImageContainer::removeSharedMemorys(command.keyNumbers());
}

} // namespace QmlDesigner
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/glue/image_decoder.h"

#pragma warning(push, 0)
#include "ImageSourceSkia.h"
#include "IntSize.h"
#include "RefPtr.h"
#include "SharedBuffer.h"
#pragma warning(pop)

#include "SkBitmap.h"

namespace webkit_glue {

ImageDecoder::ImageDecoder() : desired_icon_size_(0, 0) {
}

ImageDecoder::ImageDecoder(const gfx::Size& desired_icon_size)
    : desired_icon_size_(desired_icon_size) {
}

ImageDecoder::~ImageDecoder() {
}

SkBitmap ImageDecoder::Decode(const unsigned char* data, size_t size) {
  WebCore::ImageSourceSkia source;
  WTF::RefPtr<WebCore::SharedBuffer> buffer(new WebCore::SharedBuffer(
      data, static_cast<int>(size)));
  source.setData(buffer.get(), true,
                 WebCore::IntSize(desired_icon_size_.width(),
                                  desired_icon_size_.height()));

  if (!source.isSizeAvailable())
    return SkBitmap();

  WebCore::NativeImagePtr frame0 = source.createFrameAtIndex(0);
  if (!frame0)
    return SkBitmap();

  return *reinterpret_cast<SkBitmap*>(frame0);
}

}  // namespace webkit_glue

<commit_msg>include config.h first otherwise bad things happen<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"
#include "webkit/glue/image_decoder.h"

#pragma warning(push, 0)
#include "ImageSourceSkia.h"
#include "IntSize.h"
#include "RefPtr.h"
#include "SharedBuffer.h"
#pragma warning(pop)

#include "SkBitmap.h"

namespace webkit_glue {

ImageDecoder::ImageDecoder() : desired_icon_size_(0, 0) {
}

ImageDecoder::ImageDecoder(const gfx::Size& desired_icon_size)
    : desired_icon_size_(desired_icon_size) {
}

ImageDecoder::~ImageDecoder() {
}

SkBitmap ImageDecoder::Decode(const unsigned char* data, size_t size) {
  WebCore::ImageSourceSkia source;
  WTF::RefPtr<WebCore::SharedBuffer> buffer(new WebCore::SharedBuffer(
      data, static_cast<int>(size)));
  source.setData(buffer.get(), true,
                 WebCore::IntSize(desired_icon_size_.width(),
                                  desired_icon_size_.height()));

  if (!source.isSizeAvailable())
    return SkBitmap();

  WebCore::NativeImagePtr frame0 = source.createFrameAtIndex(0);
  if (!frame0)
    return SkBitmap();

  return *reinterpret_cast<SkBitmap*>(frame0);
}

}  // namespace webkit_glue

<|endoftext|>


<commit_before>//
//  FirebaseRemoteConfig.cpp
//  ee_x
//
//  Created by Zinge on 5/9/17.
//
//

#include "ee/firebase_remote_config/internal/FirebaseRemoteConfigBridge.hpp"

#include <ee/core/IMessageBridge.hpp>
#include <ee/core/Task.hpp>
#include <ee/core/Utils.hpp>
#include <ee/core/internal/JsonUtils.hpp>
#include <ee/nlohmann/json.hpp>

#include "ee/firebase_remote_config/FirebaseFetchStatus.hpp"

namespace ee {
namespace firebase {
namespace remote_config {
namespace {
const std::string kPrefix = "FirebaseRemoteConfigBridge";
const std::string kInitialize = kPrefix + "Initialize";
const std::string kSetSettings = kPrefix + "SetSettings";
const std::string kFetch = kPrefix + "Fetch";
const std::string kActivate = kPrefix + "Activate";
const std::string kSetDefaults = kPrefix + "SetDefaults";
const std::string kGetBool = kPrefix + "GetBool";
const std::string kGetLong = kPrefix + "GetLong";
const std::string kGetDouble = kPrefix + "GetDouble";
const std::string kGetString = kPrefix + "GetString";
} // namespace

using Self = Bridge;

Self::Bridge(IMessageBridge& bridge, ILogger& logger,
             const Destroyer& destroyer)
    : bridge_(bridge)
    , logger_(logger)
    , destroyer_(destroyer) {}

Self::~Bridge() = default;

void Self::destroy() {
    destroyer_();
}

Task<bool> Self::initialize() {
    auto response = co_await bridge_.callAsync(kInitialize);
    co_return core::toBool(response);
}

Task<> Self::setSettings(std::int64_t fetchTimeOut,
                         std::int64_t fetchInterval) {
    nlohmann::json request;
    request["fetchTimeOut"] = fetchTimeOut;
    request["fetchInterval"] = fetchInterval;
    co_await bridge_.callAsync(kSetSettings, request.dump());
}

Task<FetchStatus> Self::fetch(std::int64_t fetchInterval) {
    nlohmann::json request;
    request["fetchInterval"] = fetchTimeOut;
    auto response = co_await bridge_.callAsync(kFetch, request.dump());
    co_return static_cast<FetchStatus>(std::stoi(response));
}

Task<bool> Self::activate() {
    auto response = co_await bridge_.callAsync(kActivate);
    co_return core::toBool(response);
}

Task<> Self::setDefaults(
    const std::unordered_map<
        std::string, std::variant<bool, std::int64_t, double, std::string>>&
        defaults) {
    nlohmann::json request;
    request["defaults"] = defaults;
    co_await bridge_.callAsync(kSetDefaults, request.dump());
}

bool Self::getBool(const std::string& key) {
    auto response = bridge_.call(kGetBool, key);
    return core::toBool(response);
}

std::int64_t Self::getLong(const std::string& key) {
    auto response = bridge_.call(kGetLong, key);
    return std::stoll(response);
}

double Self::getDouble(const std::string& key) {
    auto response =  bridge_.call(kGetDouble, key);
    return std::stod(response);
}

std::string Self::getString(const std::string& key) {
    auto response = bridge_.call(kGetString, key);
    return response;
}
} // namespace remote_config
} // namespace firebase
} // namespace ee
<commit_msg>Fix typo.<commit_after>//
//  FirebaseRemoteConfig.cpp
//  ee_x
//
//  Created by Zinge on 5/9/17.
//
//

#include "ee/firebase_remote_config/internal/FirebaseRemoteConfigBridge.hpp"

#include <ee/core/IMessageBridge.hpp>
#include <ee/core/Task.hpp>
#include <ee/core/Utils.hpp>
#include <ee/core/internal/JsonUtils.hpp>
#include <ee/nlohmann/json.hpp>

#include "ee/firebase_remote_config/FirebaseFetchStatus.hpp"

namespace ee {
namespace firebase {
namespace remote_config {
namespace {
const std::string kPrefix = "FirebaseRemoteConfigBridge";
const std::string kInitialize = kPrefix + "Initialize";
const std::string kSetSettings = kPrefix + "SetSettings";
const std::string kFetch = kPrefix + "Fetch";
const std::string kActivate = kPrefix + "Activate";
const std::string kSetDefaults = kPrefix + "SetDefaults";
const std::string kGetBool = kPrefix + "GetBool";
const std::string kGetLong = kPrefix + "GetLong";
const std::string kGetDouble = kPrefix + "GetDouble";
const std::string kGetString = kPrefix + "GetString";
} // namespace

using Self = Bridge;

Self::Bridge(IMessageBridge& bridge, ILogger& logger,
             const Destroyer& destroyer)
    : bridge_(bridge)
    , logger_(logger)
    , destroyer_(destroyer) {}

Self::~Bridge() = default;

void Self::destroy() {
    destroyer_();
}

Task<bool> Self::initialize() {
    auto response = co_await bridge_.callAsync(kInitialize);
    co_return core::toBool(response);
}

Task<> Self::setSettings(std::int64_t fetchTimeOut,
                         std::int64_t fetchInterval) {
    nlohmann::json request;
    request["fetchTimeOut"] = fetchTimeOut;
    request["fetchInterval"] = fetchInterval;
    co_await bridge_.callAsync(kSetSettings, request.dump());
}

Task<FetchStatus> Self::fetch(std::int64_t fetchInterval) {
    nlohmann::json request;
    request["fetchInterval"] = fetchInterval;
    auto response = co_await bridge_.callAsync(kFetch, request.dump());
    co_return static_cast<FetchStatus>(std::stoi(response));
}

Task<bool> Self::activate() {
    auto response = co_await bridge_.callAsync(kActivate);
    co_return core::toBool(response);
}

Task<> Self::setDefaults(
    const std::unordered_map<
        std::string, std::variant<bool, std::int64_t, double, std::string>>&
        defaults) {
    nlohmann::json request;
    request["defaults"] = defaults;
    co_await bridge_.callAsync(kSetDefaults, request.dump());
}

bool Self::getBool(const std::string& key) {
    auto response = bridge_.call(kGetBool, key);
    return core::toBool(response);
}

std::int64_t Self::getLong(const std::string& key) {
    auto response = bridge_.call(kGetLong, key);
    return std::stoll(response);
}

double Self::getDouble(const std::string& key) {
    auto response =  bridge_.call(kGetDouble, key);
    return std::stod(response);
}

std::string Self::getString(const std::string& key) {
    auto response = bridge_.call(kGetString, key);
    return response;
}
} // namespace remote_config
} // namespace firebase
} // namespace ee
<|endoftext|>


<commit_before>#include "Duet.hpp"
#include "PrintHostSendDialog.hpp"

#include <algorithm>
#include <ctime>
#include <boost/filesystem/path.hpp>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <wx/frame.h>
#include <wx/event.h>
#include <wx/progdlg.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/checkbox.h>

#include "libslic3r/PrintConfig.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/MsgDialog.hpp"
#include "Http.hpp"

namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

namespace Slic3r {

Duet::Duet(DynamicPrintConfig *config) :
	host(config->opt_string("print_host")),
	password(config->opt_string("printhost_apikey"))
{}

Duet::~Duet() {}

bool Duet::test(wxString &msg) const
{
	bool connected = connect(msg);
	if (connected) {
		disconnect();
	}

	return connected;
}

wxString Duet::get_test_ok_msg () const
{
	return wxString::Format("%s", _(L("Connection to Duet works correctly.")));
}

wxString Duet::get_test_failed_msg (wxString &msg) const
{
	return wxString::Format("%s: %s", _(L("Could not connect to Duet")), msg);
}

bool Duet::send_gcode(const std::string &filename) const
{
	enum { PROGRESS_RANGE = 1000 };

	const auto errortitle = _(L("Error while uploading to the Duet"));
	fs::path filepath(filename);

	PrintHostSendDialog send_dialog(filepath.filename(), true);
	if (send_dialog.ShowModal() != wxID_OK) { return false; }

	const bool print = send_dialog.print();
	const auto upload_filepath = send_dialog.filename();
	const auto upload_filename = upload_filepath.filename();
	const auto upload_parent_path = upload_filepath.parent_path();

	wxProgressDialog progress_dialog(
	 	_(L("Duet upload")),
	 	_(L("Sending G-code file to Duet...")),
		PROGRESS_RANGE, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
	progress_dialog.Pulse();

	wxString connect_msg;
	if (!connect(connect_msg)) {
		auto errormsg = wxString::Format("%s: %s", errortitle, connect_msg);
		GUI::show_error(&progress_dialog, std::move(errormsg));
		return false;
	}

	bool res = true;

	auto upload_cmd = get_upload_url(upload_filepath.string());
	BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filename: %2%, path: %3%, print: %4%, command: %5%")
		% filepath.string()
		% upload_filename.string()
		% upload_parent_path.string()
		% print
		% upload_cmd;

	auto http = Http::post(std::move(upload_cmd));
	http.set_post_body(filename)
		.on_complete([&](std::string body, unsigned status) {
			BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body;
			progress_dialog.Update(PROGRESS_RANGE);

			int err_code = get_err_code_from_body(body);
			if (err_code != 0) {
				auto msg = format_error(body, L("Unknown error occured"), 0);
				GUI::show_error(&progress_dialog, std::move(msg));
				res = false;
			} else if (print) {
				wxString errormsg;
				res = start_print(errormsg, upload_filepath.string());
				if (!res) {
					GUI::show_error(&progress_dialog, std::move(errormsg));
				}
			}
		})
		.on_error([&](std::string body, std::string error, unsigned status) {
			BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body;
			auto errormsg = wxString::Format("%s: %s", errortitle, format_error(body, error, status));
			GUI::show_error(&progress_dialog, std::move(errormsg));
			res = false;
		})
		.on_progress([&](Http::Progress progress, bool &cancel) {
			if (cancel) {
				// Upload was canceled
				res = false;
			} else if (progress.ultotal > 0) {
				int value = PROGRESS_RANGE * progress.ulnow / progress.ultotal;
				cancel = !progress_dialog.Update(std::min(value, PROGRESS_RANGE - 1));    // Cap the value to prevent premature dialog closing
			} else {
				cancel = !progress_dialog.Pulse();
			}
		})
		.perform_sync();

	disconnect();

	return res;
}

bool Duet::has_auto_discovery() const
{
	return false;
}

bool Duet::can_test() const
{
	return true;
}

bool Duet::connect(wxString &msg) const
{
	bool res = false;
	auto url = get_connect_url();

	auto http = Http::get(std::move(url));
	http.on_error([&](std::string body, std::string error, unsigned status) {
			BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error connecting: %1%, HTTP %2%, body: `%3%`") % error % status % body;
			msg = format_error(body, error, status);
		})
		.on_complete([&](std::string body, unsigned) {
			BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body;

			int err_code = get_err_code_from_body(body);
			switch (err_code) {
				case 0:
					res = true;
					break;
				case 1:
					msg = format_error(body, L("Wrong password"), 0);
					break;
				case 2:
					msg = format_error(body, L("Could not get resources to create a new connection"), 0);
					break;
				default:
					msg = format_error(body, L("Unknown error occured"), 0);
					break;
			}

		})
		.perform_sync();

	return res;
}

void Duet::disconnect() const
{
	auto url =  (boost::format("%1%rr_disconnect")
			% get_base_url()).str();

	auto http = Http::get(std::move(url));
	http.on_error([&](std::string body, std::string error, unsigned status) {
		// we don't care about it, if disconnect is not working Duet will disconnect automatically after some time
		BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error disconnecting: %1%, HTTP %2%, body: `%3%`") % error % status % body;
	})
	.perform_sync();
}

std::string Duet::get_upload_url(const std::string &filename) const
{
	return (boost::format("%1%rr_upload?name=0:/gcodes/%2%&%3%")
			% get_base_url()
			% filename
			% timestamp_str()).str();
}

std::string Duet::get_connect_url() const
{
	return (boost::format("%1%rr_connect?password=%2%&%3%")
			% get_base_url()
			% (password.empty() ? "reprap" : password)
			% timestamp_str()).str();
}

std::string Duet::get_base_url() const
{
	if (host.find("http://") == 0 || host.find("https://") == 0) {
		if (host.back() == '/') {
			return host;
		} else {
			return (boost::format("%1%/") % host).str();
		}
	} else {
		return (boost::format("http://%1%/") % host).str();
	}
}

std::string Duet::timestamp_str() const
{
	enum { BUFFER_SIZE = 32 };

	auto t = std::time(nullptr);
	auto tm = *std::localtime(&t);

	char buffer[BUFFER_SIZE];
	std::strftime(buffer, BUFFER_SIZE, "time=%Y-%d-%mT%H:%M:%S", &tm);

	return std::string(buffer);
}

wxString Duet::format_error(const std::string &body, const std::string &error, unsigned status)
{
	if (status != 0) {
		auto wxbody = wxString::FromUTF8(body.data());
		return wxString::Format("HTTP %u: %s", status, wxbody);
	} else {
		return wxString::FromUTF8(error.data());
	}
}

bool Duet::start_print(wxString &msg, const std::string &filename) const
{
	bool res = false;
	auto url = (boost::format("%1%rr_gcode?gcode=M32%%20\"%2%\"")
			% get_base_url()
			% filename).str();

	auto http = Http::get(std::move(url));
	http.on_error([&](std::string body, std::string error, unsigned status) {
			BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error starting print: %1%, HTTP %2%, body: `%3%`") % error % status % body;
			msg = format_error(body, error, status);
		})
		.on_complete([&](std::string body, unsigned) {
			BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body;
			res = true;
		})
		.perform_sync();

	return res;
}

int Duet::get_err_code_from_body(const std::string &body) const
{
	pt::ptree root;
	std::istringstream iss (body); // wrap returned json to istringstream
	pt::read_json(iss, root);

	return root.get<int>("err", 0);
}

}
<commit_msg>fixes date for uploaded files<commit_after>#include "Duet.hpp"
#include "PrintHostSendDialog.hpp"

#include <algorithm>
#include <ctime>
#include <boost/filesystem/path.hpp>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <wx/frame.h>
#include <wx/event.h>
#include <wx/progdlg.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/checkbox.h>

#include "libslic3r/PrintConfig.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/MsgDialog.hpp"
#include "Http.hpp"

namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

namespace Slic3r {

Duet::Duet(DynamicPrintConfig *config) :
	host(config->opt_string("print_host")),
	password(config->opt_string("printhost_apikey"))
{}

Duet::~Duet() {}

bool Duet::test(wxString &msg) const
{
	bool connected = connect(msg);
	if (connected) {
		disconnect();
	}

	return connected;
}

wxString Duet::get_test_ok_msg () const
{
	return wxString::Format("%s", _(L("Connection to Duet works correctly.")));
}

wxString Duet::get_test_failed_msg (wxString &msg) const
{
	return wxString::Format("%s: %s", _(L("Could not connect to Duet")), msg);
}

bool Duet::send_gcode(const std::string &filename) const
{
	enum { PROGRESS_RANGE = 1000 };

	const auto errortitle = _(L("Error while uploading to the Duet"));
	fs::path filepath(filename);

	PrintHostSendDialog send_dialog(filepath.filename(), true);
	if (send_dialog.ShowModal() != wxID_OK) { return false; }

	const bool print = send_dialog.print();
	const auto upload_filepath = send_dialog.filename();
	const auto upload_filename = upload_filepath.filename();
	const auto upload_parent_path = upload_filepath.parent_path();

	wxProgressDialog progress_dialog(
	 	_(L("Duet upload")),
	 	_(L("Sending G-code file to Duet...")),
		PROGRESS_RANGE, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
	progress_dialog.Pulse();

	wxString connect_msg;
	if (!connect(connect_msg)) {
		auto errormsg = wxString::Format("%s: %s", errortitle, connect_msg);
		GUI::show_error(&progress_dialog, std::move(errormsg));
		return false;
	}

	bool res = true;

	auto upload_cmd = get_upload_url(upload_filepath.string());
	BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filename: %2%, path: %3%, print: %4%, command: %5%")
		% filepath.string()
		% upload_filename.string()
		% upload_parent_path.string()
		% print
		% upload_cmd;

	auto http = Http::post(std::move(upload_cmd));
	http.set_post_body(filename)
		.on_complete([&](std::string body, unsigned status) {
			BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body;
			progress_dialog.Update(PROGRESS_RANGE);

			int err_code = get_err_code_from_body(body);
			if (err_code != 0) {
				auto msg = format_error(body, L("Unknown error occured"), 0);
				GUI::show_error(&progress_dialog, std::move(msg));
				res = false;
			} else if (print) {
				wxString errormsg;
				res = start_print(errormsg, upload_filepath.string());
				if (!res) {
					GUI::show_error(&progress_dialog, std::move(errormsg));
				}
			}
		})
		.on_error([&](std::string body, std::string error, unsigned status) {
			BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body;
			auto errormsg = wxString::Format("%s: %s", errortitle, format_error(body, error, status));
			GUI::show_error(&progress_dialog, std::move(errormsg));
			res = false;
		})
		.on_progress([&](Http::Progress progress, bool &cancel) {
			if (cancel) {
				// Upload was canceled
				res = false;
			} else if (progress.ultotal > 0) {
				int value = PROGRESS_RANGE * progress.ulnow / progress.ultotal;
				cancel = !progress_dialog.Update(std::min(value, PROGRESS_RANGE - 1));    // Cap the value to prevent premature dialog closing
			} else {
				cancel = !progress_dialog.Pulse();
			}
		})
		.perform_sync();

	disconnect();

	return res;
}

bool Duet::has_auto_discovery() const
{
	return false;
}

bool Duet::can_test() const
{
	return true;
}

bool Duet::connect(wxString &msg) const
{
	bool res = false;
	auto url = get_connect_url();

	auto http = Http::get(std::move(url));
	http.on_error([&](std::string body, std::string error, unsigned status) {
			BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error connecting: %1%, HTTP %2%, body: `%3%`") % error % status % body;
			msg = format_error(body, error, status);
		})
		.on_complete([&](std::string body, unsigned) {
			BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body;

			int err_code = get_err_code_from_body(body);
			switch (err_code) {
				case 0:
					res = true;
					break;
				case 1:
					msg = format_error(body, L("Wrong password"), 0);
					break;
				case 2:
					msg = format_error(body, L("Could not get resources to create a new connection"), 0);
					break;
				default:
					msg = format_error(body, L("Unknown error occured"), 0);
					break;
			}

		})
		.perform_sync();

	return res;
}

void Duet::disconnect() const
{
	auto url =  (boost::format("%1%rr_disconnect")
			% get_base_url()).str();

	auto http = Http::get(std::move(url));
	http.on_error([&](std::string body, std::string error, unsigned status) {
		// we don't care about it, if disconnect is not working Duet will disconnect automatically after some time
		BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error disconnecting: %1%, HTTP %2%, body: `%3%`") % error % status % body;
	})
	.perform_sync();
}

std::string Duet::get_upload_url(const std::string &filename) const
{
	return (boost::format("%1%rr_upload?name=0:/gcodes/%2%&%3%")
			% get_base_url()
			% filename
			% timestamp_str()).str();
}

std::string Duet::get_connect_url() const
{
	return (boost::format("%1%rr_connect?password=%2%&%3%")
			% get_base_url()
			% (password.empty() ? "reprap" : password)
			% timestamp_str()).str();
}

std::string Duet::get_base_url() const
{
	if (host.find("http://") == 0 || host.find("https://") == 0) {
		if (host.back() == '/') {
			return host;
		} else {
			return (boost::format("%1%/") % host).str();
		}
	} else {
		return (boost::format("http://%1%/") % host).str();
	}
}

std::string Duet::timestamp_str() const
{
	enum { BUFFER_SIZE = 32 };

	auto t = std::time(nullptr);
	auto tm = *std::localtime(&t);

	char buffer[BUFFER_SIZE];
	std::strftime(buffer, BUFFER_SIZE, "time=%Y-%m-%dT%H:%M:%S", &tm);

	return std::string(buffer);
}

wxString Duet::format_error(const std::string &body, const std::string &error, unsigned status)
{
	if (status != 0) {
		auto wxbody = wxString::FromUTF8(body.data());
		return wxString::Format("HTTP %u: %s", status, wxbody);
	} else {
		return wxString::FromUTF8(error.data());
	}
}

bool Duet::start_print(wxString &msg, const std::string &filename) const
{
	bool res = false;
	auto url = (boost::format("%1%rr_gcode?gcode=M32%%20\"%2%\"")
			% get_base_url()
			% filename).str();

	auto http = Http::get(std::move(url));
	http.on_error([&](std::string body, std::string error, unsigned status) {
			BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error starting print: %1%, HTTP %2%, body: `%3%`") % error % status % body;
			msg = format_error(body, error, status);
		})
		.on_complete([&](std::string body, unsigned) {
			BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: Got: %1%") % body;
			res = true;
		})
		.perform_sync();

	return res;
}

int Duet::get_err_code_from_body(const std::string &body) const
{
	pt::ptree root;
	std::istringstream iss (body); // wrap returned json to istringstream
	pt::read_json(iss, root);

	return root.get<int>("err", 0);
}

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: Date.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 07:26:44 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_JAVA_UTIL_DATE_HXX_
#define _CONNECTIVITY_JAVA_UTIL_DATE_HXX_

#ifndef _CONNECTIVITY_JAVA_LANG_OBJECT_HXX_
#include "java/lang/Object.hxx"
#endif
#ifndef _COM_SUN_STAR_UTIL_DATE_HPP_
#include <com/sun/star/util/Date.hpp>
#endif

namespace connectivity
{

    //**************************************************************
    //************ Class: java.util.Date
    //**************************************************************

    class java_util_Date : public java_lang_Object
    {
    protected:
    // statische Daten fuer die Klasse
        static jclass theClass;
        // der Destruktor um den Object-Counter zu aktualisieren
        static void saveClassRef( jclass pClass );
    public:
        static jclass getMyClass();
        virtual ~java_util_Date();
        // ein Konstruktor, der fuer das Returnen des Objektes benoetigt wird:
        java_util_Date( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
    };
}
#endif // _CONNECTIVITY_JAVA_UTIL_DATE_HXX_

<commit_msg>INTEGRATION: CWS changefileheader (1.3.372); FILE MERGED 2008/04/01 10:53:39 thb 1.3.372.2: #i85898# Stripping all external header guards 2008/03/28 15:24:31 rt 1.3.372.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: Date.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_JAVA_UTIL_DATE_HXX_
#define _CONNECTIVITY_JAVA_UTIL_DATE_HXX_

#include "java/lang/Object.hxx"
#include <com/sun/star/util/Date.hpp>

namespace connectivity
{

    //**************************************************************
    //************ Class: java.util.Date
    //**************************************************************

    class java_util_Date : public java_lang_Object
    {
    protected:
    // statische Daten fuer die Klasse
        static jclass theClass;
        // der Destruktor um den Object-Counter zu aktualisieren
        static void saveClassRef( jclass pClass );
    public:
        static jclass getMyClass();
        virtual ~java_util_Date();
        // ein Konstruktor, der fuer das Returnen des Objektes benoetigt wird:
        java_util_Date( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){}
    };
}
#endif // _CONNECTIVITY_JAVA_UTIL_DATE_HXX_

<|endoftext|>


<commit_before>/*

The MIT License (MIT)

Copyright (c) 2014 William T. James

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

#pragma once

#include <cryptopp/cryptlib.h>
#include <cryptopp/filters.h>
#include <Python.h>
#include <CXX/Objects.hxx>
#include "PyArray.hxx"

#include <stdexcept>
#include <sstream>

class PyBytesSink : public CryptoPP::Bufferless<CryptoPP::Sink>
{
public:
	PyBytesSink()
		: _offset(0)
	{
		_buffer = py_from_string_and_size(0,4);
		if (!_buffer)
		{
			throw std::runtime_error("Unable to create python array object");
		}
		//std::cout << "Created python buffer object at: " << std::hex << (int)_buffer << " with reference count " << _buffer->ob_refcnt << std::endl;
	}

	size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
	{
		//std::cout << "entered PyBytesSink::Put2()" << std::endl;
		if (length > 0)
		{
			size_t size = py_get_size(_buffer);
			if (length < _offset && _offset + length > size)
			{
				reserve(2*_offset);
			}
			append(begin,length);
		}
		return 0;
	}

	void reserve(size_t n = 0)
	{
		//std::cout << "Attempting to resize buffer: " << std::hex << (int)_buffer << " to have length " << n << " bytes." << std::endl;
		//std::cout << "Reference count: " << _buffer->ob_refcnt << std::endl;
		if (py_resize(&_buffer,n))
		{
			std::stringstream msg;
			msg << "Unable to resize PyBytesSink.  Requested size: " << n << ", new buffer is at " << std::hex << (int)_buffer;
			throw std::runtime_error(msg.str());
		}
		//std::cout << "Buffer resized to: " << std::hex << (int)_buffer << std::endl;
	}

	void append(const byte *begin,size_t n)
	{
		//std::cout << "entered PyBytesSink::append()" << std::endl;
		char *c_ptr;
		ssize_t size = py_get_size(_buffer);
		if (_offset + n > (size_t)size)
		{
			// resize
			reserve(_offset + n);
		}
		if (py_as_string_and_size(_buffer,&c_ptr,&size))
		{
			throw std::runtime_error("AsStringAndSize failed in PyBytesSink::append.");
		}
		memcpy(c_ptr+_offset,begin,n);
		_offset += n;
	}

	py_array finish()
	{
		//std::cout << "Attempting to resize buffer: " << std::hex << (int)_buffer << " to have length " << _offset << " bytes." << std::endl;
		//std::cout << "Reference count: " << _buffer->ob_refcnt << std::endl;
		if (py_resize(&_buffer,_offset))
		{
			std::stringstream msg;
			msg << "Unable to resize PyBytesSink.  Requested size: " << _offset << ", new buffer is at " << std::hex << (int)_buffer;
			throw std::runtime_error(msg.str());
		}
		//std::cout << "Buffer resized to: " << std::hex << (int)_buffer << std::endl;
		//std::cout << "PyBytesSink finished." << std::endl;
		return py_array( _buffer, true );
	}
private:
	PyObject *_buffer;
	size_t _offset;
};<commit_msg>fixed compilation error on unix.<commit_after>/*

The MIT License (MIT)

Copyright (c) 2014 William T. James

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

*/

#pragma once

#include <cryptopp/cryptlib.h>
#include <cryptopp/filters.h>
#include <Python.h>
#include <CXX/Objects.hxx>
#include "PyArray.hxx"

#include <stdexcept>
#include <sstream>

class PyBytesSink : public CryptoPP::Bufferless<CryptoPP::Sink>
{
public:
	PyBytesSink()
		: _offset(0)
	{
		_buffer = py_from_string_and_size(0,4);
		if (!_buffer)
		{
			throw std::runtime_error("Unable to create python array object");
		}
		//std::cout << "Created python buffer object at: " << std::hex << (int)_buffer << " with reference count " << _buffer->ob_refcnt << std::endl;
	}

	size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking)
	{
		//std::cout << "entered PyBytesSink::Put2()" << std::endl;
		if (length > 0)
		{
			size_t size = py_get_size(_buffer);
			if (length < _offset && _offset + length > size)
			{
				reserve(2*_offset);
			}
			append(begin,length);
		}
		return 0;
	}

	void reserve(size_t n = 0)
	{
		//std::cout << "Attempting to resize buffer: " << std::hex << (int)_buffer << " to have length " << n << " bytes." << std::endl;
		//std::cout << "Reference count: " << _buffer->ob_refcnt << std::endl;
		if (py_resize(&_buffer,n))
		{
			std::stringstream msg;
			msg << "Unable to resize PyBytesSink.  Requested size: " << n;
			throw std::runtime_error(msg.str());
		}
		//std::cout << "Buffer resized to: " << std::hex << (int)_buffer << std::endl;
	}

	void append(const byte *begin,size_t n)
	{
		//std::cout << "entered PyBytesSink::append()" << std::endl;
		char *c_ptr;
		ssize_t size = py_get_size(_buffer);
		if (_offset + n > (size_t)size)
		{
			// resize
			reserve(_offset + n);
		}
		if (py_as_string_and_size(_buffer,&c_ptr,&size))
		{
			throw std::runtime_error("AsStringAndSize failed in PyBytesSink::append.");
		}
		memcpy(c_ptr+_offset,begin,n);
		_offset += n;
	}

	py_array finish()
	{
		//std::cout << "Attempting to resize buffer: " << std::hex << (int)_buffer << " to have length " << _offset << " bytes." << std::endl;
		//std::cout << "Reference count: " << _buffer->ob_refcnt << std::endl;
		if (py_resize(&_buffer,_offset))
		{
			std::stringstream msg;
			msg << "Unable to resize PyBytesSink.  Requested size: " << _offset;
			throw std::runtime_error(msg.str());
		}
		//std::cout << "Buffer resized to: " << std::hex << (int)_buffer << std::endl;
		//std::cout << "PyBytesSink finished." << std::endl;
		return py_array( _buffer, true );
	}
private:
	PyObject *_buffer;
	size_t _offset;
};<|endoftext|>


<commit_before>// The object hash map.
// (C) 2013 Cybozu.

#ifndef CYBOZU_HASH_MAP_HPP
#define CYBOZU_HASH_MAP_HPP

#include "MurmurHash3.h"

#include <algorithm>
#include <cstring>
#include <memory>
#include <mutex>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

namespace cybozu {

// Key class for <hash_map>.
class hash_key final {
public:
    // Construct from a statically allocated memory.
    // @p   Pointer to a statically allocated memory.
    // @len Length of the key.
    //
    // Construct from a statically allocated memory.
    //
    // As long as the constructed object lives, the memory pointed by `p`
    // must not be freed.
    hash_key(const char* p, std::size_t len) noexcept:
        m_p(p), m_len(len) {
        MurmurHash3_x86_32(m_p, (int)m_len, 0, &m_hash);
    }

    // Construct by moving a <std::vector>.
    //
    // Construct by moving a <std::vector>.  Sample usage:
    // ```
    // hash_key( std::vector<char>(p, p+len) )
    // ```
    hash_key(std::vector<char> v):
        m_v(std::move(v)), m_p(m_v.data()), m_len(m_v.size()) {
        MurmurHash3_x86_32(m_p, (int)m_len, 0, &m_hash);
    }

    // Copy constructor.
    hash_key(const hash_key& rhs):
        m_v(rhs.m_p, rhs.m_p+rhs.m_len), m_p(m_v.data()), m_len(m_v.size()),
        m_hash(rhs.m_hash) {}
    hash_key& operator=(const hash_key& rhs) = delete;

    // Move contructor and assign operator.
    hash_key(hash_key&& rhs) noexcept = default;
    hash_key& operator=(hash_key&& rhs) = default;

    std::uint32_t hash() const noexcept {
        return m_hash;
    }

    const char* data() const noexcept {
        return m_p;
    }

    std::size_t length() const noexcept {
        return m_len;
    }

    std::string str() const {
        return std::string(m_p, m_len);
    }

private:
    std::vector<char> m_v;
    const char* m_p;
    std::size_t m_len;
    std::uint32_t m_hash;

    friend bool operator==(const hash_key&, const hash_key&) noexcept;
};

inline bool operator==(const hash_key& lhs, const hash_key& rhs) noexcept {
    if( lhs.m_len != rhs.m_len ) return false;
    if( lhs.m_p == rhs.m_p ) return true;
    return std::memcmp(lhs.m_p, rhs.m_p, lhs.m_len) == 0;
}

// Return the nearest prime number.
unsigned int nearest_prime(unsigned int n) noexcept;

// Highly concurrent object hash map.
//
// Keys for this hash map are <hash_key> whereas objects are of type `T`.
// `T` must be either move-constructible or copyable.
//
// Each bucket in the hash map has its unique mutex to guard itself.
// This design reduces contensions between threads drastically in exchange
// for some functions such as dynamic resizing of the number of buckets.
template<typename T>
class hash_map {
    static_assert( std::is_move_constructible<T>::value ||
                   std::is_copy_constructible<T>::value,
                   "T must be move- or copy- constructible." );

public:
    typedef std::function<bool(const hash_key&, T&)> handler;
    typedef std::function<T(const hash_key&)> creator;

    // Hash map bucket.
    //
    // Each hash value corresponds to a bucket.
    // Member functions whose names end with `_nolock` are not thread-safe.
    class bucket {

        struct item {
            const hash_key key;
            T object;
            item* next;

            // perfect forwarding
            template<typename X>
            item(const hash_key& k, X&& o, item* n):
                key(k), object(std::forward<X>(o)), next(n) {}
        };

    public:
        bucket(): m_objects(nullptr) {}

        // Handle or insert an object.
        // @key  The object's key.
        // @h    A function to handle an existing object.
        // @c    A function to create a new object.
        //
        // This function can be used to handle an existing object, or
        // to insert a new object when such an object does not exist.
        //
        // If `h` is not `nullptr` and there is no existing object for
        // `key`, `false` is returned.  If `c` is not `nullptr` and an
        // object for `key` exists, `false` is returned.
        //
        // `h` can return `false` if it failed to handle the object.
        // Otherwise, `h` should return `true`.
        //
        // @return `true` if succeeded, `false` otherwise.
        bool apply_nolock(const hash_key& key,
                          const handler& h, const creator& c) {
            for( item* p = m_objects; p != nullptr; p = p->next ) {
                if( p->key == key ) {
                    if( ! h ) return false;
                    return h(p->key, p->object);
                }
            }
            if( ! c ) return false;
            m_objects = new item(key, c(key), m_objects);
            return true;
        }

        // Thread-safe <apply_nolock>.
        bool apply(const hash_key& key, const handler& h, const creator& c) {
            lock_guard g(m_lock);
            return apply_nolock(key, h, c);
        }

        // Remove an object for `key`.
        // @key       The object's key.
        // @callback  A function called when an object is removed.
        //
        // This removes an object associated with `key`.  If there is no
        // object associated with `key`, return `false`.  If `callback`
        // is not `nullptr`, it is called when an object is removed.
        //
        // @return `true` if successfully removed, `false` otherwise.
        bool remove_nolock(const hash_key& key,
                           const std::function<void(const hash_key&)>& callback) {
            for( item** p = &m_objects; *p != nullptr; p = &((*p)->next) ) {
                if( (*p)->key == key ) {
                    item* to_delete = *p;
                    *p = to_delete->next;
                    delete to_delete;
                    if( callback ) callback(key);
                    return true;
                }
            }
            return false;
        }

        // Thread-safe <remove_nolock>.
        bool remove(const hash_key& key,
                    const std::function<void(const hash_key&)>& callback) {
            lock_guard g(m_lock);
            return remove_nolock(key, callback);
        }

        // Remove an object for `key` if `pred` returns `true`.
        // @key   The object's key.
        // @pred  A predicate function.
        //
        // This function removes an object assiciated with `key` if a
        // predicate function returns `true`.  This function is thread-safe.
        //
        // @return `true` if object existed, `false` otherwise.
        bool remove_if(const hash_key& key,
                       const std::function<bool(const hash_key&, T&)>& pred) {
            lock_guard g(m_lock);
            for( item** p = &m_objects; *p != nullptr; p = &((*p)->next) ) {
                item* to_delete = *p;
                if( to_delete->key == key ) {
                    if( pred(key, to_delete->object) ) {
                        *p = to_delete->next;
                        delete to_delete;
                    }
                    return true;
                }
            }
            return false;
        }

        // Collect garbage objects.
        // @pred      Predicate function.
        //
        // This function collects garbage objects.
        // Objects for which `pred` returns `true` will be removed.
        void gc(const std::function<bool(const hash_key&, T&)>& pred) {
            lock_guard g(m_lock);
            for( item** p = &m_objects; *p != nullptr; ) {
                item* to_delete = *p;
                if( pred(to_delete->key, to_delete->object) ) {
                    *p = to_delete->next;
                    delete to_delete;
                } else {
                    p = &(to_delete->next);
                }
            }
        }

        // Clear objects in this bucket.
        void clear_nolock() {
            while( m_objects ) {
                item* next = m_objects->next;
                delete m_objects;
                m_objects = next;
            }
        }
    private:
        using lock_guard = std::lock_guard<std::mutex>;
        alignas(CACHELINE_SIZE)
        mutable std::mutex m_lock;
        item* m_objects;
    };

    hash_map(unsigned int buckets):
        m_size(nearest_prime(buckets)), m_buckets(m_size) {}

    // Handle or insert an object.
    // @key      The object's key.
    // @h        A function to handle an existing object.
    // @c        A function to create a new object.
    //
    // This function can be used to handle an existing object, or
    // to insert a new object when such an object does not exist.
    //
    // If `h` is not `nullptr` and there is no existing object for
    // `key`, `false` is returned.  If `c` is not `nullptr` and an
    // object for `key` exists, `false` is returned.
    //
    // `h` can return `false` if it failed to handle the object.
    // Otherwise, `h` should return `true`.
    //
    // @return `true` if succeeded, `false` otherwise.
    bool apply_nolock(const hash_key& key,
                      const handler& h, const creator& c) {
        return get_bucket(key).apply_nolock(key, h, c);
    }

    // Thread-safe <apply_nolock>.
    bool apply(const hash_key& key, const handler& h, const creator& c) {
        return get_bucket(key).apply(key, h, c);
    }

    // Remove an object for `key`.
    // @key       The object's key.
    // @callback  A function called when an object is removed.
    //
    // This removes an object associated with `key`.  If there is no
    // object associated with `key`, return `false`.  If `callback`
    // is not `nullptr`, it is called when an object is removed.
    //
    // @return `true` if successfully removed, `false` otherwise.
    bool remove_nolock(const hash_key& key,
                       const std::function<void(const hash_key&)>& callback) {
        return get_bucket(key).remove_nolock(key, callback);
    }

    // Thread-safe <remove_nolock>.
    bool remove(const hash_key& key,
                const std::function<void(const hash_key&)>& callback) {
        return get_bucket(key).remove(key, callback);
    }

    // Remove an object for `key` if `pred` returns `true`.
    // @key   The object's key.
    // @pred  A predicate function.
    //
    // This function removes an object assiciated with `key` if a
    // predicate function returns `true`.  This function is thread-safe.
    //
    // @return `true` if object existed, `false` otherwise.
    bool remove_if(const hash_key& key,
                   const std::function<bool(const hash_key&, T&)>& pred) {
        return get_bucket(key).remove_if(key, pred);
    }

    /* Bucket interfaces */

    // Return the number of buckets in this hash map.
    std::size_t bucket_count() const noexcept {
        return m_size;
    }

    bucket& get_bucket(const hash_key& key) noexcept {
        return m_buckets[key.hash() % m_size];
    }

    // <bucket> iterator.
    using iterator = typename std::vector<bucket>::iterator;

    iterator begin() {
        return m_buckets.begin();
    }

    iterator end() {
        return m_buckets.end();
    }

private:
    const std::size_t   m_size;
    std::vector<bucket> m_buckets;
};

} // namespace cybozu

#endif // CYBOZU_HASH_MAP_HPP
<commit_msg>Delete objects in hash_map at dtor.<commit_after>// The object hash map.
// (C) 2013 Cybozu.

#ifndef CYBOZU_HASH_MAP_HPP
#define CYBOZU_HASH_MAP_HPP

#include "MurmurHash3.h"

#include <algorithm>
#include <cstring>
#include <memory>
#include <mutex>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

namespace cybozu {

// Key class for <hash_map>.
class hash_key final {
public:
    // Construct from a statically allocated memory.
    // @p   Pointer to a statically allocated memory.
    // @len Length of the key.
    //
    // Construct from a statically allocated memory.
    //
    // As long as the constructed object lives, the memory pointed by `p`
    // must not be freed.
    hash_key(const char* p, std::size_t len) noexcept:
        m_p(p), m_len(len) {
        MurmurHash3_x86_32(m_p, (int)m_len, 0, &m_hash);
    }

    // Construct by moving a <std::vector>.
    //
    // Construct by moving a <std::vector>.  Sample usage:
    // ```
    // hash_key( std::vector<char>(p, p+len) )
    // ```
    hash_key(std::vector<char> v):
        m_v(std::move(v)), m_p(m_v.data()), m_len(m_v.size()) {
        MurmurHash3_x86_32(m_p, (int)m_len, 0, &m_hash);
    }

    // Copy constructor.
    hash_key(const hash_key& rhs):
        m_v(rhs.m_p, rhs.m_p+rhs.m_len), m_p(m_v.data()), m_len(m_v.size()),
        m_hash(rhs.m_hash) {}
    hash_key& operator=(const hash_key& rhs) = delete;

    // Move contructor and assign operator.
    hash_key(hash_key&& rhs) noexcept = default;
    hash_key& operator=(hash_key&& rhs) = default;

    std::uint32_t hash() const noexcept {
        return m_hash;
    }

    const char* data() const noexcept {
        return m_p;
    }

    std::size_t length() const noexcept {
        return m_len;
    }

    std::string str() const {
        return std::string(m_p, m_len);
    }

private:
    std::vector<char> m_v;
    const char* m_p;
    std::size_t m_len;
    std::uint32_t m_hash;

    friend bool operator==(const hash_key&, const hash_key&) noexcept;
};

inline bool operator==(const hash_key& lhs, const hash_key& rhs) noexcept {
    if( lhs.m_len != rhs.m_len ) return false;
    if( lhs.m_p == rhs.m_p ) return true;
    return std::memcmp(lhs.m_p, rhs.m_p, lhs.m_len) == 0;
}

// Return the nearest prime number.
unsigned int nearest_prime(unsigned int n) noexcept;

// Highly concurrent object hash map.
//
// Keys for this hash map are <hash_key> whereas objects are of type `T`.
// `T` must be either move-constructible or copyable.
//
// Each bucket in the hash map has its unique mutex to guard itself.
// This design reduces contensions between threads drastically in exchange
// for some functions such as dynamic resizing of the number of buckets.
template<typename T>
class hash_map {
    static_assert( std::is_move_constructible<T>::value ||
                   std::is_copy_constructible<T>::value,
                   "T must be move- or copy- constructible." );

public:
    typedef std::function<bool(const hash_key&, T&)> handler;
    typedef std::function<T(const hash_key&)> creator;

    // Hash map bucket.
    //
    // Each hash value corresponds to a bucket.
    // Member functions whose names end with `_nolock` are not thread-safe.
    class bucket {

        struct item {
            const hash_key key;
            T object;
            item* next;

            // perfect forwarding
            template<typename X>
            item(const hash_key& k, X&& o, item* n):
                key(k), object(std::forward<X>(o)), next(n) {}
        };

    public:
        bucket(): m_objects(nullptr) {}
        ~bucket() {
            clear_nolock();
        }

        // Handle or insert an object.
        // @key  The object's key.
        // @h    A function to handle an existing object.
        // @c    A function to create a new object.
        //
        // This function can be used to handle an existing object, or
        // to insert a new object when such an object does not exist.
        //
        // If `h` is not `nullptr` and there is no existing object for
        // `key`, `false` is returned.  If `c` is not `nullptr` and an
        // object for `key` exists, `false` is returned.
        //
        // `h` can return `false` if it failed to handle the object.
        // Otherwise, `h` should return `true`.
        //
        // @return `true` if succeeded, `false` otherwise.
        bool apply_nolock(const hash_key& key,
                          const handler& h, const creator& c) {
            for( item* p = m_objects; p != nullptr; p = p->next ) {
                if( p->key == key ) {
                    if( ! h ) return false;
                    return h(p->key, p->object);
                }
            }
            if( ! c ) return false;
            m_objects = new item(key, c(key), m_objects);
            return true;
        }

        // Thread-safe <apply_nolock>.
        bool apply(const hash_key& key, const handler& h, const creator& c) {
            lock_guard g(m_lock);
            return apply_nolock(key, h, c);
        }

        // Remove an object for `key`.
        // @key       The object's key.
        // @callback  A function called when an object is removed.
        //
        // This removes an object associated with `key`.  If there is no
        // object associated with `key`, return `false`.  If `callback`
        // is not `nullptr`, it is called when an object is removed.
        //
        // @return `true` if successfully removed, `false` otherwise.
        bool remove_nolock(const hash_key& key,
                           const std::function<void(const hash_key&)>& callback) {
            for( item** p = &m_objects; *p != nullptr; p = &((*p)->next) ) {
                if( (*p)->key == key ) {
                    item* to_delete = *p;
                    *p = to_delete->next;
                    delete to_delete;
                    if( callback ) callback(key);
                    return true;
                }
            }
            return false;
        }

        // Thread-safe <remove_nolock>.
        bool remove(const hash_key& key,
                    const std::function<void(const hash_key&)>& callback) {
            lock_guard g(m_lock);
            return remove_nolock(key, callback);
        }

        // Remove an object for `key` if `pred` returns `true`.
        // @key   The object's key.
        // @pred  A predicate function.
        //
        // This function removes an object assiciated with `key` if a
        // predicate function returns `true`.  This function is thread-safe.
        //
        // @return `true` if object existed, `false` otherwise.
        bool remove_if(const hash_key& key,
                       const std::function<bool(const hash_key&, T&)>& pred) {
            lock_guard g(m_lock);
            for( item** p = &m_objects; *p != nullptr; p = &((*p)->next) ) {
                item* to_delete = *p;
                if( to_delete->key == key ) {
                    if( pred(key, to_delete->object) ) {
                        *p = to_delete->next;
                        delete to_delete;
                    }
                    return true;
                }
            }
            return false;
        }

        // Collect garbage objects.
        // @pred      Predicate function.
        //
        // This function collects garbage objects.
        // Objects for which `pred` returns `true` will be removed.
        void gc(const std::function<bool(const hash_key&, T&)>& pred) {
            lock_guard g(m_lock);
            for( item** p = &m_objects; *p != nullptr; ) {
                item* to_delete = *p;
                if( pred(to_delete->key, to_delete->object) ) {
                    *p = to_delete->next;
                    delete to_delete;
                } else {
                    p = &(to_delete->next);
                }
            }
        }

        // Clear objects in this bucket.
        void clear_nolock() {
            while( m_objects ) {
                item* next = m_objects->next;
                delete m_objects;
                m_objects = next;
            }
        }
    private:
        using lock_guard = std::lock_guard<std::mutex>;
        mutable std::mutex m_lock;
        item* m_objects;
    };

    hash_map(unsigned int buckets):
        m_size(nearest_prime(buckets)), m_buckets(m_size) {}

    // Handle or insert an object.
    // @key      The object's key.
    // @h        A function to handle an existing object.
    // @c        A function to create a new object.
    //
    // This function can be used to handle an existing object, or
    // to insert a new object when such an object does not exist.
    //
    // If `h` is not `nullptr` and there is no existing object for
    // `key`, `false` is returned.  If `c` is not `nullptr` and an
    // object for `key` exists, `false` is returned.
    //
    // `h` can return `false` if it failed to handle the object.
    // Otherwise, `h` should return `true`.
    //
    // @return `true` if succeeded, `false` otherwise.
    bool apply_nolock(const hash_key& key,
                      const handler& h, const creator& c) {
        return get_bucket(key).apply_nolock(key, h, c);
    }

    // Thread-safe <apply_nolock>.
    bool apply(const hash_key& key, const handler& h, const creator& c) {
        return get_bucket(key).apply(key, h, c);
    }

    // Remove an object for `key`.
    // @key       The object's key.
    // @callback  A function called when an object is removed.
    //
    // This removes an object associated with `key`.  If there is no
    // object associated with `key`, return `false`.  If `callback`
    // is not `nullptr`, it is called when an object is removed.
    //
    // @return `true` if successfully removed, `false` otherwise.
    bool remove_nolock(const hash_key& key,
                       const std::function<void(const hash_key&)>& callback) {
        return get_bucket(key).remove_nolock(key, callback);
    }

    // Thread-safe <remove_nolock>.
    bool remove(const hash_key& key,
                const std::function<void(const hash_key&)>& callback) {
        return get_bucket(key).remove(key, callback);
    }

    // Remove an object for `key` if `pred` returns `true`.
    // @key   The object's key.
    // @pred  A predicate function.
    //
    // This function removes an object assiciated with `key` if a
    // predicate function returns `true`.  This function is thread-safe.
    //
    // @return `true` if object existed, `false` otherwise.
    bool remove_if(const hash_key& key,
                   const std::function<bool(const hash_key&, T&)>& pred) {
        return get_bucket(key).remove_if(key, pred);
    }

    /* Bucket interfaces */

    // Return the number of buckets in this hash map.
    std::size_t bucket_count() const noexcept {
        return m_size;
    }

    bucket& get_bucket(const hash_key& key) noexcept {
        return m_buckets[key.hash() % m_size];
    }

    // <bucket> iterator.
    using iterator = typename std::vector<bucket>::iterator;

    iterator begin() {
        return m_buckets.begin();
    }

    iterator end() {
        return m_buckets.end();
    }

private:
    const std::size_t   m_size;
    std::vector<bucket> m_buckets;
};

} // namespace cybozu

#endif // CYBOZU_HASH_MAP_HPP
<|endoftext|>


<commit_before>// Spinlock.
// (C) 2013 Cybozu.

#ifndef CYBOZU_SPINLOCK_HPP
#define CYBOZU_SPINLOCK_HPP

#include <atomic>
#if defined(__i386__) || defined(__x86_64__)
# include <x86intrin.h>
#endif

namespace cybozu {

// A simple spinlock.
class spinlock {
public:
    spinlock(): m_flag(ATOMIC_FLAG_INIT) {}
    void lock() {
        while( m_flag.test_and_set(std::memory_order_acquire) )
            pause();
    }
    void unlock() {
        m_flag.clear(std::memory_order_release);
    }

private:
    std::atomic_flag m_flag;
    void pause() {
#if defined(__i386__) || defined(__x86_64__)
# if defined(__SSE__)
        _mm_pause();
# else
        __asm__ __volatile__ ("rep; nop");
# endif
#endif
    }
};

} // namespace cybozu

#endif // CYBOZU_SPINLOCK_HPP
<commit_msg>correct initialization of atomic_flag<commit_after>// Spinlock.
// (C) 2013 Cybozu.

#ifndef CYBOZU_SPINLOCK_HPP
#define CYBOZU_SPINLOCK_HPP

#include <atomic>
#if defined(__i386__) || defined(__x86_64__)
# include <x86intrin.h>
#endif

namespace cybozu {

// A simple spinlock.
class spinlock {
public:
    spinlock() {}
    void lock() {
        while( m_flag.test_and_set(std::memory_order_acquire) )
            pause();
    }
    void unlock() {
        m_flag.clear(std::memory_order_release);
    }

private:
    std::atomic_flag m_flag = ATOMIC_FLAG_INIT;
    void pause() {
#if defined(__i386__) || defined(__x86_64__)
# if defined(__SSE__)
        _mm_pause();
# else
        __asm__ __volatile__ ("rep; nop");
# endif
#endif
    }
};

} // namespace cybozu

#endif // CYBOZU_SPINLOCK_HPP
<|endoftext|>