1 # Protocol Buffers - Google's data interchange format 2 # Copyright 2008 Google Inc. All rights reserved. 3 # https://developers.google.com/protocol-buffers/ 4 # 5 # Redistribution and use in source and binary forms, with or without 6 # modification, are permitted provided that the following conditions are 7 # met: 8 # 9 # * Redistributions of source code must retain the above copyright 10 # notice, this list of conditions and the following disclaimer. 11 # * Redistributions in binary form must reproduce the above 12 # copyright notice, this list of conditions and the following disclaimer 13 # in the documentation and/or other materials provided with the 14 # distribution. 15 # * Neither the name of Google Inc. nor the names of its 16 # contributors may be used to endorse or promote products derived from 17 # this software without specific prior written permission. 18 # 19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 require 'forwardable' 32 33 # 34 # This class makes RepeatedField act (almost-) like a Ruby Array. 35 # It has convenience methods that extend the core C or Java based 36 # methods. 37 # 38 # This is a best-effort to mirror Array behavior. Two comments: 39 # 1) patches always welcome :) 40 # 2) if performance is an issue, feel free to rewrite the method 41 # in jruby and C. The source code has plenty of examples 42 # 43 # KNOWN ISSUES 44 # - #[]= doesn't allow less used approaches such as `arr[1, 2] = 'fizz'` 45 # - #concat should return the orig array 46 # - #push should accept multiple arguments and push them all at the same time 47 # 48 module Google 49 module Protobuf 50 class RepeatedField 51 extend Forwardable 52 53 # methods defined in C or Java: 54 # + 55 # [], at 56 # []= 57 # concat 58 # clear 59 # dup, clone 60 # each 61 # push, << 62 # replace 63 # length, size 64 # == 65 # to_ary, to_a 66 # also all enumerable 67 # 68 # NOTE: using delegators rather than method_missing to make the 69 # relationship explicit instead of implicit 70 def_delegators :to_ary, 71 :&, :*, :-, :'<=>', 72 :assoc, :bsearch, :bsearch_index, :combination, :compact, :count, 73 :cycle, :dig, :drop, :drop_while, :eql?, :fetch, :find_index, :flatten, 74 :include?, :index, :inspect, :join, 75 :pack, :permutation, :product, :pretty_print, :pretty_print_cycle, 76 :rassoc, :repeated_combination, :repeated_permutation, :reverse, 77 :rindex, :rotate, :sample, :shuffle, :shelljoin, :slice, 78 :to_s, :transpose, :uniq, :| 79 80 81 def first(n=nil) 82 n ? self[0..n] : self[0] 83 end 84 85 86 def last(n=nil) 87 n ? self[(self.size-n-1)..-1] : self[-1] 88 end 89 90 91 def pop(n=nil) 92 if n 93 results = [] 94 n.times{ results << pop_one } 95 return results 96 else 97 return pop_one 98 end 99 end 100 101 102 def empty? 103 self.size == 0 104 end 105 106 # array aliases into enumerable 107 alias_method :each_index, :each_with_index 108 alias_method :slice, :[] 109 alias_method :values_at, :select 110 alias_method :map, :collect 111 112 113 class << self 114 def define_array_wrapper_method(method_name) 115 define_method(method_name) do |*args, &block| 116 arr = self.to_a 117 result = arr.send(method_name, *args) 118 self.replace(arr) 119 return result if result 120 return block ? block.call : result 121 end 122 end 123 private :define_array_wrapper_method 124 125 126 def define_array_wrapper_with_result_method(method_name) 127 define_method(method_name) do |*args, &block| 128 # result can be an Enumerator, Array, or nil 129 # Enumerator can sometimes be returned if a block is an optional argument and it is not passed in 130 # nil usually specifies that no change was made 131 result = self.to_a.send(method_name, *args, &block) 132 if result 133 new_arr = result.to_a 134 self.replace(new_arr) 135 if result.is_a?(Enumerator) 136 # generate a fresh enum; rewinding the exiting one, in Ruby 2.2, will 137 # reset the enum with the same length, but all the #next calls will 138 # return nil 139 result = new_arr.to_enum 140 # generate a wrapper enum so any changes which occur by a chained 141 # enum can be captured 142 ie = ProxyingEnumerator.new(self, result) 143 result = ie.to_enum 144 end 145 end 146 result 147 end 148 end 149 private :define_array_wrapper_with_result_method 150 end 151 152 153 %w(delete delete_at delete_if shift slice! unshift).each do |method_name| 154 define_array_wrapper_method(method_name) 155 end 156 157 158 %w(collect! compact! fill flatten! insert reverse! 159 rotate! select! shuffle! sort! sort_by! uniq!).each do |method_name| 160 define_array_wrapper_with_result_method(method_name) 161 end 162 alias_method :keep_if, :select! 163 alias_method :map!, :collect! 164 alias_method :reject!, :delete_if 165 166 167 # propagates changes made by user of enumerator back to the original repeated field. 168 # This only applies in cases where the calling function which created the enumerator, 169 # such as #sort!, modifies itself rather than a new array, such as #sort 170 class ProxyingEnumerator < Struct.new(:repeated_field, :external_enumerator) 171 def each(*args, &block) 172 results = [] 173 external_enumerator.each_with_index do |val, i| 174 result = yield(val) 175 results << result 176 #nil means no change occured from yield; usually occurs when #to_a is called 177 if result 178 repeated_field[i] = result if result != val 179 end 180 end 181 results 182 end 183 end 184 185 186 end 187 end 188 end 189