<commit_before>#include "search_engine.hpp"

#include "categories_holder.hpp"
#include "geometry_utils.hpp"
#include "search_query.hpp"
#include "search_string_utils.hpp"

#include "storage/country_info_getter.hpp"

#include "indexer/classificator.hpp"
#include "indexer/scales.hpp"

#include "platform/platform.hpp"

#include "geometry/distance_on_sphere.hpp"
#include "geometry/mercator.hpp"

#include "base/logging.hpp"
#include "base/scope_guard.hpp"
#include "base/stl_add.hpp"

#include "std/algorithm.hpp"
#include "std/bind.hpp"
#include "std/map.hpp"
#include "std/vector.hpp"

#include "3party/Alohalytics/src/alohalytics.h"

namespace search
{
namespace
{
int const kResultsCount = 30;

class InitSuggestions
{
  using TSuggestMap = map<pair<strings::UniString, int8_t>, uint8_t>;
  TSuggestMap m_suggests;

public:
  void operator()(CategoriesHolder::Category::Name const & name)
  {
    if (name.m_prefixLengthToSuggest != CategoriesHolder::Category::EMPTY_PREFIX_LENGTH)
    {
      strings::UniString const uniName = NormalizeAndSimplifyString(name.m_name);

      uint8_t & score = m_suggests[make_pair(uniName, name.m_locale)];
      if (score == 0 || score > name.m_prefixLengthToSuggest)
        score = name.m_prefixLengthToSuggest;
    }
  }

  void GetSuggests(vector<Suggest> & suggests) const
  {
    suggests.reserve(suggests.size() + m_suggests.size());
    for (auto const & s : m_suggests)
      suggests.emplace_back(s.first.first, s.second, s.first.second);
  }
};

void SendStatistics(SearchParams const & params, m2::RectD const & viewport, Results const & res)
{
  size_t const kMaxNumResultsToSend = 10;

  size_t const numResultsToSend = min(kMaxNumResultsToSend, res.GetCount());
  string resultString = strings::to_string(numResultsToSend);
  for (size_t i = 0; i < numResultsToSend; ++i)
    resultString.append("\t" + res.GetResult(i).ToStringForStats());

  string posX, posY;
  if (params.IsValidPosition())
  {
    posX = strings::to_string(MercatorBounds::LonToX(params.m_lon));
    posY = strings::to_string(MercatorBounds::LatToY(params.m_lat));
  }

  alohalytics::TStringMap const stats = {
      {"posX", posX},
      {"posY", posY},
      {"viewportMinX", strings::to_string(viewport.minX())},
      {"viewportMinY", strings::to_string(viewport.minY())},
      {"viewportMaxX", strings::to_string(viewport.maxX())},
      {"viewportMaxY", strings::to_string(viewport.maxY())},
      {"query", params.m_query},
      {"results", resultString},
  };
  alohalytics::LogEvent("searchEmitResultsAndCoords", stats);
}
}  // namespace

QueryHandle::QueryHandle() : m_query(nullptr), m_cancelled(false) {}

void QueryHandle::Cancel()
{
  lock_guard<mutex> lock(m_mu);
  m_cancelled = true;
  if (m_query)
    m_query->Cancel();
}

void QueryHandle::Attach(Query & query)
{
  lock_guard<mutex> lock(m_mu);
  m_query = &query;
  if (m_cancelled)
    m_query->Cancel();
}

void QueryHandle::Detach()
{
  lock_guard<mutex> lock(m_mu);
  m_query = nullptr;
}

Engine::Engine(Index & index, Reader * categoriesR, storage::CountryInfoGetter const & infoGetter,
               string const & locale, unique_ptr<SearchQueryFactory> && factory)
  : m_categories(categoriesR), m_factory(move(factory)), m_shutdown(false)
{
  InitSuggestions doInit;
  m_categories.ForEachName(bind<void>(ref(doInit), _1));
  doInit.GetSuggests(m_suggests);

  m_query = m_factory->BuildSearchQuery(index, m_categories, m_suggests, infoGetter);
  m_query->SetPreferredLocale(locale);

  m_thread = threads::SimpleThread(&Engine::MainLoop, this);
}

Engine::~Engine()
{
  {
    lock_guard<mutex> lock(m_mu);
    m_shutdown = true;
    m_cv.notify_one();
  }
  m_thread.join();
}

weak_ptr<QueryHandle> Engine::Search(SearchParams const & params, m2::RectD const & viewport)
{
  shared_ptr<QueryHandle> handle(new QueryHandle());
  PostTask(bind(&Engine::DoSearch, this, params, viewport, handle));
  return handle;
}

void Engine::SetSupportOldFormat(bool support)
{
  PostTask(bind(&Engine::DoSupportOldFormat, this, support));
}

void Engine::ClearCaches() { PostTask(bind(&Engine::DoClearCaches, this)); }

bool Engine::GetNameByType(uint32_t type, int8_t locale, string & name) const
{
  uint8_t level = ftype::GetLevel(type);
  ASSERT_GREATER(level, 0, ());

  while (true)
  {
    if (m_categories.GetNameByType(type, locale, name))
      return true;

    if (--level == 0)
      break;

    ftype::TruncValue(type, level);
  }

  return false;
}

void Engine::SetRankPivot(SearchParams const & params,
                          m2::RectD const & viewport, bool viewportSearch)
{
  if (!viewportSearch && params.IsValidPosition())
  {
    m2::PointD const pos = MercatorBounds::FromLatLon(params.m_lat, params.m_lon);
    if (m2::Inflate(viewport, viewport.SizeX() / 4.0, viewport.SizeY() / 4.0).IsPointInside(pos))
    {
      m_query->SetRankPivot(pos);
      return;
    }
  }

  m_query->SetRankPivot(viewport.Center());
}

void Engine::EmitResults(SearchParams const & params, Results const & res)
{
  params.m_callback(res);
}

void Engine::MainLoop()
{
  while (true)
  {
    unique_lock<mutex> lock(m_mu);
    m_cv.wait(lock, [this]()
    {
      return m_shutdown || !m_tasks.empty();
    });

    if (m_shutdown)
      break;

    function<void()> task(move(m_tasks.front()));
    m_tasks.pop();
    lock.unlock();

    task();
  }
}

void Engine::PostTask(function<void()> && task)
{
  lock_guard<mutex> lock(m_mu);
  m_tasks.push(move(task));
  m_cv.notify_one();
}

void Engine::DoSearch(SearchParams const & params, m2::RectD const & viewport,
                      shared_ptr<QueryHandle> handle)
{
  bool const viewportSearch = params.GetMode() == Mode::Viewport;

  // Initialize query.
  m_query->Init(viewportSearch);
  handle->Attach(*m_query);
  MY_SCOPE_GUARD(detach, [&handle] { handle->Detach(); });

  // Early exit when query is cancelled.
  if (m_query->IsCancelled())
  {
    params.m_callback(Results::GetEndMarker(true /* isCancelled */));
    return;
  }

  SetRankPivot(params, viewport, viewportSearch);

  if (params.IsValidPosition())
    m_query->SetPosition(MercatorBounds::FromLatLon(params.m_lat, params.m_lon));
  else
    m_query->SetPosition(viewport.Center());

  m_query->SetMode(params.GetMode());

  // This flag is needed for consistency with old search algorithm
  // only. It will gone away when we will remove old search code.
  m_query->SetSearchInWorld(true);

  m_query->SetInputLocale(params.m_inputLocale);

  ASSERT(!params.m_query.empty(), ());
  m_query->SetQuery(params.m_query);

  Results res;

  m_query->SearchCoordinates(res);

  try
  {
    if (viewportSearch)
    {
      m_query->SetViewport(viewport, true /* forceUpdate */);
      m_query->SearchViewportPoints(res);
    }
    else
    {
      m_query->SetViewport(viewport, params.IsSearchAroundPosition() /* forceUpdate */);
      m_query->Search(res, kResultsCount);
    }

    EmitResults(params, res);
  }
  catch (Query::CancelException const &)
  {
    LOG(LDEBUG, ("Search has been cancelled."));
  }

  if (!viewportSearch && !m_query->IsCancelled())
    SendStatistics(params, viewport, res);

  // Emit finish marker to client.
  params.m_callback(Results::GetEndMarker(m_query->IsCancelled()));
}

void Engine::DoSupportOldFormat(bool support) { m_query->SupportOldFormat(support); }

void Engine::DoClearCaches() { m_query->ClearCaches(); }
}  // namespace search
<commit_msg>Review fixes.<commit_after>#include "search_engine.hpp"

#include "categories_holder.hpp"
#include "geometry_utils.hpp"
#include "search_query.hpp"
#include "search_string_utils.hpp"

#include "storage/country_info_getter.hpp"

#include "indexer/classificator.hpp"
#include "indexer/scales.hpp"

#include "platform/platform.hpp"

#include "geometry/distance_on_sphere.hpp"
#include "geometry/mercator.hpp"

#include "base/logging.hpp"
#include "base/scope_guard.hpp"
#include "base/stl_add.hpp"

#include "std/algorithm.hpp"
#include "std/bind.hpp"
#include "std/map.hpp"
#include "std/vector.hpp"

#include "3party/Alohalytics/src/alohalytics.h"

namespace search
{
namespace
{
int const kResultsCount = 30;

class InitSuggestions
{
  using TSuggestMap = map<pair<strings::UniString, int8_t>, uint8_t>;
  TSuggestMap m_suggests;

public:
  void operator()(CategoriesHolder::Category::Name const & name)
  {
    if (name.m_prefixLengthToSuggest != CategoriesHolder::Category::EMPTY_PREFIX_LENGTH)
    {
      strings::UniString const uniName = NormalizeAndSimplifyString(name.m_name);

      uint8_t & score = m_suggests[make_pair(uniName, name.m_locale)];
      if (score == 0 || score > name.m_prefixLengthToSuggest)
        score = name.m_prefixLengthToSuggest;
    }
  }

  void GetSuggests(vector<Suggest> & suggests) const
  {
    suggests.reserve(suggests.size() + m_suggests.size());
    for (auto const & s : m_suggests)
      suggests.emplace_back(s.first.first, s.second, s.first.second);
  }
};

void SendStatistics(SearchParams const & params, m2::RectD const & viewport, Results const & res)
{
  size_t const kMaxNumResultsToSend = 10;

  size_t const numResultsToSend = min(kMaxNumResultsToSend, res.GetCount());
  string resultString = strings::to_string(numResultsToSend);
  for (size_t i = 0; i < numResultsToSend; ++i)
    resultString.append("\t" + res.GetResult(i).ToStringForStats());

  string posX, posY;
  if (params.IsValidPosition())
  {
    posX = strings::to_string(MercatorBounds::LonToX(params.m_lon));
    posY = strings::to_string(MercatorBounds::LatToY(params.m_lat));
  }

  alohalytics::TStringMap const stats = {
      {"posX", posX},
      {"posY", posY},
      {"viewportMinX", strings::to_string(viewport.minX())},
      {"viewportMinY", strings::to_string(viewport.minY())},
      {"viewportMaxX", strings::to_string(viewport.maxX())},
      {"viewportMaxY", strings::to_string(viewport.maxY())},
      {"query", params.m_query},
      {"results", resultString},
  };
  alohalytics::LogEvent("searchEmitResultsAndCoords", stats);
}
}  // namespace

QueryHandle::QueryHandle() : m_query(nullptr), m_cancelled(false) {}

void QueryHandle::Cancel()
{
  lock_guard<mutex> lock(m_mu);
  m_cancelled = true;
  if (m_query)
    m_query->Cancel();
}

void QueryHandle::Attach(Query & query)
{
  lock_guard<mutex> lock(m_mu);
  m_query = &query;
  if (m_cancelled)
    m_query->Cancel();
}

void QueryHandle::Detach()
{
  lock_guard<mutex> lock(m_mu);
  m_query = nullptr;
}

Engine::Engine(Index & index, Reader * categoriesR, storage::CountryInfoGetter const & infoGetter,
               string const & locale, unique_ptr<SearchQueryFactory> && factory)
  : m_categories(categoriesR), m_factory(move(factory)), m_shutdown(false)
{
  InitSuggestions doInit;
  m_categories.ForEachName(bind<void>(ref(doInit), _1));
  doInit.GetSuggests(m_suggests);

  m_query = m_factory->BuildSearchQuery(index, m_categories, m_suggests, infoGetter);
  m_query->SetPreferredLocale(locale);

  m_thread = threads::SimpleThread(&Engine::MainLoop, this);
}

Engine::~Engine()
{
  {
    lock_guard<mutex> lock(m_mu);
    m_shutdown = true;
    m_cv.notify_one();
  }
  m_thread.join();
}

weak_ptr<QueryHandle> Engine::Search(SearchParams const & params, m2::RectD const & viewport)
{
  shared_ptr<QueryHandle> handle(new QueryHandle());
  PostTask(bind(&Engine::DoSearch, this, params, viewport, handle));
  return handle;
}

void Engine::SetSupportOldFormat(bool support)
{
  PostTask(bind(&Engine::DoSupportOldFormat, this, support));
}

void Engine::ClearCaches() { PostTask(bind(&Engine::DoClearCaches, this)); }

bool Engine::GetNameByType(uint32_t type, int8_t locale, string & name) const
{
  uint8_t level = ftype::GetLevel(type);
  ASSERT_GREATER(level, 0, ());

  while (true)
  {
    if (m_categories.GetNameByType(type, locale, name))
      return true;

    if (--level == 0)
      break;

    ftype::TruncValue(type, level);
  }

  return false;
}

void Engine::SetRankPivot(SearchParams const & params,
                          m2::RectD const & viewport, bool viewportSearch)
{
  if (!viewportSearch && params.IsValidPosition())
  {
    m2::PointD const pos = MercatorBounds::FromLatLon(params.m_lat, params.m_lon);
    if (m2::Inflate(viewport, viewport.SizeX() / 4.0, viewport.SizeY() / 4.0).IsPointInside(pos))
    {
      m_query->SetRankPivot(pos);
      return;
    }
  }

  m_query->SetRankPivot(viewport.Center());
}

void Engine::EmitResults(SearchParams const & params, Results const & res)
{
  params.m_callback(res);
}

void Engine::MainLoop()
{
  while (true)
  {
    unique_lock<mutex> lock(m_mu);
    m_cv.wait(lock, [this]()
    {
      return m_shutdown || !m_tasks.empty();
    });

    if (m_shutdown)
      break;

    function<void()> task(move(m_tasks.front()));
    m_tasks.pop();
    lock.unlock();

    task();
  }
}

void Engine::PostTask(function<void()> && task)
{
  lock_guard<mutex> lock(m_mu);
  m_tasks.push(move(task));
  m_cv.notify_one();
}

void Engine::DoSearch(SearchParams const & params, m2::RectD const & viewport,
                      shared_ptr<QueryHandle> handle)
{
  bool const viewportSearch = params.GetMode() == Mode::Viewport;

  // Initialize query.
  m_query->Init(viewportSearch);
  handle->Attach(*m_query);
  MY_SCOPE_GUARD(detach, [&handle] { handle->Detach(); });

  // Early exit when query is cancelled.
  if (m_query->IsCancelled())
  {
    params.m_callback(Results::GetEndMarker(true /* isCancelled */));
    return;
  }

  SetRankPivot(params, viewport, viewportSearch);

  if (params.IsValidPosition())
    m_query->SetPosition(MercatorBounds::FromLatLon(params.m_lat, params.m_lon));
  else
    m_query->SetPosition(viewport.Center());

  m_query->SetMode(params.GetMode());

  // This flag is needed for consistency with old search algorithm
  // only. It will be gone when we remove old search code.
  m_query->SetSearchInWorld(true);

  m_query->SetInputLocale(params.m_inputLocale);

  ASSERT(!params.m_query.empty(), ());
  m_query->SetQuery(params.m_query);

  Results res;

  m_query->SearchCoordinates(res);

  try
  {
    if (viewportSearch)
    {
      m_query->SetViewport(viewport, true /* forceUpdate */);
      m_query->SearchViewportPoints(res);
    }
    else
    {
      m_query->SetViewport(viewport, params.IsSearchAroundPosition() /* forceUpdate */);
      m_query->Search(res, kResultsCount);
    }

    EmitResults(params, res);
  }
  catch (Query::CancelException const &)
  {
    LOG(LDEBUG, ("Search has been cancelled."));
  }

  if (!viewportSearch && !m_query->IsCancelled())
    SendStatistics(params, viewport, res);

  // Emit finish marker to client.
  params.m_callback(Results::GetEndMarker(m_query->IsCancelled()));
}

void Engine::DoSupportOldFormat(bool support) { m_query->SupportOldFormat(support); }

void Engine::DoClearCaches() { m_query->ClearCaches(); }
}  // namespace search
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------//
/*
  Copyright (c) 2012, Stuart R. Slattery
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:

  *: Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

  *: Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

  *: Neither the name of the University of Wisconsin - Madison nor the
  names of its contributors may be used to endorse or promote products
  derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//---------------------------------------------------------------------------//
/*!
 * \brief DTK_LibmeshNodalShapeFunction.hpp
 * \author Stuart R. Slattery
 * \brief Nodal shape function implementation for Libmesh mesh.
 */
//---------------------------------------------------------------------------//

#ifndef LIBMESHDTKADAPTERS_LIBMESHNODALSHAPEFUNCTION
#define LIBMESHDTKADAPTERS_LIBMESHNODALSHAPEFUNCTION

#include "DTK_LibmeshEntityExtraData.hpp"

#include <DTK_EntityShapeFunction.hpp>
#include <DTK_Types.hpp>

#include <Teuchos_RCP.hpp>
#include <Teuchos_Array.hpp>

#include <libmesh/mesh_base.h>
#include <libmesh/system.h>

namespace DataTransferKit
{
//---------------------------------------------------------------------------//
/*!
  \class LibmeshNodalShapeFunction
  \brief Nodal shape function implementation for Libmesh mesh.

  LibmeshNodalShapeFunction provides a shape function for node-centered
  quantities with shape functions evaluated in an element supported by
  nodes. The node ids serve as the dof ids for these shape functions. A
  corresponding DOF vector indexed via node ids should be produced to match
  this shape function. LibmeshDOFVector provides services to construct these
  vectors.
*/
//---------------------------------------------------------------------------//
class LibmeshNodalShapeFunction : public DataTransferKit::EntityShapeFunction
{
  public:

    /*!
     * \brief Constructor.
     */
    LibmeshNodalShapeFunction(
	const Teuchos::RCP<libMesh::MeshBase>& libmesh_mesh,
	const Teuchos::RCP<libMesh::System>& libmesh_system );

    /*!
     * \brief Given an entity, get the ids of its support locations.
     * \param entity Get the support locations for this entity.
     * \param support_ids Return the ids of the degrees of freedom in the parallel
     * vector space supporting the entities.
     */
    void entitySupportIds(
	const DataTransferKit::Entity& entity,
	Teuchos::Array<DataTransferKit::SupportId>& support_ids ) const;

    /*!
     * \brief Given an entity and a reference point, evaluate the shape
     * function of the entity at that point.
     * \param entity Evaluate the shape function of this entity.
     * \param reference_point Evaluate the shape function at this point
     * given in reference coordinates.
     * \param values Entity shape function evaluated at the reference
     * point.
     */
    void evaluateValue(
	const DataTransferKit::Entity& entity,
	const Teuchos::ArrayView<const double>& reference_point,
	Teuchos::Array<double> & values ) const;

    /*!
     * \brief Given an entity and a reference point, evaluate the gradient of
     * the shape function of the entity at that point.
     * \param entity Evaluate the shape function of this entity.
     * \param reference_point Evaluate the shape function at this point
     * given in reference coordinates.
     * \param gradients Entity shape function gradients evaluated at the
     * reference point. Return these ordered with respect to those return by
     * getDOFIds() such that gradients[N][D] gives the gradient value of the
     * Nth DOF in the Dth spatial dimension.
     */
    void evaluateGradient(
	const DataTransferKit::Entity& entity,
	const Teuchos::ArrayView<const double>& reference_point,
	Teuchos::Array<Teuchos::Array<double> >& gradients ) const;

  private:

    // Extract the libmesh geom object.
    template<class LibmeshGeom>
    Teuchos::Ptr<LibmeshGeom> extractGeom(
	const DataTransferKit::Entity& entity ) const;

  private:

    // Libmesh mesh.
    Teuchos::RCP<libMesh::MeshBase> d_libmesh_mesh;

    // Libmesh system.
    Teuchos::RCP<libMesh::System> d_libmesh_system;
};

//---------------------------------------------------------------------------//
// Template functions.
//---------------------------------------------------------------------------//
// Extract the libmesh geom object.
template<class LibmeshGeom>
Teuchos::Ptr<LibmeshGeom> LibmeshNodalShapeFunction::extractGeom(
    const DataTransferKit::Entity& entity ) const
{
    return Teuchos::rcp_dynamic_cast<LibmeshEntityExtraData<LibmeshGeom> >(
	entity.extraData())->d_libmesh_geom;
}

//---------------------------------------------------------------------------//

} // end namespace DataTransferKit

//---------------------------------------------------------------------------//

#endif // end LIBMESHDTKADPATERS_LIBMESHNODALSHAPEFUNCTION

//---------------------------------------------------------------------------//
// end DTK_LibmeshNodalShapeFunction.hpp
//---------------------------------------------------------------------------//
<commit_msg>Update DTK_LibmeshNodalShapeFunction.hpp<commit_after>//---------------------------------------------------------------------------//
/*
  Copyright (c) 2012, Stuart R. Slattery
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:

  *: Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

  *: Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

  *: Neither the name of the University of Wisconsin - Madison nor the
  names of its contributors may be used to endorse or promote products
  derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//---------------------------------------------------------------------------//
/*!
 * \brief DTK_LibmeshNodalShapeFunction.hpp
 * \author Stuart R. Slattery
 * \brief Nodal shape function implementation for Libmesh mesh.
 */
//---------------------------------------------------------------------------//

#ifndef LIBMESHDTKADAPTERS_LIBMESHNODALSHAPEFUNCTION
#define LIBMESHDTKADAPTERS_LIBMESHNODALSHAPEFUNCTION

#include "DTK_LibmeshEntityExtraData.hpp"

#include <DTK_EntityShapeFunction.hpp>
#include <DTK_Types.hpp>

#include <Teuchos_RCP.hpp>
#include <Teuchos_Array.hpp>

#include <libmesh/mesh_base.h>
#include <libmesh/system.h>

namespace DataTransferKit
{
//---------------------------------------------------------------------------//
/*!
  \class LibmeshNodalShapeFunction
  \brief Nodal shape function implementation for Libmesh mesh.

  LibmeshNodalShapeFunction provides a shape function for node-centered
  quantities with shape functions evaluated in an element supported by
  nodes. The node ids serve as the dof ids for these shape functions. A
  corresponding DOF vector indexed via node ids should be produced to match
  this shape function. LibmeshDOFVector provides services to construct these
  vectors.
*/
//---------------------------------------------------------------------------//
class LibmeshNodalShapeFunction : public EntityShapeFunction
{
  public:

    /*!
     * \brief Constructor.
     */
    LibmeshNodalShapeFunction(
	const Teuchos::RCP<libMesh::MeshBase>& libmesh_mesh,
	const Teuchos::RCP<libMesh::System>& libmesh_system );

    /*!
     * \brief Given an entity, get the ids of its support locations.
     * \param entity Get the support locations for this entity.
     * \param support_ids Return the ids of the degrees of freedom in the parallel
     * vector space supporting the entities.
     */
    void entitySupportIds(
	const Entity& entity,
	Teuchos::Array<SupportId>& support_ids ) const;

    /*!
     * \brief Given an entity and a reference point, evaluate the shape
     * function of the entity at that point.
     * \param entity Evaluate the shape function of this entity.
     * \param reference_point Evaluate the shape function at this point
     * given in reference coordinates.
     * \param values Entity shape function evaluated at the reference
     * point.
     */
    void evaluateValue(
	const Entity& entity,
	const Teuchos::ArrayView<const double>& reference_point,
	Teuchos::Array<double> & values ) const;

    /*!
     * \brief Given an entity and a reference point, evaluate the gradient of
     * the shape function of the entity at that point.
     * \param entity Evaluate the shape function of this entity.
     * \param reference_point Evaluate the shape function at this point
     * given in reference coordinates.
     * \param gradients Entity shape function gradients evaluated at the
     * reference point. Return these ordered with respect to those return by
     * getDOFIds() such that gradients[N][D] gives the gradient value of the
     * Nth DOF in the Dth spatial dimension.
     */
    void evaluateGradient(
	const Entity& entity,
	const Teuchos::ArrayView<const double>& reference_point,
	Teuchos::Array<Teuchos::Array<double> >& gradients ) const;

  private:

    // Extract the libmesh geom object.
    template<class LibmeshGeom>
    Teuchos::Ptr<LibmeshGeom> extractGeom(
	const Entity& entity ) const;

  private:

    // Libmesh mesh.
    Teuchos::RCP<libMesh::MeshBase> d_libmesh_mesh;

    // Libmesh system.
    Teuchos::RCP<libMesh::System> d_libmesh_system;
};

//---------------------------------------------------------------------------//
// Template functions.
//---------------------------------------------------------------------------//
// Extract the libmesh geom object.
template<class LibmeshGeom>
Teuchos::Ptr<LibmeshGeom> LibmeshNodalShapeFunction::extractGeom(
    const Entity& entity ) const
{
    return Teuchos::rcp_dynamic_cast<LibmeshEntityExtraData<LibmeshGeom> >(
	entity.extraData())->d_libmesh_geom;
}

//---------------------------------------------------------------------------//

} // end namespace DataTransferKit

//---------------------------------------------------------------------------//

#endif // end LIBMESHDTKADPATERS_LIBMESHNODALSHAPEFUNCTION

//---------------------------------------------------------------------------//
// end DTK_LibmeshNodalShapeFunction.hpp
//---------------------------------------------------------------------------//
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------
//    @FileName         :    NFCProperty.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-03-01
//    @Module           :    NFCProperty
//
// -------------------------------------------------------------------------

#include "NFCProperty.h"
#include <complex>

NFCProperty::NFCProperty()
{
    mbPublic = false;
    mbPrivate = false;
    mbSave = false;
    mSelf = NFGUID();
    eType = TDATA_UNKNOWN;

    msPropertyName = "";
}

NFCProperty::NFCProperty(const NFGUID& self, const std::string& strPropertyName, const TDATA_TYPE varType, bool bPublic,  bool bPrivate,  bool bSave, const std::string& strRelationValue)
{

    mbPublic = bPublic;
    mbPrivate = bPrivate;
    mbSave = bSave;
    mSelf = self;

    msPropertyName = strPropertyName;
    mstrRelationValue = strRelationValue;
    eType = varType;
}

NFCProperty::~NFCProperty()
{
    for (TPROPERTYCALLBACKEX::iterator iter = mtPropertyCallback.begin(); iter != mtPropertyCallback.end(); ++iter)
    {
        iter->reset();
    }

    mtPropertyCallback.clear();
    mxData.reset();
}

void NFCProperty::SetValue(const NFIDataList::TData& TData)
{
    if (eType != TData.GetType())
    {
        return;
    }

    if (!mxData.get())
    {
        if (!TData.IsNullValue())
        {
            return;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TData));
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->variantData = TData.variantData;

    NFCDataList::TData newValue;
    newValue = *mxData;

    OnEventHandler(oldValue , newValue);
}

void NFCProperty::SetValue(const NFIProperty* pProperty)
{
    SetValue(pProperty->GetValue());
}

const NFIDataList::TData& NFCProperty::GetValue() const
{
    if (mxData.get())
    {
        return *mxData;
    }

    return NULL_TDATA;
}

const std::string&  NFCProperty::GetKey() const
{
    return msPropertyName;
}

const bool NFCProperty::GetSave() const
{
    return mbSave;
}

const bool NFCProperty::GetPublic() const
{
    return mbPublic;
}

const bool NFCProperty::GetPrivate() const
{
    return mbPrivate;
}

const std::string& NFCProperty::GetRelationValue() const
{
    return mstrRelationValue;
}

void NFCProperty::SetSave(bool bSave)
{
    mbSave = bSave;
}

void NFCProperty::SetPublic(bool bPublic)
{
    mbPublic = bPublic;
}

void NFCProperty::SetPrivate(bool bPrivate)
{
    mbPrivate = bPrivate;
}

void NFCProperty::SetRelationValue(const std::string& strRelationValue)
{
    mstrRelationValue = strRelationValue;
}

NFINT64 NFCProperty::GetInt() const
{
    if (!mxData.get())
    {
        return 0;
    }

    return mxData->GetInt();
}

double NFCProperty::GetFloat() const
{
    if (!mxData.get())
    {
        return 0.0;
    }

    return mxData->GetFloat();
}

const std::string& NFCProperty::GetString() const
{
    if (!mxData.get())
    {
        return NULL_STR;
    }

    return mxData->GetString();
}

const NFGUID& NFCProperty::GetObject() const
{
    if (!mxData.get())
    {
        return NULL_OBJECT;
    }

    return mxData->GetObject();
}

void NFCProperty::RegisterCallback(const PROPERTY_EVENT_FUNCTOR_PTR& cb)
{
    mtPropertyCallback.push_back(cb);
}

int NFCProperty::OnEventHandler(const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar)
{
    if (mtPropertyCallback.size() <= 0)
    {
        return 0;
    }

    TPROPERTYCALLBACKEX::iterator it = mtPropertyCallback.begin();
    TPROPERTYCALLBACKEX::iterator end = mtPropertyCallback.end();
    for (it; it != end; ++it)
    {
        //NFIDataList:OLDֵNEWֵ, ARG(pKernel,self)
        PROPERTY_EVENT_FUNCTOR_PTR& pFunPtr = *it;
        PROPERTY_EVENT_FUNCTOR* pFunc = pFunPtr.get();
        int nTemRet = pFunc->operator()(mSelf, msPropertyName, oldVar, newVar);
    }

    return 0;
}

bool NFCProperty::SetInt(const NFINT64 value)
{
    if (eType != TDATA_INT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (0 == value)
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_INT));
        mxData->SetInt(0);
    }

    if (value == mxData->GetInt())
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetInt(value);

    OnEventHandler(oldValue, *mxData);

    return true;
}

bool NFCProperty::SetFloat(const double value)
{
    if (eType != TDATA_FLOAT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (std::abs(value) < 0.001)
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_FLOAT));
        mxData->SetFloat(0.0);
    }

    if (value - mxData->GetFloat() < 0.001)
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetFloat(value);

    OnEventHandler(oldValue, *mxData);

    return true;
}

bool NFCProperty::SetString(const std::string& value)
{
    if (eType != TDATA_STRING)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (value.empty())
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_STRING));
        mxData->SetString(NULL_STR);
    }

    if (value == mxData->GetString())
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetString(value);

    OnEventHandler(oldValue, *mxData);

    return true;
}

bool NFCProperty::SetObject(const NFGUID& value)
{
    if (eType != TDATA_OBJECT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (value.IsNull())
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_OBJECT));
        mxData->SetObject(NFGUID());

    }

    if (value == mxData->GetObject())
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetObject(value);

    OnEventHandler(oldValue , *mxData);

    return true;
}

bool NFCProperty::Changed() const
{
    return GetValue().IsNullValue();
}

const TDATA_TYPE NFCProperty::GetType() const
{
    return eType;
}

const bool NFCProperty::GeUsed() const
{
    if (mxData.get())
    {
        return true;
    }

    return false;
}

std::string NFCProperty::ToString()
{
    std::string strData;
    const TDATA_TYPE eType = GetType();
    switch (eType)
    {
        case TDATA_INT:
            strData = lexical_cast<std::string> (GetInt());
            break;
        case TDATA_FLOAT:
            strData = lexical_cast<std::string> (GetFloat());
            break;
        case TDATA_STRING:
            strData = GetString();
            break;
		case TDATA_OBJECT:
            strData = GetObject().ToString();
            break;
        default:
            strData = NULL_STR;
            break;
    }

    return strData;
}

bool NFCProperty::FromString(const std::string& strData)
{
    const TDATA_TYPE eType = GetType();
    bool bRet = false;
    switch (eType)
    {
        case TDATA_INT:
        {
            NFINT64  nValue = 0;
            bRet = NF_StrTo(strData, nValue);
            SetInt(nValue);
        }
        break;

        case TDATA_FLOAT:
        {
            double  dValue = 0;
            bRet = NF_StrTo(strData, dValue);
            SetFloat(dValue);
        }
        break;

        case TDATA_STRING:
        {
            SetString(strData);
            bRet = true;
        }
        break;
        case TDATA_OBJECT:
        {
            NFGUID xID;

            bRet = xID.FromString(strData);
            SetObject(xID);
        }
        break;
        default:
            break;
    }

    return bRet;
}

bool NFCProperty::DeSerialization()
{
    bool bRet = false;

    const TDATA_TYPE eType = GetType();
    if(eType == TDATA_STRING)
    {
        NFCDataList xDataList();
        const std::string& strData = mxData->GetString();

        xDataList.Split(strData.c_str(), ";")
        for(int i = 0; i < xDataList.GetCount(); ++i)
        {
            if(nullptr == mxEmbeddedList)
            {
                mxEmbeddedList = NF_SHARE_PTR<NFList<std::string>>(NF_NEW NFList<std::string>());
            }
            else
            {
                mxEmbeddedList->ClearAll();
            }

            if(xDataList.String(i).empty())
            {
                NFASSERT(0, strData, __FILE__, __FUNCTION__);
            }

            mxEmbeddedList->Add(xDataList.String(i));
        }

        if(nullptr != mxEmbeddedList && mxEmbeddedList->Count() > 0)
        {
            std::string strTemData;
            for(bool bListRet = mxEmbeddedList->First(strTemData); bListRet == true; bListRet = mxEmbeddedList->Next(strTemData))
            {
                NFCDataList xTemDataList();
                xTemDataList.Split(strTemData.c_str(), ",")
                if(xTemDataList.GetCount() > 0)
                {
                    if (xTemDataList.GetCount() != 2)
                    {
                        NFASSERT(0, strTemData, __FILE__, __FUNCTION__);
                    }

                    const std::string& strKey = xTemDataList.String(0);
                    const std::string& strValue = xTemDataList.String(0);

                    if(strKey.empty() || strValue.empty())
                    {
                        NFASSERT(0, strTemData, __FILE__, __FUNCTION__);
                    }

                    if(nullptr == mxEmbeddedMap)
                    {
                        mxEmbeddedMap = NF_SHARE_PTR<NFMapEx<std::string, std::string>>(NF_NEW NFMapEx<std::string, std::string>());
                    }
                    else
                    {
                        mxEmbeddedMap->ClearAll();
                    }

                    mxEmbeddedMap->AddElement(strKey, NF_SHARE_PTR<std::string>(NF_NEW std::string(strValue)))
                }
            }

            bRet = true;
        }
    }

    return bRet;
}

const NF_SHARE_PTR<NFList<std::string>> NFCProperty::GetEmbeddedList() const
{
    return this->mxEmbeddedList;
}

const NF_SHARE_PTR<NFMapEx<std::string, std::string>> NFCProperty::GetEmbeddedMap() const
{
    return this->mxEmbeddedMap;
}
<commit_msg>fixed for compile<commit_after>// -------------------------------------------------------------------------
//    @FileName         :    NFCProperty.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-03-01
//    @Module           :    NFCProperty
//
// -------------------------------------------------------------------------

#include "NFCProperty.h"
#include <complex>

NFCProperty::NFCProperty()
{
    mbPublic = false;
    mbPrivate = false;
    mbSave = false;
    mSelf = NFGUID();
    eType = TDATA_UNKNOWN;

    msPropertyName = "";
}

NFCProperty::NFCProperty(const NFGUID& self, const std::string& strPropertyName, const TDATA_TYPE varType, bool bPublic,  bool bPrivate,  bool bSave, const std::string& strRelationValue)
{

    mbPublic = bPublic;
    mbPrivate = bPrivate;
    mbSave = bSave;
    mSelf = self;

    msPropertyName = strPropertyName;
    mstrRelationValue = strRelationValue;
    eType = varType;
}

NFCProperty::~NFCProperty()
{
    for (TPROPERTYCALLBACKEX::iterator iter = mtPropertyCallback.begin(); iter != mtPropertyCallback.end(); ++iter)
    {
        iter->reset();
    }

    mtPropertyCallback.clear();
    mxData.reset();
}

void NFCProperty::SetValue(const NFIDataList::TData& TData)
{
    if (eType != TData.GetType())
    {
        return;
    }

    if (!mxData.get())
    {
        if (!TData.IsNullValue())
        {
            return;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TData));
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->variantData = TData.variantData;

    NFCDataList::TData newValue;
    newValue = *mxData;

    OnEventHandler(oldValue , newValue);
}

void NFCProperty::SetValue(const NFIProperty* pProperty)
{
    SetValue(pProperty->GetValue());
}

const NFIDataList::TData& NFCProperty::GetValue() const
{
    if (mxData.get())
    {
        return *mxData;
    }

    return NULL_TDATA;
}

const std::string&  NFCProperty::GetKey() const
{
    return msPropertyName;
}

const bool NFCProperty::GetSave() const
{
    return mbSave;
}

const bool NFCProperty::GetPublic() const
{
    return mbPublic;
}

const bool NFCProperty::GetPrivate() const
{
    return mbPrivate;
}

const std::string& NFCProperty::GetRelationValue() const
{
    return mstrRelationValue;
}

void NFCProperty::SetSave(bool bSave)
{
    mbSave = bSave;
}

void NFCProperty::SetPublic(bool bPublic)
{
    mbPublic = bPublic;
}

void NFCProperty::SetPrivate(bool bPrivate)
{
    mbPrivate = bPrivate;
}

void NFCProperty::SetRelationValue(const std::string& strRelationValue)
{
    mstrRelationValue = strRelationValue;
}

NFINT64 NFCProperty::GetInt() const
{
    if (!mxData.get())
    {
        return 0;
    }

    return mxData->GetInt();
}

double NFCProperty::GetFloat() const
{
    if (!mxData.get())
    {
        return 0.0;
    }

    return mxData->GetFloat();
}

const std::string& NFCProperty::GetString() const
{
    if (!mxData.get())
    {
        return NULL_STR;
    }

    return mxData->GetString();
}

const NFGUID& NFCProperty::GetObject() const
{
    if (!mxData.get())
    {
        return NULL_OBJECT;
    }

    return mxData->GetObject();
}

void NFCProperty::RegisterCallback(const PROPERTY_EVENT_FUNCTOR_PTR& cb)
{
    mtPropertyCallback.push_back(cb);
}

int NFCProperty::OnEventHandler(const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar)
{
    if (mtPropertyCallback.size() <= 0)
    {
        return 0;
    }

    TPROPERTYCALLBACKEX::iterator it = mtPropertyCallback.begin();
    TPROPERTYCALLBACKEX::iterator end = mtPropertyCallback.end();
    for (it; it != end; ++it)
    {
        //NFIDataList:OLDֵNEWֵ, ARG(pKernel,self)
        PROPERTY_EVENT_FUNCTOR_PTR& pFunPtr = *it;
        PROPERTY_EVENT_FUNCTOR* pFunc = pFunPtr.get();
        int nTemRet = pFunc->operator()(mSelf, msPropertyName, oldVar, newVar);
    }

    return 0;
}

bool NFCProperty::SetInt(const NFINT64 value)
{
    if (eType != TDATA_INT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (0 == value)
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_INT));
        mxData->SetInt(0);
    }

    if (value == mxData->GetInt())
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetInt(value);

    OnEventHandler(oldValue, *mxData);

    return true;
}

bool NFCProperty::SetFloat(const double value)
{
    if (eType != TDATA_FLOAT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (std::abs(value) < 0.001)
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_FLOAT));
        mxData->SetFloat(0.0);
    }

    if (value - mxData->GetFloat() < 0.001)
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetFloat(value);

    OnEventHandler(oldValue, *mxData);

    return true;
}

bool NFCProperty::SetString(const std::string& value)
{
    if (eType != TDATA_STRING)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (value.empty())
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_STRING));
        mxData->SetString(NULL_STR);
    }

    if (value == mxData->GetString())
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetString(value);

    OnEventHandler(oldValue, *mxData);

    return true;
}

bool NFCProperty::SetObject(const NFGUID& value)
{
    if (eType != TDATA_OBJECT)
    {
        return false;
    }

    if (!mxData.get())
    {
        //ǿվΪûݣûݵľͲ
        if (value.IsNull())
        {
            return false;
        }

        mxData = NF_SHARE_PTR<NFIDataList::TData>(NF_NEW NFIDataList::TData(TDATA_OBJECT));
        mxData->SetObject(NFGUID());

    }

    if (value == mxData->GetObject())
    {
        return false;
    }

    NFCDataList::TData oldValue;
    oldValue = *mxData;

    mxData->SetObject(value);

    OnEventHandler(oldValue , *mxData);

    return true;
}

bool NFCProperty::Changed() const
{
    return GetValue().IsNullValue();
}

const TDATA_TYPE NFCProperty::GetType() const
{
    return eType;
}

const bool NFCProperty::GeUsed() const
{
    if (mxData.get())
    {
        return true;
    }

    return false;
}

std::string NFCProperty::ToString()
{
    std::string strData;
    const TDATA_TYPE eType = GetType();
    switch (eType)
    {
        case TDATA_INT:
            strData = lexical_cast<std::string> (GetInt());
            break;
        case TDATA_FLOAT:
            strData = lexical_cast<std::string> (GetFloat());
            break;
        case TDATA_STRING:
            strData = GetString();
            break;
		case TDATA_OBJECT:
            strData = GetObject().ToString();
            break;
        default:
            strData = NULL_STR;
            break;
    }

    return strData;
}

bool NFCProperty::FromString(const std::string& strData)
{
    const TDATA_TYPE eType = GetType();
    bool bRet = false;
    switch (eType)
    {
        case TDATA_INT:
        {
            NFINT64  nValue = 0;
            bRet = NF_StrTo(strData, nValue);
            SetInt(nValue);
        }
        break;

        case TDATA_FLOAT:
        {
            double  dValue = 0;
            bRet = NF_StrTo(strData, dValue);
            SetFloat(dValue);
        }
        break;

        case TDATA_STRING:
        {
            SetString(strData);
            bRet = true;
        }
        break;
        case TDATA_OBJECT:
        {
            NFGUID xID;

            bRet = xID.FromString(strData);
            SetObject(xID);
        }
        break;
        default:
            break;
    }

    return bRet;
}

bool NFCProperty::DeSerialization()
{
    bool bRet = false;

    const TDATA_TYPE eType = GetType();
    if(eType == TDATA_STRING)
    {
        NFCDataList xDataList;
        const std::string& strData = mxData->GetString();

        xDataList.Split(strData.c_str(), ";")
        for(int i = 0; i < xDataList.GetCount(); ++i)
        {
            if(nullptr == mxEmbeddedList)
            {
                mxEmbeddedList = NF_SHARE_PTR<NFList<std::string>>(NF_NEW NFList<std::string>());
            }
            else
            {
                mxEmbeddedList->ClearAll();
            }

            if(xDataList.String(i).empty())
            {
                NFASSERT(0, strData, __FILE__, __FUNCTION__);
            }

            mxEmbeddedList->Add(xDataList.String(i));
        }

        if(nullptr != mxEmbeddedList && mxEmbeddedList->Count() > 0)
        {
            std::string strTemData;
            for(bool bListRet = mxEmbeddedList->First(strTemData); bListRet == true; bListRet = mxEmbeddedList->Next(strTemData))
            {
                NFCDataList xTemDataList;
                xTemDataList.Split(strTemData.c_str(), ",")
                if(xTemDataList.GetCount() > 0)
                {
                    if (xTemDataList.GetCount() != 2)
                    {
                        NFASSERT(0, strTemData, __FILE__, __FUNCTION__);
                    }

                    const std::string& strKey = xTemDataList.String(0);
                    const std::string& strValue = xTemDataList.String(0);

                    if(strKey.empty() || strValue.empty())
                    {
                        NFASSERT(0, strTemData, __FILE__, __FUNCTION__);
                    }

                    if(nullptr == mxEmbeddedMap)
                    {
                        mxEmbeddedMap = NF_SHARE_PTR<NFMapEx<std::string, std::string>>(NF_NEW NFMapEx<std::string, std::string>());
                    }
                    else
                    {
                        mxEmbeddedMap->ClearAll();
                    }

                    mxEmbeddedMap->AddElement(strKey, NF_SHARE_PTR<std::string>(NF_NEW std::string(strValue)))
                }
            }

            bRet = true;
        }
    }

    return bRet;
}

const NF_SHARE_PTR<NFList<std::string>> NFCProperty::GetEmbeddedList() const
{
    return this->mxEmbeddedList;
}

const NF_SHARE_PTR<NFMapEx<std::string, std::string>> NFCProperty::GetEmbeddedMap() const
{
    return this->mxEmbeddedMap;
}
<|endoftext|>


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

#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"

#include <X11/Xlib.h>
// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
#undef RootWindow

#include "base/debug/stack_trace.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_pump_x11.h"
#include "base/run_loop.h"
#include "ui/aura/env.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/event.h"
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/widget/widget.h"

namespace views {

namespace {

class ScopedCapturer {
 public:
  explicit ScopedCapturer(aura::WindowTreeHost* host)
      : host_(host) {
    host_->SetCapture();
  }

  ~ScopedCapturer() {
    host_->ReleaseCapture();
  }

 private:
  aura::WindowTreeHost* host_;

  DISALLOW_COPY_AND_ASSIGN(ScopedCapturer);
};

}  // namespace

X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(
    X11WholeScreenMoveLoopDelegate* delegate)
    : delegate_(delegate),
      in_move_loop_(false),
      should_reset_mouse_flags_(false),
      grab_input_window_(None) {
}

X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {}

////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostLinux, MessagePumpDispatcher implementation:

bool X11WholeScreenMoveLoop::Dispatch(const base::NativeEvent& event) {
  XEvent* xev = event;

  // Note: the escape key is handled in the tab drag controller, which has
  // keyboard focus even though we took pointer grab.
  switch (xev->type) {
    case MotionNotify: {
      if (drag_widget_.get()) {
        gfx::Screen* screen = gfx::Screen::GetNativeScreen();
        gfx::Point location = gfx::ToFlooredPoint(
            screen->GetCursorScreenPoint() - drag_offset_);
        drag_widget_->SetBounds(gfx::Rect(location, drag_image_.size()));
      }
      delegate_->OnMouseMovement(&xev->xmotion);
      break;
    }
    case ButtonRelease: {
      if (xev->xbutton.button == Button1) {
        // Assume that drags are being done with the left mouse button. Only
        // break the drag if the left mouse button was released.
        delegate_->OnMouseReleased();
      }
      break;
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostLinux, aura::client::WindowMoveClient implementation:

bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
                                         gfx::NativeCursor cursor) {
  // Start a capture on the host, so that it continues to receive events during
  // the drag.
  ScopedCapturer capturer(source->GetDispatcher()->host());

  DCHECK(!in_move_loop_);  // Can only handle one nested loop at a time.
  in_move_loop_ = true;

  XDisplay* display = gfx::GetXDisplay();

  grab_input_window_ = CreateDragInputWindow(display);
  if (!drag_image_.isNull())
    CreateDragImageWindow();
  base::MessagePumpX11::Current()->AddDispatcherForWindow(
      this, grab_input_window_);

  if (!GrabPointerWithCursor(cursor))
    return false;

  // We are handling a mouse drag outside of the aura::RootWindow system. We
  // must manually make aura think that the mouse button is pressed so that we
  // don't draw extraneous tooltips.
  aura::Env* env = aura::Env::GetInstance();
  if (!env->IsMouseButtonDown()) {
    env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON);
    should_reset_mouse_flags_ = true;
  }

  base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
  base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
  base::RunLoop run_loop;
  quit_closure_ = run_loop.QuitClosure();
  run_loop.Run();
  return true;
}

void X11WholeScreenMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {
  DCHECK(in_move_loop_);
  GrabPointerWithCursor(cursor);
}

void X11WholeScreenMoveLoop::EndMoveLoop() {
  if (!in_move_loop_)
    return;

  // We undo our emulated mouse click from RunMoveLoop();
  if (should_reset_mouse_flags_) {
    aura::Env::GetInstance()->set_mouse_button_flags(0);
    should_reset_mouse_flags_ = false;
  }

  // TODO(erg): Is this ungrab the cause of having to click to give input focus
  // on drawn out windows? Not ungrabbing here screws the X server until I kill
  // the chrome process.

  // Ungrab before we let go of the window.
  XDisplay* display = gfx::GetXDisplay();
  XUngrabPointer(display, CurrentTime);

  base::MessagePumpX11::Current()->RemoveDispatcherForWindow(
      grab_input_window_);
  drag_widget_.reset();
  delegate_->OnMoveLoopEnded();
  XDestroyWindow(display, grab_input_window_);

  in_move_loop_ = false;
  quit_closure_.Run();
}

void X11WholeScreenMoveLoop::SetDragImage(const gfx::ImageSkia& image,
                                          gfx::Vector2dF offset) {
  drag_image_ = image;
  drag_offset_ = offset;
  // Reset the Y offset, so that the drag-image is always just below the cursor,
  // so that it is possible to see where the cursor is going.
  drag_offset_.set_y(0.f);
}

bool X11WholeScreenMoveLoop::GrabPointerWithCursor(gfx::NativeCursor cursor) {
  XDisplay* display = gfx::GetXDisplay();
  XGrabServer(display);
  XUngrabPointer(display, CurrentTime);
  int ret = XGrabPointer(
      display,
      grab_input_window_,
      False,
      ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
      GrabModeAsync,
      GrabModeAsync,
      None,
      cursor.platform(),
      CurrentTime);
  XUngrabServer(display);
  if (ret != GrabSuccess) {
    DLOG(ERROR) << "Grabbing new tab for dragging failed: "
                << ui::GetX11ErrorString(display, ret);
    return false;
  }

  return true;
}

Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
  // Creates an invisible, InputOnly toplevel window. This window will receive
  // all mouse movement for drags. It turns out that normal windows doing a
  // grab doesn't redirect pointer motion events if the pointer isn't over the
  // grabbing window. But InputOnly windows are able to grab everything. This
  // is what GTK+ does, and I found a patch to KDE that did something similar.
  unsigned long attribute_mask = CWEventMask | CWOverrideRedirect;
  XSetWindowAttributes swa;
  memset(&swa, 0, sizeof(swa));
  swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
                   StructureNotifyMask;
  swa.override_redirect = True;
  Window window = XCreateWindow(display,
                                DefaultRootWindow(display),
                                -100, -100, 10, 10,
                                0, CopyFromParent, InputOnly, CopyFromParent,
                                attribute_mask, &swa);
  XMapRaised(display, window);
  base::MessagePumpX11::Current()->BlockUntilWindowMapped(window);
  return window;
}

void X11WholeScreenMoveLoop::CreateDragImageWindow() {
  Widget* widget = new Widget;
  Widget::InitParams params(Widget::InitParams::TYPE_DRAG);
  params.opacity = Widget::InitParams::OPAQUE_WINDOW;
  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.accept_events = false;

  gfx::Point location = gfx::ToFlooredPoint(
      gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() - drag_offset_);
  params.bounds = gfx::Rect(location, drag_image_.size());
  widget->set_focus_on_creation(false);
  widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE);
  widget->Init(params);
  widget->GetNativeWindow()->SetName("DragWindow");

  ImageView* image = new ImageView();
  image->SetImage(drag_image_);
  image->SetBounds(0, 0, drag_image_.width(), drag_image_.height());
  widget->SetContentsView(image);

  widget->Show();
  widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false);

  drag_widget_.reset(widget);
}

}  // namespace views
<commit_msg>linux_aura: Don't update cursor while shutting down the move loop.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h"

#include <X11/Xlib.h>
// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
#undef RootWindow

#include "base/debug/stack_trace.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_pump_x11.h"
#include "base/run_loop.h"
#include "ui/aura/env.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/x/x11_util.h"
#include "ui/events/event.h"
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/screen.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/widget/widget.h"

namespace views {

namespace {

class ScopedCapturer {
 public:
  explicit ScopedCapturer(aura::WindowTreeHost* host)
      : host_(host) {
    host_->SetCapture();
  }

  ~ScopedCapturer() {
    host_->ReleaseCapture();
  }

 private:
  aura::WindowTreeHost* host_;

  DISALLOW_COPY_AND_ASSIGN(ScopedCapturer);
};

}  // namespace

X11WholeScreenMoveLoop::X11WholeScreenMoveLoop(
    X11WholeScreenMoveLoopDelegate* delegate)
    : delegate_(delegate),
      in_move_loop_(false),
      should_reset_mouse_flags_(false),
      grab_input_window_(None) {
}

X11WholeScreenMoveLoop::~X11WholeScreenMoveLoop() {}

////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostLinux, MessagePumpDispatcher implementation:

bool X11WholeScreenMoveLoop::Dispatch(const base::NativeEvent& event) {
  XEvent* xev = event;

  // Note: the escape key is handled in the tab drag controller, which has
  // keyboard focus even though we took pointer grab.
  switch (xev->type) {
    case MotionNotify: {
      if (drag_widget_.get()) {
        gfx::Screen* screen = gfx::Screen::GetNativeScreen();
        gfx::Point location = gfx::ToFlooredPoint(
            screen->GetCursorScreenPoint() - drag_offset_);
        drag_widget_->SetBounds(gfx::Rect(location, drag_image_.size()));
      }
      delegate_->OnMouseMovement(&xev->xmotion);
      break;
    }
    case ButtonRelease: {
      if (xev->xbutton.button == Button1) {
        // Assume that drags are being done with the left mouse button. Only
        // break the drag if the left mouse button was released.
        delegate_->OnMouseReleased();
      }
      break;
    }
  }

  return true;
}

////////////////////////////////////////////////////////////////////////////////
// DesktopWindowTreeHostLinux, aura::client::WindowMoveClient implementation:

bool X11WholeScreenMoveLoop::RunMoveLoop(aura::Window* source,
                                         gfx::NativeCursor cursor) {
  // Start a capture on the host, so that it continues to receive events during
  // the drag.
  ScopedCapturer capturer(source->GetDispatcher()->host());

  DCHECK(!in_move_loop_);  // Can only handle one nested loop at a time.
  in_move_loop_ = true;

  XDisplay* display = gfx::GetXDisplay();

  grab_input_window_ = CreateDragInputWindow(display);
  if (!drag_image_.isNull())
    CreateDragImageWindow();
  base::MessagePumpX11::Current()->AddDispatcherForWindow(
      this, grab_input_window_);

  if (!GrabPointerWithCursor(cursor))
    return false;

  // We are handling a mouse drag outside of the aura::RootWindow system. We
  // must manually make aura think that the mouse button is pressed so that we
  // don't draw extraneous tooltips.
  aura::Env* env = aura::Env::GetInstance();
  if (!env->IsMouseButtonDown()) {
    env->set_mouse_button_flags(ui::EF_LEFT_MOUSE_BUTTON);
    should_reset_mouse_flags_ = true;
  }

  base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
  base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
  base::RunLoop run_loop;
  quit_closure_ = run_loop.QuitClosure();
  run_loop.Run();
  return true;
}

void X11WholeScreenMoveLoop::UpdateCursor(gfx::NativeCursor cursor) {
  if (in_move_loop_) {
    // If we're still in the move loop, regrab the pointer with the updated
    // cursor. Note: we can be called from handling an XdndStatus message after
    // EndMoveLoop() was called, but before we return from the nested RunLoop.
    GrabPointerWithCursor(cursor);
  }
}

void X11WholeScreenMoveLoop::EndMoveLoop() {
  if (!in_move_loop_)
    return;

  // We undo our emulated mouse click from RunMoveLoop();
  if (should_reset_mouse_flags_) {
    aura::Env::GetInstance()->set_mouse_button_flags(0);
    should_reset_mouse_flags_ = false;
  }

  // TODO(erg): Is this ungrab the cause of having to click to give input focus
  // on drawn out windows? Not ungrabbing here screws the X server until I kill
  // the chrome process.

  // Ungrab before we let go of the window.
  XDisplay* display = gfx::GetXDisplay();
  XUngrabPointer(display, CurrentTime);

  base::MessagePumpX11::Current()->RemoveDispatcherForWindow(
      grab_input_window_);
  drag_widget_.reset();
  delegate_->OnMoveLoopEnded();
  XDestroyWindow(display, grab_input_window_);

  in_move_loop_ = false;
  quit_closure_.Run();
}

void X11WholeScreenMoveLoop::SetDragImage(const gfx::ImageSkia& image,
                                          gfx::Vector2dF offset) {
  drag_image_ = image;
  drag_offset_ = offset;
  // Reset the Y offset, so that the drag-image is always just below the cursor,
  // so that it is possible to see where the cursor is going.
  drag_offset_.set_y(0.f);
}

bool X11WholeScreenMoveLoop::GrabPointerWithCursor(gfx::NativeCursor cursor) {
  XDisplay* display = gfx::GetXDisplay();
  XGrabServer(display);
  XUngrabPointer(display, CurrentTime);
  int ret = XGrabPointer(
      display,
      grab_input_window_,
      False,
      ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
      GrabModeAsync,
      GrabModeAsync,
      None,
      cursor.platform(),
      CurrentTime);
  XUngrabServer(display);
  if (ret != GrabSuccess) {
    DLOG(ERROR) << "Grabbing new tab for dragging failed: "
                << ui::GetX11ErrorString(display, ret);
    return false;
  }

  return true;
}

Window X11WholeScreenMoveLoop::CreateDragInputWindow(XDisplay* display) {
  // Creates an invisible, InputOnly toplevel window. This window will receive
  // all mouse movement for drags. It turns out that normal windows doing a
  // grab doesn't redirect pointer motion events if the pointer isn't over the
  // grabbing window. But InputOnly windows are able to grab everything. This
  // is what GTK+ does, and I found a patch to KDE that did something similar.
  unsigned long attribute_mask = CWEventMask | CWOverrideRedirect;
  XSetWindowAttributes swa;
  memset(&swa, 0, sizeof(swa));
  swa.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
                   StructureNotifyMask;
  swa.override_redirect = True;
  Window window = XCreateWindow(display,
                                DefaultRootWindow(display),
                                -100, -100, 10, 10,
                                0, CopyFromParent, InputOnly, CopyFromParent,
                                attribute_mask, &swa);
  XMapRaised(display, window);
  base::MessagePumpX11::Current()->BlockUntilWindowMapped(window);
  return window;
}

void X11WholeScreenMoveLoop::CreateDragImageWindow() {
  Widget* widget = new Widget;
  Widget::InitParams params(Widget::InitParams::TYPE_DRAG);
  params.opacity = Widget::InitParams::OPAQUE_WINDOW;
  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  params.accept_events = false;

  gfx::Point location = gfx::ToFlooredPoint(
      gfx::Screen::GetNativeScreen()->GetCursorScreenPoint() - drag_offset_);
  params.bounds = gfx::Rect(location, drag_image_.size());
  widget->set_focus_on_creation(false);
  widget->set_frame_type(Widget::FRAME_TYPE_FORCE_NATIVE);
  widget->Init(params);
  widget->GetNativeWindow()->SetName("DragWindow");

  ImageView* image = new ImageView();
  image->SetImage(drag_image_);
  image->SetBounds(0, 0, drag_image_.width(), drag_image_.height());
  widget->SetContentsView(image);

  widget->Show();
  widget->GetNativeWindow()->layer()->SetFillsBoundsOpaquely(false);

  drag_widget_.reset(widget);
}

}  // namespace views
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2010 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

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

    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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/SamsungV2Decompressor.h"
#include "common/Common.h"                // for uint32, ushort16, int32
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB32.h"              // for BitPumpMSB32
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for max
#include <cassert>                        // for assert
#include <type_traits>                    // for underlying_type, underlyin...

namespace rawspeed {

// Seriously Samsung just use lossless jpeg already, it compresses better too :)

// Thanks to Michael Reichmann (Luminous Landscape) for putting Pedro Côrte-Real
// in contact and Loring von Palleske (Samsung) for pointing to the open-source
// code of Samsung's DNG converter at http://opensource.samsung.com/

enum struct SamsungV2Decompressor::OptFlags : uint32 {
  NONE = 0U,       // no flags
  SKIP = 1U << 0U, // Skip checking if we need differences from previous line
  MV = 1U << 1U,   // Simplify motion vector definition
  QP = 1U << 2U,   // Don't scale the diff values

  // all possible flags
  ALL = SKIP | MV | QP,
};

constexpr SamsungV2Decompressor::OptFlags
operator|(SamsungV2Decompressor::OptFlags lhs,
          SamsungV2Decompressor::OptFlags rhs) {
  return static_cast<SamsungV2Decompressor::OptFlags>(
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          lhs) |
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          rhs));
}

constexpr bool operator&(SamsungV2Decompressor::OptFlags lhs,
                         SamsungV2Decompressor::OptFlags rhs) {
  return SamsungV2Decompressor::OptFlags::NONE !=
         static_cast<SamsungV2Decompressor::OptFlags>(
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 lhs) &
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 rhs));
}

SamsungV2Decompressor::SamsungV2Decompressor(const RawImage& image,
                                             const ByteStream& bs, int bit)
    : AbstractSamsungDecompressor(image), bits(bit) {
  BitPumpMSB32 startpump(bs);

  // Process the initial metadata bits, we only really use initVal, width and
  // height (the last two match the TIFF values anyway)
  startpump.getBits(16); // NLCVersion
  startpump.getBits(4);  // ImgFormat
  bitDepth = startpump.getBits(4) + 1;
  startpump.getBits(4); // NumBlkInRCUnit
  startpump.getBits(4); // CompressionRatio
  width = startpump.getBits(16);
  height = startpump.getBits(16);
  startpump.getBits(16); // TileWidth
  startpump.getBits(4);  // reserved

  // The format includes an optimization code that sets 3 flags to change the
  // decoding parameters
  const uint32 optflags = startpump.getBits(4);
  if (optflags > static_cast<uint32>(OptFlags::ALL))
    ThrowRDE("Invalid opt flags %x", optflags);
  _flags = static_cast<OptFlags>(optflags);

  startpump.getBits(8); // OverlapWidth
  startpump.getBits(8); // reserved
  startpump.getBits(8); // Inc
  startpump.getBits(2); // reserved
  initVal = startpump.getBits(14);

  if (width == 0 || height == 0 || width % 16 != 0 || width > 6496 ||
      height > 4336)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);

  if (width != static_cast<uint32>(mRaw->dim.x) ||
      height != static_cast<uint32>(mRaw->dim.y))
    ThrowRDE("EXIF image dimensions do not match dimensions from raw header");

  data = startpump.getStream(startpump.getRemainSize());
}

void SamsungV2Decompressor::decompress() {
  switch (_flags) {
  case OptFlags::NONE:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::NONE>(row);
    break;
  case OptFlags::ALL:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::ALL>(row);
    break;

  case OptFlags::SKIP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP>(row);
    break;
  case OptFlags::MV:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::MV>(row);
    break;
  case OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::QP>(row);
    break;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
  case OptFlags::SKIP | OptFlags::MV:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::MV>(row);
    break;
  case OptFlags::SKIP | OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::QP>(row);
    break;

  case OptFlags::MV | OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::MV | OptFlags::QP>(row);
    break;
#pragma GCC diagnostic pop

  default:
    __builtin_unreachable();
  }
}

template <SamsungV2Decompressor::OptFlags optflags>
void SamsungV2Decompressor::decompressRow(uint32 row) {
  // The format is relatively straightforward. Each line gets encoded as a set
  // of differences from pixels from another line. Pixels are grouped in blocks
  // of 16 (8 green, 8 red or blue). Each block is encoded in three sections.
  // First 1 or 4 bits to specify which reference pixels to use, then a section
  // that specifies for each pixel the number of bits in the difference, then
  // the actual difference bits

  // Align pump to 16byte boundary
  const auto line_offset = data.getPosition();
  if ((line_offset & 0xf) != 0)
    data.skipBytes(16 - (line_offset & 0xf));

  BitPumpMSB32 pump(data);

  auto* img = reinterpret_cast<ushort16*>(mRaw->getData(0, row));
  ushort16* img_up = reinterpret_cast<ushort16*>(
      mRaw->getData(0, std::max(0, static_cast<int>(row) - 1)));
  ushort16* img_up2 = reinterpret_cast<ushort16*>(
      mRaw->getData(0, std::max(0, static_cast<int>(row) - 2)));

  // Initialize the motion and diff modes at the start of the line
  uint32 motion = 7;
  // By default we are not scaling values at all
  int32 scale = 0;

  uint32 diffBitsMode[3][2] = {{0}};
  for (auto& i : diffBitsMode)
    i[0] = i[1] = (row == 0 || row == 1) ? 7 : 4;

  assert(width >= 16);
  for (uint32 col = 0; col < width; col += 16) {
    if (!(optflags & OptFlags::QP) && !(col & 63)) {
      int32 scalevals[] = {0, -2, 2};
      uint32 i = pump.getBits(2);
      scale = i < 3 ? scale + scalevals[i] : pump.getBits(12);
    }

    // First we figure out which reference pixels mode we're in
    if (optflags & OptFlags::MV)
      motion = pump.getBits(1) ? 3 : 7;
    else if (!pump.getBits(1))
      motion = pump.getBits(3);

    if ((row == 0 || row == 1) && (motion != 7))
      ThrowRDE("At start of image and motion isn't 7. File corrupted?");

    if (motion == 7) {
      // The base case, just set all pixels to the previous ones on the same
      // line If we're at the left edge we just start at the initial value
      for (uint32 i = 0; i < 16; i++)
        img[i] = (col == 0) ? initVal : *(img + i - 2);
    } else {
      // The complex case, we now need to actually lookup one or two lines
      // above
      if (row < 2)
        ThrowRDE(
            "Got a previous line lookup on first two lines. File corrupted?");

      int32 motionOffset[7] = {-4, -2, -2, 0, 0, 2, 4};
      int32 motionDoAverage[7] = {0, 0, 1, 0, 1, 0, 0};

      int32 slideOffset = motionOffset[motion];
      int32 doAverage = motionDoAverage[motion];

      for (uint32 i = 0; i < 16; i++) {
        ushort16* refpixel;

        if ((row + i) & 0x1) // Red or blue pixels use same color two lines up
          refpixel = img_up2 + i + slideOffset;
        else // Green pixel N uses Green pixel N from row above (top left or
             // top right)
          refpixel = img_up + i + slideOffset + (((i % 2) != 0) ? -1 : 1);

        // In some cases we use as reference interpolation of this pixel and
        // the next
        if (doAverage)
          img[i] = (*refpixel + *(refpixel + 2) + 1) >> 1;
        else
          img[i] = *refpixel;
      }
    }

    // Figure out how many difference bits we have to read for each pixel
    uint32 diffBits[4] = {0};
    if (optflags & OptFlags::SKIP || !pump.getBits(1)) {
      uint32 flags[4];
      for (unsigned int& flag : flags)
        flag = pump.getBits(2);

      for (uint32 i = 0; i < 4; i++) {
        // The color is 0-Green 1-Blue 2-Red
        uint32 colornum = (row % 2 != 0) ? i >> 1 : ((i >> 1) + 2) % 3;

        assert(flags[i] <= 3);
        switch (flags[i]) {
        case 0:
          diffBits[i] = diffBitsMode[colornum][0];
          break;
        case 1:
          diffBits[i] = diffBitsMode[colornum][0] + 1;
          break;
        case 2:
          diffBits[i] = diffBitsMode[colornum][0] - 1;
          break;
        case 3:
          diffBits[i] = pump.getBits(4);
          break;
        default:
          __builtin_unreachable();
        }

        diffBitsMode[colornum][0] = diffBitsMode[colornum][1];
        diffBitsMode[colornum][1] = diffBits[i];

        if (diffBits[i] > bitDepth + 1)
          ThrowRDE("Too many difference bits. File corrupted?");
      }
    }

    // Actually read the differences and write them to the pixels
    for (uint32 i = 0; i < 16; i++) {
      uint32 len = diffBits[i >> 2];
      int32 diff = pump.getBits(len);

      // If the first bit is 1 we need to turn this into a negative number
      if (len != 0 && diff >> (len - 1))
        diff -= (1 << len);

      ushort16* value = nullptr;
      // Apply the diff to pixels 0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
      if (row % 2)
        value = &img[((i & 0x7) << 1) + 1 - (i >> 3)];
      else
        value = &img[((i & 0x7) << 1) + (i >> 3)];

      diff = diff * (scale * 2 + 1) + scale;
      *value = clampBits(static_cast<int>(*value) + diff, bits);
    }

    img += 16;
    img_up += 16;
    img_up2 += 16;
  }

  data.skipBytes(pump.getBufferPosition());
}

} // namespace rawspeed
<commit_msg>SamsungV2Decompressor::decompressRow(): "complex case": first 16 pix: check<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2010 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

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

    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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/SamsungV2Decompressor.h"
#include "common/Common.h"                // for uint32, ushort16, int32
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB32.h"              // for BitPumpMSB32
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for max
#include <cassert>                        // for assert
#include <type_traits>                    // for underlying_type, underlyin...

namespace rawspeed {

// Seriously Samsung just use lossless jpeg already, it compresses better too :)

// Thanks to Michael Reichmann (Luminous Landscape) for putting Pedro Côrte-Real
// in contact and Loring von Palleske (Samsung) for pointing to the open-source
// code of Samsung's DNG converter at http://opensource.samsung.com/

enum struct SamsungV2Decompressor::OptFlags : uint32 {
  NONE = 0U,       // no flags
  SKIP = 1U << 0U, // Skip checking if we need differences from previous line
  MV = 1U << 1U,   // Simplify motion vector definition
  QP = 1U << 2U,   // Don't scale the diff values

  // all possible flags
  ALL = SKIP | MV | QP,
};

constexpr SamsungV2Decompressor::OptFlags
operator|(SamsungV2Decompressor::OptFlags lhs,
          SamsungV2Decompressor::OptFlags rhs) {
  return static_cast<SamsungV2Decompressor::OptFlags>(
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          lhs) |
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          rhs));
}

constexpr bool operator&(SamsungV2Decompressor::OptFlags lhs,
                         SamsungV2Decompressor::OptFlags rhs) {
  return SamsungV2Decompressor::OptFlags::NONE !=
         static_cast<SamsungV2Decompressor::OptFlags>(
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 lhs) &
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 rhs));
}

SamsungV2Decompressor::SamsungV2Decompressor(const RawImage& image,
                                             const ByteStream& bs, int bit)
    : AbstractSamsungDecompressor(image), bits(bit) {
  BitPumpMSB32 startpump(bs);

  // Process the initial metadata bits, we only really use initVal, width and
  // height (the last two match the TIFF values anyway)
  startpump.getBits(16); // NLCVersion
  startpump.getBits(4);  // ImgFormat
  bitDepth = startpump.getBits(4) + 1;
  startpump.getBits(4); // NumBlkInRCUnit
  startpump.getBits(4); // CompressionRatio
  width = startpump.getBits(16);
  height = startpump.getBits(16);
  startpump.getBits(16); // TileWidth
  startpump.getBits(4);  // reserved

  // The format includes an optimization code that sets 3 flags to change the
  // decoding parameters
  const uint32 optflags = startpump.getBits(4);
  if (optflags > static_cast<uint32>(OptFlags::ALL))
    ThrowRDE("Invalid opt flags %x", optflags);
  _flags = static_cast<OptFlags>(optflags);

  startpump.getBits(8); // OverlapWidth
  startpump.getBits(8); // reserved
  startpump.getBits(8); // Inc
  startpump.getBits(2); // reserved
  initVal = startpump.getBits(14);

  if (width == 0 || height == 0 || width % 16 != 0 || width > 6496 ||
      height > 4336)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);

  if (width != static_cast<uint32>(mRaw->dim.x) ||
      height != static_cast<uint32>(mRaw->dim.y))
    ThrowRDE("EXIF image dimensions do not match dimensions from raw header");

  data = startpump.getStream(startpump.getRemainSize());
}

void SamsungV2Decompressor::decompress() {
  switch (_flags) {
  case OptFlags::NONE:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::NONE>(row);
    break;
  case OptFlags::ALL:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::ALL>(row);
    break;

  case OptFlags::SKIP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP>(row);
    break;
  case OptFlags::MV:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::MV>(row);
    break;
  case OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::QP>(row);
    break;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
  case OptFlags::SKIP | OptFlags::MV:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::MV>(row);
    break;
  case OptFlags::SKIP | OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::QP>(row);
    break;

  case OptFlags::MV | OptFlags::QP:
    for (uint32 row = 0; row < height; row++)
      decompressRow<OptFlags::MV | OptFlags::QP>(row);
    break;
#pragma GCC diagnostic pop

  default:
    __builtin_unreachable();
  }
}

template <SamsungV2Decompressor::OptFlags optflags>
void SamsungV2Decompressor::decompressRow(uint32 row) {
  // The format is relatively straightforward. Each line gets encoded as a set
  // of differences from pixels from another line. Pixels are grouped in blocks
  // of 16 (8 green, 8 red or blue). Each block is encoded in three sections.
  // First 1 or 4 bits to specify which reference pixels to use, then a section
  // that specifies for each pixel the number of bits in the difference, then
  // the actual difference bits

  // Align pump to 16byte boundary
  const auto line_offset = data.getPosition();
  if ((line_offset & 0xf) != 0)
    data.skipBytes(16 - (line_offset & 0xf));

  BitPumpMSB32 pump(data);

  auto* img = reinterpret_cast<ushort16*>(mRaw->getData(0, row));
  ushort16* img_up = reinterpret_cast<ushort16*>(
      mRaw->getData(0, std::max(0, static_cast<int>(row) - 1)));
  ushort16* img_up2 = reinterpret_cast<ushort16*>(
      mRaw->getData(0, std::max(0, static_cast<int>(row) - 2)));

  // Initialize the motion and diff modes at the start of the line
  uint32 motion = 7;
  // By default we are not scaling values at all
  int32 scale = 0;

  uint32 diffBitsMode[3][2] = {{0}};
  for (auto& i : diffBitsMode)
    i[0] = i[1] = (row == 0 || row == 1) ? 7 : 4;

  assert(width >= 16);
  for (uint32 col = 0; col < width; col += 16) {
    if (!(optflags & OptFlags::QP) && !(col & 63)) {
      int32 scalevals[] = {0, -2, 2};
      uint32 i = pump.getBits(2);
      scale = i < 3 ? scale + scalevals[i] : pump.getBits(12);
    }

    // First we figure out which reference pixels mode we're in
    if (optflags & OptFlags::MV)
      motion = pump.getBits(1) ? 3 : 7;
    else if (!pump.getBits(1))
      motion = pump.getBits(3);

    if ((row == 0 || row == 1) && (motion != 7))
      ThrowRDE("At start of image and motion isn't 7. File corrupted?");

    if (motion == 7) {
      // The base case, just set all pixels to the previous ones on the same
      // line If we're at the left edge we just start at the initial value
      for (uint32 i = 0; i < 16; i++)
        img[i] = (col == 0) ? initVal : *(img + i - 2);
    } else {
      // The complex case, we now need to actually lookup one or two lines
      // above
      if (row < 2)
        ThrowRDE(
            "Got a previous line lookup on first two lines. File corrupted?");

      int32 motionOffset[7] = {-4, -2, -2, 0, 0, 2, 4};
      int32 motionDoAverage[7] = {0, 0, 1, 0, 1, 0, 0};

      int32 slideOffset = motionOffset[motion];
      int32 doAverage = motionDoAverage[motion];

      for (uint32 i = 0; i < 16; i++) {
        ushort16* refpixel;

        if ((row + i) & 0x1) {
          // Red or blue pixels use same color two lines up
          refpixel = img_up2 + i + slideOffset;

          if (col == 0 && img_up2 > refpixel)
            ThrowRDE("Bad motion %u at the beginning of the row", motion);
        } else {
          // Green pixel N uses Green pixel N from row above
          // (top left or top right)
          refpixel = img_up + i + slideOffset + (((i % 2) != 0) ? -1 : 1);

          if (col == 0 && img_up > refpixel)
            ThrowRDE("Bad motion %u at the beginning of the row", motion);
        }

        // In some cases we use as reference interpolation of this pixel and
        // the next
        if (doAverage)
          img[i] = (*refpixel + *(refpixel + 2) + 1) >> 1;
        else
          img[i] = *refpixel;
      }
    }

    // Figure out how many difference bits we have to read for each pixel
    uint32 diffBits[4] = {0};
    if (optflags & OptFlags::SKIP || !pump.getBits(1)) {
      uint32 flags[4];
      for (unsigned int& flag : flags)
        flag = pump.getBits(2);

      for (uint32 i = 0; i < 4; i++) {
        // The color is 0-Green 1-Blue 2-Red
        uint32 colornum = (row % 2 != 0) ? i >> 1 : ((i >> 1) + 2) % 3;

        assert(flags[i] <= 3);
        switch (flags[i]) {
        case 0:
          diffBits[i] = diffBitsMode[colornum][0];
          break;
        case 1:
          diffBits[i] = diffBitsMode[colornum][0] + 1;
          break;
        case 2:
          diffBits[i] = diffBitsMode[colornum][0] - 1;
          break;
        case 3:
          diffBits[i] = pump.getBits(4);
          break;
        default:
          __builtin_unreachable();
        }

        diffBitsMode[colornum][0] = diffBitsMode[colornum][1];
        diffBitsMode[colornum][1] = diffBits[i];

        if (diffBits[i] > bitDepth + 1)
          ThrowRDE("Too many difference bits. File corrupted?");
      }
    }

    // Actually read the differences and write them to the pixels
    for (uint32 i = 0; i < 16; i++) {
      uint32 len = diffBits[i >> 2];
      int32 diff = pump.getBits(len);

      // If the first bit is 1 we need to turn this into a negative number
      if (len != 0 && diff >> (len - 1))
        diff -= (1 << len);

      ushort16* value = nullptr;
      // Apply the diff to pixels 0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
      if (row % 2)
        value = &img[((i & 0x7) << 1) + 1 - (i >> 3)];
      else
        value = &img[((i & 0x7) << 1) + (i >> 3)];

      diff = diff * (scale * 2 + 1) + scale;
      *value = clampBits(static_cast<int>(*value) + diff, bits);
    }

    img += 16;
    img_up += 16;
    img_up2 += 16;
  }

  data.skipBytes(pump.getBufferPosition());
}

} // namespace rawspeed
<|endoftext|>


<commit_before><commit_msg>forgot to stage part of the patch<commit_after><|endoftext|>