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

#include <folly/Range.h>

#include <gtest/gtest.h>
#include <algorithm>

using namespace std;
using namespace folly;

TEST(CaseInsensitiveMatch, CompareWithLegacy) {
  AsciiCaseInsensitive cmp;
  for (int i=0; i<(1<<8); i++) {
    EXPECT_TRUE(cmp(tolower(i), toupper(i)));
    EXPECT_TRUE(cmp(toupper(i), tolower(i)));
  }
}

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  return RUN_ALL_TESTS();
}
<commit_msg>Add missing #include <gflags/gflags.h><commit_after>/*
 * Copyright 2015 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <folly/Range.h>

#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include <algorithm>

using namespace std;
using namespace folly;

TEST(CaseInsensitiveMatch, CompareWithLegacy) {
  AsciiCaseInsensitive cmp;
  for (int i=0; i<(1<<8); i++) {
    EXPECT_TRUE(cmp(tolower(i), toupper(i)));
    EXPECT_TRUE(cmp(toupper(i), tolower(i)));
  }
}

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

Derived MPC for flow and energy.  This couples using a block-diagonal coupler.
------------------------------------------------------------------------- */

#include "wrm_richards_evaluator.hh"
#include "mpc_frozen_prec_coupled_flow_energy.hh"

namespace Amanzi {

#define DEBUG_FLAG 0

RegisteredPKFactory<MPCFrozenCoupledFlowEnergy> MPCFrozenCoupledFlowEnergy::reg_("frozen energy-flow preconditioner coupled");

bool MPCFrozenCoupledFlowEnergy::modify_predictor(double h, Teuchos::RCP<TreeVector> u) {
  Teuchos::RCP<CompositeVector> temp_guess = u->SubVector("energy")->data();
  Epetra_MultiVector& guess_cells = *temp_guess->ViewComponent("cell",false);
  Epetra_MultiVector& guess_faces = *temp_guess->ViewComponent("face",false);

  Teuchos::RCP<const CompositeVector> temp = S_next_->GetFieldData("temperature");
  const Epetra_MultiVector& temp_cells = *temp->ViewComponent("cell",false);

  bool update_faces(false);

#if DEBUG_FLAG
  std::cout << "--- Modifying Guess: ---" << std::cout;
#endif

  int ncells = temp->size("cell",false);
  std::vector<bool> changed(ncells, false);
  for (int c=0; c!=ncells; ++c) {
    if (temp_cells[0][c] >= 273.15 && guess_cells[0][c] < 273.15) {
      // freezing
      guess_cells[0][c] = 273.15 - 1.e-4;
      changed[c] = true;
      update_faces = true;
    } else if (temp_cells[0][c] <= 273.15 && guess_cells[0][c] > 273.15) {
      // thawing
      guess_cells[0][c] = 273.15 - 1.e-3;
      changed[c] = true;
      update_faces = true;
    } else if (273.15 > temp_cells[0][c] &&
               temp_cells[0][c] >= 273.1 &&
               (temp_cells[0][c] - guess_cells[0][c]) > 1.e-2) {
      // catch the 2nd step in freezing -- after the 2nd step the
      // extrapolation should be ok?
      guess_cells[0][c] = temp_cells[0][c];
      changed[c] = true;
      update_faces = true;
    }
  }

  if (update_faces) {
    temp_guess->ScatterMasterToGhosted("cell");
    AmanziMesh::Entity_ID_List cells;

    int f_owned = temp_guess->size("face");
    for (int f=0; f!=f_owned; ++f) {
      cells.clear();
      temp_guess->mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
      if (cells.size() == 2) {
        if (changed[cells[0]] || changed[cells[1]]) {
          guess_faces[0][f] = (guess_cells[0][cells[0]]
                  + guess_cells[0][cells[1]]) / 2.0;
        }
      }
    }
    return true;
  }
  return false;
}

bool MPCFrozenCoupledFlowEnergy::modify_predictor_temp(double h, Teuchos::RCP<TreeVector> u) {
  // modification of the initial guess occurs by updating T using this guess,
  // then calculating the p that would be required to keep the same water
  // mass.

  // Stuff temperature into state
  Teuchos::RCP<TreeVector> uT = u->SubVector("energy");
  sub_pks_[1]->changed_solution();

#if DEBUG_FLAG
  std::cout << std::endl;
  std::cout << "Modifying guess:" << std::endl;
  std::cout << "  T0: " << (*uT->data())("cell",0) << std::endl;
  std::cout << "  T1: " << (*uT->data())("cell",99) << std::endl;
#endif

  // update water content, which will get all the needed vals updated at the new temp.
  S_next_->GetFieldEvaluator("water_content")
      ->HasFieldChanged(S_next_.ptr(), "richards_pk");

  // get the needed vals
  Teuchos::RCP<const CompositeVector> wc0 = S_inter_->GetFieldData("water_content");
  Teuchos::RCP<const CompositeVector> cv = S_inter_->GetFieldData("cell_volume");
  Teuchos::RCP<const CompositeVector> phi = S_next_->GetFieldData("porosity");
  Teuchos::RCP<const CompositeVector> n_g = S_next_->GetFieldData("molar_density_gas");
  Teuchos::RCP<const CompositeVector> omega_g = S_next_->GetFieldData("mol_frac_gas");
  Teuchos::RCP<const CompositeVector> n_l = S_next_->GetFieldData("molar_density_liquid");
  Teuchos::RCP<const CompositeVector> n_i = S_next_->GetFieldData("molar_density_ice");
  Teuchos::RCP<const CompositeVector> one_on_A = S_next_->GetFieldData("wrm_permafrost_one_on_A");
  Teuchos::RCP<const double> p_atm = S_next_->GetScalarData("atmospheric_pressure");

  // get the WRMs
  Teuchos::RCP<FieldEvaluator> wrm_B_eval_base = S_next_->GetFieldEvaluator("wrm_permafrost_one_on_B");
  Teuchos::RCP<Flow::FlowRelations::WRMRichardsEvaluator> wrm_B_eval =
      Teuchos::rcp_dynamic_cast<Flow::FlowRelations::WRMRichardsEvaluator>(wrm_B_eval_base);
  Teuchos::RCP<Flow::FlowRelations::WRMRegionPairList> wrms = wrm_B_eval->get_WRMs();

  // get the result pressure
  Teuchos::RCP<CompositeVector> pres = u->SubVector("flow")->data();
  for (Flow::FlowRelations::WRMRegionPairList::iterator region=wrms->begin();
       region!=wrms->end(); ++region) {
    std::string name = region->first;
    int ncells = pres->mesh()->get_set_size(name, AmanziMesh::CELL, AmanziMesh::OWNED);
    AmanziMesh::Entity_ID_List cells(ncells);
    pres->mesh()->get_set_entities(name, AmanziMesh::CELL, AmanziMesh::OWNED, &cells);

    for (AmanziMesh::Entity_ID_List::iterator c=cells.begin(); c!=cells.end(); ++c) {
      double p = (*pres)("cell",*c);
      double A_minus_one = (1.0/(*one_on_A)("cell",*c) - 1.0);

      double wc = (*wc0)("cell",*c) / (*cv)("cell",*c);
      double sstar = (wc - (*n_g)("cell",*c)*(*omega_g)("cell",*c)*(*phi)("cell",*c)) /
          ((*phi)("cell",*c) * ((*n_l)("cell",*c) - (*n_g)("cell",*c)*(*omega_g)("cell",*c)
                  + (*n_i)("cell",*c)*A_minus_one) - A_minus_one*wc);

      if (sstar > 0.) {
        if (*c==0) std::cout << "   A-1(0) = " << A_minus_one << std::endl;
        if (*c==99) std::cout << "   A-1(99) = " << A_minus_one << std::endl;
        if (*c==0) std::cout << "   S*(0) = " << sstar << std::endl;
        if (*c==99) std::cout << "   S*(99) = " << sstar << std::endl;

        double pc = region->second->capillaryPressure(sstar);

        if (*c==0) std::cout << "   pc(0) = " << pc << std::endl;
        if (*c==99) std::cout << "   pc(99) = " << pc << std::endl;

        (*pres)("cell",*c) = *p_atm - pc;

        if (*c==0) std::cout << "   p(0) = " << (*pres)("cell",*c) << std::endl;
        if (*c==99) std::cout << "   p(99) = " <<  (*pres)("cell",*c) << std::endl;

      }
    }
  }

  AmanziMesh::Entity_ID_List cells;
  pres->ScatterMasterToGhosted("cell");

  int f_owned = pres->size("face");
  for (int f=0; f!=f_owned; ++f) {
    cells.clear();
    pres->mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
    int ncells = cells.size();

    double face_value = 0.0;
    for (int n=0; n!=ncells; ++n) {
      face_value += (*pres)("cell",cells[n]);
    }
    (*pres)("face",f) = face_value / ncells;
  }

  return true;
};

} // namespace
<commit_msg>fixes race condition from last commit<commit_after>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */
/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

Derived MPC for flow and energy.  This couples using a block-diagonal coupler.
------------------------------------------------------------------------- */

#include "wrm_richards_evaluator.hh"
#include "mpc_frozen_prec_coupled_flow_energy.hh"

namespace Amanzi {

#define DEBUG_FLAG 0

RegisteredPKFactory<MPCFrozenCoupledFlowEnergy> MPCFrozenCoupledFlowEnergy::reg_("frozen energy-flow preconditioner coupled");

bool MPCFrozenCoupledFlowEnergy::modify_predictor(double h, Teuchos::RCP<TreeVector> u) {
  Teuchos::RCP<CompositeVector> temp_guess = u->SubVector("energy")->data();
  Epetra_MultiVector& guess_cells = *temp_guess->ViewComponent("cell",false);
  Epetra_MultiVector& guess_faces = *temp_guess->ViewComponent("face",false);

  Teuchos::RCP<const CompositeVector> temp = S_next_->GetFieldData("temperature");
  const Epetra_MultiVector& temp_cells = *temp->ViewComponent("cell",false);

  bool update_faces(false);

#if DEBUG_FLAG
  std::cout << "--- Modifying Guess: ---" << std::cout;
#endif

  int ncells = temp->size("cell",false);
  std::vector<bool> changed(ncells, false);
  for (int c=0; c!=ncells; ++c) {
    if (temp_cells[0][c] >= 273.15 && guess_cells[0][c] < 273.15) {
      // freezing
      guess_cells[0][c] = 273.15 - 1.e-4;
      changed[c] = true;
      update_faces = true;
    } else if (temp_cells[0][c] <= 273.15 && guess_cells[0][c] > 273.15) {
      // thawing
      guess_cells[0][c] = 273.15 - 1.e-3;
      changed[c] = true;
      update_faces = true;
    } else if (273.15 > temp_cells[0][c] &&
               temp_cells[0][c] >= 273.1 &&
               (temp_cells[0][c] - guess_cells[0][c]) > 1.e-2) {
      // catch the 2nd step in freezing -- after the 2nd step the
      // extrapolation should be ok?
      guess_cells[0][c] = temp_cells[0][c];
      changed[c] = true;
      update_faces = true;
    }
  }

  // unclear... could do an AllReduce() on update_faces and not communicate if
  // not necessary, but AllReduces() suck... maybe more than extra Scatters?
  temp_guess->ScatterMasterToGhosted("cell");
  if (update_faces) {
    AmanziMesh::Entity_ID_List cells;

    int f_owned = temp_guess->size("face");
    for (int f=0; f!=f_owned; ++f) {
      cells.clear();
      temp_guess->mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
      if (cells.size() == 2) {
        if (changed[cells[0]] || changed[cells[1]]) {
          guess_faces[0][f] = (guess_cells[0][cells[0]]
                  + guess_cells[0][cells[1]]) / 2.0;
        }
      }
    }
    return true;
  }
  return false;
}

bool MPCFrozenCoupledFlowEnergy::modify_predictor_temp(double h, Teuchos::RCP<TreeVector> u) {
  // modification of the initial guess occurs by updating T using this guess,
  // then calculating the p that would be required to keep the same water
  // mass.

  // Stuff temperature into state
  Teuchos::RCP<TreeVector> uT = u->SubVector("energy");
  sub_pks_[1]->changed_solution();

#if DEBUG_FLAG
  std::cout << std::endl;
  std::cout << "Modifying guess:" << std::endl;
  std::cout << "  T0: " << (*uT->data())("cell",0) << std::endl;
  std::cout << "  T1: " << (*uT->data())("cell",99) << std::endl;
#endif

  // update water content, which will get all the needed vals updated at the new temp.
  S_next_->GetFieldEvaluator("water_content")
      ->HasFieldChanged(S_next_.ptr(), "richards_pk");

  // get the needed vals
  Teuchos::RCP<const CompositeVector> wc0 = S_inter_->GetFieldData("water_content");
  Teuchos::RCP<const CompositeVector> cv = S_inter_->GetFieldData("cell_volume");
  Teuchos::RCP<const CompositeVector> phi = S_next_->GetFieldData("porosity");
  Teuchos::RCP<const CompositeVector> n_g = S_next_->GetFieldData("molar_density_gas");
  Teuchos::RCP<const CompositeVector> omega_g = S_next_->GetFieldData("mol_frac_gas");
  Teuchos::RCP<const CompositeVector> n_l = S_next_->GetFieldData("molar_density_liquid");
  Teuchos::RCP<const CompositeVector> n_i = S_next_->GetFieldData("molar_density_ice");
  Teuchos::RCP<const CompositeVector> one_on_A = S_next_->GetFieldData("wrm_permafrost_one_on_A");
  Teuchos::RCP<const double> p_atm = S_next_->GetScalarData("atmospheric_pressure");

  // get the WRMs
  Teuchos::RCP<FieldEvaluator> wrm_B_eval_base = S_next_->GetFieldEvaluator("wrm_permafrost_one_on_B");
  Teuchos::RCP<Flow::FlowRelations::WRMRichardsEvaluator> wrm_B_eval =
      Teuchos::rcp_dynamic_cast<Flow::FlowRelations::WRMRichardsEvaluator>(wrm_B_eval_base);
  Teuchos::RCP<Flow::FlowRelations::WRMRegionPairList> wrms = wrm_B_eval->get_WRMs();

  // get the result pressure
  Teuchos::RCP<CompositeVector> pres = u->SubVector("flow")->data();
  for (Flow::FlowRelations::WRMRegionPairList::iterator region=wrms->begin();
       region!=wrms->end(); ++region) {
    std::string name = region->first;
    int ncells = pres->mesh()->get_set_size(name, AmanziMesh::CELL, AmanziMesh::OWNED);
    AmanziMesh::Entity_ID_List cells(ncells);
    pres->mesh()->get_set_entities(name, AmanziMesh::CELL, AmanziMesh::OWNED, &cells);

    for (AmanziMesh::Entity_ID_List::iterator c=cells.begin(); c!=cells.end(); ++c) {
      double p = (*pres)("cell",*c);
      double A_minus_one = (1.0/(*one_on_A)("cell",*c) - 1.0);

      double wc = (*wc0)("cell",*c) / (*cv)("cell",*c);
      double sstar = (wc - (*n_g)("cell",*c)*(*omega_g)("cell",*c)*(*phi)("cell",*c)) /
          ((*phi)("cell",*c) * ((*n_l)("cell",*c) - (*n_g)("cell",*c)*(*omega_g)("cell",*c)
                  + (*n_i)("cell",*c)*A_minus_one) - A_minus_one*wc);

      if (sstar > 0.) {
        if (*c==0) std::cout << "   A-1(0) = " << A_minus_one << std::endl;
        if (*c==99) std::cout << "   A-1(99) = " << A_minus_one << std::endl;
        if (*c==0) std::cout << "   S*(0) = " << sstar << std::endl;
        if (*c==99) std::cout << "   S*(99) = " << sstar << std::endl;

        double pc = region->second->capillaryPressure(sstar);

        if (*c==0) std::cout << "   pc(0) = " << pc << std::endl;
        if (*c==99) std::cout << "   pc(99) = " << pc << std::endl;

        (*pres)("cell",*c) = *p_atm - pc;

        if (*c==0) std::cout << "   p(0) = " << (*pres)("cell",*c) << std::endl;
        if (*c==99) std::cout << "   p(99) = " <<  (*pres)("cell",*c) << std::endl;

      }
    }
  }

  AmanziMesh::Entity_ID_List cells;
  pres->ScatterMasterToGhosted("cell");

  int f_owned = pres->size("face");
  for (int f=0; f!=f_owned; ++f) {
    cells.clear();
    pres->mesh()->face_get_cells(f, AmanziMesh::USED, &cells);
    int ncells = cells.size();

    double face_value = 0.0;
    for (int n=0; n!=ncells; ++n) {
      face_value += (*pres)("cell",cells[n]);
    }
    (*pres)("face",f) = face_value / ncells;
  }

  return true;
};

} // namespace
<|endoftext|>


<commit_before>#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "avisynth.h"
#include <math.h>
#include <assert.h>
#include <stdint.h>
#include <algorithm>
#include <emmintrin.h>
#include "special.h"

enum class InstructionSet
{
    SSE2,
    PLAIN_C
};

static __forceinline int calculate_window_side_length(int radius, int x, int width) {
    int length = radius + 1;
    if (x <= radius) {
        length += x;
    } else if (x >= width-radius) {
        length += width-x-1;
    } else {
        length += radius;
    }
    return length;
}

template<typename T, InstructionSet instruction_set>
class MedianProcessor
{
    typedef struct {
        T coarse[16];
        T fine[256];
    } Histogram;

    typedef struct {
        int start;
        int end;
    } ColumnPair;

    static __forceinline void add_16_bins_c(T* a, const T *b) {
        for (int i = 0; i < 16; ++i) {
            a[i] += b[i];
        }
    }

    static __forceinline void sub_16_bins_c(T* a, const T *b) {
        for (int i = 0; i < 16; ++i) {
            a[i] -= b[i];
        }
    }

    static __forceinline void zero_single_bin_c(T* a) {
        for (int i = 0; i < 16; ++i) {
            a[i] = 0;
        }
    }

    static __forceinline void add_16_bins_sse2(T* a, const T *b) {
        for (int i = 0; i < sizeof(T); ++i) {
            __m128i aval = _mm_load_si128(reinterpret_cast<const __m128i*>(a)+i);
            __m128i bval = _mm_load_si128(reinterpret_cast<const __m128i*>(b)+i);
            __m128i sum = _mm_adds_epu16(aval, bval);
            _mm_store_si128(reinterpret_cast<__m128i*>(a)+i, sum);
        }
    }

    static __forceinline void sub_16_bins_sse2(T* a, const T *b) {
        for (int i = 0; i < sizeof(T); ++i) {
            __m128i aval = _mm_load_si128(reinterpret_cast<const __m128i*>(a)+i);
            __m128i bval = _mm_load_si128(reinterpret_cast<const __m128i*>(b)+i);
            __m128i sum = _mm_subs_epu16(aval, bval);
            _mm_store_si128(reinterpret_cast<__m128i*>(a)+i, sum);
        }
    }

    static __forceinline void zero_single_bin_sse2(T* a) {
        __m128i zero = _mm_setzero_si128();
        for (int i = 0; i < sizeof(T); ++i) {
            _mm_store_si128(reinterpret_cast<__m128i*>(a)+i, zero);
        }
    }

    static __forceinline void add_16_bins(T* a, const T *b) {
        if (instruction_set == InstructionSet::SSE2) {
            add_16_bins_sse2(a, b);
        } else {
            add_16_bins_c(a, b);
        }
    }

    static __forceinline void sub_16_bins(T* a, const T *b) {
        if (instruction_set == InstructionSet::SSE2) {
            sub_16_bins_sse2(a, b);
        } else {
            sub_16_bins_c(a, b);
        }
    }

    static __forceinline void zero_single_bin(T* a) {
        if (instruction_set == InstructionSet::SSE2) {
            zero_single_bin_sse2(a);
        } else {
            zero_single_bin_c(a);
        }
    }

public:
    static const int HISTOGRAM_SIZE = sizeof(Histogram);

    static void calculate_median(uint8_t* dstp, const uint8_t* srcp, int dst_pitch, int src_pitch, int width, int height, int radius, void *buffer) {
        Histogram* histograms = reinterpret_cast<Histogram*>(buffer);
        __declspec(align(16)) Histogram current_hist;
        ColumnPair fine_columns[16]; //indexes of last and first column in every fine histogram segment
        memset(histograms, 0, width * HISTOGRAM_SIZE);

        //init histograms
        for (int y = 0; y < radius+1; ++y) {
            for (int x = 0; x < width; ++x) {
                uint8_t new_element = srcp[y*src_pitch+x];
                histograms[x].coarse[new_element>>4]++;
                histograms[x].fine[new_element]++;
            }
        }

        for (int y = 0; y < height; ++y) {
            int current_length_y = calculate_window_side_length(radius, y, height);

            memset(current_hist.coarse, 0, HISTOGRAM_SIZE);
            memset(fine_columns, -1, sizeof(fine_columns));
            //init histogram of the leftmost column
            for (int x = 0; x < radius; ++x) {
                add_16_bins(current_hist.coarse, histograms[x].coarse);
            }

            for (int x = 0; x < width; ++x) {
                //add one column to the right
                if (x < (width-radius)) {
                    add_16_bins(current_hist.coarse, histograms[x+radius].coarse);
                }

                int current_length_x = calculate_window_side_length(radius, x, width);
                int start_x = std::max(0, x-radius);
                int end_x = start_x + current_length_x;
                int half_elements = (current_length_y * current_length_x + 1) / 2;

                //finding median on coarse level
                int count = 0;
                int coarse_idx = -1;
                while (count < half_elements) {
                    count += current_hist.coarse[++coarse_idx];
                }
                count -= current_hist.coarse[coarse_idx];

                assert(coarse_idx < 16);
                int fine_offset = coarse_idx*16;

                //partially updating fine histogram
                if (fine_columns[coarse_idx].end < start_x) {
                    //any data we gathered is useless, drop it and build the whole block from scratch
                    zero_single_bin(current_hist.fine + fine_offset);

                    for (int i = start_x; i < end_x; ++i) {
                        add_16_bins(current_hist.fine+fine_offset, histograms[i].fine+fine_offset);
                    }
                } else {
                    int i = fine_columns[coarse_idx].start;
                    while (i < start_x) {
                        sub_16_bins(current_hist.fine+fine_offset, histograms[i++].fine+fine_offset);
                    }
                    i = fine_columns[coarse_idx].end;
                    while (++i < end_x) {
                        add_16_bins(current_hist.fine+fine_offset, histograms[i].fine+fine_offset);
                    }
                }
                fine_columns[coarse_idx].start = start_x;
                fine_columns[coarse_idx].end = end_x-1;

                //finding median on fine level
                int fine_idx = fine_offset - 1;
                while (count < half_elements) {
                    count += current_hist.fine[++fine_idx];
                }

                assert(fine_idx < 256);
                dstp[x] = fine_idx;

                //subtract leftmost histogram
                if (x >= radius) {
                    sub_16_bins(current_hist.coarse, histograms[x-radius].coarse);
                }
            }

            //updating column histograms
            if (y >= radius) {
                for (int x = 0; x < width; ++x) {
                    uint8_t old_element = srcp[(y-radius)*src_pitch+x];
                    histograms[x].coarse[old_element>>4]--;
                    histograms[x].fine[old_element]--;
                }
            }
            if (y < height-radius-1) {
                for (int x = 0; x < width; ++x) {
                    uint8_t new_element = srcp[(y+radius+1)*src_pitch+x];
                    histograms[x].coarse[new_element>>4]++;
                    histograms[x].fine[new_element]++;
                }
            }

            dstp += dst_pitch;
        }
    }
};

class MedianBlur : public GenericVideoFilter {
public:
    MedianBlur(PClip child, int radius_y, int radius_u, int radius_v, IScriptEnvironment* env);
    PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *env);

    ~MedianBlur() {
        _aligned_free(buffer_);
    }

private:
    int radius_y_;
    int radius_u_;
    int radius_v_;
    void *buffer_;
    decltype(&MedianProcessor<uint8_t, InstructionSet::SSE2>::calculate_median) processors_[3];

    static const int MAX_RADIUS = 127;
    static const int MIN_MODE = -255;
};

MedianBlur::MedianBlur(PClip child, int radius_y, int radius_u, int radius_v, IScriptEnvironment* env)
: GenericVideoFilter(child), radius_y_(radius_y), radius_u_(radius_u), radius_v_(radius_v), buffer_(nullptr) {
    if (!vi.IsPlanar()) {
        env->ThrowError("MedianBlur: only planar formats allowed");
    }

    if (radius_y > MAX_RADIUS || radius_u > MAX_RADIUS || radius_v > MAX_RADIUS) {
        env->ThrowError("MedianBlur: radius is too large. Must be between 0 and %i", MAX_RADIUS);
    }
    if (radius_y < MIN_MODE || radius_u < MIN_MODE || radius_v < MIN_MODE) {
        env->ThrowError("MedianBlur: radius is too small. Must be between 0 and %i", MAX_RADIUS);
    }

    int planes[] = { PLANAR_Y, PLANAR_U, PLANAR_V };
    int radii[] = { radius_y, radius_u, radius_v };
    int min_width = vi.width;

#pragma warning(disable: 4800)
    bool sse2 = env->GetCPUFlags() & CPUF_SSE2;
#pragma warning(default: 4800)

    int hist_size = 0;
    for (int i = 0; i < (vi.IsY8() ? 1 : 3); ++i) {
        if (radii[i] <= 0) {
            continue;
        }
        int width = vi.width >> vi.GetPlaneWidthSubsampling(planes[i]);
        int height = vi.width >> vi.GetPlaneHeightSubsampling(planes[i]);
        int core_size = radii[i]*2 + 1;
        if (width < core_size || height < core_size) {
            env->ThrowError("MedianBlur: image is too small for this radius!");
        }

        //special cases make sense only when SSE2 is available, otherwise generic routine will be faster
        if (radii[i] == 1 && sse2 && width > 16) {
            processors_[i] = &calculate_median_r1;
        } else if (radii[i] == 2 && sse2 && width > 16) {
            processors_[i] = &calculate_median_r2;
        } else if (radii[i] < 8) {
            hist_size = std::max(hist_size, MedianProcessor<uint8_t, InstructionSet::PLAIN_C>::HISTOGRAM_SIZE);
            if (sse2) {
                processors_[i] = &MedianProcessor<uint8_t, InstructionSet::SSE2>::calculate_median;
            } else {
                processors_[i] = &MedianProcessor<uint8_t, InstructionSet::PLAIN_C>::calculate_median;
            }
        } else {
            hist_size = std::max(hist_size, MedianProcessor<uint16_t, InstructionSet::PLAIN_C>::HISTOGRAM_SIZE);
            if (sse2) {
                processors_[i] = &MedianProcessor<uint16_t, InstructionSet::SSE2>::calculate_median;
            } else {
                processors_[i] = &MedianProcessor<uint16_t, InstructionSet::PLAIN_C>::calculate_median;
            }
        }
    }

    if (!sse2 || radius_u > 2 || radius_v > 2 || radius_y > 2) {
        //allocate buffer only for generic approach
        buffer_ = _aligned_malloc(vi.width  * hist_size, 16);
    }
}

PVideoFrame MedianBlur::GetFrame(int n, IScriptEnvironment *env) {
    PVideoFrame src = child->GetFrame(n, env);
    PVideoFrame dst = env->NewVideoFrame(vi);

    int planes[] = { PLANAR_Y, PLANAR_U, PLANAR_V };
    int radii[] = { radius_y_, radius_u_, radius_v_ };
    for (int i = 0; i < (vi.IsY8() ? 1 : 3); i++) {
        int plane = planes[i];
        int radius = radii[i];
        int width = src->GetRowSize(plane);
        int height = src->GetHeight(plane);

        if (radius > 0) {
            processors_[i](dst->GetWritePtr(plane), src->GetReadPtr(plane), dst->GetPitch(plane),
                src->GetPitch(plane), width, height, radius, buffer_);
        } else if (radius == 0) {
            env->BitBlt(dst->GetWritePtr(plane), dst->GetPitch(plane),
                src->GetReadPtr(plane), src->GetPitch(plane), width, height);
        } else {
            memset(dst->GetWritePtr(plane), -radius, dst->GetPitch(plane)*height);
        }
    }

    return dst;
}

AVSValue __cdecl create_median_blur(AVSValue args, void*, IScriptEnvironment* env) {
    enum { CLIP, RADIUS, RADIUS_U, RADIUS_V };
    return new MedianBlur(args[CLIP].AsClip(), args[RADIUS].AsInt(2), args[RADIUS_U].AsInt(2), args[RADIUS_V].AsInt(2), env);
}

const AVS_Linkage *AVS_linkage = nullptr;

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit3(IScriptEnvironment* env, const AVS_Linkage* const vectors) {
    AVS_linkage = vectors;
    env->AddFunction("MedianBlur", "c[radiusy]i[radiusu]i[radiusv]i", create_median_blur, 0);
    return "Kawaikunai";
}<commit_msg>Use correct SSE2 instructions for histogram addition and subtraction depending on the bin size<commit_after>#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "avisynth.h"
#include <math.h>
#include <assert.h>
#include <stdint.h>
#include <algorithm>
#include <emmintrin.h>
#include "special.h"

enum class InstructionSet
{
    SSE2,
    PLAIN_C
};

static __forceinline int calculate_window_side_length(int radius, int x, int width) {
    int length = radius + 1;
    if (x <= radius) {
        length += x;
    } else if (x >= width-radius) {
        length += width-x-1;
    } else {
        length += radius;
    }
    return length;
}

template<typename T>
static __forceinline __m128i simd_adds(const __m128i &a, const __m128i &b) {}

template<>
static __forceinline __m128i simd_adds<uint8_t>(const __m128i &a, const __m128i &b) {
    return _mm_adds_epu8(a, b);
}

template<>
static __forceinline __m128i simd_adds<uint16_t>(const __m128i &a, const __m128i &b) {
    return _mm_adds_epu16(a, b);
}

template<typename T>
static __forceinline __m128i simd_subs(const __m128i &a, const __m128i &b) {}

template<>
static __forceinline __m128i simd_subs<uint8_t>(const __m128i &a, const __m128i &b) {
    return _mm_subs_epu8(a, b);
}

template<>
static __forceinline __m128i simd_subs<uint16_t>(const __m128i &a, const __m128i &b) {
    return _mm_subs_epu16(a, b);
}

template<typename T, InstructionSet instruction_set>
class MedianProcessor
{
    typedef struct {
        T coarse[16];
        T fine[256];
    } Histogram;

    typedef struct {
        int start;
        int end;
    } ColumnPair;

    static __forceinline void add_16_bins_c(T* a, const T *b) {
        for (int i = 0; i < 16; ++i) {
            a[i] += b[i];
        }
    }

    static __forceinline void sub_16_bins_c(T* a, const T *b) {
        for (int i = 0; i < 16; ++i) {
            a[i] -= b[i];
        }
    }

    static __forceinline void zero_single_bin_c(T* a) {
        for (int i = 0; i < 16; ++i) {
            a[i] = 0;
        }
    }

    static __forceinline void add_16_bins_sse2(T* a, const T *b) {
        for (int i = 0; i < sizeof(T); ++i) {
            __m128i aval = _mm_load_si128(reinterpret_cast<const __m128i*>(a)+i);
            __m128i bval = _mm_load_si128(reinterpret_cast<const __m128i*>(b)+i);
            __m128i sum = simd_adds<T>(aval, bval);
            _mm_store_si128(reinterpret_cast<__m128i*>(a)+i, sum);
        }
    }

    static __forceinline void sub_16_bins_sse2(T* a, const T *b) {
        for (int i = 0; i < sizeof(T); ++i) {
            __m128i aval = _mm_load_si128(reinterpret_cast<const __m128i*>(a)+i);
            __m128i bval = _mm_load_si128(reinterpret_cast<const __m128i*>(b)+i);
            __m128i sum = simd_subs<T>(aval, bval);
            _mm_store_si128(reinterpret_cast<__m128i*>(a)+i, sum);
        }
    }

    static __forceinline void zero_single_bin_sse2(T* a) {
        __m128i zero = _mm_setzero_si128();
        for (int i = 0; i < sizeof(T); ++i) {
            _mm_store_si128(reinterpret_cast<__m128i*>(a)+i, zero);
        }
    }

    static __forceinline void add_16_bins(T* a, const T *b) {
        if (instruction_set == InstructionSet::SSE2) {
            add_16_bins_sse2(a, b);
        } else {
            add_16_bins_c(a, b);
        }
    }

    static __forceinline void sub_16_bins(T* a, const T *b) {
        if (instruction_set == InstructionSet::SSE2) {
            sub_16_bins_sse2(a, b);
        } else {
            sub_16_bins_c(a, b);
        }
    }

    static __forceinline void zero_single_bin(T* a) {
        if (instruction_set == InstructionSet::SSE2) {
            zero_single_bin_sse2(a);
        } else {
            zero_single_bin_c(a);
        }
    }

public:
    static const int HISTOGRAM_SIZE = sizeof(Histogram);

    static void calculate_median(uint8_t* dstp, const uint8_t* srcp, int dst_pitch, int src_pitch, int width, int height, int radius, void *buffer) {
        Histogram* histograms = reinterpret_cast<Histogram*>(buffer);
        __declspec(align(16)) Histogram current_hist;
        ColumnPair fine_columns[16]; //indexes of last and first column in every fine histogram segment
        memset(histograms, 0, width * HISTOGRAM_SIZE);

        //init histograms
        for (int y = 0; y < radius+1; ++y) {
            for (int x = 0; x < width; ++x) {
                uint8_t new_element = srcp[y*src_pitch+x];
                histograms[x].coarse[new_element>>4]++;
                histograms[x].fine[new_element]++;
            }
        }

        for (int y = 0; y < height; ++y) {
            int current_length_y = calculate_window_side_length(radius, y, height);

            memset(current_hist.coarse, 0, HISTOGRAM_SIZE);
            memset(fine_columns, -1, sizeof(fine_columns));
            //init histogram of the leftmost column
            for (int x = 0; x < radius; ++x) {
                add_16_bins(current_hist.coarse, histograms[x].coarse);
            }

            for (int x = 0; x < width; ++x) {
                //add one column to the right
                if (x < (width-radius)) {
                    add_16_bins(current_hist.coarse, histograms[x+radius].coarse);
                }

                int current_length_x = calculate_window_side_length(radius, x, width);
                int start_x = std::max(0, x-radius);
                int end_x = start_x + current_length_x;
                int half_elements = (current_length_y * current_length_x + 1) / 2;

                //finding median on coarse level
                int count = 0;
                int coarse_idx = -1;
                while (count < half_elements) {
                    count += current_hist.coarse[++coarse_idx];
                }
                count -= current_hist.coarse[coarse_idx];

                assert(coarse_idx < 16);
                int fine_offset = coarse_idx*16;

                //partially updating fine histogram
                if (fine_columns[coarse_idx].end < start_x) {
                    //any data we gathered is useless, drop it and build the whole block from scratch
                    zero_single_bin(current_hist.fine + fine_offset);

                    for (int i = start_x; i < end_x; ++i) {
                        add_16_bins(current_hist.fine+fine_offset, histograms[i].fine+fine_offset);
                    }
                } else {
                    int i = fine_columns[coarse_idx].start;
                    while (i < start_x) {
                        sub_16_bins(current_hist.fine+fine_offset, histograms[i++].fine+fine_offset);
                    }
                    i = fine_columns[coarse_idx].end;
                    while (++i < end_x) {
                        add_16_bins(current_hist.fine+fine_offset, histograms[i].fine+fine_offset);
                    }
                }
                fine_columns[coarse_idx].start = start_x;
                fine_columns[coarse_idx].end = end_x-1;

                //finding median on fine level
                int fine_idx = fine_offset - 1;
                while (count < half_elements) {
                    count += current_hist.fine[++fine_idx];
                }

                assert(fine_idx < 256);
                dstp[x] = fine_idx;

                //subtract leftmost histogram
                if (x >= radius) {
                    sub_16_bins(current_hist.coarse, histograms[x-radius].coarse);
                }
            }

            //updating column histograms
            if (y >= radius) {
                for (int x = 0; x < width; ++x) {
                    uint8_t old_element = srcp[(y-radius)*src_pitch+x];
                    histograms[x].coarse[old_element>>4]--;
                    histograms[x].fine[old_element]--;
                }
            }
            if (y < height-radius-1) {
                for (int x = 0; x < width; ++x) {
                    uint8_t new_element = srcp[(y+radius+1)*src_pitch+x];
                    histograms[x].coarse[new_element>>4]++;
                    histograms[x].fine[new_element]++;
                }
            }

            dstp += dst_pitch;
        }
    }
};

class MedianBlur : public GenericVideoFilter {
public:
    MedianBlur(PClip child, int radius_y, int radius_u, int radius_v, IScriptEnvironment* env);
    PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment *env);

    ~MedianBlur() {
        _aligned_free(buffer_);
    }

private:
    int radius_y_;
    int radius_u_;
    int radius_v_;
    void *buffer_;
    decltype(&MedianProcessor<uint8_t, InstructionSet::SSE2>::calculate_median) processors_[3];

    static const int MAX_RADIUS = 127;
    static const int MIN_MODE = -255;
};

MedianBlur::MedianBlur(PClip child, int radius_y, int radius_u, int radius_v, IScriptEnvironment* env)
: GenericVideoFilter(child), radius_y_(radius_y), radius_u_(radius_u), radius_v_(radius_v), buffer_(nullptr) {
    if (!vi.IsPlanar()) {
        env->ThrowError("MedianBlur: only planar formats allowed");
    }

    if (radius_y > MAX_RADIUS || radius_u > MAX_RADIUS || radius_v > MAX_RADIUS) {
        env->ThrowError("MedianBlur: radius is too large. Must be between 0 and %i", MAX_RADIUS);
    }
    if (radius_y < MIN_MODE || radius_u < MIN_MODE || radius_v < MIN_MODE) {
        env->ThrowError("MedianBlur: radius is too small. Must be between 0 and %i", MAX_RADIUS);
    }

    int planes[] = { PLANAR_Y, PLANAR_U, PLANAR_V };
    int radii[] = { radius_y, radius_u, radius_v };
    int min_width = vi.width;

#pragma warning(disable: 4800)
    bool sse2 = env->GetCPUFlags() & CPUF_SSE2;
#pragma warning(default: 4800)

    int hist_size = 0;
    for (int i = 0; i < (vi.IsY8() ? 1 : 3); ++i) {
        if (radii[i] <= 0) {
            continue;
        }
        int width = vi.width >> vi.GetPlaneWidthSubsampling(planes[i]);
        int height = vi.width >> vi.GetPlaneHeightSubsampling(planes[i]);
        int core_size = radii[i]*2 + 1;
        if (width < core_size || height < core_size) {
            env->ThrowError("MedianBlur: image is too small for this radius!");
        }

        //special cases make sense only when SSE2 is available, otherwise generic routine will be faster
        if (radii[i] == 1 && sse2 && width > 16) {
            processors_[i] = &calculate_median_r1;
        } else if (radii[i] == 2 && sse2 && width > 16) {
            processors_[i] = &calculate_median_r2;
        } else if (radii[i] < 8) {
            hist_size = std::max(hist_size, MedianProcessor<uint8_t, InstructionSet::PLAIN_C>::HISTOGRAM_SIZE);
            if (sse2) {
                processors_[i] = &MedianProcessor<uint8_t, InstructionSet::SSE2>::calculate_median;
            } else {
                processors_[i] = &MedianProcessor<uint8_t, InstructionSet::PLAIN_C>::calculate_median;
            }
        } else {
            hist_size = std::max(hist_size, MedianProcessor<uint16_t, InstructionSet::PLAIN_C>::HISTOGRAM_SIZE);
            if (sse2) {
                processors_[i] = &MedianProcessor<uint16_t, InstructionSet::SSE2>::calculate_median;
            } else {
                processors_[i] = &MedianProcessor<uint16_t, InstructionSet::PLAIN_C>::calculate_median;
            }
        }
    }

    if (!sse2 || radius_u > 2 || radius_v > 2 || radius_y > 2) {
        //allocate buffer only for generic approach
        buffer_ = _aligned_malloc(vi.width  * hist_size, 16);
    }
}

PVideoFrame MedianBlur::GetFrame(int n, IScriptEnvironment *env) {
    PVideoFrame src = child->GetFrame(n, env);
    PVideoFrame dst = env->NewVideoFrame(vi);

    int planes[] = { PLANAR_Y, PLANAR_U, PLANAR_V };
    int radii[] = { radius_y_, radius_u_, radius_v_ };
    for (int i = 0; i < (vi.IsY8() ? 1 : 3); i++) {
        int plane = planes[i];
        int radius = radii[i];
        int width = src->GetRowSize(plane);
        int height = src->GetHeight(plane);

        if (radius > 0) {
            processors_[i](dst->GetWritePtr(plane), src->GetReadPtr(plane), dst->GetPitch(plane),
                src->GetPitch(plane), width, height, radius, buffer_);
        } else if (radius == 0) {
            env->BitBlt(dst->GetWritePtr(plane), dst->GetPitch(plane),
                src->GetReadPtr(plane), src->GetPitch(plane), width, height);
        } else {
            memset(dst->GetWritePtr(plane), -radius, dst->GetPitch(plane)*height);
        }
    }

    return dst;
}

AVSValue __cdecl create_median_blur(AVSValue args, void*, IScriptEnvironment* env) {
    enum { CLIP, RADIUS, RADIUS_U, RADIUS_V };
    return new MedianBlur(args[CLIP].AsClip(), args[RADIUS].AsInt(2), args[RADIUS_U].AsInt(2), args[RADIUS_V].AsInt(2), env);
}

const AVS_Linkage *AVS_linkage = nullptr;

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit3(IScriptEnvironment* env, const AVS_Linkage* const vectors) {
    AVS_linkage = vectors;
    env->AddFunction("MedianBlur", "c[radiusy]i[radiusu]i[radiusv]i", create_median_blur, 0);
    return "Kawaikunai";
}<|endoftext|>


<commit_before>// Copyright 2017 ESRI
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
//
// See the Sample code usage restrictions document for further information.
//

#include "CoordinateConversionController.h"
#include "CoordinateConversionResults.h"
#include "CoordinateFormatter.h"
#include <QClipboard>
#include <QGuiApplication>

#include "ToolManager.h"
#include "ToolResourceProvider.h"
#include "MapQuickView.h"
#include "SceneQuickView.h"
#include <functional>

/*!
  \class Esri::ArcGISRuntime::Toolkit::CoordinateConversionController
  \ingroup ToolCoordinateConversion
  \inmodule ArcGISQtToolkit
  \since Esri::ArcGISRuntime 100.2
  \brief The controller for the coordinate conversion tool.

  This tool converts a notation text string to all output notations formats
  defined in your app. Those output formats are defined using a list of
  \l CoordinateConversionOptions objects that your app builds
  using \l addOption. Each \l CoordinateConversionOptions object specifies a
  coordinate notation and options that apply to that notation (decimal places,
  use of spaces, and so on).

  \sa {Coordinate Conversion Tool}
 */

namespace Esri
{
namespace ArcGISRuntime
{
namespace Toolkit
{

using CoordinateType = CoordinateConversionOptions::CoordinateType;

/*!
  \brief A constructor that accepts an optional \a parent.
 */
CoordinateConversionController::CoordinateConversionController(QObject* parent):
  AbstractTool(parent)
{
  ToolManager::instance().addTool(this);

  auto geoView = ToolResourceProvider::instance()->geoView();
  if (geoView)
    setSpatialReference(geoView->spatialReference());

  connect(ToolResourceProvider::instance(), &ToolResourceProvider::spatialReferenceChanged, this, [this]()
  {
    setSpatialReference(ToolResourceProvider::instance()->spatialReference());
  });

  connect(ToolResourceProvider::instance(), &ToolResourceProvider::mouseClickedPoint, this,
  [this](const Point& point)
  {
    setPointToConvert(point);
  });

  connect(this, &CoordinateConversionController::optionsChanged, this,
  [this]()
  {
    QList<Result> list;
    for (const auto& option : m_options)
      list.append(Result(option->name(), QString(), option->outputMode()));

    results()->setResults(std::move(list));
  });
}

/*!
   \brief The destructor.
 */
CoordinateConversionController::~CoordinateConversionController()
{
}

/*!
  \brief Converts \a notation and updates the \l results property.

  Before calling this method, set the \l inputMode property to the
  notation type of \a notation, and call \l setSpatialReference property
  to the spatial reference of the notation's coordinates.

  \note Converting between some notation formats can result in loss
  of precision due to the number of decimal places expressed in the
  notation, and other factors. The best precision is attained by
  converting from a Point object. See \l convertPoint.
 */
void CoordinateConversionController::convertNotation(const QString& notation)
{
  QList<Result> results;
  const Point convertedPoint = pointFromNotation(notation);

  for (CoordinateConversionOptions* option : m_options)
  {
    const QString name = option->name();
    results.append(Result(name, convertPointInternal(option, convertedPoint), option->outputMode()));
  }

  this->results()->setResults(std::move(results));
  emit resultsChanged();
}

/*!
  \internal
 */
Point CoordinateConversionController::pointFromNotation(const QString& incomingNotation)
{
  if (m_spatialReference.isEmpty())
    qWarning("The spatial reference property is empty: conversions will fail.");

  switch (m_inputMode)
  {
  case CoordinateType::CoordinateTypeGars:
  {
    return CoordinateFormatter::fromGars(incomingNotation,
                                         m_spatialReference,
                                         static_cast<Esri::ArcGISRuntime::GarsConversionMode>(m_inputGarsConversionMode));
  }
  case CoordinateType::CoordinateTypeGeoRef:
  {
    return CoordinateFormatter::fromGeoRef(incomingNotation,
                                           m_spatialReference);
  }
  case CoordinateType::CoordinateTypeLatLon:
  {
    return CoordinateFormatter::fromLatitudeLongitude(incomingNotation,
                                                      m_spatialReference);
  }
  case CoordinateType::CoordinateTypeMgrs:
  {
    return CoordinateFormatter::fromMgrs(incomingNotation,
                                         m_spatialReference,
                                         static_cast<Esri::ArcGISRuntime::MgrsConversionMode>(m_inputMgrsConversionMode));
  }
  case CoordinateType::CoordinateTypeUsng:
  {
    return CoordinateFormatter::fromUsng(incomingNotation,
                                         m_spatialReference);
  }
  case CoordinateType::CoordinateTypeUtm:
  {
    return CoordinateFormatter::fromUtm(incomingNotation,
                                        m_spatialReference,
                                        static_cast<Esri::ArcGISRuntime::UtmConversionMode>(m_inputUtmConversionMode));
  }
  default: {}
  }

  return Point();
}

/*!
  \brief Converts the last point assigned with \l setPointToConvert to all the
  notations specified in the options.
 */
void CoordinateConversionController::convertPoint()
{
  QList<Result> results;

  for (CoordinateConversionOptions* option : m_options)
  {
    const QString name = option->name();
    results.append(Result(name, convertPointInternal(option, m_pointToConvert), option->outputMode()));
  }

  this->results()->setResults(std::move(results));
  emit resultsChanged();
}

/*!
  \internal
 */
QString CoordinateConversionController::convertPointInternal(CoordinateConversionOptions* option, const Esri::ArcGISRuntime::Point& point)
{
  switch (option->outputMode())
  {
  case CoordinateType::CoordinateTypeGars:
  {
    return CoordinateFormatter::toGars(point);
  }
  case CoordinateType::CoordinateTypeGeoRef:
  {
    return CoordinateFormatter::toGeoRef(point, option->precision());
  }
  case CoordinateType::CoordinateTypeLatLon:
  {
    const auto format = static_cast<Esri::ArcGISRuntime::LatitudeLongitudeFormat>(option->latLonFormat());
    return CoordinateFormatter::toLatitudeLongitude(point, format, option->decimalPlaces());
  }
  case CoordinateType::CoordinateTypeMgrs:
  {
    const auto conversionMode = static_cast<Esri::ArcGISRuntime::MgrsConversionMode>(option->mgrsConversionMode());
    return CoordinateFormatter::toMgrs(point, conversionMode, option->decimalPlaces(), option->addSpaces());
  }
  case CoordinateType::CoordinateTypeUsng:
  {
    return CoordinateFormatter::toUsng(point, option->precision(),option->decimalPlaces());
  }
  case CoordinateType::CoordinateTypeUtm:
  {
    const auto conversionMode = static_cast<Esri::ArcGISRuntime::UtmConversionMode>(option->utmConversionMode());
    return CoordinateFormatter::toUtm(point, conversionMode, option->addSpaces());
  }
  default: {}
  }

  return QString();
}

/*!
  \property CoordinateConversionController::inputMode
  \brief The current input conversion mode used for the \l convertNotation method.
 */
CoordinateType CoordinateConversionController::inputMode() const
{
  return m_inputMode;
}

void CoordinateConversionController::setInputMode(CoordinateType inputMode)
{
  m_inputMode = inputMode;
  emit inputModeChanged();
}

/*!
  \property CoordinateConversionController::results
  \brief The conversion results as a list model.

  The results are automatically updated as conversions are run.
 */
CoordinateConversionResults* CoordinateConversionController::results()
{
  if (!m_results)
  {
    m_results = new CoordinateConversionResults(this);
    connect(m_results, &CoordinateConversionResults::resultsChanged, this, &CoordinateConversionController::resultsChanged);
  }

  return m_results;
}

/*!
  \property CoordinateConversionController::options
  \brief The notation options as a list.
 */
QQmlListProperty<CoordinateConversionOptions> CoordinateConversionController::options()
{
  return QQmlListProperty<CoordinateConversionOptions>(this, &m_options,
                                                       CoordinateConversionOptions::listAppend,
                                                       CoordinateConversionOptions::listCount,
                                                       CoordinateConversionOptions::listAt,
                                                       CoordinateConversionOptions::listClear);
}

/*!
  \brief Sets the spatial reference to \a spatialReference.
  \note This property must be set before calling the \l convertNotation method.
 */
void CoordinateConversionController::setSpatialReference(const Esri::ArcGISRuntime::SpatialReference& spatialReference)
{
  m_spatialReference = spatialReference;
}

/*!
  \property CoordinateConversionController::inputGarsConversionMode
  \brief The inputGarsConversionMode.
  \note This property is only used if the \l inputMode property is set to \c Gars.
 */
CoordinateConversionOptions::GarsConversionMode CoordinateConversionController::inputGarsConversionMode() const
{
  return m_inputGarsConversionMode;
}

void CoordinateConversionController::setInputGarsConversionMode(CoordinateConversionOptions::GarsConversionMode inputGarsConversionMode)
{
  m_inputGarsConversionMode = inputGarsConversionMode;
  emit inputGarsConversionModeChanged();
}

/*!
  \property CoordinateConversionController::inputMgrsConversionMode
  \brief The inputMgrsConversionMode.
  \note This property is only used if the \l inputMode property is set to \c Mgrs.
 */
CoordinateConversionOptions::MgrsConversionMode CoordinateConversionController::inputMgrsConversionMode() const
{
  return m_inputMgrsConversionMode;
}

void CoordinateConversionController::setInputMgrsConversionMode(CoordinateConversionOptions::MgrsConversionMode inputMgrsConversionMode)
{
  m_inputMgrsConversionMode = inputMgrsConversionMode;
  emit inputMgrsConversionModeChanged();
}

/*!
  \property CoordinateConversionController::inputUtmConversionMode
  \brief The inputUtmConversionMode.
  \note This property is only used if the \l inputMode property is set to \c Utm.
 */
CoordinateConversionOptions::UtmConversionMode CoordinateConversionController::inputUtmConversionMode() const
{
  return m_inputUtmConversionMode;
}

void CoordinateConversionController::setInputUtmConversionMode(CoordinateConversionOptions::UtmConversionMode inputUtmConversionMode)
{
  m_inputUtmConversionMode = inputUtmConversionMode;
  emit inputUtmConversionModeChanged();
}

/*!
  \brief Sets the point to be converted via the \l convertPoint method to \a point.
  \note If the \l runConversion property is \c true, the conversion will be run immediately.
 */
void CoordinateConversionController::setPointToConvert(const Esri::ArcGISRuntime::Point& point)
{
  m_pointToConvert = point;

  if (m_runConversion)
    convertPoint();
}

/*!
  \internal
 */
QQmlListProperty<QObject> CoordinateConversionController::objects()
{
  return QQmlListProperty<QObject>(this, nullptr, objectAppend, nullptr, nullptr, nullptr);
}

/*!
  \internal
 */
void CoordinateConversionController::objectAppend(QQmlListProperty<QObject>* property, QObject* value)
{
  auto engine = qobject_cast<CoordinateConversionController*>(property->object);

  if (!engine)
    return;

  auto* option = qobject_cast<CoordinateConversionOptions*>(value);

  if (!option)
    return;

  engine->addOption(option);
}

/*!
  \brief Add the \l CoordinateConversionOptions object \a option to the list of options.
 */
void CoordinateConversionController::addOption(CoordinateConversionOptions* option)
{
  m_options.append(option);
  emit optionsChanged();
}

/*!
  \brief Clear all the \l CoordinateConversionOptions from the list of options.
 */
void CoordinateConversionController::clearOptions()
{
  m_options.clear();
  emit optionsChanged();
}

/*!
  \brief Returns the name of this tool: "CoordinateConversion".
 */
QString CoordinateConversionController::toolName() const
{
  return "CoordinateConversion";
}

/*!
  \brief Copy \a text to the system clipboard.
 */
void CoordinateConversionController::copyToClipboard(const QString& text)
{
  auto clipboard = QGuiApplication::clipboard();
  if (clipboard)
    clipboard->setText(text);
}

/*!
  \brief Clears the results notation strings from the results list model.
 */
void CoordinateConversionController::clearResults()
{
  if (m_results)
    m_results->clearResults();
}

/*!
  \property CoordinateConversionController::runConversion
  \brief Whether the conversion runs automatically when \l setPointToConvert
  is called.
 */
bool CoordinateConversionController::runConversion() const
{
  return m_runConversion;
}

void CoordinateConversionController::setRunConversion(bool runConversion)
{
  m_runConversion = runConversion;
  emit runConversionChanged();
}

// signals

/*!
  \fn void CoordinateConversionController::optionsChanged();
  \brief Signal emitted when the \l options property changes.
 */

/*!
  \fn void CoordinateConversionController::resultsChanged();
  \brief Signal emitted when the \l results property changes.
 */

/*!
  \fn void CoordinateConversionController::inputModeChanged();
  \brief Signal emitted when the \l inputMode property changes.
 */

/*!
  \fn void CoordinateConversionController::inputGarsConversionModeChanged();
  \brief Signal emitted when the \l inputGarsConversionMode property changes.
 */

/*!
  \fn void CoordinateConversionController::inputMgrsConversionModeChanged();
  \brief Signal emitted when the \l inputMgrsConversionMode property changes.
 */

/*!
  \fn void CoordinateConversionController::inputUtmConversionModeChanged();
  \brief Signal emitted when the \l inputUtmConversionMode property changes.
 */

/*!
  \fn void CoordinateConversionController::runConversionChanged();
  \brief Signal emitted when the \l runConversion property changes.
 */

} // Toolkit
} // ArcGISRuntime
} // Esri
<commit_msg>remove unused includes<commit_after>// Copyright 2017 ESRI
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
//
// See the Sample code usage restrictions document for further information.
//

#include "CoordinateConversionController.h"
#include "CoordinateConversionResults.h"
#include "CoordinateFormatter.h"
#include <QClipboard>
#include <QGuiApplication>

#include "ToolManager.h"
#include "ToolResourceProvider.h"
#include "GeoView.h"
#include <functional>

/*!
  \class Esri::ArcGISRuntime::Toolkit::CoordinateConversionController
  \ingroup ToolCoordinateConversion
  \inmodule ArcGISQtToolkit
  \since Esri::ArcGISRuntime 100.2
  \brief The controller for the coordinate conversion tool.

  This tool converts a notation text string to all output notations formats
  defined in your app. Those output formats are defined using a list of
  \l CoordinateConversionOptions objects that your app builds
  using \l addOption. Each \l CoordinateConversionOptions object specifies a
  coordinate notation and options that apply to that notation (decimal places,
  use of spaces, and so on).

  \sa {Coordinate Conversion Tool}
 */

namespace Esri
{
namespace ArcGISRuntime
{
namespace Toolkit
{

using CoordinateType = CoordinateConversionOptions::CoordinateType;

/*!
  \brief A constructor that accepts an optional \a parent.
 */
CoordinateConversionController::CoordinateConversionController(QObject* parent):
  AbstractTool(parent)
{
  ToolManager::instance().addTool(this);

  auto geoView = ToolResourceProvider::instance()->geoView();
  if (geoView)
    setSpatialReference(geoView->spatialReference());

  connect(ToolResourceProvider::instance(), &ToolResourceProvider::spatialReferenceChanged, this, [this]()
  {
    setSpatialReference(ToolResourceProvider::instance()->spatialReference());
  });

  connect(ToolResourceProvider::instance(), &ToolResourceProvider::mouseClickedPoint, this,
  [this](const Point& point)
  {
    setPointToConvert(point);
  });

  connect(this, &CoordinateConversionController::optionsChanged, this,
  [this]()
  {
    QList<Result> list;
    for (const auto& option : m_options)
      list.append(Result(option->name(), QString(), option->outputMode()));

    results()->setResults(std::move(list));
  });
}

/*!
   \brief The destructor.
 */
CoordinateConversionController::~CoordinateConversionController()
{
}

/*!
  \brief Converts \a notation and updates the \l results property.

  Before calling this method, set the \l inputMode property to the
  notation type of \a notation, and call \l setSpatialReference property
  to the spatial reference of the notation's coordinates.

  \note Converting between some notation formats can result in loss
  of precision due to the number of decimal places expressed in the
  notation, and other factors. The best precision is attained by
  converting from a Point object. See \l convertPoint.
 */
void CoordinateConversionController::convertNotation(const QString& notation)
{
  QList<Result> results;
  const Point convertedPoint = pointFromNotation(notation);

  for (CoordinateConversionOptions* option : m_options)
  {
    const QString name = option->name();
    results.append(Result(name, convertPointInternal(option, convertedPoint), option->outputMode()));
  }

  this->results()->setResults(std::move(results));
  emit resultsChanged();
}

/*!
  \internal
 */
Point CoordinateConversionController::pointFromNotation(const QString& incomingNotation)
{
  if (m_spatialReference.isEmpty())
    qWarning("The spatial reference property is empty: conversions will fail.");

  switch (m_inputMode)
  {
  case CoordinateType::CoordinateTypeGars:
  {
    return CoordinateFormatter::fromGars(incomingNotation,
                                         m_spatialReference,
                                         static_cast<Esri::ArcGISRuntime::GarsConversionMode>(m_inputGarsConversionMode));
  }
  case CoordinateType::CoordinateTypeGeoRef:
  {
    return CoordinateFormatter::fromGeoRef(incomingNotation,
                                           m_spatialReference);
  }
  case CoordinateType::CoordinateTypeLatLon:
  {
    return CoordinateFormatter::fromLatitudeLongitude(incomingNotation,
                                                      m_spatialReference);
  }
  case CoordinateType::CoordinateTypeMgrs:
  {
    return CoordinateFormatter::fromMgrs(incomingNotation,
                                         m_spatialReference,
                                         static_cast<Esri::ArcGISRuntime::MgrsConversionMode>(m_inputMgrsConversionMode));
  }
  case CoordinateType::CoordinateTypeUsng:
  {
    return CoordinateFormatter::fromUsng(incomingNotation,
                                         m_spatialReference);
  }
  case CoordinateType::CoordinateTypeUtm:
  {
    return CoordinateFormatter::fromUtm(incomingNotation,
                                        m_spatialReference,
                                        static_cast<Esri::ArcGISRuntime::UtmConversionMode>(m_inputUtmConversionMode));
  }
  default: {}
  }

  return Point();
}

/*!
  \brief Converts the last point assigned with \l setPointToConvert to all the
  notations specified in the options.
 */
void CoordinateConversionController::convertPoint()
{
  QList<Result> results;

  for (CoordinateConversionOptions* option : m_options)
  {
    const QString name = option->name();
    results.append(Result(name, convertPointInternal(option, m_pointToConvert), option->outputMode()));
  }

  this->results()->setResults(std::move(results));
  emit resultsChanged();
}

/*!
  \internal
 */
QString CoordinateConversionController::convertPointInternal(CoordinateConversionOptions* option, const Esri::ArcGISRuntime::Point& point)
{
  switch (option->outputMode())
  {
  case CoordinateType::CoordinateTypeGars:
  {
    return CoordinateFormatter::toGars(point);
  }
  case CoordinateType::CoordinateTypeGeoRef:
  {
    return CoordinateFormatter::toGeoRef(point, option->precision());
  }
  case CoordinateType::CoordinateTypeLatLon:
  {
    const auto format = static_cast<Esri::ArcGISRuntime::LatitudeLongitudeFormat>(option->latLonFormat());
    return CoordinateFormatter::toLatitudeLongitude(point, format, option->decimalPlaces());
  }
  case CoordinateType::CoordinateTypeMgrs:
  {
    const auto conversionMode = static_cast<Esri::ArcGISRuntime::MgrsConversionMode>(option->mgrsConversionMode());
    return CoordinateFormatter::toMgrs(point, conversionMode, option->decimalPlaces(), option->addSpaces());
  }
  case CoordinateType::CoordinateTypeUsng:
  {
    return CoordinateFormatter::toUsng(point, option->precision(),option->decimalPlaces());
  }
  case CoordinateType::CoordinateTypeUtm:
  {
    const auto conversionMode = static_cast<Esri::ArcGISRuntime::UtmConversionMode>(option->utmConversionMode());
    return CoordinateFormatter::toUtm(point, conversionMode, option->addSpaces());
  }
  default: {}
  }

  return QString();
}

/*!
  \property CoordinateConversionController::inputMode
  \brief The current input conversion mode used for the \l convertNotation method.
 */
CoordinateType CoordinateConversionController::inputMode() const
{
  return m_inputMode;
}

void CoordinateConversionController::setInputMode(CoordinateType inputMode)
{
  m_inputMode = inputMode;
  emit inputModeChanged();
}

/*!
  \property CoordinateConversionController::results
  \brief The conversion results as a list model.

  The results are automatically updated as conversions are run.
 */
CoordinateConversionResults* CoordinateConversionController::results()
{
  if (!m_results)
  {
    m_results = new CoordinateConversionResults(this);
    connect(m_results, &CoordinateConversionResults::resultsChanged, this, &CoordinateConversionController::resultsChanged);
  }

  return m_results;
}

/*!
  \property CoordinateConversionController::options
  \brief The notation options as a list.
 */
QQmlListProperty<CoordinateConversionOptions> CoordinateConversionController::options()
{
  return QQmlListProperty<CoordinateConversionOptions>(this, &m_options,
                                                       CoordinateConversionOptions::listAppend,
                                                       CoordinateConversionOptions::listCount,
                                                       CoordinateConversionOptions::listAt,
                                                       CoordinateConversionOptions::listClear);
}

/*!
  \brief Sets the spatial reference to \a spatialReference.
  \note This property must be set before calling the \l convertNotation method.
 */
void CoordinateConversionController::setSpatialReference(const Esri::ArcGISRuntime::SpatialReference& spatialReference)
{
  m_spatialReference = spatialReference;
}

/*!
  \property CoordinateConversionController::inputGarsConversionMode
  \brief The inputGarsConversionMode.
  \note This property is only used if the \l inputMode property is set to \c Gars.
 */
CoordinateConversionOptions::GarsConversionMode CoordinateConversionController::inputGarsConversionMode() const
{
  return m_inputGarsConversionMode;
}

void CoordinateConversionController::setInputGarsConversionMode(CoordinateConversionOptions::GarsConversionMode inputGarsConversionMode)
{
  m_inputGarsConversionMode = inputGarsConversionMode;
  emit inputGarsConversionModeChanged();
}

/*!
  \property CoordinateConversionController::inputMgrsConversionMode
  \brief The inputMgrsConversionMode.
  \note This property is only used if the \l inputMode property is set to \c Mgrs.
 */
CoordinateConversionOptions::MgrsConversionMode CoordinateConversionController::inputMgrsConversionMode() const
{
  return m_inputMgrsConversionMode;
}

void CoordinateConversionController::setInputMgrsConversionMode(CoordinateConversionOptions::MgrsConversionMode inputMgrsConversionMode)
{
  m_inputMgrsConversionMode = inputMgrsConversionMode;
  emit inputMgrsConversionModeChanged();
}

/*!
  \property CoordinateConversionController::inputUtmConversionMode
  \brief The inputUtmConversionMode.
  \note This property is only used if the \l inputMode property is set to \c Utm.
 */
CoordinateConversionOptions::UtmConversionMode CoordinateConversionController::inputUtmConversionMode() const
{
  return m_inputUtmConversionMode;
}

void CoordinateConversionController::setInputUtmConversionMode(CoordinateConversionOptions::UtmConversionMode inputUtmConversionMode)
{
  m_inputUtmConversionMode = inputUtmConversionMode;
  emit inputUtmConversionModeChanged();
}

/*!
  \brief Sets the point to be converted via the \l convertPoint method to \a point.
  \note If the \l runConversion property is \c true, the conversion will be run immediately.
 */
void CoordinateConversionController::setPointToConvert(const Esri::ArcGISRuntime::Point& point)
{
  m_pointToConvert = point;

  if (m_runConversion)
    convertPoint();
}

/*!
  \internal
 */
QQmlListProperty<QObject> CoordinateConversionController::objects()
{
  return QQmlListProperty<QObject>(this, nullptr, objectAppend, nullptr, nullptr, nullptr);
}

/*!
  \internal
 */
void CoordinateConversionController::objectAppend(QQmlListProperty<QObject>* property, QObject* value)
{
  auto engine = qobject_cast<CoordinateConversionController*>(property->object);

  if (!engine)
    return;

  auto* option = qobject_cast<CoordinateConversionOptions*>(value);

  if (!option)
    return;

  engine->addOption(option);
}

/*!
  \brief Add the \l CoordinateConversionOptions object \a option to the list of options.
 */
void CoordinateConversionController::addOption(CoordinateConversionOptions* option)
{
  m_options.append(option);
  emit optionsChanged();
}

/*!
  \brief Clear all the \l CoordinateConversionOptions from the list of options.
 */
void CoordinateConversionController::clearOptions()
{
  m_options.clear();
  emit optionsChanged();
}

/*!
  \brief Returns the name of this tool: "CoordinateConversion".
 */
QString CoordinateConversionController::toolName() const
{
  return "CoordinateConversion";
}

/*!
  \brief Copy \a text to the system clipboard.
 */
void CoordinateConversionController::copyToClipboard(const QString& text)
{
  auto clipboard = QGuiApplication::clipboard();
  if (clipboard)
    clipboard->setText(text);
}

/*!
  \brief Clears the results notation strings from the results list model.
 */
void CoordinateConversionController::clearResults()
{
  if (m_results)
    m_results->clearResults();
}

/*!
  \property CoordinateConversionController::runConversion
  \brief Whether the conversion runs automatically when \l setPointToConvert
  is called.
 */
bool CoordinateConversionController::runConversion() const
{
  return m_runConversion;
}

void CoordinateConversionController::setRunConversion(bool runConversion)
{
  m_runConversion = runConversion;
  emit runConversionChanged();
}

// signals

/*!
  \fn void CoordinateConversionController::optionsChanged();
  \brief Signal emitted when the \l options property changes.
 */

/*!
  \fn void CoordinateConversionController::resultsChanged();
  \brief Signal emitted when the \l results property changes.
 */

/*!
  \fn void CoordinateConversionController::inputModeChanged();
  \brief Signal emitted when the \l inputMode property changes.
 */

/*!
  \fn void CoordinateConversionController::inputGarsConversionModeChanged();
  \brief Signal emitted when the \l inputGarsConversionMode property changes.
 */

/*!
  \fn void CoordinateConversionController::inputMgrsConversionModeChanged();
  \brief Signal emitted when the \l inputMgrsConversionMode property changes.
 */

/*!
  \fn void CoordinateConversionController::inputUtmConversionModeChanged();
  \brief Signal emitted when the \l inputUtmConversionMode property changes.
 */

/*!
  \fn void CoordinateConversionController::runConversionChanged();
  \brief Signal emitted when the \l runConversion property changes.
 */

} // Toolkit
} // ArcGISRuntime
} // Esri
<|endoftext|>


<commit_before>/**
* Time Functions
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/time.h>
#include <botan/exceptn.h>
#include <ctime>

#if defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME)
  #include <windows.h>
#endif

#if defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY)
  #include <sys/time.h>
#endif

#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)

  #ifndef _POSIX_C_SOURCE
    #define _POSIX_C_SOURCE 199309
  #endif

  #include <time.h>

  #ifndef CLOCK_REALTIME
    #define CLOCK_REALTIME 0
  #endif

#endif

namespace Botan {

namespace {

/**
* Combine a two time values into a single one
*/
u64bit combine_timers(u32bit seconds, u32bit parts, u32bit parts_hz)
   {
   static const u64bit NANOSECONDS_UNITS = 1000000000;

   u64bit res = seconds * NANOSECONDS_UNITS;
   res += parts * (NANOSECONDS_UNITS / parts_hz);
   return res;
   }

std::tm do_gmtime(time_t time_val)
   {
   // Race condition: std::gmtime is not assured thread safe,
   // and C++ does not include gmtime_r. Use a mutex here?

   std::tm* tm_p = std::gmtime(&time_val);
   if (tm_p == 0)
      throw Encoding_Error("calendar_value could not convert with gmtime");
   return *tm_p;
   }

}

/*
* Convert a time_point to a calendar_point
*/
calendar_point calendar_value(
   const std::chrono::system_clock::time_point& time_point)
   {
   std::tm tm = do_gmtime(std::chrono::system_clock::to_time_t(time_point));

<<<<<<< variant A
   std::tm tm;

#if defined(BOTAN_TARGET_OS_HAS_GMTIME_S)
   gmtime_s(&tm, &time_val); // Windows
#elif defined(BOTAN_TARGET_OS_HAS_GMTIME_R)
   gmtime_r(&time_val, &tm); // Unix/SUSv2
#else
   std::tm* tm_p = std::gmtime(&time_val);
   if (tm_p == 0)
      throw Encoding_Error("time_t_to_tm could not convert");
   tm = *tm_p;
#endif

   return tm;
>>>>>>> variant B
   return calendar_point(tm.tm_year + 1900,
                         tm.tm_mon + 1,
                         tm.tm_mday,
                         tm.tm_hour,
                         tm.tm_min,
                         tm.tm_sec);
####### Ancestor
   std::tm* tm_p = std::gmtime(&time_val);
   if (tm_p == 0)
      throw Encoding_Error("time_t_to_tm could not convert");
   return (*tm_p);
======= end
   }

u64bit get_nanoseconds_clock()
   {
#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
   struct ::timespec tv;
   ::clock_gettime(CLOCK_REALTIME, &tv);
   return combine_timers(tv.tv_sec, tv.tv_nsec, 1000000000);

#elif defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY)
   struct ::timeval tv;
   ::gettimeofday(&tv, 0);
   return combine_timers(tv.tv_sec, tv.tv_usec, 1000000);

#elif defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME)

   // Returns time since January 1, 1601 in 100-ns increments
   ::FILETIME tv;
   ::GetSystemTimeAsFileTime(&tv);
   u64bit tstamp = (static_cast<u64bit>(tv.dwHighDateTime) << 32) |
                   tv.dwLowDateTime;

   return (tstamp * 100); // Scale to 1 nanosecond units

#else
   return combine_timers(std::time(0), std::clock(), CLOCKS_PER_SEC);

#endif
   }

}
<commit_msg>propagate from branch 'net.randombit.botan' (head d2ed6f8447671a5a6ce2df0053e0d69bb22ae1ac)             to branch 'net.randombit.botan.c++0x' (head cb3a496f342feba900b1a2901ed87565602bc1f6)<commit_after>/**
* Time Functions
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/time.h>
#include <botan/exceptn.h>
#include <ctime>

#if defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME)
  #include <windows.h>
#endif

#if defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY)
  #include <sys/time.h>
#endif

#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)

  #ifndef _POSIX_C_SOURCE
    #define _POSIX_C_SOURCE 199309
  #endif

  #include <time.h>

  #ifndef CLOCK_REALTIME
    #define CLOCK_REALTIME 0
  #endif

#endif

namespace Botan {

namespace {

/**
* Combine a two time values into a single one
*/
u64bit combine_timers(u32bit seconds, u32bit parts, u32bit parts_hz)
   {
   static const u64bit NANOSECONDS_UNITS = 1000000000;

   u64bit res = seconds * NANOSECONDS_UNITS;
   res += parts * (NANOSECONDS_UNITS / parts_hz);
   return res;
   }

std::tm do_gmtime(time_t time_val)
   {
   std::tm tm;

#if defined(BOTAN_TARGET_OS_HAS_GMTIME_S)
   gmtime_s(&tm, &time_val); // Windows
#elif defined(BOTAN_TARGET_OS_HAS_GMTIME_R)
   gmtime_r(&time_val, &tm); // Unix/SUSv2
#else
   std::tm* tm_p = std::gmtime(&time_val);
   if (tm_p == 0)
      throw Encoding_Error("time_t_to_tm could not convert");
   tm = *tm_p;
#endif

   return tm;
   }

}

/*
* Convert a time_point to a calendar_point
*/
calendar_point calendar_value(
   const std::chrono::system_clock::time_point& time_point)
   {
   std::tm tm = do_gmtime(std::chrono::system_clock::to_time_t(time_point));

   std::tm tm = do_gmtime(time_val);

   return calendar_point(tm.tm_year + 1900,
                         tm.tm_mon + 1,
                         tm.tm_mday,
                         tm.tm_hour,
                         tm.tm_min,
                         tm.tm_sec);
   }

u64bit get_nanoseconds_clock()
   {
#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
   struct ::timespec tv;
   ::clock_gettime(CLOCK_REALTIME, &tv);
   return combine_timers(tv.tv_sec, tv.tv_nsec, 1000000000);

#elif defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY)
   struct ::timeval tv;
   ::gettimeofday(&tv, 0);
   return combine_timers(tv.tv_sec, tv.tv_usec, 1000000);

#elif defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME)

   // Returns time since January 1, 1601 in 100-ns increments
   ::FILETIME tv;
   ::GetSystemTimeAsFileTime(&tv);
   u64bit tstamp = (static_cast<u64bit>(tv.dwHighDateTime) << 32) |
                   tv.dwLowDateTime;

   return (tstamp * 100); // Scale to 1 nanosecond units

#else
   return combine_timers(std::time(0), std::clock(), CLOCKS_PER_SEC);

#endif
   }

}
<|endoftext|>


<commit_before>// Time:  O(logn)
// Space: O(n)

class Solution {
public:
    Solution(vector<int> w) :
        prefix_sum_(w.size()),
        uni_((random_device())()) {

        partial_sum(w.cbegin(), w.cend(), prefix_sum_.begin(), plus<int>());
        uni_ = uniform_int_distribution<int>{0, prefix_sum_.back() - 1};
    }

    int pickIndex() {
        const auto target = uni_(gen_);
        int left = 0, right = prefix_sum_.size() - 1;
        while (left <= right) {
            const auto mid = left + (right - left) / 2;
            if (prefix_sum_[mid] > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }

private:
    vector<int> prefix_sum_;
    default_random_engine gen_;
    uniform_int_distribution<int> uni_;
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(w);
 * int param_1 = obj.pickIndex();
 */

<commit_msg>Update random-pick-with-weight.cpp<commit_after>// Time:  O(logn)
// Space: O(n)

class Solution {
public:
    Solution(vector<int> w) :
        prefix_sum_(w.size()),
        uni_((random_device())()) {

        partial_sum(w.cbegin(), w.cend(), prefix_sum_.begin(), plus<int>());
        uni_ = uniform_int_distribution<int>{0, prefix_sum_.back() - 1};
    }

    int pickIndex() {
        const auto target = uni_(gen_);
        return upper_bound(prefix_sum_.cbegin(), prefix_sum_.cend(), target) -
               prefix_sum_.cbegin();
    }

private:
    vector<int> prefix_sum_;
    default_random_engine gen_;
    uniform_int_distribution<int> uni_;
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(w);
 * int param_1 = obj.pickIndex();
 */
<|endoftext|>