| 762 | |
| 763 | template <typename FnType> |
| 764 | static Status ForEachIndexInternal(const Shape& shape, |
| 765 | absl::Span<const int64> base, |
| 766 | absl::Span<const int64> count, |
| 767 | absl::Span<const int64> incr, |
| 768 | const FnType& visitor_function, |
| 769 | bool parallel = false) { |
| 770 | if (ShapeUtil::IsZeroElementArray(shape)) { |
| 771 | return Status::OK(); |
| 772 | } |
| 773 | CHECK_EQ(shape.rank(), base.size()); |
| 774 | CHECK_EQ(incr.size(), base.size()); |
| 775 | CHECK_EQ(count.size(), base.size()); |
| 776 | const int64 rank = LayoutUtil::MinorToMajor(shape).size(); |
| 777 | // Allows handling R0 arrays, such that the visitor function will be called |
| 778 | // once with the proper empty indexes. |
| 779 | int64 n = -1; |
| 780 | std::vector<int64> indexes(base.begin(), base.end()); |
| 781 | const int kNumThreads = tensorflow::port::MaxParallelism(); |
| 782 | absl::optional<tensorflow::thread::ThreadPool> pool; |
| 783 | if (parallel) { |
| 784 | pool.emplace(tensorflow::Env::Default(), "foreach", kNumThreads); |
| 785 | } |
| 786 | |
| 787 | tensorflow::mutex mu; |
| 788 | Status status; // Guarded by mu |
| 789 | |
| 790 | while (n < rank) { |
| 791 | if (pool != absl::nullopt) { |
| 792 | pool->Schedule([indexes, &visitor_function, &mu, &status] { |
| 793 | StatusOr<bool> result = visitor_function(indexes); |
| 794 | if (!result.ok()) { |
| 795 | tensorflow::mutex_lock lock(mu); |
| 796 | status = status.ok() ? result.status() : status; |
| 797 | } |
| 798 | }); |
| 799 | } else { |
| 800 | TF_ASSIGN_OR_RETURN(bool should_continue, visitor_function(indexes)); |
| 801 | if (!should_continue) { |
| 802 | break; |
| 803 | } |
| 804 | } |
| 805 | // Increments dimensions in minor to major order. |
| 806 | for (n = 0; n < rank; ++n) { |
| 807 | int64 dim = LayoutUtil::Minor(shape.layout(), n); |
| 808 | indexes[dim] += incr[dim]; |
| 809 | if (indexes[dim] < base[dim] + count[dim]) { |
| 810 | break; |
| 811 | } |
| 812 | indexes[dim] = base[dim]; |
| 813 | } |
| 814 | } |
| 815 | |
| 816 | // Waits for the scheduled work to complete. |
| 817 | pool.reset(); |
| 818 | return status; |
| 819 | } |
| 820 | |
| 821 | TF_DISALLOW_COPY_AND_ASSIGN(ShapeUtil); |
nothing calls this directly
no test coverage detected