2016-04-16 8 views
1

У меня есть цикл обработки, которому нужен указатель на большую таблицу поиска. Указатель, к сожалению, непрямо косвенен из исходных данных, поэтому сохранение этого указателя для внутреннего цикла имеет важное значение для производительности.Могу ли я восстановить заимствование локального в цикле?

Есть ли какой-либо способ, которым я могу сказать, что я "unborrowing" переменную состояния в маловероятном случае мне нужно изменить состояние ... поэтому я могу только повторно просмотреть срез в том случае, если срабатывает функция modify_state?

Одно из решений, о которых я думал, заключалось в том, чтобы изменить данные как ссылку на срез и сделать mem::replace в структуре в начале функции и вытащить фрагмент в локальную область, а затем заменить его обратно в конце функции - но это очень хрупкое и подверженное ошибкам (как мне нужно помнить, чтобы заменить элемент на каждый возврат). Есть ли другой способ сделать это?

struct DoubleIndirect { 
    data: [u8; 512 * 512], 
    lut: [usize; 16384], 
    lut_index: usize, 
} 

#[cold] 
fn modify_state(s: &mut DoubleIndirect) { 
    s.lut_index += 63; 
    s.lut_index %= 16384; 
} 

fn process(state: &mut DoubleIndirect) -> [u8; 65536] { 
    let mut ret: [u8; 65536] = [0; 65536]; 
    let mut count = 0; 
    let mut data_slice = &state.data[state.lut[state.lut_index]..]; 
    for ret_item in ret.iter_mut() { 
     *ret_item = data_slice[count]; 
     if count % 197 == 196 { 
      data_slice = &[]; 
      modify_state(state); 
      data_slice = &state.data[state.lut[state.lut_index]..]; 
     } 
     count += 1 
    } 
    return ret; 
} 
+0

Можете ли вы просто передать '& mut state.lut_index' значение' modify_state'? –

+0

Код о упрощении ... изменение состояния вызывает тонны помощников – hellcatv

ответ

3

Самый простой способ сделать это, чтобы обеспечить заимствует из state все непересекающиеся:

#[cold] 
fn modify_state(lut_index: &mut usize) { 
    *lut_index += 63; 
    *lut_index %= 16384; 
} 

fn process(state: &mut DoubleIndirect) -> [u8; 65536] { 
    let mut ret: [u8; 65536] = [0; 65536]; 
    let mut count = 0; 
    let mut lut_index = &mut state.lut_index; 
    let mut data_slice = &state.data[state.lut[*lut_index]..]; 
    for ret_item in ret.iter_mut() { 
     *ret_item = data_slice[count]; 
     if count % 197 == 196 { 
      modify_state(lut_index); 
      data_slice = &state.data[state.lut[*lut_index]..]; 
     } 
     count += 1 
    } 
    return ret; 
} 

Проблема состоит в основном две вещи: во-первых, Rust не будет взгляд за подписью функция в чтобы узнать, что он делает. Насколько компилятор знает, ваш звонок modify_state также может меняться state.data, и он не может этого допустить.

Вторая проблема заключается в том, что заимствования: lexical; компилятор просматривает блок кода, где может использоваться . Он (в настоящее время) не пытается попытаться уменьшить длину заимствований, чтобы они соответствовали тому, где они находятся фактически активно.

Вы также можете играть в игры, используя, например, std::mem::replace, чтобы вытащить state.data в локальную переменную, сделайте свою работу, затем replace верните ее прямо перед тем, как вы вернетесь.

+0

Есть ли способ сделать std :: mem :: replace в блоке try/finally-sort (возможно, используя RAII)? Настоящий код, с которым я работаю, имеет массу возвратов во всем мире? – hellcatv

+1

@hellcatv Не совсем: это означало бы, что сфера охвата будет изменчивым заимствованием 'DoubleIndirect' и, * oh look *, вы снова вернетесь к исходной проблеме. Вы можете обернуть часть функции «много возвратов» внутри закрытия, что позволит вам «ловушку» вернуть. –

+0

Я решил это решить, отбросив части состояния, которые были изменены в функции modify_state, и поместив их в отдельную структуру, которая была членом моей государственной структуры. – hellcatv