From: Ari Brown Date: 2007-09-07T07:34:07+09:00 Subject: Re: [QUIZ] Twisting a Rope (#137) --Apple-Mail-1-357442536 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed Nyah!!!! Here it is. I tried to keep this sort of normalish, and each leaf(?) has a base limit of 15 characters. This makes searching for a specific character at a lengthy location pretty quick (i hope), however, my slice method uses a very unorthodox method, and I am BEGGING for help in making it better. I want to start using my Rope implementation regularly (for kicks), but am also hoping it can be fast. I envy Mahurin's speed. --Apple-Mail-1-357442536 Content-Transfer-Encoding: 7bit Content-Type: text/x-ruby-script; x-unix-mode=0644; name=rope.rb Content-Disposition: attachment; filename=rope.rb #!/usr/local/bin/ruby # # Created by me on 2007-09-05. # Copyright (c) 2007. All pwnage reserved. class String alias_method(:old_plus, :+) def +(other) self + other.to_s if other.is_a? Rope self.old_plus(other) end def to_rope Rope.new(self) end alias_method(:to_r, :to_rope) end class Rope attr_reader :strands attr_reader :length attr_reader :depth attr_reader :segments def initialize(strand, chunk_size=15) CHUNK_SIZE = chunk_size raise "What are you doing?!" if strands.nil? strand = strand.to_s if strands.is_a? Integer @strands = check_size(strand) @depth = 1 @segments = 0 calc_info end def update(&b) instance_eval(b) calc_info conform end def calc_info @strands.each { |s| @length += s.length } @strands.each { |s| @depth += s.depth if s.is_a? Rope} @strands.each { |s| @segments += 1} end def check_size(strand) return if strand.nil? if strand.size > CHUNK_SIZE start, finish = 0, (-CHUNK_SIZE + 1) strands = [] until strand[start] == nil strands << strand.slice(start, CHUNK_SIZE) start = finish finish += CHUNK_SIZE end puts strands return strands end return [strand] end def conform @strands = check_size(to_s) end def append(*strings) update do raise "What are you doing?!" if strings.nil? strings.each { |s| @strands << s} end end alias_method(:<<, :append) def prepend(*strings) update do old_strands = @strands strings.each { |s| s = s.to_s if s.is_a? Integer @strands = s } @strands << old_strands end end def flatten old_strands, @strands = @strands, [] update do @strands.each do |s| if s.is_a? Rope s.strands.map { |s| @strands << s } elsif not s.nil? @strands << s end end end self end def +(other) update do if other.is_a? Rope @strands += other.strands elsif not other.nil? @strands += other.to_s end end end alias_method(:add, :+) alias_method(:push, :+) def to_s case @strands when 0: "" else return (@strands * "") end end def slice(here, length=nil) begin return nil if here < 0 || here > self.length return to_s.slice(start, length||0) if here.is_a? Regexp location = here%CHUNK_SIZE car = here/CHUNK_SIZE left = start ret = "" if here < 0 || here > self.length nil elsif !length @segments.detect { |s| (start -= s.length) < 0 }.slice(start) elsif true while @strands[car] thing = @strands[car][0..-1] thing.each_byte { |l| ret << l.chr left -= 1 return ret if left == 0 } car += 1 if left != 0 end end rescue to_s.slice(here, length) end end def [](here, length) if !length && start.is_a? Range length = here.last - here.first - (exclude_end? ? 1 : 0) here = here.first end self.slice(here, length) self.slice(here, length) end def at(here) location = here%CHUNK_SIZE car = here/CHUNK_SIZE train_car = @strands[car] return train_car[location].chr end def method_missing(m, *args, &block) if "".responds_to?(m) && m =~ /^string_(.+)/ ret = to_s.__send__($1, *args, &block) if ret.is_a? String ret = Rope.new(ret) end end ret end end --Apple-Mail-1-357442536 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed ---------------------------------------------------------------| ~Ari "I don't suffer from insanity. I enjoy every minute of it" --1337est man alive --Apple-Mail-1-357442536--