Реализация цепочечных итераторов в расширении Ruby C

Я вижу, что в Ruby есть относительно новая функция, которая позволяет связывать итерации - другими словами, вместо each_with_indices { |x,i,j| ... } вы могли бы сделать each.with_indices { |x,i,j| ... }, где #each возвращает Enumerator объект и Enumerator#with_indices вызывает включение дополнительных параметров доходности.

Так, Enumerator имеет свой метод #with_index, предположительно для одномерных объектов, источник найден здесь. Но я не могу найти лучший способ приспособить это к другим объектам.

Чтобы было понятно, и в ответ на комментарии: у Ruby нет #each_with_indices прямо сейчас - это только есть #each_with_index, (Вот почему я хочу создать один.)

Ряд вопросов, сами прикованные цепью:

  1. Как можно адаптировать цепную итерацию к одномерному объекту? Просто сделай include Enumerable?
  2. Предположительно, вышеприведенный (#1) не будет работать дляn - мерного объекта. Будет ли один создать EnumerableNкласс, производный отEnumerable, но с #with_index конвертирован в #with_indices?
  3. Можно ли сделать № 2 для расширений Ruby, написанных на C? Например, у меня есть класс матрицы, в котором хранятся различные типы данных (числа с плавающей запятой, двойные числа, целые числа, иногда обычные объекты Rubyи т. Д.). Перечисление должно проверить тип данных (dtype) сначала согласно примеру ниже.

Пример:

VALUE nm_dense_each(VALUE nm) {
  volatile VALUE nm = nmatrix; // Not sure this actually does anything.
  DENSE_STORAGE* s = NM_STORAGE_DENSE(nm); // get the storage pointer

  RETURN_ENUMERATOR(nm, 0, 0);

  if (NM_DTYPE(nm) == nm::RUBYOBJ) { // matrix stores VALUEs

    // matrix of Ruby objects -- yield those objects directly
    for (size_t i = 0; i < nm_storage_count_max_elements(s); ++i)
      rb_yield( reinterpret_cast<VALUE*>(s->elements)[i] );

  } else { // matrix stores non-Ruby data (int, float, etc)

    // We're going to copy the matrix element into a Ruby VALUE and then operate on it. This way user can't accidentally
    // modify it and cause a seg fault.
    for (size_t i = 0; i < nm_storage_count_max_elements(s); ++i) {
      // rubyobj_from_cval() converts any type of data into a VALUE using macros such as INT2FIX()
      VALUE v = rubyobj_from_cval((char*)(s->elements) + i*DTYPE_SIZES[NM_DTYPE(nm)], NM_DTYPE(nm)).rval;
      rb_yield( v ); // yield to the copy we made
    }
  }
}

Итак, чтобы объединить три моих вопроса в один: как бы я написал, в C, #with_indices цепляться на NMatrix#each метод выше?

Я не хочу, чтобы кто-то чувствовал, что я прошу их написать это для меня, хотя, если бы вы захотели, мы бы хотели, чтобы вы участвовали в нашем проекте. знак равно

Но если вы знаете какой-нибудь пример в Интернете, как это делается, это было бы идеально - или если бы вы могли просто объяснить словами, это тоже было бы прекрасно.

2 ответа

#with_index это метод Enumerator: http://ruby-doc.org/core-1.9.3/Enumerator.html

Я полагаю, вы могли бы сделать подкласс Enumerator который имеет #with_indices и ваш #each вернуть экземпляр этого класса? Это первое, что приходит на ум, хотя ваш перечислитель может быть довольно тесно связан с исходным классом...

Поскольку вы говорите, что вы также интересуетесь лингвистикой Ruby, а не только C, позвольте мне внести свои 5 центов, не требуя фактически ответить на вопрос. #each_with_index а также #with_index уже стало настолько идиоматичным, что большинство людей полагается на индекс, являющийся числом. Поэтому, если вы идете и реализуете NMatrix#each_with_index таким образом, что в блоке { |e, i| ... } это будет поставлять, например. массивы [0, 0], [0, 1], [0, 2], [1, 0], [1, 1], ... в качестве индекса iудивишь людей. Кроме того, если другие приковывают вас NMatrix#each счетчик с #with_index метод, они получат только одно число в качестве индекса. Итак, действительно, вы правы, заключив, что вам нужен отдельный метод для заботы о типе 2 индексов (или, в более общем случае, n индексов для матриц более высокой размерности):

matrix.each_with_indices { |e, indices| ... }

Этот метод должен возвращать 2-мерный (n-мерный) массив как indices == [i, j], Вы не должны идти на версию:

matrix.each_with_indices { |e, i, j| ... }

Для #with_index метод, это не ваша забота вообще. Если твой NMatrix обеспечивает #each метод (что, безусловно, делает), то #with_index будет работать с ним нормально, вне вашего контроля. И вам не нужно задумываться о введении матриц-специфических #with_indices, так как #each сама по себе не специфична для матриц, а для одномерных упорядоченных коллекций любого рода. Наконец, извините за то, что вы не являетесь опытным программистом C, чтобы удовлетворить вашу часть вопроса, связанную с C.

Другие вопросы по тегам