<commit_before>/** \file    find_tue_dups.cc
 *  \author  Dr. Johannes Ruscheinski
 *
 *  Local data blocks are embedded marc records inside of a record using LOK-Fields.
 *  Each local data block belongs to an institution and is marked by the institution's sigil.
 *  This tool filters for local data blocks of some institutions of the University of Tübingen
 *  and deletes all other local blocks.
 */

/*
    Copyright (C) 2017, Library of the University of Tübingen

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iostream>
#include <cstring>
#include "Compiler.h"
#include "TextUtil.h"
#include "MarcRecord.h"
#include "RegexMatcher.h"
#include "util.h"

void Usage() {
    std::cerr << "Usage: " << ::progname << " --input-format=(BSZ|UB_FREIBURG) marc_input\n";
    std::exit(EXIT_FAILURE);
}

static const RegexMatcher * const tue_sigil_matcher(RegexMatcher::RegexMatcherFactory("^DE-21.*"));

bool FindTueSigil(const MarcRecord * const record, const std::pair<size_t, size_t> &block_start_and_end,
                  std::string * const sigil)
{
    std::vector<size_t> field_indices;
    record->findFieldsInLocalBlock("852", "??", block_start_and_end, &field_indices);

    for (size_t field_index : field_indices) {
        const std::string field_data(record->getFieldData(field_index));
        const Subfields subfields(field_data);
        if (subfields.extractSubfieldWithPattern('a', *tue_sigil_matcher, sigil))
            return true;
    }
    return false;
}

std::string CSVEscape(const std::string &value) {
    std::string escaped_value;
    escaped_value.reserve(value.length());

    std::vector<uint32_t> utf32_chars;
    if (unlikely(not TextUtil::UTF8ToUTF32(value, &utf32_chars)))
        return "";

    for (const uint32_t ch : utf32_chars) {
        if (unlikely(ch == '"'))
            escaped_value += '"';
        escaped_value += TextUtil::UTF32ToUTF8(ch);
    }

    return escaped_value;
}

enum InputFormat { BSZ, UB_FREIBURG };

bool FindTueDups(const InputFormat input_format, const MarcRecord * const record) {
    std::vector<std::string> sigils;
    if (input_format == BSZ) {
        std::vector<std::pair<size_t, size_t>> local_block_boundaries;
        ssize_t local_data_count = record->findAllLocalDataBlocks(&local_block_boundaries);
        if (local_data_count == 0)
            return false;

        for (const auto &block_start_and_end : local_block_boundaries) {
            std::string sigil;
            if (FindTueSigil(record, block_start_and_end, &sigil))
                sigils.emplace_back(sigil);
        }
    } else { // input_format == UB_FREIBURG
        std::vector<size_t> _910_indices;
        record->getFieldIndices("910", &_910_indices);
        for (const size_t _910_index : _910_indices) {
            const std::string _910_field_contents(record->getFieldData(_910_index));
            if (_910_field_contents.empty())
                continue;
            const Subfields subfields(_910_field_contents);
            const std::string sigil(subfields.getFirstSubfieldValue('c'));
            if (not sigil.empty())
                sigils.emplace_back(sigil);
        }
    }

    if (sigils.size() < 2)
        return false;

    const std::string _008_contents(record->getFieldData("008"));
    std::string publication_year;
    if (likely(_008_contents.length() >= 11))
        publication_year = _008_contents.substr(7, 4);

    const std::string _079_contents(record->getFieldData("008"));
    std::string area;
    if (not _079_contents.empty()) {
        const Subfields subfields(_079_contents);
        area = subfields.getFirstSubfieldValue('f');
    }

    const std::string _245_contents(record->getFieldData("245"));
    std::string main_title;
    if (not _245_contents.empty()) {
        const Subfields subfields(_245_contents);
        main_title = subfields.getFirstSubfieldValue('a');
    }

    std::sort(sigils.begin(), sigils.end());
    std::cout << '"' << record->getControlNumber() << "\",\"" << publication_year << "\",\"" << area <<"\",\""
              << CSVEscape(main_title) << "\",\"" << StringUtil::Join(sigils, ',') << "\"\n";

    return true;
}

void FindTueDups(const InputFormat input_format, MarcReader * const marc_reader) {
    unsigned count(0), dups_count(0), monograph_count(0), serial_count(0);
    while (MarcRecord record = marc_reader->read()) {
        ++count;

        // Only consider monographs and serials:
        const Leader &leader(record.getLeader());
        if (not (leader.isMonograph() or leader.isSerial()))
            continue;

        if (FindTueDups(input_format, &record)) {
            ++dups_count;
            if (leader.isMonograph())
                ++monograph_count;
            else
                ++serial_count;
        }
    }
    std::cerr << "Processed " << count << " records and found " << dups_count << " dups (" << monograph_count
              << " monographs and " << serial_count << " serials).\n";
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 3)
        Usage();

    InputFormat input_format;
    if (std::strcmp(argv[1], "--input-format=BSZ") == 0)
        input_format = BSZ;
    else if (std::strcmp(argv[1], "--input-format=UB_FREIBURG") == 0)
        input_format = UB_FREIBURG;
    else
        Error("invalid input format \"" + std::string(argv[1]) + "\"!  (Must be either BSZ or UB_FREIBURG)");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(argv[2], MarcReader::BINARY));

    try {
        FindTueDups(input_format, marc_reader.get());
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Small improvements.<commit_after>/** \file    find_tue_dups.cc
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2017, Library of the University of Tübingen

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iostream>
#include <cstring>
#include "Compiler.h"
#include "TextUtil.h"
#include "MarcRecord.h"
#include "RegexMatcher.h"
#include "util.h"

void Usage() {
    std::cerr << "Usage: " << ::progname << " --input-format=(BSZ|UB_FREIBURG) marc_input\n";
    std::exit(EXIT_FAILURE);
}

static const RegexMatcher * const tue_sigil_matcher(RegexMatcher::RegexMatcherFactory("^DE-21.*"));

bool FindTueSigil(const MarcRecord * const record, const std::pair<size_t, size_t> &block_start_and_end,
                  std::string * const sigil)
{
    std::vector<size_t> field_indices;
    record->findFieldsInLocalBlock("852", "??", block_start_and_end, &field_indices);

    for (size_t field_index : field_indices) {
        const std::string field_data(record->getFieldData(field_index));
        const Subfields subfields(field_data);
        if (subfields.extractSubfieldWithPattern('a', *tue_sigil_matcher, sigil))
            return true;
    }
    return false;
}

std::string CSVEscape(const std::string &value) {
    std::string escaped_value;
    escaped_value.reserve(value.length());

    std::vector<uint32_t> utf32_chars;
    if (unlikely(not TextUtil::UTF8ToUTF32(value, &utf32_chars)))
        return "";

    for (const uint32_t ch : utf32_chars) {
        if (unlikely(ch == '"'))
            escaped_value += '"';
        escaped_value += TextUtil::UTF32ToUTF8(ch);
    }

    return escaped_value;
}

enum InputFormat { BSZ, UB_FREIBURG };

bool FindTueDups(const InputFormat input_format, const char bibliographic_level, const MarcRecord * const record) {
    std::vector<std::string> sigils;
    if (input_format == BSZ) {
        std::vector<std::pair<size_t, size_t>> local_block_boundaries;
        ssize_t local_data_count = record->findAllLocalDataBlocks(&local_block_boundaries);
        if (local_data_count == 0)
            return false;

        for (const auto &block_start_and_end : local_block_boundaries) {
            std::string sigil;
            if (FindTueSigil(record, block_start_and_end, &sigil))
                sigils.emplace_back(sigil);
        }
    } else { // input_format == UB_FREIBURG
        std::vector<size_t> _910_indices;
        record->getFieldIndices("910", &_910_indices);
        for (const size_t _910_index : _910_indices) {
            const std::string _910_field_contents(record->getFieldData(_910_index));
            if (_910_field_contents.empty())
                continue;
            const Subfields subfields(_910_field_contents);
            const std::string sigil(subfields.getFirstSubfieldValue('c'));
            if (not sigil.empty())
                sigils.emplace_back(sigil);
        }
    }

    if (sigils.size() < 2)
        return false;

    const std::string _008_contents(record->getFieldData("008"));
    std::string publication_year;
    if (likely(_008_contents.length() >= 11))
        publication_year = _008_contents.substr(7, 4);

    std::string area;

    // Only determine the area if we're have the sigil of the university main library:
    if (std::find(sigils.cbegin(), sigils.cend(), "21") != sigils.cend()) {
        const std::string _910_contents(record->getFieldData("910"));
        if (not _910_contents.empty()) {
            const Subfields subfields(_910_contents);
            area = subfields.getFirstSubfieldValue('j');
        }
    }

    const std::string _245_contents(record->getFieldData("245"));
    std::string main_title;
    if (not _245_contents.empty()) {
        const Subfields subfields(_245_contents);
        main_title = subfields.getFirstSubfieldValue('a');
    }

    std::sort(sigils.begin(), sigils.end());
    std::cout << '"' << record->getControlNumber() << "\",\"" << bibliographic_level << "\",\"" << publication_year
              << "\",\"" << area <<"\",\"" << CSVEscape(main_title) << "\",\"" << StringUtil::Join(sigils, ',')
              << "\"\n";

    return true;
}

void FindTueDups(const InputFormat input_format, MarcReader * const marc_reader) {
    unsigned count(0), dups_count(0), monograph_count(0), serial_count(0);
    while (MarcRecord record = marc_reader->read()) {
        ++count;

        // Only consider monographs and serials:
        const Leader &leader(record.getLeader());
        if (not (leader.isMonograph() or leader.isSerial()))
            continue;

        if (FindTueDups(input_format, leader.getBibliographicLevel(), &record)) {
            ++dups_count;
            if (leader.isMonograph())
                ++monograph_count;
            else
                ++serial_count;
        }
    }
    std::cerr << "Processed " << count << " records and found " << dups_count << " dups (" << monograph_count
              << " monographs and " << serial_count << " serials).\n";
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 3)
        Usage();

    InputFormat input_format;
    if (std::strcmp(argv[1], "--input-format=BSZ") == 0)
        input_format = BSZ;
    else if (std::strcmp(argv[1], "--input-format=UB_FREIBURG") == 0)
        input_format = UB_FREIBURG;
    else
        Error("invalid input format \"" + std::string(argv[1]) + "\"!  (Must be either BSZ or UB_FREIBURG)");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(argv[2], MarcReader::BINARY));

    try {
        FindTueDups(input_format, marc_reader.get());
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>#ifndef ITER_CHAIN_HPP_
#define ITER_CHAIN_HPP_

#include "internal/iterbase.hpp"

#include <array>
#include <initializer_list>
#include <iterator>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>

namespace iter {
  namespace impl {
    template <typename TupType, std::size_t... Is>
    class Chained;

    template <typename Container>
    class ChainedFromIterable;

    // rather than a chain function, use a callable object to support
    // from_iterable
    class ChainMaker;
  }
}

template <typename TupType, std::size_t... Is>
class iter::impl::Chained {
 private:
  friend class ChainMaker;

  static_assert(std::tuple_size<std::decay_t<TupType>>::value == sizeof...(Is),
      "tuple size != sizeof Is");

  static_assert(
      are_same<iterator_deref<std::tuple_element_t<Is, TupType>>...>::value,
      "All chained iterables must have iterators that "
      "dereference to the same type, including cv-qualifiers "
      "and references.");

  using IterTupType = iterator_tuple_type<TupType>;
  using DerefType = iterator_deref<std::tuple_element_t<0, TupType>>;

  template <std::size_t Idx>
  static DerefType get_and_deref(IterTupType& iters) {
    return *std::get<Idx>(iters);
  }

  template <std::size_t Idx>
  static void get_and_increment(IterTupType& iters) {
    ++std::get<Idx>(iters);
  }

  template <std::size_t Idx>
  static bool get_and_check_not_equal(
      const IterTupType& lhs, const IterTupType& rhs) {
    return std::get<Idx>(lhs) != std::get<Idx>(rhs);
  }

  using DerefFunc = DerefType (*)(IterTupType&);
  using IncFunc = void (*)(IterTupType&);
  using NeqFunc = bool (*)(const IterTupType&, const IterTupType&);

  constexpr static std::array<DerefFunc, sizeof...(Is)> derefers{
      {get_and_deref<Is>...}};

  constexpr static std::array<IncFunc, sizeof...(Is)> incrementers{
      {get_and_increment<Is>...}};

  constexpr static std::array<NeqFunc, sizeof...(Is)> neq_comparers{
      {get_and_check_not_equal<Is>...}};

  using TraitsValue = iterator_traits_deref<std::tuple_element_t<0, TupType>>;

 private:
  TupType tup;

 public:
  Chained(Chained&&) = default;
  Chained(TupType&& t) : tup(std::move(t)) {}

  class Iterator : public std::iterator<std::input_iterator_tag, TraitsValue> {
   private:
    std::size_t index;
    IterTupType iters;
    IterTupType ends;

    void check_for_end_and_adjust() {
      while (this->index < sizeof...(Is)
             && !(neq_comparers[this->index](this->iters, this->ends))) {
        ++this->index;
      }
    }

   public:
    Iterator(std::size_t i, IterTupType&& in_iters, IterTupType&& in_ends)
        : index{i}, iters(in_iters), ends(in_ends) {
      this->check_for_end_and_adjust();
    }

    decltype(auto) operator*() {
      return derefers[this->index](this->iters);
    }

    Iterator& operator++() {
      incrementers[this->index](this->iters);
      this->check_for_end_and_adjust();
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->index != other.index
             || (this->index != sizeof...(Is)
                    && neq_comparers[this->index](this->iters, other.iters));
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {0, IterTupType{std::begin(std::get<Is>(this->tup))...},
        IterTupType{std::end(std::get<Is>(this->tup))...}};
  }

  Iterator end() {
    return {sizeof...(Is), IterTupType{std::end(std::get<Is>(this->tup))...},
        IterTupType{std::end(std::get<Is>(this->tup))...}};
  }
};

template <typename TupType, std::size_t... Is>
constexpr std::array<typename iter::impl::Chained<TupType, Is...>::DerefFunc,
    sizeof...(Is)> iter::impl::Chained<TupType, Is...>::derefers;

template <typename TupType, std::size_t... Is>
constexpr std::array<typename iter::impl::Chained<TupType, Is...>::IncFunc,
    sizeof...(Is)> iter::impl::Chained<TupType, Is...>::incrementers;

template <typename TupType, std::size_t... Is>
constexpr std::array<typename iter::impl::Chained<TupType, Is...>::NeqFunc,
    sizeof...(Is)> iter::impl::Chained<TupType, Is...>::neq_comparers;

template <typename Container>
class iter::impl::ChainedFromIterable {
 private:
  Container container;
  friend class ChainMaker;
  ChainedFromIterable(Container&& in_container)
      : container(std::forward<Container>(in_container)) {}

 public:
  class Iterator : public std::iterator<std::input_iterator_tag,
                       iterator_traits_deref<iterator_deref<Container>>> {
   private:
    using SubContainer = iterator_deref<Container>;
    using SubIter = iterator_type<SubContainer>;

    iterator_type<Container> top_level_iter;
    iterator_type<Container> top_level_end;
    std::unique_ptr<SubIter> sub_iter_p;
    std::unique_ptr<SubIter> sub_end_p;

    static std::unique_ptr<SubIter> clone_sub_pointer(const SubIter* sub_iter) {
      return sub_iter ? std::make_unique<SubIter>(*sub_iter) : nullptr;
    }

    bool sub_iters_differ(const Iterator& other) const {
      if (this->sub_iter_p == other.sub_iter_p) {
        return false;
      }
      if (this->sub_iter_p == nullptr || other.sub_iter_p == nullptr) {
        // since the first check tests if they're the same,
        // this will return if only one is nullptr
        return true;
      }
      return *this->sub_iter_p != *other.sub_iter_p;
    }

   public:
    Iterator(
        iterator_type<Container>&& top_iter, iterator_type<Container>&& top_end)
        : top_level_iter{std::move(top_iter)},
          top_level_end{std::move(top_end)},
          sub_iter_p{!(top_iter != top_end)
                         ?  // iter == end ?
                         nullptr
                         : std::make_unique<SubIter>(std::begin(*top_iter))},
          sub_end_p{!(top_iter != top_end)
                        ?  // iter == end ?
                        nullptr
                        : std::make_unique<SubIter>(std::end(*top_iter))} {}

    Iterator(const Iterator& other)
        : top_level_iter{other.top_level_iter},
          top_level_end{other.top_level_end},
          sub_iter_p{clone_sub_pointer(other.sub_iter_p.get())},
          sub_end_p{clone_sub_pointer(other.sub_end_p.get())} {}

    Iterator& operator=(const Iterator& other) {
      if (this == &other) return *this;

      this->top_level_iter = other.top_level_iter;
      this->top_level_end = other.top_level_end;
      this->sub_iter_p = clone_sub_pointer(other.sub_iter_p.get());
      this->sub_end_p = clone_sub_pointer(other.sub_end_p.get());

      return *this;
    }

    Iterator(Iterator&&) = default;
    Iterator& operator=(Iterator&&) = default;
    ~Iterator() = default;

    Iterator& operator++() {
      ++*this->sub_iter_p;
      if (!(*this->sub_iter_p != *this->sub_end_p)) {
        ++this->top_level_iter;
        if (this->top_level_iter != this->top_level_end) {
          sub_iter_p =
              std::make_unique<SubIter>(std::begin(*this->top_level_iter));
          sub_end_p =
              std::make_unique<SubIter>(std::end(*this->top_level_iter));
        } else {
          sub_iter_p.reset();
          sub_end_p.reset();
        }
      }
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->top_level_iter != other.top_level_iter
             || this->sub_iters_differ(other);
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }

    iterator_deref<iterator_deref<Container>> operator*() {
      return **this->sub_iter_p;
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container)};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container)};
  }
};

class iter::impl::ChainMaker {
 private:
  template <typename TupleType, std::size_t... Is>
  Chained<TupleType, Is...> chain_impl(
      TupleType&& in_containers, std::index_sequence<Is...>) const {
    return {std::move(in_containers)};
  }

 public:
  // expose regular call operator to provide usual chain()
  template <typename... Containers>
  auto operator()(Containers&&... cs) const {
    return this->chain_impl(
        std::tuple<Containers...>{std::forward<Containers>(cs)...},
        std::index_sequence_for<Containers...>{});
  }

  // chain.from_iterable
  template <typename Container>
  ChainedFromIterable<Container> from_iterable(Container&& container) const {
    return {std::forward<Container>(container)};
  }
};

namespace iter {
  namespace {
    constexpr auto chain = iter::impl::ChainMaker{};
  }
}

#endif
<commit_msg>implements chain.from_iterable arrow<commit_after>#ifndef ITER_CHAIN_HPP_
#define ITER_CHAIN_HPP_

#include "internal/iterbase.hpp"

#include <array>
#include <initializer_list>
#include <iterator>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>

namespace iter {
  namespace impl {
    template <typename TupType, std::size_t... Is>
    class Chained;

    template <typename Container>
    class ChainedFromIterable;

    // rather than a chain function, use a callable object to support
    // from_iterable
    class ChainMaker;
  }
}

template <typename TupType, std::size_t... Is>
class iter::impl::Chained {
 private:
  friend class ChainMaker;

  static_assert(std::tuple_size<std::decay_t<TupType>>::value == sizeof...(Is),
      "tuple size != sizeof Is");

  static_assert(
      are_same<iterator_deref<std::tuple_element_t<Is, TupType>>...>::value,
      "All chained iterables must have iterators that "
      "dereference to the same type, including cv-qualifiers "
      "and references.");

  using IterTupType = iterator_tuple_type<TupType>;
  using DerefType = iterator_deref<std::tuple_element_t<0, TupType>>;

  template <std::size_t Idx>
  static DerefType get_and_deref(IterTupType& iters) {
    return *std::get<Idx>(iters);
  }

  template <std::size_t Idx>
  static void get_and_increment(IterTupType& iters) {
    ++std::get<Idx>(iters);
  }

  template <std::size_t Idx>
  static bool get_and_check_not_equal(
      const IterTupType& lhs, const IterTupType& rhs) {
    return std::get<Idx>(lhs) != std::get<Idx>(rhs);
  }

  using DerefFunc = DerefType (*)(IterTupType&);
  using IncFunc = void (*)(IterTupType&);
  using NeqFunc = bool (*)(const IterTupType&, const IterTupType&);

  constexpr static std::array<DerefFunc, sizeof...(Is)> derefers{
      {get_and_deref<Is>...}};

  constexpr static std::array<IncFunc, sizeof...(Is)> incrementers{
      {get_and_increment<Is>...}};

  constexpr static std::array<NeqFunc, sizeof...(Is)> neq_comparers{
      {get_and_check_not_equal<Is>...}};

  using TraitsValue = iterator_traits_deref<std::tuple_element_t<0, TupType>>;

 private:
  TupType tup;

 public:
  Chained(Chained&&) = default;
  Chained(TupType&& t) : tup(std::move(t)) {}

  class Iterator : public std::iterator<std::input_iterator_tag, TraitsValue> {
   private:
    std::size_t index;
    IterTupType iters;
    IterTupType ends;

    void check_for_end_and_adjust() {
      while (this->index < sizeof...(Is)
             && !(neq_comparers[this->index](this->iters, this->ends))) {
        ++this->index;
      }
    }

   public:
    Iterator(std::size_t i, IterTupType&& in_iters, IterTupType&& in_ends)
        : index{i}, iters(in_iters), ends(in_ends) {
      this->check_for_end_and_adjust();
    }

    decltype(auto) operator*() {
      return derefers[this->index](this->iters);
    }

    Iterator& operator++() {
      incrementers[this->index](this->iters);
      this->check_for_end_and_adjust();
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->index != other.index
             || (this->index != sizeof...(Is)
                    && neq_comparers[this->index](this->iters, other.iters));
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {0, IterTupType{std::begin(std::get<Is>(this->tup))...},
        IterTupType{std::end(std::get<Is>(this->tup))...}};
  }

  Iterator end() {
    return {sizeof...(Is), IterTupType{std::end(std::get<Is>(this->tup))...},
        IterTupType{std::end(std::get<Is>(this->tup))...}};
  }
};

template <typename TupType, std::size_t... Is>
constexpr std::array<typename iter::impl::Chained<TupType, Is...>::DerefFunc,
    sizeof...(Is)> iter::impl::Chained<TupType, Is...>::derefers;

template <typename TupType, std::size_t... Is>
constexpr std::array<typename iter::impl::Chained<TupType, Is...>::IncFunc,
    sizeof...(Is)> iter::impl::Chained<TupType, Is...>::incrementers;

template <typename TupType, std::size_t... Is>
constexpr std::array<typename iter::impl::Chained<TupType, Is...>::NeqFunc,
    sizeof...(Is)> iter::impl::Chained<TupType, Is...>::neq_comparers;

template <typename Container>
class iter::impl::ChainedFromIterable {
 private:
  Container container;
  friend class ChainMaker;
  ChainedFromIterable(Container&& in_container)
      : container(std::forward<Container>(in_container)) {}

 public:
  class Iterator : public std::iterator<std::input_iterator_tag,
                       iterator_traits_deref<iterator_deref<Container>>> {
   private:
    using SubContainer = iterator_deref<Container>;
    using SubIter = iterator_type<SubContainer>;

    iterator_type<Container> top_level_iter;
    iterator_type<Container> top_level_end;
    std::unique_ptr<SubIter> sub_iter_p;
    std::unique_ptr<SubIter> sub_end_p;

    static std::unique_ptr<SubIter> clone_sub_pointer(const SubIter* sub_iter) {
      return sub_iter ? std::make_unique<SubIter>(*sub_iter) : nullptr;
    }

    bool sub_iters_differ(const Iterator& other) const {
      if (this->sub_iter_p == other.sub_iter_p) {
        return false;
      }
      if (this->sub_iter_p == nullptr || other.sub_iter_p == nullptr) {
        // since the first check tests if they're the same,
        // this will return if only one is nullptr
        return true;
      }
      return *this->sub_iter_p != *other.sub_iter_p;
    }

   public:
    Iterator(
        iterator_type<Container>&& top_iter, iterator_type<Container>&& top_end)
        : top_level_iter{std::move(top_iter)},
          top_level_end{std::move(top_end)},
          sub_iter_p{!(top_iter != top_end)
                         ?  // iter == end ?
                         nullptr
                         : std::make_unique<SubIter>(std::begin(*top_iter))},
          sub_end_p{!(top_iter != top_end)
                        ?  // iter == end ?
                        nullptr
                        : std::make_unique<SubIter>(std::end(*top_iter))} {}

    Iterator(const Iterator& other)
        : top_level_iter{other.top_level_iter},
          top_level_end{other.top_level_end},
          sub_iter_p{clone_sub_pointer(other.sub_iter_p.get())},
          sub_end_p{clone_sub_pointer(other.sub_end_p.get())} {}

    Iterator& operator=(const Iterator& other) {
      if (this == &other) return *this;

      this->top_level_iter = other.top_level_iter;
      this->top_level_end = other.top_level_end;
      this->sub_iter_p = clone_sub_pointer(other.sub_iter_p.get());
      this->sub_end_p = clone_sub_pointer(other.sub_end_p.get());

      return *this;
    }

    Iterator(Iterator&&) = default;
    Iterator& operator=(Iterator&&) = default;
    ~Iterator() = default;

    Iterator& operator++() {
      ++*this->sub_iter_p;
      if (!(*this->sub_iter_p != *this->sub_end_p)) {
        ++this->top_level_iter;
        if (this->top_level_iter != this->top_level_end) {
          sub_iter_p =
              std::make_unique<SubIter>(std::begin(*this->top_level_iter));
          sub_end_p =
              std::make_unique<SubIter>(std::end(*this->top_level_iter));
        } else {
          sub_iter_p.reset();
          sub_end_p.reset();
        }
      }
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->top_level_iter != other.top_level_iter
             || this->sub_iters_differ(other);
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }

    iterator_deref<iterator_deref<Container>> operator*() {
      return **this->sub_iter_p;
    }

    iterator_arrow<iterator_deref<Container>> operator->() {
      return apply_arrow(*this->sub_iter_p);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container)};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container)};
  }
};

class iter::impl::ChainMaker {
 private:
  template <typename TupleType, std::size_t... Is>
  Chained<TupleType, Is...> chain_impl(
      TupleType&& in_containers, std::index_sequence<Is...>) const {
    return {std::move(in_containers)};
  }

 public:
  // expose regular call operator to provide usual chain()
  template <typename... Containers>
  auto operator()(Containers&&... cs) const {
    return this->chain_impl(
        std::tuple<Containers...>{std::forward<Containers>(cs)...},
        std::index_sequence_for<Containers...>{});
  }

  // chain.from_iterable
  template <typename Container>
  ChainedFromIterable<Container> from_iterable(Container&& container) const {
    return {std::forward<Container>(container)};
  }
};

namespace iter {
  namespace {
    constexpr auto chain = iter::impl::ChainMaker{};
  }
}

#endif
<|endoftext|>


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

#include <string.h>

#include "content/public/app/content_main.h"

namespace node {
int Start(int argc, char *argv[]);
}

#if defined(OS_WIN)

#include <windows.h>  // NOLINT

#include "app/atom_main_delegate.h"
#include "content/public/app/startup_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"

int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* wargv, int argc) {
  const wchar_t* wargv1 = reinterpret_cast<const wchar_t*>(wargv[1]);
  if (argc > 1 && wcscmp(wargv1, L"--atom-child_process-fork") == 0) {
    // Convert argv to to UTF8
    char** argv = new char*[argc];
    for (int i = 0; i < argc; i++) {
      const wchar_t* wargvi = reinterpret_cast<const wchar_t*>(wargv[i]);
      // Compute the size of the required buffer
      DWORD size = WideCharToMultiByte(CP_UTF8,
                                       0,
                                       wargvi,
                                       -1,
                                       NULL,
                                       0,
                                       NULL,
                                       NULL);
      if (size == 0) {
        // This should never happen.
        fprintf(stderr, "Could not convert arguments to utf8.");
        exit(1);
      }
      // Do the actual conversion
      argv[i] = new char[size];
      DWORD result = WideCharToMultiByte(CP_UTF8,
                                         0,
                                         wargvi,
                                         -1,
                                         argv[i],
                                         size,
                                         NULL,
                                         NULL);
      if (result == 0) {
        // This should never happen.
        fprintf(stderr, "Could not convert arguments to utf8.");
        exit(1);
      }
    }
    // Now that conversion is done, we can finally start.
    argv[1] = argv[0];
    return node::Start(argc - 1, argv + 1);
  }

  sandbox::SandboxInterfaceInfo sandbox_info = {0};
  content::InitializeSandboxInfo(&sandbox_info);
  atom::AtomMainDelegate delegate;
  return content::ContentMain(instance, &sandbox_info, &delegate);
}

#else  // defined(OS_WIN)

#include "app/atom_library_main.h"

int main(int argc, const char* argv[]) {
  if (argc > 1 && strcmp(argv[1], "--atom-child_process-fork") == 0) {
    argv[1] = argv[0];
    return node::Start(argc - 1, const_cast<char**>(argv + 1));
  }

  return AtomMain(argc, argv);
}

#endif
<commit_msg>[Win] Fix the command line spliting code.<commit_after>// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string.h>

#include "content/public/app/content_main.h"

namespace node {
int Start(int argc, char *argv[]);
}

#if defined(OS_WIN)

#include <windows.h>  // NOLINT
#include <shellapi.h>  // NOLINT

#include "app/atom_main_delegate.h"
#include "content/public/app/startup_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"

int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
  int argc = 0;
  wchar_t** wargv = ::CommandLineToArgvW(cmd, &argc);
  if (argc > 1 && wcscmp(wargv[1], L"--atom-child_process-fork") == 0) {
    // Convert argv to to UTF8
    char** argv = new char*[argc];
    for (int i = 0; i < argc; i++) {
      // Compute the size of the required buffer
      DWORD size = WideCharToMultiByte(CP_UTF8,
                                       0,
                                       wargv[i],
                                       -1,
                                       NULL,
                                       0,
                                       NULL,
                                       NULL);
      if (size == 0) {
        // This should never happen.
        fprintf(stderr, "Could not convert arguments to utf8.");
        exit(1);
      }
      // Do the actual conversion
      argv[i] = new char[size];
      DWORD result = WideCharToMultiByte(CP_UTF8,
                                         0,
                                         wargv[i],
                                         -1,
                                         argv[i],
                                         size,
                                         NULL,
                                         NULL);
      if (result == 0) {
        // This should never happen.
        fprintf(stderr, "Could not convert arguments to utf8.");
        exit(1);
      }
    }
    // Now that conversion is done, we can finally start.
    argv[1] = argv[0];
    return node::Start(argc - 1, argv + 1);
  }

  sandbox::SandboxInterfaceInfo sandbox_info = {0};
  content::InitializeSandboxInfo(&sandbox_info);
  atom::AtomMainDelegate delegate;
  return content::ContentMain(instance, &sandbox_info, &delegate);
}

#else  // defined(OS_WIN)

#include "app/atom_library_main.h"

int main(int argc, const char* argv[]) {
  if (argc > 1 && strcmp(argv[1], "--atom-child_process-fork") == 0) {
    argv[1] = argv[0];
    return node::Start(argc - 1, const_cast<char**>(argv + 1));
  }

  return AtomMain(argc, argv);
}

#endif
<|endoftext|>


<commit_before>// cells.cpp
// 3-D Rods
// Author: Yuding Ai
// Date: 2015.07.15

#include "cells.h"
extern const string EXC_INVALID_DESC = "Not a valid description of cells!";

Cells::Cells()
{
	Boxlist.clear();
	Planelist.clear();
	N0 = 1;
	N1 = 1;
	N2 = 1;
	size = 1;
	//initialize my cell
	arr = new Square[1];
	arr[0] = Square();
}

Cells::Cells(int X, int Y, int Z, int init,int length)
{
	Boxlist.clear(); // the list of subBox
	Planelist.clear(); // the list of subplane
	N0 = X; // length
	N1 = Y; // width
    N2 = Z; // height
    size = (N0)*(N1)*(N2);
    arr = new Square[size];
    if (init == EMPTY)
    {
    	//initialize my cell with empty config
		for(int i = 0; i < size; i++)
		{
			arr[i] = Square();
		}
    }

    else if (init == BOX)
	{
		//initialize my cell with filling up with subboxes config

    	//firstly: initialize my cell with full config
		for(int i = 0; i < size; i++)
		{
			arr[i] = Square(1);
		}
		//then: randomly filling up it with subboxes
		srand (time(NULL));
    	for(int i = 0; i < X/length; i++)
    	{
			for ( int j = 0; j < Y/length; j++)
			{
				for (int k = 0; k < Z/length; k++)
				{
					int Or; //pick a random config of subbox to add into Box
					Or = rand()%3;
					int l,m,n;
					l = i*length;
					m = j*length;
					n = k*length;
					Boxgen subox(l,m,n,Or,length);
					Boxlist.push_back(subox);
				}
			}
    	}
    }

    else if (init == PLANE)
    {
    	//initialize my cell with filling up with subplane config
    	//firstly: initialize my cell with full config
		for(int i = 0; i < size; i++)
		{
			arr[i] = Square(1);
		}

		//then: randomly filling up it with subplanes
		srand (time(NULL));
		int Pl; // pick an plane first
		Pl = rand()%3;

		if (Pl == X_)
		{
			int Or;// Pick a random Orientation: in the case of X_plane, one can only choose from VER or UP
			for (int i = 0; i < N0; i ++)
			{
				Or = 2*(rand()%2);// Or can be either 0 --> Ver or 2 --> UP;
				Planegen subplane(X_, i, N0, Or, length);
				// Planegen(int Plane, int Lay, int L, int Orien,int Len);
				Planelist.push_back(subplane);
			}

		}

		else if (Pl == Y_)
		{
			int Or;// Pick a random Orientation: in the case of Y_plane, one can only choose from HOR or UP
			for (int i = 0; i< N1; i++)
			{
				Or = rand()%2 +1;// Or can be either 1 --> HOR or 2 --> UP;
				Planegen subplane(Y_, i, N1, Or, length);
				Planelist.push_back(subplane);
			}
		}

		else if (Pl == Z_)
		{
			int Or;// Pick a random Orientation: in the case of Z_plane, one can only choose from VER or HOR
			for (int i = 0; i<N2; i++)
			{
				Or = rand()%2; // Or can be either 0 --> VER or 1 --> HOR;
				Planegen subplane(Z_, i, N2, Or, length);
				Planelist.push_back(subplane);
			}
		}
    }
}

/*
*  Destructor
*/
Cells::~Cells()
{
	if(arr)
	{
		delete [] arr;
	}
}

// *** Getters *** //
int Cells::getN0() const
{
	return N0;
}
int Cells::getN1() const
{
	return N1;
}

int Cells::getN2() const
{
	return N2;
}
int Cells::getSize() const
{
	return (N0)*(N1)*(N2);
}

const vector<Boxgen>& Cells::getBoxlist() const
{
	return Boxlist;
}

const vector<Planegen>& Cells::getPlanelist() const
{
	return Planelist;
}
// *** Other Functionality *** //

int Cells::getIdx( int x, int y, int z) const
{
	return  x + N0*y + N1*N0*z;
}

Square& Cells::getSquare( int x, int y, int z) const
{
	if (x >= N0 || y >= N1 || z >= N2)
	{
		throw EXC_INVALID_DESC;
	}

	int idx = getIdx(x,y,z);
	return arr[idx];
}

<commit_msg>fix bug in cells.cpp<commit_after>// cells.cpp
// 3-D Rods
// Author: Yuding Ai
// Date: 2015.07.15

#include "cells.h"
extern const string EXC_INVALID_DESC = "Not a valid description of cells!";

Cells::Cells()
{
	Boxlist.clear();
	Planelist.clear();
	N0 = 1;
	N1 = 1;
	N2 = 1;
	size = 1;
	//initialize my cell
	arr = new Square[1];
	arr[0] = Square();
}

Cells::Cells(int X, int Y, int Z, int init,int length)
{
	Boxlist.clear(); // the list of subBox
	Planelist.clear(); // the list of subplane
	N0 = X; // length
	N1 = Y; // width
    N2 = Z; // height
    size = (N0)*(N1)*(N2);
    arr = new Square[size];
    if (init == EMPTY)
    {
    	//initialize my cell with empty config
		for(int i = 0; i < size; i++)
		{
			arr[i] = Square();
		}
    }

    else if (init == BOX)
	{
		//initialize my cell with filling up with subboxes config

    	//firstly: initialize my cell with full config
		for(int i = 0; i < size; i++)
		{
			arr[i] = Square(1);
		}
		//then: randomly filling up it with subboxes
		srand (time(NULL));
    	for(int i = 0; i < X/length; i++)
    	{
			for ( int j = 0; j < Y/length; j++)
			{
				for (int k = 0; k < Z/length; k++)
				{
					int Or; //pick a random config of subbox to add into Box
					Or = rand()%3;
					int l,m,n;
					l = i*length;
					m = j*length;
					n = k*length;
					Boxgen subox(l,m,n,Or,length);
					Boxlist.push_back(subox);
				}
			}
    	}
    }

    else if (init == PLANE)
    {
    	//initialize my cell with filling up with subplane config
    	//firstly: initialize my cell with full config
		for(int i = 0; i < size; i++)
		{
			arr[i] = Square(1);
		}

		//then: randomly filling up it with subplanes
		srand (time(NULL));
		int Pl; // pick an plane first
		Pl = rand()%3;

		if (Pl == X_)
		{
			int Or;// Pick a random Orientation: in the case of X_plane, one can only choose from VER or UP
			for (int i = 0; i < N0; i ++)
			{
				Or = 2*(rand()%2);// Or can be either 0 --> Ver or 2 --> UP;
				Planegen subplane(X_, i, N0, Or, length);
				// Planegen(int Plane, int Lay, int L, int Orien,int Len);
				Planelist.push_back(subplane);
			}

		}

		else if (Pl == Y_)
		{
			int Or;// Pick a random Orientation: in the case of Y_plane, one can only choose from HOR or UP
			for (int i = 0; i< N1; i++)
			{
				Or = rand()%2 +1;// Or can be either 1 --> HOR or 2 --> UP;
				Planegen subplane(Y_, i, N1, Or, length);
				Planelist.push_back(subplane);
			}
		}

		else if (Pl == Z_)
		{
			int Or;// Pick a random Orientation: in the case of Z_plane, one can only choose from VER or HOR
			for (int i = 0; i<N2; i++)
			{
				Or = rand()%2; // Or can be either 0 --> VER or 1 --> HOR;
				Planegen subplane(Z_, i, N2, Or, length);
				Planelist.push_back(subplane);
			}
		}
    }
}

/*
*  Destructor
*/
Cells::~Cells()
{
	delete [] arr;
}

// *** Getters *** //
int Cells::getN0() const
{
	return N0;
}
int Cells::getN1() const
{
	return N1;
}

int Cells::getN2() const
{
	return N2;
}
int Cells::getSize() const
{
	return (N0)*(N1)*(N2);
}

const vector<Boxgen>& Cells::getBoxlist() const
{
	return Boxlist;
}

const vector<Planegen>& Cells::getPlanelist() const
{
	return Planelist;
}
// *** Other Functionality *** //

int Cells::getIdx( int x, int y, int z) const
{
	return  x + N0*y + N1*N0*z;
}

Square& Cells::getSquare( int x, int y, int z) const
{
	if (x >= N0 || y >= N1 || z >= N2)
	{
		throw EXC_INVALID_DESC;
	}

	int idx = getIdx(x,y,z);
	return arr[idx];
}

<|endoftext|>


<commit_before>/* Copyright (c) 2013 Simeon Bird <spb@ias.edu>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */

#include <cmath>

#define  BOLTZMANN   1.3806504e-23  /* m2 kg s-2 K-1 */
#define  LIGHT           2.99792458e8 /*in km/s*/
#define  PROTONMASS  1.66053886e-27 /* 1 a.m.u */
#define  KPC 3.08568025e19 /*in m*/
#define  SIGMA_T 6.652458558e-29 /* Thompson cross-section in m^2*/

class LineAbsorption
{
    public:
      LineAbsorption(const double lambda, const double gamma, const double fosc, const double amumass):
      sigma_a( sqrt(3.0*M_PI*SIGMA_T/8.0) * lambda  * fosc ),
      bfac( sqrt(2.0*BOLTZMANN/(amumass*PROTONMASS)) ),
      voigt_fac( gamma*lambda/(4.*M_PI) )
      {    }

      /* Compute the absorption in a single bin, using
       * either straight Gaussian or a Voigt profile.
       * Arguments:
       * colden: column density of absorber in amu per m^2.
       * vdiff: the relative velocities between absorper and bin.
       * temp: temperature of absorber in K
       */
      inline double tau_single(const double colden, const double vdiff, const double temp)
      {
          /* b has the units of velocity: km/s*/
          const double b_H1   = bfac*sqrt(temp);
          const double T0 = pow(vdiff/b_H1,2);
          const double T1 = exp(-T0);
          /* Voigt profile: Tepper-Garcia, 2006, MNRAS, 369, 2025
           * includes thermal and doppler broadening. */
        #ifdef VOIGT
          const double aa_H1 = voigt_fac/b_H1;
          const double T2 = 1.5/T0;
          const double profile_H1 = (T0 < 1.e-6 ? T1 : T1 - aa_H1/sqrt(M_PI)/T0*(T1*T1*(4.0*T0*T0 + 7.0*T0 + 4.0 + T2) - T2 -1.0));
        #else
          const double profile_H1 = T1;
        #endif
          return sigma_a / sqrt(M_PI) * (LIGHT/b_H1) * colden * profile_H1;
      }

      /* Absorption cross-sections m^2 */
      const double sigma_a;
      /* Constant factor to turn sqrt(temperature) into velocity*/
      const double bfac;
      /* Factor to turn b into a dimensionless Voigt profile broadening factor,
       * giving the balance between doppler and thermal broadening. */
      const double voigt_fac;
};

/*****************************************************************************/
/* This function calculates absorption from a given integrated temperature, density
 * and line profile properties.
 * Note: a lot of variables are named _H1. This is historical: the function works for arbitrary species.
 * Arguments are:
 * tau_H1: Array to store the ouput optical depth
 * H1 : species with density, velocity and temperature arrays
 * Hz: conversion factor from linear to velocity space, Hubble(z) in km/s/Mpc
 * box100: box size in comoving kpc/h
 * h100: hubble constant h (~ 0.7)
 * atime: a = 1/(1+z)
 * lambda_lya, gamma_lya, fosc_lya: parameters of the atomic transition (use those from VPFIT)
 * mass: mass of the species in amu
 * */
void Compute_Absorption(double * tau_H1, double * rho, double * veloc, double * temp, const int nbins, const double Hz, const double h100, const double box100, const double atime, const double lambda_lya, const double gamma_lya, const double fosc_lya, const double mass)
{
  /* Conversion factors from internal units */
  const double rscale = (KPC*atime)/h100;   /* convert length to m */
  /*    Calculate the length scales to be used in the box */
  const double vmax = box100 * Hz * rscale/ (1e3*KPC); /* box size (kms^-1) */
  const double dzgrid   = box100 * rscale / (double) nbins; /* bin size m */
  const double dvbin = dzgrid * Hz / (1e3*KPC); /* velocity bin size (kms^-1) */
  LineAbsorption line(lambda_lya, gamma_lya, fosc_lya, mass);
  /* Compute the HI Lya spectra */
  for(int i=0;i<nbins;i++){
      for(int j=0;j<nbins;j++)
        {
          double u_H1, vdiff_H1;

          u_H1  = dvbin*j*1.0e3;
      #ifdef PECVEL
          u_H1 +=veloc[j]*1.0e3;
      #endif
          /* Note this is indexed with i, above with j!
           * This is the difference in velocities between two clouds
           * on the same sightline*/
          vdiff_H1  = fabs(dvbin*i*1.0e3 - u_H1); /* ms^-1 */
       #ifdef PERIODIC
          if (vdiff_H1 > (vmax/2.0*1.0e3))
              vdiff_H1 = (vmax*1.0e3) - vdiff_H1;
       #endif
          tau_H1[j] += line.tau_single(dzgrid * rho[j]/(mass*PROTONMASS), vdiff_H1, temp[j]);
        }
  }             /* Spectrum convolution */

  return;
}

<commit_msg>Extend the LineAbsorption class with a new interpolation method that computes directly the optical depth from each particle, rather than averaging all particles into binned absorbers and computing the optical depth from them.<commit_after>/* Copyright (c) 2013 Simeon Bird <spb@ias.edu>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */

#include <cmath>

#define  BOLTZMANN   1.3806504e-23  /* m2 kg s-2 K-1 */
#define  LIGHT           2.99792458e8 /*in km/s*/
#define  PROTONMASS  1.66053886e-27 /* 1 a.m.u */
#define  KPC 3.08568025e19 /*in m*/
#define  SIGMA_T 6.652458558e-29 /* Thompson cross-section in m^2*/

class LineAbsorption
{
    public:
      LineAbsorption(const double lambda, const double gamma, const double fosc, const double amumass):
      sigma_a( sqrt(3.0*M_PI*SIGMA_T/8.0) * lambda  * fosc ),
      bfac( sqrt(2.0*BOLTZMANN/(amumass*PROTONMASS)) ),
      voigt_fac( gamma*lambda/(4.*M_PI) )
      {    }

      /* Compute the absorption in a single bin, using
       * either straight Gaussian or a Voigt profile.
       * Arguments:
       * colden: column density of absorber in amu per m^2.
       * vdiff: the relative velocities between absorper and bin.
       * temp: temperature of absorber in K
       */
      inline double tau_single(const double colden, const double vdiff, const double temp)
      {
          /* b has the units of velocity: km/s*/
          const double b_H1   = bfac*sqrt(temp);
          const double T0 = pow(vdiff/b_H1,2);
          const double T1 = exp(-T0);
          /* Voigt profile: Tepper-Garcia, 2006, MNRAS, 369, 2025
           * includes thermal and doppler broadening. */
        #ifdef VOIGT
          const double aa_H1 = voigt_fac/b_H1;
          const double T2 = 1.5/T0;
          const double profile_H1 = (T0 < 1.e-6 ? T1 : T1 - aa_H1/sqrt(M_PI)/T0*(T1*T1*(4.0*T0*T0 + 7.0*T0 + 4.0 + T2) - T2 -1.0));
        #else
          const double profile_H1 = T1;
        #endif
          return sigma_a / sqrt(M_PI) * (LIGHT/b_H1) * colden * profile_H1;
      }

      /* Absorption cross-sections m^2 */
      const double sigma_a;
      /* Constant factor to turn sqrt(temperature) into velocity*/
      const double bfac;
      /* Factor to turn b into a dimensionless Voigt profile broadening factor,
       * giving the balance between doppler and thermal broadening. */
      const double voigt_fac;
};

/*****************************************************************************/
/* This function calculates absorption from a given integrated temperature, density
 * and line profile properties.
 * Note: a lot of variables are named _H1. This is historical: the function works for arbitrary species.
 * Arguments are:
 * tau_H1: Array to store the ouput optical depth
 * H1 : species with density, velocity and temperature arrays
 * Hz: conversion factor from linear to velocity space, Hubble(z) in km/s/Mpc
 * box100: box size in comoving kpc/h
 * h100: hubble constant h (~ 0.7)
 * atime: a = 1/(1+z)
 * lambda_lya, gamma_lya, fosc_lya: parameters of the atomic transition (use those from VPFIT)
 * mass: mass of the species in amu
 * */
void Compute_Absorption(double * tau_H1, double * rho, double * veloc, double * temp, const int nbins, const double Hz, const double h100, const double box100, const double atime, const double lambda_lya, const double gamma_lya, const double fosc_lya, const double mass)
{
  /* Conversion factors from internal units */
  const double rscale = (KPC*atime)/h100;   /* convert length to m */
  /*    Calculate the length scales to be used in the box */
  const double vmax = box100 * Hz * rscale/ (1e3*KPC); /* box size (kms^-1) */
  const double dzgrid   = box100 * rscale / (double) nbins; /* bin size m */
  const double dvbin = dzgrid * Hz / (1e3*KPC); /* velocity bin size (kms^-1) */
  LineAbsorption line(lambda_lya, gamma_lya, fosc_lya, mass);
  /* Compute the HI Lya spectra */
  for(int i=0;i<nbins;i++){
      for(int j=0;j<nbins;j++)
        {
          double u_H1, vdiff_H1;

          u_H1  = dvbin*j*1.0e3;
      #ifdef PECVEL
          u_H1 +=veloc[j]*1.0e3;
      #endif
          /* Note this is indexed with i, above with j!
           * This is the difference in velocities between two clouds
           * on the same sightline*/
          vdiff_H1  = fabs(dvbin*i*1.0e3 - u_H1); /* ms^-1 */
       #ifdef PERIODIC
          if (vdiff_H1 > (vmax/2.0*1.0e3))
              vdiff_H1 = (vmax*1.0e3) - vdiff_H1;
       #endif
          tau_H1[j] += line.tau_single(dzgrid * rho[j]/(mass*PROTONMASS), vdiff_H1, temp[j]);
        }
  }             /* Spectrum convolution */

  return;
}

#define NGRID 8

inline double sph_kernel(const double q)
{
    if(q<0.5)
        return 1-6*q*q+6*q*q*q;
    else
        return 2*pow(1.- q,3);
}

/* Find the fraction of the total particle density in this pixel by integrating an SPH kernel
 * over the z direction. All distances in units of smoothing length.
 * Arguments:
 * zlow - Lower z limit for the integral (as z distance from particle center).
 * zhigh - Upper z limit for the integral (again as distance from particle center)
 * bb2 - transverse distance from particle to pixel, squared.
 * */
double sph_kern_frac(double zlow, double zhigh, double bb2)
{
    double total = sph_kernel(sqrt(bb2+zlow*zlow))/2.;
    const double deltaz=(zhigh-zlow)/NGRID;
    for(int i=1; i<NGRID; ++i)
    {
        const double zz = i*deltaz+zlow;
        const double q = sqrt(bb2+zz*zz);
        if(q > 1)
            break;
        total+=sph_kernel(q);
    }
    double qhigh = sqrt(bb2+zhigh*zhigh);
    if (qhigh < 1)
        total += sph_kernel(qhigh)/2.;
    return 8*deltaz*total/M_PI;
}

/* Conversion factors from internal units */
//const double rscale = (KPC*atime)/h100;   /* convert length to m */
//
class ComputeLineAbsorption: public LineAbsorption
{
    public:
        /*Dimensions:
         * velocities in km/s (physical).
         * distances in kpc/h (comoving)
         * velfac: factor to convert from distance to velocity units.
         * Should be h100 * atime * Hz/1e3 (Hz in km/s/Mpc)
         * */
        //This makes dvbin be in km/s: the 1e3 converts Hz from km/s/Mpc to km/s/kpc
        // kpc /h       h                    km/s/kpc
        //vbox = ( box100 * h100 * atime * Hz/1e3 ) /* box size (kms^-1) */
        ComputeLineAbsorption(const double lambda_lya, const double gamma_lya, const double fosc_lya, const double mass, const double velfac_i, const double boxsize):
        LineAbsorption(lambda_lya, gamma_lya, fosc_lya, mass),
        amumass(mass), velfac(velfac_i), vbox(boxsize*velfac_i)
        {
        }

        /* Add the absorption from a particle to the spectrum in the array
         * tau, and the density from the particle to the array colden
         * The slightly C-style interface is so we can easily use the data in python.
         *
         * Output:
         * tau: array specifying the optical depth of the spectrum.
         * If this is NULL, just compute the column density.
         * colden: array specifying the column density of the spectrum. (atoms/ (comoving kpc/h)^2)
         * nbins: Size of above arrays
         *
         * Input:
         * dr2: transverse distance to spectra from particle (comoving kpc/h)
         * mass: mass of particle in absorping species (kg)
         * ppos: particle distance from box edge parallel to spectrum (comoving kpc/h)
         * pvel: particle velocity parallel to spectrum (physical km/s)
         * temp: particle temperature (K)
         * smooth: particle smoothing length (comoving kpc/h)
         */
        void add_particle(double * tau, double * colden, const int nbins, const double dr2, const double mass, const double ppos, const double pvel, const double temp, const double smooth)
        {
          /*Factor to convert the dimensionless quantity found by sph_kern_frac to a column density.*/
          const double avgdens = mass/(amumass*PROTONMASS*pow(smooth,3));
          /*Impact parameter in units of the smoothing length */
          const double bb2 = dr2/smooth/smooth;
          /* Velocity of particle parallel to los: pos in */
          double vel = (velfac * ppos + pvel );
          if (vel > vbox ){
              vel -= vbox*floor(vel/vbox);
          }
          const double vsmooth = velfac * smooth;
          const double zrange = sqrt(smooth*smooth - dr2);
          const int zlow = floor((nbins/vbox) * velfac * (ppos - zrange));
          const int zhigh = ceil((nbins/vbox) * velfac * (ppos + zrange));
          /* Compute the HI Lya spectra */
          for(int z=zlow; z<zhigh; z++)
          {
              const int j = (z+nbins ) % nbins;
              /*Difference between velocity of bin edges and particle*/
              const double vlow = (vel - vbox*j/nbins)/vsmooth;
              const double vhigh= (vel - vbox*(j+1)/nbins)/vsmooth;

              const double colden_this = avgdens*sph_kern_frac(vlow, vhigh, bb2);
              colden[j] += colden_this;
              /* Loop again, because the column density that contributes to this
               * bin may be broadened thermal or doppler broadened*/
              //Add natural broadening someday
              //
              if (tau) {
                for(int i=0;j<nbins;i++)
                {
                    double vdiff = fabs(vbox*(i-j)/nbins);
                    if (vdiff > (vbox/2.0))
                      vdiff = vbox - vdiff;
                    tau[i] += tau_single(colden_this, vdiff, temp);
                }
              }
          }

          return;
        }

        const double amumass, velfac, vbox;
};

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: persist.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2003-03-18 13:48:51 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <precomp.h>
#include <cosv/persist.hxx>

// NOT FULLY DECLARED SERVICES
#include <cosv/streamstr.hxx>
#include <cosv/ploc.hxx>

#ifdef WNT
#include <io.h>

namespace csv
{
namespace ploc
{

bool
Persistent::Exists() const
{
    return access( StrPath(), 00) == 0;
}

} // namespace ploc
} // namespace csv

#elif defined(UNX)
#include <unistd.h>

/*
#ifndef __SUNPRO_CC
#include <unistd.h>
#else
#define F_OK    0   // Test for existence of File
extern int access(const char *, int);
#endif
*/

namespace csv
{
namespace ploc
{

bool
Persistent::Exists() const
{
    return access( StrPath(), F_OK ) == 0;
}

} // namespace ploc
} // namespace csv

#else
#error  For using csv::ploc there has to be defined: WNT or UNX.
#endif

namespace csv
{
namespace ploc
{

const char *
Persistent::StrPath() const
{
    if (sPath.empty() )
    {
#ifndef CSV_NO_MUTABLE
        StreamStr & rsPath = sPath;
#else
        StreamStr & rsPath = const_cast< StreamStr& >(sPath);
#endif
        rsPath.seekp(0);
        rsPath << MyPath();
        if (MyPath().IsDirectory())
            rsPath.pop_back(1);    // Remove closing delimiter.
    }
    return sPath.c_str();
}

} // namespace ploc
} // namespace csv

<commit_msg>INTEGRATION: CWS ooo19126 (1.2.86); FILE MERGED 2005/09/05 14:09:00 rt 1.2.86.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: persist.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 08:06:50 $
 *
 *  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
 *
 ************************************************************************/

#include <precomp.h>
#include <cosv/persist.hxx>

// NOT FULLY DECLARED SERVICES
#include <cosv/streamstr.hxx>
#include <cosv/ploc.hxx>

#ifdef WNT
#include <io.h>

namespace csv
{
namespace ploc
{

bool
Persistent::Exists() const
{
    return access( StrPath(), 00) == 0;
}

} // namespace ploc
} // namespace csv

#elif defined(UNX)
#include <unistd.h>

/*
#ifndef __SUNPRO_CC
#include <unistd.h>
#else
#define F_OK    0   // Test for existence of File
extern int access(const char *, int);
#endif
*/

namespace csv
{
namespace ploc
{

bool
Persistent::Exists() const
{
    return access( StrPath(), F_OK ) == 0;
}

} // namespace ploc
} // namespace csv

#else
#error  For using csv::ploc there has to be defined: WNT or UNX.
#endif

namespace csv
{
namespace ploc
{

const char *
Persistent::StrPath() const
{
    if (sPath.empty() )
    {
#ifndef CSV_NO_MUTABLE
        StreamStr & rsPath = sPath;
#else
        StreamStr & rsPath = const_cast< StreamStr& >(sPath);
#endif
        rsPath.seekp(0);
        rsPath << MyPath();
        if (MyPath().IsDirectory())
            rsPath.pop_back(1);    // Remove closing delimiter.
    }
    return sPath.c_str();
}

} // namespace ploc
} // namespace csv

<|endoftext|>


<commit_before><commit_msg>Revert "Dupe code removal in cui"<commit_after><|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "IncrementalParser.h"

#include "ASTDumper.h"
#include "ChainedConsumer.h"
#include "DeclExtractor.h"
#include "DynamicLookup.h"
#include "ValuePrinterSynthesizer.h"
#include "cling/Interpreter/CIFactory.h"
#include "cling/Interpreter/Interpreter.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/FileManager.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Parse/Parser.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Serialization/ASTWriter.h"

#include "llvm/LLVMContext.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_os_ostream.h"

#include <ctime>
#include <iostream>
#include <stdio.h>
#include <sstream>

using namespace clang;

namespace cling {
  IncrementalParser::IncrementalParser(Interpreter* interp,
                                       int argc, const char* const *argv,
                                       const char* llvmdir):
    m_Interpreter(interp),
    m_DynamicLookupEnabled(false),
    m_Consumer(0),
    m_FirstTopLevelDecl(0),
    m_LastTopLevelDecl(0),
    m_SyntaxOnly(false)
  {
    CompilerInstance* CI
      = CIFactory::createCI(llvm::MemoryBuffer::getMemBuffer("", "CLING"),
                            argc, argv, llvmdir);
    assert(CI && "CompilerInstance is (null)!");
    m_CI.reset(CI);
    m_SyntaxOnly = (CI->getFrontendOpts().ProgramAction == clang::frontend::ParseSyntaxOnly);

    CreateSLocOffsetGenerator();

    m_Consumer = dyn_cast<ChainedConsumer>(&CI->getASTConsumer());
    assert(m_Consumer && "Expected ChainedConsumer!");
    // Add consumers to the ChainedConsumer, which owns them
    EvaluateTSynthesizer* ES = new EvaluateTSynthesizer(interp);
    ES->Attach(m_Consumer);
    addConsumer(ChainedConsumer::kEvaluateTSynthesizer, ES);

    DeclExtractor* DE = new DeclExtractor();
    DE->Attach(m_Consumer);
    addConsumer(ChainedConsumer::kDeclExtractor, DE);

    ValuePrinterSynthesizer* VPS = new ValuePrinterSynthesizer(interp);
    VPS->Attach(m_Consumer);
    addConsumer(ChainedConsumer::kValuePrinterSynthesizer, VPS);
    addConsumer(ChainedConsumer::kASTDumper, new ASTDumper());
    if (!m_SyntaxOnly) {
      CodeGenerator* CG = CreateLLVMCodeGen(CI->getDiagnostics(),
                                            "cling input",
                                            CI->getCodeGenOpts(),
                                  /*Owned by codegen*/ * new llvm::LLVMContext()
                                            );
      assert(CG && "No CodeGen?!");
      addConsumer(ChainedConsumer::kCodeGenerator, CG);
    }
    m_Consumer->Initialize(CI->getASTContext());
    m_Consumer->InitializeSema(CI->getSema());
    // Initialize the parser.
    m_Parser.reset(new Parser(CI->getPreprocessor(), CI->getSema()));
    CI->getPreprocessor().EnterMainSourceFile();
    m_Parser->Initialize();
  }

  // Each input line is contained in separate memory buffer. The SourceManager
  // assigns sort-of invalid FileID for each buffer, i.e there is no FileEntry
  // for the MemoryBuffer's FileID. That in turn is problem because invalid
  // SourceLocations are given to the diagnostics. Thus the diagnostics cannot
  // order the overloads, for example
  //
  // Our work-around is creating a virtual file, which doesn't exist on the disk
  // with enormous size (no allocation is done). That file has valid FileEntry
  // and so on... We use it for generating valid SourceLocations with valid
  // offsets so that it doesn't cause any troubles to the diagnostics.
  //
  // +---------------------+
  // | Main memory buffer  |
  // +---------------------+
  // |  Virtual file SLoc  |
  // |    address space    |<-----------------+
  // |         ...         |<------------+    |
  // |         ...         |             |    |
  // |         ...         |<----+       |    |
  // |         ...         |     |       |    |
  // +~~~~~~~~~~~~~~~~~~~~~+     |       |    |
  // |     input_line_1    | ....+.......+..--+
  // +---------------------+     |       |
  // |     input_line_2    | ....+.....--+
  // +---------------------+     |
  // |          ...        |     |
  // +---------------------+     |
  // |     input_line_N    | ..--+
  // +---------------------+
  //
  void IncrementalParser::CreateSLocOffsetGenerator() {
    SourceManager& SM = getCI()->getSourceManager();
    FileManager& FM = SM.getFileManager();
    const FileEntry* FE
      = FM.getVirtualFile("Interactrive/InputLineIncluder", 1U << 15U, time(0));
    m_VirtualFileID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);

    assert(!m_VirtualFileID.isInvalid() && "No VirtualFileID created?");
  }

  IncrementalParser::~IncrementalParser() {
     if (GetCodeGenerator()) {
       GetCodeGenerator()->ReleaseModule();
     }
  }

  void IncrementalParser::Initialize() {

    // Init the consumers

    CompileAsIs(""); // Consume initialization.
  }

  IncrementalParser::EParseResult
  IncrementalParser::CompileLineFromPrompt(llvm::StringRef input) {
    assert(input.str()[0] != '#'
           && "Preprocessed line! Call CompilePreprocessed instead");

    bool p, q;
    m_Consumer->RestorePreviousState(ChainedConsumer::kEvaluateTSynthesizer,
                                     isDynamicLookupEnabled());

    p = m_Consumer->EnableConsumer(ChainedConsumer::kDeclExtractor);
    q = m_Consumer->EnableConsumer(ChainedConsumer::kValuePrinterSynthesizer);
    EParseResult Result = Compile(input);
    m_Consumer->RestorePreviousState(ChainedConsumer::kDeclExtractor, p);
    m_Consumer->RestorePreviousState(ChainedConsumer::kValuePrinterSynthesizer, q);

    return Result;

  }

  IncrementalParser::EParseResult
  IncrementalParser::CompileAsIs(llvm::StringRef input) {
    bool p, q;
    m_Consumer->RestorePreviousState(ChainedConsumer::kEvaluateTSynthesizer,
                                     isDynamicLookupEnabled());

    p = m_Consumer->DisableConsumer(ChainedConsumer::kDeclExtractor);
    q = m_Consumer->DisableConsumer(ChainedConsumer::kValuePrinterSynthesizer);
    EParseResult Result = Compile(input);
    m_Consumer->RestorePreviousState(ChainedConsumer::kDeclExtractor, p);
    m_Consumer->RestorePreviousState(ChainedConsumer::kValuePrinterSynthesizer, q);

    return Result;
  }

  void IncrementalParser::Parse(llvm::StringRef input,
                                llvm::SmallVector<DeclGroupRef, 4>& DGRs){
    if (!m_SyntaxOnly)
      m_Consumer->DisableConsumer(ChainedConsumer::kCodeGenerator);

    Parse(input);
    for (llvm::SmallVector<ChainedConsumer::DGRInfo, 64>::iterator
           I = m_Consumer->DeclsQueue.begin(), E = m_Consumer->DeclsQueue.end();
         I != E; ++I) {
      DGRs.push_back((*I).D);
    }

    if (!m_SyntaxOnly)
      m_Consumer->EnableConsumer(ChainedConsumer::kCodeGenerator);
  }

  IncrementalParser::EParseResult
  IncrementalParser::Compile(llvm::StringRef input) {
    // Just in case when Parse is called, we want to complete the transaction
    // coming from parse and then start new one.
    m_Consumer->HandleTranslationUnit(getCI()->getASTContext());

    // Reset the module builder to clean up global initializers, c'tors, d'tors:
    if (GetCodeGenerator()) {
      GetCodeGenerator()->Initialize(getCI()->getASTContext());
    }

    EParseResult Result = Parse(input);

    // Check for errors coming from our custom consumers.
    DiagnosticConsumer& DClient = m_CI->getDiagnosticClient();
    DClient.BeginSourceFile(getCI()->getLangOpts(), &getCI()->getPreprocessor());
    m_Consumer->HandleTranslationUnit(getCI()->getASTContext());

    DClient.EndSourceFile();
    m_CI->getDiagnostics().Reset();

    if (!m_SyntaxOnly) {
      m_Interpreter->runStaticInitializersOnce();
    }

    return Result;
  }

  IncrementalParser::EParseResult
  IncrementalParser::Parse(llvm::StringRef input) {

    // Add src to the memory buffer, parse it, and add it to
    // the AST. Returns the CompilerInstance (and thus the AST).
    // Diagnostics are reset for each call of parse: they are only covering
    // src.

    Preprocessor& PP = m_CI->getPreprocessor();
    DiagnosticConsumer& DClient = m_CI->getDiagnosticClient();

    PP.enableIncrementalProcessing();

    DClient.BeginSourceFile(m_CI->getLangOpts(), &PP);
    // Reset the transaction information
    getLastTransaction().setBeforeFirstDecl(getCI()->getSema().CurContext);

    if (input.size()) {
      std::ostringstream source_name;
      source_name << "input_line_" << (m_MemoryBuffer.size() + 1);
      m_MemoryBuffer.push_back(llvm::MemoryBuffer::getMemBufferCopy(input, source_name.str()));
      SourceManager& SM = getCI()->getSourceManager();

      // Create SourceLocation, which will allow clang to order the overload
      // candidates for example
      SourceLocation NewLoc = SM.getLocForStartOfFile(m_VirtualFileID);
      NewLoc = NewLoc.getLocWithOffset(m_MemoryBuffer.size() + 1);

      // Create FileID for the current buffer
      FileID FID = SM.createFileIDForMemBuffer(m_MemoryBuffer.back(),
                                               /*LoadedID*/0,
                                               /*LoadedOffset*/0, NewLoc);

      PP.EnterSourceFile(FID, 0, NewLoc);

      //Token &tok = const_cast<Token&>(m_Parser->getCurToken());
      //tok.setKind(tok::semi);
    }

    Parser::DeclGroupPtrTy ADecl;

    while (!m_Parser->ParseTopLevelDecl(ADecl)) {
      // Not end of file.
      // If we got a null return and something *was* parsed, ignore it.  This
      // is due to a top-level semicolon, an action override, or a parse error
      // skipping something.
      if (ADecl) {
        DeclGroupRef DGR = ADecl.getAsVal<DeclGroupRef>();
        for (DeclGroupRef::iterator i=DGR.begin(); i< DGR.end(); ++i) {
         if (!m_FirstTopLevelDecl)
           m_FirstTopLevelDecl = *((*i)->getDeclContext()->decls_begin());

          m_LastTopLevelDecl = *i;
        }
        m_Consumer->HandleTopLevelDecl(DGR);
      } // ADecl
    };

    // Process any TopLevelDecls generated by #pragma weak.
    for (llvm::SmallVector<Decl*,2>::iterator
           I = getCI()->getSema().WeakTopLevelDecls().begin(),
           E = getCI()->getSema().WeakTopLevelDecls().end(); I != E; ++I) {
      m_Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
    }

    getCI()->getSema().PerformPendingInstantiations();

    DClient.EndSourceFile();

    PP.enableIncrementalProcessing(false);

    DiagnosticsEngine& Diag = getCI()->getSema().getDiagnostics();
    if (Diag.hasErrorOccurred())
      return IncrementalParser::kFailed;
    else if (Diag.getNumWarnings())
      return IncrementalParser::kSuccessWithWarnings;

    return IncrementalParser::kSuccess;
  }

  void IncrementalParser::enableDynamicLookup(bool value) {
    m_DynamicLookupEnabled = value;
    Sema& S = m_CI->getSema();
    if (isDynamicLookupEnabled()) {
      assert(!S.ExternalSource && "Already set Sema ExternalSource");
      S.ExternalSource = new DynamicIDHandler(&S);
    }
    else {
      delete S.ExternalSource;
      S.ExternalSource = 0;
    }
  }

  void IncrementalParser::addConsumer(ChainedConsumer::EConsumerIndex I, ASTConsumer* consumer) {
    if (m_Consumer->Exists(I))
      return;

    m_Consumer->Add(I, consumer);
    if (I == ChainedConsumer::kCodeGenerator)
      m_Consumer->EnableConsumer(I);
  }

  CodeGenerator* IncrementalParser::GetCodeGenerator() const {
    return
      (CodeGenerator*)m_Consumer->getConsumer(ChainedConsumer::kCodeGenerator);
  }

} // namespace cling
<commit_msg>Initialize sema, which in turn initalizes the consumers.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "IncrementalParser.h"

#include "ASTDumper.h"
#include "ChainedConsumer.h"
#include "DeclExtractor.h"
#include "DynamicLookup.h"
#include "ValuePrinterSynthesizer.h"
#include "cling/Interpreter/CIFactory.h"
#include "cling/Interpreter/Interpreter.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/FileManager.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Parse/Parser.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Serialization/ASTWriter.h"

#include "llvm/LLVMContext.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_os_ostream.h"

#include <ctime>
#include <iostream>
#include <stdio.h>
#include <sstream>

using namespace clang;

namespace cling {
  IncrementalParser::IncrementalParser(Interpreter* interp,
                                       int argc, const char* const *argv,
                                       const char* llvmdir):
    m_Interpreter(interp),
    m_DynamicLookupEnabled(false),
    m_Consumer(0),
    m_FirstTopLevelDecl(0),
    m_LastTopLevelDecl(0),
    m_SyntaxOnly(false)
  {
    CompilerInstance* CI
      = CIFactory::createCI(llvm::MemoryBuffer::getMemBuffer("", "CLING"),
                            argc, argv, llvmdir);
    assert(CI && "CompilerInstance is (null)!");
    m_CI.reset(CI);
    m_SyntaxOnly = (CI->getFrontendOpts().ProgramAction == clang::frontend::ParseSyntaxOnly);

    CreateSLocOffsetGenerator();

    m_Consumer = dyn_cast<ChainedConsumer>(&CI->getASTConsumer());
    assert(m_Consumer && "Expected ChainedConsumer!");
    // Add consumers to the ChainedConsumer, which owns them
    EvaluateTSynthesizer* ES = new EvaluateTSynthesizer(interp);
    ES->Attach(m_Consumer);
    addConsumer(ChainedConsumer::kEvaluateTSynthesizer, ES);

    DeclExtractor* DE = new DeclExtractor();
    DE->Attach(m_Consumer);
    addConsumer(ChainedConsumer::kDeclExtractor, DE);

    ValuePrinterSynthesizer* VPS = new ValuePrinterSynthesizer(interp);
    VPS->Attach(m_Consumer);
    addConsumer(ChainedConsumer::kValuePrinterSynthesizer, VPS);
    addConsumer(ChainedConsumer::kASTDumper, new ASTDumper());
    if (!m_SyntaxOnly) {
      CodeGenerator* CG = CreateLLVMCodeGen(CI->getDiagnostics(),
                                            "cling input",
                                            CI->getCodeGenOpts(),
                                  /*Owned by codegen*/ * new llvm::LLVMContext()
                                            );
      assert(CG && "No CodeGen?!");
      addConsumer(ChainedConsumer::kCodeGenerator, CG);
    }
    m_Parser.reset(new Parser(CI->getPreprocessor(), CI->getSema()));
    CI->getPreprocessor().EnterMainSourceFile();
    // Initialize the parser after we have entered the main source file.
    m_Parser->Initialize();
    // Perform initialization that occurs after the parser has been initialized
    // but before it parses anything. Initializes the consumers too.
    CI->getSema().Initialize();
  }

  // Each input line is contained in separate memory buffer. The SourceManager
  // assigns sort-of invalid FileID for each buffer, i.e there is no FileEntry
  // for the MemoryBuffer's FileID. That in turn is problem because invalid
  // SourceLocations are given to the diagnostics. Thus the diagnostics cannot
  // order the overloads, for example
  //
  // Our work-around is creating a virtual file, which doesn't exist on the disk
  // with enormous size (no allocation is done). That file has valid FileEntry
  // and so on... We use it for generating valid SourceLocations with valid
  // offsets so that it doesn't cause any troubles to the diagnostics.
  //
  // +---------------------+
  // | Main memory buffer  |
  // +---------------------+
  // |  Virtual file SLoc  |
  // |    address space    |<-----------------+
  // |         ...         |<------------+    |
  // |         ...         |             |    |
  // |         ...         |<----+       |    |
  // |         ...         |     |       |    |
  // +~~~~~~~~~~~~~~~~~~~~~+     |       |    |
  // |     input_line_1    | ....+.......+..--+
  // +---------------------+     |       |
  // |     input_line_2    | ....+.....--+
  // +---------------------+     |
  // |          ...        |     |
  // +---------------------+     |
  // |     input_line_N    | ..--+
  // +---------------------+
  //
  void IncrementalParser::CreateSLocOffsetGenerator() {
    SourceManager& SM = getCI()->getSourceManager();
    FileManager& FM = SM.getFileManager();
    const FileEntry* FE
      = FM.getVirtualFile("Interactrive/InputLineIncluder", 1U << 15U, time(0));
    m_VirtualFileID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);

    assert(!m_VirtualFileID.isInvalid() && "No VirtualFileID created?");
  }

  IncrementalParser::~IncrementalParser() {
     if (GetCodeGenerator()) {
       GetCodeGenerator()->ReleaseModule();
     }
  }

  void IncrementalParser::Initialize() {
    CompileAsIs(""); // Consume initialization.
  }

  IncrementalParser::EParseResult
  IncrementalParser::CompileLineFromPrompt(llvm::StringRef input) {
    assert(input.str()[0] != '#'
           && "Preprocessed line! Call CompilePreprocessed instead");

    bool p, q;
    m_Consumer->RestorePreviousState(ChainedConsumer::kEvaluateTSynthesizer,
                                     isDynamicLookupEnabled());

    p = m_Consumer->EnableConsumer(ChainedConsumer::kDeclExtractor);
    q = m_Consumer->EnableConsumer(ChainedConsumer::kValuePrinterSynthesizer);
    EParseResult Result = Compile(input);
    m_Consumer->RestorePreviousState(ChainedConsumer::kDeclExtractor, p);
    m_Consumer->RestorePreviousState(ChainedConsumer::kValuePrinterSynthesizer, q);

    return Result;

  }

  IncrementalParser::EParseResult
  IncrementalParser::CompileAsIs(llvm::StringRef input) {
    bool p, q;
    m_Consumer->RestorePreviousState(ChainedConsumer::kEvaluateTSynthesizer,
                                     isDynamicLookupEnabled());

    p = m_Consumer->DisableConsumer(ChainedConsumer::kDeclExtractor);
    q = m_Consumer->DisableConsumer(ChainedConsumer::kValuePrinterSynthesizer);
    EParseResult Result = Compile(input);
    m_Consumer->RestorePreviousState(ChainedConsumer::kDeclExtractor, p);
    m_Consumer->RestorePreviousState(ChainedConsumer::kValuePrinterSynthesizer, q);

    return Result;
  }

  void IncrementalParser::Parse(llvm::StringRef input,
                                llvm::SmallVector<DeclGroupRef, 4>& DGRs){
    if (!m_SyntaxOnly)
      m_Consumer->DisableConsumer(ChainedConsumer::kCodeGenerator);

    Parse(input);
    for (llvm::SmallVector<ChainedConsumer::DGRInfo, 64>::iterator
           I = m_Consumer->DeclsQueue.begin(), E = m_Consumer->DeclsQueue.end();
         I != E; ++I) {
      DGRs.push_back((*I).D);
    }

    if (!m_SyntaxOnly)
      m_Consumer->EnableConsumer(ChainedConsumer::kCodeGenerator);
  }

  IncrementalParser::EParseResult
  IncrementalParser::Compile(llvm::StringRef input) {
    // Just in case when Parse is called, we want to complete the transaction
    // coming from parse and then start new one.
    m_Consumer->HandleTranslationUnit(getCI()->getASTContext());

    // Reset the module builder to clean up global initializers, c'tors, d'tors:
    if (GetCodeGenerator()) {
      GetCodeGenerator()->Initialize(getCI()->getASTContext());
    }

    EParseResult Result = Parse(input);

    // Check for errors coming from our custom consumers.
    DiagnosticConsumer& DClient = m_CI->getDiagnosticClient();
    DClient.BeginSourceFile(getCI()->getLangOpts(), &getCI()->getPreprocessor());
    m_Consumer->HandleTranslationUnit(getCI()->getASTContext());

    DClient.EndSourceFile();
    m_CI->getDiagnostics().Reset();

    if (!m_SyntaxOnly) {
      m_Interpreter->runStaticInitializersOnce();
    }

    return Result;
  }

  IncrementalParser::EParseResult
  IncrementalParser::Parse(llvm::StringRef input) {

    // Add src to the memory buffer, parse it, and add it to
    // the AST. Returns the CompilerInstance (and thus the AST).
    // Diagnostics are reset for each call of parse: they are only covering
    // src.

    Preprocessor& PP = m_CI->getPreprocessor();
    DiagnosticConsumer& DClient = m_CI->getDiagnosticClient();

    PP.enableIncrementalProcessing();

    DClient.BeginSourceFile(m_CI->getLangOpts(), &PP);
    // Reset the transaction information
    getLastTransaction().setBeforeFirstDecl(getCI()->getSema().CurContext);

    if (input.size()) {
      std::ostringstream source_name;
      source_name << "input_line_" << (m_MemoryBuffer.size() + 1);
      m_MemoryBuffer.push_back(llvm::MemoryBuffer::getMemBufferCopy(input, source_name.str()));
      SourceManager& SM = getCI()->getSourceManager();

      // Create SourceLocation, which will allow clang to order the overload
      // candidates for example
      SourceLocation NewLoc = SM.getLocForStartOfFile(m_VirtualFileID);
      NewLoc = NewLoc.getLocWithOffset(m_MemoryBuffer.size() + 1);

      // Create FileID for the current buffer
      FileID FID = SM.createFileIDForMemBuffer(m_MemoryBuffer.back(),
                                               /*LoadedID*/0,
                                               /*LoadedOffset*/0, NewLoc);

      PP.EnterSourceFile(FID, 0, NewLoc);

      //Token &tok = const_cast<Token&>(m_Parser->getCurToken());
      //tok.setKind(tok::semi);
    }

    Parser::DeclGroupPtrTy ADecl;

    while (!m_Parser->ParseTopLevelDecl(ADecl)) {
      // Not end of file.
      // If we got a null return and something *was* parsed, ignore it.  This
      // is due to a top-level semicolon, an action override, or a parse error
      // skipping something.
      if (ADecl) {
        DeclGroupRef DGR = ADecl.getAsVal<DeclGroupRef>();
        for (DeclGroupRef::iterator i=DGR.begin(); i< DGR.end(); ++i) {
         if (!m_FirstTopLevelDecl)
           m_FirstTopLevelDecl = *((*i)->getDeclContext()->decls_begin());

          m_LastTopLevelDecl = *i;
        }
        m_Consumer->HandleTopLevelDecl(DGR);
      } // ADecl
    };

    // Process any TopLevelDecls generated by #pragma weak.
    for (llvm::SmallVector<Decl*,2>::iterator
           I = getCI()->getSema().WeakTopLevelDecls().begin(),
           E = getCI()->getSema().WeakTopLevelDecls().end(); I != E; ++I) {
      m_Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
    }

    getCI()->getSema().PerformPendingInstantiations();

    DClient.EndSourceFile();

    PP.enableIncrementalProcessing(false);

    DiagnosticsEngine& Diag = getCI()->getSema().getDiagnostics();
    if (Diag.hasErrorOccurred())
      return IncrementalParser::kFailed;
    else if (Diag.getNumWarnings())
      return IncrementalParser::kSuccessWithWarnings;

    return IncrementalParser::kSuccess;
  }

  void IncrementalParser::enableDynamicLookup(bool value) {
    m_DynamicLookupEnabled = value;
    Sema& S = m_CI->getSema();
    if (isDynamicLookupEnabled()) {
      assert(!S.ExternalSource && "Already set Sema ExternalSource");
      S.ExternalSource = new DynamicIDHandler(&S);
    }
    else {
      delete S.ExternalSource;
      S.ExternalSource = 0;
    }
  }

  void IncrementalParser::addConsumer(ChainedConsumer::EConsumerIndex I, ASTConsumer* consumer) {
    if (m_Consumer->Exists(I))
      return;

    m_Consumer->Add(I, consumer);
    if (I == ChainedConsumer::kCodeGenerator)
      m_Consumer->EnableConsumer(I);
  }

  CodeGenerator* IncrementalParser::GetCodeGenerator() const {
    return
      (CodeGenerator*)m_Consumer->getConsumer(ChainedConsumer::kCodeGenerator);
  }

} // namespace cling
<|endoftext|>


<commit_before>#include <glog/logging.h>
#include <gflags/gflags.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

int main(int argc, char **argv)
{
    ::gflags::ParseCommandLineFlags(&argc, &argv, false);
    ::testing::GTEST_FLAG(throw_on_failure) = true;
    ::testing::InitGoogleMock(&argc, argv);

    return RUN_ALL_TESTS();
}<commit_msg>use ::google namespace<commit_after>#include <glog/logging.h>
#include <gflags/gflags.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

int main(int argc, char **argv)
{
    ::google::ParseCommandLineFlags(&argc, &argv, false);
    ::testing::GTEST_FLAG(throw_on_failure) = true;
    ::testing::InitGoogleMock(&argc, argv);

    return RUN_ALL_TESTS();
}<|endoftext|>


<commit_before>#include <iostream>
#include "../src/Trie.h"

using namespace std;

int main() {
  Trie* trie = new Trie();
  trie->add("asparagus");
  trie->add("aspen");
  cout << "This should be true: " << trie->search("asparagus") << endl;
  cout << "This should be false: " << trie->search("aaragus") << endl;
}
<commit_msg>Add more tests<commit_after>#include <iostream>
#include "../src/Trie.h"

using namespace std;

int main() {
  Trie* trie = new Trie();
  trie->add("asparagus");
  trie->add("aspen");
  cout << "This should be true: " << trie->search("asparagus") << endl;
  cout << "This should be false: " << trie->search("aaragus") << endl;
  cout << "This should be false: " << trie->search("asparaguse") << endl;
}
<|endoftext|>


<commit_before>/** \brief  A MARC-21 filter utility that adds ACO tags with entry $a set to 1 for article collections.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <string>
#include <unordered_set>
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcUtil.h"
#include "MarcWriter.h"

void Usage() {
    std::cerr << "Usage: " << ::progname << " marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

void CollectArticleCollectionPPNs(MarcReader * const reader,
                                  std::unordered_set<std::string> * const article_collection_ppns)
{
    article_collection_ppns->clear();
    while (const MarcRecord record = reader->read()) {
        if (MarcUtil::IsArticle(record)) {
            const std::string parent_ppn(MarcUtil::GetParentPPN(record));
            if (not parent_ppn.empty())
                article_collection_ppns->insert(parent_ppn);
        }
    }
}

void MarkArticleCollections(MarcReader * const reader, MarcWriter * const writer,
                            const std::unordered_set<std::string> &article_collection_ppns)
{
    unsigned count(0), modified_count(0);
    while (MarcRecord record = reader->read()) {
        ++count;

        bool is_article_collection(false);
        if (article_collection_ppns.find(record.getControlNumber()) != article_collection_ppns.end())
            is_article_collection = true;
        if (not is_article_collection and not MarcUtil::IsArticle(record)) {
            is_article_collection = MarcUtil::HasSubfieldWithValue(record, "935", 'c', "fe");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "655", 'a', "Festschrift");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "655", 'a', "Konferenzschrift");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "689", 'a', "Konferenzschrift");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "689", 'a', "Kongress");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "935", 'c', "gkko");
        }

        if (is_article_collection) {
            record.insertSubfield("ACO", 'a', "1");
            ++modified_count;
        }

        writer->write(record);
    }

    std::cerr << "Read " << count << " records.\n";
    std::cerr << "Identified " << modified_count << " record(s) as an article collection.\n";
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 3)
        Usage();

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(argv[1]));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(argv[2]));
    try {
        std::unordered_set<std::string> article_collection_ppns;
        CollectArticleCollectionPPNs(marc_reader.get(), &article_collection_ppns);
        marc_reader->rewind();
        MarkArticleCollections(marc_reader.get(), marc_writer.get(), article_collection_ppns);
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Update flag_article_collections.cc<commit_after>/** \brief  A MARC-21 filter utility that adds ACO tags with entry $a set to 1 for article collections.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2017 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <string>
#include <unordered_set>
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcUtil.h"
#include "MarcWriter.h"

void Usage() {
    std::cerr << "Usage: " << ::progname << " marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

void CollectArticleCollectionPPNs(MarcReader * const reader,
                                  std::unordered_set<std::string> * const article_collection_ppns)
{
    article_collection_ppns->clear();
    while (const MarcRecord record = reader->read()) {
        if (MarcUtil::IsArticle(record)) {
            const std::string parent_ppn(MarcUtil::GetParentPPN(record));
            if (not parent_ppn.empty())
                article_collection_ppns->insert(parent_ppn);
        }
    }
}

void MarkArticleCollections(MarcReader * const reader, MarcWriter * const writer,
                            const std::unordered_set<std::string> &article_collection_ppns)
{
    unsigned count(0), modified_count(0);
    while (MarcRecord record = reader->read()) {
        ++count;

        bool is_article_collection(false);
        if (article_collection_ppns.find(record.getControlNumber()) != article_collection_ppns.end())
            is_article_collection = true;
        if (not is_article_collection and not MarcUtil::IsArticle(record)) {
            is_article_collection = MarcUtil::HasSubfieldWithValue(record, "935", 'c', "fe");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "655", 'a', "Aufsatzsammlung");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "689", 'a', "Aufsatzsammlung");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "655", 'a', "Festschrift");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "655", 'a', "Konferenzschrift");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "689", 'a', "Konferenzschrift");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "689", 'a', "Kongress");
            if (not is_article_collection)
                is_article_collection = MarcUtil::HasSubfieldWithValue(record, "935", 'c', "gkko");
        }

        if (is_article_collection) {
            record.insertSubfield("ACO", 'a', "1");
            ++modified_count;
        }

        writer->write(record);
    }

    std::cerr << "Read " << count << " records.\n";
    std::cerr << "Identified " << modified_count << " record(s) as an article collection.\n";
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 3)
        Usage();

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(argv[1]));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(argv[2]));
    try {
        std::unordered_set<std::string> article_collection_ppns;
        CollectArticleCollectionPPNs(marc_reader.get(), &article_collection_ppns);
        marc_reader->rewind();
        MarkArticleCollections(marc_reader.get(), marc_writer.get(), article_collection_ppns);
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>