<commit_before>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix 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.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "command.h"
#include "memory.h"
#include "dwi/fmls.h"
#include "dwi/tractography/file.h"
#include "dwi/tractography/properties.h"
#include "dwi/tractography/mapping/loader.h"
#include "dwi/tractography/mapping/mapper.h"
#include "dwi/tractography/mapping/mapping.h"
#include "dwi/tractography/SIFT/model_base.h"

using namespace MR;
using namespace MR::DWI;
using namespace App;

void usage ()
{
  AUTHOR = "David Raffelt (david.raffelt@florey.edu.au) and Robert E. Smith (robert.smith@florey.edu.au)";

  DESCRIPTION
  + "obtain an estimate of fibre connectivity between two regions using AFD and streamlines tractography"

  + "This estimate is obtained by determining a fibre volume (AFD) occupied by the pathway "
    "of interest, and dividing by the streamline length."

  + "If only the streamlines belonging to the pathway of interest are provided, then "
    "ALL of the fibre volume within each fixel selected will contribute to the result. "
    "If the -wbft option is used to provide whole-brain fibre-tracking (of which the pathway of "
    "interest should contain a subset), only the fraction of the fibre volume in each fixel "
    "estiamted to belong to the pathway of interest will contribute to the result."

  + "Use -quiet to suppress progress messages and output fibre connectivity value only."

  + "For valid comparisons of AFD connectivity across scans, images MUST be intensity "
    "normalised and bias field corrected, and a common response function for all subjects "
    "must be used."

  + "Note that the sum of the AFD is normalised by streamline length to "
    "account for subject differences in fibre bundle length. This normalisation results in a measure "
    "that is more related to the cross-sectional volume of the tract (and therefore 'connectivity'). "
    "Note that SIFT-ed tract count is a superior measure because it is unaffected by tangential yet unrelated "
    "fibres. However, AFD connectivity may be used as a substitute when Anatomically Constrained Tractography "
    "is not possible due to uncorrectable EPI distortions, and SIFT may therefore not be as effective.";

  ARGUMENTS
  + Argument ("image", "the input FOD image.").type_image_in()

  + Argument ("tracks", "the input track file defining the bundle of interest.").type_tracks_in();

  OPTIONS
  + Option ("wbft", "provide a whole-brain fibre-tracking data set (of which the input track file "
                    "should be a subset), to improve the estimate of fibre bundle volume in the "
                    "presence of partial volume")
    + Argument ("tracks").type_tracks_in()

  + Option ("afd_map", "output a 3D image containing the AFD estimated for each voxel.")
    + Argument ("image").type_image_out()

  + Option ("all_fixels", "if whole-brain fibre-tracking is NOT provided, then if multiple fixels within "
                          "a voxel are traversed by the pathway of interest, by default the fixel with the "
                          "greatest streamlines density is selected to contribute to the AFD in that voxel. "
                          "If this option is provided, then ALL fixels with non-zero streamlines density "
                          "will contribute to the result, even if multiple fixels per voxel are selected.");

}

typedef float value_type;
typedef DWI::Tractography::Mapping::SetDixel SetDixel;
typedef DWI::Tractography::SIFT::FixelBase FixelBase;

class Fixel : public FixelBase
{
  public:
    Fixel () : FixelBase (), length (0.0) { }
    Fixel (const FMLS::FOD_lobe& lobe) : FixelBase (lobe), length (0.0) { }
    Fixel (const Fixel& that) : FixelBase (that), length (that.length) { }

    void       add_to_selection (const value_type l) { length += l; }
    value_type get_selected_volume (const value_type l) const { return get_TD() ? (get_FOD() * (l / get_TD())) : 0.0; }
    value_type get_selected_volume ()                   const { return get_TD() ? (get_FOD() * (length / get_TD())) : 0.0; }
    value_type get_selected_length() const { return length; }
    bool       is_selected()         const { return length; }

  private:
    value_type length;

};

class AFDConnectivity : public DWI::Tractography::SIFT::ModelBase<Fixel>
{
  public:
    AFDConnectivity (Image<value_type>& fod_buffer, const DWI::Directions::FastLookupSet& dirs, const std::string& tck_path, const std::string& wbft_path) :
        DWI::Tractography::SIFT::ModelBase<Fixel> (fod_buffer, dirs),
        have_wbft (wbft_path.size()),
        all_fixels (false),
        mapper (fod_buffer, dirs),
        v_fod (fod_buffer)
    {
      if (have_wbft) {
        perform_FOD_segmentation (fod_buffer);
        map_streamlines (wbft_path);
      } else {
        fmls.reset (new DWI::FMLS::Segmenter (dirs, Math::SH::LforN (fod_buffer.size (3))));
      }
      mapper.set_upsample_ratio (DWI::Tractography::Mapping::determine_upsample_ratio (fod_buffer, tck_path, 0.1));
      mapper.set_use_precise_mapping (true);
    }

    void set_all_fixels (const bool i) { all_fixels = i; }

    value_type get  (const std::string& path);
    void       save (const std::string& path);

  private:
    const bool have_wbft;
    bool all_fixels;
    DWI::Tractography::Mapping::TrackMapperBase mapper;
    Image<value_type> v_fod;
    copy_ptr<DWI::FMLS::Segmenter> fmls;

    using Fixel_map<Fixel>::accessor;

};

value_type AFDConnectivity::get (const std::string& path)
{

  Tractography::Properties properties;
  Tractography::Reader<value_type> reader (path, properties);
  const size_t track_count = (properties.find ("count") == properties.end() ? 0 : to<size_t>(properties["count"]));
  DWI::Tractography::Mapping::TrackLoader loader (reader, track_count, "summing apparent fibre density within track");

  // If WBFT is provided, this is the sum of (volume/length) across streamlines
  // Otherwise, it's a sum of lengths of all streamlines (for later scaling by mean streamline length)
  double sum_contributions = 0.0;

  size_t count = 0;

  Tractography::Streamline<value_type> tck;
  while (loader (tck)) {
    ++count;

    SetDixel dixels;
    mapper (tck, dixels);
    double this_length = 0.0, this_volume = 0.0;

    for (SetDixel::const_iterator i = dixels.begin(); i != dixels.end(); ++i) {
      this_length += i->get_length();

      // If wbft has not been provided (i.e. FODs have not been pre-segmented), need to
      //   check to see if any data have been provided for this voxel; and if not yet,
      //   run the segmenter
      if (!have_wbft) {

        VoxelAccessor v (accessor());
        assign_pos_of (*i, 0, 3).to (v);
        if (!v.value()) {

          assign_pos_of (*i, 0, 3).to (v_fod);
          DWI::FMLS::SH_coefs fod_data;
          DWI::FMLS::FOD_lobes fod_lobes;

          fod_data.vox[0] = v_fod.index (0); fod_data.vox[1] = v_fod.index (1); fod_data.vox[2] = v_fod.index (2);
          fod_data.resize (v_fod.size (3));
          for (auto i = Loop(3) (v_fod); i; ++i)
            fod_data[v_fod.index (3)] = v_fod.value();

          (*fmls) (fod_data, fod_lobes);
          (*this) (fod_lobes);

        }
      }

      const size_t fixel_index = dixel2fixel (*i);
      Fixel& fixel = fixels[fixel_index];
      fixel.add_to_selection (i->get_length());
      if (have_wbft)
        this_volume += fixel.get_selected_volume (i->get_length());

    }

    if (have_wbft)
      sum_contributions += (this_volume / this_length);
    else
      sum_contributions += this_length;

  }

  if (!have_wbft) {

    // Streamlines define a fixel mask; go through and get all the fibre volumes
    double sum_volumes = 0.0;

    if (all_fixels) {

      // All fixels contribute to the result
      for (std::vector<Fixel>::const_iterator i = fixels.begin(); i != fixels.end(); ++i) {
        if (i->is_selected())
          sum_volumes += i->get_FOD();
      }

    } else {

      // Only allow one fixel per voxel to contribute to the result
      VoxelAccessor v (accessor());
      for (auto l = Loop(v) (v); l; ++l) {
        if (v.value()) {
          value_type voxel_afd = 0.0, max_td = 0.0;
          for (Fixel_map<Fixel>::Iterator i = begin (v); i; ++i) {
            if (i().get_selected_length() > max_td) {
              max_td = i().get_selected_length();
              voxel_afd = i().get_FOD();
            }
          }
          sum_volumes += voxel_afd;
        }
      }

    }

    // sum_contributions currently stores sum of streamline lengths;
    //   turn into a mean length, then combine with volume to get a connectivity value
    const double mean_length = sum_contributions / double(count);
    sum_contributions = sum_volumes / mean_length;

  }

  return sum_contributions;

}

void AFDConnectivity::save (const std::string& path)
{
  auto out = Image<value_type>::create (path, original_header());
  VoxelAccessor v (accessor());
  for (auto l = Loop(v) (v, out); l; ++l) {
    value_type value = 0.0;
    if (have_wbft) {
      for (Fixel_map<Fixel>::Iterator i = begin (v); i; ++i)
        value += i().get_selected_volume();
    } else if (all_fixels) {
      for (Fixel_map<Fixel>::Iterator i = begin (v); i; ++i)
        value += (i().is_selected() ? i().get_FOD() : 0.0);
    } else {
      value_type max_td = 0.0;
      for (Fixel_map<Fixel>::Iterator i = begin (v); i; ++i) {
        if (i().get_selected_length() > max_td) {
          max_td = i().get_selected_length();
          value = i().get_FOD();
        }
      }
    }
    out.value() = value;
  }
}

void run ()
{
  auto opt = get_options ("wbft");
  const std::string wbft_path = opt.size() ? str(opt[0][0]) : "";

  DWI::Directions::FastLookupSet dirs (1281);
  auto fod = Image<value_type>::open (argument[0]);
  Math::SH::check (fod);
  AFDConnectivity model (fod, dirs, argument[1], wbft_path);

  opt = get_options ("all_fixels");
  model.set_all_fixels (opt.size());

  const value_type connectivity_value = model.get (argument[1]);

  // output the AFD sum using std::cout. This enables output to be redirected to a file without the console output.
  std::cout << connectivity_value << std::endl;

  opt = get_options ("afd_map");
  if (opt.size())
    model.save (opt[0][0]);
}

<commit_msg>estiamted -> estimated<commit_after>/*
 * Copyright (c) 2008-2016 the MRtrix3 contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix 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.
 *
 * For more details, see www.mrtrix.org
 *
 */

#include "command.h"
#include "memory.h"
#include "dwi/fmls.h"
#include "dwi/tractography/file.h"
#include "dwi/tractography/properties.h"
#include "dwi/tractography/mapping/loader.h"
#include "dwi/tractography/mapping/mapper.h"
#include "dwi/tractography/mapping/mapping.h"
#include "dwi/tractography/SIFT/model_base.h"

using namespace MR;
using namespace MR::DWI;
using namespace App;

void usage ()
{
  AUTHOR = "David Raffelt (david.raffelt@florey.edu.au) and Robert E. Smith (robert.smith@florey.edu.au)";

  DESCRIPTION
  + "obtain an estimate of fibre connectivity between two regions using AFD and streamlines tractography"

  + "This estimate is obtained by determining a fibre volume (AFD) occupied by the pathway "
    "of interest, and dividing by the streamline length."

  + "If only the streamlines belonging to the pathway of interest are provided, then "
    "ALL of the fibre volume within each fixel selected will contribute to the result. "
    "If the -wbft option is used to provide whole-brain fibre-tracking (of which the pathway of "
    "interest should contain a subset), only the fraction of the fibre volume in each fixel "
    "estimated to belong to the pathway of interest will contribute to the result."

  + "Use -quiet to suppress progress messages and output fibre connectivity value only."

  + "For valid comparisons of AFD connectivity across scans, images MUST be intensity "
    "normalised and bias field corrected, and a common response function for all subjects "
    "must be used."

  + "Note that the sum of the AFD is normalised by streamline length to "
    "account for subject differences in fibre bundle length. This normalisation results in a measure "
    "that is more related to the cross-sectional volume of the tract (and therefore 'connectivity'). "
    "Note that SIFT-ed tract count is a superior measure because it is unaffected by tangential yet unrelated "
    "fibres. However, AFD connectivity may be used as a substitute when Anatomically Constrained Tractography "
    "is not possible due to uncorrectable EPI distortions, and SIFT may therefore not be as effective.";

  ARGUMENTS
  + Argument ("image", "the input FOD image.").type_image_in()

  + Argument ("tracks", "the input track file defining the bundle of interest.").type_tracks_in();

  OPTIONS
  + Option ("wbft", "provide a whole-brain fibre-tracking data set (of which the input track file "
                    "should be a subset), to improve the estimate of fibre bundle volume in the "
                    "presence of partial volume")
    + Argument ("tracks").type_tracks_in()

  + Option ("afd_map", "output a 3D image containing the AFD estimated for each voxel.")
    + Argument ("image").type_image_out()

  + Option ("all_fixels", "if whole-brain fibre-tracking is NOT provided, then if multiple fixels within "
                          "a voxel are traversed by the pathway of interest, by default the fixel with the "
                          "greatest streamlines density is selected to contribute to the AFD in that voxel. "
                          "If this option is provided, then ALL fixels with non-zero streamlines density "
                          "will contribute to the result, even if multiple fixels per voxel are selected.");

}

typedef float value_type;
typedef DWI::Tractography::Mapping::SetDixel SetDixel;
typedef DWI::Tractography::SIFT::FixelBase FixelBase;

class Fixel : public FixelBase
{
  public:
    Fixel () : FixelBase (), length (0.0) { }
    Fixel (const FMLS::FOD_lobe& lobe) : FixelBase (lobe), length (0.0) { }
    Fixel (const Fixel& that) : FixelBase (that), length (that.length) { }

    void       add_to_selection (const value_type l) { length += l; }
    value_type get_selected_volume (const value_type l) const { return get_TD() ? (get_FOD() * (l / get_TD())) : 0.0; }
    value_type get_selected_volume ()                   const { return get_TD() ? (get_FOD() * (length / get_TD())) : 0.0; }
    value_type get_selected_length() const { return length; }
    bool       is_selected()         const { return length; }

  private:
    value_type length;

};

class AFDConnectivity : public DWI::Tractography::SIFT::ModelBase<Fixel>
{
  public:
    AFDConnectivity (Image<value_type>& fod_buffer, const DWI::Directions::FastLookupSet& dirs, const std::string& tck_path, const std::string& wbft_path) :
        DWI::Tractography::SIFT::ModelBase<Fixel> (fod_buffer, dirs),
        have_wbft (wbft_path.size()),
        all_fixels (false),
        mapper (fod_buffer, dirs),
        v_fod (fod_buffer)
    {
      if (have_wbft) {
        perform_FOD_segmentation (fod_buffer);
        map_streamlines (wbft_path);
      } else {
        fmls.reset (new DWI::FMLS::Segmenter (dirs, Math::SH::LforN (fod_buffer.size (3))));
      }
      mapper.set_upsample_ratio (DWI::Tractography::Mapping::determine_upsample_ratio (fod_buffer, tck_path, 0.1));
      mapper.set_use_precise_mapping (true);
    }

    void set_all_fixels (const bool i) { all_fixels = i; }

    value_type get  (const std::string& path);
    void       save (const std::string& path);

  private:
    const bool have_wbft;
    bool all_fixels;
    DWI::Tractography::Mapping::TrackMapperBase mapper;
    Image<value_type> v_fod;
    copy_ptr<DWI::FMLS::Segmenter> fmls;

    using Fixel_map<Fixel>::accessor;

};

value_type AFDConnectivity::get (const std::string& path)
{

  Tractography::Properties properties;
  Tractography::Reader<value_type> reader (path, properties);
  const size_t track_count = (properties.find ("count") == properties.end() ? 0 : to<size_t>(properties["count"]));
  DWI::Tractography::Mapping::TrackLoader loader (reader, track_count, "summing apparent fibre density within track");

  // If WBFT is provided, this is the sum of (volume/length) across streamlines
  // Otherwise, it's a sum of lengths of all streamlines (for later scaling by mean streamline length)
  double sum_contributions = 0.0;

  size_t count = 0;

  Tractography::Streamline<value_type> tck;
  while (loader (tck)) {
    ++count;

    SetDixel dixels;
    mapper (tck, dixels);
    double this_length = 0.0, this_volume = 0.0;

    for (SetDixel::const_iterator i = dixels.begin(); i != dixels.end(); ++i) {
      this_length += i->get_length();

      // If wbft has not been provided (i.e. FODs have not been pre-segmented), need to
      //   check to see if any data have been provided for this voxel; and if not yet,
      //   run the segmenter
      if (!have_wbft) {

        VoxelAccessor v (accessor());
        assign_pos_of (*i, 0, 3).to (v);
        if (!v.value()) {

          assign_pos_of (*i, 0, 3).to (v_fod);
          DWI::FMLS::SH_coefs fod_data;
          DWI::FMLS::FOD_lobes fod_lobes;

          fod_data.vox[0] = v_fod.index (0); fod_data.vox[1] = v_fod.index (1); fod_data.vox[2] = v_fod.index (2);
          fod_data.resize (v_fod.size (3));
          for (auto i = Loop(3) (v_fod); i; ++i)
            fod_data[v_fod.index (3)] = v_fod.value();

          (*fmls) (fod_data, fod_lobes);
          (*this) (fod_lobes);

        }
      }

      const size_t fixel_index = dixel2fixel (*i);
      Fixel& fixel = fixels[fixel_index];
      fixel.add_to_selection (i->get_length());
      if (have_wbft)
        this_volume += fixel.get_selected_volume (i->get_length());

    }

    if (have_wbft)
      sum_contributions += (this_volume / this_length);
    else
      sum_contributions += this_length;

  }

  if (!have_wbft) {

    // Streamlines define a fixel mask; go through and get all the fibre volumes
    double sum_volumes = 0.0;

    if (all_fixels) {

      // All fixels contribute to the result
      for (std::vector<Fixel>::const_iterator i = fixels.begin(); i != fixels.end(); ++i) {
        if (i->is_selected())
          sum_volumes += i->get_FOD();
      }

    } else {

      // Only allow one fixel per voxel to contribute to the result
      VoxelAccessor v (accessor());
      for (auto l = Loop(v) (v); l; ++l) {
        if (v.value()) {
          value_type voxel_afd = 0.0, max_td = 0.0;
          for (Fixel_map<Fixel>::Iterator i = begin (v); i; ++i) {
            if (i().get_selected_length() > max_td) {
              max_td = i().get_selected_length();
              voxel_afd = i().get_FOD();
            }
          }
          sum_volumes += voxel_afd;
        }
      }

    }

    // sum_contributions currently stores sum of streamline lengths;
    //   turn into a mean length, then combine with volume to get a connectivity value
    const double mean_length = sum_contributions / double(count);
    sum_contributions = sum_volumes / mean_length;

  }

  return sum_contributions;

}

void AFDConnectivity::save (const std::string& path)
{
  auto out = Image<value_type>::create (path, original_header());
  VoxelAccessor v (accessor());
  for (auto l = Loop(v) (v, out); l; ++l) {
    value_type value = 0.0;
    if (have_wbft) {
      for (Fixel_map<Fixel>::Iterator i = begin (v); i; ++i)
        value += i().get_selected_volume();
    } else if (all_fixels) {
      for (Fixel_map<Fixel>::Iterator i = begin (v); i; ++i)
        value += (i().is_selected() ? i().get_FOD() : 0.0);
    } else {
      value_type max_td = 0.0;
      for (Fixel_map<Fixel>::Iterator i = begin (v); i; ++i) {
        if (i().get_selected_length() > max_td) {
          max_td = i().get_selected_length();
          value = i().get_FOD();
        }
      }
    }
    out.value() = value;
  }
}

void run ()
{
  auto opt = get_options ("wbft");
  const std::string wbft_path = opt.size() ? str(opt[0][0]) : "";

  DWI::Directions::FastLookupSet dirs (1281);
  auto fod = Image<value_type>::open (argument[0]);
  Math::SH::check (fod);
  AFDConnectivity model (fod, dirs, argument[1], wbft_path);

  opt = get_options ("all_fixels");
  model.set_all_fixels (opt.size());

  const value_type connectivity_value = model.get (argument[1]);

  // output the AFD sum using std::cout. This enables output to be redirected to a file without the console output.
  std::cout << connectivity_value << std::endl;

  opt = get_options ("afd_map");
  if (opt.size())
    model.save (opt[0][0]);
}

<|endoftext|>


<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2021 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program 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 Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#ifdef _WIN32
#define DLLEXPORT extern "C" __declspec (dllexport)
#else
#define DLLEXPORT extern "C"
#endif

#ifndef STATIC_PLUGIN
#define DEF_SERVER
#endif

#include "../Interface/Server.h"
#include "pluginmgr.h"
#include "../stringtools.h"
#include "../urbackupcommon/WalCheckpointThread.h"

#include <aws/core/utils/logging/AWSLogging.h>
#include <aws/core/utils/logging/FormattedLogSystem.h>
#include <aws/core/Aws.h>

#include "../urbackupcommon/os_functions.h"

#ifndef STATIC_PLUGIN
IServer* Server;
#else
#include "../StaticPluginRegistration.h"

extern IServer* Server;

#define LoadActions LoadActions_clouddrive
#define UnloadActions UnloadActions_clouddrive
#endif

void init_compress_encrypt_factory();

bool is_automount_finished()
{
    return false;
}

std::string getCdInterfacePath()
{
    os_create_dir("urbackup/cd");
    return "urbackup/cd";
}

class ServerLogging : public Aws::Utils::Logging::FormattedLogSystem
{
public:
    ServerLogging(Aws::Utils::Logging::LogLevel loglevel)
        : Aws::Utils::Logging::FormattedLogSystem(loglevel)
    {}

    void Flush() {}
protected:
    virtual void ProcessFormattedStatement(Aws::String&& statement)
    {
        Server->Log(trim(statement.c_str()), LL_INFO);
    }
};

ClouddrivePluginMgr* clouddrivepluginmgr;

DLLEXPORT void LoadActions(IServer* pServer)
{
    Server = pServer;

    WalCheckpointThread::init_mutex();

    clouddrivepluginmgr = new ClouddrivePluginMgr;

    init_compress_encrypt_factory();

    Aws::SDKOptions options;
    Aws::InitAPI(options);

    Aws::Utils::Logging::InitializeAWSLogging(Aws::MakeShared<ServerLogging>("KvStoreBackend", Aws::Utils::Logging::LogLevel::Warn));

    Server->RegisterPluginThreadsafeModel(clouddrivepluginmgr, "clouddriveplugin");

#ifndef STATIC_PLUGIN
    Server->Log("Loaded -btrfsplugin- plugin", LL_INFO);
#endif
}

DLLEXPORT void UnloadActions(void)
{
    if (Server->getServerParameter("leak_check") == "true")
    {
        Aws::SDKOptions options;
        Aws::ShutdownAPI(options);
    }
}

#ifdef STATIC_PLUGIN
namespace
{
    static RegisterPluginHelper register_plugin(LoadActions, UnloadActions, 10);
}
#endif<commit_msg>Fix initialization<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2021 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program 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 Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#ifdef _WIN32
#define DLLEXPORT extern "C" __declspec (dllexport)
#else
#define DLLEXPORT extern "C"
#endif

#ifndef STATIC_PLUGIN
#define DEF_SERVER
#endif

#include "../Interface/Server.h"
#include "pluginmgr.h"
#include "../stringtools.h"
#include "../urbackupcommon/WalCheckpointThread.h"

#include <aws/core/utils/logging/AWSLogging.h>
#include <aws/core/utils/logging/FormattedLogSystem.h>
#include <aws/core/Aws.h>

#include "../urbackupcommon/os_functions.h"

#ifndef STATIC_PLUGIN
IServer* Server;
#else
#include "../StaticPluginRegistration.h"

extern IServer* Server;

#define LoadActions LoadActions_clouddrive
#define UnloadActions UnloadActions_clouddrive
#endif

#include "KvStoreBackendS3.h"

void init_compress_encrypt_factory();

bool is_automount_finished()
{
    return false;
}

std::string getCdInterfacePath()
{
    os_create_dir("urbackup/cd");
    return "urbackup/cd";
}

class ServerLogging : public Aws::Utils::Logging::FormattedLogSystem
{
public:
    ServerLogging(Aws::Utils::Logging::LogLevel loglevel)
        : Aws::Utils::Logging::FormattedLogSystem(loglevel)
    {}

    void Flush() {}
protected:
    virtual void ProcessFormattedStatement(Aws::String&& statement)
    {
        Server->Log(trim(statement.c_str()), LL_INFO);
    }
};

ClouddrivePluginMgr* clouddrivepluginmgr;

DLLEXPORT void LoadActions(IServer* pServer)
{
    Server = pServer;

    WalCheckpointThread::init_mutex();
    KvStoreBackendS3::init_mutex();

    clouddrivepluginmgr = new ClouddrivePluginMgr;

    init_compress_encrypt_factory();

    Aws::SDKOptions options = {};
    Aws::InitAPI(options);

    Aws::Utils::Logging::InitializeAWSLogging(Aws::MakeShared<ServerLogging>("KvStoreBackend", Aws::Utils::Logging::LogLevel::Warn));

    Server->RegisterPluginThreadsafeModel(clouddrivepluginmgr, "clouddriveplugin");

#ifndef STATIC_PLUGIN
    Server->Log("Loaded -btrfsplugin- plugin", LL_INFO);
#endif
}

DLLEXPORT void UnloadActions(void)
{
    if (Server->getServerParameter("leak_check") == "true")
    {
        Aws::SDKOptions options;
        Aws::ShutdownAPI(options);
    }
}

#ifdef STATIC_PLUGIN
namespace
{
    static RegisterPluginHelper register_plugin(LoadActions, UnloadActions, 10);
}
#endif<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2015, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.	You may
 * obtain a copy of the License at
 *
 *		http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_attributes.h"
#include "condor_classad.h"
#include "condor_config.h"
#include "condor_constants.h"
#include "condor_uid.h"
#include "condor_md.h"
#include "directory_util.h"
#include "filename_tools.h"
#include "stat_wrapper.h"
#include <string>

#ifndef WIN32
	#include <unistd.h>
#endif

#ifdef HAVE_HTTP_PUBLIC_FILES

using namespace std;

namespace {	// Anonymous namespace to limit scope of names to this file

const int HASHNAMELEN = 17;

static string MakeHashName(const char* fileName, time_t fileModifiedTime) {

	unsigned char hashResult[HASHNAMELEN * 3]; // Allocate extra space for safety.

	// Convert the modified time to a string object
	std::string modifiedTimeStr = std::to_string((long long int) fileModifiedTime);

	// Create a new string which will be the source for our hash function.
	// This will append two strings:
	// 1. Full path to the file
	// 2. Modified time of the file
	unsigned char* hashSource = new unsigned char[strlen(fileName)
									+ strlen(modifiedTimeStr.c_str()) + 1];
	strcpy( (char*) hashSource, fileName );
	strcat( (char*) hashSource, modifiedTimeStr.c_str() );

	// Now calculate the hash
	memcpy(hashResult, Condor_MD_MAC::computeOnce(hashSource,
		strlen((const char*) hashSource)), HASHNAMELEN);
	char entryHashName[HASHNAMELEN * 2]; // 2 chars per hex byte
	entryHashName[0] = '\0';
	char letter[3];
	for (int i = 0; i < HASHNAMELEN - 1; ++i) {
		sprintf(letter, "%x", hashResult[i]);
		strcat(entryHashName, letter);
	}

	return entryHashName;
}

// WARNING!  This code changes priv state.  Be very careful if modifying it.
// Do not return in the block of code where the priv has been set to either
// condor or root.  -zmiller
static bool MakeLink(const char* srcFile, const string &newLink) {
	std::string webRootDir;
	param(webRootDir, "HTTP_PUBLIC_FILES_ROOT_DIR");
	if(webRootDir.empty()) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_DIR "
						"not set! Falling back to regular file transfer\n");
		return (false);
	}
	char goodPath[PATH_MAX];
	if (realpath(webRootDir.c_str(), goodPath) == NULL) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_DIR "
			"not a valid path: %s. Falling back to regular file transfer.\n",
			webRootDir.c_str());
		return (false);
	}
	StatWrapper fileMode;
	bool fileOK = false;
	if (fileMode.Stat(srcFile) == 0) {
		const StatStructType *statrec = fileMode.GetBuf();
		if (statrec != NULL)
			fileOK = (statrec->st_mode & S_IROTH); // Verify readable by all
	}
	if (fileOK == false) {
		dprintf(D_ALWAYS,
			"Cannot transfer -- public input file not world readable: %s\n", srcFile);
		return (false);
	}

	// see how we should create the link.  There are a few options.
	// 1) As the condor user.
	// 2) As root, and then chown to the user.
	// 3) As root, and then chown to some other user (like "httpd")
	std::string link_owner;
	param(link_owner, "HTTP_PUBLIC_FILES_USER");

	uid_t link_uid = -1;
	gid_t link_gid = -1;
	bool  create_as_root = false;

	priv_state priv = PRIV_UNKNOWN;

	if (strcasecmp(link_owner.c_str(), "<user>") == 0) {
		// we'll do everything in user priv except use root
		// to create and chown the link

		link_uid = get_user_uid();
		link_gid = get_user_gid();
		create_as_root = true;
		priv = set_user_priv();
	} else if (strcasecmp(link_owner.c_str(), "<condor>") == 0) {
		// in this case we do everything as the condor user since they
		// own the directory

		priv = set_condor_priv();
	} else {
		// in this case we need to determine what uid they requested
		// and then do everything as that user.  we set root priv and
		// then temporarily assume the uid and gid of the specified
		// user.

		// has to be a username and not just a uid, since otherwise it
		// isn't clear what gid we should use (if they aren't in the passwd
		// file, for instance) and we also save on lookups.
		bool isname = pcache()->get_user_ids(link_owner.c_str(), link_uid, link_gid);
		if (!isname) {
			dprintf(D_ALWAYS, "ERROR: unable to look up HTTP_PUBLIC_FILES_USER (%s)"
				" in /etc/passwd.\n", link_owner.c_str());

			// we ARE allowed to return here because we have not
			// yet switched priv state in this case.
			return false;
		}

		if (link_uid == 0 || link_gid == 0) {
			dprintf(D_ALWAYS, "ERROR: HTTP_PUBLIC_FILES_USER (%s)"
				" in /etc/passwd has UID 0.  Aborting.\n", link_owner.c_str());

			// we ARE allowed to return here because we have not
			// yet switched priv state in this case.
			return false;
		}

		// now become the specified user for this operation.
		priv = set_root_priv();
		if (setegid(link_gid)) {}
		if (seteuid(link_uid)) {}
	}

	// STARTING HERE, DO NOT RETURN FROM THIS FUNCTION WITHOUT RESETTING
	// THE ORIGINAL PRIV STATE.

	// we will now create or update the link
	const char *const targetLink = dircat(goodPath, newLink.c_str()); // needs to be freed
	bool retVal = false;
	if (targetLink != NULL) {
		// Check if target already exists
		if (fileMode.Stat(targetLink, StatWrapper::STATOP_LSTAT) == 0) {
			// Good enough if link exists, ok if update fails
			retVal = true;

			// It is assumed that existing link points to srcFile.
			//
			// I don't like this assumption.  I think we need to
			// add username or uid to filename to prevent
			// accidents/mischeif when two users happen to us the
			// same file.  If user A then deletes or modifies the
			// file, user B is stuck with a link they probably
			// can't update.  To be fixed ASAP.  -zmiller
			const StatStructType *statrec = fileMode.GetBuf();
			if (statrec != NULL) {
				time_t filemtime = statrec->st_mtime;
				// Must be careful to operate on link, not target file.
				//
				// This should be done AS THE OWNER OF THE FILE.
				if ((time(NULL) - filemtime) > 3600 && lutimes(targetLink, NULL) != 0) {
					// Update mod time, but only once an hour to avoid excess file access
					dprintf(D_ALWAYS, "Could not update modification date on %s,"
						"error = %s\n", targetLink, strerror(errno));
				}
			} else {
				dprintf(D_ALWAYS, "Could not stat file %s\n", targetLink);
			}
		} else {
			// now create the link.  we may need to do this as root and chown
			// it, depending on the create_as_root flag.  if that's false, just
			// stay in the priv state we are in for creation and there's no need
			// to chown.

			priv_state link_priv = PRIV_UNKNOWN;
			if (create_as_root) {
				link_priv = set_root_priv();
			}

			if (symlink(srcFile, targetLink) == 0) {
				// so far, so good!
				retVal = true;
			} else {
				dprintf(D_ALWAYS, "Could not link %s to %s, error = %s\n", srcFile,
					targetLink, strerror(errno));
			}

			if (create_as_root) {
				// if we succesfully created the link, now chown to the user
				if (retVal && lchown(targetLink, link_uid, link_gid) != 0) {
					// chown didn't actually succeed, so this operation is now a failure.
					retVal = false;

					// destroy the evidence?
					unlink(targetLink);

					dprintf(D_ALWAYS, "Could not change ownership of %s to %i:%i, error = %s\n",
						targetLink, link_uid, link_gid, strerror(errno));
				}

				// either way, reset priv state
				set_priv(link_priv);
			}
		}

		delete [] targetLink;
	}

	// return to original privilege level, and exit
	set_priv(priv);

	return retVal;
}

static string MakeAbsolutePath(const char* path, const char* initialWorkingDir) {
	if (is_relative_to_cwd(path)) {
		string fullPath = initialWorkingDir;
		fullPath += DIR_DELIM_CHAR;
		fullPath += path;
		return (fullPath);
	}
	return (path);
}

} // end namespace

void ProcessCachedInpFiles(ClassAd *const Ad, StringList *const InputFiles,
	StringList &PubInpFiles) {

	char *initialWorkingDir = NULL;
	const char *path;
	MyString remap;
	struct stat fileStat;
	time_t fileModifiedTime = time(NULL);

	if (PubInpFiles.isEmpty() == false) {
		const char *webServerAddress = param("HTTP_PUBLIC_FILES_ADDRESS");

		// If a web server address is not defined, exit quickly. The file
		// transfer will go on using the regular CEDAR protocol.
		if(!webServerAddress) {
			dprintf(D_FULLDEBUG, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ADDRESS "
							"not set! Falling back to regular file transfer\n");
			return;
		}

		// Build out the base URL for public files
		string url = "http://";
		url += webServerAddress;
		url += "/";

		PubInpFiles.rewind();

		if (Ad->LookupString(ATTR_JOB_IWD, &initialWorkingDir) != 1) {
			dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Job ad did not have an "
				"initialWorkingDir! Falling back to regular file transfer\n");
			return;
		}
		while ((path = PubInpFiles.next()) != NULL) {
			// Determine the full path of the file to be transferred
			string fullPath = MakeAbsolutePath(path, initialWorkingDir);

			// Determine the time last modified of the file to be transferred
			if( stat( fullPath.c_str(), &fileStat ) == 0 ) {
				struct timespec fileTime = fileStat.st_mtim;
				fileModifiedTime = fileTime.tv_sec;
			}
			else {
				dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Unable to access file "
					"%s. Falling back to regular file transfer\n", fullPath.c_str());
				return;
			}

			string hashName = MakeHashName( fullPath.c_str(), fileModifiedTime );
			if (MakeLink(fullPath.c_str(), hashName)) {
				InputFiles->remove(path); // Remove plain file name from InputFiles
				remap += hashName;
				remap += "=";
				remap += basename(path);
				remap += ";";
				hashName = url + hashName;
				const char *const namePtr = hashName.c_str();
				if ( !InputFiles->contains(namePtr) ) {
					InputFiles->append(namePtr);
					dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Adding url to "
												"InputFiles: %s\n", namePtr);
				}
				else dprintf(D_FULLDEBUG, "mk_cache_links.cpp: url already "
											"in InputFiles: %s\n", namePtr);
			}
			else {
				dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Failed to generate "
									" hash link for %s\n", fullPath.c_str());
			}
		}
		free( initialWorkingDir );
		if ( remap.Length() > 0 ) {
			MyString remapnew;
			char *buf = NULL;
			if (Ad->LookupString(ATTR_TRANSFER_INPUT_REMAPS, &buf) == 1) {
				remapnew = buf;
				free(buf);
				buf = NULL;
				remapnew += ";";
			}
			remapnew += remap;
			if (Ad->Assign(ATTR_TRANSFER_INPUT_REMAPS, remap.Value()) == false) {
				dprintf(D_ALWAYS, "mk_cache_links.cpp: Could not add to jobAd: "
													"%s\n", remap.c_str());
			}
		}
	}
	else
		dprintf(D_FULLDEBUG, "mk_cache_links.cpp: No public input files.\n");
}

#endif

<commit_msg>Fixed potential memory leak (#6356)<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2015, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.	You may
 * obtain a copy of the License at
 *
 *		http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_attributes.h"
#include "condor_classad.h"
#include "condor_config.h"
#include "condor_constants.h"
#include "condor_uid.h"
#include "condor_md.h"
#include "directory_util.h"
#include "filename_tools.h"
#include "stat_wrapper.h"
#include <string>

#ifndef WIN32
	#include <unistd.h>
#endif

#ifdef HAVE_HTTP_PUBLIC_FILES

using namespace std;

namespace {	// Anonymous namespace to limit scope of names to this file

const int HASHNAMELEN = 17;

static string MakeHashName(const char* fileName, time_t fileModifiedTime) {

	unsigned char hashResult[HASHNAMELEN * 3]; // Allocate extra space for safety.

	// Convert the modified time to a string object
	std::string modifiedTimeStr = std::to_string((long long int) fileModifiedTime);

	// Create a new string which will be the source for our hash function.
	// This will append two strings:
	// 1. Full path to the file
	// 2. Modified time of the file
	unsigned char* hashSource = new unsigned char[strlen(fileName)
									+ strlen(modifiedTimeStr.c_str()) + 1];
	strcpy( (char*) hashSource, fileName );
	strcat( (char*) hashSource, modifiedTimeStr.c_str() );

	// Now calculate the hash
	memcpy(hashResult, Condor_MD_MAC::computeOnce(hashSource,
		strlen((const char*) hashSource)), HASHNAMELEN);
	char entryHashName[HASHNAMELEN * 2]; // 2 chars per hex byte
	entryHashName[0] = '\0';
	char letter[3];
	for (int i = 0; i < HASHNAMELEN - 1; ++i) {
		sprintf(letter, "%x", hashResult[i]);
		strcat(entryHashName, letter);
	}

	return entryHashName;
}

// WARNING!  This code changes priv state.  Be very careful if modifying it.
// Do not return in the block of code where the priv has been set to either
// condor or root.  -zmiller
static bool MakeLink(const char* srcFile, const string &newLink) {
	std::string webRootDir;
	param(webRootDir, "HTTP_PUBLIC_FILES_ROOT_DIR");
	if(webRootDir.empty()) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_DIR "
						"not set! Falling back to regular file transfer\n");
		return (false);
	}
	char goodPath[PATH_MAX];
	if (realpath(webRootDir.c_str(), goodPath) == NULL) {
		dprintf(D_ALWAYS, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ROOT_DIR "
			"not a valid path: %s. Falling back to regular file transfer.\n",
			webRootDir.c_str());
		return (false);
	}
	StatWrapper fileMode;
	bool fileOK = false;
	if (fileMode.Stat(srcFile) == 0) {
		const StatStructType *statrec = fileMode.GetBuf();
		if (statrec != NULL)
			fileOK = (statrec->st_mode & S_IROTH); // Verify readable by all
	}
	if (fileOK == false) {
		dprintf(D_ALWAYS,
			"Cannot transfer -- public input file not world readable: %s\n", srcFile);
		return (false);
	}

	// see how we should create the link.  There are a few options.
	// 1) As the condor user.
	// 2) As root, and then chown to the user.
	// 3) As root, and then chown to some other user (like "httpd")
	std::string link_owner;
	param(link_owner, "HTTP_PUBLIC_FILES_USER");

	uid_t link_uid = -1;
	gid_t link_gid = -1;
	bool  create_as_root = false;

	priv_state priv = PRIV_UNKNOWN;

	if (strcasecmp(link_owner.c_str(), "<user>") == 0) {
		// we'll do everything in user priv except use root
		// to create and chown the link

		link_uid = get_user_uid();
		link_gid = get_user_gid();
		create_as_root = true;
		priv = set_user_priv();
	} else if (strcasecmp(link_owner.c_str(), "<condor>") == 0) {
		// in this case we do everything as the condor user since they
		// own the directory

		priv = set_condor_priv();
	} else {
		// in this case we need to determine what uid they requested
		// and then do everything as that user.  we set root priv and
		// then temporarily assume the uid and gid of the specified
		// user.

		// has to be a username and not just a uid, since otherwise it
		// isn't clear what gid we should use (if they aren't in the passwd
		// file, for instance) and we also save on lookups.
		bool isname = pcache()->get_user_ids(link_owner.c_str(), link_uid, link_gid);
		if (!isname) {
			dprintf(D_ALWAYS, "ERROR: unable to look up HTTP_PUBLIC_FILES_USER (%s)"
				" in /etc/passwd.\n", link_owner.c_str());

			// we ARE allowed to return here because we have not
			// yet switched priv state in this case.
			return false;
		}

		if (link_uid == 0 || link_gid == 0) {
			dprintf(D_ALWAYS, "ERROR: HTTP_PUBLIC_FILES_USER (%s)"
				" in /etc/passwd has UID 0.  Aborting.\n", link_owner.c_str());

			// we ARE allowed to return here because we have not
			// yet switched priv state in this case.
			return false;
		}

		// now become the specified user for this operation.
		priv = set_root_priv();
		if (setegid(link_gid)) {}
		if (seteuid(link_uid)) {}
	}

	// STARTING HERE, DO NOT RETURN FROM THIS FUNCTION WITHOUT RESETTING
	// THE ORIGINAL PRIV STATE.

	// we will now create or update the link
	const char *const targetLink = dircat(goodPath, newLink.c_str()); // needs to be freed
	bool retVal = false;
	if (targetLink != NULL) {
		// Check if target already exists
		if (fileMode.Stat(targetLink, StatWrapper::STATOP_LSTAT) == 0) {
			// Good enough if link exists, ok if update fails
			retVal = true;

			// It is assumed that existing link points to srcFile.
			//
			// I don't like this assumption.  I think we need to
			// add username or uid to filename to prevent
			// accidents/mischeif when two users happen to us the
			// same file.  If user A then deletes or modifies the
			// file, user B is stuck with a link they probably
			// can't update.  To be fixed ASAP.  -zmiller
			const StatStructType *statrec = fileMode.GetBuf();
			if (statrec != NULL) {
				time_t filemtime = statrec->st_mtime;
				// Must be careful to operate on link, not target file.
				//
				// This should be done AS THE OWNER OF THE FILE.
				if ((time(NULL) - filemtime) > 3600 && lutimes(targetLink, NULL) != 0) {
					// Update mod time, but only once an hour to avoid excess file access
					dprintf(D_ALWAYS, "Could not update modification date on %s,"
						"error = %s\n", targetLink, strerror(errno));
				}
			} else {
				dprintf(D_ALWAYS, "Could not stat file %s\n", targetLink);
			}
		} else {
			// now create the link.  we may need to do this as root and chown
			// it, depending on the create_as_root flag.  if that's false, just
			// stay in the priv state we are in for creation and there's no need
			// to chown.

			priv_state link_priv = PRIV_UNKNOWN;
			if (create_as_root) {
				link_priv = set_root_priv();
			}

			if (symlink(srcFile, targetLink) == 0) {
				// so far, so good!
				retVal = true;
			} else {
				dprintf(D_ALWAYS, "Could not link %s to %s, error = %s\n", srcFile,
					targetLink, strerror(errno));
			}

			if (create_as_root) {
				// if we succesfully created the link, now chown to the user
				if (retVal && lchown(targetLink, link_uid, link_gid) != 0) {
					// chown didn't actually succeed, so this operation is now a failure.
					retVal = false;

					// destroy the evidence?
					unlink(targetLink);

					dprintf(D_ALWAYS, "Could not change ownership of %s to %i:%i, error = %s\n",
						targetLink, link_uid, link_gid, strerror(errno));
				}

				// either way, reset priv state
				set_priv(link_priv);
			}
		}

		delete [] targetLink;
	}

	// return to original privilege level, and exit
	set_priv(priv);

	return retVal;
}

static string MakeAbsolutePath(const char* path, const char* initialWorkingDir) {
	if (is_relative_to_cwd(path)) {
		string fullPath = initialWorkingDir;
		fullPath += DIR_DELIM_CHAR;
		fullPath += path;
		return (fullPath);
	}
	return (path);
}

} // end namespace

void ProcessCachedInpFiles(ClassAd *const Ad, StringList *const InputFiles,
	StringList &PubInpFiles) {

	char *initialWorkingDir = NULL;
	const char *path;
	MyString remap;
	struct stat fileStat;
	time_t fileModifiedTime = time(NULL);

	if (PubInpFiles.isEmpty() == false) {
		const char *webServerAddress = param("HTTP_PUBLIC_FILES_ADDRESS");

		// If a web server address is not defined, exit quickly. The file
		// transfer will go on using the regular CEDAR protocol.
		if(!webServerAddress) {
			dprintf(D_FULLDEBUG, "mk_cache_links.cpp: HTTP_PUBLIC_FILES_ADDRESS "
							"not set! Falling back to regular file transfer\n");
			return;
		}

		// Build out the base URL for public files
		string url = "http://";
		url += webServerAddress;
		url += "/";

		PubInpFiles.rewind();

		if (Ad->LookupString(ATTR_JOB_IWD, &initialWorkingDir) != 1) {
			dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Job ad did not have an "
				"initialWorkingDir! Falling back to regular file transfer\n");
			return;
		}
		while ((path = PubInpFiles.next()) != NULL) {
			// Determine the full path of the file to be transferred
			string fullPath = MakeAbsolutePath(path, initialWorkingDir);

			// Determine the time last modified of the file to be transferred
			if( stat( fullPath.c_str(), &fileStat ) == 0 ) {
				struct timespec fileTime = fileStat.st_mtim;
				fileModifiedTime = fileTime.tv_sec;
			}
			else {
				dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Unable to access file "
					"%s. Falling back to regular file transfer\n", fullPath.c_str());
				free( initialWorkingDir );
				return;
			}

			string hashName = MakeHashName( fullPath.c_str(), fileModifiedTime );
			if (MakeLink(fullPath.c_str(), hashName)) {
				InputFiles->remove(path); // Remove plain file name from InputFiles
				remap += hashName;
				remap += "=";
				remap += basename(path);
				remap += ";";
				hashName = url + hashName;
				const char *const namePtr = hashName.c_str();
				if ( !InputFiles->contains(namePtr) ) {
					InputFiles->append(namePtr);
					dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Adding url to "
												"InputFiles: %s\n", namePtr);
				}
				else dprintf(D_FULLDEBUG, "mk_cache_links.cpp: url already "
											"in InputFiles: %s\n", namePtr);
			}
			else {
				dprintf(D_FULLDEBUG, "mk_cache_links.cpp: Failed to generate "
									" hash link for %s\n", fullPath.c_str());
			}
		}
		free( initialWorkingDir );
		if ( remap.Length() > 0 ) {
			MyString remapnew;
			char *buf = NULL;
			if (Ad->LookupString(ATTR_TRANSFER_INPUT_REMAPS, &buf) == 1) {
				remapnew = buf;
				free(buf);
				buf = NULL;
				remapnew += ";";
			}
			remapnew += remap;
			if (Ad->Assign(ATTR_TRANSFER_INPUT_REMAPS, remap.Value()) == false) {
				dprintf(D_ALWAYS, "mk_cache_links.cpp: Could not add to jobAd: "
													"%s\n", remap.c_str());
			}
		}
	}
	else
		dprintf(D_FULLDEBUG, "mk_cache_links.cpp: No public input files.\n");
}

#endif

<|endoftext|>


<commit_before>#include "ConstantBitP_TransferFunctions.h"
#include "ConstantBitP_Utility.h"

namespace simplifier
{
namespace constantBitP
{

namespace BEEV
{
typedef unsigned int * CBV;
}

// Misc (easy) transfer functions.
// Trevor Hansen. BSD License.

// if the result is fixed to true. Then fix a==b.
// if the result is fixed to false, there is a single unspecied value, and all the rest are the same. Fix it to the opposite.

// if a==b then fix the result to true.
// if a!=b then fix the result to false.
Result bvEqualsBothWays(FixedBits& a, FixedBits& b, FixedBits& output)
{
	assert(a.getWidth() == b.getWidth());
	assert(1 == output.getWidth());

	const int childWidth = a.getWidth();

	Result r = NO_CHANGE;

	bool allSame = true;
	bool definatelyFalse = false;

	for (int i = 0; i < childWidth; i++)
	{
		// if both fixed
		if (a.isFixed(i) && b.isFixed(i))
		{
			// And have different values.
			if (a.getValue(i) != b.getValue(i))
			{
				definatelyFalse = true;
			}
			else
			{
				allSame &= true;
				continue;
			}
		}
		allSame &= false;
	}

	if (definatelyFalse)
	{
		if (output.isFixed(0) && output.getValue(0))
		{
			return CONFLICT;
		}
		else if (!output.isFixed(0))
		{
			output.setFixed(0, true);
			output.setValue(0, false);
			r = CHANGED;
		}
	}
	else if (allSame)
	{
		if (output.isFixed(0) && !output.getValue(0))
		{
			return CONFLICT;
		}
		else if (!output.isFixed(0))
		{
			output.setFixed(0, true);
			output.setValue(0, true);
			r = CHANGED;
		}
	}

	if (output.isFixed(0) && output.getValue(0)) // all should be the same.
	{
		for (int i = 0; i < childWidth; i++)
		{
			if (a.isFixed(i) && b.isFixed(i))
			{
				if (a.getValue(i) != b.getValue(i))
				{
					return CONFLICT;
				}
			}
			else if (a.isFixed(i) != b.isFixed(i)) // both same but only one is fixed.
			{
				if (a.isFixed(i))
				{
					b.setFixed(i, true);
					b.setValue(i, a.getValue(i));
					r = CHANGED;
				}
				else
				{
					a.setFixed(i, true);
					a.setValue(i, b.getValue(i));
					r = CHANGED;
				}
			}
		}
	}

	// if the result is fixed to false, there is a single unspecied value, and all the rest are the same. Fix it to the opposite.
	if (output.isFixed(0) && !output.getValue(0))
	{
		int unknown = 0;

		for (int i = 0; i < childWidth; i++)
		{
			if (!a.isFixed(i))
				unknown++;
			if (!b.isFixed(i))
				unknown++;
			else if (a.isFixed(i) && b.isFixed(i) && a.getValue(i) != b.getValue(i))
			{
				unknown = 10; // hack, don't do the next loop.
				break;
			}
		}

		if (1 == unknown)
		{
			for (int i = 0; i < childWidth; i++)
			{
				if (!a.isFixed(i))
				{
					a.setFixed(i, true);
					a.setValue(i, !b.getValue(i));
					r = CHANGED;
				}
				if (!b.isFixed(i))
				{
					b.setFixed(i, true);
					b.setValue(i, !a.getValue(i));
					r = CHANGED;
				}
			}
		}
	}
	return r;
}

Result bvEqualsBothWays(vector<FixedBits*>& children, FixedBits& result)
{
	return bvEqualsBothWays(*(children[0]), *(children[1]), result);
}

Result bvZeroExtendBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	assert(children.size() ==2 );
	// The second argument is a junk size arugment.

	FixedBits& input = *children[0];
	const int inputBitWidth = input.getWidth();
	const int outputBitWidth = output.getWidth();

	Result result = makeEqual(input, output, 0, inputBitWidth);
	if (CONFLICT == result)
		return CONFLICT;

	// Fix all the topmost bits of the output to zero.
	for (int i = inputBitWidth; i < outputBitWidth; i++)
	{
		if (output.isFixed(i) && output.getValue(i))
			return CONFLICT; // set to one. Never right.
		else if (!output.isFixed(i))
		{
			output.setFixed(i, true);
			output.setValue(i, false);
			result = CHANGED;
		}
	}
	return result;
}

Result bvSignExtendBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	assert(children.size() ==2 );
	// The second argument is a junk size arugment.

	FixedBits& input = *children[0];
	const int inputBitWidth = input.getWidth();
	const int outputBitWidth = output.getWidth();
	assert(inputBitWidth <= outputBitWidth);

	Result result = makeEqual(input, output, 0, inputBitWidth);
	if (CONFLICT == result)
		return CONFLICT;

	// If any of the topmost bits of the output are fixed. Then they all should be.
	// They should all be fixed to the same value.
	bool found = false;
	bool setTo;
	for (int i = inputBitWidth - /**/1 /**/; i < outputBitWidth; i++)
	{
		if (output.isFixed(i))
		{
			setTo = output.getValue(i);
			found = true;
			break;
		}
	}

	if (found)
	{
		for (int i = inputBitWidth - 1; i < outputBitWidth; i++)
		{
			if (output.isFixed(i) && (output.getValue(i) != setTo))
				return CONFLICT; // if any are set to the wrong value! bad.
			else if (!output.isFixed(i))
			{
				output.setFixed(i, true);
				output.setValue(i, setTo);
				result = CHANGED;
			}
		}

		Result result2 = makeEqual(input, output, 0, inputBitWidth);
		if (CONFLICT == result2)
			return CONFLICT;

	}
	return result;
}

Result bvExtractBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	const int numberOfChildren = children.size();
	const int outputBitWidth = output.getWidth();

	Result result = NO_CHANGE;

	assert(3 == numberOfChildren);

	int top = children[1]->getUnsignedValue();
	int bottom = children[2]->getUnsignedValue();

	FixedBits& input = *(children[0]);

	assert(top >= bottom);
	assert(bottom >=0);
	assert(top - bottom + 1 == outputBitWidth);
	assert(top < input.getWidth());

	for (int outputPosition = 0; outputPosition < outputBitWidth; outputPosition++)
	{
		int inputPosition = outputPosition + bottom;

		if (input.isFixed(inputPosition) && output.isFixed(outputPosition))
			if (input.getValue(inputPosition) ^ output.getValue(outputPosition))
				return CONFLICT;

		if (input.isFixed(inputPosition) ^ output.isFixed(outputPosition))
		{
			if (input.isFixed(inputPosition))
			{
				output.setFixed(outputPosition, true);
				output.setValue(outputPosition, input.getValue(inputPosition));
				result = CHANGED;
			}
			else
			{
				input.setFixed(inputPosition, true);
				input.setValue(inputPosition, output.getValue(outputPosition));
				result = CHANGED;
			}
		}
	}

	//cerr << "extract[" << top << ":" << bottom << "]" << input << "=" << output<< endl;

	return result;
}

// UMINUS, is NEG followed by +1
Result bvUnaryMinusBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	assert(children.size() == 1);
	const int bitWidth = children[0]->getWidth();

	// If it's only one bit. This will be negative one.
	FixedBits one(bitWidth, false);
	one.fixToZero();
	one.setFixed(0, true);
	one.setValue(0, true);

	FixedBits notted(bitWidth, false);

	vector<FixedBits*> args;
	args.push_back(&notted);
	args.push_back(&one);

	Result result = NO_CHANGE;
	while (true) // until it fixed points
	{
		FixedBits initialNot(notted);
		FixedBits initialIn(*children[0]);
		FixedBits initialOut(output);

		result = bvNotBothWays(*children[0], notted);
		if (CONFLICT == result)
			return CONFLICT;

		result = bvAddBothWays(args, output);
		if (CONFLICT == result)
			return CONFLICT;

		if (FixedBits::equals(initialNot, notted) && FixedBits::equals(initialIn, *children[0]) && FixedBits::equals(initialOut, output))
			break;
	}

	return NOT_IMPLEMENTED; // don't set the status properly yet..
}

Result bvConcatBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	Result r = NO_CHANGE;
	const int numberOfChildren = children.size();
	int current = 0;
	for (int i = numberOfChildren - 1; i >= 0; i--) // least significant is last.

	{
		FixedBits& child = *children[i];
		for (int j = 0; j < child.getWidth(); j++)
		{
			// values are different. Bad.
			if (output.isFixed(current) && child.isFixed(j) && (output.getValue(current) != child.getValue(j)))
				return CONFLICT;

			if (output.isFixed(current) && !child.isFixed(j))
			{
				// only output is fixed.
				child.setFixed(j, true);
				child.setValue(j, output.getValue(current));
				r = CHANGED;
			}
			else if (!output.isFixed(current) && child.isFixed(j))
			{
				// only input is fixed.
				output.setFixed(current, true);
				output.setValue(current, child.getValue(j));
				r = CHANGED;
			}
			current++;
		}
	}
	return r;
}

// If the guard is fixed, make equal the appropriate input and output.
// If one input can not possibly be the output. Then set the guard to make it the other one.
// If both values are the same. Set the output to that value.
Result bvITEBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	Result result = NO_CHANGE;

	assert(3 == children.size());
	const int bitWidth = output.getWidth();
	FixedBits& guard = *children[0];
	FixedBits& c1 = *children[1];
	FixedBits& c2 = *children[2];

	assert(c1.getWidth() == c2.getWidth());
	assert(output.getWidth() == c2.getWidth());

	if (guard.isFixed(0) && guard.getValue(0))
	{ // guard fixed to true. So make (first arg == output)
		result = makeEqual(output, c1, 0, bitWidth);
		if (CONFLICT == result)
			return CONFLICT;

	}
	else if (guard.isFixed(0) && !guard.getValue(0))
	{
		result = makeEqual(output, c2, 0, bitWidth);
		if (CONFLICT == result)
			return CONFLICT;

	}
	else
	{
		for (int i = 0; i < bitWidth; i++)
		{
			if (c1.isFixed(i) && c2.isFixed(i) && (c1.getValue(i) == c2.getValue(i)))
			{

				if (output.isFixed(i) && (output.getValue(i) != c1.getValue(i)))
					return CONFLICT;

				if (!output.isFixed(i))
				{
					output.setFixed(i, true);
					output.setValue(i, c1.getValue(i));
					result = CHANGED;
				}
			}
		}
	}

	bool changed = false;
	if (CHANGED == result)
		changed = true;

	for (int i = 0; i < bitWidth; i++)
	{
		if (output.isFixed(i))
		{
			if (c1.isFixed(i) && (c1.getValue(i) != output.getValue(i)))
			{
				//c1 is fixed to a value that's not the same as the output.
				if (!guard.isFixed(0))
				{
					guard.setFixed(0, true);
					guard.setValue(0, false);
					result = bvITEBothWays(children, output);
					if (CONFLICT == result)
						return CONFLICT;
					changed = true;
				}
				else if (guard.getValue(0))
					return CONFLICT;
			}

			if (c2.isFixed(i) && (c2.getValue(i) != output.getValue(i)))
			{
				//c2 is fixed to a value that's not the same as the output.
				if (!guard.isFixed(0))
				{
					guard.setFixed(0, true);
					guard.setValue(0, true);
					result = bvITEBothWays(children, output);
					if (CONFLICT == result)
						return CONFLICT;
					changed = true;

				}
				else if (!guard.getValue(0))
					return CONFLICT;
			}
		}
	}

	if (result == CONFLICT)
		return CONFLICT;
	if (changed)
		return CHANGED;

	return result;
}

}

}
<commit_msg>Slightly speed up the equals propagator.<commit_after>#include "ConstantBitP_TransferFunctions.h"
#include "ConstantBitP_Utility.h"

namespace simplifier
{
namespace constantBitP
{

namespace BEEV
{
typedef unsigned int * CBV;
}

// Misc (easy) transfer functions.
// Trevor Hansen. BSD License.

// if the result is fixed to true. Then fix a==b.
// if the result is fixed to false, there is a single unspecied value, and all the rest are the same. Fix it to the opposite.

// if a==b then fix the result to true.
// if a!=b then fix the result to false.
Result bvEqualsBothWays(FixedBits& a, FixedBits& b, FixedBits& output)
{
	assert(a.getWidth() == b.getWidth());
	assert(1 == output.getWidth());

	const int childWidth = a.getWidth();

	Result r = NO_CHANGE;

	bool allSame = true;
	bool definatelyFalse = false;

	for (int i = 0; i < childWidth; i++)
	{
		// if both fixed
		if (a.isFixed(i) && b.isFixed(i))
		{
			// And have different values.
			if (a.getValue(i) != b.getValue(i))
			{
				definatelyFalse = true;
				break;
			}
			else
			{
				allSame &= true;
				continue;
			}
		}
		allSame &= false;
	}

	if (definatelyFalse)
	{
		if (output.isFixed(0) && output.getValue(0))
		{
			return CONFLICT;
		}
		else if (!output.isFixed(0))
		{
			output.setFixed(0, true);
			output.setValue(0, false);
			r = CHANGED;
		}
	}
	else if (allSame)
	{
		if (output.isFixed(0) && !output.getValue(0))
		{
			return CONFLICT;
		}
		else if (!output.isFixed(0))
		{
			output.setFixed(0, true);
			output.setValue(0, true);
			r = CHANGED;
		}
	}

	if (output.isFixed(0) && output.getValue(0)) // all should be the same.
	{
		for (int i = 0; i < childWidth; i++)
		{
			if (a.isFixed(i) && b.isFixed(i))
			{
				if (a.getValue(i) != b.getValue(i))
				{
					return CONFLICT;
				}
			}
			else if (a.isFixed(i) != b.isFixed(i)) // both same but only one is fixed.
			{
				if (a.isFixed(i))
				{
					b.setFixed(i, true);
					b.setValue(i, a.getValue(i));
					r = CHANGED;
				}
				else
				{
					a.setFixed(i, true);
					a.setValue(i, b.getValue(i));
					r = CHANGED;
				}
			}
		}
	}

	// if the result is fixed to false, there is a single unspecied value, and all the rest are the same. Fix it to the opposite.
	if (output.isFixed(0) && !output.getValue(0))
	{
		int unknown = 0;

		for (int i = 0; i < childWidth && unknown < 2; i++)
		{
			if (!a.isFixed(i))
				unknown++;
			if (!b.isFixed(i))
				unknown++;
			else if (a.isFixed(i) && b.isFixed(i) && a.getValue(i) != b.getValue(i))
			{
				unknown = 10; // hack, don't do the next loop.
				break;
			}
		}

		if (1 == unknown)
		{
			for (int i = 0; i < childWidth; i++)
			{
				if (!a.isFixed(i))
				{
					a.setFixed(i, true);
					a.setValue(i, !b.getValue(i));
					r = CHANGED;
				}
				if (!b.isFixed(i))
				{
					b.setFixed(i, true);
					b.setValue(i, !a.getValue(i));
					r = CHANGED;
				}
			}
		}
	}
	return r;
}

Result bvEqualsBothWays(vector<FixedBits*>& children, FixedBits& result)
{
	return bvEqualsBothWays(*(children[0]), *(children[1]), result);
}

Result bvZeroExtendBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	assert(children.size() ==2 );
	// The second argument is a junk size arugment.

	FixedBits& input = *children[0];
	const int inputBitWidth = input.getWidth();
	const int outputBitWidth = output.getWidth();

	Result result = makeEqual(input, output, 0, inputBitWidth);
	if (CONFLICT == result)
		return CONFLICT;

	// Fix all the topmost bits of the output to zero.
	for (int i = inputBitWidth; i < outputBitWidth; i++)
	{
		if (output.isFixed(i) && output.getValue(i))
			return CONFLICT; // set to one. Never right.
		else if (!output.isFixed(i))
		{
			output.setFixed(i, true);
			output.setValue(i, false);
			result = CHANGED;
		}
	}
	return result;
}

Result bvSignExtendBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	assert(children.size() ==2 );
	// The second argument is a junk size arugment.

	FixedBits& input = *children[0];
	const int inputBitWidth = input.getWidth();
	const int outputBitWidth = output.getWidth();
	assert(inputBitWidth <= outputBitWidth);

	Result result = makeEqual(input, output, 0, inputBitWidth);
	if (CONFLICT == result)
		return CONFLICT;

	// If any of the topmost bits of the output are fixed. Then they all should be.
	// They should all be fixed to the same value.
	bool found = false;
	bool setTo;
	for (int i = inputBitWidth - /**/1 /**/; i < outputBitWidth; i++)
	{
		if (output.isFixed(i))
		{
			setTo = output.getValue(i);
			found = true;
			break;
		}
	}

	if (found)
	{
		for (int i = inputBitWidth - 1; i < outputBitWidth; i++)
		{
			if (output.isFixed(i) && (output.getValue(i) != setTo))
				return CONFLICT; // if any are set to the wrong value! bad.
			else if (!output.isFixed(i))
			{
				output.setFixed(i, true);
				output.setValue(i, setTo);
				result = CHANGED;
			}
		}

		Result result2 = makeEqual(input, output, 0, inputBitWidth);
		if (CONFLICT == result2)
			return CONFLICT;

	}
	return result;
}

Result bvExtractBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	const int numberOfChildren = children.size();
	const int outputBitWidth = output.getWidth();

	Result result = NO_CHANGE;

	assert(3 == numberOfChildren);

	int top = children[1]->getUnsignedValue();
	int bottom = children[2]->getUnsignedValue();

	FixedBits& input = *(children[0]);

	assert(top >= bottom);
	assert(bottom >=0);
	assert(top - bottom + 1 == outputBitWidth);
	assert(top < input.getWidth());

	for (int outputPosition = 0; outputPosition < outputBitWidth; outputPosition++)
	{
		int inputPosition = outputPosition + bottom;

		if (input.isFixed(inputPosition) && output.isFixed(outputPosition))
			if (input.getValue(inputPosition) ^ output.getValue(outputPosition))
				return CONFLICT;

		if (input.isFixed(inputPosition) ^ output.isFixed(outputPosition))
		{
			if (input.isFixed(inputPosition))
			{
				output.setFixed(outputPosition, true);
				output.setValue(outputPosition, input.getValue(inputPosition));
				result = CHANGED;
			}
			else
			{
				input.setFixed(inputPosition, true);
				input.setValue(inputPosition, output.getValue(outputPosition));
				result = CHANGED;
			}
		}
	}

	//cerr << "extract[" << top << ":" << bottom << "]" << input << "=" << output<< endl;

	return result;
}

// UMINUS, is NEG followed by +1
Result bvUnaryMinusBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	assert(children.size() == 1);
	const int bitWidth = children[0]->getWidth();

	// If it's only one bit. This will be negative one.
	FixedBits one(bitWidth, false);
	one.fixToZero();
	one.setFixed(0, true);
	one.setValue(0, true);

	FixedBits notted(bitWidth, false);

	vector<FixedBits*> args;
	args.push_back(&notted);
	args.push_back(&one);

	Result result = NO_CHANGE;
	while (true) // until it fixed points
	{
		FixedBits initialNot(notted);
		FixedBits initialIn(*children[0]);
		FixedBits initialOut(output);

		result = bvNotBothWays(*children[0], notted);
		if (CONFLICT == result)
			return CONFLICT;

		result = bvAddBothWays(args, output);
		if (CONFLICT == result)
			return CONFLICT;

		if (FixedBits::equals(initialNot, notted) && FixedBits::equals(initialIn, *children[0]) && FixedBits::equals(initialOut, output))
			break;
	}

	return NOT_IMPLEMENTED; // don't set the status properly yet..
}

Result bvConcatBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	Result r = NO_CHANGE;
	const int numberOfChildren = children.size();
	int current = 0;
	for (int i = numberOfChildren - 1; i >= 0; i--) // least significant is last.

	{
		FixedBits& child = *children[i];
		for (int j = 0; j < child.getWidth(); j++)
		{
			// values are different. Bad.
			if (output.isFixed(current) && child.isFixed(j) && (output.getValue(current) != child.getValue(j)))
				return CONFLICT;

			if (output.isFixed(current) && !child.isFixed(j))
			{
				// only output is fixed.
				child.setFixed(j, true);
				child.setValue(j, output.getValue(current));
				r = CHANGED;
			}
			else if (!output.isFixed(current) && child.isFixed(j))
			{
				// only input is fixed.
				output.setFixed(current, true);
				output.setValue(current, child.getValue(j));
				r = CHANGED;
			}
			current++;
		}
	}
	return r;
}

// If the guard is fixed, make equal the appropriate input and output.
// If one input can not possibly be the output. Then set the guard to make it the other one.
// If both values are the same. Set the output to that value.
Result bvITEBothWays(vector<FixedBits*>& children, FixedBits& output)
{
	Result result = NO_CHANGE;

	assert(3 == children.size());
	const int bitWidth = output.getWidth();
	FixedBits& guard = *children[0];
	FixedBits& c1 = *children[1];
	FixedBits& c2 = *children[2];

	assert(c1.getWidth() == c2.getWidth());
	assert(output.getWidth() == c2.getWidth());

	if (guard.isFixed(0) && guard.getValue(0))
	{ // guard fixed to true. So make (first arg == output)
		result = makeEqual(output, c1, 0, bitWidth);
		if (CONFLICT == result)
			return CONFLICT;

	}
	else if (guard.isFixed(0) && !guard.getValue(0))
	{
		result = makeEqual(output, c2, 0, bitWidth);
		if (CONFLICT == result)
			return CONFLICT;

	}
	else
	{
		for (int i = 0; i < bitWidth; i++)
		{
			if (c1.isFixed(i) && c2.isFixed(i) && (c1.getValue(i) == c2.getValue(i)))
			{

				if (output.isFixed(i) && (output.getValue(i) != c1.getValue(i)))
					return CONFLICT;

				if (!output.isFixed(i))
				{
					output.setFixed(i, true);
					output.setValue(i, c1.getValue(i));
					result = CHANGED;
				}
			}
		}
	}

	bool changed = false;
	if (CHANGED == result)
		changed = true;

	for (int i = 0; i < bitWidth; i++)
	{
		if (output.isFixed(i))
		{
			if (c1.isFixed(i) && (c1.getValue(i) != output.getValue(i)))
			{
				//c1 is fixed to a value that's not the same as the output.
				if (!guard.isFixed(0))
				{
					guard.setFixed(0, true);
					guard.setValue(0, false);
					result = bvITEBothWays(children, output);
					if (CONFLICT == result)
						return CONFLICT;
					changed = true;
				}
				else if (guard.getValue(0))
					return CONFLICT;
			}

			if (c2.isFixed(i) && (c2.getValue(i) != output.getValue(i)))
			{
				//c2 is fixed to a value that's not the same as the output.
				if (!guard.isFixed(0))
				{
					guard.setFixed(0, true);
					guard.setValue(0, true);
					result = bvITEBothWays(children, output);
					if (CONFLICT == result)
						return CONFLICT;
					changed = true;

				}
				else if (!guard.getValue(0))
					return CONFLICT;
			}
		}
	}

	if (result == CONFLICT)
		return CONFLICT;
	if (changed)
		return CHANGED;

	return result;
}

}

}
<|endoftext|>


<commit_before>#ifndef FROMEVENT_HPP
#define FROMEVENT_HPP

#include "FlagStatus.hpp"
#include "IOLogWrapper.hpp"
#include "List.hpp"
#include "Params.hpp"
#include "Vector.hpp"
#include "bridge.h"

namespace org_pqrs_Karabiner {
class FromEvent;

class PressingFromEvents final {
  friend class FromEvent;

public:
  class Item final : public List::Item {
  public:
    Item(const FromEvent* p) : fromEvent_(p) {}
    ~Item(void) {}

    const FromEvent* getFromEvent(void) const { return fromEvent_; }

  private:
    const FromEvent* fromEvent_;
  };

  static Item* find(const FromEvent* p) {
    for (Item* q = static_cast<Item*>(list_.safe_front()); q; q = static_cast<Item*>(q->getnext())) {
      if (q->getFromEvent() == p) {
        return q;
      }
    }
    return nullptr;
  }

  static void clear(void) {
    list_.clear();
  }

  static void push_back(const FromEvent* p) {
    list_.push_back(new Item(p));
  }

  static bool erase(const FromEvent* p) {
    Item* q = find(p);
    if (q) {
      list_.erase_and_delete(q);
      return true;
    }
    return false;
  }

  static void erase_all(const FromEvent* p) {
    for (;;) {
      if (!erase(p)) {
        break;
      }
    }
  }

private:
  static List list_;
};

class FromEvent final {
public:
  class Type final {
  public:
    enum Value {
      NONE,
      KEY,
      CONSUMER_KEY, // Mute, VolumeIncrement, VolumeDecrement, etcetc.
      POINTING_BUTTON,
    };
  };

  FromEvent(void) : type_(Type::NONE) {}
  explicit FromEvent(KeyCode v) : type_(Type::KEY), key_(v) {}
  explicit FromEvent(ConsumerKeyCode v) : type_(Type::CONSUMER_KEY), consumer_(v) {}
  explicit FromEvent(PointingButton v) : type_(Type::POINTING_BUTTON), button_(v) {}

  explicit FromEvent(const Params_Base& paramsBase) {
    type_ = Type::NONE;

    {
      auto p = paramsBase.get_Params_KeyboardEventCallBack();
      if (p) {
        type_ = Type::KEY;
        key_ = p->key;
        return;
      }
    }
    {
      auto p = paramsBase.get_Params_KeyboardSpecialEventCallback();
      if (p) {
        type_ = Type::CONSUMER_KEY;
        consumer_ = p->key;
        return;
      }
    }
    {
      auto p = paramsBase.get_Params_RelativePointerEventCallback();
      if (p) {
        type_ = Type::POINTING_BUTTON;
        button_ = p->ex_button;
        return;
      }
    }
  }

  FromEvent(AddDataType datatype, AddValue v) {
    switch (datatype) {
    case BRIDGE_DATATYPE_KEYCODE:
      type_ = Type::KEY;
      key_ = KeyCode(v);
      break;
    case BRIDGE_DATATYPE_CONSUMERKEYCODE:
      type_ = Type::CONSUMER_KEY;
      consumer_ = ConsumerKeyCode(v);
      break;
    case BRIDGE_DATATYPE_POINTINGBUTTON:
      type_ = Type::POINTING_BUTTON;
      button_ = PointingButton(v);
      break;
    default:
      IOLOG_ERROR("Unknown datatype: %u\n", static_cast<unsigned int>(datatype));
      type_ = Type::NONE;
      break;
    }
  }

  ~FromEvent(void) { PressingFromEvents::erase_all(this); }

  Type::Value getType(void) const { return type_; }

  // Return whether pressing state is changed.
  bool changePressingState(const Params_Base& paramsBase,
                           const FlagStatus& currentFlags,
                           const Vector_ModifierFlag& fromFlags);

  bool isPressing(void) const { return PressingFromEvents::find(this); }

  // Primitive functions:
  // These functions do not treat Flags.
  // Use changePressingState in general.
  bool isTargetEvent(const Params_Base& paramsBase) const;
  bool isTargetDownEvent(const Params_Base& paramsBase) const;
  bool isTargetUpEvent(const Params_Base& paramsBase) const;

  // Get ModifierFlag from KeyCode.
  ModifierFlag getModifierFlag(void) const {
    if (type_ != Type::KEY) return ModifierFlag::ZERO;
    return key_.getModifierFlag();
  }
  PointingButton getPointingButton(void) const {
    if (type_ != Type::POINTING_BUTTON) return PointingButton::NONE;
    return button_;
  }

private:
  bool isTargetEvent(bool& isDown, const Params_Base& paramsBase) const;

  // Do not store Flags in FromEvent because SimultaneousKeyPresses uses multiple FromEvents.

  Type::Value type_;
  KeyCode key_;
  ConsumerKeyCode consumer_;
  PointingButton button_;
};

DECLARE_VECTOR(FromEvent);
}

#endif
<commit_msg>add comment<commit_after>#ifndef FROMEVENT_HPP
#define FROMEVENT_HPP

#include "FlagStatus.hpp"
#include "IOLogWrapper.hpp"
#include "List.hpp"
#include "Params.hpp"
#include "Vector.hpp"
#include "bridge.h"

namespace org_pqrs_Karabiner {
class FromEvent;

class PressingFromEvents final {
  friend class FromEvent;

public:
  class Item final : public List::Item {
  public:
    Item(const FromEvent* p) : fromEvent_(p) {}
    ~Item(void) {}

    const FromEvent* getFromEvent(void) const { return fromEvent_; }

  private:
    const FromEvent* fromEvent_;
  };

  static Item* find(const FromEvent* p) {
    for (Item* q = static_cast<Item*>(list_.safe_front()); q; q = static_cast<Item*>(q->getnext())) {
      if (q->getFromEvent() == p) {
        return q;
      }
    }
    return nullptr;
  }

  static void clear(void) {
    list_.clear();
  }

  static void push_back(const FromEvent* p) {
    list_.push_back(new Item(p));
  }

  static bool erase(const FromEvent* p) {
    Item* q = find(p);
    if (q) {
      list_.erase_and_delete(q);
      return true;
    }
    return false;
  }

  static void erase_all(const FromEvent* p) {
    for (;;) {
      if (!erase(p)) {
        break;
      }
    }
  }

private:
  static List list_;
};

class FromEvent final {
public:
  class Type final {
  public:
    enum Value {
      NONE,
      KEY,
      CONSUMER_KEY, // Mute, VolumeIncrement, VolumeDecrement, etcetc.
      POINTING_BUTTON,
    };
  };

  FromEvent(void) : type_(Type::NONE) {}
  explicit FromEvent(KeyCode v) : type_(Type::KEY), key_(v) {}
  explicit FromEvent(ConsumerKeyCode v) : type_(Type::CONSUMER_KEY), consumer_(v) {}
  explicit FromEvent(PointingButton v) : type_(Type::POINTING_BUTTON), button_(v) {}

  explicit FromEvent(const Params_Base& paramsBase) {
    type_ = Type::NONE;

    {
      auto p = paramsBase.get_Params_KeyboardEventCallBack();
      if (p) {
        type_ = Type::KEY;
        key_ = p->key;
        return;
      }
    }
    {
      auto p = paramsBase.get_Params_KeyboardSpecialEventCallback();
      if (p) {
        type_ = Type::CONSUMER_KEY;
        consumer_ = p->key;
        return;
      }
    }
    {
      auto p = paramsBase.get_Params_RelativePointerEventCallback();
      if (p) {
        type_ = Type::POINTING_BUTTON;
        button_ = p->ex_button;
        return;
      }
    }
  }

  FromEvent(AddDataType datatype, AddValue v) {
    switch (datatype) {
    case BRIDGE_DATATYPE_KEYCODE:
      type_ = Type::KEY;
      key_ = KeyCode(v);
      break;
    case BRIDGE_DATATYPE_CONSUMERKEYCODE:
      type_ = Type::CONSUMER_KEY;
      consumer_ = ConsumerKeyCode(v);
      break;
    case BRIDGE_DATATYPE_POINTINGBUTTON:
      type_ = Type::POINTING_BUTTON;
      button_ = PointingButton(v);
      break;
    default:
      IOLOG_ERROR("Unknown datatype: %u\n", static_cast<unsigned int>(datatype));
      type_ = Type::NONE;
      break;
    }
  }

  ~FromEvent(void) { PressingFromEvents::erase_all(this); }

  Type::Value getType(void) const { return type_; }

  // Return whether pressing state is changed.
  bool changePressingState(const Params_Base& paramsBase,
                           const FlagStatus& currentFlags,
                           const Vector_ModifierFlag& fromFlags);

  // Caution:
  // `isPressing` may return true at key up event if you connected multiple keyboards and pressing the same key.
  //
  // For example,
  //  1. Press the return key in keyboard1.   (isPressing == true)
  //  2. Press the return key in keyboard2.   (isPressing == true)
  //  3. Release the return key in keyboard1. (isPressing == true)
  //  4. Release the return key in keyboard2. (isPressing == false)
  //
  // So you must not use `isPressing` to detect the input event is key down or key up.
  // (You should use `Params_Base::iskeydown` to determine key down or key up.)
  bool isPressing(void) const { return PressingFromEvents::find(this); }

  // Primitive functions:
  // These functions do not treat Flags.
  // Use changePressingState in general.
  bool isTargetEvent(const Params_Base& paramsBase) const;
  bool isTargetDownEvent(const Params_Base& paramsBase) const;
  bool isTargetUpEvent(const Params_Base& paramsBase) const;

  // Get ModifierFlag from KeyCode.
  ModifierFlag getModifierFlag(void) const {
    if (type_ != Type::KEY) return ModifierFlag::ZERO;
    return key_.getModifierFlag();
  }
  PointingButton getPointingButton(void) const {
    if (type_ != Type::POINTING_BUTTON) return PointingButton::NONE;
    return button_;
  }

private:
  bool isTargetEvent(bool& isDown, const Params_Base& paramsBase) const;

  // Do not store Flags in FromEvent because SimultaneousKeyPresses uses multiple FromEvents.

  Type::Value type_;
  KeyCode key_;
  ConsumerKeyCode consumer_;
  PointingButton button_;
};

DECLARE_VECTOR(FromEvent);
}

#endif
<|endoftext|>


<commit_before>
// $Id: Cache.cpp 3456 2013-06-14 02:11:13Z jiaying $

/*
 * The Software is made available solely for use according to the License Agreement. Any reproduction
 * or redistribution of the Software not in accordance with the License Agreement is expressly prohibited
 * by law, and may result in severe civil and criminal penalties. Violators will be prosecuted to the
 * maximum extent possible.
 *
 * THE SOFTWARE IS WARRANTED, IF AT ALL, ONLY ACCORDING TO THE TERMS OF THE LICENSE AGREEMENT. EXCEPT
 * AS WARRANTED IN THE LICENSE AGREEMENT, SRCH2 INC. HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS WITH
 * REGARD TO THE SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT.  IN NO EVENT SHALL SRCH2 INC. BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF SOFTWARE.

 * Copyright © 2010 SRCH2 Inc. All rights reserved
 */

#include "CacheManager.h"
#include "util/Assert.h"
#include "util/Logger.h"
#include "operation/physical_plan/PhysicalPlan.h"
#include <string>
#include <map>
#include <stddef.h>

#include <iostream>
#include <sstream>

using std::vector;
using std::map;

namespace srch2
{
namespace instantsearch
{

bool PhysicalOperatorsCache::getPhysicalOperatorsInfo(string & key,  boost::shared_ptr<PhysicalOperatorCacheObject> & in){
	return this->cacheContainer->get(key , in);
}
void PhysicalOperatorsCache::setPhysicalOperatosInfo(string & key , boost::shared_ptr<PhysicalOperatorCacheObject> object){
	this->cacheContainer->put(key , object);
}
int PhysicalOperatorsCache::clear(){
	return this->cacheContainer->clear();
}

int ActiveNodesCache::findLongestPrefixActiveNodes(Term *term, boost::shared_ptr<PrefixActiveNodeSet> &in){

	/*// find the longest prefix with active nodes in the cache
	unsigned termThreshold = term->getThreshold();
	string *keyword = term->getKeyword();
	for (int i = keyword->size(); i >= 2; i --)
	{
		string prefix = keyword->substr(0, i);
		std::string exactOrFuzzy =  termThreshold == 0?"0":"1";
		string key = prefix + "$" + exactOrFuzzy;
		// Cache key is : keyword+0 (for exact) or keyword+1 (for fuzzy)
		// for example: terminator => "terminator$0"
		//         and  terminator~0.5 => "terminator$1"
		boost::shared_ptr<PrefixActiveNodeSet> cacheHit;
		if(this->cacheContainer->get(key , cacheHit) == true && cacheHit->getEditDistanceThreshold() >= termThreshold){
			in = cacheHit;
			return 1;
		}
	}*/
    // no prefix has a cached PrefixActiveNodeSet
	return 0;

}

int ActiveNodesCache::setPrefixActiveNodeSet(boost::shared_ptr<PrefixActiveNodeSet> &prefixActiveNodeSet){
	vector<CharType> *prefix = prefixActiveNodeSet->getPrefix();
	std::stringstream ss ;
	ss << prefixActiveNodeSet->getEditDistanceThreshold();
	std::string exactOrFuzzy = ss.str();
//	std::string exactOrFuzzy =  prefixActiveNodeSet->getEditDistanceThreshold() == 0?"0":"1";
	string key = getUtf8String(*prefix) + "$" + exactOrFuzzy;
	this->cacheContainer->put(key , prefixActiveNodeSet);
	return 1;
}
int ActiveNodesCache::clear(){
	return this->cacheContainer->clear();
}

ActiveNodesCache * CacheManager::getActiveNodesCache(){
	return this->aCache;
}

QueryResultsCache * CacheManager::getQueryResultsCache(){
	return this->qCache;
}

PhysicalOperatorsCache * CacheManager::getPhysicalOperatorsCache(){
	return this->pCache;
}

PhysicalPlanRecordItemFactory * CacheManager::getPhysicalPlanRecordItemFactory(){
	return this->physicalPlanRecordItemFactory;
}

bool QueryResultsCache::getQueryResults(string & key, boost::shared_ptr<QueryResultsCacheEntry> & in){
	return this->cacheContainer->get(key , in);
}
void QueryResultsCache::setQueryResults(string & key , boost::shared_ptr<QueryResultsCacheEntry> object){
	this->cacheContainer->put(key , object);
}
int QueryResultsCache::clear(){
	return this->cacheContainer->clear();
}

int CacheManager::clear(){
	return this->aCache->clear() && this->qCache->clear() && this->pCache->clear() && this->physicalPlanRecordItemFactory->clear();
}

}}
<commit_msg>Active node cache was disabled mistakenly. Now enabled again.<commit_after>
// $Id: Cache.cpp 3456 2013-06-14 02:11:13Z jiaying $

/*
 * The Software is made available solely for use according to the License Agreement. Any reproduction
 * or redistribution of the Software not in accordance with the License Agreement is expressly prohibited
 * by law, and may result in severe civil and criminal penalties. Violators will be prosecuted to the
 * maximum extent possible.
 *
 * THE SOFTWARE IS WARRANTED, IF AT ALL, ONLY ACCORDING TO THE TERMS OF THE LICENSE AGREEMENT. EXCEPT
 * AS WARRANTED IN THE LICENSE AGREEMENT, SRCH2 INC. HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS WITH
 * REGARD TO THE SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT.  IN NO EVENT SHALL SRCH2 INC. BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF SOFTWARE.

 * Copyright © 2010 SRCH2 Inc. All rights reserved
 */

#include "CacheManager.h"
#include "util/Assert.h"
#include "util/Logger.h"
#include "operation/physical_plan/PhysicalPlan.h"
#include <string>
#include <map>
#include <stddef.h>

#include <iostream>
#include <sstream>

using std::vector;
using std::map;

namespace srch2
{
namespace instantsearch
{

bool PhysicalOperatorsCache::getPhysicalOperatorsInfo(string & key,  boost::shared_ptr<PhysicalOperatorCacheObject> & in){
	return this->cacheContainer->get(key , in);
}
void PhysicalOperatorsCache::setPhysicalOperatosInfo(string & key , boost::shared_ptr<PhysicalOperatorCacheObject> object){
	this->cacheContainer->put(key , object);
}
int PhysicalOperatorsCache::clear(){
	return this->cacheContainer->clear();
}

int ActiveNodesCache::findLongestPrefixActiveNodes(Term *term, boost::shared_ptr<PrefixActiveNodeSet> &in){

	// find the longest prefix with active nodes in the cache
	unsigned termThreshold = term->getThreshold();
	string *keyword = term->getKeyword();
	for (int i = keyword->size(); i >= 2; i --)
	{
		string prefix = keyword->substr(0, i);
		std::string exactOrFuzzy =  termThreshold == 0?"0":"1";
		string key = prefix + "$" + exactOrFuzzy;
		// Cache key is : keyword+0 (for exact) or keyword+1 (for fuzzy)
		// for example: terminator => "terminator$0"
		//         and  terminator~0.5 => "terminator$1"
		boost::shared_ptr<PrefixActiveNodeSet> cacheHit;
		if(this->cacheContainer->get(key , cacheHit) == true && cacheHit->getEditDistanceThreshold() >= termThreshold){
			in = cacheHit;
			return 1;
		}
	}
    // no prefix has a cached PrefixActiveNodeSet
	return 0;

}

int ActiveNodesCache::setPrefixActiveNodeSet(boost::shared_ptr<PrefixActiveNodeSet> &prefixActiveNodeSet){
	vector<CharType> *prefix = prefixActiveNodeSet->getPrefix();
	std::stringstream ss ;
	ss << prefixActiveNodeSet->getEditDistanceThreshold();
	std::string exactOrFuzzy = ss.str();
//	std::string exactOrFuzzy =  prefixActiveNodeSet->getEditDistanceThreshold() == 0?"0":"1";
	string key = getUtf8String(*prefix) + "$" + exactOrFuzzy;
	this->cacheContainer->put(key , prefixActiveNodeSet);
	return 1;
}
int ActiveNodesCache::clear(){
	return this->cacheContainer->clear();
}

ActiveNodesCache * CacheManager::getActiveNodesCache(){
	return this->aCache;
}

QueryResultsCache * CacheManager::getQueryResultsCache(){
	return this->qCache;
}

PhysicalOperatorsCache * CacheManager::getPhysicalOperatorsCache(){
	return this->pCache;
}

PhysicalPlanRecordItemFactory * CacheManager::getPhysicalPlanRecordItemFactory(){
	return this->physicalPlanRecordItemFactory;
}

bool QueryResultsCache::getQueryResults(string & key, boost::shared_ptr<QueryResultsCacheEntry> & in){
	return this->cacheContainer->get(key , in);
}
void QueryResultsCache::setQueryResults(string & key , boost::shared_ptr<QueryResultsCacheEntry> object){
	this->cacheContainer->put(key , object);
}
int QueryResultsCache::clear(){
	return this->cacheContainer->clear();
}

int CacheManager::clear(){
	return this->aCache->clear() && this->qCache->clear() && this->pCache->clear() && this->physicalPlanRecordItemFactory->clear();
}

}}
<|endoftext|>