<commit_before>//===- PowerPCSubtarget.cpp - PPC Subtarget Information -------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the PPC specific subclass of TargetSubtarget.
//
//===----------------------------------------------------------------------===//

#include "PPCSubtarget.h"
#include "PPC.h"
#include "llvm/Module.h"
#include "llvm/Target/TargetMachine.h"
#include "PPCGenSubtarget.inc"
using namespace llvm;

#if defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#include <mach/machine.h>

/// GetCurrentPowerPCFeatures - Returns the current CPUs features.
static const char *GetCurrentPowerPCCPU() {
  host_basic_info_data_t hostInfo;
  mach_msg_type_number_t infoCount;

  infoCount = HOST_BASIC_INFO_COUNT;
  host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo,
            &infoCount);

  if (hostInfo.cpu_type != CPU_TYPE_POWERPC) return "generic";

  switch(hostInfo.cpu_subtype) {
  case CPU_SUBTYPE_POWERPC_601:   return "601";
  case CPU_SUBTYPE_POWERPC_602:   return "602";
  case CPU_SUBTYPE_POWERPC_603:   return "603";
  case CPU_SUBTYPE_POWERPC_603e:  return "603e";
  case CPU_SUBTYPE_POWERPC_603ev: return "603ev";
  case CPU_SUBTYPE_POWERPC_604:   return "604";
  case CPU_SUBTYPE_POWERPC_604e:  return "604e";
  case CPU_SUBTYPE_POWERPC_620:   return "620";
  case CPU_SUBTYPE_POWERPC_750:   return "750";
  case CPU_SUBTYPE_POWERPC_7400:  return "7400";
  case CPU_SUBTYPE_POWERPC_7450:  return "7450";
  case CPU_SUBTYPE_POWERPC_970:   return "970";
  default: ;
  }

  return "generic";
}
#endif

PPCSubtarget::PPCSubtarget(const TargetMachine &tm, const Module &M,
                           const std::string &FS, bool is64Bit)
  : TM(tm)
  , StackAlignment(16)
  , DarwinDirective(PPC::DIR_NONE)
  , IsGigaProcessor(false)
  , Has64BitSupport(false)
  , Use64BitRegs(false)
  , IsPPC64(is64Bit)
  , HasAltivec(false)
  , HasFSQRT(false)
  , HasSTFIWX(false)
  , HasLazyResolverStubs(false)
  , DarwinVers(0) {

  // Determine default and user specified characteristics
  std::string CPU = "generic";
#if defined(__APPLE__)
  CPU = GetCurrentPowerPCCPU();
#endif

  // Parse features string.
  ParseSubtargetFeatures(FS, CPU);

  // If we are generating code for ppc64, verify that options make sense.
  if (is64Bit) {
    if (!has64BitSupport()) {
      Has64BitSupport = true;
    }
    // Silently force 64-bit register use on ppc64.
    Use64BitRegs = true;
  }

  // If the user requested use of 64-bit regs, but the cpu selected doesn't
  // support it, warn and ignore.
  if (use64BitRegs() && !has64BitSupport()) {
    Use64BitRegs = false;
  }

  // Set the boolean corresponding to the current target triple, or the default
  // if one cannot be determined, to true.
  const std::string &TT = M.getTargetTriple();
  if (TT.length() > 7) {
    // Determine which version of darwin this is.
    size_t DarwinPos = TT.find("-darwin");
    if (DarwinPos != std::string::npos) {
      if (isdigit(TT[DarwinPos+7]))
        DarwinVers = atoi(&TT[DarwinPos+7]);
      else
        DarwinVers = 8;  // Minimum supported darwin is Tiger.
    }
  } else if (TT.empty()) {
    // Try to autosense the subtarget from the host compiler.
#if defined(__APPLE__)
#if __APPLE_CC__ > 5400
    DarwinVers = 9;  // GCC 5400+ is Leopard.
#else
    DarwinVers = 8;  // Minimum supported darwin is Tiger.
#endif
#endif
  }

  // Set up darwin-specific properties.
  if (isDarwin()) {
    HasLazyResolverStubs = true;
    AsmFlavor = NewMnemonic;
  } else {
    AsmFlavor = OldMnemonic;
  }
}

/// SetJITMode - This is called to inform the subtarget info that we are
/// producing code for the JIT.
void PPCSubtarget::SetJITMode() {
  // JIT mode doesn't want lazy resolver stubs, it knows exactly where
  // everything is.  This matters for PPC64, which codegens in PIC mode without
  // stubs.
  HasLazyResolverStubs = false;
}

/// hasLazyResolverStub - Return true if accesses to the specified global have
/// to go through a dyld lazy resolution stub.  This means that an extra load
/// is required to get the address of the global.
bool PPCSubtarget::hasLazyResolverStub(const GlobalValue *GV) const {
  // We never hae stubs if HasLazyResolverStubs=false or if in static mode.
  if (!HasLazyResolverStubs || TM.getRelocationModel() == Reloc::Static)
    return false;

  return GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
         (GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode());
}
<commit_msg>Cosmetics.<commit_after>//===- PowerPCSubtarget.cpp - PPC Subtarget Information -------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the PPC specific subclass of TargetSubtarget.
//
//===----------------------------------------------------------------------===//

#include "PPCSubtarget.h"
#include "PPC.h"
#include "llvm/Module.h"
#include "llvm/Target/TargetMachine.h"
#include "PPCGenSubtarget.inc"
using namespace llvm;

#if defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#include <mach/machine.h>

/// GetCurrentPowerPCFeatures - Returns the current CPUs features.
static const char *GetCurrentPowerPCCPU() {
  host_basic_info_data_t hostInfo;
  mach_msg_type_number_t infoCount;

  infoCount = HOST_BASIC_INFO_COUNT;
  host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo,
            &infoCount);

  if (hostInfo.cpu_type != CPU_TYPE_POWERPC) return "generic";

  switch(hostInfo.cpu_subtype) {
  case CPU_SUBTYPE_POWERPC_601:   return "601";
  case CPU_SUBTYPE_POWERPC_602:   return "602";
  case CPU_SUBTYPE_POWERPC_603:   return "603";
  case CPU_SUBTYPE_POWERPC_603e:  return "603e";
  case CPU_SUBTYPE_POWERPC_603ev: return "603ev";
  case CPU_SUBTYPE_POWERPC_604:   return "604";
  case CPU_SUBTYPE_POWERPC_604e:  return "604e";
  case CPU_SUBTYPE_POWERPC_620:   return "620";
  case CPU_SUBTYPE_POWERPC_750:   return "750";
  case CPU_SUBTYPE_POWERPC_7400:  return "7400";
  case CPU_SUBTYPE_POWERPC_7450:  return "7450";
  case CPU_SUBTYPE_POWERPC_970:   return "970";
  default: ;
  }

  return "generic";
}
#endif

PPCSubtarget::PPCSubtarget(const TargetMachine &tm, const Module &M,
                           const std::string &FS, bool is64Bit)
  : TM(tm)
  , StackAlignment(16)
  , DarwinDirective(PPC::DIR_NONE)
  , IsGigaProcessor(false)
  , Has64BitSupport(false)
  , Use64BitRegs(false)
  , IsPPC64(is64Bit)
  , HasAltivec(false)
  , HasFSQRT(false)
  , HasSTFIWX(false)
  , HasLazyResolverStubs(false)
  , DarwinVers(0) {

  // Determine default and user specified characteristics
  std::string CPU = "generic";
#if defined(__APPLE__)
  CPU = GetCurrentPowerPCCPU();
#endif

  // Parse features string.
  ParseSubtargetFeatures(FS, CPU);

  // If we are generating code for ppc64, verify that options make sense.
  if (is64Bit) {
    Has64BitSupport = true;
    // Silently force 64-bit register use on ppc64.
    Use64BitRegs = true;
  }

  // If the user requested use of 64-bit regs, but the cpu selected doesn't
  // support it, ignore.
  if (use64BitRegs() && !has64BitSupport())
    Use64BitRegs = false;

  // Set the boolean corresponding to the current target triple, or the default
  // if one cannot be determined, to true.
  const std::string &TT = M.getTargetTriple();
  if (TT.length() > 7) {
    // Determine which version of darwin this is.
    size_t DarwinPos = TT.find("-darwin");
    if (DarwinPos != std::string::npos) {
      if (isdigit(TT[DarwinPos+7]))
        DarwinVers = atoi(&TT[DarwinPos+7]);
      else
        DarwinVers = 8;  // Minimum supported darwin is Tiger.
    }
  } else if (TT.empty()) {
    // Try to autosense the subtarget from the host compiler.
#if defined(__APPLE__)
#if __APPLE_CC__ > 5400
    DarwinVers = 9;  // GCC 5400+ is Leopard.
#else
    DarwinVers = 8;  // Minimum supported darwin is Tiger.
#endif
#endif
  }

  // Set up darwin-specific properties.
  if (isDarwin()) {
    HasLazyResolverStubs = true;
    AsmFlavor = NewMnemonic;
  } else {
    AsmFlavor = OldMnemonic;
  }
}

/// SetJITMode - This is called to inform the subtarget info that we are
/// producing code for the JIT.
void PPCSubtarget::SetJITMode() {
  // JIT mode doesn't want lazy resolver stubs, it knows exactly where
  // everything is.  This matters for PPC64, which codegens in PIC mode without
  // stubs.
  HasLazyResolverStubs = false;
}

/// hasLazyResolverStub - Return true if accesses to the specified global have
/// to go through a dyld lazy resolution stub.  This means that an extra load
/// is required to get the address of the global.
bool PPCSubtarget::hasLazyResolverStub(const GlobalValue *GV) const {
  // We never hae stubs if HasLazyResolverStubs=false or if in static mode.
  if (!HasLazyResolverStubs || TM.getRelocationModel() == Reloc::Static)
    return false;

  return GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
         (GV->isDeclaration() && !GV->hasNotBeenReadFromBitcode());
}
<|endoftext|>


<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.
#include "global_timestamp_reader.h"
#include <chrono>

namespace librealsense
{
    CSample& CSample::operator-=(const CSample& other)
    {
        _x -= other._x;
        _y -= other._y;
        return *this;
    }

    CSample& CSample::operator+=(const CSample& other)
    {
        _x += other._x;
        _y += other._y;
        return *this;
    }

    CLinearCoefficients::CLinearCoefficients(unsigned int buffer_size) :
        _base_sample(0, 0),
        _buffer_size(buffer_size),
        _time_span_ms(1000) // Spread the linear equation modifications over a whole second.
    {
    }

    void CLinearCoefficients::reset()
    {
        _last_values.clear();
    }

    bool CLinearCoefficients::is_full() const
    {
        return _last_values.size() >= _buffer_size;
    }

    void CLinearCoefficients::add_value(CSample val)
    {
        std::lock_guard<std::recursive_mutex> lock(_add_mtx);   // Redandent as only being read from update_diff_time() and there is a lock there.
        while (_last_values.size() > _buffer_size)
        {
            _last_values.pop_back();
        }
        _last_values.push_front(val);
        calc_linear_coefs();
    }

    void CLinearCoefficients::calc_linear_coefs()
    {
        // Calculate linear coefficients, based on calculus described in: https://www.statisticshowto.datasciencecentral.com/probability-and-statistics/regression-analysis/find-a-linear-regression-equation/
        // Calculate Std
        double n(static_cast<double>(_last_values.size()));
        double a(1);
        double b(0);
        double crnt_time(_last_values.front()._x);
        double dt(1);
        if (n == 1)
        {
            _base_sample = _last_values.back();
            _dest_a = 1;
            _dest_b = 0;
            _prev_a = 0;
            _prev_b = 0;
        }
        else
        {
            double sum_x(0);
            double sum_y(0);
            double sum_xy(0);
            double sum_x2(0);
            for (auto sample = _last_values.begin(); sample != _last_values.end(); sample++)
            {
                CSample crnt_sample(*sample);
                crnt_sample -= _base_sample;
                sum_x += crnt_sample._x;
                sum_y += crnt_sample._y;
                sum_xy += (crnt_sample._x * crnt_sample._y);
                sum_x2 += (crnt_sample._x * crnt_sample._x);
            }
            b = (sum_y*sum_x2 - sum_x * sum_xy) / (n*sum_x2 - sum_x * sum_x);
            a = (n*sum_xy - sum_x * sum_y) / (n*sum_x2 - sum_x * sum_x);

            if (crnt_time - _prev_time < _time_span_ms)
            {
                dt = (crnt_time - _prev_time) / _time_span_ms;
            }
        }
        std::lock_guard<std::recursive_mutex> lock(_stat_mtx);
        _prev_a = _dest_a * dt + _prev_a * (1 - dt);
        _prev_b = _dest_b * dt + _prev_b * (1 - dt);
        _dest_a = a;
        _dest_b = b;
        _prev_time = crnt_time;
    }

    double CLinearCoefficients::calc_value(double x) const
    {
        std::lock_guard<std::recursive_mutex> lock(_stat_mtx);
        double a(_dest_a), b(_dest_b);
        if (x - _prev_time < _time_span_ms)
        {
            double dt( (x - _prev_time) / _time_span_ms );
            a = _dest_a * dt + _prev_a * (1 - dt);
            b = _dest_b * dt + _prev_b * (1 - dt);
        }
        double y(a * (x - _base_sample._x) + b + _base_sample._y);
        LOG_DEBUG("CLinearCoefficients::calc_value: " << x << " -> " << y << " with coefs:" << a << ", " << b << ", " << _base_sample._x << ", " << _base_sample._y);
        return y;
    }

    time_diff_keeper::time_diff_keeper(global_time_interface* dev, const unsigned int sampling_interval_ms) :
        _device(dev),
        _poll_intervals_ms(sampling_interval_ms),
        _last_sample_hw_time(1e+200),
        _coefs(15),
        _users_count(0),
        _is_ready(false),
        _active_object([this](dispatcher::cancellable_timer cancellable_timer)
            {
                polling(cancellable_timer);
            })
    {
        //LOG_DEBUG("start new time_diff_keeper ");
    }

    void time_diff_keeper::start()
    {
        std::lock_guard<std::recursive_mutex> lock(_enable_mtx);
        _users_count++;
        LOG_DEBUG("time_diff_keeper::start: _users_count = " << _users_count);
        _active_object.start();
    }

    void time_diff_keeper::stop()
    {
        std::lock_guard<std::recursive_mutex> lock(_enable_mtx);
        if (_users_count <= 0)
            LOG_ERROR("time_diff_keeper users_count <= 0.");

        _users_count--;
        LOG_DEBUG("time_diff_keeper::stop: _users_count = " << _users_count);
        if (_users_count == 0)
        {
            LOG_DEBUG("time_diff_keeper::stop: stop object.");
            _active_object.stop();
            _coefs.reset();
        }
    }

    time_diff_keeper::~time_diff_keeper()
    {
        _active_object.stop();
    }

    bool time_diff_keeper::update_diff_time()
    {
        using namespace std::chrono;
        try
        {
            if (!_users_count)
                throw wrong_api_call_sequence_exception("time_diff_keeper::update_diff_time called before object started.");
            std::lock_guard<std::recursive_mutex> lock(_mtx);
            double system_time_start = duration<double, std::milli>(system_clock::now().time_since_epoch()).count();

            double sample_hw_time = _device->get_device_time_ms();
            double system_time_finish = duration<double, std::milli>(system_clock::now().time_since_epoch()).count();
            double system_time((system_time_finish + system_time_start) / 2);
            if (sample_hw_time < _last_sample_hw_time)
            {
                // A time loop happend:
                //LOG_DEBUG("time_diff_keeper::call reset()");
                _coefs.reset();
            }
            _last_sample_hw_time = sample_hw_time;
            CSample crnt_sample(_last_sample_hw_time, system_time);
            _coefs.add_value(crnt_sample);
            _is_ready = true;
            return true;
        }
        catch (const wrong_api_call_sequence_exception& ex)
        {
            LOG_DEBUG("Temporary skip during time_diff_keeper polling: " << ex.what());
        }
        catch (const std::exception& ex)
        {
            LOG_ERROR("Error during time_diff_keeper polling: " << ex.what());
        }
        catch (...)
        {
            LOG_ERROR("Unknown error during time_diff_keeper polling!");
        }
        return false;
    }

    void time_diff_keeper::polling(dispatcher::cancellable_timer cancellable_timer)
    {
        unsigned int time_to_sleep = _poll_intervals_ms + _coefs.is_full() * (9 * _poll_intervals_ms);
        if (cancellable_timer.try_sleep(time_to_sleep))
        {
            update_diff_time();
        }
        else
        {
            LOG_DEBUG("Notification: time_diff_keeper polling loop is being shut-down");
        }
    }

    double time_diff_keeper::get_system_hw_time(double crnt_hw_time, bool& is_ready)
    {
        static const double possible_loop_time(3000);
        {
            std::lock_guard<std::recursive_mutex> lock(_read_mtx);
            if ((_last_sample_hw_time - crnt_hw_time) > possible_loop_time)
            {
                update_diff_time();
            }
        }
        is_ready = _is_ready;
        if (_is_ready)
            return _coefs.calc_value(crnt_hw_time);
        else
            return crnt_hw_time;
    }

    global_timestamp_reader::global_timestamp_reader(std::unique_ptr<frame_timestamp_reader> device_timestamp_reader,
                                                     std::shared_ptr<time_diff_keeper> timediff,
                                                     std::shared_ptr<global_time_option> enable_option) :
        _device_timestamp_reader(std::move(device_timestamp_reader)),
        _time_diff_keeper(timediff),
        _option_is_enabled(enable_option),
        _ts_is_ready(false)
    {
    }

    double global_timestamp_reader::get_frame_timestamp(const std::shared_ptr<frame_interface>& frame)
    {
        double frame_time = _device_timestamp_reader->get_frame_timestamp(frame);
        rs2_timestamp_domain ts_domain = _device_timestamp_reader->get_frame_timestamp_domain(frame);
        if (_option_is_enabled->is_true() && ts_domain == RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK)
        {
            auto sp = _time_diff_keeper.lock();
            if (sp)
                frame_time = sp->get_system_hw_time(frame_time, _ts_is_ready);
            else
                LOG_DEBUG("Notification: global_timestamp_reader - time_diff_keeper is being shut-down");
        }
        return frame_time;
    }

    unsigned long long global_timestamp_reader::get_frame_counter(const std::shared_ptr<frame_interface>& frame) const
    {
        return _device_timestamp_reader->get_frame_counter(frame);
    }

    rs2_timestamp_domain global_timestamp_reader::get_frame_timestamp_domain(const std::shared_ptr<frame_interface>& frame) const
    {
        rs2_timestamp_domain ts_domain = _device_timestamp_reader->get_frame_timestamp_domain(frame);
        return (_option_is_enabled->is_true() && _ts_is_ready && ts_domain == RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK) ? RS2_TIMESTAMP_DOMAIN_GLOBAL_TIME : ts_domain;
    }

    void global_timestamp_reader::reset()
    {
        _device_timestamp_reader->reset();
    }

    global_time_interface::global_time_interface() :
        _tf_keeper(std::make_shared<time_diff_keeper>(this, 100))
    {}

    void global_time_interface::enable_time_diff_keeper(bool is_enable)
    {
        if (is_enable)
            _tf_keeper->start();
        else
            _tf_keeper->stop();
    }
}
<commit_msg>fix bug: sometimes calls for get_device_time_ms() takes too long and the assumption that the system time corresponding with hw time is in the midpoint between start and end of call is not true.<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.
#include "global_timestamp_reader.h"
#include <chrono>

namespace librealsense
{
    CSample& CSample::operator-=(const CSample& other)
    {
        _x -= other._x;
        _y -= other._y;
        return *this;
    }

    CSample& CSample::operator+=(const CSample& other)
    {
        _x += other._x;
        _y += other._y;
        return *this;
    }

    CLinearCoefficients::CLinearCoefficients(unsigned int buffer_size) :
        _base_sample(0, 0),
        _buffer_size(buffer_size),
        _time_span_ms(1000) // Spread the linear equation modifications over a whole second.
    {
    }

    void CLinearCoefficients::reset()
    {
        _last_values.clear();
    }

    bool CLinearCoefficients::is_full() const
    {
        return _last_values.size() >= _buffer_size;
    }

    void CLinearCoefficients::add_value(CSample val)
    {
        std::lock_guard<std::recursive_mutex> lock(_add_mtx);   // Redandent as only being read from update_diff_time() and there is a lock there.
        while (_last_values.size() > _buffer_size)
        {
            _last_values.pop_back();
        }
        _last_values.push_front(val);
        calc_linear_coefs();
    }

    void CLinearCoefficients::calc_linear_coefs()
    {
        // Calculate linear coefficients, based on calculus described in: https://www.statisticshowto.datasciencecentral.com/probability-and-statistics/regression-analysis/find-a-linear-regression-equation/
        // Calculate Std
        double n(static_cast<double>(_last_values.size()));
        double a(1);
        double b(0);
        double crnt_time(_last_values.front()._x);
        double dt(1);
        if (n == 1)
        {
            _base_sample = _last_values.back();
            _dest_a = 1;
            _dest_b = 0;
            _prev_a = 0;
            _prev_b = 0;
        }
        else
        {
            double sum_x(0);
            double sum_y(0);
            double sum_xy(0);
            double sum_x2(0);
            for (auto sample = _last_values.begin(); sample != _last_values.end(); sample++)
            {
                CSample crnt_sample(*sample);
                crnt_sample -= _base_sample;
                sum_x += crnt_sample._x;
                sum_y += crnt_sample._y;
                sum_xy += (crnt_sample._x * crnt_sample._y);
                sum_x2 += (crnt_sample._x * crnt_sample._x);
            }
            b = (sum_y*sum_x2 - sum_x * sum_xy) / (n*sum_x2 - sum_x * sum_x);
            a = (n*sum_xy - sum_x * sum_y) / (n*sum_x2 - sum_x * sum_x);

            if (crnt_time - _prev_time < _time_span_ms)
            {
                dt = (crnt_time - _prev_time) / _time_span_ms;
            }
        }
        std::lock_guard<std::recursive_mutex> lock(_stat_mtx);
        _prev_a = _dest_a * dt + _prev_a * (1 - dt);
        _prev_b = _dest_b * dt + _prev_b * (1 - dt);
        _dest_a = a;
        _dest_b = b;
        _prev_time = crnt_time;
    }

    double CLinearCoefficients::calc_value(double x) const
    {
        std::lock_guard<std::recursive_mutex> lock(_stat_mtx);
        double a(_dest_a), b(_dest_b);
        if (x - _prev_time < _time_span_ms)
        {
            double dt( (x - _prev_time) / _time_span_ms );
            a = _dest_a * dt + _prev_a * (1 - dt);
            b = _dest_b * dt + _prev_b * (1 - dt);
        }
        double y(a * (x - _base_sample._x) + b + _base_sample._y);
        LOG_DEBUG("CLinearCoefficients::calc_value: " << x << " -> " << y << " with coefs:" << a << ", " << b << ", " << _base_sample._x << ", " << _base_sample._y);
        return y;
    }

    time_diff_keeper::time_diff_keeper(global_time_interface* dev, const unsigned int sampling_interval_ms) :
        _device(dev),
        _poll_intervals_ms(sampling_interval_ms),
        _last_sample_hw_time(1e+200),
        _coefs(15),
        _users_count(0),
        _is_ready(false),
        _active_object([this](dispatcher::cancellable_timer cancellable_timer)
            {
                polling(cancellable_timer);
            })
    {
        //LOG_DEBUG("start new time_diff_keeper ");
    }

    void time_diff_keeper::start()
    {
        std::lock_guard<std::recursive_mutex> lock(_enable_mtx);
        _users_count++;
        LOG_DEBUG("time_diff_keeper::start: _users_count = " << _users_count);
        _active_object.start();
    }

    void time_diff_keeper::stop()
    {
        std::lock_guard<std::recursive_mutex> lock(_enable_mtx);
        if (_users_count <= 0)
            LOG_ERROR("time_diff_keeper users_count <= 0.");

        _users_count--;
        LOG_DEBUG("time_diff_keeper::stop: _users_count = " << _users_count);
        if (_users_count == 0)
        {
            LOG_DEBUG("time_diff_keeper::stop: stop object.");
            _active_object.stop();
            _coefs.reset();
        }
    }

    time_diff_keeper::~time_diff_keeper()
    {
        _active_object.stop();
    }

    bool time_diff_keeper::update_diff_time()
    {
        using namespace std::chrono;
        try
        {
            if (!_users_count)
                throw wrong_api_call_sequence_exception("time_diff_keeper::update_diff_time called before object started.");
            std::lock_guard<std::recursive_mutex> lock(_mtx);
            double system_time_start = duration<double, std::milli>(system_clock::now().time_since_epoch()).count();

            double sample_hw_time = _device->get_device_time_ms();
            double system_time_finish = duration<double, std::milli>(system_clock::now().time_since_epoch()).count();
            if (system_time_finish - system_time_start > 2.0)
                throw io_exception("get_device_time_ms() took too long (more then 2 mSecs)");
            double system_time((system_time_finish + system_time_start) / 2);
            if (sample_hw_time < _last_sample_hw_time)
            {
                // A time loop happend:
                //LOG_DEBUG("time_diff_keeper::call reset()");
                _coefs.reset();
            }
            _last_sample_hw_time = sample_hw_time;
            CSample crnt_sample(_last_sample_hw_time, system_time);
            _coefs.add_value(crnt_sample);
            _is_ready = true;
            return true;
        }
        catch (const io_exception& ex)
        {
            LOG_DEBUG("Temporary skip during time_diff_keeper polling: " << ex.what());
        }
        catch (const wrong_api_call_sequence_exception& ex)
        {
            LOG_DEBUG("Temporary skip during time_diff_keeper polling: " << ex.what());
        }
        catch (const std::exception& ex)
        {
            LOG_ERROR("Error during time_diff_keeper polling: " << ex.what());
        }
        catch (...)
        {
            LOG_ERROR("Unknown error during time_diff_keeper polling!");
        }
        return false;
    }

    void time_diff_keeper::polling(dispatcher::cancellable_timer cancellable_timer)
    {
        unsigned int time_to_sleep = _poll_intervals_ms + _coefs.is_full() * (9 * _poll_intervals_ms);
        if (cancellable_timer.try_sleep(time_to_sleep))
        {
            update_diff_time();
        }
        else
        {
            LOG_DEBUG("Notification: time_diff_keeper polling loop is being shut-down");
        }
    }

    double time_diff_keeper::get_system_hw_time(double crnt_hw_time, bool& is_ready)
    {
        static const double possible_loop_time(3000);
        {
            std::lock_guard<std::recursive_mutex> lock(_read_mtx);
            if ((_last_sample_hw_time - crnt_hw_time) > possible_loop_time)
            {
                update_diff_time();
            }
        }
        is_ready = _is_ready;
        if (_is_ready)
            return _coefs.calc_value(crnt_hw_time);
        else
            return crnt_hw_time;
    }

    global_timestamp_reader::global_timestamp_reader(std::unique_ptr<frame_timestamp_reader> device_timestamp_reader,
                                                     std::shared_ptr<time_diff_keeper> timediff,
                                                     std::shared_ptr<global_time_option> enable_option) :
        _device_timestamp_reader(std::move(device_timestamp_reader)),
        _time_diff_keeper(timediff),
        _option_is_enabled(enable_option),
        _ts_is_ready(false)
    {
    }

    double global_timestamp_reader::get_frame_timestamp(const std::shared_ptr<frame_interface>& frame)
    {
        double frame_time = _device_timestamp_reader->get_frame_timestamp(frame);
        rs2_timestamp_domain ts_domain = _device_timestamp_reader->get_frame_timestamp_domain(frame);
        if (_option_is_enabled->is_true() && ts_domain == RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK)
        {
            auto sp = _time_diff_keeper.lock();
            if (sp)
                frame_time = sp->get_system_hw_time(frame_time, _ts_is_ready);
            else
                LOG_DEBUG("Notification: global_timestamp_reader - time_diff_keeper is being shut-down");
        }
        return frame_time;
    }

    unsigned long long global_timestamp_reader::get_frame_counter(const std::shared_ptr<frame_interface>& frame) const
    {
        return _device_timestamp_reader->get_frame_counter(frame);
    }

    rs2_timestamp_domain global_timestamp_reader::get_frame_timestamp_domain(const std::shared_ptr<frame_interface>& frame) const
    {
        rs2_timestamp_domain ts_domain = _device_timestamp_reader->get_frame_timestamp_domain(frame);
        return (_option_is_enabled->is_true() && _ts_is_ready && ts_domain == RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK) ? RS2_TIMESTAMP_DOMAIN_GLOBAL_TIME : ts_domain;
    }

    void global_timestamp_reader::reset()
    {
        _device_timestamp_reader->reset();
    }

    global_time_interface::global_time_interface() :
        _tf_keeper(std::make_shared<time_diff_keeper>(this, 100))
    {}

    void global_time_interface::enable_time_diff_keeper(bool is_enable)
    {
        if (is_enable)
            _tf_keeper->start();
        else
            _tf_keeper->stop();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2017 The Bitcoin Core developers
// Copyright (c) 2009-2017 The DigiByte Core developers
// Copyright (c) 2013-2014 Phoenixcoin Developers
// Copyright (c) 2016-2018 The CryptoCoderz Team / Espers
// Copyright (c) 2017-2018 The AmsterdamCoin developers
// Copyright (c) 2009-2016 The Litecoin Core developers
// Copyright (c) 2014-2017 The Mun Core developers
// Copyright (c) 2017 The Raven Core developers
// Copyright (c) 2018-2019 The GlobalToken Core developers
// Copyright (c) 2018-2018 The Pptp Core developers
// Copyright (c) 2017-2018 The XDNA Core developers
// Copyright (c) 2017-2018 The Denarius developers
// Copyright (c) 2019 The Globaltoken Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <globaltoken/multihasher.h>
#include <globaltoken/powalgorithm.h>
#include <crypto/algos/hashlib/multihash.h>
#include <crypto/algos/neoscrypt/neoscrypt.h>
#include <crypto/algos/scrypt/scrypt.h>
#include <crypto/algos/yescrypt/yescrypt.h>
#include <crypto/algos/Lyra2RE/Lyra2RE.h>
#include <crypto/algos/Lyra2RE/Lyra2Z.h>
#include <crypto/algos/blake/hashblake.h>
#include <crypto/algos/bcrypt/bcrypt.h>
#include <crypto/algos/argon2d/hashargon.h>
#include <crypto/algos/yespower/yespower.h>
#include <crypto/algos/honeycomb/hash_honeycomb.h>
#include <crypto/algos/allium/allium.h>
#include <uint256.h>
#include <hash.h>

uint256 CMultihasher::GetSHA256Hash() const
{
    CHashWriter ss(nType, nVersion);
    for(size_t i = 0; i < buf.size(); i++)
        ss << buf[i];
    return ss.GetHash();
}

uint256 CMultihasher::GetHash() const
{
    switch (nAlgo)
    {
        case ALGO_SHA256D:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_SCRYPT:
        {
            uint256 thash;
            assert(buf.size() == 80);
            scrypt_1024_1_1_256((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_X11:
        {
            return HashX11(buf.data(), buf.data() + buf.size());
        }
        case ALGO_NEOSCRYPT:
        {
            unsigned int profile = 0x0;
            uint256 thash;
            assert(buf.size() == 80);
            neoscrypt(buf.data(), (unsigned char *)&thash, profile);
            return thash;
        }
        case ALGO_EQUIHASH:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_YESCRYPT:
        {
            uint256 thash;
            assert(buf.size() == 80);
            yescrypt_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_HMQ1725:
        {
            return HMQ1725(buf.data(), buf.data() + buf.size());
        }
        case ALGO_XEVAN:
        {
            return XEVAN(buf.data(), buf.data() + buf.size());
        }
        case ALGO_NIST5:
        {
            return NIST5(buf.data(), buf.data() + buf.size());
        }
        case ALGO_TIMETRAVEL10:
        {
            assert(buf.size() == 80);
            uint32_t nTime;
            memcpy(&nTime, buf.data() + 68, 4);
            return HashTimeTravel(buf.data(), buf.data() + buf.size(), nTime);
        }
        case ALGO_PAWELHASH:
        {
            return PawelHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X13:
        {
            return HashX13(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X14:
        {
            return HashX14(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X15:
        {
            return HashX15(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X17:
        {
            return HashX17(buf.data(), buf.data() + buf.size());
        }
        case ALGO_LYRA2REV2:
        {
            assert(buf.size() == 80);
            uint256 thash;
            lyra2re2_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_BLAKE2S:
        {
            return HashBlake2S(buf.data(), buf.data() + buf.size());
        }
        case ALGO_BLAKE2B:
        {
            return HashBlake2B(buf.data(), buf.data() + buf.size());
        }
        case ALGO_ASTRALHASH:
        {
            return AstralHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_PADIHASH:
        {
            return PadiHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_JEONGHASH:
        {
            return JeongHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_KECCAKC:
        {
            return HashKeccakC(buf.data(), buf.data() + buf.size());
        }
        case ALGO_ZHASH:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_GLOBALHASH:
        {
            return GlobalHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_GROESTL:
        {
            return HashGroestl(buf.data(), buf.data() + buf.size());
        }
        case ALGO_SKEIN:
        {
            return HashSkein(buf.data(), buf.data() + buf.size());
        }
        case ALGO_QUBIT:
        {
            return HashQubit(buf.data(), buf.data() + buf.size());
        }
        case ALGO_SKUNKHASH:
        {
            return SkunkHash5(buf.data(), buf.data() + buf.size());
        }
        case ALGO_QUARK:
        {
            return QUARK(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X16R:
        {
            assert(buf.size() == 80);
            uint256 hashPrevBlock;
            memcpy(&hashPrevBlock, buf.data() + 4, 32);
            return HashX16R(buf.data(), buf.data() + buf.size(), hashPrevBlock);
        }
        case ALGO_LYRA2REV3:
        {
            assert(buf.size() == 80);
            uint256 thash;
            lyra2re3_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_YESCRYPT_R16V2:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yescrypt_r16v2_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_YESCRYPT_R24:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yescrypt_r24_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_YESCRYPT_R8:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yescrypt_r8_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_YESCRYPT_R32:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yescrypt_r32_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_BCRYPT:
        {
            uint256 thash;
            bcrypt((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_ARGON2D:
        {
            assert(buf.size() == 80);
            uint32_t nTime;
            memcpy(&nTime, buf.data() + 68, 4);
            uint256 thash;
            Argon2dHash((const char*)buf.data(), (char*)&thash, nTime);
            return thash;
        }
        case ALGO_ARGON2I:
        {
            assert(buf.size() == 80);
            uint32_t nTime;
            memcpy(&nTime, buf.data() + 68, 4);
            uint256 thash;
            Argon2iHash((const char*)buf.data(), (char*)&thash, nTime);
            return thash;
        }
        case ALGO_CPU23R:
        {
            assert(buf.size() == 80);
            uint256 hashPrevBlock;
            memcpy(&hashPrevBlock, buf.data() + 4, 32);
            return HashCPU23R(buf.data(), buf.data() + buf.size(), hashPrevBlock);
        }
        case ALGO_YESPOWER:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yespower_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_X21S:
        {
            assert(buf.size() == 80);
            uint256 hashPrevBlock;
            memcpy(&hashPrevBlock, buf.data() + 4, 32);
            return HashX21S(buf.data(), buf.data() + buf.size(), hashPrevBlock);
        }
        case ALGO_X16S:
        {
            assert(buf.size() == 80);
            uint256 hashPrevBlock;
            memcpy(&hashPrevBlock, buf.data() + 4, 32);
            return HashX16s(buf.data(), buf.data() + buf.size(), hashPrevBlock);
        }
        case ALGO_X22I:
        {
            return HashX22I(buf.data(), buf.data() + buf.size());
        }
        case ALGO_LYRA2Z:
        {
            assert(buf.size() == 80);
            uint256 thash;
            lyra2z_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_HONEYCOMB:
        {
            return HashHoneyComb(buf.data(), buf.data() + buf.size());
        }
        case ALGO_EH192:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_MARS:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_X12:
        {
            return HashX12(buf.data(), buf.data() + buf.size());
        }
        case ALGO_HEX:
        {
            return HashHEX(buf.data(), buf.data() + buf.size());
        }
        case ALGO_DEDAL:
        {
            return HashDedal(buf.data(), buf.data() + buf.size());
        }
        case ALGO_C11:
        {
            return HashC11(buf.data(), buf.data() + buf.size());
        }
        case ALGO_PHI1612:
        {
            return Phi1612(buf.data(), buf.data() + buf.size());
        }
        case ALGO_PHI2:
        {
            return PHI2(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X16RT:
        {
            assert(buf.size() == 80);
            uint32_t nTime;
            unsigned char timeBuffer[4];
            memcpy(&nTime, buf.data() + 68, 4);
            int32_t nTimeX16r = nTime & 0xffffff80;
            memcpy(&timeBuffer, &nTimeX16r, 4);
            uint256 hashTime = Hash(timeBuffer, timeBuffer + 3);
            return HashX16R(buf.data(), buf.data() + buf.size(), hashTime);
        }
        case ALGO_TRIBUS:
        {
            return Tribus(buf.data(), buf.data() + buf.size());
        }
        case ALGO_ALLIUM:
        {
            assert(buf.size() == 80);
            uint256 thash;
            allium_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_ARCTICHASH:
        {
            return ArcticHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_DESERTHASH:
        {
            return DesertHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_CRYPTOANDCOFFEE:
        {
            return cryptoandcoffee_hash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_RICKHASH:
        {
            return RickHash(buf.data(), buf.data() + buf.size());
        }
    }
    return this->GetSHA256Hash();
}<commit_msg>Changed X16RT hashTime hash<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2017 The Bitcoin Core developers
// Copyright (c) 2009-2017 The DigiByte Core developers
// Copyright (c) 2013-2014 Phoenixcoin Developers
// Copyright (c) 2016-2018 The CryptoCoderz Team / Espers
// Copyright (c) 2017-2018 The AmsterdamCoin developers
// Copyright (c) 2009-2016 The Litecoin Core developers
// Copyright (c) 2014-2017 The Mun Core developers
// Copyright (c) 2017 The Raven Core developers
// Copyright (c) 2018-2019 The GlobalToken Core developers
// Copyright (c) 2018-2018 The Pptp Core developers
// Copyright (c) 2017-2018 The XDNA Core developers
// Copyright (c) 2017-2018 The Denarius developers
// Copyright (c) 2019 The Globaltoken Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <globaltoken/multihasher.h>
#include <globaltoken/powalgorithm.h>
#include <crypto/algos/hashlib/multihash.h>
#include <crypto/algos/neoscrypt/neoscrypt.h>
#include <crypto/algos/scrypt/scrypt.h>
#include <crypto/algos/yescrypt/yescrypt.h>
#include <crypto/algos/Lyra2RE/Lyra2RE.h>
#include <crypto/algos/Lyra2RE/Lyra2Z.h>
#include <crypto/algos/blake/hashblake.h>
#include <crypto/algos/bcrypt/bcrypt.h>
#include <crypto/algos/argon2d/hashargon.h>
#include <crypto/algos/yespower/yespower.h>
#include <crypto/algos/honeycomb/hash_honeycomb.h>
#include <crypto/algos/allium/allium.h>
#include <uint256.h>
#include <hash.h>

uint256 CMultihasher::GetSHA256Hash() const
{
    CHashWriter ss(nType, nVersion);
    for(size_t i = 0; i < buf.size(); i++)
        ss << buf[i];
    return ss.GetHash();
}

uint256 CMultihasher::GetHash() const
{
    switch (nAlgo)
    {
        case ALGO_SHA256D:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_SCRYPT:
        {
            uint256 thash;
            assert(buf.size() == 80);
            scrypt_1024_1_1_256((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_X11:
        {
            return HashX11(buf.data(), buf.data() + buf.size());
        }
        case ALGO_NEOSCRYPT:
        {
            unsigned int profile = 0x0;
            uint256 thash;
            assert(buf.size() == 80);
            neoscrypt(buf.data(), (unsigned char *)&thash, profile);
            return thash;
        }
        case ALGO_EQUIHASH:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_YESCRYPT:
        {
            uint256 thash;
            assert(buf.size() == 80);
            yescrypt_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_HMQ1725:
        {
            return HMQ1725(buf.data(), buf.data() + buf.size());
        }
        case ALGO_XEVAN:
        {
            return XEVAN(buf.data(), buf.data() + buf.size());
        }
        case ALGO_NIST5:
        {
            return NIST5(buf.data(), buf.data() + buf.size());
        }
        case ALGO_TIMETRAVEL10:
        {
            assert(buf.size() == 80);
            uint32_t nTime;
            memcpy(&nTime, buf.data() + 68, 4);
            return HashTimeTravel(buf.data(), buf.data() + buf.size(), nTime);
        }
        case ALGO_PAWELHASH:
        {
            return PawelHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X13:
        {
            return HashX13(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X14:
        {
            return HashX14(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X15:
        {
            return HashX15(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X17:
        {
            return HashX17(buf.data(), buf.data() + buf.size());
        }
        case ALGO_LYRA2REV2:
        {
            assert(buf.size() == 80);
            uint256 thash;
            lyra2re2_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_BLAKE2S:
        {
            return HashBlake2S(buf.data(), buf.data() + buf.size());
        }
        case ALGO_BLAKE2B:
        {
            return HashBlake2B(buf.data(), buf.data() + buf.size());
        }
        case ALGO_ASTRALHASH:
        {
            return AstralHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_PADIHASH:
        {
            return PadiHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_JEONGHASH:
        {
            return JeongHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_KECCAKC:
        {
            return HashKeccakC(buf.data(), buf.data() + buf.size());
        }
        case ALGO_ZHASH:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_GLOBALHASH:
        {
            return GlobalHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_GROESTL:
        {
            return HashGroestl(buf.data(), buf.data() + buf.size());
        }
        case ALGO_SKEIN:
        {
            return HashSkein(buf.data(), buf.data() + buf.size());
        }
        case ALGO_QUBIT:
        {
            return HashQubit(buf.data(), buf.data() + buf.size());
        }
        case ALGO_SKUNKHASH:
        {
            return SkunkHash5(buf.data(), buf.data() + buf.size());
        }
        case ALGO_QUARK:
        {
            return QUARK(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X16R:
        {
            assert(buf.size() == 80);
            uint256 hashPrevBlock;
            memcpy(&hashPrevBlock, buf.data() + 4, 32);
            return HashX16R(buf.data(), buf.data() + buf.size(), hashPrevBlock);
        }
        case ALGO_LYRA2REV3:
        {
            assert(buf.size() == 80);
            uint256 thash;
            lyra2re3_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_YESCRYPT_R16V2:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yescrypt_r16v2_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_YESCRYPT_R24:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yescrypt_r24_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_YESCRYPT_R8:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yescrypt_r8_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_YESCRYPT_R32:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yescrypt_r32_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_BCRYPT:
        {
            uint256 thash;
            bcrypt((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_ARGON2D:
        {
            assert(buf.size() == 80);
            uint32_t nTime;
            memcpy(&nTime, buf.data() + 68, 4);
            uint256 thash;
            Argon2dHash((const char*)buf.data(), (char*)&thash, nTime);
            return thash;
        }
        case ALGO_ARGON2I:
        {
            assert(buf.size() == 80);
            uint32_t nTime;
            memcpy(&nTime, buf.data() + 68, 4);
            uint256 thash;
            Argon2iHash((const char*)buf.data(), (char*)&thash, nTime);
            return thash;
        }
        case ALGO_CPU23R:
        {
            assert(buf.size() == 80);
            uint256 hashPrevBlock;
            memcpy(&hashPrevBlock, buf.data() + 4, 32);
            return HashCPU23R(buf.data(), buf.data() + buf.size(), hashPrevBlock);
        }
        case ALGO_YESPOWER:
        {
            assert(buf.size() == 80);
            uint256 thash;
            yespower_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_X21S:
        {
            assert(buf.size() == 80);
            uint256 hashPrevBlock;
            memcpy(&hashPrevBlock, buf.data() + 4, 32);
            return HashX21S(buf.data(), buf.data() + buf.size(), hashPrevBlock);
        }
        case ALGO_X16S:
        {
            assert(buf.size() == 80);
            uint256 hashPrevBlock;
            memcpy(&hashPrevBlock, buf.data() + 4, 32);
            return HashX16s(buf.data(), buf.data() + buf.size(), hashPrevBlock);
        }
        case ALGO_X22I:
        {
            return HashX22I(buf.data(), buf.data() + buf.size());
        }
        case ALGO_LYRA2Z:
        {
            assert(buf.size() == 80);
            uint256 thash;
            lyra2z_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_HONEYCOMB:
        {
            return HashHoneyComb(buf.data(), buf.data() + buf.size());
        }
        case ALGO_EH192:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_MARS:
        {
            return this->GetSHA256Hash();
        }
        case ALGO_X12:
        {
            return HashX12(buf.data(), buf.data() + buf.size());
        }
        case ALGO_HEX:
        {
            return HashHEX(buf.data(), buf.data() + buf.size());
        }
        case ALGO_DEDAL:
        {
            return HashDedal(buf.data(), buf.data() + buf.size());
        }
        case ALGO_C11:
        {
            return HashC11(buf.data(), buf.data() + buf.size());
        }
        case ALGO_PHI1612:
        {
            return Phi1612(buf.data(), buf.data() + buf.size());
        }
        case ALGO_PHI2:
        {
            return PHI2(buf.data(), buf.data() + buf.size());
        }
        case ALGO_X16RT:
        {
            assert(buf.size() == 80);
            uint32_t nTime;
            memcpy(&nTime, buf.data() + 68, 4);
            int32_t nTimeX16r = nTime & 0xffffff80;
            uint256 hashTime = Hash(static_cast<char*>(static_cast<void*>(&nTimeX16r)), static_cast<char*>(static_cast<void*>(&nTimeX16r))+4);
            return HashX16R(buf.data(), buf.data() + buf.size(), hashTime);
        }
        case ALGO_TRIBUS:
        {
            return Tribus(buf.data(), buf.data() + buf.size());
        }
        case ALGO_ALLIUM:
        {
            assert(buf.size() == 80);
            uint256 thash;
            allium_hash((const char*)buf.data(), (char*)&thash);
            return thash;
        }
        case ALGO_ARCTICHASH:
        {
            return ArcticHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_DESERTHASH:
        {
            return DesertHash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_CRYPTOANDCOFFEE:
        {
            return cryptoandcoffee_hash(buf.data(), buf.data() + buf.size());
        }
        case ALGO_RICKHASH:
        {
            return RickHash(buf.data(), buf.data() + buf.size());
        }
    }
    return this->GetSHA256Hash();
}<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2006 Tim Beaulen <tbscope@gmail.com>
    Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "volumefadereffect.h"
#include "xineengine.h"

namespace Phonon
{
namespace Xine
{

enum ParameterIds {
    VolumeParameter = 0,
    FadeCurveParameter = 1,
    FadeToParameter = 2,
    FadeTimeParameter = 3,
    StartFadeParameter = 4
};

VolumeFaderEffectXT::VolumeFaderEffectXT()
    : EffectXT("KVolumeFader"),
    m_parameters(Phonon::VolumeFaderEffect::Fade3Decibel, 1.0f, 1.0f, 0)
{
}

VolumeFaderEffect::VolumeFaderEffect(QObject *parent)
    : Effect(new VolumeFaderEffectXT, parent)
{
    const QVariant one = 1.0;
    const QVariant dZero = 0.0;
    const QVariant iZero = 0;
    addParameter(EffectParameter(VolumeParameter, tr( "Volume" ), 0, one, dZero, one));
    addParameter(EffectParameter(FadeCurveParameter, tr( "Fade Curve" ),
                EffectParameter::IntegerHint, iZero, iZero, 3));
    addParameter(EffectParameter(FadeToParameter, tr( "Fade To Volume" ), 0, one, dZero, one));
    addParameter(EffectParameter(FadeTimeParameter, tr( "Fade Time" ),
                EffectParameter::IntegerHint, iZero, iZero, 10000));
    addParameter(EffectParameter(StartFadeParameter, tr( "Start Fade" ),
                EffectParameter::ToggledHint, iZero, iZero, 1));
}

VolumeFaderEffect::~VolumeFaderEffect()
{
}

QVariant VolumeFaderEffect::parameterValue(const EffectParameter &p) const
{
    K_XT(const VolumeFaderEffect);

    const int parameterId = p.id();
    qDebug() << parameterId;
    switch (static_cast<ParameterIds>(parameterId)) {
    case VolumeParameter:
        return static_cast<double>(volume());
    case FadeCurveParameter:
        return static_cast<int>(fadeCurve());
    case FadeToParameter:
        return static_cast<double>(xt->m_parameters.fadeTo);
    case FadeTimeParameter:
        return xt->m_parameters.fadeTime;
    case StartFadeParameter:
        return 0;
    }
    return QVariant();
}

void VolumeFaderEffect::setParameterValue(const EffectParameter &p, const QVariant &newValue)
{
    K_XT(VolumeFaderEffect);

    const int parameterId = p.id();
    qDebug() << parameterId << newValue;
    switch (static_cast<ParameterIds>(parameterId)) {
    case VolumeParameter:
        setVolume(newValue.toDouble());
        break;
    case FadeCurveParameter:
        setFadeCurve(static_cast<Phonon::VolumeFaderEffect::FadeCurve>(newValue.toInt()));
        break;
    case FadeToParameter:
        xt->m_parameters.fadeTo = newValue.toDouble();
        break;
    case FadeTimeParameter:
        xt->m_parameters.fadeTime = newValue.toInt();
        break;
    case StartFadeParameter:
        if (newValue.toBool()) {
            fadeTo(xt->m_parameters.fadeTo, xt->m_parameters.fadeTime);
        }
        break;
    default:
        qWarning() << "request for unknown parameter " << parameterId;
        break;
    }
}

void VolumeFaderEffectXT::createInstance()
{
    xine_audio_port_t *audioPort = fakeAudioPort();
    Q_ASSERT(0 == m_plugin);
    qDebug() << audioPort << " fadeTime = " << m_parameters.fadeTime;
    m_plugin = xine_post_init(m_xine, "KVolumeFader", 1, &audioPort, 0);
    xine_post_in_t *paraInput = xine_post_input(m_plugin, "parameters");
    Q_ASSERT(paraInput);
    Q_ASSERT(paraInput->type == XINE_POST_DATA_PARAMETERS);
    Q_ASSERT(paraInput->data);
    m_pluginApi = reinterpret_cast<xine_post_api_t *>(paraInput->data);
    m_pluginApi->set_parameters(m_plugin, &m_parameters);
}

void VolumeFaderEffect::getParameters() const
{
    K_XT(const VolumeFaderEffect);

    if (xt->m_pluginApi) {
        xt->m_pluginApi->get_parameters(xt->m_plugin, &xt->m_parameters);
    }
}

float VolumeFaderEffect::volume() const
{
    K_XT(const VolumeFaderEffect);

    //qDebug();
    getParameters();
    return xt->m_parameters.currentVolume;
}

void VolumeFaderEffect::setVolume(float volume)
{
    K_XT(VolumeFaderEffect);

    //qDebug() << volume;
    xt->m_parameters.currentVolume = volume;
}

Phonon::VolumeFaderEffect::FadeCurve VolumeFaderEffect::fadeCurve() const
{
    K_XT(const VolumeFaderEffect);

    //qDebug();
    getParameters();
    return xt->m_parameters.fadeCurve;
}

void VolumeFaderEffect::setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve curve)
{
    K_XT(VolumeFaderEffect);

    //qDebug() << curve;
    xt->m_parameters.fadeCurve = curve;
}

void VolumeFaderEffect::fadeTo(float volume, int fadeTime)
{
    K_XT(VolumeFaderEffect);

    //qDebug() << volume << fadeTime;
    xt->m_parameters.fadeTo = volume;
    xt->m_parameters.fadeTime = fadeTime;
    if (xt->m_pluginApi) {
        xt->m_pluginApi->set_parameters(xt->m_plugin, &xt->m_parameters);
    }
}

void VolumeFaderEffectXT::rewireTo(SourceNodeXT *source)
{
    if (!source->audioOutputPort()) {
        return;
    }
    EffectXT::rewireTo(source);
    Q_ASSERT(m_pluginApi);
    Q_ASSERT(m_plugin);
    m_pluginApi->set_parameters(m_plugin, &m_parameters);
}

}} //namespace Phonon::Xine

#include "volumefadereffect.moc"
// vim: sw=4 ts=4
<commit_msg>- Restore warning message<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2006 Tim Beaulen <tbscope@gmail.com>
    Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "volumefadereffect.h"
#include "xineengine.h"

namespace Phonon
{
namespace Xine
{

enum ParameterIds {
    VolumeParameter = 0,
    FadeCurveParameter = 1,
    FadeToParameter = 2,
    FadeTimeParameter = 3,
    StartFadeParameter = 4
};

VolumeFaderEffectXT::VolumeFaderEffectXT()
    : EffectXT("KVolumeFader"),
    m_parameters(Phonon::VolumeFaderEffect::Fade3Decibel, 1.0f, 1.0f, 0)
{
}

VolumeFaderEffect::VolumeFaderEffect(QObject *parent)
    : Effect(new VolumeFaderEffectXT, parent)
{
    const QVariant one = 1.0;
    const QVariant dZero = 0.0;
    const QVariant iZero = 0;
    addParameter(EffectParameter(VolumeParameter, tr( "Volume" ), 0, one, dZero, one));
    addParameter(EffectParameter(FadeCurveParameter, tr( "Fade Curve" ),
                EffectParameter::IntegerHint, iZero, iZero, 3));
    addParameter(EffectParameter(FadeToParameter, tr( "Fade To Volume" ), 0, one, dZero, one));
    addParameter(EffectParameter(FadeTimeParameter, tr( "Fade Time" ),
                EffectParameter::IntegerHint, iZero, iZero, 10000));
    addParameter(EffectParameter(StartFadeParameter, tr( "Start Fade" ),
                EffectParameter::ToggledHint, iZero, iZero, 1));
}

VolumeFaderEffect::~VolumeFaderEffect()
{
}

QVariant VolumeFaderEffect::parameterValue(const EffectParameter &p) const
{
    K_XT(const VolumeFaderEffect);

    const int parameterId = p.id();
    qDebug() << parameterId;
    switch (static_cast<ParameterIds>(parameterId)) {
    case VolumeParameter:
        return static_cast<double>(volume());
    case FadeCurveParameter:
        return static_cast<int>(fadeCurve());
    case FadeToParameter:
        return static_cast<double>(xt->m_parameters.fadeTo);
    case FadeTimeParameter:
        return xt->m_parameters.fadeTime;
    case StartFadeParameter:
        return 0;
    }

    qWarning() << "request for unknown parameter " << parameterId;
    return QVariant();
}

void VolumeFaderEffect::setParameterValue(const EffectParameter &p, const QVariant &newValue)
{
    K_XT(VolumeFaderEffect);

    const int parameterId = p.id();
    qDebug() << parameterId << newValue;
    switch (static_cast<ParameterIds>(parameterId)) {
    case VolumeParameter:
        setVolume(newValue.toDouble());
        break;
    case FadeCurveParameter:
        setFadeCurve(static_cast<Phonon::VolumeFaderEffect::FadeCurve>(newValue.toInt()));
        break;
    case FadeToParameter:
        xt->m_parameters.fadeTo = newValue.toDouble();
        break;
    case FadeTimeParameter:
        xt->m_parameters.fadeTime = newValue.toInt();
        break;
    case StartFadeParameter:
        if (newValue.toBool()) {
            fadeTo(xt->m_parameters.fadeTo, xt->m_parameters.fadeTime);
        }
        break;
    default:
        qWarning() << "request for unknown parameter " << parameterId;
        break;
    }
}

void VolumeFaderEffectXT::createInstance()
{
    xine_audio_port_t *audioPort = fakeAudioPort();
    Q_ASSERT(0 == m_plugin);
    qDebug() << audioPort << " fadeTime = " << m_parameters.fadeTime;
    m_plugin = xine_post_init(m_xine, "KVolumeFader", 1, &audioPort, 0);
    xine_post_in_t *paraInput = xine_post_input(m_plugin, "parameters");
    Q_ASSERT(paraInput);
    Q_ASSERT(paraInput->type == XINE_POST_DATA_PARAMETERS);
    Q_ASSERT(paraInput->data);
    m_pluginApi = reinterpret_cast<xine_post_api_t *>(paraInput->data);
    m_pluginApi->set_parameters(m_plugin, &m_parameters);
}

void VolumeFaderEffect::getParameters() const
{
    K_XT(const VolumeFaderEffect);

    if (xt->m_pluginApi) {
        xt->m_pluginApi->get_parameters(xt->m_plugin, &xt->m_parameters);
    }
}

float VolumeFaderEffect::volume() const
{
    K_XT(const VolumeFaderEffect);

    //qDebug();
    getParameters();
    return xt->m_parameters.currentVolume;
}

void VolumeFaderEffect::setVolume(float volume)
{
    K_XT(VolumeFaderEffect);

    //qDebug() << volume;
    xt->m_parameters.currentVolume = volume;
}

Phonon::VolumeFaderEffect::FadeCurve VolumeFaderEffect::fadeCurve() const
{
    K_XT(const VolumeFaderEffect);

    //qDebug();
    getParameters();
    return xt->m_parameters.fadeCurve;
}

void VolumeFaderEffect::setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve curve)
{
    K_XT(VolumeFaderEffect);

    //qDebug() << curve;
    xt->m_parameters.fadeCurve = curve;
}

void VolumeFaderEffect::fadeTo(float volume, int fadeTime)
{
    K_XT(VolumeFaderEffect);

    //qDebug() << volume << fadeTime;
    xt->m_parameters.fadeTo = volume;
    xt->m_parameters.fadeTime = fadeTime;
    if (xt->m_pluginApi) {
        xt->m_pluginApi->set_parameters(xt->m_plugin, &xt->m_parameters);
    }
}

void VolumeFaderEffectXT::rewireTo(SourceNodeXT *source)
{
    if (!source->audioOutputPort()) {
        return;
    }
    EffectXT::rewireTo(source);
    Q_ASSERT(m_pluginApi);
    Q_ASSERT(m_plugin);
    m_pluginApi->set_parameters(m_plugin, &m_parameters);
}

}} //namespace Phonon::Xine

#include "volumefadereffect.moc"
// vim: sw=4 ts=4
<|endoftext|>


<commit_before>#include <fountain/fountaindef.h>
#include <cstdio>
#include <vector>

using ftType::charInfo;
using ftType::FontMan;

static bool alive = false;
FT_Library library;

FontMan *defaultFontMan;

bool ftType::init()
{
	int error = FT_Init_FreeType(&library);
	if (error) {
		return false;
	}
	alive = true;
	return true;
}

void ftType::close()
{
	FT_Done_FreeType(library);
	alive = false;
}

bool ftType::isAlive()
{
	return alive;
}

//class ftType::charInfo
charInfo::charInfo()
{
	center = ftVec2(0.0f, 0.0f);
	advance = ftVec2(0.0f, 0.0f);
}

charInfo::charInfo(const ftVec2 & ct, const ftVec2 & adv)
{
	center = ct;
	advance = adv;
}

void copyBitmapToBufferData(FT_Bitmap &bitmap, unsigned char *expanded_data, int imgW, unsigned w, unsigned h, int row, int col)
{
	for(unsigned j = 0; j < h; j++) {
		for(unsigned i = 0; i < w; i++) {
			int r = row * h + j;
			int c = col * w + i;
			expanded_data[2 * (r * imgW + c)] = 255;
			expanded_data[2 * (r * imgW + c) + 1] =
			    (i >= bitmap.width || j >= bitmap.rows) ?
			    0 : bitmap.buffer[i + bitmap.width * (bitmap.rows - 1 - j)];
		}
	}
}

//class ftType::FontMan
FontMan::FontMan()
{
	picID = 0;
}

FontMan::~FontMan()
{
	if (ftType::isAlive()) FT_Done_Face(face);
	if (ftRender::isAlive()) ftRender::deletePicture(picID);
	if (defaultFontMan == this) defaultFontMan = NULL;
}

bool FontMan::loadFont(const char *fontname)
{
	int error = FT_New_Face(library, fontname, 0, &face);
	if (error) {
		return false;
	}
	useKerning = FT_HAS_KERNING(face);
	return true;
}

//TODO: make these two functions less code
void FontMan::genAsciiTable(int h)
{
	//TODO: check the state of picID
	char asciiTable[129];
	asciiTable[0] = ' ';
	for (int i = 1; i < 128; i++)
		asciiTable[i] = i;
	asciiTable[128] = '\0';
	this->genStringTable(asciiTable, h);
}

void FontMan::genStringTable(const char *str, int h)
{
	//TODO: check the state of picID
	//TODO: create a SubImage to store default char
	h = ftAlgorithm::nextPower2(h);
	std::vector<unsigned long> v = ftAlgorithm::utf8toUnicode(str);
	int strSize = v.size();
	int size = ftAlgorithm::nextPower2(strSize);
	int cols = 1;
	while (size / cols > cols) cols <<= 1;
	int rows = size / cols;
	int w = h;
	int imgW = w * cols;
	int imgH = h * rows;

	FT_Set_Pixel_Sizes(face, 0, h);
	FT_GlyphSlot slot = face->glyph;
	unsigned char* expanded_data = new unsigned char[2 * imgW * imgH];
	std::vector<ftRect> rectV;
	for (int ci = 0; ci < strSize; ci++) {
		FT_Load_Char(face, v[ci], FT_LOAD_RENDER);
		FT_Bitmap& bitmap = slot->bitmap;
		ftVec2 center(slot->bitmap_left + bitmap.width / 2.0f,
		              slot->bitmap_top - bitmap.rows + bitmap.rows / 2.0f);
		ftVec2 advance(slot->advance.x >> 6, slot->advance.y >> 6);
		charInfo ch(center, advance);
		unicode2charInfo[v[ci]] = ch;
		int row = ci / cols;
		int col = ci % cols;
		ftRect si(col * w, row * h, bitmap.width, bitmap.rows);
		rectV.push_back(si);
		copyBitmapToBufferData(bitmap, expanded_data, imgW, w, h, row, col);
	}
	picID = ftRender::getPicture(expanded_data, imgW, imgH, FT_GRAY_ALPHA);
	for (int ci = 0; ci < strSize; ci++) {
		ftRender::SubImage t(picID, rectV[ci]);
		unicode2SubImage[v[ci]] = t;
	}
	delete [] expanded_data;
	fontSize = h;
}

//TODO: complete this function
int FontMan::drawString(const std::vector<unsigned long> & s)
{
	ftVec2 pen(0, 0);
	FT_Int previous = 0;
	FT_UInt glyphIndex;
	for (unsigned i = 0; i < s.size(); i++) {
		charInfo ch = unicode2charInfo[s[i]];
		ftRender::SubImage im = unicode2SubImage[s[i]];
		ftRender::transformBegin();
		ftRender::ftTranslate(pen + ch.center);
		ftRender::drawImage(im);
		ftRender::transformEnd();
		pen = pen + ch.advance;
		//kerning
		glyphIndex = FT_Get_Char_Index(face, s[i]);
		if (useKerning && previous && glyphIndex) {
			FT_Vector delta;
			FT_Get_Kerning(face, previous, glyphIndex, FT_KERNING_DEFAULT, &delta);
			pen.x += delta.x >> 6;
		}
		previous = glyphIndex;
	}
	return pen.x;
}

int FontMan::getStringLength(const std::vector<unsigned long> & s)
{
	ftVec2 pen(0, 0);
	FT_Int previous = 0;
	FT_UInt glyphIndex;
	for (unsigned i = 0; i < s.size(); i++) {
		charInfo ch = unicode2charInfo[s[i]];
		pen = pen + ch.advance;
		//kerning
		glyphIndex = FT_Get_Char_Index(face, s[i]);
		if (useKerning && previous && glyphIndex) {
			FT_Vector delta;
			FT_Get_Kerning(face, previous, glyphIndex, FT_KERNING_DEFAULT, &delta);
			pen.x += delta.x >> 6;
		}
		previous = glyphIndex;
	}
	return pen.x;
}

int FontMan::drawString(const char *str)
{
	std::vector<unsigned long> s = ftAlgorithm::utf8toUnicode(str);
	return drawString(s);
}

int FontMan::getFontSize()
{
	return fontSize;
}
<commit_msg>fix bug: fix font drawing<commit_after>#include <fountain/fountaindef.h>
#include <cstdio>
#include <vector>

using ftType::charInfo;
using ftType::FontMan;

static bool alive = false;
FT_Library library;

FontMan *defaultFontMan;

bool ftType::init()
{
	int error = FT_Init_FreeType(&library);
	if (error) {
		return false;
	}
	alive = true;
	return true;
}

void ftType::close()
{
	FT_Done_FreeType(library);
	alive = false;
}

bool ftType::isAlive()
{
	return alive;
}

//class ftType::charInfo
charInfo::charInfo()
{
	center = ftVec2(0.0f, 0.0f);
	advance = ftVec2(0.0f, 0.0f);
}

charInfo::charInfo(const ftVec2 & ct, const ftVec2 & adv)
{
	center = ct;
	advance = adv;
}

void copyBitmapToBufferData(FT_Bitmap &bitmap, unsigned char *expanded_data, int imgW, unsigned w, unsigned h, int row, int col)
{
	for(unsigned j = 0; j < h; j++) {
		for(unsigned i = 0; i < w; i++) {
			int r = row * h + j;
			int c = col * w + i;
			expanded_data[2 * (r * imgW + c)] = 255;
			expanded_data[2 * (r * imgW + c) + 1] =
			    (i >= bitmap.width || j >= bitmap.rows) ?
			    0 : bitmap.buffer[i + bitmap.width * (bitmap.rows - 1 - j)];
		}
	}
}

//class ftType::FontMan
FontMan::FontMan()
{
	picID = 0;
}

FontMan::~FontMan()
{
	if (ftType::isAlive()) FT_Done_Face(face);
	if (ftRender::isAlive()) ftRender::deletePicture(picID);
	if (defaultFontMan == this) defaultFontMan = NULL;
}

bool FontMan::loadFont(const char *fontname)
{
	int error = FT_New_Face(library, fontname, 0, &face);
	if (error) {
		return false;
	}
	useKerning = FT_HAS_KERNING(face);
	return true;
}

//TODO: make these two functions less code
void FontMan::genAsciiTable(int h)
{
	//TODO: check the state of picID
	char asciiTable[129];
	asciiTable[0] = ' ';
	for (int i = 1; i < 128; i++)
		asciiTable[i] = i;
	asciiTable[128] = '\0';
	this->genStringTable(asciiTable, h);
}

void FontMan::genStringTable(const char *str, int h)
{
	//TODO: check the state of picID
	//TODO: create a SubImage to store default char
	h = ftAlgorithm::nextPower2(h);
	std::vector<unsigned long> v = ftAlgorithm::utf8toUnicode(str);
	int strSize = v.size();
	int size = ftAlgorithm::nextPower2(strSize);
	int cols = 1;
	while (size / cols > cols) cols <<= 1;
	int rows = size / cols;
	int w = h;
	int imgW = w * cols;
	int imgH = h * rows;

	FT_Set_Pixel_Sizes(face, 0, h);
	FT_GlyphSlot slot = face->glyph;
	unsigned char* expanded_data = new unsigned char[2 * imgW * imgH];
	std::vector<ftRect> rectV;
	for (int ci = 0; ci < strSize; ci++) {
		FT_Load_Char(face, v[ci], FT_LOAD_RENDER);
		FT_Bitmap& bitmap = slot->bitmap;
		ftVec2 center(slot->bitmap_left + bitmap.width / 2.0f,
		              slot->bitmap_top - bitmap.rows / 2.0f);
		ftVec2 advance(slot->advance.x >> 6, slot->advance.y >> 6);
		charInfo ch(center, advance);
		unicode2charInfo[v[ci]] = ch;
		int row = ci / cols;
		int col = ci % cols;
		ftRect si(col * w, row * h, bitmap.width, bitmap.rows);
		rectV.push_back(si);
		copyBitmapToBufferData(bitmap, expanded_data, imgW, w, h, row, col);
	}
	picID = ftRender::getPicture(expanded_data, imgW, imgH, FT_GRAY_ALPHA);
	for (int ci = 0; ci < strSize; ci++) {
		ftRender::SubImage t(picID, rectV[ci]);
		unicode2SubImage[v[ci]] = t;
	}
	delete [] expanded_data;
	fontSize = h;
}

//TODO: complete this function
int FontMan::drawString(const std::vector<unsigned long> & s)
{
	ftVec2 pen(0, 0);
	FT_Int previous = 0;
	FT_UInt glyphIndex;
	for (unsigned i = 0; i < s.size(); i++) {
		charInfo ch = unicode2charInfo[s[i]];
		ftRender::SubImage im = unicode2SubImage[s[i]];
		ftRender::transformBegin();
		ftRender::ftTranslate(pen + ch.center);
		ftRender::drawImage(im);
		ftRender::transformEnd();
		pen = pen + ch.advance;
		//kerning
		glyphIndex = FT_Get_Char_Index(face, s[i]);
		if (useKerning && previous && glyphIndex) {
			FT_Vector delta;
			FT_Get_Kerning(face, previous, glyphIndex, FT_KERNING_DEFAULT, &delta);
			pen.x += delta.x >> 6;
		}
		previous = glyphIndex;
	}
	return pen.x;
}

int FontMan::getStringLength(const std::vector<unsigned long> & s)
{
	ftVec2 pen(0, 0);
	FT_Int previous = 0;
	FT_UInt glyphIndex;
	for (unsigned i = 0; i < s.size(); i++) {
		charInfo ch = unicode2charInfo[s[i]];
		pen = pen + ch.advance;
		//kerning
		glyphIndex = FT_Get_Char_Index(face, s[i]);
		if (useKerning && previous && glyphIndex) {
			FT_Vector delta;
			FT_Get_Kerning(face, previous, glyphIndex, FT_KERNING_DEFAULT, &delta);
			pen.x += delta.x >> 6;
		}
		previous = glyphIndex;
	}
	return pen.x;
}

int FontMan::drawString(const char *str)
{
	std::vector<unsigned long> s = ftAlgorithm::utf8toUnicode(str);
	return drawString(s);
}

int FontMan::getFontSize()
{
	return fontSize;
}
<|endoftext|>


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

#include "attributedfw.h"
#include "docsumwriter.h"
#include "docsumstate.h"
#include "docsum_field_writer_state.h"
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchcommon/attribute/i_multi_value_attribute.h>
#include <vespa/searchcommon/attribute/multi_value_traits.h>
#include <vespa/searchlib/attribute/iattributemanager.h>
#include <vespa/searchlib/common/matching_elements.h>
#include <vespa/searchlib/common/matching_elements_fields.h>
#include <vespa/searchlib/tensor/i_tensor_attribute.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/issue.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchlib.docsummary.attributedfw");

using namespace search;
using search::attribute::BasicType;
using search::attribute::IAttributeContext;
using search::attribute::IAttributeVector;
using search::attribute::IMultiValueAttribute;
using search::attribute::IMultiValueReadView;
using vespalib::Memory;
using vespalib::slime::Cursor;
using vespalib::slime::Inserter;
using vespalib::slime::Symbol;
using vespalib::eval::Value;
using vespalib::Issue;

namespace search::docsummary {

AttrDFW::AttrDFW(const vespalib::string & attrName) :
    _attrName(attrName)
{
}

const attribute::IAttributeVector&
AttrDFW::get_attribute(const GetDocsumsState& s) const
{
    return *s.getAttribute(getIndex());
}

namespace {

class SingleAttrDFW : public AttrDFW
{
public:
    explicit SingleAttrDFW(const vespalib::string & attrName) :
        AttrDFW(attrName)
    { }
    void insertField(uint32_t docid, GetDocsumsState *state, ResType, Inserter &target) const override;
    bool isDefaultValue(uint32_t docid, const GetDocsumsState * state) const override {
        return get_attribute(*state).isUndefined(docid);
    }
};

void
SingleAttrDFW::insertField(uint32_t docid, GetDocsumsState * state, ResType, Inserter &target) const
{
    const auto& v = get_attribute(*state);
    switch (v.getBasicType()) {
    case BasicType::Type::UINT2:
    case BasicType::Type::UINT4:
    case BasicType::Type::INT8:
    case BasicType::Type::INT16:
    case BasicType::Type::INT32:
    case BasicType::Type::INT64: {
        uint32_t val = v.getInt(docid);
        target.insertLong(val);
        break;
    }
    case BasicType::Type::BOOL: {
        uint8_t val = v.getInt(docid);
        target.insertBool(val != 0);
        break;
    }
    case BasicType::Type::FLOAT:
    case BasicType::Type::DOUBLE: {
        float val = v.getFloat(docid);
        target.insertDouble(val);
        break;
    }
    case BasicType::Type::TENSOR: {
        const tensor::ITensorAttribute *tv = v.asTensorAttribute();
        assert(tv != nullptr);
        const auto tensor = tv->getTensor(docid);
        if (tensor) {
            vespalib::nbostream str;
            encode_value(*tensor, str);
            target.insertData(vespalib::Memory(str.peek(), str.size()));
        }
        break;
    }
    case BasicType::STRING: {
        const char *s = v.getString(docid, nullptr, 0); // no need to pass in a buffer, this attribute has a string storage.
        target.insertString(vespalib::Memory(s));
        break;
    }
    case BasicType::REFERENCE:
    case BasicType::PREDICATE:
        break; // Should never use attribute docsum field writer
    default:
        break; // Unknown type
    }
    return;
}

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

template <typename MultiValueType>
const IMultiValueReadView<MultiValueType>*
make_read_view(const IAttributeVector& attribute, vespalib::Stash& stash)
{
    auto multi_value_attribute = attribute.as_multi_value_attribute();
    if (multi_value_attribute != nullptr) {
        return multi_value_attribute->make_read_view(IMultiValueAttribute::MultiValueTag<MultiValueType>(), stash);
    }
    return nullptr;
}

class EmptyWriterState : public DocsumFieldWriterState
{
public:
    EmptyWriterState() = default;
    ~EmptyWriterState() = default;
    void insertField(uint32_t, Inserter&) override { }
};

template <typename MultiValueType>
class MultiAttrDFWState : public DocsumFieldWriterState
{
    const vespalib::string&                    _field_name;
    const IMultiValueReadView<MultiValueType>* _read_view;
    const MatchingElements*                    _matching_elements;
public:
    MultiAttrDFWState(const vespalib::string& field_name, const IAttributeVector& attr, vespalib::Stash& stash, const MatchingElements* matching_elements);
    ~MultiAttrDFWState() override;
    void insertField(uint32_t docid, Inserter& target) override;
};

template <typename MultiValueType>
MultiAttrDFWState<MultiValueType>::MultiAttrDFWState(const vespalib::string& field_name, const IAttributeVector& attr, vespalib::Stash& stash, const MatchingElements* matching_elements)
    : _field_name(field_name),
      _read_view(make_read_view<MultiValueType>(attr, stash)),
      _matching_elements(matching_elements)
{
}

template <typename MultiValueType>
MultiAttrDFWState<MultiValueType>::~MultiAttrDFWState() = default;

template <typename V>
void
set_value(V value, Symbol item_symbol, Cursor& cursor)
{
    if constexpr (std::is_same_v<V, const char*>) {
        cursor.setString(item_symbol, value);
    } else if constexpr(std::is_floating_point_v<V>) {
        cursor.setDouble(item_symbol, value);
    } else {
        cursor.setLong(item_symbol, value);
    }
}

template <typename V>
void
append_value(V value, Cursor& arr)
{
    if constexpr (std::is_same_v<V, const char*>) {
        arr.addString(value);
    } else if constexpr(std::is_floating_point_v<V>) {
        arr.addDouble(value);
    } else {
        arr.addLong(value);
    }
}

Memory ITEM("item");
Memory WEIGHT("weight");

template <typename MultiValueType>
void
MultiAttrDFWState<MultiValueType>::insertField(uint32_t docid, Inserter& target)
{
    using ValueType = multivalue::ValueType_t<MultiValueType>;
    if (!_read_view) {
        return;
    }
    auto elements = _read_view->get_values(docid);
    if (elements.empty()) {
        return;
    }
    Cursor &arr = target.insertArray(elements.size());

    if (_matching_elements) {
        const auto& matching_elems = _matching_elements->get_matching_elements(docid, _field_name);
        if (!matching_elems.empty() && matching_elems.back() < elements.size()) {
            if constexpr (multivalue::is_WeightedValue_v<MultiValueType>) {
                Symbol itemSymbol = arr.resolve(ITEM);
                Symbol weightSymbol = arr.resolve(WEIGHT);
                for (uint32_t id_to_keep : matching_elems) {
                    auto& element = elements[id_to_keep];
                    Cursor& elemC = arr.addObject();
                    set_value<ValueType>(element.value(), itemSymbol, elemC);
                    elemC.setLong(weightSymbol, element.weight());
                }
            } else {
                for (uint32_t id_to_keep : matching_elems) {
                    append_value<ValueType>(elements[id_to_keep], arr);
                }
            }
        }
    } else {
        if constexpr (multivalue::is_WeightedValue_v<MultiValueType>) {
            Symbol itemSymbol = arr.resolve(ITEM);
            Symbol weightSymbol = arr.resolve(WEIGHT);
            for (const auto & element : elements) {
                Cursor& elemC = arr.addObject();
                set_value<ValueType>(element.value(), itemSymbol, elemC);
                elemC.setLong(weightSymbol, element.weight());
            }
        } else {
            for (const auto & element : elements) {
                append_value<ValueType>(element, arr);
            }
        }
    }
}

class MultiAttrDFW : public AttrDFW {
private:
    bool _filter_elements;
    uint32_t _state_index; // index into _fieldWriterStates in GetDocsumsState
    std::shared_ptr<MatchingElementsFields> _matching_elems_fields;

public:
    MultiAttrDFW(const vespalib::string& attr_name, bool filter_elements, std::shared_ptr<MatchingElementsFields> matching_elems_fields)
        : AttrDFW(attr_name),
          _filter_elements(filter_elements),
          _state_index(0),
          _matching_elems_fields(std::move(matching_elems_fields))
    {
        if (filter_elements && _matching_elems_fields) {
            _matching_elems_fields->add_field(attr_name);
        }
    }
    bool setFieldWriterStateIndex(uint32_t fieldWriterStateIndex) override;
    void insertField(uint32_t docid, GetDocsumsState* state, ResType, Inserter& target) const override;
};

bool
MultiAttrDFW::setFieldWriterStateIndex(uint32_t fieldWriterStateIndex)
{
    _state_index = fieldWriterStateIndex;
    return true;
}

template <typename DataType>
DocsumFieldWriterState*
make_field_writer_state_helper(const vespalib::string& field_name, const IAttributeVector& attr, vespalib::Stash& stash, const MatchingElements* matching_elements)
{
    bool is_weighted_set = attr.hasWeightedSetType();
    if (is_weighted_set) {
        return &stash.create<MultiAttrDFWState<multivalue::WeightedValue<DataType>>>(field_name, attr, stash, matching_elements);
    } else {
        return &stash.create<MultiAttrDFWState<DataType>>(field_name, attr, stash, matching_elements);
    }
}

DocsumFieldWriterState*
make_field_writer_state(const vespalib::string& field_name, const IAttributeVector& attr, vespalib::Stash& stash, const MatchingElements* matching_elements)
{
    auto type = attr.getBasicType();
    switch (type) {
    case BasicType::Type::STRING:
        return make_field_writer_state_helper<const char*>(field_name, attr, stash, matching_elements);
    case BasicType::Type::INT8:
        return make_field_writer_state_helper<int8_t>(field_name, attr, stash, matching_elements);
    case BasicType::Type::INT16:
        return make_field_writer_state_helper<int16_t>(field_name, attr, stash, matching_elements);
    case BasicType::Type::INT32:
        return make_field_writer_state_helper<int32_t>(field_name, attr, stash, matching_elements);
    case BasicType::Type::INT64:
        return make_field_writer_state_helper<int64_t>(field_name, attr, stash, matching_elements);
    case BasicType::Type::FLOAT:
        return make_field_writer_state_helper<float>(field_name, attr, stash, matching_elements);
    case BasicType::Type::DOUBLE:
        return make_field_writer_state_helper<double>(field_name, attr, stash, matching_elements);
    default:
        ;
    }
    return &stash.create<EmptyWriterState>();
}

void
MultiAttrDFW::insertField(uint32_t docid, GetDocsumsState *state, ResType, vespalib::slime::Inserter &target) const
{
    auto& field_writer_state = state->_fieldWriterStates[_state_index];
    if (!field_writer_state) {
        const MatchingElements *matching_elements = nullptr;
        if (_filter_elements) {
            matching_elements = &state->get_matching_elements(*_matching_elems_fields);
        }
        const auto& attr = get_attribute(*state);
        field_writer_state = make_field_writer_state(getAttributeName(), attr, state->get_stash(), matching_elements);
    }
    field_writer_state->insertField(docid, target);
}

std::unique_ptr<DocsumFieldWriter>
create_multi_writer(const IAttributeVector& attr, bool filter_elements, std::shared_ptr<MatchingElementsFields> matching_elems_fields)
{
    auto type = attr.getBasicType();
    switch (type) {
    case BasicType::STRING:
    case BasicType::INT8:
    case BasicType::INT16:
    case BasicType::INT32:
    case BasicType::INT64:
    case BasicType::FLOAT:
    case BasicType::DOUBLE:
        return std::make_unique<MultiAttrDFW>(attr.getName(), filter_elements, std::move(matching_elems_fields));
    default:
        // should not happen
        LOG(error, "Bad value for attribute type: %u", type);
        LOG_ASSERT(false);
    }
}

}

std::unique_ptr<DocsumFieldWriter>
AttributeDFWFactory::create(const IAttributeManager& attr_mgr,
                            const vespalib::string& attr_name,
                            bool filter_elements,
                            std::shared_ptr<MatchingElementsFields> matching_elems_fields)
{
    auto ctx = attr_mgr.createContext();
    const auto* attr = ctx->getAttribute(attr_name);
    if (attr == nullptr) {
        Issue::report("No valid attribute vector found: '%s'", attr_name.c_str());
        return std::unique_ptr<DocsumFieldWriter>();
    }
    if (attr->hasMultiValue()) {
        return create_multi_writer(*attr, filter_elements, std::move(matching_elems_fields));
    } else {
        return std::make_unique<SingleAttrDFW>(attr->getName());
    }
}

}
<commit_msg>Use int64_t and double when printing values for single value numeric attributes.<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "attributedfw.h"
#include "docsumwriter.h"
#include "docsumstate.h"
#include "docsum_field_writer_state.h"
#include <vespa/eval/eval/value.h>
#include <vespa/eval/eval/value_codec.h>
#include <vespa/searchcommon/attribute/i_multi_value_attribute.h>
#include <vespa/searchcommon/attribute/multi_value_traits.h>
#include <vespa/searchlib/attribute/iattributemanager.h>
#include <vespa/searchlib/common/matching_elements.h>
#include <vespa/searchlib/common/matching_elements_fields.h>
#include <vespa/searchlib/tensor/i_tensor_attribute.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <vespa/vespalib/objects/nbostream.h>
#include <vespa/vespalib/util/issue.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchlib.docsummary.attributedfw");

using namespace search;
using search::attribute::BasicType;
using search::attribute::IAttributeContext;
using search::attribute::IAttributeVector;
using search::attribute::IMultiValueAttribute;
using search::attribute::IMultiValueReadView;
using vespalib::Memory;
using vespalib::slime::Cursor;
using vespalib::slime::Inserter;
using vespalib::slime::Symbol;
using vespalib::eval::Value;
using vespalib::Issue;

namespace search::docsummary {

AttrDFW::AttrDFW(const vespalib::string & attrName) :
    _attrName(attrName)
{
}

const attribute::IAttributeVector&
AttrDFW::get_attribute(const GetDocsumsState& s) const
{
    return *s.getAttribute(getIndex());
}

namespace {

class SingleAttrDFW : public AttrDFW
{
public:
    explicit SingleAttrDFW(const vespalib::string & attrName) :
        AttrDFW(attrName)
    { }
    void insertField(uint32_t docid, GetDocsumsState *state, ResType, Inserter &target) const override;
    bool isDefaultValue(uint32_t docid, const GetDocsumsState * state) const override {
        return get_attribute(*state).isUndefined(docid);
    }
};

void
SingleAttrDFW::insertField(uint32_t docid, GetDocsumsState * state, ResType, Inserter &target) const
{
    const auto& v = get_attribute(*state);
    switch (v.getBasicType()) {
    case BasicType::Type::UINT2:
    case BasicType::Type::UINT4:
    case BasicType::Type::INT8:
    case BasicType::Type::INT16:
    case BasicType::Type::INT32:
    case BasicType::Type::INT64: {
        int64_t val = v.getInt(docid);
        target.insertLong(val);
        break;
    }
    case BasicType::Type::BOOL: {
        uint8_t val = v.getInt(docid);
        target.insertBool(val != 0);
        break;
    }
    case BasicType::Type::FLOAT:
    case BasicType::Type::DOUBLE: {
        double val = v.getFloat(docid);
        target.insertDouble(val);
        break;
    }
    case BasicType::Type::TENSOR: {
        const tensor::ITensorAttribute *tv = v.asTensorAttribute();
        assert(tv != nullptr);
        const auto tensor = tv->getTensor(docid);
        if (tensor) {
            vespalib::nbostream str;
            encode_value(*tensor, str);
            target.insertData(vespalib::Memory(str.peek(), str.size()));
        }
        break;
    }
    case BasicType::STRING: {
        const char *s = v.getString(docid, nullptr, 0); // no need to pass in a buffer, this attribute has a string storage.
        target.insertString(vespalib::Memory(s));
        break;
    }
    case BasicType::REFERENCE:
    case BasicType::PREDICATE:
        break; // Should never use attribute docsum field writer
    default:
        break; // Unknown type
    }
    return;
}

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

template <typename MultiValueType>
const IMultiValueReadView<MultiValueType>*
make_read_view(const IAttributeVector& attribute, vespalib::Stash& stash)
{
    auto multi_value_attribute = attribute.as_multi_value_attribute();
    if (multi_value_attribute != nullptr) {
        return multi_value_attribute->make_read_view(IMultiValueAttribute::MultiValueTag<MultiValueType>(), stash);
    }
    return nullptr;
}

class EmptyWriterState : public DocsumFieldWriterState
{
public:
    EmptyWriterState() = default;
    ~EmptyWriterState() = default;
    void insertField(uint32_t, Inserter&) override { }
};

template <typename MultiValueType>
class MultiAttrDFWState : public DocsumFieldWriterState
{
    const vespalib::string&                    _field_name;
    const IMultiValueReadView<MultiValueType>* _read_view;
    const MatchingElements*                    _matching_elements;
public:
    MultiAttrDFWState(const vespalib::string& field_name, const IAttributeVector& attr, vespalib::Stash& stash, const MatchingElements* matching_elements);
    ~MultiAttrDFWState() override;
    void insertField(uint32_t docid, Inserter& target) override;
};

template <typename MultiValueType>
MultiAttrDFWState<MultiValueType>::MultiAttrDFWState(const vespalib::string& field_name, const IAttributeVector& attr, vespalib::Stash& stash, const MatchingElements* matching_elements)
    : _field_name(field_name),
      _read_view(make_read_view<MultiValueType>(attr, stash)),
      _matching_elements(matching_elements)
{
}

template <typename MultiValueType>
MultiAttrDFWState<MultiValueType>::~MultiAttrDFWState() = default;

template <typename V>
void
set_value(V value, Symbol item_symbol, Cursor& cursor)
{
    if constexpr (std::is_same_v<V, const char*>) {
        cursor.setString(item_symbol, value);
    } else if constexpr(std::is_floating_point_v<V>) {
        cursor.setDouble(item_symbol, value);
    } else {
        cursor.setLong(item_symbol, value);
    }
}

template <typename V>
void
append_value(V value, Cursor& arr)
{
    if constexpr (std::is_same_v<V, const char*>) {
        arr.addString(value);
    } else if constexpr(std::is_floating_point_v<V>) {
        arr.addDouble(value);
    } else {
        arr.addLong(value);
    }
}

Memory ITEM("item");
Memory WEIGHT("weight");

template <typename MultiValueType>
void
MultiAttrDFWState<MultiValueType>::insertField(uint32_t docid, Inserter& target)
{
    using ValueType = multivalue::ValueType_t<MultiValueType>;
    if (!_read_view) {
        return;
    }
    auto elements = _read_view->get_values(docid);
    if (elements.empty()) {
        return;
    }
    Cursor &arr = target.insertArray(elements.size());

    if (_matching_elements) {
        const auto& matching_elems = _matching_elements->get_matching_elements(docid, _field_name);
        if (!matching_elems.empty() && matching_elems.back() < elements.size()) {
            if constexpr (multivalue::is_WeightedValue_v<MultiValueType>) {
                Symbol itemSymbol = arr.resolve(ITEM);
                Symbol weightSymbol = arr.resolve(WEIGHT);
                for (uint32_t id_to_keep : matching_elems) {
                    auto& element = elements[id_to_keep];
                    Cursor& elemC = arr.addObject();
                    set_value<ValueType>(element.value(), itemSymbol, elemC);
                    elemC.setLong(weightSymbol, element.weight());
                }
            } else {
                for (uint32_t id_to_keep : matching_elems) {
                    append_value<ValueType>(elements[id_to_keep], arr);
                }
            }
        }
    } else {
        if constexpr (multivalue::is_WeightedValue_v<MultiValueType>) {
            Symbol itemSymbol = arr.resolve(ITEM);
            Symbol weightSymbol = arr.resolve(WEIGHT);
            for (const auto & element : elements) {
                Cursor& elemC = arr.addObject();
                set_value<ValueType>(element.value(), itemSymbol, elemC);
                elemC.setLong(weightSymbol, element.weight());
            }
        } else {
            for (const auto & element : elements) {
                append_value<ValueType>(element, arr);
            }
        }
    }
}

class MultiAttrDFW : public AttrDFW {
private:
    bool _filter_elements;
    uint32_t _state_index; // index into _fieldWriterStates in GetDocsumsState
    std::shared_ptr<MatchingElementsFields> _matching_elems_fields;

public:
    MultiAttrDFW(const vespalib::string& attr_name, bool filter_elements, std::shared_ptr<MatchingElementsFields> matching_elems_fields)
        : AttrDFW(attr_name),
          _filter_elements(filter_elements),
          _state_index(0),
          _matching_elems_fields(std::move(matching_elems_fields))
    {
        if (filter_elements && _matching_elems_fields) {
            _matching_elems_fields->add_field(attr_name);
        }
    }
    bool setFieldWriterStateIndex(uint32_t fieldWriterStateIndex) override;
    void insertField(uint32_t docid, GetDocsumsState* state, ResType, Inserter& target) const override;
};

bool
MultiAttrDFW::setFieldWriterStateIndex(uint32_t fieldWriterStateIndex)
{
    _state_index = fieldWriterStateIndex;
    return true;
}

template <typename DataType>
DocsumFieldWriterState*
make_field_writer_state_helper(const vespalib::string& field_name, const IAttributeVector& attr, vespalib::Stash& stash, const MatchingElements* matching_elements)
{
    bool is_weighted_set = attr.hasWeightedSetType();
    if (is_weighted_set) {
        return &stash.create<MultiAttrDFWState<multivalue::WeightedValue<DataType>>>(field_name, attr, stash, matching_elements);
    } else {
        return &stash.create<MultiAttrDFWState<DataType>>(field_name, attr, stash, matching_elements);
    }
}

DocsumFieldWriterState*
make_field_writer_state(const vespalib::string& field_name, const IAttributeVector& attr, vespalib::Stash& stash, const MatchingElements* matching_elements)
{
    auto type = attr.getBasicType();
    switch (type) {
    case BasicType::Type::STRING:
        return make_field_writer_state_helper<const char*>(field_name, attr, stash, matching_elements);
    case BasicType::Type::INT8:
        return make_field_writer_state_helper<int8_t>(field_name, attr, stash, matching_elements);
    case BasicType::Type::INT16:
        return make_field_writer_state_helper<int16_t>(field_name, attr, stash, matching_elements);
    case BasicType::Type::INT32:
        return make_field_writer_state_helper<int32_t>(field_name, attr, stash, matching_elements);
    case BasicType::Type::INT64:
        return make_field_writer_state_helper<int64_t>(field_name, attr, stash, matching_elements);
    case BasicType::Type::FLOAT:
        return make_field_writer_state_helper<float>(field_name, attr, stash, matching_elements);
    case BasicType::Type::DOUBLE:
        return make_field_writer_state_helper<double>(field_name, attr, stash, matching_elements);
    default:
        ;
    }
    return &stash.create<EmptyWriterState>();
}

void
MultiAttrDFW::insertField(uint32_t docid, GetDocsumsState *state, ResType, vespalib::slime::Inserter &target) const
{
    auto& field_writer_state = state->_fieldWriterStates[_state_index];
    if (!field_writer_state) {
        const MatchingElements *matching_elements = nullptr;
        if (_filter_elements) {
            matching_elements = &state->get_matching_elements(*_matching_elems_fields);
        }
        const auto& attr = get_attribute(*state);
        field_writer_state = make_field_writer_state(getAttributeName(), attr, state->get_stash(), matching_elements);
    }
    field_writer_state->insertField(docid, target);
}

std::unique_ptr<DocsumFieldWriter>
create_multi_writer(const IAttributeVector& attr, bool filter_elements, std::shared_ptr<MatchingElementsFields> matching_elems_fields)
{
    auto type = attr.getBasicType();
    switch (type) {
    case BasicType::STRING:
    case BasicType::INT8:
    case BasicType::INT16:
    case BasicType::INT32:
    case BasicType::INT64:
    case BasicType::FLOAT:
    case BasicType::DOUBLE:
        return std::make_unique<MultiAttrDFW>(attr.getName(), filter_elements, std::move(matching_elems_fields));
    default:
        // should not happen
        LOG(error, "Bad value for attribute type: %u", type);
        LOG_ASSERT(false);
    }
}

}

std::unique_ptr<DocsumFieldWriter>
AttributeDFWFactory::create(const IAttributeManager& attr_mgr,
                            const vespalib::string& attr_name,
                            bool filter_elements,
                            std::shared_ptr<MatchingElementsFields> matching_elems_fields)
{
    auto ctx = attr_mgr.createContext();
    const auto* attr = ctx->getAttribute(attr_name);
    if (attr == nullptr) {
        Issue::report("No valid attribute vector found: '%s'", attr_name.c_str());
        return std::unique_ptr<DocsumFieldWriter>();
    }
    if (attr->hasMultiValue()) {
        return create_multi_writer(*attr, filter_elements, std::move(matching_elems_fields));
    } else {
        return std::make_unique<SingleAttrDFW>(attr->getName());
    }
}

}
<|endoftext|>