<commit_before>// Copyright (c) 2010 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 "gpu/pgl/command_buffer_pepper.h"

#include "gpu/command_buffer/common/logging.h"

using base::SharedMemory;
using gpu::Buffer;
using gpu::CommandBuffer;

CommandBufferPepper::CommandBufferPepper(NPP npp,
                                         NPDevice* device,
                                         NPDeviceContext3D* context)
    : npp_(npp),
      device_(device),
      context_(context) {
}

CommandBufferPepper::~CommandBufferPepper() {
}

// Not implemented in CommandBufferPepper.
bool CommandBufferPepper::Initialize(int32 size) {
  NOTREACHED();
  return false;
}

Buffer CommandBufferPepper::GetRingBuffer() {
  Buffer buffer;
#if defined(ENABLE_NEW_NPDEVICE_API)
  NPDeviceBuffer np_buffer;
  device_->mapBuffer(npp_,
                     context_,
                     NP3DCommandBufferId,
                     &np_buffer);
  buffer.ptr = np_buffer.ptr;
  buffer.size = np_buffer.size;
#else
  buffer.ptr = context_->commandBuffer;
  buffer.size = context_->commandBufferSize * sizeof(int32);
#endif
  return buffer;
}

CommandBuffer::State CommandBufferPepper::GetState() {
#if defined(ENABLE_NEW_NPDEVICE_API)
  int32 output_attribs[] = {
    NP3DAttrib_CommandBufferSize, 0,
    NP3DAttrib_GetOffset, 0,
    NP3DAttrib_PutOffset, 0,
    NP3DAttrib_Token, 0,
    NPAttrib_Error, 0,
    NPAttrib_End
  };
  device_->synchronizeContext(npp_,
                              context_,
                              NPDeviceSynchronizationMode_Immediate,
                              NULL,
                              output_attribs,
                              NULL,
                              NULL);

  CommandBuffer::State state;
  state.num_entries = output_attribs[1];
  state.get_offset = output_attribs[3];
  state.put_offset = output_attribs[5];
  state.token = output_attribs[7];
  state.error = static_cast<gpu::error::Error>(
      output_attribs[9]);

  return state;
#else
  context_->waitForProgress = false;

  if (NPERR_NO_ERROR != device_->flushContext(npp_, context_, NULL, NULL))
    context_->error = NPDeviceContext3DError_GenericError;

  context_->waitForProgress = true;

  return ConvertState();
#endif  // ENABLE_NEW_NPDEVICE_API
}

CommandBuffer::State CommandBufferPepper::Flush(int32 put_offset) {
#if defined(ENABLE_NEW_NPDEVICE_API)
  int32 input_attribs[] = {
    NP3DAttrib_PutOffset, put_offset,
    NPAttrib_End
  };
  int32 output_attribs[] = {
    NP3DAttrib_CommandBufferSize, 0,
    NP3DAttrib_GetOffset, 0,
    NP3DAttrib_PutOffset, 0,
    NP3DAttrib_Token, 0,
    NPAttrib_Error, 0,
    NPAttrib_End
  };
  device_->synchronizeContext(npp_,
                              context_,
                              NPDeviceSynchronizationMode_Flush,
                              input_attribs,
                              output_attribs,
                              NULL,
                              NULL);

  CommandBuffer::State state;
  state.num_entries = output_attribs[1];
  state.get_offset = output_attribs[3];
  state.put_offset = output_attribs[5];
  state.token = output_attribs[7];
  state.error = static_cast<gpu::error::Error>(
      output_attribs[9]);

  return state;
#else
  context_->waitForProgress = true;
  context_->putOffset = put_offset;

  if (NPERR_NO_ERROR != device_->flushContext(npp_, context_, NULL, NULL))
    context_->error = NPDeviceContext3DError_GenericError;

  return ConvertState();
#endif  // ENABLE_NEW_NPDEVICE_API
}

void CommandBufferPepper::SetGetOffset(int32 get_offset) {
  // Not implemented by proxy.
  NOTREACHED();
}

int32 CommandBufferPepper::CreateTransferBuffer(size_t size) {
  int32 id;
  if (NPERR_NO_ERROR != device_->createBuffer(npp_, context_, size, &id))
    return -1;

  return id;
}

void CommandBufferPepper::DestroyTransferBuffer(int32 id) {
  device_->destroyBuffer(npp_, context_, id);
}

Buffer CommandBufferPepper::GetTransferBuffer(int32 id) {
  NPDeviceBuffer np_buffer;
  if (NPERR_NO_ERROR != device_->mapBuffer(npp_, context_, id, &np_buffer))
    return Buffer();

  Buffer buffer;
  buffer.ptr = np_buffer.ptr;
  buffer.size = np_buffer.size;
  return buffer;
}

void CommandBufferPepper::SetToken(int32 token) {
  // Not implemented by proxy.
  NOTREACHED();
}

void CommandBufferPepper::SetParseError(
    gpu::error::Error error) {
  // Not implemented by proxy.
  NOTREACHED();
}

gpu::error::Error CommandBufferPepper::GetCachedError() {
  int32 attrib_list[] = {
    NPAttrib_Error, 0,
    NPAttrib_End
  };
  device_->synchronizeContext(npp_,
                              context_,
                              NPDeviceSynchronizationMode_Cached,
                              NULL,
                              attrib_list,
                              NULL,
                              NULL);
  return static_cast<gpu::error::Error>(attrib_list[1]);
}

CommandBuffer::State CommandBufferPepper::ConvertState() {
  CommandBuffer::State state;
  state.num_entries = context_->commandBufferSize;
  state.get_offset = context_->getOffset;
  state.put_offset = context_->putOffset;
  state.token = context_->token;
  state.error = static_cast<gpu::error::Error>(
      context_->error);
  return state;
}
<commit_msg>Fix two problems with int32 <-> int32_t conversion when compiled in -pedantic mode inside Native Client. BUG=none TEST=none<commit_after>// Copyright (c) 2010 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 "gpu/pgl/command_buffer_pepper.h"

#include "gpu/command_buffer/common/logging.h"

using base::SharedMemory;
using gpu::Buffer;
using gpu::CommandBuffer;

CommandBufferPepper::CommandBufferPepper(NPP npp,
                                         NPDevice* device,
                                         NPDeviceContext3D* context)
    : npp_(npp),
      device_(device),
      context_(context) {
}

CommandBufferPepper::~CommandBufferPepper() {
}

// Not implemented in CommandBufferPepper.
bool CommandBufferPepper::Initialize(int32 size) {
  NOTREACHED();
  return false;
}

Buffer CommandBufferPepper::GetRingBuffer() {
  Buffer buffer;
#if defined(ENABLE_NEW_NPDEVICE_API)
  NPDeviceBuffer np_buffer;
  device_->mapBuffer(npp_,
                     context_,
                     NP3DCommandBufferId,
                     &np_buffer);
  buffer.ptr = np_buffer.ptr;
  buffer.size = np_buffer.size;
#else
  buffer.ptr = context_->commandBuffer;
  buffer.size = context_->commandBufferSize * sizeof(int32);
#endif
  return buffer;
}

CommandBuffer::State CommandBufferPepper::GetState() {
#if defined(ENABLE_NEW_NPDEVICE_API)
  int32 output_attribs[] = {
    NP3DAttrib_CommandBufferSize, 0,
    NP3DAttrib_GetOffset, 0,
    NP3DAttrib_PutOffset, 0,
    NP3DAttrib_Token, 0,
    NPAttrib_Error, 0,
    NPAttrib_End
  };
  device_->synchronizeContext(npp_,
                              context_,
                              NPDeviceSynchronizationMode_Immediate,
                              NULL,
                              output_attribs,
                              NULL,
                              NULL);

  CommandBuffer::State state;
  state.num_entries = output_attribs[1];
  state.get_offset = output_attribs[3];
  state.put_offset = output_attribs[5];
  state.token = output_attribs[7];
  state.error = static_cast<gpu::error::Error>(
      output_attribs[9]);

  return state;
#else
  context_->waitForProgress = false;

  if (NPERR_NO_ERROR != device_->flushContext(npp_, context_, NULL, NULL))
    context_->error = NPDeviceContext3DError_GenericError;

  context_->waitForProgress = true;

  return ConvertState();
#endif  // ENABLE_NEW_NPDEVICE_API
}

CommandBuffer::State CommandBufferPepper::Flush(int32 put_offset) {
#if defined(ENABLE_NEW_NPDEVICE_API)
  int32 input_attribs[] = {
    NP3DAttrib_PutOffset, put_offset,
    NPAttrib_End
  };
  int32 output_attribs[] = {
    NP3DAttrib_CommandBufferSize, 0,
    NP3DAttrib_GetOffset, 0,
    NP3DAttrib_PutOffset, 0,
    NP3DAttrib_Token, 0,
    NPAttrib_Error, 0,
    NPAttrib_End
  };
  device_->synchronizeContext(npp_,
                              context_,
                              NPDeviceSynchronizationMode_Flush,
                              input_attribs,
                              output_attribs,
                              NULL,
                              NULL);

  CommandBuffer::State state;
  state.num_entries = output_attribs[1];
  state.get_offset = output_attribs[3];
  state.put_offset = output_attribs[5];
  state.token = output_attribs[7];
  state.error = static_cast<gpu::error::Error>(
      output_attribs[9]);

  return state;
#else
  context_->waitForProgress = true;
  context_->putOffset = put_offset;

  if (NPERR_NO_ERROR != device_->flushContext(npp_, context_, NULL, NULL))
    context_->error = NPDeviceContext3DError_GenericError;

  return ConvertState();
#endif  // ENABLE_NEW_NPDEVICE_API
}

void CommandBufferPepper::SetGetOffset(int32 get_offset) {
  // Not implemented by proxy.
  NOTREACHED();
}

int32 CommandBufferPepper::CreateTransferBuffer(size_t size) {
  int32_t id;
  if (NPERR_NO_ERROR != device_->createBuffer(npp_, context_, size, &id))
    return -1;

  return static_cast<int32>(id);
}

void CommandBufferPepper::DestroyTransferBuffer(int32 id) {
  device_->destroyBuffer(npp_, context_, id);
}

Buffer CommandBufferPepper::GetTransferBuffer(int32 id) {
  NPDeviceBuffer np_buffer;
  if (NPERR_NO_ERROR != device_->mapBuffer(npp_, context_, id, &np_buffer))
    return Buffer();

  Buffer buffer;
  buffer.ptr = np_buffer.ptr;
  buffer.size = np_buffer.size;
  return buffer;
}

void CommandBufferPepper::SetToken(int32 token) {
  // Not implemented by proxy.
  NOTREACHED();
}

void CommandBufferPepper::SetParseError(
    gpu::error::Error error) {
  // Not implemented by proxy.
  NOTREACHED();
}

gpu::error::Error CommandBufferPepper::GetCachedError() {
  int32_t attrib_list[] = {
    NPAttrib_Error, 0,
    NPAttrib_End
  };
  device_->synchronizeContext(npp_,
                              context_,
                              NPDeviceSynchronizationMode_Cached,
                              NULL,
                              attrib_list,
                              NULL,
                              NULL);
  return static_cast<gpu::error::Error>(attrib_list[1]);
}

CommandBuffer::State CommandBufferPepper::ConvertState() {
  CommandBuffer::State state;
  state.num_entries = context_->commandBufferSize;
  state.get_offset = context_->getOffset;
  state.put_offset = context_->putOffset;
  state.token = context_->token;
  state.error = static_cast<gpu::error::Error>(
      context_->error);
  return state;
}
<|endoftext|>


<commit_before><commit_msg>If no argument supplied, do not set the first "real" argument<commit_after><|endoftext|>


<commit_before>/***********************************************************************
 *    filename:   TreeView.cpp
 *    created:    Fri Jun 13 2014
 *    author:     Timotei Dolean <timotei21@gmail.com>
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2014 Paul D Turner & The CEGUI Development Team
 *
 *    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 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.
***************************************************************************/
#include <boost/test/unit_test.hpp>

#include "CEGUI/CEGUI.h"
#include "InventoryModel.h"

using namespace CEGUI;

//----------------------------------------------------------------------------//
struct TreeViewFixture
{
    TreeViewFixture()
    {
        view = static_cast<TreeView*>(WindowManager::getSingleton().createWindow("TaharezLook/TreeView", "tv"));
        view->setModel(&model);
        font_height = view->getFont()->getFontHeight();
    }

    TreeView* view;
    InventoryModel model;
    float font_height;
};

BOOST_FIXTURE_TEST_SUITE(TreeViewTestSuite, TreeViewFixture)

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_NoItems_ReturnsInvalidIndex)
{
    ModelIndex index = view->indexAt(Vector2f(1, 0));

    BOOST_REQUIRE(index.d_modelData == 0);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionInsideObject_ReturnsCorrectIndex)
{
    // we do this on purpose: we need to skip the root from selection & related.
    // if it has a name then we need not to render it.
    model.getInventoryRoot().d_name = "Root";
    model.addRandomItemWithChild(model.getRootIndex(), 0);

    ModelIndex index = view->indexAt(Vector2f(1, font_height / 2.0f));

    BOOST_REQUIRE(index.d_modelData != 0);
    BOOST_REQUIRE_EQUAL(
        model.getInventoryRoot().d_items.at(0),
        static_cast<InventoryItem*>(index.d_modelData));
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionInsideObjectTreeWithOffset_ReturnsCorrectIndex)
{
    float x_offset = 500;
    float y_offset = 354;
    view->setPosition(UVector2(cegui_absdim(x_offset), cegui_absdim(y_offset)));
    model.addRandomItemWithChild(model.getRootIndex(), 0);

    ModelIndex index = view->indexAt(Vector2f(
        x_offset + 1,
        y_offset + font_height / 2.0f));

    BOOST_REQUIRE(index.d_modelData != 0);
    BOOST_REQUIRE_EQUAL(
        model.getInventoryRoot().d_items.at(0),
        static_cast<InventoryItem*>(index.d_modelData));
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionInsideSingleObjectTreeWithScrollbar_ReturnsCorrectIndex)
{
    for (int i = 0; i < 50; ++i)
        model.addRandomItemWithChild(model.getRootIndex(), 0);

    view->setSize(USize(cegui_absdim(200), cegui_absdim(font_height * 10)));
    view->prepareForRender();
    view->getVertScrollbar()->setUnitIntervalScrollPosition(1.0f);

    ModelIndex index = view->indexAt(Vector2f(50, 9 * font_height + font_height / 2.0f));

    BOOST_REQUIRE(index.d_modelData != 0);
    BOOST_REQUIRE_EQUAL(
        model.getInventoryRoot().d_items.at(49)->d_items.at(0),
        static_cast<InventoryItem*>(index.d_modelData));
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionOutsideObject_ReturnsInvalidIndex)
{
    model.addRandomItemWithChild(model.getRootIndex(), 0);

    ModelIndex index = view->indexAt(Vector2f(1, font_height * 3));

    BOOST_REQUIRE(index.d_modelData == 0);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionInsideSecondObject_ReturnsCorrectIndex)
{
    model.addRandomItemWithChild(model.getRootIndex(), 0);
    model.addRandomItemWithChild(model.getRootIndex(), 0);

    ModelIndex index = view->indexAt(Vector2f(1, font_height * 2 + font_height / 2));

    BOOST_REQUIRE(index.d_modelData != 0);
    BOOST_REQUIRE_EQUAL(
        model.getInventoryRoot().d_items.at(1),
        static_cast<InventoryItem*>(index.d_modelData));
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(SetSelectedItem_InitialSelection_SelectsFirstObject)
{
    model.load();

    bool selected = view->setSelectedItem(model.makeIndex(0, model.getRootIndex()));
    view->prepareForRender();

    BOOST_REQUIRE(selected);
    BOOST_REQUIRE(view->getRootItemState().d_renderedChildren.at(0).d_isSelected);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(SetSelectedItem_SecondSelection_SelectsSecondObject)
{
    model.load();
    view->setSelectedItem(model.makeIndex(0, model.getRootIndex()));
    view->prepareForRender();

    bool selected = view->setSelectedItem(model.makeIndex(1, model.getRootIndex()));
    view->prepareForRender();

    BOOST_REQUIRE(selected);
    BOOST_REQUIRE(!view->getRootItemState().d_renderedChildren.at(0).d_isSelected);
    BOOST_REQUIRE(view->getRootItemState().d_renderedChildren.at(1).d_isSelected);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(ItemAdded_ProperSelectionIsPersisted)
{
    model.load();
    view->setSelectedItem(model.makeIndex(1, model.getRootIndex()));
    view->prepareForRender();

    model.addRandomItemWithChild(model.getRootIndex(), 0);
    view->prepareForRender();

    BOOST_REQUIRE(!view->getRootItemState().d_renderedChildren.at(0).d_isSelected);
    BOOST_REQUIRE(!view->getRootItemState().d_renderedChildren.at(1).d_isSelected);
    BOOST_REQUIRE(view->getRootItemState().d_renderedChildren.at(2).d_isSelected);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(ItemAdded_ProperChildSelectionIsPersisted)
{
    model.load();
    // first child
    view->setSelectedItem(model.makeIndex(0, model.makeIndex(1, model.getRootIndex())));
    view->prepareForRender();

    model.addRandomItemWithChild(model.getRootIndex(), 0);
    view->prepareForRender();

    BOOST_REQUIRE(!view->getRootItemState().d_renderedChildren.at(0).d_isSelected);
    BOOST_REQUIRE(!view->getRootItemState().d_renderedChildren.at(1).d_isSelected);
    BOOST_REQUIRE(!view->getRootItemState().d_renderedChildren.at(2).d_isSelected);
    BOOST_REQUIRE(view->getRootItemState().d_renderedChildren.at(2).d_renderedChildren.at(0).d_isSelected);
    BOOST_REQUIRE(!view->getRootItemState().d_renderedChildren.at(3).d_isSelected);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(ItemRemoved_NothingIsSelected)
{
    model.load();
    size_t initial_size = model.getInventoryRoot().d_items.size();
    view->setSelectedItem(model.makeIndex(1, model.getRootIndex()));
    view->prepareForRender();

    model.removeItem(model.makeIndex(1, model.getRootIndex()));

    view->prepareForRender();

    BOOST_REQUIRE_EQUAL(initial_size - 1, view->getRootItemState().d_renderedChildren.size());
    BOOST_REQUIRE(!view->getRootItemState().d_renderedChildren.at(0).d_isSelected);
    BOOST_REQUIRE(!view->getRootItemState().d_renderedChildren.at(1).d_isSelected);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Fix (part) of the TreeView test cases<commit_after>/***********************************************************************
 *    filename:   TreeView.cpp
 *    created:    Fri Jun 13 2014
 *    author:     Timotei Dolean <timotei21@gmail.com>
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2014 Paul D Turner & The CEGUI Development Team
 *
 *    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 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.
***************************************************************************/
#include <boost/test/unit_test.hpp>

#include "CEGUI/CEGUI.h"
#include "InventoryModel.h"

using namespace CEGUI;

//----------------------------------------------------------------------------//
struct TreeViewFixture
{
    TreeViewFixture()
    {
        view = static_cast<TreeView*>(WindowManager::getSingleton().createWindow("TaharezLook/TreeView", "tv"));
        view->setModel(&model);
        font_height = view->getFont()->getFontHeight();
    }

    TreeView* view;
    InventoryModel model;
    float font_height;
};

BOOST_FIXTURE_TEST_SUITE(TreeViewTestSuite, TreeViewFixture)

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_NoItems_ReturnsInvalidIndex)
{
    ModelIndex index = view->indexAt(Vector2f(1, 0));

    BOOST_REQUIRE(index.d_modelData == 0);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionInsideObject_ReturnsCorrectIndex)
{
    // we do this on purpose: we need to skip the root from selection & related.
    // if it has a name then we need not to render it.
    model.getInventoryRoot().d_name = "Root";
    model.addRandomItemWithChild(model.getRootIndex(), 0);

    ModelIndex index = view->indexAt(Vector2f(1, font_height / 2.0f));

    BOOST_REQUIRE(index.d_modelData != 0);
    BOOST_REQUIRE_EQUAL(
        model.getInventoryRoot().d_items.at(0),
        static_cast<InventoryItem*>(index.d_modelData));
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionInsideObjectTreeWithOffset_ReturnsCorrectIndex)
{
    float x_offset = 500;
    float y_offset = 354;
    view->setPosition(UVector2(cegui_absdim(x_offset), cegui_absdim(y_offset)));
    model.addRandomItemWithChild(model.getRootIndex(), 0);

    ModelIndex index = view->indexAt(Vector2f(
        x_offset + 1,
        y_offset + font_height / 2.0f));

    BOOST_REQUIRE(index.d_modelData != 0);
    BOOST_REQUIRE_EQUAL(
        model.getInventoryRoot().d_items.at(0),
        static_cast<InventoryItem*>(index.d_modelData));
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionInsideSingleObjectTreeWithScrollbar_ReturnsCorrectIndex)
{
    for (int i = 0; i < 50; ++i)
        model.addRandomItemWithChild(model.getRootIndex(), 0);

    view->setSize(USize(cegui_absdim(200), cegui_absdim(font_height * 10)));
    view->prepareForRender();
    view->getVertScrollbar()->setUnitIntervalScrollPosition(1.0f);

    ModelIndex index = view->indexAt(Vector2f(50, 9 * font_height + font_height / 2.0f));

    BOOST_REQUIRE(index.d_modelData != 0);
    BOOST_REQUIRE_EQUAL(
        model.getInventoryRoot().d_items.at(49),
        static_cast<InventoryItem*>(index.d_modelData));
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionOutsideObject_ReturnsInvalidIndex)
{
    model.addRandomItemWithChild(model.getRootIndex(), 0);

    ModelIndex index = view->indexAt(Vector2f(1, font_height * 3));

    BOOST_REQUIRE(index.d_modelData == 0);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(IndexAt_PositionInsideSecondObject_ReturnsCorrectIndex)
{
    model.addRandomItemWithChild(model.getRootIndex(), 0);
    model.addRandomItemWithChild(model.getRootIndex(), 0);

    ModelIndex index = view->indexAt(Vector2f(1, font_height  + font_height / 2));

    BOOST_REQUIRE(index.d_modelData != 0);
    BOOST_REQUIRE_EQUAL(
        model.getInventoryRoot().d_items.at(1),
        static_cast<InventoryItem*>(index.d_modelData));
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(SetSelectedItem_InitialSelection_SelectsFirstObject)
{
    model.load();

    bool selected = view->setSelectedItem(model.makeIndex(0, model.getRootIndex()));
    view->prepareForRender();

    BOOST_REQUIRE(selected);
    BOOST_REQUIRE(view->getRootItemState().d_renderedChildren.at(0).d_isSelected);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(SetSelectedItem_SecondSelection_SelectsSecondObject)
{
    model.load();
    view->setSelectedItem(model.makeIndex(0, model.getRootIndex()));
    view->prepareForRender();

    bool selected = view->setSelectedItem(model.makeIndex(1, model.getRootIndex()));
    view->prepareForRender();

    BOOST_REQUIRE(selected);

    const std::vector<TreeViewItemRenderingState>& children = view->getRootItemState().d_renderedChildren;
    BOOST_REQUIRE(!children.at(0).d_isSelected);
    BOOST_REQUIRE(children.at(1).d_isSelected);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(ItemAdded_ProperSelectionIsPersisted)
{
    model.load();
    view->setSelectedItem(model.makeIndex(1, model.getRootIndex()));
    view->prepareForRender();

    model.addRandomItemWithChild(model.getRootIndex(), 0);
    view->prepareForRender();

    const std::vector<TreeViewItemRenderingState>& children = view->getRootItemState().d_renderedChildren;
    BOOST_REQUIRE(!children.at(0).d_isSelected);
    BOOST_REQUIRE(!children.at(1).d_isSelected);
    BOOST_REQUIRE(children.at(2).d_isSelected);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(ItemAdded_ProperChildSelectionIsPersisted)
{
    model.load();
    // first child
    view->setSelectedItem(model.makeIndex(0, model.makeIndex(1, model.getRootIndex())));
    view->prepareForRender();

    model.addRandomItemWithChild(model.getRootIndex(), 0);
    view->prepareForRender();

    const std::vector<TreeViewItemRenderingState>& children = view->getRootItemState().d_renderedChildren;
    BOOST_REQUIRE(!children.at(0).d_isSelected);
    BOOST_REQUIRE(!children.at(1).d_isSelected);
    BOOST_REQUIRE(!children.at(2).d_isSelected);
    BOOST_REQUIRE(children.at(2).d_renderedChildren.at(0).d_isSelected);
    BOOST_REQUIRE(!children.at(3).d_isSelected);
}

//----------------------------------------------------------------------------//
BOOST_AUTO_TEST_CASE(ItemRemoved_NothingIsSelected)
{
    model.load();
    size_t initial_size = model.getInventoryRoot().d_items.size();
    view->setSelectedItem(model.makeIndex(1, model.getRootIndex()));
    view->prepareForRender();

    model.removeItem(model.makeIndex(1, model.getRootIndex()));

    view->prepareForRender();

    const std::vector<TreeViewItemRenderingState>& children = view->getRootItemState().d_renderedChildren;
    BOOST_REQUIRE_EQUAL(initial_size - 1, view->getRootItemState().d_renderedChildren.size());
    BOOST_REQUIRE(!children.at(0).d_isSelected);
    BOOST_REQUIRE(!children.at(1).d_isSelected);
}

BOOST_AUTO_TEST_CASE(InitialState_NoSubtreesOpenedAndCountIsComputedRight)
{
    model.addRandomItemWithChild(model.getRootIndex(), 0);
    model.addRandomItemWithChild(model.getRootIndex(), 0);
    view->prepareForRender();

    const std::vector<TreeViewItemRenderingState>& children = view->getRootItemState().d_renderedChildren;
    BOOST_REQUIRE(!children.at(0).d_subtreeIsOpen);
    BOOST_REQUIRE(children.at(0).d_totalChildCount == 1);
    BOOST_REQUIRE(!children.at(1).d_subtreeIsOpen);
    BOOST_REQUIRE(children.at(1).d_totalChildCount == 1);

}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "common.h"
#include "timer.h"
#include <Grappa.hpp>
#include <ForkJoin.hpp>
#include <Cache.hpp>
#include <Delegate.hpp>
#include <PerformanceTools.hpp>
#include <GlobalAllocator.hpp>
#include <GlobalTaskJoiner.hpp>
#include <AsyncParallelFor.hpp>
#include <PushBuffer.hpp>
#include <Collective.hpp>
#include <Array.hpp>

//#include <boost/hash.hpp>
//#include <boost/unordered_set.hpp>
#include <boost/dynamic_bitset.hpp>

GRAPPA_DEFINE_EVENT_GROUP(bfs);

#define read      Grappa_delegate_read_word
#define write     Grappa_delegate_write_word
//#define cmp_swap  Grappa_delegate_compare_and_swap_word
#define fetch_add Grappa_delegate_fetch_and_add_word
#define allreduce_add Grappa_allreduce<int64_t,coll_add<int64_t>,0>

static PushBuffer<int64_t> vlist_buf;

static GlobalAddress<int64_t> vlist;
static GlobalAddress<int64_t> xoff;
static GlobalAddress<int64_t> xadj;
static GlobalAddress<int64_t> bfs_tree;
static GlobalAddress<int64_t> k2;
static int64_t nadj;
static int64_t nv;

#define XOFF(k) (xoff+2*(k))
#define XENDOFF(k) (xoff+2*(k)+1)

#define GA64(name) ((GlobalAddress<int64_t>,name))

// count number of neighbors visited
static uint64_t bfs_neighbors_visited = 0;
static bool bfs_counters_added = false;

// count number of vertex visited
static uint64_t bfs_vertex_visited = 0;

//template< typename T >
//std::size_t hash_value(GlobalAddress<T> const& a) {
  //boost::hash<int64_t> h;
  //return h((int64_t)a.raw_bits());
//}
//static boost::unordered_set< GlobalAddress<int64_t> > parent_set;

DEFINE_int64(cas_flattener_size, 20, "log2 of the number of unique elements in the hash set used to short-circuit compare and swaps");

int64_t cmp_swaps_total;
int64_t cmp_swaps_shorted;

class CmpSwapCombiner {
  size_t log2n;
  intptr_t * in_set;
public:
  CmpSwapCombiner() {
    log2n = FLAGS_cas_flattener_size;
    in_set = new intptr_t[1L << log2n];
    clear();
  }
  ~CmpSwapCombiner() { delete in_set; }

  void clear() {
    cmp_swaps_total = cmp_swaps_shorted = 0;
    memset(in_set, 0, sizeof(intptr_t)*(1L<<log2n));
  }

  bool flat_cas(GlobalAddress<int64_t> target, int64_t cmp_val, int64_t set_val) {
    cmp_swaps_total++;
    intptr_t t = target.raw_bits();
    uint64_t h = ((uint64_t)t) % (1L << log2n);

    if (in_set[h] == t) {
      cmp_swaps_shorted++;
      return false;
    } else {
      if (in_set[h] == 0) {
        in_set[h] = t;
      }
      return Grappa_delegate_compare_and_swap_word(target, cmp_val, set_val);
    }
  }
};

static CmpSwapCombiner * combiner = NULL;

//inline bool cmp_swap_short(GlobalAddress<int64_t> target, int64_t cmp_val, int64_t set_val) {
  //cmp_swaps_total++;
  //if (parent_set.count(target)) {
    //cmp_swaps_shorted++;
    //return false;
  //} else {
    //parent_set.insert(target);
    //return Grappa_delegate_compare_and_swap_word(target, cmp_val, set_val);
  //}
//}

void visit_neighbor(int64_t i, int64_t * neighbor_base, const int64_t& v) {
  ++bfs_neighbors_visited;

  CHECK( v < nv ) << "| v = " << v << ", nv = " << nv;
  CHECK( i < nv ) << "| i = " << i << " (nv = " << nv << ")";

  const int64_t j = neighbor_base[i];

  //if (v == 33707) { VLOG(1) << "neighbor_base = " << neighbor_base; }

  CHECK( j < nv ) << "| v[" << v << "].neighbors[" << i << "] = " << j << " (nv = " << nv << ") \n neighbor_base = " << neighbor_base;

  if (combiner->flat_cas(bfs_tree+j, -1, v)) {
    vlist_buf.push(j);
  }
}

/// for use with forall_local
/// @param v  vertex in frontier
void visit_frontier(int64_t * va) {
  ++bfs_vertex_visited;
  const int64_t v = *va;

  int64_t buf[2];
  Incoherent<int64_t>::RO cxoff(xoff+2*v, 2, buf);
  const int64_t vstart = cxoff[0], vend = cxoff[1];

  //if (v == 33707) {
    ////std::stringstream ss; ss << "neighbors: ";
    ////for (int64_t i=vstart; i<vend; i++) { ss << read(xadj+i) << " "; }
    ////VLOG(1) << ss.str();
    //VLOG(1) << "vstart: " << vstart << ", vend-vstart = " << vend-vstart;
    //VLOG(1) << "start node: " << (xadj+vstart).node();
  //}

  forall_local_async<int64_t,int64_t,visit_neighbor>(xadj+vstart, vend-vstart, make_linear(va));
}

static unsigned marker = -1;

LOOP_FUNCTOR(setup_bfs, nid, GA64(_vlist)GA64(_xoff)GA64(_xadj)GA64(_bfs_tree)GA64(_k2)((int64_t,_nadj)) ((int64_t,_nv))) {

  if ( !bfs_counters_added ) {
    bfs_counters_added = true;
    Grappa_add_profiling_counter( &bfs_neighbors_visited, "bfs_neighbors_visited", "bfsneigh", true, 0 );
    Grappa_add_profiling_counter( &bfs_vertex_visited, "bfs_vertex_visited", "bfsverts", true, 0 );
  }

  // setup globals
  vlist = _vlist;
  xoff = _xoff;
  xadj = _xadj;
  bfs_tree = _bfs_tree;
  k2 = _k2;
  nadj = _nadj;
  nv = _nv;

  // initialize push buffer (so it knows where to push to)
  vlist_buf.setup(vlist, k2);

  // initialize cmp_swap flat combiner
  //cmp_swaps_total = cmp_swaps_shorted = 0;
  //parent_set.clear();
  if (combiner == NULL) { combiner = new CmpSwapCombiner(); }
  combiner->clear();
}

LOOP_FUNCTION( bfs_finish_level, nid ) {
  vlist_buf.flush();
  VLOG(2) << "phase complete";
}

LOOP_FUNCTION( bfs_finish, nid ) {
  bfs_neighbors_visited = allreduce_add(bfs_neighbors_visited);
  bfs_vertex_visited = allreduce_add(bfs_vertex_visited);
  cmp_swaps_shorted = allreduce_add(cmp_swaps_shorted);
  cmp_swaps_total = allreduce_add(cmp_swaps_total);
}

double make_bfs_tree(csr_graph * g, GlobalAddress<int64_t> bfs_tree, int64_t root) {
  int64_t NV = g->nv;
  GlobalAddress<int64_t> vlist = Grappa_typed_malloc<int64_t>(NV);

#ifdef VTRACE
  if (marker == -1) marker = VT_MARKER_DEF("bfs_level", VT_MARKER_TYPE_HINT);
#endif

  double t;
  t = timer();

  // start with root as only thing in vlist
  write(vlist, root);

  int64_t k1 = 0, k2 = 1;
  GlobalAddress<int64_t> k2addr = make_global(&k2);

  // setup globals on all nodes
  { setup_bfs f(vlist, g->xoff, g->xadj, bfs_tree, k2addr, g->nadj, g->nv); fork_join_custom(&f); }

  // initialize bfs_tree to -1
  Grappa_memset(bfs_tree, (int64_t)-1,  NV);

  write(bfs_tree+root, root); // parent of root is self

  while (k1 != k2) {
    VLOG(2) << "k1=" << k1 << ", k2=" << k2;
    const int64_t oldk2 = k2;

    forall_local<int64_t,visit_frontier>(vlist+k1, k2-k1);

    { bfs_finish_level f; fork_join_custom(&f); }

    k1 = oldk2;
    k2 = k2;
  }
  t = timer() - t;

  { bfs_finish f; fork_join_custom(&f); }
  VLOG(1) << "bfs_vertex_visited = " << bfs_vertex_visited;
  VLOG(1) << "bfs_neighbors_visited = " << bfs_neighbors_visited;
  VLOG(1) << "cmp_swaps_shorted: " << cmp_swaps_shorted;
  VLOG(1) << "cmp_swaps_total: " << cmp_swaps_total;

  Grappa_free(vlist);

  return t;
}

<commit_msg>bfs: port localized version of bfs (but GCE bugs cause to hang)<commit_after>#include "common.h"
#include "timer.h"
#include <Grappa.hpp>
#include <ForkJoin.hpp>
#include <Cache.hpp>
#include <Delegate.hpp>
#include <PerformanceTools.hpp>
#include <GlobalAllocator.hpp>
#include <GlobalTaskJoiner.hpp>
#include <AsyncParallelFor.hpp>
#include <PushBuffer.hpp>
#include <Collective.hpp>
#include <Array.hpp>
#include <Collective.hpp>
#include <ParallelLoop.hpp>

using namespace Grappa;

//#include <boost/hash.hpp>
//#include <boost/unordered_set.hpp>
//#include <boost/dynamic_bitset.hpp>

GRAPPA_DEFINE_EVENT_GROUP(bfs);

//#define read      Grappa_delegate_read_word
//#define write     Grappa_delegate_write_word
//#define cmp_swap  Grappa_delegate_compare_and_swap_word
//#define fetch_add Grappa_delegate_fetch_and_add_word
//#define allreduce_add Grappa_allreduce<int64_t,coll_add<int64_t>,0>

static PushBuffer<int64_t> vlist_buf;

static GlobalAddress<int64_t> vlist;
static GlobalAddress<int64_t> xoff;
static GlobalAddress<int64_t> xadj;
static GlobalAddress<int64_t> bfs_tree;
static GlobalAddress<int64_t> k2;
static int64_t nadj;
static int64_t nv;

#define XOFF(k) (xoff+2*(k))
#define XENDOFF(k) (xoff+2*(k)+1)

//#define GA64(name) ((GlobalAddress<int64_t>,name))

// count number of neighbors visited
static uint64_t bfs_neighbors_visited = 0;
static bool bfs_counters_added = false;

// count number of vertex visited
static uint64_t bfs_vertex_visited = 0;

//template< typename T >
//std::size_t hash_value(GlobalAddress<T> const& a) {
  //boost::hash<int64_t> h;
  //return h((int64_t)a.raw_bits());
//}
//static boost::unordered_set< GlobalAddress<int64_t> > parent_set;

//DEFINE_int64(cas_flattener_size, 20, "log2 of the number of unique elements in the hash set used to short-circuit compare and swaps");

//int64_t cmp_swaps_total;
//int64_t cmp_swaps_shorted;
//
//class CmpSwapCombiner {
//  size_t log2n;
//  intptr_t * in_set;
//public:
//  CmpSwapCombiner() {
//    log2n = FLAGS_cas_flattener_size;
//    in_set = new intptr_t[1L << log2n];
//    clear();
//  }
//  ~CmpSwapCombiner() { delete in_set; }
//
//  void clear() {
//    cmp_swaps_total = cmp_swaps_shorted = 0;
//    memset(in_set, 0, sizeof(intptr_t)*(1L<<log2n));
//  }
//
//  bool flat_cas(GlobalAddress<int64_t> target, int64_t cmp_val, int64_t set_val) {
//    cmp_swaps_total++;
//    intptr_t t = target.raw_bits();
//    uint64_t h = ((uint64_t)t) % (1L << log2n);
//
//    if (in_set[h] == t) {
//      cmp_swaps_shorted++;
//      return false;
//    } else {
//      if (in_set[h] == 0) {
//        in_set[h] = t;
//      }
//      return Grappa_delegate_compare_and_swap_word(target, cmp_val, set_val);
//    }
//  }
//};
//
//static CmpSwapCombiner * combiner = NULL;

//inline bool cmp_swap_short(GlobalAddress<int64_t> target, int64_t cmp_val, int64_t set_val) {
  //cmp_swaps_total++;
  //if (parent_set.count(target)) {
    //cmp_swaps_shorted++;
    //return false;
  //} else {
    //parent_set.insert(target);
    //return Grappa_delegate_compare_and_swap_word(target, cmp_val, set_val);
  //}
//}

static unsigned marker = -1;

double make_bfs_tree(csr_graph * g, GlobalAddress<int64_t> _bfs_tree, int64_t root) {
  int64_t NV = g->nv;
  GlobalAddress<int64_t> _vlist = Grappa_typed_malloc<int64_t>(NV);

#ifdef VTRACE
  if (marker == -1) marker = VT_MARKER_DEF("bfs_level", VT_MARKER_TYPE_HINT);
#endif

  double t;
  t = timer();

  // start with root as only thing in vlist
  delegate::write(_vlist, root);

  int64_t k1 = 0, _k2 = 1;
  GlobalAddress<int64_t> k2addr = make_global(&_k2);

  // setup globals on all nodes

//  { setup_bfs f(vlist, g->xoff, g->xadj, bfs_tree, k2addr, g->nadj, g->nv); fork_join_custom(&f); }
  auto& graph = *g;

  on_all_cores([_vlist,graph,_bfs_tree,k2addr]{
    if ( !bfs_counters_added ) {
      bfs_counters_added = true;
      Grappa_add_profiling_counter( &bfs_neighbors_visited, "bfs_neighbors_visited", "bfsneigh", true, 0 );
      Grappa_add_profiling_counter( &bfs_vertex_visited, "bfs_vertex_visited", "bfsverts", true, 0 );
    }

    // setup globals
    vlist = _vlist;
    xoff = graph.xoff;
    xadj = graph.xadj;
    bfs_tree = _bfs_tree;
    k2 = k2addr;
    nadj = graph.nadj;
    nv = graph.nv;

    // initialize push buffer (so it knows where to push to)
    vlist_buf.setup(vlist, k2);

    // initialize cmp_swap flat combiner
    //cmp_swaps_total = cmp_swaps_shorted = 0;
    //parent_set.clear();
//    if (combiner == NULL) { combiner = new CmpSwapCombiner(); }
//    combiner->clear();
  });

  // initialize bfs_tree to -1
  Grappa::memset(_bfs_tree, (int64_t)-1,  NV);

  delegate::write(_bfs_tree+root, root); // parent of root is self

  while (k1 != _k2) {
    VLOG(2) << "k1=" << k1 << ", k2=" << _k2;
    const int64_t oldk2 = _k2;

    forall_localized(_vlist+k1, _k2-k1, [](int64_t index, int64_t& source_v) {
      ++bfs_vertex_visited;

      int64_t buf[2];
      Incoherent<int64_t>::RO cxoff(xoff+2*source_v, 2, buf);
      const int64_t vstart = cxoff[0], vend = cxoff[1];

      //if (v == 33707) {
      ////std::stringstream ss; ss << "neighbors: ";
      ////for (int64_t i=vstart; i<vend; i++) { ss << read(xadj+i) << " "; }
      ////VLOG(1) << ss.str();
      //VLOG(1) << "vstart: " << vstart << ", vend-vstart = " << vend-vstart;
      //VLOG(1) << "start node: " << (xadj+vstart).node();
      //}

      //  forall_local_async<int64_t,int64_t,visit_neighbor>(xadj+vstart, vend-vstart, make_linear(va));
      forall_localized_async(xadj+vstart, vend-vstart, [source_v](int64_t index, int64_t& edge){
        ++bfs_neighbors_visited;

        DCHECK( source_v < nv ) << "| v = " << source_v << ", nv = " << nv;
        DCHECK( index < nv ) << "| i = " << index << " (nv = " << nv << ")";

        const int64_t j = edge;

        //if (v == 33707) { VLOG(1) << "neighbor_base = " << neighbor_base; }

        DCHECK( j < nv ) << "| v[" << source_v << "].neighbors[" << index << "] = " << j << " (nv = " << nv << ") \n &edge = " << &edge;

        //  if (combiner->flat_cas(bfs_tree+j, -1, v)) {
        if (delegate::compare_and_swap(bfs_tree+j, -1, source_v)) {
          vlist_buf.push(j);
        }
      });
    });

    on_all_cores([]{
      vlist_buf.flush();
      VLOG(2) << "phase complete";
    });
    k1 = oldk2;
    _k2 = _k2;
  }
  t = timer() - t;

  bfs_neighbors_visited = Grappa::reduce<uint64_t,collective_add>(&bfs_neighbors_visited);
  bfs_vertex_visited    = Grappa::reduce<uint64_t,collective_add>(&bfs_vertex_visited);
//  cmp_swaps_shorted     = Grappa::reduce<uint64_t,collective_add>(&cmp_swaps_shorted);
//  cmp_swaps_total       = Grappa::reduce<uint64_t,collective_add>(&cmp_swaps_total);

  VLOG(1) << "bfs_vertex_visited = " << bfs_vertex_visited;
  VLOG(1) << "bfs_neighbors_visited = " << bfs_neighbors_visited;
//  VLOG(1) << "cmp_swaps_shorted: " << cmp_swaps_shorted;
//  VLOG(1) << "cmp_swaps_total: " << cmp_swaps_total;

  Grappa_free(_vlist);

  return t;
}

<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/fastos/fastos.h>
#include "match_thread.h"
#include "match_tools.h"
#include "handlerecorder.h"
#include "i_match_loop_communicator.h"
#include "matching_stats.h"
#include "document_scorer.h"
#include <memory>
#include <vespa/searchlib/common/featureset.h>
#include <vespa/searchlib/common/resultset.h>
#include <vespa/searchlib/fef/fef.h>
#include <vespa/searchlib/query/base.h>
#include <vespa/searchlib/queryeval/hitcollector.h>
#include <vespa/searchlib/queryeval/searchiterator.h>
#include <vespa/searchlib/queryeval/multibitvectoriterator.h>
#include <vespa/searchlib/queryeval/andnotsearch.h>
#include <vespa/vespalib/util/clock.h>
#include <vespa/vespalib/util/closure.h>
#include <vespa/vespalib/util/thread_bundle.h>
#include <vespa/log/log.h>
#include <cmath>

LOG_SETUP(".proton.matching.match_thread");

namespace proton {
namespace matching {

namespace {

using search::fef::FeatureHandle;
using search::fef::IllegalHandle;
using search::fef::RankProgram;

const double *get_score_feature(const RankProgram &rankProgram) {
    std::vector<vespalib::string> featureNames;
    std::vector<FeatureHandle> featureHandles;
    rankProgram.get_seed_handles(featureNames, featureHandles);
    assert(featureNames.size() == 1);
    assert(featureHandles.size() == 1);
    return rankProgram.match_data().resolveFeature(featureHandles.front());
}

}

using vespalib::Doom;
using search::queryeval::OptimizedAndNotForBlackListing;

template <typename IteratorT, bool do_rank, bool do_limit, bool do_share_work>
void
MatchThread::match_loop(MatchTools &matchTools, IteratorT search,
                        RankProgram &ranking, HitCollector &hits)
{
    const Doom &doom = matchTools.doom();
    const double *score_feature = do_rank ? get_score_feature(ranking) : nullptr;
    uint32_t matches = 0;
    uint32_t matches_limit = (do_limit) ? matchTools.match_limiter().sample_hits_per_thread(num_threads) : 0;
    IdleObserver idle_observer = scheduler.make_idle_observer();
    for (DocidRange docid_range = scheduler.first_range(thread_id);
         !docid_range.empty();
         docid_range = scheduler.next_range(thread_id))
    {
        search->initRange(docid_range.begin, docid_range.end);
        uint32_t docId = search->seekFirst(docid_range.begin);
        while ((docId < docid_range.end) && !doom.doom()) {
            if (do_rank) {
                search->unpack(docId);
                ranking.run(docId);
                double score = *score_feature;
                // convert NaN and Inf scores to -Inf
                if (__builtin_expect(std::isnan(score) || std::isinf(score), false)) {
                    score = -HUGE_VAL;
                }
                // invert test since default drop limit is -NaN (keep all hits)
                if (!(score <= matchParams.rankDropLimit)) {
                    hits.addHit(docId, score);
                }
            } else {
                hits.addHit(docId, 0.0);
            }
            ++matches;
            if (do_limit && matches == matches_limit) {
                const size_t local_todo = (docid_range.end - docId - 1);
                const size_t searchedSoFar = (scheduler.total_size(thread_id) - local_todo);
                IMatchLoopCommunicator::Matches my_matches(matches, searchedSoFar);
                WaitTimer count_matches_timer(wait_time_s);
                double match_freq = communicator.estimate_match_frequency(my_matches);
                const size_t global_todo = scheduler.unassigned_size();
                count_matches_timer.done();
                search.reset(matchTools.match_limiter().maybe_limit(SearchIterator::UP(search.release()),
                                match_freq,
                                matchParams.numDocs).release());
                matchTools.match_limiter().updateDocIdSpaceEstimate(searchedSoFar, local_todo + (global_todo / num_threads));
                LOG(debug, "Limit=%d has been reached at docid=%d which is after %zu docs.",
                    matches, docId, searchedSoFar);
                LOG(debug, "SearchIterator after limiter: %s", search->asString().c_str());
                docId = search->seekFirst(docId + 1);
            } else if (do_share_work && (idle_observer.get() > 0)) {
                DocidRange todo(docId + 1, docid_range.end);
                DocidRange my_work = scheduler.share_range(thread_id, todo);
                if (my_work.end < todo.end) {
                    docid_range = my_work;
                    search->initRange(docid_range.begin, docid_range.end);
                    docId = search->seekFirst(docid_range.begin);
                } else {
                    docId = search->seekNext(docId + 1);
                }
            } else {
                docId = search->seekNext(docId + 1);
            }
        }
    }
    if (do_limit && matches < matches_limit) {
        IMatchLoopCommunicator::Matches my_matches(matches, scheduler.total_size(thread_id));
        WaitTimer count_matches_timer(wait_time_s);
        LOG(debug, "Limit not reached (had %d) at docid=%d which is after %zu docs.",
            matches, scheduler.total_span(thread_id).end, scheduler.total_size(thread_id));
        communicator.estimate_match_frequency(my_matches); // for other threads
        matchTools.match_limiter().updateDocIdSpaceEstimate(scheduler.total_size(thread_id), 0);
        count_matches_timer.done();
    }
    thread_stats.docsMatched(matches);
    if (do_rank) {
        thread_stats.docsRanked(matches);
    }
}

template <typename IteratorT, bool do_rank, bool do_limit>
void
MatchThread::match_loop_helper_2(MatchTools &matchTools, IteratorT search,
                                 RankProgram &ranking, HitCollector &hits)
{
    if (scheduler.make_idle_observer().is_always_zero()) {
        match_loop<IteratorT, do_rank, do_limit, false>(matchTools, std::move(search), ranking, hits);
    } else {
        match_loop<IteratorT, do_rank, do_limit, true>(matchTools, std::move(search), ranking, hits);
    }
}

template <typename IteratorT, bool do_rank>
void
MatchThread::match_loop_helper(MatchTools &matchTools, IteratorT search,
                               RankProgram &ranking, HitCollector &hits)
{
    if (matchTools.match_limiter().is_enabled()) {
        match_loop_helper_2<IteratorT, do_rank, true>(matchTools, std::move(search), ranking, hits);
    } else {
        match_loop_helper_2<IteratorT, do_rank, false>(matchTools, std::move(search), ranking, hits);
    }
}

using search::fef::TermFieldHandle;
using search::fef::MatchData;

class FastSeekWrapper
{
private:
    typedef search::queryeval::SearchIterator SearchIterator;
public:
    FastSeekWrapper(SearchIterator::UP iterator)
    {
        reset(iterator.release());
    }
    void initRange(uint32_t begin_id, uint32_t end_id) {
        _search->initRange(begin_id, end_id);
    }
    uint32_t seekFirst(uint32_t docId) {
        return _search->seekFirst(docId);
    }
    uint32_t seekNext(uint32_t docId) {
        return _search->seekFast(docId);
    }
    vespalib::string asString() const {
        return _search->asString();
    }
    void unpack(uint32_t docId) {
        _search->unpack(docId);
    }
    void reset(SearchIterator * search) {
        _search.reset(&dynamic_cast<OptimizedAndNotForBlackListing &>(*search));
    }
    OptimizedAndNotForBlackListing * release() {
        return _search.release();
    }
    FastSeekWrapper * operator ->() { return this; }
private:
    std::unique_ptr<OptimizedAndNotForBlackListing> _search;
};

MatchThread::MatchThread(size_t thread_id_in,
                         size_t num_threads_in,
                         const MatchParams &mp,
                         const MatchToolsFactory &mtf,
                         IMatchLoopCommunicator &com,
                         DocidRangeScheduler &sched,
                         ResultProcessor &rp,
                         vespalib::DualMergeDirector &md,
                         uint32_t distributionKey) :
    thread_id(thread_id_in),
    num_threads(num_threads_in),
    matchParams(mp),
    matchToolsFactory(mtf),
    communicator(com),
    scheduler(sched),
    _distributionKey(distributionKey),
    resultProcessor(rp),
    mergeDirector(md),
    resultContext(),
    thread_stats(),
    total_time_s(0.0),
    match_time_s(0.0),
    wait_time_s(0.0)
{
}

search::ResultSet::UP
MatchThread::findMatches(MatchTools &matchTools)
{
    const Doom &doom = matchTools.doom();
    RankProgram::UP ranking = matchTools.first_phase_program();
    SearchIterator::UP search = matchTools.createSearch(ranking->match_data());
    LOG(debug, "SearchIterator: %s", search->asString().c_str());
    search = search::queryeval::MultiBitVectorIteratorBase::optimize(std::move(search));
    LOG(debug, "SearchIterator after MultiBitVectorIteratorBase::optimize(): %s", search->asString().c_str());
    HitCollector hits(matchParams.numDocs, matchParams.arraySize, matchParams.heapSize);
    if (matchTools.has_first_phase_rank() && ((matchParams.arraySize + matchParams.heapSize) != 0)) {
        match_loop_helper<SearchIterator::UP, true>(matchTools, std::move(search), *ranking, hits);
    } else {
        if ((dynamic_cast<const OptimizedAndNotForBlackListing *>(search.get()) != 0) &&
            ! matchTools.match_limiter().is_enabled())  // We cannot replace the iterator if we inline the loop.
        {
            match_loop_helper<FastSeekWrapper, false>(matchTools, FastSeekWrapper(std::move(search)), *ranking, hits);
        } else {
            match_loop_helper<SearchIterator::UP, false>(matchTools, std::move(search), *ranking, hits);
        }
    }
    if (matchTools.has_second_phase_rank()) {
        { // 2nd phase ranking
            ranking = matchTools.second_phase_program();
            search = matchTools.createSearch(ranking->match_data());
            DocidRange docid_range = scheduler.total_span(thread_id);
            search->initRange(docid_range.begin, docid_range.end);
            auto sorted_scores = hits.getSortedHeapScores();
            WaitTimer select_best_timer(wait_time_s);
            size_t useHits = communicator.selectBest(sorted_scores);
            select_best_timer.done();
            DocumentScorer scorer(*ranking, *search);
            uint32_t reRanked = hits.reRank(scorer, doom.doom() ? 0 : useHits);
            thread_stats.docsReRanked(reRanked);
        }
        { // rank scaling
            auto my_ranges = hits.getRanges();
            WaitTimer range_cover_timer(wait_time_s);
            auto ranges = communicator.rangeCover(my_ranges);
            range_cover_timer.done();
            hits.setRanges(ranges);
        }
    }
    return hits.getResultSet();
}

void
MatchThread::processResult(const Doom & doom,
                           search::ResultSet::UP result,
                           ResultProcessor::Context &context)
{
    if (doom.doom()) return;
    bool hasGrouping = (context.grouping.get() != 0);
    if (context.sort->hasSortData() || hasGrouping) {
        result->mergeWithBitOverflow();
    }
    if (doom.doom()) return;
    size_t             totalHits = result->getNumHits();
    search::RankedHit *hits      = result->getArray();
    size_t             numHits   = result->getArrayUsed();
    search::BitVector *bits  = result->getBitOverflow();
    if (bits != nullptr && hits != nullptr) {
        bits->andNotWithT(search::RankedHitIterator(hits, numHits));
    }
    if (doom.doom()) return;
    if (hasGrouping) {
        search::grouping::GroupingManager man(*context.grouping);
        man.groupUnordered(hits, numHits, bits);
    }
    if (doom.doom()) return;
    size_t sortLimit = hasGrouping ? numHits : context.result->maxSize();
    context.sort->sorter->sortResults(hits, numHits, sortLimit);
    if (doom.doom()) return;
    if (hasGrouping) {
        search::grouping::GroupingManager man(*context.grouping);
        man.groupInRelevanceOrder(hits, numHits);
    }
    if (doom.doom()) return;
    PartialResult &pr = *context.result;
    pr.totalHits(totalHits);
    size_t maxHits = std::min(numHits, pr.maxSize());
    if (pr.hasSortData()) {
        FastS_SortSpec &spec = context.sort->sortSpec;
        for (size_t i = 0; i < maxHits; ++i) {
            pr.add(hits[i], spec.getSortRef(i));
        }
    } else {
        for (size_t i = 0; i < maxHits; ++i) {
            pr.add(hits[i]);
        }
        if ((bits != nullptr) && (pr.size() < pr.maxSize())) {
            for (unsigned int bitId = bits->getFirstTrueBit();
                 (bitId < bits->size()) && (pr.size() < pr.maxSize());
                 bitId = bits->getNextTrueBit(bitId + 1))
            {
                pr.add(search::RankedHit(bitId));
            }
        }
    }
    if (hasGrouping) {
        context.grouping->setDistributionKey(_distributionKey);
    }
}

void
MatchThread::run()
{
    fastos::StopWatch total_time;
    fastos::StopWatch match_time;
    total_time.start();
    match_time.start();
    MatchTools::UP matchTools = matchToolsFactory.createMatchTools();
    search::ResultSet::UP result = findMatches(*matchTools);
    match_time.stop();
    match_time_s = match_time.elapsed().sec();
    resultContext = resultProcessor.createThreadContext(matchTools->doom(), thread_id);
    {
        WaitTimer get_token_timer(wait_time_s);
        QueryLimiter::Token::UP processToken(
                matchTools->getQueryLimiter().getToken(matchTools->doom(),
                        scheduler.total_size(thread_id),
                        result->getNumHits(),
                        resultContext->sort->hasSortData(),
                        resultContext->grouping.get() != 0));
        get_token_timer.done();
        processResult(matchTools->doom(), std::move(result), *resultContext);
    }
    total_time.stop();
    total_time_s = total_time.elapsed().sec();
    thread_stats.active_time(total_time_s - wait_time_s).wait_time(wait_time_s);
    mergeDirector.dualMerge(thread_id, *resultContext->result, resultContext->groupingSource);
}

} // namespace proton::matching
} // namespace proton
<commit_msg>Add spam logging of ranges searched.<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/fastos/fastos.h>
#include "match_thread.h"
#include "match_tools.h"
#include "handlerecorder.h"
#include "i_match_loop_communicator.h"
#include "matching_stats.h"
#include "document_scorer.h"
#include <memory>
#include <vespa/searchlib/common/featureset.h>
#include <vespa/searchlib/common/resultset.h>
#include <vespa/searchlib/fef/fef.h>
#include <vespa/searchlib/query/base.h>
#include <vespa/searchlib/queryeval/hitcollector.h>
#include <vespa/searchlib/queryeval/searchiterator.h>
#include <vespa/searchlib/queryeval/multibitvectoriterator.h>
#include <vespa/searchlib/queryeval/andnotsearch.h>
#include <vespa/vespalib/util/clock.h>
#include <vespa/vespalib/util/closure.h>
#include <vespa/vespalib/util/thread_bundle.h>
#include <vespa/log/log.h>
#include <cmath>

LOG_SETUP(".proton.matching.match_thread");

namespace proton {
namespace matching {

namespace {

using search::fef::FeatureHandle;
using search::fef::IllegalHandle;
using search::fef::RankProgram;

const double *get_score_feature(const RankProgram &rankProgram) {
    std::vector<vespalib::string> featureNames;
    std::vector<FeatureHandle> featureHandles;
    rankProgram.get_seed_handles(featureNames, featureHandles);
    assert(featureNames.size() == 1);
    assert(featureHandles.size() == 1);
    return rankProgram.match_data().resolveFeature(featureHandles.front());
}

}

using vespalib::Doom;
using search::queryeval::OptimizedAndNotForBlackListing;

template <typename IteratorT, bool do_rank, bool do_limit, bool do_share_work>
void
MatchThread::match_loop(MatchTools &matchTools, IteratorT search,
                        RankProgram &ranking, HitCollector &hits)
{
    const Doom &doom = matchTools.doom();
    const double *score_feature = do_rank ? get_score_feature(ranking) : nullptr;
    uint32_t matches = 0;
    uint32_t matches_limit = (do_limit) ? matchTools.match_limiter().sample_hits_per_thread(num_threads) : 0;
    IdleObserver idle_observer = scheduler.make_idle_observer();
    for (DocidRange docid_range = scheduler.first_range(thread_id);
         !docid_range.empty();
         docid_range = scheduler.next_range(thread_id))
    {
        LOG(spam, "Thread %d Evaluating range [%d, %d]", thread_id, docid_range.begin, docid_range.end);
        search->initRange(docid_range.begin, docid_range.end);
        uint32_t docId = search->seekFirst(docid_range.begin);
        while ((docId < docid_range.end) && !doom.doom()) {
            if (do_rank) {
                search->unpack(docId);
                ranking.run(docId);
                double score = *score_feature;
                // convert NaN and Inf scores to -Inf
                if (__builtin_expect(std::isnan(score) || std::isinf(score), false)) {
                    score = -HUGE_VAL;
                }
                // invert test since default drop limit is -NaN (keep all hits)
                if (!(score <= matchParams.rankDropLimit)) {
                    hits.addHit(docId, score);
                }
            } else {
                hits.addHit(docId, 0.0);
            }
            ++matches;
            if (do_limit && matches == matches_limit) {
                const size_t local_todo = (docid_range.end - docId - 1);
                const size_t searchedSoFar = (scheduler.total_size(thread_id) - local_todo);
                IMatchLoopCommunicator::Matches my_matches(matches, searchedSoFar);
                WaitTimer count_matches_timer(wait_time_s);
                double match_freq = communicator.estimate_match_frequency(my_matches);
                const size_t global_todo = scheduler.unassigned_size();
                count_matches_timer.done();
                search.reset(matchTools.match_limiter().maybe_limit(SearchIterator::UP(search.release()),
                                match_freq,
                                matchParams.numDocs).release());
                matchTools.match_limiter().updateDocIdSpaceEstimate(searchedSoFar, local_todo + (global_todo / num_threads));
                LOG(debug, "Limit=%d has been reached at docid=%d which is after %zu docs.",
                    matches, docId, searchedSoFar);
                LOG(debug, "SearchIterator after limiter: %s", search->asString().c_str());
                docId = search->seekFirst(docId + 1);
            } else if (do_share_work && (idle_observer.get() > 0)) {
                DocidRange todo(docId + 1, docid_range.end);
                DocidRange my_work = scheduler.share_range(thread_id, todo);
                LOG(spam, "Thread %d Share range([%d, %d]) = [%d, %d]", thread_id, todo.begin, todo.end, my_work.begin, my_work.end);
                if (my_work.end < todo.end) {
                    docid_range = my_work;
                    search->initRange(docid_range.begin, docid_range.end);
                    docId = search->seekFirst(docid_range.begin);
                } else {
                    docId = search->seekNext(docId + 1);
                }
            } else {
                docId = search->seekNext(docId + 1);
            }
        }
    }
    if (do_limit && matches < matches_limit) {
        IMatchLoopCommunicator::Matches my_matches(matches, scheduler.total_size(thread_id));
        WaitTimer count_matches_timer(wait_time_s);
        LOG(debug, "Limit not reached (had %d) at docid=%d which is after %zu docs.",
            matches, scheduler.total_span(thread_id).end, scheduler.total_size(thread_id));
        communicator.estimate_match_frequency(my_matches); // for other threads
        matchTools.match_limiter().updateDocIdSpaceEstimate(scheduler.total_size(thread_id), 0);
        count_matches_timer.done();
    }
    thread_stats.docsMatched(matches);
    if (do_rank) {
        thread_stats.docsRanked(matches);
    }
}

template <typename IteratorT, bool do_rank, bool do_limit>
void
MatchThread::match_loop_helper_2(MatchTools &matchTools, IteratorT search,
                                 RankProgram &ranking, HitCollector &hits)
{
    if (scheduler.make_idle_observer().is_always_zero()) {
        match_loop<IteratorT, do_rank, do_limit, false>(matchTools, std::move(search), ranking, hits);
    } else {
        match_loop<IteratorT, do_rank, do_limit, true>(matchTools, std::move(search), ranking, hits);
    }
}

template <typename IteratorT, bool do_rank>
void
MatchThread::match_loop_helper(MatchTools &matchTools, IteratorT search,
                               RankProgram &ranking, HitCollector &hits)
{
    if (matchTools.match_limiter().is_enabled()) {
        match_loop_helper_2<IteratorT, do_rank, true>(matchTools, std::move(search), ranking, hits);
    } else {
        match_loop_helper_2<IteratorT, do_rank, false>(matchTools, std::move(search), ranking, hits);
    }
}

using search::fef::TermFieldHandle;
using search::fef::MatchData;

class FastSeekWrapper
{
private:
    typedef search::queryeval::SearchIterator SearchIterator;
public:
    FastSeekWrapper(SearchIterator::UP iterator)
    {
        reset(iterator.release());
    }
    void initRange(uint32_t begin_id, uint32_t end_id) {
        _search->initRange(begin_id, end_id);
    }
    uint32_t seekFirst(uint32_t docId) {
        return _search->seekFirst(docId);
    }
    uint32_t seekNext(uint32_t docId) {
        return _search->seekFast(docId);
    }
    vespalib::string asString() const {
        return _search->asString();
    }
    void unpack(uint32_t docId) {
        _search->unpack(docId);
    }
    void reset(SearchIterator * search) {
        _search.reset(&dynamic_cast<OptimizedAndNotForBlackListing &>(*search));
    }
    OptimizedAndNotForBlackListing * release() {
        return _search.release();
    }
    FastSeekWrapper * operator ->() { return this; }
private:
    std::unique_ptr<OptimizedAndNotForBlackListing> _search;
};

MatchThread::MatchThread(size_t thread_id_in,
                         size_t num_threads_in,
                         const MatchParams &mp,
                         const MatchToolsFactory &mtf,
                         IMatchLoopCommunicator &com,
                         DocidRangeScheduler &sched,
                         ResultProcessor &rp,
                         vespalib::DualMergeDirector &md,
                         uint32_t distributionKey) :
    thread_id(thread_id_in),
    num_threads(num_threads_in),
    matchParams(mp),
    matchToolsFactory(mtf),
    communicator(com),
    scheduler(sched),
    _distributionKey(distributionKey),
    resultProcessor(rp),
    mergeDirector(md),
    resultContext(),
    thread_stats(),
    total_time_s(0.0),
    match_time_s(0.0),
    wait_time_s(0.0)
{
}

search::ResultSet::UP
MatchThread::findMatches(MatchTools &matchTools)
{
    const Doom &doom = matchTools.doom();
    RankProgram::UP ranking = matchTools.first_phase_program();
    SearchIterator::UP search = matchTools.createSearch(ranking->match_data());
    LOG(debug, "SearchIterator: %s", search->asString().c_str());
    search = search::queryeval::MultiBitVectorIteratorBase::optimize(std::move(search));
    LOG(debug, "SearchIterator after MultiBitVectorIteratorBase::optimize(): %s", search->asString().c_str());
    HitCollector hits(matchParams.numDocs, matchParams.arraySize, matchParams.heapSize);
    if (matchTools.has_first_phase_rank() && ((matchParams.arraySize + matchParams.heapSize) != 0)) {
        match_loop_helper<SearchIterator::UP, true>(matchTools, std::move(search), *ranking, hits);
    } else {
        if ((dynamic_cast<const OptimizedAndNotForBlackListing *>(search.get()) != 0) &&
            ! matchTools.match_limiter().is_enabled())  // We cannot replace the iterator if we inline the loop.
        {
            match_loop_helper<FastSeekWrapper, false>(matchTools, FastSeekWrapper(std::move(search)), *ranking, hits);
        } else {
            match_loop_helper<SearchIterator::UP, false>(matchTools, std::move(search), *ranking, hits);
        }
    }
    if (matchTools.has_second_phase_rank()) {
        { // 2nd phase ranking
            ranking = matchTools.second_phase_program();
            search = matchTools.createSearch(ranking->match_data());
            DocidRange docid_range = scheduler.total_span(thread_id);
            search->initRange(docid_range.begin, docid_range.end);
            auto sorted_scores = hits.getSortedHeapScores();
            WaitTimer select_best_timer(wait_time_s);
            size_t useHits = communicator.selectBest(sorted_scores);
            select_best_timer.done();
            DocumentScorer scorer(*ranking, *search);
            uint32_t reRanked = hits.reRank(scorer, doom.doom() ? 0 : useHits);
            thread_stats.docsReRanked(reRanked);
        }
        { // rank scaling
            auto my_ranges = hits.getRanges();
            WaitTimer range_cover_timer(wait_time_s);
            auto ranges = communicator.rangeCover(my_ranges);
            range_cover_timer.done();
            hits.setRanges(ranges);
        }
    }
    return hits.getResultSet();
}

void
MatchThread::processResult(const Doom & doom,
                           search::ResultSet::UP result,
                           ResultProcessor::Context &context)
{
    if (doom.doom()) return;
    bool hasGrouping = (context.grouping.get() != 0);
    if (context.sort->hasSortData() || hasGrouping) {
        result->mergeWithBitOverflow();
    }
    if (doom.doom()) return;
    size_t             totalHits = result->getNumHits();
    search::RankedHit *hits      = result->getArray();
    size_t             numHits   = result->getArrayUsed();
    search::BitVector *bits  = result->getBitOverflow();
    if (bits != nullptr && hits != nullptr) {
        bits->andNotWithT(search::RankedHitIterator(hits, numHits));
    }
    if (doom.doom()) return;
    if (hasGrouping) {
        search::grouping::GroupingManager man(*context.grouping);
        man.groupUnordered(hits, numHits, bits);
    }
    if (doom.doom()) return;
    size_t sortLimit = hasGrouping ? numHits : context.result->maxSize();
    context.sort->sorter->sortResults(hits, numHits, sortLimit);
    if (doom.doom()) return;
    if (hasGrouping) {
        search::grouping::GroupingManager man(*context.grouping);
        man.groupInRelevanceOrder(hits, numHits);
    }
    if (doom.doom()) return;
    PartialResult &pr = *context.result;
    pr.totalHits(totalHits);
    size_t maxHits = std::min(numHits, pr.maxSize());
    if (pr.hasSortData()) {
        FastS_SortSpec &spec = context.sort->sortSpec;
        for (size_t i = 0; i < maxHits; ++i) {
            pr.add(hits[i], spec.getSortRef(i));
        }
    } else {
        for (size_t i = 0; i < maxHits; ++i) {
            pr.add(hits[i]);
        }
        if ((bits != nullptr) && (pr.size() < pr.maxSize())) {
            for (unsigned int bitId = bits->getFirstTrueBit();
                 (bitId < bits->size()) && (pr.size() < pr.maxSize());
                 bitId = bits->getNextTrueBit(bitId + 1))
            {
                pr.add(search::RankedHit(bitId));
            }
        }
    }
    if (hasGrouping) {
        context.grouping->setDistributionKey(_distributionKey);
    }
}

void
MatchThread::run()
{
    fastos::StopWatch total_time;
    fastos::StopWatch match_time;
    total_time.start();
    match_time.start();
    MatchTools::UP matchTools = matchToolsFactory.createMatchTools();
    search::ResultSet::UP result = findMatches(*matchTools);
    match_time.stop();
    match_time_s = match_time.elapsed().sec();
    resultContext = resultProcessor.createThreadContext(matchTools->doom(), thread_id);
    {
        WaitTimer get_token_timer(wait_time_s);
        QueryLimiter::Token::UP processToken(
                matchTools->getQueryLimiter().getToken(matchTools->doom(),
                        scheduler.total_size(thread_id),
                        result->getNumHits(),
                        resultContext->sort->hasSortData(),
                        resultContext->grouping.get() != 0));
        get_token_timer.done();
        processResult(matchTools->doom(), std::move(result), *resultContext);
    }
    total_time.stop();
    total_time_s = total_time.elapsed().sec();
    thread_stats.active_time(total_time_s - wait_time_s).wait_time(wait_time_s);
    mergeDirector.dualMerge(thread_id, *resultContext->result, resultContext->groupingSource);
}

} // namespace proton::matching
} // namespace proton
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "indexflushtarget.h"
#include <vespa/vespalib/util/size_literals.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchcorespi.index.indexflushtarget");

namespace searchcorespi::index {

IndexFlushTarget::IndexFlushTarget(IndexMaintainer &indexMaintainer, IndexMaintainer::FlushStats flushStats)
    : IFlushTarget("memoryindex.flush", Type::FLUSH, Component::INDEX),
      _indexMaintainer(indexMaintainer),
      _flushStats(flushStats),
      _numFrozenMemoryIndexes(indexMaintainer.getNumFrozenMemoryIndexes()),
      _maxFrozenMemoryIndexes(indexMaintainer.getMaxFrozenMemoryIndexes()),
      _lastStats()
{
    _lastStats.setPathElementsToLog(7);
}

IndexFlushTarget::IndexFlushTarget(IndexMaintainer &indexMaintainer)
    : IndexFlushTarget(indexMaintainer, indexMaintainer.getFlushStats())
{}

IndexFlushTarget::~IndexFlushTarget() = default;

IFlushTarget::MemoryGain
IndexFlushTarget::getApproxMemoryGain() const
{
    return MemoryGain(_flushStats.memory_before_bytes, _flushStats.memory_after_bytes);
}

IFlushTarget::DiskGain
IndexFlushTarget::getApproxDiskGain() const
{
    return DiskGain(0, 0);
}

bool
IndexFlushTarget::needUrgentFlush() const
{
    // Due to limitation of 16G address space of single datastore
    // TODO: Even better if urgency was decided by memory index itself.
    constexpr int64_t G =1_Gi;
    bool urgent = (_numFrozenMemoryIndexes > _maxFrozenMemoryIndexes) ||
                  (getApproxMemoryGain().gain() > 16*G);
    SerialNum flushedSerial = _indexMaintainer.getFlushedSerialNum();
    LOG(debug, "Num frozen: %u Memory gain: %ld Urgent: %d, flushedSerial=%" PRIu64,
        _numFrozenMemoryIndexes, getApproxMemoryGain().gain(), static_cast<int>(urgent), flushedSerial);
    return urgent;
}

IFlushTarget::Time
IndexFlushTarget::getLastFlushTime() const
{
    return _indexMaintainer.getLastFlushTime();
}

IFlushTarget::SerialNum
IndexFlushTarget::getFlushedSerialNum() const
{
    return _indexMaintainer.getFlushedSerialNum();
}

IFlushTarget::Task::UP
IndexFlushTarget::initFlush(SerialNum serialNum, std::shared_ptr<search::IFlushToken>)
{
    // the target must live until this task is done (handled by flush engine).
    return _indexMaintainer.initFlush(serialNum, &_lastStats);
}

uint64_t
IndexFlushTarget::getApproxBytesToWriteToDisk() const
{
    MemoryGain gain(_flushStats.memory_before_bytes, _flushStats.memory_after_bytes);
    if (gain.getAfter() < gain.getBefore()) {
        return gain.getBefore() - gain.getAfter();
    } else {
        return 0;
    }
}

}
<commit_msg>use 16_Gi directly<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "indexflushtarget.h"
#include <vespa/vespalib/util/size_literals.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchcorespi.index.indexflushtarget");

namespace searchcorespi::index {

IndexFlushTarget::IndexFlushTarget(IndexMaintainer &indexMaintainer, IndexMaintainer::FlushStats flushStats)
    : IFlushTarget("memoryindex.flush", Type::FLUSH, Component::INDEX),
      _indexMaintainer(indexMaintainer),
      _flushStats(flushStats),
      _numFrozenMemoryIndexes(indexMaintainer.getNumFrozenMemoryIndexes()),
      _maxFrozenMemoryIndexes(indexMaintainer.getMaxFrozenMemoryIndexes()),
      _lastStats()
{
    _lastStats.setPathElementsToLog(7);
}

IndexFlushTarget::IndexFlushTarget(IndexMaintainer &indexMaintainer)
    : IndexFlushTarget(indexMaintainer, indexMaintainer.getFlushStats())
{}

IndexFlushTarget::~IndexFlushTarget() = default;

IFlushTarget::MemoryGain
IndexFlushTarget::getApproxMemoryGain() const
{
    return MemoryGain(_flushStats.memory_before_bytes, _flushStats.memory_after_bytes);
}

IFlushTarget::DiskGain
IndexFlushTarget::getApproxDiskGain() const
{
    return DiskGain(0, 0);
}

bool
IndexFlushTarget::needUrgentFlush() const
{
    // Due to limitation of 16G address space of single datastore
    // TODO: Even better if urgency was decided by memory index itself.
    bool urgent = (_numFrozenMemoryIndexes > _maxFrozenMemoryIndexes) ||
                  (getApproxMemoryGain().gain() > ssize_t(16_Gi));
    SerialNum flushedSerial = _indexMaintainer.getFlushedSerialNum();
    LOG(debug, "Num frozen: %u Memory gain: %ld Urgent: %d, flushedSerial=%" PRIu64,
        _numFrozenMemoryIndexes, getApproxMemoryGain().gain(), static_cast<int>(urgent), flushedSerial);
    return urgent;
}

IFlushTarget::Time
IndexFlushTarget::getLastFlushTime() const
{
    return _indexMaintainer.getLastFlushTime();
}

IFlushTarget::SerialNum
IndexFlushTarget::getFlushedSerialNum() const
{
    return _indexMaintainer.getFlushedSerialNum();
}

IFlushTarget::Task::UP
IndexFlushTarget::initFlush(SerialNum serialNum, std::shared_ptr<search::IFlushToken>)
{
    // the target must live until this task is done (handled by flush engine).
    return _indexMaintainer.initFlush(serialNum, &_lastStats);
}

uint64_t
IndexFlushTarget::getApproxBytesToWriteToDisk() const
{
    MemoryGain gain(_flushStats.memory_before_bytes, _flushStats.memory_after_bytes);
    if (gain.getAfter() < gain.getBefore()) {
        return gain.getBefore() - gain.getAfter();
    } else {
        return 0;
    }
}

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: XMLPropertyBackpatcher.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 11:10:06 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif

#ifndef _RTL_USTRING
#include <rtl/ustring.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _XMLOFF_XMLPROPERTYBACKPATCHER_HXX
#include "XMLPropertyBackpatcher.hxx"
#endif

#ifndef _XMLOFF_TEXTIMP_HXX_
#include "txtimp.hxx"   // XMLTextImportHelper partially implemented here
#endif

using ::rtl::OUString;
using ::std::vector;
using ::std::map;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Any;
using ::com::sun::star::beans::XPropertySet;

template<class A>
XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
    const ::rtl::OUString& sPropName)
:   sPropertyName(sPropName)
,   bDefaultHandling(sal_False)
,   bPreserveProperty(sal_False)
,   sPreservePropertyName()
{
}

template<class A>
XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
    const OUString& sPropName,
    const OUString& sPreserveName,
    sal_Bool bDefault,
    A aDef)
:   sPropertyName(sPropName)
,   bDefaultHandling(bDefault)
,   bPreserveProperty(sPreserveName.getLength()>0)
,   sPreservePropertyName(sPreserveName)
,   aDefault(aDef)
{
}

template<class A>
XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
    const sal_Char* pPropName)
:   bDefaultHandling(sal_False)
,   bPreserveProperty(sal_False)
{
    DBG_ASSERT(pPropName != NULL, "need property name");
    sPropertyName = OUString::createFromAscii(pPropName);
}

template<class A>
XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
    const sal_Char* pPropName,
    const sal_Char* pPreservePropName,
    sal_Bool bDefault,
    A aDef)
:   bDefaultHandling(bDefault)
,   bPreserveProperty(pPreservePropName != NULL)
,   aDefault(aDef)
{
    DBG_ASSERT(pPropName != NULL, "need property name");
    sPropertyName = OUString::createFromAscii(pPropName);
    if (pPreservePropName != NULL)
    {
        sPreservePropertyName = OUString::createFromAscii(pPreservePropName);
    }
}

template<class A>
XMLPropertyBackpatcher<A>::~XMLPropertyBackpatcher()
{
    SetDefault();
}

template<class A>
void XMLPropertyBackpatcher<A>::ResolveId(
    const OUString& sName,
    A aValue)
{
    // insert ID into ID map
    aIDMap[sName] = aValue;

    // backpatch old references, if backpatch list exists
    if (aBackpatchListMap.count(sName))
    {
        // aah, we have a backpatch list!
        BackpatchListType* pList =
            (BackpatchListType*)aBackpatchListMap[sName];

        // a) remove list from list map
        aBackpatchListMap.erase(sName);

        // b) for every item, set SequenceNumber
        //    (and preserve Property, if appropriate)
        Any aAny;
        aAny <<= aValue;
        if (bPreserveProperty)
        {
            // preserve version
            for(BackpatchListType::iterator aIter = pList->begin();
                aIter != pList->end();
                aIter++)
            {
                Reference<XPropertySet> xProp = (*aIter);
                Any aPres = xProp->getPropertyValue(sPreservePropertyName);
                xProp->setPropertyValue(sPropertyName, aAny);
                xProp->setPropertyValue(sPreservePropertyName, aPres);
            }
        }
        else
        {
            // without preserve
            for(BackpatchListType::iterator aIter = pList->begin();
                aIter != pList->end();
                aIter++)
            {
                (*aIter)->setPropertyValue(sPropertyName, aAny);
            }
        }

        // c) delete list
        delete pList;
    }
    // else: no backpatch list -> then we're finished
}

template<class A>
void XMLPropertyBackpatcher<A>::SetProperty(
    const Reference<XPropertySet> & xPropSet,
    const OUString& sName)
{
    Reference<XPropertySet> xNonConstPropSet(xPropSet);
    SetProperty(xNonConstPropSet, sName);
}

template<class A>
void XMLPropertyBackpatcher<A>::SetProperty(
    Reference<XPropertySet> & xPropSet,
    const OUString& sName)
{
    if (aIDMap.count(sName))
    {
        // we know this ID -> set property
        Any aAny;
        aAny <<= aIDMap[sName];
        xPropSet->setPropertyValue(sPropertyName, aAny);
    }
    else
    {
        // ID unknown -> into backpatch list for later fixup
        if (! aBackpatchListMap.count(sName))
        {
            // create backpatch list for this name
            BackpatchListType* pTmp = new BackpatchListType() ;
            aBackpatchListMap[sName] = (void*)pTmp;
        }

        // insert footnote
        ((BackpatchListType*)aBackpatchListMap[sName])->push_back(xPropSet);
    }
}

template<class A>
void XMLPropertyBackpatcher<A>::SetDefault()
{
    if (bDefaultHandling)
    {
        // not implemented yet
    }
}

// force instantiation of templates
template class XMLPropertyBackpatcher<sal_Int16>;
template class XMLPropertyBackpatcher<OUString>;

//
// XMLTextImportHelper
//
// Code from XMLTextImportHelper using the XMLPropertyBackpatcher is
// implemented here. The reason is that in the unxsols2 environment,
// all templates are instatiated as file local (switch
// -instances=static), and thus are not accessible from the outside.
//
// The previous solution was to force additional instantiation of
// XMLPropertyBackpatcher in txtimp.cxx. This solution combines all
// usage of the XMLPropertyBackpatcher in XMLPropertyBackpatcher.cxx
// instead.
//

XMLPropertyBackpatcher<sal_Int16>& XMLTextImportHelper::GetFootnoteBP()
{
    if (NULL == pFootnoteBackpatcher)
    {
        pFootnoteBackpatcher =
            new XMLPropertyBackpatcher<sal_Int16>(sSequenceNumber);
    }
    return *pFootnoteBackpatcher;
}

XMLPropertyBackpatcher<sal_Int16>& XMLTextImportHelper::GetSequenceIdBP()
{
    if (NULL == pSequenceIdBackpatcher)
    {
        pSequenceIdBackpatcher =
            new XMLPropertyBackpatcher<sal_Int16>(sSequenceNumber);
    }
    return *pSequenceIdBackpatcher;
}

XMLPropertyBackpatcher<OUString>& XMLTextImportHelper::GetSequenceNameBP()
{
    if (NULL == pSequenceNameBackpatcher)
    {
        pSequenceNameBackpatcher =
            new XMLPropertyBackpatcher<OUString>(sSourceName);
    }
    return *pSequenceNameBackpatcher;
}

void XMLTextImportHelper::InsertFootnoteID(
    const OUString& sXMLId,
    sal_Int16 nAPIId)
{
    GetFootnoteBP().ResolveId(sXMLId, nAPIId);
}

void XMLTextImportHelper::ProcessFootnoteReference(
    const OUString& sXMLId,
    const Reference<XPropertySet> & xPropSet)
{
    GetFootnoteBP().SetProperty(xPropSet, sXMLId);
}

void XMLTextImportHelper::InsertSequenceID(
    const OUString& sXMLId,
    const OUString& sName,
    sal_Int16 nAPIId)
{
    GetSequenceIdBP().ResolveId(sXMLId, nAPIId);
    GetSequenceNameBP().ResolveId(sXMLId, sName);
}

void XMLTextImportHelper::ProcessSequenceReference(
    const OUString& sXMLId,
    const Reference<XPropertySet> & xPropSet)
{
    GetSequenceIdBP().SetProperty(xPropSet, sXMLId);
    GetSequenceNameBP().SetProperty(xPropSet, sXMLId);
}

void XMLTextImportHelper::_FinitBackpatcher()
{
    delete pFootnoteBackpatcher;
    delete pSequenceIdBackpatcher;
    delete pSequenceNameBackpatcher;
}
<commit_msg>INTEGRATION: CWS vgbugs07 (1.7.124); FILE MERGED 2007/06/04 13:23:38 vg 1.7.124.1: #i76605# Remove -I .../inc/module hack introduced by hedaburemove01<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: XMLPropertyBackpatcher.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 16:03:41 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif

#ifndef _RTL_USTRING
#include <rtl/ustring.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _XMLOFF_XMLPROPERTYBACKPATCHER_HXX
#include "XMLPropertyBackpatcher.hxx"
#endif

#ifndef _XMLOFF_TEXTIMP_HXX_
#include <xmloff/txtimp.hxx>    // XMLTextImportHelper partially implemented here
#endif

using ::rtl::OUString;
using ::std::vector;
using ::std::map;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Any;
using ::com::sun::star::beans::XPropertySet;

template<class A>
XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
    const ::rtl::OUString& sPropName)
:   sPropertyName(sPropName)
,   bDefaultHandling(sal_False)
,   bPreserveProperty(sal_False)
,   sPreservePropertyName()
{
}

template<class A>
XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
    const OUString& sPropName,
    const OUString& sPreserveName,
    sal_Bool bDefault,
    A aDef)
:   sPropertyName(sPropName)
,   bDefaultHandling(bDefault)
,   bPreserveProperty(sPreserveName.getLength()>0)
,   sPreservePropertyName(sPreserveName)
,   aDefault(aDef)
{
}

template<class A>
XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
    const sal_Char* pPropName)
:   bDefaultHandling(sal_False)
,   bPreserveProperty(sal_False)
{
    DBG_ASSERT(pPropName != NULL, "need property name");
    sPropertyName = OUString::createFromAscii(pPropName);
}

template<class A>
XMLPropertyBackpatcher<A>::XMLPropertyBackpatcher(
    const sal_Char* pPropName,
    const sal_Char* pPreservePropName,
    sal_Bool bDefault,
    A aDef)
:   bDefaultHandling(bDefault)
,   bPreserveProperty(pPreservePropName != NULL)
,   aDefault(aDef)
{
    DBG_ASSERT(pPropName != NULL, "need property name");
    sPropertyName = OUString::createFromAscii(pPropName);
    if (pPreservePropName != NULL)
    {
        sPreservePropertyName = OUString::createFromAscii(pPreservePropName);
    }
}

template<class A>
XMLPropertyBackpatcher<A>::~XMLPropertyBackpatcher()
{
    SetDefault();
}

template<class A>
void XMLPropertyBackpatcher<A>::ResolveId(
    const OUString& sName,
    A aValue)
{
    // insert ID into ID map
    aIDMap[sName] = aValue;

    // backpatch old references, if backpatch list exists
    if (aBackpatchListMap.count(sName))
    {
        // aah, we have a backpatch list!
        BackpatchListType* pList =
            (BackpatchListType*)aBackpatchListMap[sName];

        // a) remove list from list map
        aBackpatchListMap.erase(sName);

        // b) for every item, set SequenceNumber
        //    (and preserve Property, if appropriate)
        Any aAny;
        aAny <<= aValue;
        if (bPreserveProperty)
        {
            // preserve version
            for(BackpatchListType::iterator aIter = pList->begin();
                aIter != pList->end();
                aIter++)
            {
                Reference<XPropertySet> xProp = (*aIter);
                Any aPres = xProp->getPropertyValue(sPreservePropertyName);
                xProp->setPropertyValue(sPropertyName, aAny);
                xProp->setPropertyValue(sPreservePropertyName, aPres);
            }
        }
        else
        {
            // without preserve
            for(BackpatchListType::iterator aIter = pList->begin();
                aIter != pList->end();
                aIter++)
            {
                (*aIter)->setPropertyValue(sPropertyName, aAny);
            }
        }

        // c) delete list
        delete pList;
    }
    // else: no backpatch list -> then we're finished
}

template<class A>
void XMLPropertyBackpatcher<A>::SetProperty(
    const Reference<XPropertySet> & xPropSet,
    const OUString& sName)
{
    Reference<XPropertySet> xNonConstPropSet(xPropSet);
    SetProperty(xNonConstPropSet, sName);
}

template<class A>
void XMLPropertyBackpatcher<A>::SetProperty(
    Reference<XPropertySet> & xPropSet,
    const OUString& sName)
{
    if (aIDMap.count(sName))
    {
        // we know this ID -> set property
        Any aAny;
        aAny <<= aIDMap[sName];
        xPropSet->setPropertyValue(sPropertyName, aAny);
    }
    else
    {
        // ID unknown -> into backpatch list for later fixup
        if (! aBackpatchListMap.count(sName))
        {
            // create backpatch list for this name
            BackpatchListType* pTmp = new BackpatchListType() ;
            aBackpatchListMap[sName] = (void*)pTmp;
        }

        // insert footnote
        ((BackpatchListType*)aBackpatchListMap[sName])->push_back(xPropSet);
    }
}

template<class A>
void XMLPropertyBackpatcher<A>::SetDefault()
{
    if (bDefaultHandling)
    {
        // not implemented yet
    }
}

// force instantiation of templates
template class XMLPropertyBackpatcher<sal_Int16>;
template class XMLPropertyBackpatcher<OUString>;

//
// XMLTextImportHelper
//
// Code from XMLTextImportHelper using the XMLPropertyBackpatcher is
// implemented here. The reason is that in the unxsols2 environment,
// all templates are instatiated as file local (switch
// -instances=static), and thus are not accessible from the outside.
//
// The previous solution was to force additional instantiation of
// XMLPropertyBackpatcher in txtimp.cxx. This solution combines all
// usage of the XMLPropertyBackpatcher in XMLPropertyBackpatcher.cxx
// instead.
//

XMLPropertyBackpatcher<sal_Int16>& XMLTextImportHelper::GetFootnoteBP()
{
    if (NULL == pFootnoteBackpatcher)
    {
        pFootnoteBackpatcher =
            new XMLPropertyBackpatcher<sal_Int16>(sSequenceNumber);
    }
    return *pFootnoteBackpatcher;
}

XMLPropertyBackpatcher<sal_Int16>& XMLTextImportHelper::GetSequenceIdBP()
{
    if (NULL == pSequenceIdBackpatcher)
    {
        pSequenceIdBackpatcher =
            new XMLPropertyBackpatcher<sal_Int16>(sSequenceNumber);
    }
    return *pSequenceIdBackpatcher;
}

XMLPropertyBackpatcher<OUString>& XMLTextImportHelper::GetSequenceNameBP()
{
    if (NULL == pSequenceNameBackpatcher)
    {
        pSequenceNameBackpatcher =
            new XMLPropertyBackpatcher<OUString>(sSourceName);
    }
    return *pSequenceNameBackpatcher;
}

void XMLTextImportHelper::InsertFootnoteID(
    const OUString& sXMLId,
    sal_Int16 nAPIId)
{
    GetFootnoteBP().ResolveId(sXMLId, nAPIId);
}

void XMLTextImportHelper::ProcessFootnoteReference(
    const OUString& sXMLId,
    const Reference<XPropertySet> & xPropSet)
{
    GetFootnoteBP().SetProperty(xPropSet, sXMLId);
}

void XMLTextImportHelper::InsertSequenceID(
    const OUString& sXMLId,
    const OUString& sName,
    sal_Int16 nAPIId)
{
    GetSequenceIdBP().ResolveId(sXMLId, nAPIId);
    GetSequenceNameBP().ResolveId(sXMLId, sName);
}

void XMLTextImportHelper::ProcessSequenceReference(
    const OUString& sXMLId,
    const Reference<XPropertySet> & xPropSet)
{
    GetSequenceIdBP().SetProperty(xPropSet, sXMLId);
    GetSequenceNameBP().SetProperty(xPropSet, sXMLId);
}

void XMLTextImportHelper::_FinitBackpatcher()
{
    delete pFootnoteBackpatcher;
    delete pSequenceIdBackpatcher;
    delete pSequenceNameBackpatcher;
}
<|endoftext|>