# -*- coding: utf-8 -*- ########################################################################################## # Copyright © 2013 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify, # and distribute this software and its documentation, without fee and without a signed # licensing agreement, is hereby granted, provided that the above copyright notice, this # paragraph and the following two paragraphs appear in all copies, modifications, and # distributions. # # IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, # INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF # THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE # SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". # RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, # OR MODIFICATIONS. ########################################################################################## class MDArray #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def get_current_index @local_iterator.get_current_index end #------------------------------------------------------------------------------------ # Returns the next element of the local_iterator or nil if no next element available #------------------------------------------------------------------------------------ def next if (@local_iterator && @local_iterator.has_next?) @local_iterator.get_next else nil end end #------------------------------------------------------------------------------------ # When get is used to retrieve an element, it is assumed that the index does not need # correction, for instance, no negative index is allowed. If one wants to use # negative indexes, then method [] should be used. So mat.get([-1, 0, 0]) raises an # exception while mat[-1, 0, 0] gets the last value for the first dimension. #------------------------------------------------------------------------------------ def [](*index) if (index.size != 0) @local_index[*index] elsif (@local_iterator) @local_iterator.get_current else raise "No iterator defined! Cannot get element" end end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def get(index = nil) @local_index.get(index) end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def jget(index = nil) @local_index.jget(index) end #------------------------------------------------------------------------------------ # Gets the next element of the local iterator #------------------------------------------------------------------------------------ def get_next if (@local_iterator) @local_iterator.get_next else raise "No iterator defined! Cannot get next element" end end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def []=(*index, value) if (index.size != 0) @local_index[index] = value elsif (@local_iterator) @local_iterator.set_current(value) else raise "No iterator defined! Cannot set element value" end end #--------------------------------------------------------------------------------------- # When set is used to assign to an element, it is assumed that the index does not need # correction, for instance, no negative index is allowed. If one wants to use # negative indexes, then method [] should be used. So mat.set([-1, 0, 0], 10), raises # an exection while mat[-1, 0, 0] = 10 sets the last value for the first dimension. # *index: array with the index position # *value: value to be set #--------------------------------------------------------------------------------------- def set(index, value) @local_index.set(index, value) end #--------------------------------------------------------------------------------------- # #--------------------------------------------------------------------------------------- def set_next(value) if (@local_iterator) @local_iterator.set_next(value) else raise "No iterator defined! Cannot set element value" end end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def get_counter Counter.new(self) end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def reset_traversal @local_iterator = get_iterator_fast end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ def each iterator = get_iterator_fast while (iterator.has_next?) yield iterator.get_next if block_given? end end # (1) Each creates a new iterator and does not touch the @local_iterator so that # one should be able to call each from different threads. Still, should be careful # if another thread adds or removes elements from the array. Needs to check what # happens in this situation #------------------------------------------------------------------------------------ # Cycles through the whole list of elements yielding to a block (if given) the next # element and its index. The index is a ruby array. #------------------------------------------------------------------------------------ def each_with_counter iterator = get_iterator_fast while (iterator.has_next?) yield iterator.get_next, iterator.get_current_counter if block_given? end end #------------------------------------------------------------------------------------ # Continues a each from the position the @local_iterator is in. each_cont cannot be # called from multiple threads as there is only one @local_iterator. #------------------------------------------------------------------------------------ def each_cont while (elmt = self.next) yield elmt if block_given? end end #------------------------------------------------------------------------------------ # #------------------------------------------------------------------------------------ private #------------------------------------------------------------------------------------ # Cycles through the whole list of elements yielding to a block (if given) the next # element and its iterator. Was made private so that users do not need to know about # iterator. Giving iterator could be a speed up usefule for final users concerned # about performance. #------------------------------------------------------------------------------------ def each_with_iterator iterator = get_iterator_fast while (iterator.has_next?) yield iterator.get_next, iterator if block_given? end end end