<commit_before>#ifndef TEST_HELPER_H_
#define TEST_HELPER_H_

#include <internal/iterbase.hpp>

#include <stdexcept>
#include <type_traits>
#include <utility>
#include <vector>

namespace itertest {

  // non-copyable. non-movable. non-default-constructible
  class SolidInt {
   private:
    const int i;

   public:
    constexpr SolidInt(int n) : i{n} {}

    constexpr int getint() const {
      return this->i;
    }

    SolidInt() = delete;
    SolidInt(const SolidInt&) = delete;
    SolidInt& operator=(const SolidInt&) = delete;
    SolidInt& operator=(SolidInt&&) = delete;
    SolidInt(SolidInt&&) = delete;
  };

  namespace {
    struct DoubleDereferenceError : std::exception {
      const char* what() const noexcept override {
        return "Iterator dereferenced twice without increment";
      }
    };

    // this class's iterator will throw if it's dereference twice without
    // an increment in between
    class InputIterable {
     public:
      class Iterator {
       private:
        int i;
        bool was_incremented = true;

       public:
        Iterator(int n) : i{n} {}

        Iterator& operator++() {
          ++this->i;
          this->was_incremented = true;
          return *this;
        }

        int operator*() {
          if (!this->was_incremented) {
            throw DoubleDereferenceError{};
          }
          this->was_incremented = false;
          return this->i;
        }

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

      Iterator begin() {
        return {0};
      }

      Iterator end() {
        return {5};
      }
    };
  }

  // BasicIterable provides a minimal forward iterator
  // operator++(), operator!=(const BasicIterable&), operator*()
  // move constructible only
  // not copy constructible, move assignable, or copy assignable
  template <typename T>
  class BasicIterable {
   private:
    T* data;
    std::size_t size;
    bool was_moved_from_ = false;
    mutable bool was_copied_from_ = false;

   public:
    BasicIterable(std::initializer_list<T> il)
        : data{new T[il.size()]}, size{il.size()} {
      // would like to use enumerate, can't because it's for unit
      // testing enumerate
      std::size_t i = 0;
      for (auto&& e : il) {
        data[i] = e;
        ++i;
      }
    }

    BasicIterable& operator=(BasicIterable&&) = delete;
    BasicIterable& operator=(const BasicIterable&) = delete;

#ifndef DEFINE_BASIC_ITERABLE_COPY_CTOR
    BasicIterable(const BasicIterable&) = delete;
#else
    BasicIterable(const BasicIterable& other)
        : data{new T[other.size]}, size{other.size} {
      other.was_copied_from_ = true;
      for (auto it = begin(*this), o_it = begin(other); o_it != end(other);
           ++it, ++o_it) {
        *it = *o_it;
      }
    }
#endif

    BasicIterable(BasicIterable&& other) : data{other.data}, size{other.size} {
      other.data = nullptr;
      other.was_moved_from_ = true;
    }

    bool was_moved_from() const {
      return this->was_moved_from_;
    }

    bool was_copied_from() const {
      return this->was_copied_from_;
    }

    ~BasicIterable() {
      delete[] this->data;
    }

    template <typename U>
    class Iterator {
     private:
      U* p;

     public:
#ifdef DEFINE_DEFAULT_ITERATOR_CTOR
      Iterator() = default;
#endif
      Iterator(U* b) : p{b} {}
      bool operator!=(const Iterator& other) const {
        return this->p != other.p;
      }

      Iterator& operator++() {
        ++this->p;
        return *this;
      }

      U& operator*() {
        return *this->p;
      }
    };

    friend BasicIterable::Iterator<T> begin(BasicIterable& b) {
      return {b.data};
    }

    friend BasicIterable::Iterator<T> end(BasicIterable& b) {
      return {b.data + b.size};
    }

#ifdef DEFINE_BASIC_ITERABLE_CONST_BEGIN_AND_END
    friend BasicIterable::Iterator<const T> begin(const BasicIterable& b) {
      return {b.data};
    }

    friend BasicIterable::Iterator<const T> end(const BasicIterable& b) {
      return {b.data + b.size};
    }
#endif

#ifdef DECLARE_REVERSE_ITERATOR
    Iterator<T> rbegin();
    Iterator<T> rend();
#endif  // ifdef DECLARE_REVERSE_ITERATOR
  };

  using iter::impl::void_t;

  template <typename, typename = void>
  struct IsIterator : std::false_type {};

  template <typename T>
  struct IsIterator<T,
      void_t<decltype(T(std::declval<const T&>())),                 // copyctor
          decltype(std::declval<T&>() = std::declval<const T&>()),  // copy =
          decltype(*std::declval<T&>()),                            // operator*
          decltype(std::declval<T&>().operator->()),  // operator->
          decltype(++std::declval<T&>()),             // prefix ++
          decltype(std::declval<T&>()++),             // postfix ++
          decltype(
              std::declval<const T&>() != std::declval<const T&>()),      //  !=
          decltype(std::declval<const T&>() == std::declval<const T&>())  //  ==
          >> : std::true_type {};

  template <typename T>
  struct IsForwardIterator
      : std::integral_constant<bool,
            IsIterator<T>::value && std::is_default_constructible<T>::value> {};

  template <typename T>
  struct IsMoveConstructibleOnly
      : std::integral_constant<bool,
            !std::is_copy_constructible<T>::value
                && !std::is_copy_assignable<T>::value
                && !std::is_move_assignable<T>::value
                && std::is_move_constructible<T>::value> {};
}
template <typename T, typename Inc>
class DiffEndRange {
 private:
  T start_;
  T stop_;
  std::vector<T> all_results_;

 public:
  constexpr DiffEndRange(T start, T stop) : start_{start}, stop_{stop} {
    while (start < stop_) {
      all_results_.push_back(start);
      Inc{}(start);
    }
  }

  class Iterator;
  class EndIterator;

  class Iterator {
    using SubIter = typename std::vector<T>::iterator;

   private:
    SubIter it_;
    SubIter end_;

   public:
#ifdef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE
    Iterator() = default;
#endif
    Iterator(SubIter it, SubIter end_it) : it_{it}, end_{end_it} {}

    T& operator*() const {
      return *it_;
    }
    T* operator->() const {
      return &*it_;
    }

    Iterator& operator++() {
      ++it_;
      return *this;
    }

    bool operator!=(const Iterator& other) const {
      return it_ != other.it_;
    }

    bool operator!=(const EndIterator&) const {
      return it_ != end_;
    }

    friend bool operator!=(const EndIterator& lhs, const Iterator& rhs) {
      return rhs != lhs;
    }
  };

  class ReverseIterator {
    using SubIter = typename std::vector<T>::reverse_iterator;

   private:
    SubIter it_;
    SubIter end_;

   public:
#ifdef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE
    ReverseIterator() = default;
#endif
    ReverseIterator(SubIter it, SubIter end_it) : it_{it}, end_{end_it} {}

    T& operator*() const {
      return *it_;
    }
    T* operator->() const {
      return &*it_;
    }

    Iterator& operator++() {
      ++it_;
      return *this;
    }

    bool operator!=(const Iterator& other) const {
      return it_ != other.it_;
    }

    bool operator!=(const EndIterator&) const {
      return it_ != end_;
    }

    friend bool operator!=(const EndIterator& lhs, const Iterator& rhs) {
      return rhs != lhs;
    }
  };

  class EndIterator {};
  class ReverseEndIterator {};

  Iterator begin() {
    return {std::begin(all_results_), std::end(all_results_)};
  }

  EndIterator end() {
    return {};
  }

  ReverseIterator rbegin() {
    return {std::rbegin(all_results_), std::rend(all_results_)};
  }

  ReverseEndIterator rend() {
    return {};
  }
};

struct CharInc {
  void operator()(char& c) {
    ++c;
  }
};

// A range from 'a' to stop, begin() and end() are different
class CharRange : public DiffEndRange<char, CharInc> {
 public:
  constexpr CharRange(char stop) : DiffEndRange<char, CharInc>('a', stop) {}
};

struct IncIntCharPair {
  void operator()(std::pair<int, char>& p) {
    ++p.first;
    ++p.second;
  }
};

class IntCharPairRange
    : public DiffEndRange<std::pair<int, char>, IncIntCharPair> {
 public:
  IntCharPairRange(std::pair<int, char> stop)
      : DiffEndRange<std::pair<int, char>, IncIntCharPair>({0, 'a'}, stop) {}
};

#endif
<commit_msg>Some iterator type disagreement thing<commit_after>#ifndef TEST_HELPER_H_
#define TEST_HELPER_H_

#include <internal/iterbase.hpp>

#include <stdexcept>
#include <type_traits>
#include <utility>
#include <vector>

namespace itertest {

  // non-copyable. non-movable. non-default-constructible
  class SolidInt {
   private:
    const int i;

   public:
    constexpr SolidInt(int n) : i{n} {}

    constexpr int getint() const {
      return this->i;
    }

    SolidInt() = delete;
    SolidInt(const SolidInt&) = delete;
    SolidInt& operator=(const SolidInt&) = delete;
    SolidInt& operator=(SolidInt&&) = delete;
    SolidInt(SolidInt&&) = delete;
  };

  namespace {
    struct DoubleDereferenceError : std::exception {
      const char* what() const noexcept override {
        return "Iterator dereferenced twice without increment";
      }
    };

    // this class's iterator will throw if it's dereference twice without
    // an increment in between
    class InputIterable {
     public:
      class Iterator {
       private:
        int i;
        bool was_incremented = true;

       public:
        Iterator(int n) : i{n} {}

        Iterator& operator++() {
          ++this->i;
          this->was_incremented = true;
          return *this;
        }

        int operator*() {
          if (!this->was_incremented) {
            throw DoubleDereferenceError{};
          }
          this->was_incremented = false;
          return this->i;
        }

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

      Iterator begin() {
        return {0};
      }

      Iterator end() {
        return {5};
      }
    };
  }

  // BasicIterable provides a minimal forward iterator
  // operator++(), operator!=(const BasicIterable&), operator*()
  // move constructible only
  // not copy constructible, move assignable, or copy assignable
  template <typename T>
  class BasicIterable {
   private:
    T* data;
    std::size_t size;
    bool was_moved_from_ = false;
    mutable bool was_copied_from_ = false;

   public:
    BasicIterable(std::initializer_list<T> il)
        : data{new T[il.size()]}, size{il.size()} {
      // would like to use enumerate, can't because it's for unit
      // testing enumerate
      std::size_t i = 0;
      for (auto&& e : il) {
        data[i] = e;
        ++i;
      }
    }

    BasicIterable& operator=(BasicIterable&&) = delete;
    BasicIterable& operator=(const BasicIterable&) = delete;

#ifndef DEFINE_BASIC_ITERABLE_COPY_CTOR
    BasicIterable(const BasicIterable&) = delete;
#else
    BasicIterable(const BasicIterable& other)
        : data{new T[other.size]}, size{other.size} {
      other.was_copied_from_ = true;
      auto o_it = begin(other);
      for (auto it = begin(*this); o_it != end(other);
           ++it, ++o_it) {
        *it = *o_it;
      }
    }
#endif

    BasicIterable(BasicIterable&& other) : data{other.data}, size{other.size} {
      other.data = nullptr;
      other.was_moved_from_ = true;
    }

    bool was_moved_from() const {
      return this->was_moved_from_;
    }

    bool was_copied_from() const {
      return this->was_copied_from_;
    }

    ~BasicIterable() {
      delete[] this->data;
    }

    template <typename U>
    class Iterator {
     private:
      U* p;

     public:
#ifdef DEFINE_DEFAULT_ITERATOR_CTOR
      Iterator() = default;
#endif
      Iterator(U* b) : p{b} {}
      bool operator!=(const Iterator& other) const {
        return this->p != other.p;
      }

      Iterator& operator++() {
        ++this->p;
        return *this;
      }

      U& operator*() {
        return *this->p;
      }
    };

    friend BasicIterable::Iterator<T> begin(BasicIterable& b) {
      return {b.data};
    }

    friend BasicIterable::Iterator<T> end(BasicIterable& b) {
      return {b.data + b.size};
    }

#ifdef DEFINE_BASIC_ITERABLE_CONST_BEGIN_AND_END
    friend BasicIterable::Iterator<const T> begin(const BasicIterable& b) {
      return {b.data};
    }

    friend BasicIterable::Iterator<const T> end(const BasicIterable& b) {
      return {b.data + b.size};
    }
#endif

#ifdef DECLARE_REVERSE_ITERATOR
    Iterator<T> rbegin();
    Iterator<T> rend();
#endif  // ifdef DECLARE_REVERSE_ITERATOR
  };

  using iter::impl::void_t;

  template <typename, typename = void>
  struct IsIterator : std::false_type {};

  template <typename T>
  struct IsIterator<T,
      void_t<decltype(T(std::declval<const T&>())),                 // copyctor
          decltype(std::declval<T&>() = std::declval<const T&>()),  // copy =
          decltype(*std::declval<T&>()),                            // operator*
          decltype(std::declval<T&>().operator->()),  // operator->
          decltype(++std::declval<T&>()),             // prefix ++
          decltype(std::declval<T&>()++),             // postfix ++
          decltype(
              std::declval<const T&>() != std::declval<const T&>()),      //  !=
          decltype(std::declval<const T&>() == std::declval<const T&>())  //  ==
          >> : std::true_type {};

  template <typename T>
  struct IsForwardIterator
      : std::integral_constant<bool,
            IsIterator<T>::value && std::is_default_constructible<T>::value> {};

  template <typename T>
  struct IsMoveConstructibleOnly
      : std::integral_constant<bool,
            !std::is_copy_constructible<T>::value
                && !std::is_copy_assignable<T>::value
                && !std::is_move_assignable<T>::value
                && std::is_move_constructible<T>::value> {};
}
template <typename T, typename Inc>
class DiffEndRange {
 private:
  T start_;
  T stop_;
  std::vector<T> all_results_;

 public:
  constexpr DiffEndRange(T start, T stop) : start_{start}, stop_{stop} {
    while (start < stop_) {
      all_results_.push_back(start);
      Inc{}(start);
    }
  }

  class Iterator;
  class EndIterator;

  class Iterator {
    using SubIter = typename std::vector<T>::iterator;

   private:
    SubIter it_;
    SubIter end_;

   public:
#ifdef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE
    Iterator() = default;
#endif
    Iterator(SubIter it, SubIter end_it) : it_{it}, end_{end_it} {}

    T& operator*() const {
      return *it_;
    }
    T* operator->() const {
      return &*it_;
    }

    Iterator& operator++() {
      ++it_;
      return *this;
    }

    bool operator!=(const Iterator& other) const {
      return it_ != other.it_;
    }

    bool operator!=(const EndIterator&) const {
      return it_ != end_;
    }

    friend bool operator!=(const EndIterator& lhs, const Iterator& rhs) {
      return rhs != lhs;
    }
  };

  class ReverseIterator {
    using SubIter = typename std::vector<T>::reverse_iterator;

   private:
    SubIter it_;
    SubIter end_;

   public:
#ifdef CHAR_RANGE_DEFAULT_CONSTRUCTIBLE
    ReverseIterator() = default;
#endif
    ReverseIterator(SubIter it, SubIter end_it) : it_{it}, end_{end_it} {}

    T& operator*() const {
      return *it_;
    }
    T* operator->() const {
      return &*it_;
    }

    Iterator& operator++() {
      ++it_;
      return *this;
    }

    bool operator!=(const Iterator& other) const {
      return it_ != other.it_;
    }

    bool operator!=(const EndIterator&) const {
      return it_ != end_;
    }

    friend bool operator!=(const EndIterator& lhs, const Iterator& rhs) {
      return rhs != lhs;
    }
  };

  class EndIterator {};
  class ReverseEndIterator {};

  Iterator begin() {
    return {std::begin(all_results_), std::end(all_results_)};
  }

  EndIterator end() {
    return {};
  }

  ReverseIterator rbegin() {
    return {std::rbegin(all_results_), std::rend(all_results_)};
  }

  ReverseEndIterator rend() {
    return {};
  }
};

struct CharInc {
  void operator()(char& c) {
    ++c;
  }
};

// A range from 'a' to stop, begin() and end() are different
class CharRange : public DiffEndRange<char, CharInc> {
 public:
  constexpr CharRange(char stop) : DiffEndRange<char, CharInc>('a', stop) {}
};

struct IncIntCharPair {
  void operator()(std::pair<int, char>& p) {
    ++p.first;
    ++p.second;
  }
};

class IntCharPairRange
    : public DiffEndRange<std::pair<int, char>, IncIntCharPair> {
 public:
  IntCharPairRange(std::pair<int, char> stop)
      : DiffEndRange<std::pair<int, char>, IncIntCharPair>({0, 'a'}, stop) {}
};

#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <complex>
#include <iostream>

#include "cuda.h"
#include "cuda_runtime.h"
#include "cuda_runtime_api.h"

#include "egblas.hpp"
#include "test.hpp"

#include "catch.hpp"

TEST_CASE("cce/loss/s/0", "[float][cce]") {
    const size_t N = 137;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.1 * (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    float loss = egblas_cce_sloss(N, 1.1, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(22055.71875f));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("cce/loss/d/0", "[double][cce]") {
    const size_t N = 145;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.01 * (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double loss = egblas_cce_sloss(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(-1587.1035));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("cce/error/s/0", "[float][cce]") {
    const size_t N = 137;
    const size_t M = 8;

    float* x_cpu = new float[N * M];
    float* y_cpu = new float[N * M];

    for (size_t i = 0; i < N * M; ++i) {
        x_cpu[i] = (i + 1);
        y_cpu[i] = ((i + 1) % 9);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * M * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * M * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * M * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * M * sizeof(float), cudaMemcpyHostToDevice));

    float loss = egblas_cce_serror(N, M, 1.0 / 137.0f, x_gpu, y_gpu);

    REQUIRE(loss == Approx(0.76642));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("cce/error/d/0", "[double][cce]") {
    const size_t N = 128;
    const size_t M = 9;

    double* x_cpu = new double[N * M];
    double* y_cpu = new double[N * M];

    for (size_t i = 0; i < N * M; ++i) {
        x_cpu[i] = (i + 1);
        y_cpu[i] = ((i + 1) % 11);
    }

    double* x_gpu;
    double* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * M * sizeof(double)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * M * sizeof(double)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * M * sizeof(double), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * M * sizeof(double), cudaMemcpyHostToDevice));

    double loss = egblas_cce_derror(N, M, 1.0 / 128.0f, x_gpu, y_gpu);

    REQUIRE(loss == Approx(0.71875));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}
<commit_msg>Complete the CCE tests<commit_after>//=======================================================================
// Copyright (c) 2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <complex>
#include <iostream>

#include "cuda.h"
#include "cuda_runtime.h"
#include "cuda_runtime_api.h"

#include "egblas.hpp"
#include "test.hpp"

#include "catch.hpp"

TEST_CASE("cce/loss/s/0", "[float][cce]") {
    const size_t N = 137;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.1 * (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    float loss = egblas_cce_sloss(N, 1.1, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(22055.71875f));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("cce/loss/d/0", "[double][cce]") {
    const size_t N = 145;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.01 * (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double loss = egblas_cce_sloss(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(-1587.1035));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("cce/loss/d/1", "[double][cce]") {
    const size_t N = 13 * 1024;

    float* x_cpu = new float[N];
    float* y_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = 0.01 * (i + 1);
        y_cpu[i] = (i + 1);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    double loss = egblas_cce_sloss(N, 1.2, x_gpu, 1, y_gpu, 1);

    REQUIRE(loss == Approx(466941536.0));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("cce/error/s/0", "[float][cce]") {
    const size_t N = 137;
    const size_t M = 8;

    float* x_cpu = new float[N * M];
    float* y_cpu = new float[N * M];

    for (size_t i = 0; i < N * M; ++i) {
        x_cpu[i] = (i + 1);
        y_cpu[i] = ((i + 1) % 9);
    }

    float* x_gpu;
    float* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * M * sizeof(float)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * M * sizeof(float)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * M * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * M * sizeof(float), cudaMemcpyHostToDevice));

    float loss = egblas_cce_serror(N, M, 1.0 / 137.0f, x_gpu, y_gpu);

    REQUIRE(loss == Approx(0.76642));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("cce/error/d/0", "[double][cce]") {
    const size_t N = 128;
    const size_t M = 9;

    double* x_cpu = new double[N * M];
    double* y_cpu = new double[N * M];

    for (size_t i = 0; i < N * M; ++i) {
        x_cpu[i] = (i + 1);
        y_cpu[i] = ((i + 1) % 11);
    }

    double* x_gpu;
    double* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * M * sizeof(double)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * M * sizeof(double)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * M * sizeof(double), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * M * sizeof(double), cudaMemcpyHostToDevice));

    double loss = egblas_cce_derror(N, M, 1.0 / 128.0f, x_gpu, y_gpu);

    REQUIRE(loss == Approx(0.71875));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}

TEST_CASE("cce/error/d/1", "[double][cce]") {
    const size_t N = 3 * 1024;
    const size_t M = 9;

    double* x_cpu = new double[N * M];
    double* y_cpu = new double[N * M];

    for (size_t i = 0; i < N * M; ++i) {
        x_cpu[i] = (i + 1);
        y_cpu[i] = ((i + 1) % 11);
    }

    double* x_gpu;
    double* y_gpu;
    cuda_check(cudaMalloc((void**)&x_gpu, N * M * sizeof(double)));
    cuda_check(cudaMalloc((void**)&y_gpu, N * M * sizeof(double)));

    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * M * sizeof(double), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(y_gpu, y_cpu, N * M * sizeof(double), cudaMemcpyHostToDevice));

    double loss = egblas_cce_derror(N, M, 1.0 / 128.0f, x_gpu, y_gpu);

    REQUIRE(loss == Approx(17.453125));

    cuda_check(cudaFree(x_gpu));
    cuda_check(cudaFree(y_gpu));

    delete[] x_cpu;
    delete[] y_cpu;
}
<|endoftext|>


<commit_before>#ifndef __STAN__AGRAD__FVAR_HPP__
#define __STAN__AGRAD__FVAR_HPP__

#include <stan/meta/traits.hpp>

namespace stan {

  namespace agrad {

    template <typename T>
    struct fvar {

      T val_;  // value
      T d_;    // tangent (aka derivative)

      // TV and TD must be assignable to T
      template <typename TV, typename TD>
      fvar(const TV& val, const TD& deriv) : val_(val), d_(deriv) {  }

      // TV must be assignable to T
      template <typename TV>
      fvar(const TV& val) : val_(val), d_(0.0) {  }

      fvar() : val_(0.0), d_(0.0) { }

      template <typename T2>
      inline
      fvar<T>&
      operator+=(const fvar<T2>& x2) {
        val_ += x2.val_;
        d_ += x2.d_;
        return *this;
      }

      template <typename T2>
      inline
      fvar<T>&
      operator-=(const fvar<T2>& x2) {
        val_ -= x2.val_;
        d_ -= x2.d_;
        return *this;
      }

      template <typename T2>
      inline
      fvar<T>&
      operator*=(const fvar<T2>& x2) {
        d_ = d_ * x2.val_ + val_ * x2.d_;
        val_ *= x2.val_;
        return *this;
      }

      // SPEEDUP: specialize for T2 == var with d_ function

      template <typename T2>
      inline
      fvar<T>&
      operator/=(const fvar<T2>& x2) {
        d_ = (d_ * x2.val_ - val_ * x2.d_) / ( x2.v_ * x2.v_);
        val_ /= x2.val_;
        return *this;
      }

      inline
      fvar<T>&
      operator++() {
        ++val_;
        return *this;
      }
      inline
      fvar<T>
      operator++(int /*dummy*/) {
        fvar<T> result(val_,d_);
        ++val_;
        return result;
      }

      inline
      fvar<T>&
      operator--() {
        --val_;
        return *this;
      }
      inline
      fvar<T>
      operator--(int /*dummy*/) {
        fvar<T> result(val_,d_);
        --val_;
        return result;
      }

    };

    template <typename T>
    inline
    fvar<T>
    operator-(const fvar<T>& x) {
      return fvar<T>(-x.val_, -x.d_);
    }

    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator+(const fvar<T1>& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ + x2.val_,
                                                  x1.d_ + x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator+(const T1& x1,
              const fvar<T2>& x2) {
      return
        fvar<typename
             stan::return_type<T1,T2>::type>(x1 + x2.val_,
                                             x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator+(const fvar<T1>& x1,
              const T2& x2) {
      return
        fvar<typename
             stan::return_type<T1,T2>::type>(x1.val_ + x2,
                                             x1.d_);
    }

    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator-(const fvar<T1>& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ - x2.val_,
                                                  x1.d_ - x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator-(const T1& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1 - x2.val_,
                                                  -x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator-(const fvar<T1>& x1,
              const T2& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ - x2,
                                                  x1.d_);
    }

    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator*(const fvar<T1>& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ * x2.val_,
                                                  x1.d_ * x2.val_
                                                  + x1.val_ * x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator*(const T1& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1 * x2.val_,
                                                  x1 * x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator*(const fvar<T1>& x1,
              const T2& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ * x2,
                                                  x1.d_ * x2);
    }

    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator/(const fvar<T1>& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan
                  ::return_type<T1,T2>::type>(x1.val_ / x2.val_,
                                              ( x1.d_ * x2.val_
                                                - x1.val_ * x2.d_ )
                                              / (x2.val_ * x2.val_));
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator/(const fvar<T1>& x1,
              T2& x2) {
      return fvar<typename stan::return_type<T1,T2>::type>(x1.val_ / x2,
                                                           x1.d_ / x2);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator/(const T1& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan
                  ::return_type<T1,T2>::type>(x1 / x2.val_,
                                              - x1.val_ * x2.d_
                                              / (x2.val_ * x2.val_));
    }

    template <typename T>
    inline
    fvar<T>
    sin(const fvar<T>& x) {
      using std::sin;
      using std::cos;
      return fvar<T>(sin(x.val_),
                     x.d_ * cos(x.val_));
    }

  }
}

#endif
<commit_msg>added second version for non-fvar operator+= arg<commit_after>#ifndef __STAN__AGRAD__FVAR_HPP__
#define __STAN__AGRAD__FVAR_HPP__

#include <stan/meta/traits.hpp>

namespace stan {

  namespace agrad {

    template <typename T>
    struct fvar {

      T val_;  // value
      T d_;    // tangent (aka derivative)

      // TV and TD must be assignable to T
      template <typename TV, typename TD>
      fvar(const TV& val, const TD& deriv) : val_(val), d_(deriv) {  }

      // TV must be assignable to T
      template <typename TV>
      fvar(const TV& val) : val_(val), d_(0.0) {  }

      fvar() : val_(0.0), d_(0.0) { }

      template <typename T2>
      inline
      fvar<T>&
      operator+=(const fvar<T2>& x2) {
        val_ += x2.val_;
        d_ += x2.d_;
        return *this;
      }
      template <typename T2>
      inline
      fvar<T>&
      operator+=(const T2& x2) {
        val_ += x2;
        return *this;
      }

      template <typename T2>
      inline
      fvar<T>&
      operator-=(const fvar<T2>& x2) {
        val_ -= x2.val_;
        d_ -= x2.d_;
        return *this;
      }

      template <typename T2>
      inline
      fvar<T>&
      operator*=(const fvar<T2>& x2) {
        d_ = d_ * x2.val_ + val_ * x2.d_;
        val_ *= x2.val_;
        return *this;
      }

      // SPEEDUP: specialize for T2 == var with d_ function

      template <typename T2>
      inline
      fvar<T>&
      operator/=(const fvar<T2>& x2) {
        d_ = (d_ * x2.val_ - val_ * x2.d_) / ( x2.v_ * x2.v_);
        val_ /= x2.val_;
        return *this;
      }

      inline
      fvar<T>&
      operator++() {
        ++val_;
        return *this;
      }
      inline
      fvar<T>
      operator++(int /*dummy*/) {
        fvar<T> result(val_,d_);
        ++val_;
        return result;
      }

      inline
      fvar<T>&
      operator--() {
        --val_;
        return *this;
      }
      inline
      fvar<T>
      operator--(int /*dummy*/) {
        fvar<T> result(val_,d_);
        --val_;
        return result;
      }

    };

    template <typename T>
    inline
    fvar<T>
    operator-(const fvar<T>& x) {
      return fvar<T>(-x.val_, -x.d_);
    }

    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator+(const fvar<T1>& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ + x2.val_,
                                                  x1.d_ + x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator+(const T1& x1,
              const fvar<T2>& x2) {
      return
        fvar<typename
             stan::return_type<T1,T2>::type>(x1 + x2.val_,
                                             x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator+(const fvar<T1>& x1,
              const T2& x2) {
      return
        fvar<typename
             stan::return_type<T1,T2>::type>(x1.val_ + x2,
                                             x1.d_);
    }

    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator-(const fvar<T1>& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ - x2.val_,
                                                  x1.d_ - x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator-(const T1& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1 - x2.val_,
                                                  -x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator-(const fvar<T1>& x1,
              const T2& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ - x2,
                                                  x1.d_);
    }

    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator*(const fvar<T1>& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ * x2.val_,
                                                  x1.d_ * x2.val_
                                                  + x1.val_ * x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator*(const T1& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1 * x2.val_,
                                                  x1 * x2.d_);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator*(const fvar<T1>& x1,
              const T2& x2) {
      return fvar<typename
                  stan::return_type<T1,T2>::type>(x1.val_ * x2,
                                                  x1.d_ * x2);
    }

    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator/(const fvar<T1>& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan
                  ::return_type<T1,T2>::type>(x1.val_ / x2.val_,
                                              ( x1.d_ * x2.val_
                                                - x1.val_ * x2.d_ )
                                              / (x2.val_ * x2.val_));
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator/(const fvar<T1>& x1,
              T2& x2) {
      return fvar<typename stan::return_type<T1,T2>::type>(x1.val_ / x2,
                                                           x1.d_ / x2);
    }
    template <typename T1, typename T2>
    inline
    fvar<typename stan::return_type<T1,T2>::type>
    operator/(const T1& x1,
              const fvar<T2>& x2) {
      return fvar<typename
                  stan
                  ::return_type<T1,T2>::type>(x1 / x2.val_,
                                              - x1.val_ * x2.d_
                                              / (x2.val_ * x2.val_));
    }

    template <typename T>
    inline
    fvar<T>
    sin(const fvar<T>& x) {
      using std::sin;
      using std::cos;
      return fvar<T>(sin(x.val_),
                     x.d_ * cos(x.val_));
    }

  }
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <support/cleanse.h>

#include <openssl/crypto.h>

void memory_cleanse(void *ptr, size_t len)
{
    OPENSSL_cleanse(ptr, len);
}
<commit_msg>Switch memory_cleanse implementation to BoringSSL's to ensure memory clearing even with link-time optimization.<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <support/cleanse.h>

#include <cstring>

/* Compilers have a bad habit of removing "superfluous" memset calls that
 * are trying to zero memory. For example, when memset()ing a buffer and
 * then free()ing it, the compiler might decide that the memset is
 * unobservable and thus can be removed.
 *
 * Previously we used OpenSSL which tried to stop this by a) implementing
 * memset in assembly on x86 and b) putting the function in its own file
 * for other platforms.
 *
 * This change removes those tricks in favour of using asm directives to
 * scare the compiler away. As best as our compiler folks can tell, this is
 * sufficient and will continue to be so.
 *
 * Adam Langley <agl@google.com>
 * Commit: ad1907fe73334d6c696c8539646c21b11178f20f
 * BoringSSL (LICENSE: ISC)
 */
void memory_cleanse(void *ptr, size_t len)
{
    std::memset(ptr, 0, len);

    /* As best as we can tell, this is sufficient to break any optimisations that
       might try to eliminate "superfluous" memsets. If there's an easy way to
       detect memset_s, it would be better to use that. */
#if defined(_MSC_VER)
    __asm;
#else
    __asm__ __volatile__("" : : "r"(ptr) : "memory");
#endif
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "CodeUnitPart.h"
#include "CodeUnit.h"

#include "Export/src/tree/CompositeFragment.h"
#include "OOModel/src/allOOModelNodes.h"

namespace CppExport {

CodeUnitPart::CodeUnitPart(CodeUnit* parent) : parent_{parent} {}

bool CodeUnitPart::isSourceFragmentEmpty() const
{
	if (!sourceFragment_) return true;

	QList<Export::SourceFragment*> workList{sourceFragment_};
	while (!workList.empty())
	{
		auto current = workList.takeLast();
		if (dynamic_cast<Export::TextFragment*>(current))
			return false;
		else if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(current))
			workList << compositeFragment->fragments();
	}
	return true;
}

void CodeUnitPart::setSourceFragment(Export::SourceFragment* sourceFragment)
{
	sourceFragment_ = sourceFragment;

	// calculate name and reference nodes
	nameNodes_.clear();
	referenceNodes_.clear();
	QList<Export::SourceFragment*> workStack{sourceFragment};
	while (!workStack.empty())
	{
		auto fragment = workStack.takeLast();

		auto node = fragment->node();
		if (node->definesSymbol())
			nameNodes_.insert(node);
		else if (auto reference = DCast<OOModel::ReferenceExpression>(node))
			referenceNodes_.insert(reference);

		if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(fragment))
			workStack << compositeFragment->fragments();
	}

	// calculate targets
	softTargets_.clear();
	hardTargets_.clear();
	for (auto reference : referenceNodes_)
		if (auto target = fixedTarget(reference))
		{
			if (isNameOnlyDependency(reference))
				softTargets_.insert(target);
			else
				hardTargets_.insert(target);
		}
}

bool CodeUnitPart::isNameOnlyDependency(OOModel::ReferenceExpression* reference)
{
	auto parent = reference->parent();
	Q_ASSERT(parent);

	if (reference->firstAncestorOfType<OOModel::MethodCallExpression>()) return false;

	if (DCast<OOModel::TypeQualifierExpression>(parent)) parent = parent->parent();
	if (!DCast<OOModel::PointerTypeExpression>(parent) && !DCast<OOModel::ReferenceTypeExpression>(parent)) return false;

	return true;
}

Model::Node* CodeUnitPart::fixedTarget(OOModel::ReferenceExpression* referenceExpression)
{
	if (auto target = referenceExpression->target()) return target;

	// insert custom resolution adjustments here

	return nullptr;
}

void CodeUnitPart::calculateDependencies(QList<CodeUnitPart*>& allHeaderParts)
{
	dependencies_.clear();
	if (this == parent()->sourcePart())
		dependencies_.insert(parent()->headerPart());

	for (auto target : hardTargets_)
		for (auto headerPart : allHeaderParts)
			if (headerPart != this && headerPart->nameNodes().contains(target))
					dependencies_.insert(headerPart);
}

}
<commit_msg>detect hard dependencies introduced by member access<commit_after>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "CodeUnitPart.h"
#include "CodeUnit.h"

#include "Export/src/tree/CompositeFragment.h"
#include "OOModel/src/allOOModelNodes.h"
#include "OOModel/src/types/ClassType.h"
#include "OOModel/src/types/PointerType.h"

namespace CppExport {

CodeUnitPart::CodeUnitPart(CodeUnit* parent) : parent_{parent} {}

bool CodeUnitPart::isSourceFragmentEmpty() const
{
	if (!sourceFragment_) return true;

	QList<Export::SourceFragment*> workList{sourceFragment_};
	while (!workList.empty())
	{
		auto current = workList.takeLast();
		if (dynamic_cast<Export::TextFragment*>(current))
			return false;
		else if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(current))
			workList << compositeFragment->fragments();
	}
	return true;
}

void CodeUnitPart::setSourceFragment(Export::SourceFragment* sourceFragment)
{
	sourceFragment_ = sourceFragment;

	// calculate name and reference nodes
	nameNodes_.clear();
	referenceNodes_.clear();
	QList<Export::SourceFragment*> workStack{sourceFragment};
	while (!workStack.empty())
	{
		auto fragment = workStack.takeLast();

		auto node = fragment->node();
		if (node->definesSymbol())
			nameNodes_.insert(node);
		else if (auto reference = DCast<OOModel::ReferenceExpression>(node))
			referenceNodes_.insert(reference);

		if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(fragment))
			workStack << compositeFragment->fragments();
	}

	// calculate targets
	softTargets_.clear();
	hardTargets_.clear();
	for (auto reference : referenceNodes_)
		if (auto target = fixedTarget(reference))
		{
			if (isNameOnlyDependency(reference))
				softTargets_.insert(target);
			else
			{
				hardTargets_.insert(target);

				// member access
				auto parentMethodCall = DCast<OOModel::MethodCallExpression>(reference->parent());
				if (parentMethodCall || DCast<OOModel::ReferenceExpression>(reference->parent()))
				{
					const OOModel::Type* type{};

					if (parentMethodCall && parentMethodCall->callee()->isAncestorOf(reference))
						type = parentMethodCall->type();
					else
						type = reference->type();

					if (auto pointerType = dynamic_cast<const OOModel::PointerType*>(type))
						type = pointerType->baseType();

					if (auto classType = dynamic_cast<const OOModel::ClassType*>(type))
						hardTargets_.insert(classType->classDefinition());
				}
			}
		}
}

bool CodeUnitPart::isNameOnlyDependency(OOModel::ReferenceExpression* reference)
{
	auto parent = reference->parent();
	Q_ASSERT(parent);

	if (reference->firstAncestorOfType<OOModel::MethodCallExpression>()) return false;

	if (DCast<OOModel::TypeQualifierExpression>(parent)) parent = parent->parent();
	if (!DCast<OOModel::PointerTypeExpression>(parent) && !DCast<OOModel::ReferenceTypeExpression>(parent)) return false;

	return true;
}

Model::Node* CodeUnitPart::fixedTarget(OOModel::ReferenceExpression* referenceExpression)
{
	if (auto target = referenceExpression->target()) return target;

	// insert custom resolution adjustments here

	return nullptr;
}

void CodeUnitPart::calculateDependencies(QList<CodeUnitPart*>& allHeaderParts)
{
	dependencies_.clear();
	if (this == parent()->sourcePart())
		dependencies_.insert(parent()->headerPart());

	for (auto target : hardTargets_)
		for (auto headerPart : allHeaderParts)
			if (headerPart != this && headerPart->nameNodes().contains(target))
					dependencies_.insert(headerPart);
}

}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "CodeUnitPart.h"
#include "CodeUnit.h"

#include "Export/src/tree/CompositeFragment.h"
#include "OOModel/src/allOOModelNodes.h"
#include "OOModel/src/types/ClassType.h"
#include "OOModel/src/types/PointerType.h"

namespace CppExport {

CodeUnitPart::CodeUnitPart(CodeUnit* parent) : parent_{parent} {}

bool CodeUnitPart::isSourceFragmentEmpty() const
{
	if (!sourceFragment_) return true;

	QList<Export::SourceFragment*> workList{sourceFragment_};
	while (!workList.empty())
	{
		auto current = workList.takeLast();
		if (dynamic_cast<Export::TextFragment*>(current))
			return false;
		else if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(current))
			workList << compositeFragment->fragments();
	}
	return true;
}

void CodeUnitPart::setSourceFragment(Export::SourceFragment* sourceFragment)
{
	sourceFragment_ = sourceFragment;

	// calculate name and reference nodes
	nameNodes_.clear();
	referenceNodes_.clear();
	QList<Export::SourceFragment*> workStack{sourceFragment};
	while (!workStack.empty())
	{
		auto fragment = workStack.takeLast();

		auto node = fragment->node();
		if (node->definesSymbol())
			nameNodes_.insert(node);
		else if (auto reference = DCast<OOModel::ReferenceExpression>(node))
			referenceNodes_.insert(reference);

		if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(fragment))
			workStack << compositeFragment->fragments();
	}

	// calculate targets
	softTargets_.clear();
	hardTargets_.clear();
	for (auto reference : referenceNodes_)
		if (auto target = fixedTarget(reference))
		{
			if (isNameOnlyDependency(reference))
				softTargets_.insert(target);
			else
			{
				hardTargets_.insert(target);

				// member access
				auto parentMethodCall = DCast<OOModel::MethodCallExpression>(reference->parent());
				if (parentMethodCall || DCast<OOModel::ReferenceExpression>(reference->parent()))
				{
					const OOModel::Type* type{};

					if (parentMethodCall && parentMethodCall->callee()->isAncestorOf(reference))
						type = parentMethodCall->type();
					else
						type = reference->type();

					if (auto pointerType = dynamic_cast<const OOModel::PointerType*>(type))
						type = pointerType->baseType();

					if (auto classType = dynamic_cast<const OOModel::ClassType*>(type))
						hardTargets_.insert(classType->classDefinition());
				}
			}
		}
}

bool CodeUnitPart::isNameOnlyDependency(OOModel::ReferenceExpression* reference)
{
	auto parent = reference->parent();
	Q_ASSERT(parent);

	if (reference->firstAncestorOfType<OOModel::MethodCallExpression>()) return false;

	if (DCast<OOModel::TypeQualifierExpression>(parent)) parent = parent->parent();
	if (!DCast<OOModel::PointerTypeExpression>(parent) && !DCast<OOModel::ReferenceTypeExpression>(parent)) return false;

	return true;
}

Model::Node* CodeUnitPart::fixedTarget(OOModel::ReferenceExpression* referenceExpression)
{
	if (auto target = referenceExpression->target()) return target;

	// insert custom resolution adjustments here

	return nullptr;
}

void CodeUnitPart::calculateDependencies(QList<CodeUnitPart*>& allHeaderParts)
{
	dependencies_.clear();
	if (this == parent()->sourcePart())
		dependencies_.insert(parent()->headerPart());

	for (auto target : hardTargets_)
		for (auto headerPart : allHeaderParts)
			if (headerPart != this && headerPart->nameNodes().contains(target))
					dependencies_.insert(headerPart);
}

}
<commit_msg>make references in catch clauses introduce hard dependencies<commit_after>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "CodeUnitPart.h"
#include "CodeUnit.h"

#include "Export/src/tree/CompositeFragment.h"
#include "OOModel/src/allOOModelNodes.h"
#include "OOModel/src/types/ClassType.h"
#include "OOModel/src/types/PointerType.h"

namespace CppExport {

CodeUnitPart::CodeUnitPart(CodeUnit* parent) : parent_{parent} {}

bool CodeUnitPart::isSourceFragmentEmpty() const
{
	if (!sourceFragment_) return true;

	QList<Export::SourceFragment*> workList{sourceFragment_};
	while (!workList.empty())
	{
		auto current = workList.takeLast();
		if (dynamic_cast<Export::TextFragment*>(current))
			return false;
		else if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(current))
			workList << compositeFragment->fragments();
	}
	return true;
}

void CodeUnitPart::setSourceFragment(Export::SourceFragment* sourceFragment)
{
	sourceFragment_ = sourceFragment;

	// calculate name and reference nodes
	nameNodes_.clear();
	referenceNodes_.clear();
	QList<Export::SourceFragment*> workStack{sourceFragment};
	while (!workStack.empty())
	{
		auto fragment = workStack.takeLast();

		auto node = fragment->node();
		if (node->definesSymbol())
			nameNodes_.insert(node);
		else if (auto reference = DCast<OOModel::ReferenceExpression>(node))
			referenceNodes_.insert(reference);

		if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(fragment))
			workStack << compositeFragment->fragments();
	}

	// calculate targets
	softTargets_.clear();
	hardTargets_.clear();
	for (auto reference : referenceNodes_)
		if (auto target = fixedTarget(reference))
		{
			if (isNameOnlyDependency(reference))
				softTargets_.insert(target);
			else
			{
				hardTargets_.insert(target);

				// member access
				auto parentMethodCall = DCast<OOModel::MethodCallExpression>(reference->parent());
				if (parentMethodCall || DCast<OOModel::ReferenceExpression>(reference->parent()))
				{
					const OOModel::Type* type{};

					if (parentMethodCall && parentMethodCall->callee()->isAncestorOf(reference))
						type = parentMethodCall->type();
					else
						type = reference->type();

					if (auto pointerType = dynamic_cast<const OOModel::PointerType*>(type))
						type = pointerType->baseType();

					if (auto classType = dynamic_cast<const OOModel::ClassType*>(type))
						hardTargets_.insert(classType->classDefinition());
				}
			}
		}
}

bool CodeUnitPart::isNameOnlyDependency(OOModel::ReferenceExpression* reference)
{
	auto parent = reference->parent();
	Q_ASSERT(parent);

	if (reference->firstAncestorOfType<OOModel::MethodCallExpression>()) return false;

	if (DCast<OOModel::TypeQualifierExpression>(parent)) parent = parent->parent();
	if (!DCast<OOModel::PointerTypeExpression>(parent) && !DCast<OOModel::ReferenceTypeExpression>(parent)) return false;
	if (auto tryCatchFinally = reference->firstAncestorOfType<OOModel::TryCatchFinallyStatement>())
		if (tryCatchFinally->catchClauses()->isAncestorOf(reference)) return false;

	return true;
}

Model::Node* CodeUnitPart::fixedTarget(OOModel::ReferenceExpression* referenceExpression)
{
	if (auto target = referenceExpression->target()) return target;

	// insert custom resolution adjustments here

	return nullptr;
}

void CodeUnitPart::calculateDependencies(QList<CodeUnitPart*>& allHeaderParts)
{
	dependencies_.clear();
	if (this == parent()->sourcePart())
		dependencies_.insert(parent()->headerPart());

	for (auto target : hardTargets_)
		for (auto headerPart : allHeaderParts)
			if (headerPart != this && headerPart->nameNodes().contains(target))
					dependencies_.insert(headerPart);
}

}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "CodeUnitPart.h"
#include "CodeUnit.h"

#include "Export/src/tree/CompositeFragment.h"
#include "OOModel/src/allOOModelNodes.h"
#include "OOModel/src/types/ClassType.h"
#include "OOModel/src/types/PointerType.h"
#include "OOModel/src/types/ReferenceType.h"

namespace CppExport {

CodeUnitPart::CodeUnitPart(CodeUnit* parent) : parent_{parent} {}

bool CodeUnitPart::isSourceFragmentEmpty() const
{
	if (!sourceFragment_) return true;

	QList<Export::SourceFragment*> workList{sourceFragment_};
	while (!workList.empty())
	{
		auto current = workList.takeLast();
		if (dynamic_cast<Export::TextFragment*>(current))
			return false;
		else if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(current))
			workList << compositeFragment->fragments();
	}
	return true;
}

void CodeUnitPart::setSourceFragment(Export::SourceFragment* sourceFragment)
{
	sourceFragment_ = sourceFragment;

	// calculate name and reference nodes
	nameNodes_.clear();
	referenceNodes_.clear();
	QList<Export::SourceFragment*> workStack{sourceFragment};
	while (!workStack.empty())
	{
		auto fragment = workStack.takeLast();

		auto node = fragment->node();
		if (node->definesSymbol())
			nameNodes_.insert(node);
		else if (auto reference = DCast<OOModel::ReferenceExpression>(node))
			referenceNodes_.insert(reference);

		if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(fragment))
			workStack << compositeFragment->fragments();
	}

	// calculate targets
	softTargets_.clear();
	hardTargets_.clear();
	for (auto reference : referenceNodes_)
		if (auto target = fixedTarget(reference))
		{
			if (isNameOnlyDependency(reference))
				softTargets_.insert(target);
			else
			{
				hardTargets_.insert(target);

				// member access
				auto parentMethodCall = DCast<OOModel::MethodCallExpression>(reference->parent());
				if (parentMethodCall || DCast<OOModel::ReferenceExpression>(reference->parent()))
				{
					const OOModel::Type* baseType{};
					if (parentMethodCall && parentMethodCall->callee()->isAncestorOf(reference))
						baseType = parentMethodCall->type();
					else
						baseType = reference->type();

					auto finalType = baseType;
					if (auto pointerType = dynamic_cast<const OOModel::PointerType*>(baseType))
						finalType = pointerType->baseType();
					else if (auto referenceType = dynamic_cast<const OOModel::ReferenceType*>(baseType))
						finalType = referenceType->baseType();

					if (auto classType = dynamic_cast<const OOModel::ClassType*>(finalType))
						hardTargets_.insert(classType->classDefinition());

					SAFE_DELETE(baseType);
				}
			}
		}
}

bool CodeUnitPart::isNameOnlyDependency(OOModel::ReferenceExpression* reference)
{
	auto parent = reference->parent();
	Q_ASSERT(parent);

	if (reference->firstAncestorOfType<OOModel::MethodCallExpression>()) return false;

	if (DCast<OOModel::TypeQualifierExpression>(parent)) parent = parent->parent();
	if (!DCast<OOModel::PointerTypeExpression>(parent) && !DCast<OOModel::ReferenceTypeExpression>(parent)) return false;
	if (auto tryCatchFinally = reference->firstAncestorOfType<OOModel::TryCatchFinallyStatement>())
		if (tryCatchFinally->catchClauses()->isAncestorOf(reference)) return false;

	return true;
}

Model::Node* CodeUnitPart::fixedTarget(OOModel::ReferenceExpression* referenceExpression)
{
	if (auto target = referenceExpression->target()) return target;

	// insert custom resolution adjustments here

	return nullptr;
}

void CodeUnitPart::calculateDependencies(QList<CodeUnit*>& allUnits)
{
	if (DCast<OOModel::MetaDefinition>(parent_->node())) return;

	dependencies_.clear();
	if (this == parent()->sourcePart())
		dependencies_.insert(parent()->headerPart());

	for (auto target : hardTargets_)
		for (auto unit : allUnits)
			if (unit->headerPart() != this && unit->headerPart()->nameNodes().contains(target))
					dependencies_.insert(unit->headerPart());
}

QSet<CodeUnitPart*> CodeUnitPart::sourceDependencies(QList<CodeUnit*> units)
{
	QSet<CodeUnitPart*> result;
	for (auto referenceNode : referenceNodes_)
		if (auto target = referenceNode->target())
			for (auto unit : units)
				if (unit->sourcePart() != this &&
					 unit->sourcePart()->nameNodes().contains(target))
						result.insert(unit->sourcePart());
	return result;
}

}
<commit_msg>detect certain kinds of hard dependencies as soft dependencies<commit_after>/***********************************************************************************************************************
 **
 ** Copyright (c) 2011, 2015 ETH Zurich
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 **
 **    * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **      following disclaimer.
 **    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 **      following disclaimer in the documentation and/or other materials provided with the distribution.
 **    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
 **      derived from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **
 **********************************************************************************************************************/

#include "CodeUnitPart.h"
#include "CodeUnit.h"

#include "Export/src/tree/CompositeFragment.h"
#include "OOModel/src/allOOModelNodes.h"
#include "OOModel/src/types/ClassType.h"
#include "OOModel/src/types/PointerType.h"
#include "OOModel/src/types/ReferenceType.h"

namespace CppExport {

CodeUnitPart::CodeUnitPart(CodeUnit* parent) : parent_{parent} {}

bool CodeUnitPart::isSourceFragmentEmpty() const
{
	if (!sourceFragment_) return true;

	QList<Export::SourceFragment*> workList{sourceFragment_};
	while (!workList.empty())
	{
		auto current = workList.takeLast();
		if (dynamic_cast<Export::TextFragment*>(current))
			return false;
		else if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(current))
			workList << compositeFragment->fragments();
	}
	return true;
}

void CodeUnitPart::setSourceFragment(Export::SourceFragment* sourceFragment)
{
	sourceFragment_ = sourceFragment;

	// calculate name and reference nodes
	nameNodes_.clear();
	referenceNodes_.clear();
	QList<Export::SourceFragment*> workStack{sourceFragment};
	while (!workStack.empty())
	{
		auto fragment = workStack.takeLast();

		auto node = fragment->node();
		if (node->definesSymbol())
			nameNodes_.insert(node);
		else if (auto reference = DCast<OOModel::ReferenceExpression>(node))
			referenceNodes_.insert(reference);

		if (auto compositeFragment = dynamic_cast<Export::CompositeFragment*>(fragment))
			workStack << compositeFragment->fragments();
	}

	// calculate targets
	softTargets_.clear();
	hardTargets_.clear();
	for (auto reference : referenceNodes_)
		if (auto target = fixedTarget(reference))
		{
			if (isNameOnlyDependency(reference))
				softTargets_.insert(target);
			else
			{
				auto parentMethodCall = DCast<OOModel::MethodCallExpression>(reference->parent());
				auto prefixReference = DCast<OOModel::ReferenceExpression>(reference->prefix());

				if (!parentMethodCall || !prefixReference || prefixReference->typeArguments()->isEmpty())
					hardTargets_.insert(target);

				// member access
				if (parentMethodCall || DCast<OOModel::ReferenceExpression>(reference->parent()))
				{
					const OOModel::Type* baseType{};
					if (parentMethodCall && parentMethodCall->callee()->isAncestorOf(reference))
						baseType = parentMethodCall->type();
					else
						baseType = reference->type();

					auto finalType = baseType;
					if (auto pointerType = dynamic_cast<const OOModel::PointerType*>(baseType))
						finalType = pointerType->baseType();
					else if (auto referenceType = dynamic_cast<const OOModel::ReferenceType*>(baseType))
						finalType = referenceType->baseType();

					if (auto classType = dynamic_cast<const OOModel::ClassType*>(finalType))
						hardTargets_.insert(classType->classDefinition());

					SAFE_DELETE(baseType);
				}
			}
		}
}

bool CodeUnitPart::isNameOnlyDependency(OOModel::ReferenceExpression* reference)
{
	auto parent = reference->parent();
	Q_ASSERT(parent);

	auto parentClass = reference->firstAncestorOfType<OOModel::Class>();
	if (reference->firstAncestorOfType<OOModel::MethodCallExpression>() &&
		 !reference->typeArguments()->isEmpty() && parentClass && !parentClass->typeArguments()->isEmpty())
		return true;

	if (reference->firstAncestorOfType<OOModel::MethodCallExpression>()) return false;

	if (DCast<OOModel::TypeQualifierExpression>(parent)) parent = parent->parent();
	if (!DCast<OOModel::PointerTypeExpression>(parent) && !DCast<OOModel::ReferenceTypeExpression>(parent)) return false;
	if (auto tryCatchFinally = reference->firstAncestorOfType<OOModel::TryCatchFinallyStatement>())
		if (tryCatchFinally->catchClauses()->isAncestorOf(reference)) return false;

	return true;
}

Model::Node* CodeUnitPart::fixedTarget(OOModel::ReferenceExpression* referenceExpression)
{
	if (auto target = referenceExpression->target()) return target;

	// insert custom resolution adjustments here

	return nullptr;
}

void CodeUnitPart::calculateDependencies(QList<CodeUnit*>& allUnits)
{
	if (DCast<OOModel::MetaDefinition>(parent_->node())) return;

	dependencies_.clear();
	if (this == parent()->sourcePart())
		dependencies_.insert(parent()->headerPart());

	for (auto target : hardTargets_)
		for (auto unit : allUnits)
			if (unit->headerPart() != this && unit->headerPart()->nameNodes().contains(target))
					dependencies_.insert(unit->headerPart());
}

QSet<CodeUnitPart*> CodeUnitPart::sourceDependencies(QList<CodeUnit*> units)
{
	QSet<CodeUnitPart*> result;
	for (auto referenceNode : referenceNodes_)
		if (auto target = referenceNode->target())
			for (auto unit : units)
				if (unit->sourcePart() != this &&
					 unit->sourcePart()->nameNodes().contains(target))
						result.insert(unit->sourcePart());
	return result;
}

}
<|endoftext|>


<commit_before>/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/phi/api/lib/kernel_dispatch.h"

#include "paddle/phi/api/include/context_pool.h"
#include "paddle/phi/core/compat/convert_utils.h"
#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace paddle {
namespace experimental {
namespace detail {

BackendSet GetTensorBackendSet(const phi::TensorBase& t) {
  BackendSet backend_set(phi::TransToPhiBackend(t.place()));
  switch (t.layout()) {
    case DataLayout::MKLDNN:
      backend_set = backend_set | BackendSet(Backend::MKLDNN);
      break;
    default:
      // do nothing
      break;
  }
  return backend_set;
}

std::size_t CountLeadingZeros(uint64_t val) {
#if defined(__clang__) || defined(__GNUC__)
  return __builtin_clzl(val);
#elif defined(_MSC_VER)
  return __lzcnt64(val);
#else
  if (val == 0) {
    return 64;
  }
  std::size_t zero_bits = 0;
  for (std::size_t shift = 64 >> 1; shift; shift >>= 1) {
    uint64_t tmp = val >> shift;
    if (tmp) {
      val = tmp;
    } else {
      zero_bits |= shift;
    }
  }
  return zero_bits;
#endif
}

}  // namespace detail

phi::DeviceContext* GetDeviceContextByBackend(phi::Backend backend) {
  auto& pool = paddle::experimental::DeviceContextPool::Instance();
  return pool.GetMutable(phi::TransToPhiPlace(backend));
}

DataType ParseDataType(DataType dtype) { return dtype; }
DataType ParseDataType(const Tensor& tensor) { return tensor.type(); }
DataType ParseDataType(const std::vector<Tensor>& tensors) {
  if (tensors.empty()) {
    return DataType::UNDEFINED;
  }
  DataType dtype = tensors[0].type();
  auto n = tensors.size();
  for (size_t i = 1; i < n; ++i) {
    if (tensors[i].type() != dtype) {
      PADDLE_THROW(platform::errors::InvalidArgument(
          "The data_type of input tensor in list isn't consistent, "
          "the first tensor is %s, but %dth tensor is %s.",
          dtype,
          i,
          tensors[i].type()));
    }
  }
  return dtype;
}

DataType ParseDataTypeWithInputOrder(DataType dtype, const Tensor& tensor) {
  return dtype != DataType::UNDEFINED ? dtype : ParseDataType(tensor);
}

Backend ParseBackend(const Place& place) {
  return phi::TransToPhiBackend(place);
}
Backend ParseBackend(const Tensor& tensor) {
  return phi::TransToPhiBackend(tensor.inner_place());
}

Backend ParseBackendWithInputOrder(const Place& place, const Tensor& tensor) {
  return place.GetType() != phi::AllocationType::UNDEFINED
             ? ParseBackend(place)
             : ParseBackend(tensor);
}

DataLayout ParseLayout(DataLayout layout) { return layout; }
DataLayout ParseLayout(const Tensor& tensor) { return tensor.layout(); }

DataLayout ParseLayoutWithInputOrder(DataLayout layout, const Tensor& tensor) {
  return layout != DataLayout::UNDEFINED ? layout : ParseLayout(tensor);
}

}  // namespace experimental
}  // namespace paddle
<commit_msg>fix kernel backend select bug (#41002)<commit_after>/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/phi/api/lib/kernel_dispatch.h"

#include "paddle/phi/api/include/context_pool.h"
#include "paddle/phi/core/compat/convert_utils.h"
#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace paddle {
namespace experimental {
namespace detail {

BackendSet GetTensorBackendSet(const phi::TensorBase& t) {
  if (t.initialized()) {
    BackendSet backend_set(phi::TransToPhiBackend(t.place()));
    switch (t.layout()) {
      case DataLayout::MKLDNN:
        backend_set = backend_set | BackendSet(Backend::MKLDNN);
        break;
      default:
        // do nothing
        break;
    }
    return backend_set;
  }
  return BackendSet(Backend::UNDEFINED);
}

std::size_t CountLeadingZeros(uint64_t val) {
#if defined(__clang__) || defined(__GNUC__)
  return __builtin_clzl(val);
#elif defined(_MSC_VER)
  return __lzcnt64(val);
#else
  if (val == 0) {
    return 64;
  }
  std::size_t zero_bits = 0;
  for (std::size_t shift = 64 >> 1; shift; shift >>= 1) {
    uint64_t tmp = val >> shift;
    if (tmp) {
      val = tmp;
    } else {
      zero_bits |= shift;
    }
  }
  return zero_bits;
#endif
}

}  // namespace detail

phi::DeviceContext* GetDeviceContextByBackend(phi::Backend backend) {
  auto& pool = paddle::experimental::DeviceContextPool::Instance();
  return pool.GetMutable(phi::TransToPhiPlace(backend));
}

DataType ParseDataType(DataType dtype) { return dtype; }
DataType ParseDataType(const Tensor& tensor) { return tensor.type(); }
DataType ParseDataType(const std::vector<Tensor>& tensors) {
  if (tensors.empty()) {
    return DataType::UNDEFINED;
  }
  DataType dtype = tensors[0].type();
  auto n = tensors.size();
  for (size_t i = 1; i < n; ++i) {
    if (tensors[i].type() != dtype) {
      PADDLE_THROW(platform::errors::InvalidArgument(
          "The data_type of input tensor in list isn't consistent, "
          "the first tensor is %s, but %dth tensor is %s.",
          dtype,
          i,
          tensors[i].type()));
    }
  }
  return dtype;
}

DataType ParseDataTypeWithInputOrder(DataType dtype, const Tensor& tensor) {
  return dtype != DataType::UNDEFINED ? dtype : ParseDataType(tensor);
}

Backend ParseBackend(const Place& place) {
  return phi::TransToPhiBackend(place);
}
Backend ParseBackend(const Tensor& tensor) {
  return phi::TransToPhiBackend(tensor.inner_place());
}

Backend ParseBackendWithInputOrder(const Place& place, const Tensor& tensor) {
  return place.GetType() != phi::AllocationType::UNDEFINED
             ? ParseBackend(place)
             : ParseBackend(tensor);
}

DataLayout ParseLayout(DataLayout layout) { return layout; }
DataLayout ParseLayout(const Tensor& tensor) { return tensor.layout(); }

DataLayout ParseLayoutWithInputOrder(DataLayout layout, const Tensor& tensor) {
  return layout != DataLayout::UNDEFINED ? layout : ParseLayout(tensor);
}

}  // namespace experimental
}  // namespace paddle
<|endoftext|>