Repository: apache/arrow
File: cpp/src/arrow/util/thread_pool.h (C/C++)

Code before:
  } else {
    return SerialExecutor::RunInSerialExecutor<ValueType>(std::move(get_future));
  }
}

/// \brief Potentially iterate an async generator serially (if use_threads is false)
///   using a potentially custom Executor
/// \see IterateGenerator
///
/// If `use_threads` is true, the global CPU executor will be used.  Each call to
///   the iterator will simply wait until the next item is available.  Tasks may run in
///   the background between calls.
///
/// If `use_threads` is false, the calling thread only will be used.  Each call to
///   the iterator will use the calling thread to do enough work to generate one item.
///   Tasks will be left in a queue until the next call and no work will be done between
///   calls.
///
/// If `executor` is null, then the default CPU thread pool will be used.
/// If `executor` is not null, then it will be used.
template <typename T>
Iterator<T> IterateSynchronously(
    FnOnce<Result<std::function<Future<T>()>>(Executor*)> get_gen, bool use_threads,
    Executor* executor) {
  if (use_threads) {
    auto used_executor = executor != nullptr ? executor : GetCpuThreadPool();
    auto maybe_gen = std::move(get_gen)(used_executor);
    if (!maybe_gen.ok()) {
      return MakeErrorIterator<T>(maybe_gen.status());
    }
    return MakeGeneratorIterator(*maybe_gen);
  } else {
    return SerialExecutor::IterateGenerator(std::move(get_gen));
  }
}

/// \brief Potentially iterate an async generator serially (if use_threads is false)
///   using the default CPU thread pool
/// \see IterateGenerator
///
/// If `use_threads` is true, the global CPU executor will be used.  Each call to
///   the iterator will simply wait until the next item is available.  Tasks may run in
///   the background between calls.
///
/// If `use_threads` is false, the calling thread only will be used.  Each call to
///   the iterator will use the calling thread to do enough work to generate one item.
///   Tasks will be left in a queue until the next call and no work will be done between
///   calls.
template <typename T>
Iterator<T> IterateSynchronously(
    FnOnce<Result<std::function<Future<T>()>>(Executor*)> get_gen, bool use_threads) {

Review comment (bug):
We seem to require our `NULLPTR` macro usage on header files due to C++/CLI compatibilty. This is why is failing linting.
To be honest I am not sure whether the C++/CLI compatibiltiy is required anymore so I am asking on Zulip and I might follow up in the ML.
```suggestion
    auto used_executor = executor != NULLPTR ? executor : GetCpuThreadPool();
```

Code after:
  } else {
    return SerialExecutor::RunInSerialExecutor<ValueType>(std::move(get_future));
  }
}

/// \brief Potentially iterate an async generator serially (if use_threads is false)
///   using a potentially custom Executor
/// \see IterateGenerator
///
/// If `use_threads` is true, the custom executor or, if null,
///   the global CPU executor will be used.  Each call to
///   the iterator will simply wait until the next item is available.  Tasks may run in
///   the background between calls.
///
/// If `use_threads` is false, the calling thread only will be used.  Each call to
///   the iterator will use the calling thread to do enough work to generate one item.
///   Tasks will be left in a queue until the next call and no work will be done between
///   calls.
template <typename T>
Iterator<T> IterateSynchronously(
    FnOnce<Result<std::function<Future<T>()>>(Executor*)> get_gen, bool use_threads,
    Executor* executor) {
  if (use_threads) {
    auto used_executor = executor != NULLPTR ? executor : GetCpuThreadPool();
    auto maybe_gen = std::move(get_gen)(used_executor);
    if (!maybe_gen.ok()) {
      return MakeErrorIterator<T>(maybe_gen.status());
    }
    return MakeGeneratorIterator(*maybe_gen);
  } else {
    return SerialExecutor::IterateGenerator(std::move(get_gen));
  }
}

/// \brief Potentially iterate an async generator serially (if use_threads is false)
///   using the default CPU thread pool
/// \see IterateGenerator
///
/// If `use_threads` is true, the global CPU executor will be used.  Each call to
///   the iterator will simply wait until the next item is available.  Tasks may run in
///   the background between calls.
///
/// If `use_threads` is false, the calling thread only will be used.  Each call to
///   the iterator will use the calling thread to do enough work to generate one item.
///   Tasks will be left in a queue until the next call and no work will be done between
///   calls.
template <typename T>
Iterator<T> IterateSynchronously(
    FnOnce<Result<std::function<Future<T>()>>(Executor*)> get_gen, bool use_threads) {
  return IterateSynchronously(std::move(get_gen), use_threads, NULLPTR);
}