<commit_before>#include "caffe2/operators/transpose_op.h"
#ifdef CAFFE2_USE_HPTT

#include <hptt.h>

namespace caffe2 {

namespace {
template <typename T>
bool tryRunWithHPTT(const std::vector<int>& axes, const TensorCPU& input, TensorCPU* output) {
  if (!std::is_same<T, float>::value) {
    return false;
  }
  std::vector<int> axes_cm(axes.size());
  for (auto i = 0; i < axes.size(); ++i) {
    axes_cm[i] = axes.size() - axes[i] - 1;
  }
  std::vector<int> idims_cm(axes.size());
  std::vector<int> odims_cm(axes.size());
  for (auto i = 0; i < axes.size(); ++i) {
    odims_cm[i] = output->dim32(axes.size() - i - 1);
    idims_cm[i] = input.dim32(axes.size() - i - 1);
  }

  auto plan = hptt::create_plan(axes_cm.data(),
                                axes.size(),
                                1.0,
                                input.template data<float>(),
                                idims_cm.data(),
                                nullptr,
                                0.0,
                                output->template mutable_data<float>(),
                                nullptr,
                                hptt::ESTIMATE,
                                1);
  if (!plan) {
    return false;
  }
  plan->execute();
  return true;
}
} // namespace

} // namespace caffe2
#endif

namespace caffe2 {

#define COMPILE_TIME_MAX_TRANSPOSE_DIMS 10

template <>
template <typename T>
bool TransposeOp<CPUContext>::DoRunWithType() {
  const auto& input = Input(0);
  auto* output = Output(0);

#ifdef CAFFE2_USE_HPTT
  if (tryRunWithHPTT<T>(axes_, input, output)) {
    return true;
  }
#endif

  int from_inds[COMPILE_TIME_MAX_TRANSPOSE_DIMS] = {0};
  size_t count = input.size();
  int num_axes = axes_.size();
  const T* from_data = input.template data<T>();
  T* to_data = output->template mutable_data<T>();
  auto in_dims = input.dims();
  auto out_dims = output->dims();

  // Measure amount of contiguous data we can copy at once
  TIndex blocksize = 1;
  int n_shared_idxs = 0;
  for (int i = num_axes - 1; i >= 0; --i) {
    if (axes_[i] == i) {
      blocksize *= new_dims_[i];
      ++n_shared_idxs;
    } else {
      break;
    }
  }

  if (num_axes < 2 || n_shared_idxs == num_axes) {
    memcpy(to_data, from_data, count * sizeof(T));
    return true;
  }

  int itr_axes = num_axes - n_shared_idxs;

  // Calculate strides
  TIndex stride_x[COMPILE_TIME_MAX_TRANSPOSE_DIMS] = {0};
  for (size_t i = 0; i < itr_axes; i++) {
    stride_x[i] = 1;
    for (size_t j = axes_[i] + 1; j < itr_axes; j++) {
      stride_x[i] *= in_dims[j];
    }
  }

  TIndex itr_idxs[COMPILE_TIME_MAX_TRANSPOSE_DIMS] = {0};

  // Branch here to avoid branching within the loop
  if (blocksize > 1) {
    for (size_t index = 0; index < (count / blocksize); index++) {
      TIndex from_index = 0;
      for (int i = 0; i < itr_axes; ++i) {
        from_index += stride_x[i] * itr_idxs[i];
      }

      memcpy(
          to_data + blocksize * index,
          from_data + blocksize * from_index,
          blocksize * sizeof(T));

      ++itr_idxs[itr_axes - 1];
      for (int i = itr_axes - 1; i >= 1; --i) {
        auto expected_dim = out_dims[i];
        if (itr_idxs[i] < expected_dim) {
          break;
        }
        itr_idxs[i] %= expected_dim;
        ++itr_idxs[i - 1];
      }
    }
  } else {
    for (size_t index = 0; index < count; index++) {
      TIndex from_index = 0;
      for (int i = 0; i < itr_axes; ++i) {
        from_index += stride_x[i] * itr_idxs[i];
      }

      *(to_data + index) = *(from_data + from_index);

      ++itr_idxs[itr_axes - 1];
      for (int i = itr_axes - 1; i >= 1; --i) {
        auto expected_dim = out_dims[i];
        if (itr_idxs[i] < expected_dim) {
          break;
        }
        itr_idxs[i] %= expected_dim;
        ++itr_idxs[i - 1];
      }
    }
  }

  return true;
}

REGISTER_CPU_OPERATOR(Transpose, TransposeOp<CPUContext>);

OPERATOR_SCHEMA(Transpose)
    .NumInputs(1)
    .NumOutputs(1)
    .TensorInferenceFunction([](
        const OperatorDef& def,
        const vector<TensorShape>& in) {
      ArgumentHelper helper(def);
      vector<int> axes = helper.GetRepeatedArgument<int>("axes");
      vector<TensorShape> out(1);
      out[0].set_data_type(in[0].data_type());

      if (axes.empty()) {
        for (auto axis = in [0].dims().rbegin(); axis != in[0].dims().rend();
             ++axis) {
          out[0].add_dims(*axis);
        }
      } else {
        auto tensor_size = in[0].dims().size();
        auto valid_axes =
            std::all_of(axes.begin(), axes.end(), [&tensor_size](int& axis) {
              return axis >= 0 && axis < tensor_size;
            });

        CAFFE_ENFORCE(valid_axes, "Axes argument passed in had invalid values");
        CAFFE_ENFORCE(
            axes.size() == tensor_size,
            "Axes argument passed in had the incorrect size");

        for (auto axis = axes.begin(); axis != axes.end(); ++axis) {
          out[0].add_dims(in[0].dims().Get(*axis));
        }
      }

      return out;
    })
    .SetDoc(R"DOC(
Transpose the input tensor similar to numpy.transpose. For example, when
axes=(1, 0, 2), given an input tensor of shape (1, 2, 3), the output shape
will be (2, 1, 3).
)DOC")
    .Arg(
        "axes",
        "A list of integers. By default, reverse the dimensions, "
        "otherwise permute the axes according to the values given.")
    .Input(0, "data", "An input tensor.")
    .Output(0, "transposed", "Transposed output.");

class GetTransposeGradient : public GradientMakerBase {
  using GradientMakerBase::GradientMakerBase;
  // We will create our own arguments.
  bool CopyArguments() const override {
    return false;
  }
  vector<OperatorDef> GetGradientDefs() override {
    auto ops = SingleGradientDef(
        "Transpose", "", vector<string>{GO(0)}, vector<string>{GI(0)});
    ops[0].mutable_arg()->CopyFrom(Def().arg());
    if (ArgumentHelper::HasArgument(Def(), "axes")) {
      // If axes is specified, we will need to figure out the inverse index.
      const Argument& old_axes = GetArgument(Def(), "axes");
      const int axes_size = old_axes.ints_size();
      Argument* new_arg = GetMutableArgument("axes", false, &ops[0]);
      for (int i = 0; i < axes_size; ++i) {
        new_arg->set_ints(old_axes.ints(i), i);
      }
    }
    return ops;
  }
};
REGISTER_GRADIENT(Transpose, GetTransposeGradient);
} // namespace caffe2
<commit_msg>HPTT<commit_after>#include "caffe2/operators/transpose_op.h"
#ifdef CAFFE2_USE_HPTT

#include <hptt.h>

namespace caffe2 {

namespace {
template <typename T>
bool tryRunWithHPTT(const std::vector<int>& axes, const TensorCPU& input, TensorCPU* output) {
  if (!std::is_same<T, float>::value) {
    return false;
  }
  std::vector<int> axes_cm(axes.size());
  std::vector<int> idims_cm(axes.size());

  // Convert row-major index to column major.
  auto cm = [&](int i) { return axes.size() - i - 1; };

  for (auto i = 0; i < axes.size(); ++i) {
    axes_cm[i] = cm(axes[cm(i)]);
    idims_cm[i] = input.dim32(cm(i));
  }

  auto plan = hptt::create_plan(axes_cm.data(),
                                axes.size(),
                                1.0,
                                input.template data<float>(),
                                idims_cm.data(),
                                nullptr,
                                0.0,
                                output->template mutable_data<float>(),
                                nullptr,
                                hptt::ESTIMATE,
                                1);
  if (!plan) {
    return false;
  }
  plan->execute();
  return true;
}
} // namespace

} // namespace caffe2
#endif

namespace caffe2 {

#define COMPILE_TIME_MAX_TRANSPOSE_DIMS 10

template <>
template <typename T>
bool TransposeOp<CPUContext>::DoRunWithType() {
  const auto& input = Input(0);
  auto* output = Output(0);

#ifdef CAFFE2_USE_HPTT
  if (tryRunWithHPTT<T>(axes_, input, output)) {
    return true;
  }
#endif

  int from_inds[COMPILE_TIME_MAX_TRANSPOSE_DIMS] = {0};
  size_t count = input.size();
  int num_axes = axes_.size();
  const T* from_data = input.template data<T>();
  T* to_data = output->template mutable_data<T>();
  auto in_dims = input.dims();
  auto out_dims = output->dims();

  // Measure amount of contiguous data we can copy at once
  TIndex blocksize = 1;
  int n_shared_idxs = 0;
  for (int i = num_axes - 1; i >= 0; --i) {
    if (axes_[i] == i) {
      blocksize *= new_dims_[i];
      ++n_shared_idxs;
    } else {
      break;
    }
  }

  if (num_axes < 2 || n_shared_idxs == num_axes) {
    memcpy(to_data, from_data, count * sizeof(T));
    return true;
  }

  int itr_axes = num_axes - n_shared_idxs;

  // Calculate strides
  TIndex stride_x[COMPILE_TIME_MAX_TRANSPOSE_DIMS] = {0};
  for (size_t i = 0; i < itr_axes; i++) {
    stride_x[i] = 1;
    for (size_t j = axes_[i] + 1; j < itr_axes; j++) {
      stride_x[i] *= in_dims[j];
    }
  }

  TIndex itr_idxs[COMPILE_TIME_MAX_TRANSPOSE_DIMS] = {0};

  // Branch here to avoid branching within the loop
  if (blocksize > 1) {
    for (size_t index = 0; index < (count / blocksize); index++) {
      TIndex from_index = 0;
      for (int i = 0; i < itr_axes; ++i) {
        from_index += stride_x[i] * itr_idxs[i];
      }

      memcpy(
          to_data + blocksize * index,
          from_data + blocksize * from_index,
          blocksize * sizeof(T));

      ++itr_idxs[itr_axes - 1];
      for (int i = itr_axes - 1; i >= 1; --i) {
        auto expected_dim = out_dims[i];
        if (itr_idxs[i] < expected_dim) {
          break;
        }
        itr_idxs[i] %= expected_dim;
        ++itr_idxs[i - 1];
      }
    }
  } else {
    for (size_t index = 0; index < count; index++) {
      TIndex from_index = 0;
      for (int i = 0; i < itr_axes; ++i) {
        from_index += stride_x[i] * itr_idxs[i];
      }

      *(to_data + index) = *(from_data + from_index);

      ++itr_idxs[itr_axes - 1];
      for (int i = itr_axes - 1; i >= 1; --i) {
        auto expected_dim = out_dims[i];
        if (itr_idxs[i] < expected_dim) {
          break;
        }
        itr_idxs[i] %= expected_dim;
        ++itr_idxs[i - 1];
      }
    }
  }

  return true;
}

REGISTER_CPU_OPERATOR(Transpose, TransposeOp<CPUContext>);

OPERATOR_SCHEMA(Transpose)
    .NumInputs(1)
    .NumOutputs(1)
    .TensorInferenceFunction([](
        const OperatorDef& def,
        const vector<TensorShape>& in) {
      ArgumentHelper helper(def);
      vector<int> axes = helper.GetRepeatedArgument<int>("axes");
      vector<TensorShape> out(1);
      out[0].set_data_type(in[0].data_type());

      if (axes.empty()) {
        for (auto axis = in [0].dims().rbegin(); axis != in[0].dims().rend();
             ++axis) {
          out[0].add_dims(*axis);
        }
      } else {
        auto tensor_size = in[0].dims().size();
        auto valid_axes =
            std::all_of(axes.begin(), axes.end(), [&tensor_size](int& axis) {
              return axis >= 0 && axis < tensor_size;
            });

        CAFFE_ENFORCE(valid_axes, "Axes argument passed in had invalid values");
        CAFFE_ENFORCE(
            axes.size() == tensor_size,
            "Axes argument passed in had the incorrect size");

        for (auto axis = axes.begin(); axis != axes.end(); ++axis) {
          out[0].add_dims(in[0].dims().Get(*axis));
        }
      }

      return out;
    })
    .SetDoc(R"DOC(
Transpose the input tensor similar to numpy.transpose. For example, when
axes=(1, 0, 2), given an input tensor of shape (1, 2, 3), the output shape
will be (2, 1, 3).
)DOC")
    .Arg(
        "axes",
        "A list of integers. By default, reverse the dimensions, "
        "otherwise permute the axes according to the values given.")
    .Input(0, "data", "An input tensor.")
    .Output(0, "transposed", "Transposed output.");

class GetTransposeGradient : public GradientMakerBase {
  using GradientMakerBase::GradientMakerBase;
  // We will create our own arguments.
  bool CopyArguments() const override {
    return false;
  }
  vector<OperatorDef> GetGradientDefs() override {
    auto ops = SingleGradientDef(
        "Transpose", "", vector<string>{GO(0)}, vector<string>{GI(0)});
    ops[0].mutable_arg()->CopyFrom(Def().arg());
    if (ArgumentHelper::HasArgument(Def(), "axes")) {
      // If axes is specified, we will need to figure out the inverse index.
      const Argument& old_axes = GetArgument(Def(), "axes");
      const int axes_size = old_axes.ints_size();
      Argument* new_arg = GetMutableArgument("axes", false, &ops[0]);
      for (int i = 0; i < axes_size; ++i) {
        new_arg->set_ints(old_axes.ints(i), i);
      }
    }
    return ops;
  }
};
REGISTER_GRADIENT(Transpose, GetTransposeGradient);
} // namespace caffe2
<|endoftext|>


<commit_before>AliAnalysisTaskEmcalHFeJetCorrel* AddTaskEmcalHFCJ(
  const char *ntracks            = "Tracks",
  const char *nclusters          = "CaloClusters",
  const char *njets              = "Jets",
  const char *nrho               = "Rho",
  Int_t       nCentBins          = 1,
  Double_t    jetradius          = 0.4,
  Double_t    jetptcut           = 0,
  Double_t    jetareacut         = 0.6,
  const char *type               = "EMCAL",
  Int_t       leadhadtype        = 0,
  const char *taskname           = "AliAnalysisTaskEmcalHFeJetCorrel",
  TString cutfile				 ="HFCJCuts.root",
  UInt_t triggerMask			 =-1,//AliVEvent::kEMC1 | AliVEvent::kEMC7 | AliVEvent::kEMC8,/*kMB kEMC7 (kEMC8) kEMCEJE kEMCEGA*/
  Bool_t isMC					 = kFALSE,
  bool TestContainer			 = kFALSE,
  bool EGA1                      = kFALSE,
  const char *MCtracks            = "",
  const char *MCclusters          = "",
  const char *MCjets              = ""
)
{
  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr)
  {
    ::Error("AddTaskEmcalHFCJ", "No analysis manager to connect to.");
    return NULL;
  }

  // Check the analysis type using the event handlers connected to the analysis manager.
  //==============================================================================
  if (!mgr->GetInputEventHandler())
  {
    ::Error("AddTaskEmcalHFCJ", "This task requires an input event handler");
    return NULL;
  }

  //-------------------------------------------------------
  // Init the task and do settings
  //-------------------------------------------------------

  TString name(taskname);
  if (strcmp(njets,"")) {
    name += "_";
    name += njets;
  }
  if (strcmp(nrho,"")) {
    name += "_";
    name += nrho;
  }
  if (strcmp(type,"")) {
    name += "_";
    name += type;
  }

  Printf("name: %s",name.Data());

  AliAnalysisTaskEmcalHFeJetCorrel* jetTask = new AliAnalysisTaskEmcalHFeJetCorrel(name);
  jetTask->SetCentRange(0.,100.);
  jetTask->SetNCentBins(nCentBins);
  jetTask->SetReadMC(isMC);
  jetTask->SetMCParticles(MCtracks);
  jetTask->SetQA(kTRUE);//FALSE);
  jetTask->SetCheckClusterMatching(kFALSE);
  jetTask->SetDoAnalysis(kTRUE);//FALSE);
  jetTask->SetGeneralSpectra(kTRUE);//FALSE);
  jetTask->SetDetectorsTest(kTRUE);//FALSE);
  //Shingo Electron Selection
  jetTask->SetFilterBitElectron(AliAODTrack::kTrkGlobalNoDCA);

  //Defaut parameters
  jetTask->SetMinPtElectron(0.1);
  jetTask->SetEtaTracks(-0.9,0.9);
  jetTask->SetNsigmaTPCelectron(-10,3.5);
  jetTask->SetPhotonicMassCut(0.5);
  jetTask->SetMinNumberOfClusterCells(4);
  jetTask->SetMaxM20(0.9);
  jetTask->SetMaxM02(0.9);
  jetTask->SetEoverPlimits(0.0, 3.0);

  AliParticleContainer *trackCont  = jetTask->AddParticleContainer(ntracks);
  trackCont->SetClassName("AliVTrack");
  AliClusterContainer *clusterCont = jetTask->AddClusterContainer(nclusters);

  TString strType(type);
  AliJetContainer *jetCont = jetTask->AddJetContainer(njets,strType,jetradius);
  if(jetCont) {
    jetCont->SetRhoName(nrho);
    jetCont->ConnectParticleContainer(trackCont);
    jetCont->ConnectClusterContainer(clusterCont);
    jetCont->SetZLeadingCut(0.98,0.98);
    jetCont->SetPercAreaCut(0.6);
    jetCont->SetJetPtCut(jetptcut);
    jetCont->SetLeadingHadronType(leadhadtype);
  }

//=========================CUTS=========================
AliRDHFJetsCuts *cuts;

bool kFileExists=kFALSE;
//if(!gSystem->AccessPathName(cutfile.Data(),kFileExists)){

if(gSystem->AccessPathName(cutfile.Data(),kFileExists))
{
	::Error("\n==CutObject not Defined. Verify your .root file==\n");
	return NULL;
}
	TFile *f=TFile::Open(cutfile.Data());
	//cuts= (AliRDHFCutsD0toKpi*)f->Get("EventTrackCuts");
	cuts= (AliRDHFJetsCuts*)f->Get("HFCJCuts");

	cout<<"\n==========================================\n Cutfile used:\n"<<cutfile.Data()<<endl;
	//cuts->PrintAll();

    if(triggerMask>0)
    {
        cuts->SetTriggerMask(triggerMask);
        if( (triggerMask == AliVEvent::kEMCEGA)&&(EGA1) )cuts->SetTriggerClass("EG1");
    }

jetTask->SetJetCuts(cuts);
delete cuts;
//==========================================================

//-------------------------------------------------------
// Final settings, pass to manager and set the containers
//-------------------------------------------------------

  mgr->AddTask(jetTask);

  // Create containers for input/output
  AliAnalysisDataContainer *cinput1  = mgr->GetCommonInputContainer()  ;
  TString contname(name);
  contname += "_histos";
  AliAnalysisDataContainer *coutput1 = mgr->CreateContainer(contname.Data(),
							    TList::Class(),AliAnalysisManager::kOutputContainer,
							    Form("%s", AliAnalysisManager::GetCommonFileName()));
  mgr->ConnectInput  (jetTask, 0,  cinput1 );
  mgr->ConnectOutput (jetTask, 1, coutput1 );

  return jetTask;
}
<commit_msg>Changing comment.<commit_after>AliAnalysisTaskEmcalHFeJetCorrel* AddTaskEmcalHFCJ(
  const char *ntracks            = "Tracks",
  const char *nclusters          = "CaloClusters",
  const char *njets              = "Jets",
  const char *nrho               = "Rho",
  Int_t       nCentBins          = 1,
  Double_t    jetradius          = 0.4,
  Double_t    jetptcut           = 0,
  Double_t    jetareacut         = 0.6,
  const char *type               = "EMCAL",
  Int_t       leadhadtype        = 0,
  const char *taskname           = "AliAnalysisTaskEmcalHFeJetCorrel",
  TString cutfile				 ="HFCJCuts.root",
  UInt_t triggerMask			 =-1,/*AliVEvent::kEMC1 | AliVEvent::kEMC7 | AliVEvent::kEMC8, kMB kEMC7 (kEMC8) kEMCEJE kEMCEGA*/
  Bool_t isMC					 = kFALSE,
  bool TestContainer			 = kFALSE,
  bool EGA1                      = kFALSE,
  const char *MCtracks            = "",
  const char *MCclusters          = "",
  const char *MCjets              = ""
)
{
  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr)
  {
    ::Error("AddTaskEmcalHFCJ", "No analysis manager to connect to.");
    return NULL;
  }

  // Check the analysis type using the event handlers connected to the analysis manager.
  //==============================================================================
  if (!mgr->GetInputEventHandler())
  {
    ::Error("AddTaskEmcalHFCJ", "This task requires an input event handler");
    return NULL;
  }

  //-------------------------------------------------------
  // Init the task and do settings
  //-------------------------------------------------------

  TString name(taskname);
  if (strcmp(njets,"")) {
    name += "_";
    name += njets;
  }
  if (strcmp(nrho,"")) {
    name += "_";
    name += nrho;
  }
  if (strcmp(type,"")) {
    name += "_";
    name += type;
  }

  Printf("name: %s",name.Data());

  AliAnalysisTaskEmcalHFeJetCorrel* jetTask = new AliAnalysisTaskEmcalHFeJetCorrel(name);
  jetTask->SetCentRange(0.,100.);
  jetTask->SetNCentBins(nCentBins);
  jetTask->SetReadMC(isMC);
  jetTask->SetMCParticles(MCtracks);
  jetTask->SetQA(kTRUE);//FALSE);
  jetTask->SetCheckClusterMatching(kFALSE);
  jetTask->SetDoAnalysis(kTRUE);//FALSE);
  jetTask->SetGeneralSpectra(kTRUE);//FALSE);
  jetTask->SetDetectorsTest(kTRUE);//FALSE);
  //Shingo Electron Selection
  jetTask->SetFilterBitElectron(AliAODTrack::kTrkGlobalNoDCA);

  //Defaut parameters
  jetTask->SetMinPtElectron(0.1);
  jetTask->SetEtaTracks(-0.9,0.9);
  jetTask->SetNsigmaTPCelectron(-10,3.5);
  jetTask->SetPhotonicMassCut(0.5);
  jetTask->SetMinNumberOfClusterCells(4);
  jetTask->SetMaxM20(0.9);
  jetTask->SetMaxM02(0.9);
  jetTask->SetEoverPlimits(0.0, 3.0);

  AliParticleContainer *trackCont  = jetTask->AddParticleContainer(ntracks);
  trackCont->SetClassName("AliVTrack");
  AliClusterContainer *clusterCont = jetTask->AddClusterContainer(nclusters);

  TString strType(type);
  AliJetContainer *jetCont = jetTask->AddJetContainer(njets,strType,jetradius);
  if(jetCont) {
    jetCont->SetRhoName(nrho);
    jetCont->ConnectParticleContainer(trackCont);
    jetCont->ConnectClusterContainer(clusterCont);
    jetCont->SetZLeadingCut(0.98,0.98);
    jetCont->SetPercAreaCut(0.6);
    jetCont->SetJetPtCut(jetptcut);
    jetCont->SetLeadingHadronType(leadhadtype);
  }

//=========================CUTS=========================
AliRDHFJetsCuts *cuts;

bool kFileExists=kFALSE;
//if(!gSystem->AccessPathName(cutfile.Data(),kFileExists)){

if(gSystem->AccessPathName(cutfile.Data(),kFileExists))
{
	::Error("\n==CutObject not Defined. Verify your .root file==\n");
	return NULL;
}
	TFile *f=TFile::Open(cutfile.Data());
	//cuts= (AliRDHFCutsD0toKpi*)f->Get("EventTrackCuts");
	cuts= (AliRDHFJetsCuts*)f->Get("HFCJCuts");

	cout<<"\n==========================================\n Cutfile used:\n"<<cutfile.Data()<<endl;
	//cuts->PrintAll();

    if(triggerMask>0)
    {
        cuts->SetTriggerMask(triggerMask);
        if( (triggerMask == AliVEvent::kEMCEGA)&&(EGA1) )cuts->SetTriggerClass("EG1");
    }

jetTask->SetJetCuts(cuts);
delete cuts;
//==========================================================

//-------------------------------------------------------
// Final settings, pass to manager and set the containers
//-------------------------------------------------------

  mgr->AddTask(jetTask);

  // Create containers for input/output
  AliAnalysisDataContainer *cinput1  = mgr->GetCommonInputContainer()  ;
  TString contname(name);
  contname += "_histos";
  AliAnalysisDataContainer *coutput1 = mgr->CreateContainer(contname.Data(),
							    TList::Class(),AliAnalysisManager::kOutputContainer,
							    Form("%s", AliAnalysisManager::GetCommonFileName()));
  mgr->ConnectInput  (jetTask, 0,  cinput1 );
  mgr->ConnectOutput (jetTask, 1, coutput1 );

  return jetTask;
}
<|endoftext|>


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

#ifndef _CANVAS_VCLWRAPPER_HXX
#define _CANVAS_VCLWRAPPER_HXX

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif
#ifndef _VOS_MUTEX_HXX_
#include <vos/mutex.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

namespace canvas
{
    namespace vcltools
    {
        /** This helper template wraps VCL objects, and protects
            object deletion with the Solar mutex. All other operations
            are unprotected, this must be handled by client code.

            The reason for this template is the fact that VCL objects
            hold by value in uno::Reference-handled classes are
            deleted without having the chance to get inbetween and
            lock the solar mutex.

            This template handles that problem transparently, the only
            inconvenience is the fact that object member access now
            has to be performed via operator->, since . is not
            overloadable.

            Otherwise, the template preserves the value semantics of
            the wrapped object, that is, copy operations are performed
            not by copying pointers, but by copying the underlying
            object. This includes constness, i.e. on a const
            VCLObject, only const methods of the wrapped object can be
            called. Simply imagine this to be a value object of type
            "template argument", with the only peculiarity that
            member/method access is performed by operator-> instead of
            the non-existing "operator.".
         */
        template< class _Wrappee > class VCLObject
        {
        public:
            typedef _Wrappee Wrappee;

            VCLObject() :
                mpWrappee( new Wrappee() )
            {
            }

            // no explicit here. VCLObjects should be freely
            // constructible with Wrappees, and AFAIK there is no other
            // implicit conversion path that could cause harm here
            VCLObject( Wrappee* pWrappee ) :
                mpWrappee( pWrappee )
            {
            }

            // This object has value semantics, thus, forward copy
            // to wrappee
            VCLObject( const VCLObject& rOrig )
            {
                if( rOrig.mpWrappee )
                    mpWrappee = new Wrappee( *rOrig.mpWrappee );
                else
                    mpWrappee = NULL;
            }

            // This object has value semantics, thus, forward copy
            // to wrappee
            VCLObject( const Wrappee& rOrig ) :
                mpWrappee( new Wrappee( rOrig ) )
            {
            }

            // This object has value semantics, thus, forward
            // assignment to wrappee
            VCLObject& operator=( const VCLObject& rhs )
            {
                if( mpWrappee )
                {
                    if( rhs.mpWrappee )
                        *mpWrappee = *rhs.mpWrappee;
                }
                else
                {
                    if( rhs.mpWrappee )
                        mpWrappee = new Wrappee( *rhs.mpWrappee );
                }

                return *this;
            }

            ~VCLObject()
            {
                // This here is the whole purpose of the template:
                // protecting object deletion with the solar mutex
                ::vos::OGuard aGuard( Application::GetSolarMutex() );

                if( mpWrappee )
                    delete mpWrappee;
            }

            Wrappee*        operator->() { return mpWrappee; }
            const Wrappee*  operator->() const { return mpWrappee; }

            Wrappee&        operator*() { return *mpWrappee; }
            const Wrappee&  operator*() const { return *mpWrappee; }

            Wrappee&        get() { return *mpWrappee; }
            const Wrappee&  get() const { return *mpWrappee; }

            void swap( VCLObject& rOther )
            {
                ::std::swap( mpWrappee, rOther.mpWrappee );
            }

        private:

            Wrappee* mpWrappee;
        };

    }
}

#endif /* _CANVAS_VCLWRAPPER_HXX */
<commit_msg>INTEGRATION: CWS presfixes09 (1.4.38); FILE MERGED 2006/03/15 13:43:02 thb 1.4.38.1: #i49357# Cleaned up include guards; added method to convert to system window coordinates (to account for VCL's pseudo windows)<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: vclwrapper.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-13 14:35:28 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef INCLUDED_CANVAS_VCLWRAPPER_HXX
#define INCLUDED_CANVAS_VCLWRAPPER_HXX

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif
#ifndef _VOS_MUTEX_HXX_
#include <vos/mutex.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

namespace canvas
{
    namespace vcltools
    {
        /** This helper template wraps VCL objects, and protects
            object deletion with the Solar mutex. All other operations
            are unprotected, this must be handled by client code.

            The reason for this template is the fact that VCL objects
            hold by value in uno::Reference-handled classes are
            deleted without having the chance to get inbetween and
            lock the solar mutex.

            This template handles that problem transparently, the only
            inconvenience is the fact that object member access now
            has to be performed via operator->, since . is not
            overloadable.

            Otherwise, the template preserves the value semantics of
            the wrapped object, that is, copy operations are performed
            not by copying pointers, but by copying the underlying
            object. This includes constness, i.e. on a const
            VCLObject, only const methods of the wrapped object can be
            called. Simply imagine this to be a value object of type
            "template argument", with the only peculiarity that
            member/method access is performed by operator-> instead of
            the non-existing "operator.".
         */
        template< class _Wrappee > class VCLObject
        {
        public:
            typedef _Wrappee Wrappee;

            VCLObject() :
                mpWrappee( new Wrappee() )
            {
            }

            // no explicit here. VCLObjects should be freely
            // constructible with Wrappees, and AFAIK there is no other
            // implicit conversion path that could cause harm here
            VCLObject( Wrappee* pWrappee ) :
                mpWrappee( pWrappee )
            {
            }

            // This object has value semantics, thus, forward copy
            // to wrappee
            VCLObject( const VCLObject& rOrig )
            {
                if( rOrig.mpWrappee )
                    mpWrappee = new Wrappee( *rOrig.mpWrappee );
                else
                    mpWrappee = NULL;
            }

            // This object has value semantics, thus, forward copy
            // to wrappee
            VCLObject( const Wrappee& rOrig ) :
                mpWrappee( new Wrappee( rOrig ) )
            {
            }

            // This object has value semantics, thus, forward
            // assignment to wrappee
            VCLObject& operator=( const VCLObject& rhs )
            {
                if( mpWrappee )
                {
                    if( rhs.mpWrappee )
                        *mpWrappee = *rhs.mpWrappee;
                }
                else
                {
                    if( rhs.mpWrappee )
                        mpWrappee = new Wrappee( *rhs.mpWrappee );
                }

                return *this;
            }

            ~VCLObject()
            {
                // This here is the whole purpose of the template:
                // protecting object deletion with the solar mutex
                ::vos::OGuard aGuard( Application::GetSolarMutex() );

                if( mpWrappee )
                    delete mpWrappee;
            }

            Wrappee*        operator->() { return mpWrappee; }
            const Wrappee*  operator->() const { return mpWrappee; }

            Wrappee&        operator*() { return *mpWrappee; }
            const Wrappee&  operator*() const { return *mpWrappee; }

            Wrappee&        get() { return *mpWrappee; }
            const Wrappee&  get() const { return *mpWrappee; }

            void swap( VCLObject& rOther )
            {
                ::std::swap( mpWrappee, rOther.mpWrappee );
            }

        private:

            Wrappee* mpWrappee;
        };

    }
}

#endif /* INCLUDED_CANVAS_VCLWRAPPER_HXX */
<|endoftext|>


<commit_before>#include "MeshNameScriptParser.h"
#include <DebugUtil.h>
#include <ValueClamp.h>

string MeshNameScriptParser::separators = "_";
string MeshNameScriptParser::instantiate = "I";
string MeshNameScriptParser::connectionpoint = "CP";
string MeshNameScriptParser::spawnpoint = "SP";

pair<MeshNameScriptParser::Data,MeshNameScriptParser::Token>
	MeshNameScriptParser::parse(const string& p_string)
{
	Token tokenVal = MESH;
	Data data = {p_string,""};
	string instr = getInstruction(p_string);
	if (instr==instantiate)
	{
		tokenVal = INSTANTIATE;
		data.filename = extractPart(p_string,0)+".agl";
		data.name = extractPart(p_string,1);
	}
	else if (instr==connectionpoint)
	{
		tokenVal = CONNECTIONPOINT;
		data.name = extractPart(p_string,0);
	}
	else if (instr==spawnpoint)
	{
		tokenVal = SPAWNPOINT;
		data.name = extractPart(p_string,0);
	}
	return pair<Data,Token>(data,tokenVal);
}

std::string MeshNameScriptParser::getInstruction( const string& p_string )
{
	return p_string.substr(0,p_string.find(separators));
}

std::string MeshNameScriptParser::extractPart( const string& p_string,int offset )
{
	int start=-1;
	for (int i=-1;i<offset;i++)
	{
		start=p_string.find(separators,start+1);
	}
	int s = clamp(start+1, 0, (int)p_string.size()-1);
	int l = max(0, (int)p_string.size()-(p_string.find(separators,s)-1)-s );
	string sub = p_string.substr(s,l);
	return sub;
}
<commit_msg>Corrected the types when calling the max function.<commit_after>#include "MeshNameScriptParser.h"
#include <DebugUtil.h>
#include <ValueClamp.h>

string MeshNameScriptParser::separators = "_";
string MeshNameScriptParser::instantiate = "I";
string MeshNameScriptParser::connectionpoint = "CP";
string MeshNameScriptParser::spawnpoint = "SP";

pair<MeshNameScriptParser::Data,MeshNameScriptParser::Token>
	MeshNameScriptParser::parse(const string& p_string)
{
	Token tokenVal = MESH;
	Data data = {p_string,""};
	string instr = getInstruction(p_string);
	if (instr==instantiate)
	{
		tokenVal = INSTANTIATE;
		data.filename = extractPart(p_string,0)+".agl";
		data.name = extractPart(p_string,1);
	}
	else if (instr==connectionpoint)
	{
		tokenVal = CONNECTIONPOINT;
		data.name = extractPart(p_string,0);
	}
	else if (instr==spawnpoint)
	{
		tokenVal = SPAWNPOINT;
		data.name = extractPart(p_string,0);
	}
	return pair<Data,Token>(data,tokenVal);
}

std::string MeshNameScriptParser::getInstruction( const string& p_string )
{
	return p_string.substr(0,p_string.find(separators));
}

std::string MeshNameScriptParser::extractPart( const string& p_string,int offset )
{
	int start=-1;
	for (int i=-1;i<offset;i++)
	{
		start=p_string.find(separators,start+1);
	}
	int s = clamp(start+1, 0, (int)p_string.size()-1);
	int suffixLength = max((unsigned int)0, p_string.size()-(p_string.find(separators,s)));
	int l = (int)p_string.size()-suffixLength-s;
	string sub = p_string.substr(s,l);
	return sub;
}<|endoftext|>


<commit_before>/*
 *  RustEditor: Plugin to add Rust language support to QtCreator IDE.
 *  Copyright (C) 2015  Davide Ghilardi
 *
 *  This file is part of RustEditor.
 *
 *  RustEditor is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 2.1 of the License, or
 *  (at your option) any later version.
 *
 *  RustEditor is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with RustEditor.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "rustcompletionassist.h"
#include "rusteditorconstants.h"
#include "rusteditorplugin.h"
#include "configuration.h"

#include <coreplugin/idocument.h>
#include <coreplugin/id.h>
#include <texteditor/completionsettings.h>
#include <texteditor/convenience.h>
#include <texteditor/codeassist/assistproposalitem.h>
#include <texteditor/codeassist/genericproposalmodel.h>
#include <texteditor/codeassist/genericproposal.h>
#include <texteditor/codeassist/functionhintproposal.h>

#include <utils/faketooltip.h>

#include <QIcon>
#include <QPainter>
#include <QLabel>
#include <QToolButton>
#include <QHBoxLayout>
#include <QApplication>
#include <QDesktopWidget>
#include <QDebug>
#include <QProcess>
#include <QTemporaryFile>
#include <QTextDocument>

using namespace TextEditor;

using namespace RustEditor::Internal;

enum RacerOutputPosMeaning{
    MATCH,
    LINENUM,
    CHARNUM,
    FILEPATH,
    TYPE,
    DESCR
};

enum CompletionOrder {
    SpecialMemberOrder = -5
};

static bool isActivationChar(const QChar &ch)
{
    return ch == QLatin1Char('(') || ch == QLatin1Char('.') || ch == QLatin1Char(',');
}

static bool isIdentifierChar(QChar ch)
{
    return ch.isLetterOrNumber() || ch == QLatin1Char('_');
}

static bool isDelimiter(QChar ch)
{
    switch (ch.unicode()) {
    case '{':
    case '}':
    case '[':
    case ']':
    case ')':
    case '?':
    case '!':
    case ':':
    case ';':
    case ',':
    case '+':
    case '-':
    case '*':
    case '/':
        return true;

    default:
        return false;
    }
}

static bool checkStartOfIdentifier(const QString &word)
{
    if (! word.isEmpty()) {
        const QChar ch = word.at(0);
        if (ch.isLetter() || ch == QLatin1Char('_'))
            return true;
    }

    return false;
}

// ----------------------------
// RustCompletionAssistProvider
// ----------------------------
bool RustCompletionAssistProvider::supportsEditor(Core::Id editorId) const
{
    return editorId == Constants::RUSTEDITOR_ID;
}

IAssistProcessor *RustCompletionAssistProvider::createProcessor() const
{
    return new RustCompletionAssistProcessor;
}

int RustCompletionAssistProvider::activationCharSequenceLength() const
{
    return 1;
}

bool RustCompletionAssistProvider::isActivationCharSequence(const QString &sequence) const
{
    return isActivationChar(sequence.at(0));
}

// -----------------------------
// RustCompletionAssistProcessor
// -----------------------------
RustCompletionAssistProcessor::RustCompletionAssistProcessor()
    : m_startPosition(0)
    , m_keywordIcon(QLatin1String(":/rusteditor/images/keyword.png"))
    , m_varIcon(QLatin1String(":/rusteditor/images/var.png"))
    , m_functionIcon(QLatin1String(":/rusteditor/images/func.png"))
    , m_typeIcon(QLatin1String(":/rusteditor/images/type.png"))
    , m_constIcon(QLatin1String(":/rusteditor/images/const.png"))
    , m_attributeIcon(QLatin1String(":/rusteditor/images/attribute.png"))
    , m_uniformIcon(QLatin1String(":/rusteditor/images/uniform.png"))
    , m_varyingIcon(QLatin1String(":/rusteditor/images/varying.png"))
    , m_otherIcon(QLatin1String(":/rusteditor/images/other.png"))
{}

RustCompletionAssistProcessor::~RustCompletionAssistProcessor()
{}

static AssistProposalItem *createCompletionItem(const QString &text, const QIcon &icon, int order = 0)
{
    AssistProposalItem *item = new AssistProposalItem;
    item->setText(text);
    item->setIcon(icon);
    item->setOrder(order);
    return item;
}

/**
 * @brief RustCompletionAssistProcessor::getRacerIcon Match completion type with the relative icon
 * @param type String representing the type of the completion returned by racer
 * @return icon that matches the given type
 */
const QIcon &RustCompletionAssistProcessor::getRacerIcon(const QString &type){
    if(type == QLatin1String("Module")) return m_otherIcon;
    else if(type == QLatin1String("Struct")) return m_typeIcon;
    else if(type == QLatin1String("MatchArm")) return m_otherIcon; //??
    else if(type == QLatin1String("Function")) return m_functionIcon;
    else if(type == QLatin1String("Crate")) return m_otherIcon; //
    else if(type == QLatin1String("Let")) return m_varIcon;
    else if(type == QLatin1String("IfLet")) return m_varIcon; //??
    else if(type == QLatin1String("StructField")) return m_attributeIcon;
    else if(type == QLatin1String("Impl")) return m_typeIcon;
    else if(type == QLatin1String("Enum")) return m_typeIcon;
    else if(type == QLatin1String("EnumVariant")) return m_typeIcon;
    else if(type == QLatin1String("Type")) return m_typeIcon;
    else if(type == QLatin1String("FnArg")) return m_varIcon;
    else if(type == QLatin1String("Trait")) return m_typeIcon;
    else if(type == QLatin1String("Const")) return m_constIcon;
    else if(type == QLatin1String("Static")) return m_constIcon;
    else return m_otherIcon;
}

IAssistProposal *RustCompletionAssistProcessor::perform(const AssistInterface *interface)
{

    m_interface.reset(static_cast<const RustCompletionAssistInterface *>(interface));

    if (interface->reason() == IdleEditor && !acceptsIdleEditor())
        return 0;

    //Save the current document to a temporary file so I can call racer on it
    QFile tmpsrc(m_interface->fileName() + QLatin1String(".racer.rs"));
    if(!tmpsrc.open(QFile::ReadWrite)) return 0;
    const QTextDocument *doc = m_interface->textDocument();
    QString fullDoc = doc->toPlainText();
    QTextStream tmpstream(&tmpsrc);
    tmpstream << fullDoc;
    tmpstream.flush();

    int pos = m_interface->position() - 1;
    QChar ch = m_interface->characterAt(pos);
    while (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
        ch = m_interface->characterAt(--pos);

    int charnum, linenum;
    TextEditor::Convenience::convertPosition(doc, m_interface->position(), &linenum, &charnum);

    //Keep the compatibility with 3.x until 4.0 is out
#if (QTC_VERSION_MAJOR == 3) && (QTC_VERSION_MINOR == 6)
    QList<AssistProposalItem *> m_completions;
#elif (QTC_VERSION_MAJOR == 4) && (QTC_VERSION_MINOR == 0)
    QList<AssistProposalItemInterface *> m_completions; // all possible completions at given point
#endif

    const Settings &rustEditorSettings = Configuration::getSettingsPtr();

    QString rustPath = rustEditorSettings.rustSrcPath().toString();
    QString racerPath = rustEditorSettings.racerPath().toString();
    if(!racerPath.isEmpty() && !racerPath.endsWith(QLatin1Char('/'))) racerPath.append(QLatin1Char('/'));

    //set environment variable pointing to where rust source is located
    QStringList env;
    env << (QLatin1String("RUST_SRC_PATH=")+rustPath);

    //run 'racer complete <linenum> <charnum> <filename>' and retrieve the output
    QProcess process;
    process.setEnvironment(env);
    QStringList params;
    params << QLatin1String("complete") << QString::number(linenum) << QString::number(charnum) << tmpsrc.fileName();
    process.start(racerPath+QLatin1String("racer"), params);
    process.waitForFinished();
    QString result = QString::fromLatin1(process.readAllStandardOutput());

    QStringList lines = result.split(QLatin1String("\n"));
    foreach (QString l, lines) {
        if(l.left(5) == QString::fromLatin1("MATCH")){
            QStringList fields = l.split(QLatin1String(","));
            m_completions << createCompletionItem(fields[MATCH].mid(6),getRacerIcon(fields[TYPE]));
        }
    }

    m_startPosition = pos + 1;

    tmpsrc.remove();
    return new GenericProposal(m_startPosition, m_completions);
}

bool RustCompletionAssistProcessor::acceptsIdleEditor() const
{
    const int cursorPosition = m_interface->position();
    const QChar ch = m_interface->characterAt(cursorPosition - 1);

    const QChar characterUnderCursor = m_interface->characterAt(cursorPosition);

    if (isIdentifierChar(ch) && (characterUnderCursor.isSpace() ||
                                 characterUnderCursor.isNull() ||
                                 isDelimiter(characterUnderCursor))) {
        int pos = m_interface->position() - 1;
        for (; pos != -1; --pos) {
            if (! isIdentifierChar(m_interface->characterAt(pos)))
                break;
        }
        ++pos;

        const QString word = m_interface->textAt(pos, cursorPosition - pos);
        if (word.length() > 2 && checkStartOfIdentifier(word)) {
            for (int i = 0; i < word.length(); ++i) {
                if (! isIdentifierChar(word.at(i)))
                    return false;
            }
            return true;
        }
    }

    return isActivationChar(ch);
}

// -----------------------------
// RustCompletionAssistInterface
// -----------------------------
RustCompletionAssistInterface::RustCompletionAssistInterface(QTextDocument *textDocument,
                                                             int position,
                                                             const QString &fileName,
                                                             AssistReason reason,
                                                             const QString &mimeType)
    : AssistInterface(textDocument, position, fileName, reason)
    , m_mimeType(mimeType)
{
}
<commit_msg>show message if racer return nonzero exit code<commit_after>/*
 *  RustEditor: Plugin to add Rust language support to QtCreator IDE.
 *  Copyright (C) 2015  Davide Ghilardi
 *
 *  This file is part of RustEditor.
 *
 *  RustEditor is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 2.1 of the License, or
 *  (at your option) any later version.
 *
 *  RustEditor is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with RustEditor.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "rustcompletionassist.h"
#include "rusteditorconstants.h"
#include "rusteditorplugin.h"
#include "configuration.h"

#include <coreplugin/messagemanager.h>
#include <coreplugin/idocument.h>
#include <coreplugin/id.h>
#include <texteditor/completionsettings.h>
#include <texteditor/convenience.h>
#include <texteditor/codeassist/assistproposalitem.h>
#include <texteditor/codeassist/genericproposalmodel.h>
#include <texteditor/codeassist/genericproposal.h>
#include <texteditor/codeassist/functionhintproposal.h>

#include <utils/faketooltip.h>

#include <QIcon>
#include <QPainter>
#include <QLabel>
#include <QToolButton>
#include <QHBoxLayout>
#include <QApplication>
#include <QDesktopWidget>
#include <QDebug>
#include <QProcess>
#include <QTemporaryFile>
#include <QTextDocument>

using namespace TextEditor;

using namespace RustEditor::Internal;

enum RacerOutputPosMeaning{
    MATCH,
    LINENUM,
    CHARNUM,
    FILEPATH,
    TYPE,
    DESCR
};

enum CompletionOrder {
    SpecialMemberOrder = -5
};

static bool isActivationChar(const QChar &ch)
{
    return ch == QLatin1Char('(') || ch == QLatin1Char('.') || ch == QLatin1Char(',');
}

static bool isIdentifierChar(QChar ch)
{
    return ch.isLetterOrNumber() || ch == QLatin1Char('_');
}

static bool isDelimiter(QChar ch)
{
    switch (ch.unicode()) {
    case '{':
    case '}':
    case '[':
    case ']':
    case ')':
    case '?':
    case '!':
    case ':':
    case ';':
    case ',':
    case '+':
    case '-':
    case '*':
    case '/':
        return true;

    default:
        return false;
    }
}

static bool checkStartOfIdentifier(const QString &word)
{
    if (! word.isEmpty()) {
        const QChar ch = word.at(0);
        if (ch.isLetter() || ch == QLatin1Char('_'))
            return true;
    }

    return false;
}

// ----------------------------
// RustCompletionAssistProvider
// ----------------------------
bool RustCompletionAssistProvider::supportsEditor(Core::Id editorId) const
{
    return editorId == Constants::RUSTEDITOR_ID;
}

IAssistProcessor *RustCompletionAssistProvider::createProcessor() const
{
    return new RustCompletionAssistProcessor;
}

int RustCompletionAssistProvider::activationCharSequenceLength() const
{
    return 1;
}

bool RustCompletionAssistProvider::isActivationCharSequence(const QString &sequence) const
{
    return isActivationChar(sequence.at(0));
}

// -----------------------------
// RustCompletionAssistProcessor
// -----------------------------
RustCompletionAssistProcessor::RustCompletionAssistProcessor()
    : m_startPosition(0)
    , m_keywordIcon(QLatin1String(":/rusteditor/images/keyword.png"))
    , m_varIcon(QLatin1String(":/rusteditor/images/var.png"))
    , m_functionIcon(QLatin1String(":/rusteditor/images/func.png"))
    , m_typeIcon(QLatin1String(":/rusteditor/images/type.png"))
    , m_constIcon(QLatin1String(":/rusteditor/images/const.png"))
    , m_attributeIcon(QLatin1String(":/rusteditor/images/attribute.png"))
    , m_uniformIcon(QLatin1String(":/rusteditor/images/uniform.png"))
    , m_varyingIcon(QLatin1String(":/rusteditor/images/varying.png"))
    , m_otherIcon(QLatin1String(":/rusteditor/images/other.png"))
{}

RustCompletionAssistProcessor::~RustCompletionAssistProcessor()
{}

static AssistProposalItem *createCompletionItem(const QString &text, const QIcon &icon, int order = 0)
{
    AssistProposalItem *item = new AssistProposalItem;
    item->setText(text);
    item->setIcon(icon);
    item->setOrder(order);
    return item;
}

/**
 * @brief RustCompletionAssistProcessor::getRacerIcon Match completion type with the relative icon
 * @param type String representing the type of the completion returned by racer
 * @return icon that matches the given type
 */
const QIcon &RustCompletionAssistProcessor::getRacerIcon(const QString &type){
    if(type == QLatin1String("Module")) return m_otherIcon;
    else if(type == QLatin1String("Struct")) return m_typeIcon;
    else if(type == QLatin1String("MatchArm")) return m_otherIcon; //??
    else if(type == QLatin1String("Function")) return m_functionIcon;
    else if(type == QLatin1String("Crate")) return m_otherIcon; //
    else if(type == QLatin1String("Let")) return m_varIcon;
    else if(type == QLatin1String("IfLet")) return m_varIcon; //??
    else if(type == QLatin1String("StructField")) return m_attributeIcon;
    else if(type == QLatin1String("Impl")) return m_typeIcon;
    else if(type == QLatin1String("Enum")) return m_typeIcon;
    else if(type == QLatin1String("EnumVariant")) return m_typeIcon;
    else if(type == QLatin1String("Type")) return m_typeIcon;
    else if(type == QLatin1String("FnArg")) return m_varIcon;
    else if(type == QLatin1String("Trait")) return m_typeIcon;
    else if(type == QLatin1String("Const")) return m_constIcon;
    else if(type == QLatin1String("Static")) return m_constIcon;
    else return m_otherIcon;
}

IAssistProposal *RustCompletionAssistProcessor::perform(const AssistInterface *interface)
{

    m_interface.reset(static_cast<const RustCompletionAssistInterface *>(interface));

    if (interface->reason() == IdleEditor && !acceptsIdleEditor())
        return 0;

    //Save the current document to a temporary file so I can call racer on it
    QFile tmpsrc(m_interface->fileName() + QLatin1String(".racer.rs"));
    if(!tmpsrc.open(QFile::ReadWrite)) return 0;
    const QTextDocument *doc = m_interface->textDocument();
    QString fullDoc = doc->toPlainText();
    QTextStream tmpstream(&tmpsrc);
    tmpstream << fullDoc;
    tmpstream.flush();

    int pos = m_interface->position() - 1;
    QChar ch = m_interface->characterAt(pos);
    while (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
        ch = m_interface->characterAt(--pos);

    int charnum, linenum;
    TextEditor::Convenience::convertPosition(doc, m_interface->position(), &linenum, &charnum);

    //Keep the compatibility with 3.x until 4.0 is out
#if (QTC_VERSION_MAJOR == 3) && (QTC_VERSION_MINOR == 6)
    QList<AssistProposalItem *> m_completions;
#elif (QTC_VERSION_MAJOR == 4) && (QTC_VERSION_MINOR == 0)
    QList<AssistProposalItemInterface *> m_completions; // all possible completions at given point
#endif

    const Settings &rustEditorSettings = Configuration::getSettingsPtr();

    QString rustPath = rustEditorSettings.rustSrcPath().toString();
    QString racerPath = rustEditorSettings.racerPath().toString();
    if(!racerPath.isEmpty() && !racerPath.endsWith(QLatin1Char('/'))) racerPath.append(QLatin1Char('/'));

    //set environment variable pointing to where rust source is located
    QStringList env;
    env << (QLatin1String("RUST_SRC_PATH=")+rustPath);

    //run 'racer complete <linenum> <charnum> <filename>' and retrieve the output
    QProcess process;
    process.setEnvironment(env);
    QStringList params;
    params << QLatin1String("complete") << QString::number(linenum) << QString::number(charnum) << tmpsrc.fileName();
    process.start(racerPath+QLatin1String("racer"), params);
    process.waitForFinished();
    QString result = QString::fromLatin1(process.readAllStandardOutput());

    if(process.exitCode() == 0){
        QStringList lines = result.split(QLatin1String("\n"));
        foreach (QString l, lines) {
            if(l.left(5) == QString::fromLatin1("MATCH")){
                QStringList fields = l.split(QLatin1String(","));
                m_completions << createCompletionItem(fields[MATCH].mid(6),getRacerIcon(fields[TYPE]));
            }
        }
    }else{
        Core::MessageManager::write(result);
    }

    m_startPosition = pos + 1;

    tmpsrc.remove();
    return new GenericProposal(m_startPosition, m_completions);
}

bool RustCompletionAssistProcessor::acceptsIdleEditor() const
{
    const int cursorPosition = m_interface->position();
    const QChar ch = m_interface->characterAt(cursorPosition - 1);

    const QChar characterUnderCursor = m_interface->characterAt(cursorPosition);

    if (isIdentifierChar(ch) && (characterUnderCursor.isSpace() ||
                                 characterUnderCursor.isNull() ||
                                 isDelimiter(characterUnderCursor))) {
        int pos = m_interface->position() - 1;
        for (; pos != -1; --pos) {
            if (! isIdentifierChar(m_interface->characterAt(pos)))
                break;
        }
        ++pos;

        const QString word = m_interface->textAt(pos, cursorPosition - pos);
        if (word.length() > 2 && checkStartOfIdentifier(word)) {
            for (int i = 0; i < word.length(); ++i) {
                if (! isIdentifierChar(word.at(i)))
                    return false;
            }
            return true;
        }
    }

    return isActivationChar(ch);
}

// -----------------------------
// RustCompletionAssistInterface
// -----------------------------
RustCompletionAssistInterface::RustCompletionAssistInterface(QTextDocument *textDocument,
                                                             int position,
                                                             const QString &fileName,
                                                             AssistReason reason,
                                                             const QString &mimeType)
    : AssistInterface(textDocument, position, fileName, reason)
    , m_mimeType(mimeType)
{
}
<|endoftext|>


<commit_before>// -*- mode: c++; coding: utf-8 -*-
/*! @file program.cpp
    @brief Inplementation of Program class
*/
#include "program.hpp"

#include <cstdlib>
#include <regex>

#include <cxxwtils/debug.hpp>
#include <cxxwtils/iostr.hpp>
#include <cxxwtils/gz.hpp>
#include <cxxwtils/os.hpp>
#include <cxxwtils/getopt.hpp>
#include <cxxwtils/eigen.hpp>

#include "exclusivity.hpp"

namespace likeligrid {

namespace po = boost::program_options;

inline po::options_description general_desc() {HERE;
    po::options_description description("General");
    description.add_options()
        ("help,h", po::value<bool>()->default_value(false)->implicit_value(true), "print this help")
        ("verbose,v", po::value<bool>()->default_value(false)->implicit_value(true), "verbose output")
        ("test", po::value<int>()->default_value(0)->implicit_value(1));
    return description;
}

po::options_description Program::options_desc() {HERE;
    po::options_description description("Program");
    description.add_options()
        ("max-sites,s", po::value(&MAX_SITES)->default_value(MAX_SITES));
    return description;
}

po::options_description Program::positional_desc() {HERE;
    po::options_description description("Positional");
    description.add_options()
        ("genotypes", po::value(&GENOTYPES_FILE)->default_value(GENOTYPES_FILE));
    return description;
}

void Program::help_and_exit() {HERE;
    auto description = general_desc();
    description.add(options_desc());
    // do not print positional arguments as options
    std::cout << "Usage: likeligrid [options] genotypes\n" << std::endl;
    description.print(std::cout);
    throw wtl::ExitSuccess();
}

//! Unit test for each class
inline void test(const int flg) {HERE;
    switch (flg) {
      case 0:
        break;
      case 1:
        ExclusivityModel::unit_test();
        throw wtl::ExitSuccess();
      default:
        throw std::runtime_error("Unknown argument for --test");
    }
}

Program::Program(const std::vector<std::string>& arguments) {HERE;
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.precision(15);
    std::cerr.precision(6);

    auto description = general_desc();
    description.add(options_desc());
    description.add(positional_desc());
    po::positional_options_description positional;
    positional.add("genotypes", 1);
    po::variables_map vm;
    po::store(po::command_line_parser(arguments).
              options(description).
              positional(positional).run(), vm);
    if (vm["help"].as<bool>()) {help_and_exit();}
    po::notify(vm);

    if (vm["verbose"].as<bool>()) {
        std::cerr << wtl::iso8601datetime() << std::endl;
        std::cerr << wtl::flags_into_string(vm) << std::endl;
    }
    test(vm["test"].as<int>());
}

void Program::run() {HERE;
    std::string prefix = "stdin";
    if (GENOTYPES_FILE == "-") {
        GENOTYPES_FILE = "/dev/stdin";
    } else {
        std::smatch mobj;
        std::regex_search(GENOTYPES_FILE, mobj, std::regex("([^/]+?)\\.[^/]+$"));
        prefix = mobj.str(1);
    }
    std::vector<std::string> colnames;
    ExclusivityModel::ArrayXXu matrix;
    if (std::regex_search(GENOTYPES_FILE, std::regex("\\.gz$"))) {
        wtl::igzstream ist(GENOTYPES_FILE);
        colnames = wtl::read_header(ist);
        matrix = wtl::eigen::read_array<size_t>(ist, colnames.size());
    } else {
        std::ifstream ist(GENOTYPES_FILE);
        colnames = wtl::read_header(ist);
        matrix = wtl::eigen::read_array<size_t>(ist, colnames.size());
    }
    std::ostringstream ost;
    ost << prefix << "-s" << MAX_SITES;
    const std::string outdir = ost.str();
    wtl::mkdir(outdir);
    wtl::Pushd cd(outdir);
    ExclusivityModel model(colnames, matrix, MAX_SITES);
    model.run();
    model.search_limits();
}

} // namespace likeligrid
<commit_msg>Use std::unique_ptr<std::istream><commit_after>// -*- mode: c++; coding: utf-8 -*-
/*! @file program.cpp
    @brief Inplementation of Program class
*/
#include "program.hpp"

#include <cstdlib>
#include <memory>
#include <regex>

#include <cxxwtils/debug.hpp>
#include <cxxwtils/iostr.hpp>
#include <cxxwtils/gz.hpp>
#include <cxxwtils/os.hpp>
#include <cxxwtils/getopt.hpp>
#include <cxxwtils/eigen.hpp>

#include "exclusivity.hpp"

namespace likeligrid {

namespace po = boost::program_options;

inline po::options_description general_desc() {HERE;
    po::options_description description("General");
    description.add_options()
        ("help,h", po::value<bool>()->default_value(false)->implicit_value(true), "print this help")
        ("verbose,v", po::value<bool>()->default_value(false)->implicit_value(true), "verbose output")
        ("test", po::value<int>()->default_value(0)->implicit_value(1));
    return description;
}

po::options_description Program::options_desc() {HERE;
    po::options_description description("Program");
    description.add_options()
        ("max-sites,s", po::value(&MAX_SITES)->default_value(MAX_SITES));
    return description;
}

po::options_description Program::positional_desc() {HERE;
    po::options_description description("Positional");
    description.add_options()
        ("genotypes", po::value(&GENOTYPES_FILE)->default_value(GENOTYPES_FILE));
    return description;
}

void Program::help_and_exit() {HERE;
    auto description = general_desc();
    description.add(options_desc());
    // do not print positional arguments as options
    std::cout << "Usage: likeligrid [options] genotypes\n" << std::endl;
    description.print(std::cout);
    throw wtl::ExitSuccess();
}

//! Unit test for each class
inline void test(const int flg) {HERE;
    switch (flg) {
      case 0:
        break;
      case 1:
        ExclusivityModel::unit_test();
        throw wtl::ExitSuccess();
      default:
        throw std::runtime_error("Unknown argument for --test");
    }
}

Program::Program(const std::vector<std::string>& arguments) {HERE;
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.precision(15);
    std::cerr.precision(6);

    auto description = general_desc();
    description.add(options_desc());
    description.add(positional_desc());
    po::positional_options_description positional;
    positional.add("genotypes", 1);
    po::variables_map vm;
    po::store(po::command_line_parser(arguments).
              options(description).
              positional(positional).run(), vm);
    if (vm["help"].as<bool>()) {help_and_exit();}
    po::notify(vm);

    if (vm["verbose"].as<bool>()) {
        std::cerr << wtl::iso8601datetime() << std::endl;
        std::cerr << wtl::flags_into_string(vm) << std::endl;
    }
    test(vm["test"].as<int>());
}

void Program::run() {HERE;
    std::string prefix = "stdin";
    if (GENOTYPES_FILE == "-") {
        GENOTYPES_FILE = "/dev/stdin";
    } else {
        std::smatch mobj;
        std::regex_search(GENOTYPES_FILE, mobj, std::regex("([^/]+?)\\.[^/]+$"));
        prefix = mobj.str(1);
    }
    std::unique_ptr<std::istream> ifp;
    if (std::regex_search(GENOTYPES_FILE, std::regex("\\.gz$"))) {
        ifp = std::make_unique<wtl::igzstream>(GENOTYPES_FILE);
    } else {
        ifp = std::make_unique<std::ifstream>(GENOTYPES_FILE);
    }
    const auto colnames = wtl::read_header(*ifp);
    const auto matrix = wtl::eigen::read_array<size_t>(*ifp, colnames.size());
    std::ostringstream ost;
    ost << prefix << "-s" << MAX_SITES;
    const std::string outdir = ost.str();
    wtl::mkdir(outdir);
    wtl::Pushd cd(outdir);
    ExclusivityModel model(colnames, matrix, MAX_SITES);
    model.run();
    model.search_limits();
}

} // namespace likeligrid
<|endoftext|>


<commit_before><commit_msg>we don't need this include in the header file<commit_after><|endoftext|>


<commit_before>#include "mainwindow.h"
#include "types.h"
#include "connectiontester.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->startButton, SIGNAL(clicked()), this, SLOT(startClicked()));
    connect(ui->actionConnection_does_not_work, SIGNAL(triggered()), this, SLOT(noConnectionClicked()));
    connect(ui->actionConnection_is_slow, SIGNAL(triggered()), this, SLOT(connectionSlowClicked()));
    connect(ui->action_Quit, SIGNAL(triggered()), qApp, SLOT(quit()));

#ifndef Q_OS_MAC // Mac applications don't use icons
    setWindowIcon(QIcon(":/tray.png"));
#endif // Q_OS_MAC

    // No reason to continue when there is no system tray supported
    if (!QSystemTrayIcon::isSystemTrayAvailable())
        return;

    QIcon trayIcon;
#ifdef Q_OS_MAC
    trayIcon.addFile(":/tray_mac.png");
#else // Q_OS_MAC
    trayIcon.addFile(":/tray.png");
#endif // Q_OS_MAC
    m_tray.setIcon(trayIcon);
    m_tray.setContextMenu(ui->menu_File);
    m_tray.setToolTip(tr("mPlane client"));
    m_tray.show();
}

MainWindow::~MainWindow()
{
    m_tray.hide();
    delete ui;
}

void MainWindow::setClient(Client *client)
{
    if (client == m_client)
        return;

    if (m_client) {
        disconnect(m_client.data(), SIGNAL(statusChanged()), this, SLOT(statusChanged()));
    }

    m_client = client;

    if (m_client) {
        connect(m_client.data(), SIGNAL(statusChanged()), this, SLOT(statusChanged()));

        // Update methods
        statusChanged();
    }
}

Client *MainWindow::client() const
{
    return m_client;
}

void MainWindow::startClicked()
{
    // Don't continue when client is no registered
    if (m_client->status() != Client::Registered) {
        return;
    }

    m_client->requestTest();
}

void MainWindow::noConnectionClicked()
{
    ConnectionTester tester;
    connect(&tester, SIGNAL(message(QString,MessageType)), ui->textEdit, SLOT(append(QString)));
    tester.start();
}

void MainWindow::connectionSlowClicked()
{
}

void MainWindow::statusChanged()
{
    ui->startButton->setEnabled( m_client->status() == Client::Registered );
    ui->statusbar->showMessage( enumToString(Client, "Status", m_client->status()) );
}
<commit_msg>Output a line when a manual test has been requested.<commit_after>#include "mainwindow.h"
#include "types.h"
#include "connectiontester.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->startButton, SIGNAL(clicked()), this, SLOT(startClicked()));
    connect(ui->actionConnection_does_not_work, SIGNAL(triggered()), this, SLOT(noConnectionClicked()));
    connect(ui->actionConnection_is_slow, SIGNAL(triggered()), this, SLOT(connectionSlowClicked()));
    connect(ui->action_Quit, SIGNAL(triggered()), qApp, SLOT(quit()));

#ifndef Q_OS_MAC // Mac applications don't use icons
    setWindowIcon(QIcon(":/tray.png"));
#endif // Q_OS_MAC

    // No reason to continue when there is no system tray supported
    if (!QSystemTrayIcon::isSystemTrayAvailable())
        return;

    QIcon trayIcon;
#ifdef Q_OS_MAC
    trayIcon.addFile(":/tray_mac.png");
#else // Q_OS_MAC
    trayIcon.addFile(":/tray.png");
#endif // Q_OS_MAC
    m_tray.setIcon(trayIcon);
    m_tray.setContextMenu(ui->menu_File);
    m_tray.setToolTip(tr("mPlane client"));
    m_tray.show();
}

MainWindow::~MainWindow()
{
    m_tray.hide();
    delete ui;
}

void MainWindow::setClient(Client *client)
{
    if (client == m_client)
        return;

    if (m_client) {
        disconnect(m_client.data(), SIGNAL(statusChanged()), this, SLOT(statusChanged()));
    }

    m_client = client;

    if (m_client) {
        connect(m_client.data(), SIGNAL(statusChanged()), this, SLOT(statusChanged()));

        // Update methods
        statusChanged();
    }
}

Client *MainWindow::client() const
{
    return m_client;
}

void MainWindow::startClicked()
{
    // Don't continue when client is no registered
    if (m_client->status() != Client::Registered) {
        return;
    }

    ui->textEdit->append(tr("Requesting manual test"));

    m_client->requestTest();
}

void MainWindow::noConnectionClicked()
{
    ConnectionTester tester;
    connect(&tester, SIGNAL(message(QString,MessageType)), ui->textEdit, SLOT(append(QString)));
    tester.start();
}

void MainWindow::connectionSlowClicked()
{
}

void MainWindow::statusChanged()
{
    ui->startButton->setEnabled( m_client->status() == Client::Registered );
    ui->statusbar->showMessage( enumToString(Client, "Status", m_client->status()) );
}
<|endoftext|>


<commit_before>#ifndef __MCSCANNER_HPP__
#define __MCSCANNER_HPP__ 1

#if ! defined(yyFlexLexerOnce)
#include <FlexLexer.h>
#endif

#include "mc_parser.tab.hh"
#include "location.hh"

namespace MC{

class MC_Scanner : public yyFlexLexer{
public:

   MC_Scanner(std::istream *in) : yyFlexLexer(in)
   {
      loc = new MC::MC_Parser::location_type();
   };

   //get rid of override virtual function warning
   using FlexLexer::yylex;

   virtual
   int yylex( MC::MC_Parser::semantic_type * const lval,
              MC::MC_Parser::location_type *location );
   // YY_DECL defined in mc_lexer.l
   // Method body created by flex in mc_lexer.yy.cc

private:
   /* yyval ptr */
   MC::MC_Parser::semantic_type *yylval = nullptr;
   /* location ptr */
   MC::MC_Parser::location_type *loc    = nullptr;
};

} /* end namespace MC */

#endif /* END __MCSCANNER_HPP__ */
<commit_msg>This will fix small memory leak<commit_after>#ifndef __MCSCANNER_HPP__
#define __MCSCANNER_HPP__ 1

#if ! defined(yyFlexLexerOnce)
#include <FlexLexer.h>
#endif

#include "mc_parser.tab.hh"
#include "location.hh"

namespace MC{

class MC_Scanner : public yyFlexLexer{
public:

   MC_Scanner(std::istream *in) : yyFlexLexer(in)
   {
      loc = new MC::MC_Parser::location_type();
   };
   virtual ~MC_Scanner() {
      delete loc;
   };

   //get rid of override virtual function warning
   using FlexLexer::yylex;

   virtual
   int yylex( MC::MC_Parser::semantic_type * const lval,
              MC::MC_Parser::location_type *location );
   // YY_DECL defined in mc_lexer.l
   // Method body created by flex in mc_lexer.yy.cc

private:
   /* yyval ptr */
   MC::MC_Parser::semantic_type *yylval = nullptr;
   /* location ptr */
   MC::MC_Parser::location_type *loc    = nullptr;
};

} /* end namespace MC */

#endif /* END __MCSCANNER_HPP__ */
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <string>
#include <iostream>
#include <google/protobuf/message.h>

#include <skullcpp/api.h>
#include "skull_protos.h"
#include "config.h"
#include "cache.h"

using namespace skull::service::dns;

// ====================== Service Init/Release =================================
static
void skull_service_init(skullcpp::Service& service, const skull_config_t* config)
{
    printf("skull service init\n");

    // 1. Convert skull_config to skull_static_config
    skull_static_config_convert(config);

    // 2. Init Cache
    adns::Cache* dnsCache = new adns::Cache();
    service.set(dnsCache);
}

static
void skull_service_release(skullcpp::Service& service)
{
    skull_static_config_destroy();
    printf("skull service release\n");
}

// ====================== Service APIs Calls ===================================
static
void skull_service_query(const skullcpp::Service& service,
                         const google::protobuf::Message& request,
                         google::protobuf::Message& response)
{
    std::cout << "skull service api: query" << std::endl;
    SKULLCPP_LOG_INFO("svc.dns.query-1", "service api: query");

    const adns::Cache* dnsCache = (const adns::Cache*)service.get();
    auto& queryReq = (const query_req&)request;
    auto& queryResp = (query_resp&)response;

    // Try query it from cache first
    const std::string ip = dnsCache->queryFromCache(service, queryReq.domain());

    if (ip.empty()) {
        SKULLCPP_LOG_ERROR("svc.dns.query-2", "dns query from cache failed",
                        "Will query it from dns servers");
        printf("dns query from cache failed\n");
    } else {
        queryResp.set_code(0);
        queryResp.set_ip(ip);
        return;
    }

    // Try query it from DNS
    bool res = dnsCache->queryFromDNS(service, queryReq.domain(), false);
    if (!res) {
        SKULLCPP_LOG_ERROR("svc.dns.query-3", "dns query from dns failed",
                        "Check whether the name server is correct");
        queryResp.set_code(1);
        queryResp.set_error("query dns error");
    }
}

// ====================== Register Service =====================================
static skullcpp::ServiceReadApi api_read_tbl[] = {
    {"query", skull_service_query},
    {NULL, NULL}
};

static skullcpp::ServiceEntry service_entry = {
    skull_service_init,
    skull_service_release,
    api_read_tbl,
    NULL
};

SKULLCPP_SERVICE_REGISTER(&service_entry)
<commit_msg>Refactor config initialization part<commit_after>#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <string>
#include <iostream>
#include <google/protobuf/message.h>

#include <skullcpp/api.h>
#include "skull_protos.h"
#include "config.h"
#include "cache.h"

using namespace skull::service::dns;

// ====================== Service Init/Release =================================
static
void skull_service_init(skullcpp::Service& service, const skull_config_t* config)
{
    printf("skull service init\n");
    skullcpp::Config::instance().load(config);

    // 2. Init Cache
    adns::Cache* dnsCache = new adns::Cache();
    service.set(dnsCache);
}

static
void skull_service_release(skullcpp::Service& service)
{
    printf("skull service release\n");
}

// ====================== Service APIs Calls ===================================
static
void skull_service_query(const skullcpp::Service& service,
                         const google::protobuf::Message& request,
                         google::protobuf::Message& response)
{
    std::cout << "skull service api: query" << std::endl;
    SKULLCPP_LOG_INFO("svc.dns.query-1", "service api: query");

    const adns::Cache* dnsCache = (const adns::Cache*)service.get();
    auto& queryReq = (const query_req&)request;
    auto& queryResp = (query_resp&)response;

    // Try query it from cache first
    const std::string ip = dnsCache->queryFromCache(service, queryReq.domain());

    if (ip.empty()) {
        SKULLCPP_LOG_ERROR("svc.dns.query-2", "dns query from cache failed",
                        "Will query it from dns servers");
        printf("dns query from cache failed\n");
    } else {
        queryResp.set_code(0);
        queryResp.set_ip(ip);
        return;
    }

    // Try query it from DNS
    bool res = dnsCache->queryFromDNS(service, queryReq.domain(), false);
    if (!res) {
        SKULLCPP_LOG_ERROR("svc.dns.query-3", "dns query from dns failed",
                        "Check whether the name server is correct");
        queryResp.set_code(1);
        queryResp.set_error("query dns error");
    }
}

// ====================== Register Service =====================================
static skullcpp::ServiceReadApi api_read_tbl[] = {
    {"query", skull_service_query},
    {NULL, NULL}
};

static skullcpp::ServiceEntry service_entry = {
    skull_service_init,
    skull_service_release,
    api_read_tbl,
    NULL
};

SKULLCPP_SERVICE_REGISTER(&service_entry)
<|endoftext|>


<commit_before>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of TeapotNet.                                     *
 *                                                                       *
 *   TeapotNet 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.                 *
 *                                                                       *
 *   TeapotNet 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 TeapotNet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "splicer.h"
#include "request.h"
#include "pipe.h"
#include "config.h"

namespace tpot
{

Map<ByteString, Splicer::CacheEntry*> Splicer::Cache;
Mutex Splicer::CacheMutex;

Splicer::Splicer(const ByteString &target, int64_t begin, int64_t end) :
	mFirstBlock(0),
	mCurrentBlock(0),
	mBegin(begin),
	mEnd(end),
	mPosition(0)
{
	{
		CacheMutex.lock();
		if(!Cache.get(target, mCacheEntry))
		{
			Log("Splicer", "No cached file, creating a new one");

			try {
				mCacheEntry = new CacheEntry(target);
			}
			catch(...)
			{
				CacheMutex.unlock();
				throw;
			}

			Cache.insert(target, mCacheEntry);
		}

		Map<ByteString, CacheEntry*>::iterator it = Cache.begin();
		while(it != Cache.end())
		{
			if(!it->second || Time::Now() - it->second->lastAccessTime() > 3600)
				Cache.erase(it++);
			else it++;
		}

		CacheMutex.unlock();
	}

	Set<Identifier> sources;
	mCacheEntry->getSources(sources);
	if(sources.empty())
		throw Exception("No sources found for " + target.toString());

	// OK, the cache entry is initialized

	// Initialize variables
	mBegin = bounds(mBegin, int64_t(0), mCacheEntry->size());
	if(mEnd < 0) mEnd = mCacheEntry->size();
	else mEnd = bounds(mEnd, mBegin, mCacheEntry->size());
	mPosition = mBegin;

	mCurrentBlock = mCacheEntry->block(mBegin);
	mFirstBlock = mCurrentBlock;
	while(mCacheEntry->isBlockFinished(mFirstBlock))
		++mFirstBlock;

	//Log("Splicer", "Starting for " + mCacheEntry->name() + " [" + String::number(mBegin) + "," + String::number(mEnd) + "]");

	// Request stripes
	int nbStripes = std::max(1, int(sources.size()));	// TODO

	if(!finished())
	{
		mRequests.fill(NULL, nbStripes);
        	mStripes.fill(NULL, nbStripes);

		Set<Identifier>::iterator it = sources.begin();
		int i = 0;
		while(i<nbStripes)
		{
			if(!query(i, *it))
			{
				mCacheEntry->refreshSources();
				mCacheEntry->getSources(sources);
				it = sources.begin();

				if(sources.empty())
					throw Exception("No sources found for " + target.toString());

				continue;
			}

			++i; ++it;
			if(it == sources.end()) it = sources.begin();
		}

		//Log("Splicer", "Transfers launched successfully");
	}
}

Splicer::~Splicer(void)
{
	close();
}

const String &Splicer::name(void) const
{
	return mCacheEntry->name();
}

int64_t Splicer::size(void) const
{
	return mEnd - mBegin;
}

int64_t Splicer::begin(void) const
{
	return mBegin;
}

int64_t Splicer::end(void) const
{
	return mEnd;
}

bool Splicer::finished(void) const
{
	return mCacheEntry->finished();
}

int64_t Splicer::process(ByteStream *output)
{
	int64_t written = 0;

	mCacheEntry->setAccessTime();
	unsigned currentBlock = mCacheEntry->block(mCacheEntry->size());
	int nbPending = 0;
	for(int i=0; i<mRequests.size(); ++i)
	{
		Assert(mRequests[i]);
		Assert(mStripes[i]);
		Synchronize(mRequests[i]);

		if(mRequests[i]->responsesCount())
		{
			const Request::Response *response = mRequests[i]->response(0);
			Assert(response != NULL);
			if(response->finished()) continue;
		}

		//std::cout<<i<<" -> "<<mStripes[i]->tellWriteBlock()<<std::endl;
		currentBlock = std::min(currentBlock, mStripes[i]->tellWriteBlock());
		mStripes[i]->flush();
		++nbPending;
	}

	if(!nbPending) ++currentBlock;

	while(mCurrentBlock < currentBlock)
	{
		mCacheEntry->markBlockFinished(mCurrentBlock);

		if(output && mPosition < mEnd)
		{
			// Open file to read
        		File file(mCacheEntry->fileName(), File::Read);
        		file.seekRead(mPosition);

			size_t size = size_t(std::min(int64_t(mCacheEntry->blockSize()), mEnd-mPosition));
			Assert(size == file.readBinary(*output, size));
			mPosition+= size;
			written+= size;

			file.close();
			if(mPosition == mEnd) return written;
		}

		++mCurrentBlock;
	}

	std::vector<int>		onError;
	std::multimap<unsigned, int> 	byBlocks;

	for(int i=0; i<mRequests.size(); ++i)
	{
		Assert(mRequests[i]);
		Assert(mStripes[i]);
		Synchronize(mRequests[i]);

		byBlocks.insert(std::pair<unsigned,int>(mStripes[i]->tellWriteBlock(), i));

		if(mRequests[i]->responsesCount())
		{
			const Request::Response *response = mRequests[i]->response(0);
			Assert(response != NULL);

			if(response->error())
				onError.push_back(i);
		}
	}

	if(onError.empty())
	{
		if(mRequests.size() >= 2)
		{
			int slowest = byBlocks.begin()->second;
			int fastest = byBlocks.rbegin()->second;
			if(mRequests[fastest]->receiver() != mRequests[slowest]->receiver())
			{
				if((mStripes[fastest]->tellWriteBlock()-mFirstBlock) > 2*(mStripes[slowest]->tellWriteBlock()-mFirstBlock) + 2)
					query(slowest, mRequests[fastest]->receiver());
			}
		}
	}
	else for(int k=0; k<onError.size(); ++k)
	{
		int i = onError[k];
		Log("Splicer::process", String("Error on request ") + String::number(i));

		Identifier formerSource = mRequests[i]->receiver();
		Identifier source;
		Map<unsigned, int>::reverse_iterator it = byBlocks.rbegin();
		while(true)
		{
			source = mRequests[it->second]->receiver();
			if(source != formerSource) break;
			++it;
			if(it == byBlocks.rend())
			{
				Set<Identifier> sources;
				mCacheEntry->refreshSources();
				mCacheEntry->getSources(sources);

				if(sources.empty())
				{
					msleep(30000);
					return written;
				}

				if(sources.find(formerSource) != sources.end())
				{
					if(sources.size()> 1) sources.erase(formerSource);
					else msleep(30000);
				}

				Set<Identifier>::iterator jt = sources.begin();
				int r = rand() % sources.size();
				for(int i=0; i<r; ++i) jt++;
				source = *jt;
				break;
			}
		}

		query(i, source);
	}

	return written;
}

void Splicer::close(void)
{
	if(!mRequests.empty())
	{
		for(int i=0; i<mRequests.size(); ++i)
			delete mRequests[i];

		mRequests.clear();
	}

	// Deleting the requests deletes the responses
	// Deleting the responses deletes the contents
	// So the stripes are already deleted

	mStripes.clear();
}

bool Splicer::query(int i, const Identifier &source)
{
	Assert(i < mRequests.size());
	Assert(i < mStripes.size());

	int nbStripes = mStripes.size();
	unsigned block = mFirstBlock;
	size_t offset = 0;

	if(mStripes[i])
	{
		block = std::max(block, mStripes[i]->tellWriteBlock());
		mStripes[i]->flush();
	}

	if(mRequests[i]) delete mRequests[i];
	mStripes[i] = NULL;
	mRequests[i] = NULL;

	File *file = new File(mCacheEntry->fileName(), File::ReadWrite);
	StripedFile *striped = new StripedFile(file, mCacheEntry->blockSize(), nbStripes, i);
	striped->seekWrite(block, offset);
	mStripes[i] = striped;

	StringMap parameters;
	parameters["block-size"] << mCacheEntry->blockSize();
	parameters["stripes-count"] << nbStripes;
	parameters["stripe"] << i;
	parameters["block"] << block;
	parameters["offset"] << offset;

	Request *request = new Request;
	request->setTarget(mCacheEntry->target().toString(),true);
	request->setParameters(parameters);
	request->setContentSink(striped);

	try {
		request->submit(source);
	}
	catch(...)
	{
		return false;
	}

	mRequests[i] = request;
	return true;
}

Splicer::CacheEntry::CacheEntry(const ByteString &target) :
	mTarget(target),
	mSize(0),
	mBlockSize(128*1024),	// TODO
	mTime(Time::Now())
{
	mFileName = File::TempName();
	File dummy(mFileName, File::TruncateReadWrite);
	dummy.close();
}

Splicer::CacheEntry::~CacheEntry(void)
{
	File::Remove(mFileName);
}

const ByteString &Splicer::CacheEntry::target(void) const
{
	Synchronize(this);
	return mTarget;
}

const String &Splicer::CacheEntry::fileName(void) const
{
	Synchronize(this);
	return mFileName;
}

const String &Splicer::CacheEntry::name(void) const
{
	Synchronize(this);
	return mName;
}

int64_t Splicer::CacheEntry::size(void) const
{
	Synchronize(this);
	return mSize;
}

size_t Splicer::CacheEntry::blockSize(void) const
{
	Synchronize(this);
	return mBlockSize;
}

bool Splicer::CacheEntry::finished(void) const
{
	Synchronize(this);
	if(mFinishedBlocks.size() < (mSize + mBlockSize - 1) / mBlockSize) return false;
	if(std::find(mFinishedBlocks.begin(), mFinishedBlocks.end(), false) != mFinishedBlocks.end()) return false;
	return true;
}

Time Splicer::CacheEntry::lastAccessTime(void) const
{
	Synchronize(this);
	return mTime;
}

void Splicer::CacheEntry::setAccessTime(void)
{
	Synchronize(this);
	mTime = Time::Now();
}

unsigned Splicer::CacheEntry::block(int64_t position) const
{
	Synchronize(this);
	return unsigned(position / int64_t(mBlockSize));
}

bool Splicer::CacheEntry::getSources(Set<Identifier> &sources)
{
	Synchronize(this);
	if(mSources.empty()) refreshSources();
	sources = mSources;
	return !sources.empty();
}

void Splicer::CacheEntry::refreshSources(void)
{
	Synchronize(this);

	Log("Splicer", "Requesting available sources...");

	const unsigned timeout = Config::Get("request_timeout").toInt();

	Request request(mTarget.toString(), false);
	request.submit();
	DesynchronizeStatement(this, request.wait(timeout));

	{
		Synchronize(&request);
		mSources.clear();
		for(int i=0; i<request.responsesCount(); ++i)
		{
			Request::Response *response = request.response(i);
			const StringMap &parameters = response->parameters();

			if(!response->error())
			{
				if(mName.empty() && parameters.contains("name"))
					mName = parameters.get("name");

				// TODO: check size
				if(mSize == 0 && parameters.contains("size"))
					parameters.get("size").extract(mSize);

				mSources.insert(response->peering());
			}
		}
	}

	if(mName.empty()) throw Exception("Unable to retrieve the file name");

	Log("Splicer", "Found " + String::number(int(mSources.size())) + " sources");
}

bool Splicer::CacheEntry::isBlockFinished(unsigned block) const
{
	Synchronize(this);

	if(block >= mFinishedBlocks.size()) return false;
	return mFinishedBlocks[block];
}

bool Splicer::CacheEntry::markBlockFinished(unsigned block)
{
	Synchronize(this);

	if(block >= mFinishedBlocks.size())
	{
		unsigned i = mFinishedBlocks.size();
		mFinishedBlocks.resize(block+1);
		while(i < mFinishedBlocks.size()-1)
		{
			mFinishedBlocks[i] = false;
			++i;
		}
	}

	mFinishedBlocks[block] = true;
}

}
<commit_msg>Fixed<commit_after>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of TeapotNet.                                     *
 *                                                                       *
 *   TeapotNet 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.                 *
 *                                                                       *
 *   TeapotNet 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 TeapotNet.                                       *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "splicer.h"
#include "request.h"
#include "pipe.h"
#include "config.h"

namespace tpot
{

Map<ByteString, Splicer::CacheEntry*> Splicer::Cache;
Mutex Splicer::CacheMutex;

Splicer::Splicer(const ByteString &target, int64_t begin, int64_t end) :
	mFirstBlock(0),
	mCurrentBlock(0),
	mBegin(begin),
	mEnd(end),
	mPosition(0)
{
	{
		CacheMutex.lock();
		if(!Cache.get(target, mCacheEntry))
		{
			Log("Splicer", "No cached file, creating a new one");

			try {
				mCacheEntry = new CacheEntry(target);
			}
			catch(...)
			{
				CacheMutex.unlock();
				throw;
			}

			Cache.insert(target, mCacheEntry);
		}

		Map<ByteString, CacheEntry*>::iterator it = Cache.begin();
		while(it != Cache.end())
		{
			if(!it->second || Time::Now() - it->second->lastAccessTime() > 3600)
				Cache.erase(it++);
			else it++;
		}

		CacheMutex.unlock();
	}

	Set<Identifier> sources;
	mCacheEntry->getSources(sources);
	if(sources.empty())
		throw Exception("No sources found for " + target.toString());

	// OK, the cache entry is initialized

	// Initialize variables
	mBegin = bounds(mBegin, int64_t(0), mCacheEntry->size());
	if(mEnd < 0) mEnd = mCacheEntry->size();
	else mEnd = bounds(mEnd, mBegin, mCacheEntry->size());
	mPosition = mBegin;

	mCurrentBlock = mCacheEntry->block(mBegin);
	mFirstBlock = mCurrentBlock;
	while(mCacheEntry->isBlockFinished(mFirstBlock))
		++mFirstBlock;

	//Log("Splicer", "Starting for " + mCacheEntry->name() + " [" + String::number(mBegin) + "," + String::number(mEnd) + "]");

	// Request stripes
	int nbStripes = std::max(1, int(sources.size()));	// TODO

	if(!finished())
	{
		mRequests.fill(NULL, nbStripes);
        	mStripes.fill(NULL, nbStripes);

		Set<Identifier>::iterator it = sources.begin();
		int i = 0;
		while(i<nbStripes)
		{
			if(!query(i, *it))
			{
				mCacheEntry->refreshSources();
				mCacheEntry->getSources(sources);
				it = sources.begin();

				if(sources.empty())
					throw Exception("No sources found for " + target.toString());

				continue;
			}

			++i; ++it;
			if(it == sources.end()) it = sources.begin();
		}

		//Log("Splicer", "Transfers launched successfully");
	}
}

Splicer::~Splicer(void)
{
	close();
}

const String &Splicer::name(void) const
{
	return mCacheEntry->name();
}

int64_t Splicer::size(void) const
{
	return mEnd - mBegin;
}

int64_t Splicer::begin(void) const
{
	return mBegin;
}

int64_t Splicer::end(void) const
{
	return mEnd;
}

bool Splicer::finished(void) const
{
	return mCacheEntry->finished();
}

int64_t Splicer::process(ByteStream *output)
{
	int64_t written = 0;

	mCacheEntry->setAccessTime();
	unsigned currentBlock = mCacheEntry->block(mCacheEntry->size());
	int nbPending = 0;
	for(int i=0; i<mRequests.size(); ++i)
	{
		Assert(mRequests[i]);
		Assert(mStripes[i]);
		Synchronize(mRequests[i]);

		if(mRequests[i]->responsesCount())
		{
			const Request::Response *response = mRequests[i]->response(0);
			Assert(response != NULL);
			if(response->finished()) continue;
		}

		//std::cout<<i<<" -> "<<mStripes[i]->tellWriteBlock()<<std::endl;
		currentBlock = std::min(currentBlock, mStripes[i]->tellWriteBlock());
		mStripes[i]->flush();
		++nbPending;
	}

	if(!nbPending) ++currentBlock;
	else if(currentBlock > 0) --currentBlock;

	while(mCurrentBlock < currentBlock)
	{
		mCacheEntry->markBlockFinished(mCurrentBlock);

		if(output && mPosition < mEnd)
		{
			// Open file to read
        		File file(mCacheEntry->fileName(), File::Read);
        		file.seekRead(mPosition);

			size_t size = size_t(std::min(int64_t(mCacheEntry->blockSize()), mEnd-mPosition));
			Assert(size == file.readBinary(*output, size));
			mPosition+= size;
			written+= size;

			file.close();
			if(mPosition == mEnd) return written;
		}

		++mCurrentBlock;
	}

	std::vector<int>		onError;
	std::multimap<unsigned, int> 	byBlocks;

	for(int i=0; i<mRequests.size(); ++i)
	{
		Assert(mRequests[i]);
		Assert(mStripes[i]);
		Synchronize(mRequests[i]);

		byBlocks.insert(std::pair<unsigned,int>(mStripes[i]->tellWriteBlock(), i));

		if(mRequests[i]->responsesCount())
		{
			const Request::Response *response = mRequests[i]->response(0);
			Assert(response != NULL);

			if(response->error())
				onError.push_back(i);
		}
	}

	if(onError.empty())
	{
		if(mRequests.size() >= 2)
		{
			int slowest = byBlocks.begin()->second;
			int fastest = byBlocks.rbegin()->second;
			if(mRequests[fastest]->receiver() != mRequests[slowest]->receiver())
			{
				if((mStripes[fastest]->tellWriteBlock()-mFirstBlock) > 2*(mStripes[slowest]->tellWriteBlock()-mFirstBlock) + 2)
					query(slowest, mRequests[fastest]->receiver());
			}
		}
	}
	else for(int k=0; k<onError.size(); ++k)
	{
		int i = onError[k];
		Log("Splicer::process", String("Error on request ") + String::number(i));

		Identifier formerSource = mRequests[i]->receiver();
		Identifier source;
		Map<unsigned, int>::reverse_iterator it = byBlocks.rbegin();
		while(true)
		{
			source = mRequests[it->second]->receiver();
			if(source != formerSource) break;
			++it;
			if(it == byBlocks.rend())
			{
				Set<Identifier> sources;
				mCacheEntry->refreshSources();
				mCacheEntry->getSources(sources);

				if(sources.empty())
				{
					msleep(30000);
					return written;
				}

				if(sources.find(formerSource) != sources.end())
				{
					if(sources.size()> 1) sources.erase(formerSource);
					else msleep(30000);
				}

				Set<Identifier>::iterator jt = sources.begin();
				int r = rand() % sources.size();
				for(int i=0; i<r; ++i) jt++;
				source = *jt;
				break;
			}
		}

		query(i, source);
	}

	return written;
}

void Splicer::close(void)
{
	if(!mRequests.empty())
	{
		for(int i=0; i<mRequests.size(); ++i)
			delete mRequests[i];

		mRequests.clear();
	}

	// Deleting the requests deletes the responses
	// Deleting the responses deletes the contents
	// So the stripes are already deleted

	mStripes.clear();
}

bool Splicer::query(int i, const Identifier &source)
{
	Assert(i < mRequests.size());
	Assert(i < mStripes.size());

	int nbStripes = mStripes.size();
	unsigned block = mFirstBlock;
	size_t offset = 0;

	if(mStripes[i])
	{
		block = std::max(block, mStripes[i]->tellWriteBlock());
		mStripes[i]->flush();
	}

	if(mRequests[i]) delete mRequests[i];
	mStripes[i] = NULL;
	mRequests[i] = NULL;

	File *file = new File(mCacheEntry->fileName(), File::ReadWrite);
	StripedFile *striped = new StripedFile(file, mCacheEntry->blockSize(), nbStripes, i);
	striped->seekWrite(block, offset);
	mStripes[i] = striped;

	StringMap parameters;
	parameters["block-size"] << mCacheEntry->blockSize();
	parameters["stripes-count"] << nbStripes;
	parameters["stripe"] << i;
	parameters["block"] << block;
	parameters["offset"] << offset;

	Request *request = new Request;
	request->setTarget(mCacheEntry->target().toString(),true);
	request->setParameters(parameters);
	request->setContentSink(striped);

	try {
		request->submit(source);
	}
	catch(...)
	{
		return false;
	}

	mRequests[i] = request;
	return true;
}

Splicer::CacheEntry::CacheEntry(const ByteString &target) :
	mTarget(target),
	mSize(0),
	mBlockSize(128*1024),	// TODO
	mTime(Time::Now())
{
	mFileName = File::TempName();
	File dummy(mFileName, File::TruncateReadWrite);
	dummy.close();
}

Splicer::CacheEntry::~CacheEntry(void)
{
	File::Remove(mFileName);
}

const ByteString &Splicer::CacheEntry::target(void) const
{
	Synchronize(this);
	return mTarget;
}

const String &Splicer::CacheEntry::fileName(void) const
{
	Synchronize(this);
	return mFileName;
}

const String &Splicer::CacheEntry::name(void) const
{
	Synchronize(this);
	return mName;
}

int64_t Splicer::CacheEntry::size(void) const
{
	Synchronize(this);
	return mSize;
}

size_t Splicer::CacheEntry::blockSize(void) const
{
	Synchronize(this);
	return mBlockSize;
}

bool Splicer::CacheEntry::finished(void) const
{
	Synchronize(this);
	if(mFinishedBlocks.size() < (mSize + mBlockSize - 1) / mBlockSize) return false;
	if(std::find(mFinishedBlocks.begin(), mFinishedBlocks.end(), false) != mFinishedBlocks.end()) return false;
	return true;
}

Time Splicer::CacheEntry::lastAccessTime(void) const
{
	Synchronize(this);
	return mTime;
}

void Splicer::CacheEntry::setAccessTime(void)
{
	Synchronize(this);
	mTime = Time::Now();
}

unsigned Splicer::CacheEntry::block(int64_t position) const
{
	Synchronize(this);
	return unsigned(position / int64_t(mBlockSize));
}

bool Splicer::CacheEntry::getSources(Set<Identifier> &sources)
{
	Synchronize(this);
	if(mSources.empty()) refreshSources();
	sources = mSources;
	return !sources.empty();
}

void Splicer::CacheEntry::refreshSources(void)
{
	Synchronize(this);

	Log("Splicer", "Requesting available sources...");

	const unsigned timeout = Config::Get("request_timeout").toInt();

	Request request(mTarget.toString(), false);
	request.submit();
	DesynchronizeStatement(this, request.wait(timeout));

	{
		Synchronize(&request);
		mSources.clear();
		for(int i=0; i<request.responsesCount(); ++i)
		{
			Request::Response *response = request.response(i);
			const StringMap &parameters = response->parameters();

			if(!response->error())
			{
				if(mName.empty() && parameters.contains("name"))
					mName = parameters.get("name");

				// TODO: check size
				if(mSize == 0 && parameters.contains("size"))
					parameters.get("size").extract(mSize);

				mSources.insert(response->peering());
			}
		}
	}

	if(mName.empty()) throw Exception("Unable to retrieve the file name");

	Log("Splicer", "Found " + String::number(int(mSources.size())) + " sources");
}

bool Splicer::CacheEntry::isBlockFinished(unsigned block) const
{
	Synchronize(this);

	if(block >= mFinishedBlocks.size()) return false;
	return mFinishedBlocks[block];
}

bool Splicer::CacheEntry::markBlockFinished(unsigned block)
{
	Synchronize(this);

	if(block >= mFinishedBlocks.size())
	{
		unsigned i = mFinishedBlocks.size();
		mFinishedBlocks.resize(block+1);
		while(i < mFinishedBlocks.size()-1)
		{
			mFinishedBlocks[i] = false;
			++i;
		}
	}

	mFinishedBlocks[block] = true;
}

}
<|endoftext|>