class AutoC::Range::ForwardRange::ContiguousRange

@abstract

Constants

OPTIONAL_OMP_H

Public Class Methods

new(iterable, visibility: :public, parallel: nil) click to toggle source
Calls superclass method AutoC::Range::new
# File lib/autoc/ranges.rb, line 392
def initialize(iterable, visibility: :public, parallel: nil)
  super(iterable, visibility:)
  @parallel = parallel
end

Public Instance Methods

render_interface(stream) click to toggle source
# File lib/autoc/ranges.rb, line 397
def render_interface(stream)
  if public?
    case @parallel
    when nil
      stream << %{
        /**
          #{defgroup}

          #{brief}

          This is the range for contiguous data structures (vectors, strings etc.)

          It can be used the following way:

          @code{.c}
          for(#{signature} r = #{new}(&it); !#{empty}(&r); #{pop_front}(&r)) { ... }
          @endcode

          @see @ref Range

          @since 2.0
        */
      }
    when :openmp
      stream << %{
        /**
          #{defgroup}

          #{brief}

          This is the range for contiguous data structures (vectors, strings etc.)

          The @ref #{new} and @ref #{custom_create} range constructors create OpenMP-aware range objects
          which account for parallel iteration in the way

          @code{.c}
          #pragma omp parallel
          for(#{signature} r = #{new}(&it); !#{empty}(&r); #{pop_front}(&r)) { ... }
          @endcode

          @see @ref Range

          @since 2.0
        */
      }
    end
  end
  if public?
    stream << %{
      /**
        #{ingroup}
        @brief Opaque structure holding state of the contiguous container's range
        @since 2.0
      */
    }
  else
    stream << PRIVATE
  end
  stream << %{
    typedef struct {
      #{iterable.element.lvalue} front; /**< @private */
      #{iterable.element.lvalue} back; /**< @private */
    } #{signature};
  }
end

Private Instance Methods

configure() click to toggle source
# File lib/autoc/ranges.rb, line 471
def configure
  super
  case @parallel
  when nil
    custom_create.configure do
      inline_code %{
        assert(range);
        assert(iterable);
        range->front = #{_iterable.storage(iterable)};
        range->back  = #{_iterable.storage(iterable)} + #{_iterable.size.(iterable)} - 1;
      }
    end
  when :openmp
    dependencies << OPTIONAL_OMP_H
    custom_create.configure do
      inline_code %{
        size_t size;
        #ifdef _OPENMP
          unsigned chunk_count;
        #endif
        assert(range);
        assert(iterable);
        size = #{_iterable.size.(iterable)};
        #ifdef _OPENMP
          if(omp_in_parallel() && (chunk_count = omp_get_num_threads()) > 1) {
            int chunk_id = omp_get_thread_num();
            size_t chunk_size = size / omp_get_num_threads();
            range->front = #{_iterable.storage(iterable)} + chunk_id*chunk_size;
            range->back  = #{_iterable.storage(iterable)} + (
              chunk_id < chunk_count - 1 ?
              (chunk_id + 1)*chunk_size - 1 :
              size - 1
            );
          } else {
        #endif
          range->front = #{_iterable.storage(iterable)};
          range->back  = #{_iterable.storage(iterable)} + size - 1;
        #ifdef _OPENMP
          }
        #endif
      }
    end
  else
    raise "unsupported parallel range specifier #{@parallel}"
  end
  empty.configure do
    inline_code %{
      assert(range);
      assert(range->front);
      assert(range->back);
      return range->front > range->back;
    }
  end
  pop_front.configure do
    dependencies << empty
    inline_code %{
      assert(range);
      assert(range->front);
      assert(!#{empty.(range)});
      ++range->front;
    }
  end
  pop_back.configure do
    dependencies << empty
    inline_code %{
      assert(range);
      assert(range->back);
      assert(!#{empty.(range)});
      --range->back;
    }
  end
  view_front.configure do
    dependencies << empty
    inline_code %{
      assert(range);
      assert(range->front);
      assert(!#{empty.(range)});
      return range->front;
    }
  end
  view_back.configure do
    dependencies << empty
    inline_code %{
      assert(range);
      assert(range->back);
      assert(!#{empty.(range)});
      return range->back;
    }
  end
  size.configure do
    dependencies << empty
    inline_code %{
      assert(range);
      assert(range->front);
      assert(range->back);
      return #{empty.(range)} ? 0 : range->back - range->front + 1;
    }
  end
  view.configure do
    dependencies << check
    inline_code %{
      assert(range);
      assert(#{check.(range, index)});
      return range->front + index;
    }
  end
end