└── multix.rb /multix.rb: -------------------------------------------------------------------------------- 1 | require 'delegate' 2 | 3 | class Multix 4 | class Node < SimpleDelegator 5 | def initialize(o) 6 | super(o) 7 | end 8 | 9 | def _iterators 10 | @iterators ||= {} 11 | end 12 | 13 | def succ(key = :seq) 14 | @iterators[key].succ 15 | end 16 | alias :next :succ 17 | 18 | def prev(key = :seq) 19 | @iterators[key].prev 20 | end 21 | end 22 | 23 | def initialize(*indexes) 24 | @indexes = {} 25 | indexes.each do |index| 26 | @indexes[index.key] = index 27 | end 28 | end 29 | 30 | def by(key) 31 | @indexes[key].enum 32 | end 33 | 34 | def push(o) 35 | @indexes.each do |key, index| 36 | unless index.can_push?(o) 37 | return nil 38 | end 39 | end 40 | 41 | n = Node.new(o) 42 | @indexes.each do |key, index| 43 | index.push(n) 44 | end 45 | n 46 | end 47 | alias :<< :push 48 | 49 | def delete(n) 50 | @indexes.each do |key, index| 51 | index.delete(n) 52 | end 53 | end 54 | 55 | class Collection 56 | attr_reader :key 57 | 58 | def can_push?(o) 59 | true 60 | end 61 | end 62 | 63 | class Sequenced < Collection 64 | include Enumerable 65 | 66 | class Node 67 | attr_accessor :nxt, :prv, :o 68 | 69 | def initialize(o) 70 | @o = o 71 | end 72 | 73 | def succ 74 | nxt.o 75 | end 76 | 77 | def prev 78 | prv.o 79 | end 80 | end 81 | 82 | def initialize(key) 83 | @key = key 84 | @head = nil 85 | @tail = nil 86 | end 87 | 88 | def push(o) 89 | n = Node.new(o) 90 | o._iterators[@key] = n 91 | if @tail 92 | n.prv = @tail 93 | @tail.nxt = n 94 | @tail = n 95 | else 96 | @head = @tail = n 97 | end 98 | end 99 | 100 | def delete(o) 101 | n = o._iterators[@key] 102 | prv = n.prv 103 | nxt = n.nxt 104 | prv.nxt = nxt 105 | nxt.prv = prv 106 | end 107 | 108 | def enum 109 | self 110 | end 111 | 112 | def each 113 | n = @head 114 | while n 115 | yield n.o 116 | n = n.nxt 117 | end 118 | end 119 | end 120 | 121 | def self.sequenced(key = :seq) 122 | Sequenced.new(key) 123 | end 124 | 125 | class Hashed < Collection 126 | def initialize(key) 127 | @hash = Hash.new 128 | @key = key 129 | def self.push(o) 130 | @hash[o.send(@key)] = o 131 | end 132 | end 133 | 134 | def delete(o) 135 | @hash.delete(o.send(@key)) 136 | end 137 | 138 | def can_push?(o) 139 | !@hash.has_key?(o.send(@key)) 140 | end 141 | 142 | def enum 143 | @hash 144 | end 145 | end 146 | 147 | def self.hashed(key) 148 | Hashed.new(key) 149 | end 150 | 151 | class Ordered < Collection 152 | include Enumerable 153 | 154 | class Node 155 | attr_accessor :left, :right, :parent, :o 156 | 157 | def initialize(o) 158 | @o = o 159 | end 160 | 161 | def succ 162 | if @right 163 | c = @right 164 | while c.left 165 | c = c.left 166 | end 167 | else 168 | n = self 169 | c = @parent 170 | while c 171 | if n == c.left 172 | break 173 | end 174 | n = c 175 | c = n.parent 176 | end 177 | end 178 | c ? c.o : nil 179 | end 180 | 181 | def prev 182 | if @left 183 | c = @left 184 | while c.right 185 | c = c.right 186 | end 187 | else 188 | n = self 189 | c = @parent 190 | while c 191 | if n == c.right 192 | break 193 | end 194 | n = c 195 | c = n.parent 196 | end 197 | end 198 | c ? c.o : nil 199 | end 200 | end 201 | 202 | def initialize(key) 203 | @key = key 204 | @root = nil 205 | end 206 | 207 | def push(o) 208 | n = Node.new(o) 209 | o._iterators[@key] = n 210 | key = o.send(@key) 211 | if @root 212 | c = @root 213 | while true 214 | k = c.o.send(@key) 215 | if key < k 216 | if c.left 217 | c = c.left 218 | else 219 | c.left = n 220 | break 221 | end 222 | # For unique tree. 223 | #elsif key > k 224 | elsif key >= k 225 | if c.right 226 | c = c.right 227 | else 228 | c.right = n 229 | break 230 | end 231 | else 232 | # TODO 233 | return 234 | end 235 | end 236 | 237 | n.parent = c 238 | 239 | _splay(n) 240 | else 241 | @root = n 242 | end 243 | 244 | #begin 245 | # _validate 246 | #rescue 247 | # puts $! 248 | #end 249 | end 250 | 251 | def [](key) 252 | n = _fetch_node(key) 253 | n ? n.o : nil 254 | end 255 | 256 | def has_key?(key) 257 | n = _fetch_node(key) 258 | n != nil 259 | end 260 | 261 | def delete(o) 262 | n = o._iterators[@key] 263 | if n.left 264 | c = n.left 265 | if c.right 266 | while c.right 267 | c = c.right 268 | end 269 | 270 | _set_right(c.parent, c.left) 271 | _set_left(c, n.left) 272 | end 273 | _set_right(c, n.right) 274 | else 275 | c = n.right 276 | end 277 | 278 | _set_parent(c, n) 279 | if @root == n 280 | @root = c 281 | else 282 | _splay(c.parent) 283 | end 284 | end 285 | 286 | def enum 287 | self 288 | end 289 | 290 | def each 291 | n = @root 292 | while n.left 293 | n = n.left 294 | end 295 | 296 | st = :dr 297 | while n 298 | yield n.o 299 | 300 | while true 301 | #STDERR.puts "#{n.o.val} #{st}" 302 | 303 | case st 304 | when :up 305 | c = n 306 | n = n.parent 307 | unless n 308 | return 309 | end 310 | 311 | if c == n.left 312 | st = :dr 313 | break 314 | elsif c == n.right 315 | else 316 | raise 'internal error: broken tree' 317 | end 318 | when :dr 319 | if n.right 320 | n = n.right 321 | st = :dl 322 | else 323 | st = :up 324 | end 325 | when :dl 326 | if n.left 327 | n = n.left 328 | st = :dl 329 | else 330 | st = :dr 331 | break 332 | end 333 | end 334 | end 335 | end 336 | end 337 | 338 | if __FILE__ == $0 339 | def dump 340 | dump_node(@root, 0, 'X') 341 | end 342 | 343 | def dump_node(n, depth, type) 344 | return unless n 345 | puts " " * depth + type + n.o.to_s + "\t#{n.parent ? n.parent.o : 'nil'}" 346 | dump_node(n.left, depth + 1, 'L') 347 | dump_node(n.right, depth + 1, 'R') 348 | end 349 | end 350 | 351 | private 352 | 353 | def _validate 354 | raise 'validation failure' unless @root 355 | raise 'validation failure' if @root.parent 356 | _validate_node(@root) 357 | end 358 | 359 | def _validate_node(n) 360 | if n.left 361 | raise 'validation failure' if n.left.o.send(@key) > n.o.send(@key) 362 | raise 'validation failure' if n.left.parent != n 363 | _validate_node(n.left) 364 | end 365 | if n.right 366 | raise 'validation failure' if n.right.o.send(@key) < n.o.send(@key) 367 | raise 'validation failure' if n.right.parent != n 368 | _validate_node(n.right) 369 | end 370 | end 371 | 372 | def _fetch_node(key) 373 | c = @root 374 | unless c 375 | return nil 376 | end 377 | 378 | while true 379 | k = c.o.send(@key) 380 | if key < k 381 | if c.left 382 | c = c.left 383 | else 384 | _splay(c) 385 | return nil 386 | end 387 | elsif key > k 388 | if c.right 389 | c = c.right 390 | else 391 | _splay(c) 392 | return nil 393 | end 394 | else 395 | _splay(c) 396 | return c 397 | end 398 | end 399 | end 400 | 401 | def _set_parent(n, o, m = o.parent) 402 | if n 403 | n.parent = m 404 | end 405 | if m 406 | if m.left == o 407 | m.left = n 408 | elsif m.right == o 409 | m.right = n 410 | else 411 | raise 'internal error: broken tree' 412 | end 413 | end 414 | end 415 | 416 | def _set_left(n, c) 417 | n.left = c 418 | c.parent = n if c 419 | end 420 | 421 | def _set_right(n, c) 422 | n.right = c 423 | c.parent = n if c 424 | end 425 | 426 | def _splay(n) 427 | #until n == @root 428 | _splay_step(n) 429 | #end 430 | end 431 | 432 | def _splay_step(n) 433 | if @root == n 434 | return 435 | end 436 | 437 | m = n.parent 438 | if @root == m 439 | if m.left == n 440 | # zig 441 | _set_left(m, n.right) 442 | n.right = m 443 | elsif m.right == n 444 | # zag 445 | _set_right(m, n.left) 446 | n.left = m 447 | else 448 | raise 'TODO' 449 | end 450 | n.parent = m.parent 451 | m.parent = n 452 | @root = n 453 | else 454 | g = m.parent 455 | if m.left == n 456 | if g.left == m 457 | # zig-zig 458 | _set_left(g, m.right) 459 | m.right = g 460 | _set_left(m, n.right) 461 | n.right = m 462 | _set_parent(n, g) 463 | m.parent = n 464 | g.parent = m 465 | elsif g.right == m 466 | # zag-zig 467 | _set_left(m, n.right) 468 | _set_right(g, n.left) 469 | n.right = m 470 | n.left = g 471 | _set_parent(n, g) 472 | m.parent = n 473 | g.parent = n 474 | else 475 | raise 'TODO' 476 | end 477 | elsif m.right == n 478 | if g.left == m 479 | # zig-zag 480 | _set_right(m, n.left) 481 | _set_left(g, n.right) 482 | n.left = m 483 | n.right = g 484 | _set_parent(n, g) 485 | m.parent = n 486 | g.parent = n 487 | elsif g.right == m 488 | # zag-zag 489 | _set_right(g, m.left) 490 | m.left = g 491 | _set_right(m, n.left) 492 | n.left = m 493 | _set_parent(n, g) 494 | m.parent = n 495 | g.parent = m 496 | else 497 | raise 'TODO' 498 | end 499 | end 500 | 501 | unless n.parent 502 | @root = n 503 | end 504 | end 505 | end 506 | end 507 | 508 | def self.ordered(key) 509 | Ordered.new(key) 510 | end 511 | end 512 | 513 | def Multix(*a) 514 | Multix.new(*a) 515 | end 516 | 517 | if __FILE__ == $0 518 | 519 | require 'test/unit' 520 | 521 | class TestMultix < Test::Unit::TestCase 522 | 523 | class Presen 524 | attr_accessor :twitter_id, :hatena_id, :title 525 | def initialize(twitter_id, hatena_id, title) 526 | @twitter_id = twitter_id 527 | @hatena_id = hatena_id 528 | @title = title 529 | end 530 | end 531 | 532 | def test_multix 533 | m = Multix(Multix.sequenced, 534 | Multix.ordered(:twitter_id), 535 | Multix.hashed(:hatena_id)) 536 | m.push(Presen.new('cpp_akira', 'faith_and_brave', 'Boost issyuu')) 537 | m.push(Presen.new('kinaba', 'cafelier', 'Boost.MultiIntrusivedex')) 538 | foo = m.push(Presen.new('foo', 'bar', 'baz')) 539 | m.push(Presen.new('melponn', 'melpon', 'Boost.Coroutine')) 540 | 541 | assert_equal('foo', foo.twitter_id) 542 | 543 | assert_equal('faith_and_brave', m.by(:twitter_id)['cpp_akira'].hatena_id) 544 | assert_equal('kinaba', m.by(:hatena_id)['cafelier'].twitter_id) 545 | 546 | assert_equal('baz', m.by(:twitter_id)['foo'].title) 547 | assert_equal('baz', m.by(:hatena_id)['bar'].title) 548 | assert_equal('baz', m.by(:seq).to_a[2].title) 549 | 550 | foo = m.by(:twitter_id)['foo'] 551 | succ = foo.succ(:seq) 552 | m.delete(foo) 553 | # Deleted element. 554 | assert_nil(m.by(:twitter_id)['foo']) 555 | assert_nil(m.by(:hatena_id)['bar']) 556 | assert_equal('Boost.Coroutine', m.by(:seq).to_a[2].title) 557 | 558 | assert_equal('melponn', succ.twitter_id) 559 | 560 | assert_not_nil(m.push(Presen.new('foo', 'bar', 'baz'))) 561 | assert_nil(m.push(Presen.new('foo', 'bar', 'baz'))) 562 | assert_nil(m.push(Presen.new('foo2', 'bar', 'baz2'))) 563 | assert_not_nil(m.push(Presen.new('foo', 'bar2', 'baz2'))) 564 | 565 | a = m.by(:hatena_id).map{|k, o|o.twitter_id} 566 | b = m.by(:twitter_id).map{|o|o.twitter_id} 567 | assert_equal(a.size, b.size) 568 | assert_equal(a.sort, b) 569 | assert_equal(["cpp_akira", "foo", "foo", "kinaba", "melponn"], b) 570 | 571 | kinaba = m.by(:twitter_id)['kinaba'] 572 | melponn = kinaba.succ(:twitter_id) 573 | assert_equal('melponn', melponn.twitter_id) 574 | end 575 | 576 | class Num 577 | attr_accessor :val 578 | 579 | def initialize(v) 580 | @val = v 581 | end 582 | 583 | def to_s 584 | @val.to_s 585 | end 586 | 587 | def inspect 588 | @val.inspect 589 | end 590 | end 591 | 592 | def test_ordered 593 | num = 100 594 | 595 | m = Multix(Multix.ordered(:val)) 596 | (0..num).sort_by{rand}.each do |v| 597 | m.push(Num.new(v)) 598 | 599 | #puts 600 | #m.by(:val).dump 601 | end 602 | 603 | #m.by(:val).dump 604 | 605 | m.by(:val).each_with_index do |v, i| 606 | assert_equal(i, v.val) 607 | end 608 | 609 | num.times do |i| 610 | assert_equal(i, m.by(:val)[i].val) 611 | end 612 | #m.by(:val).dump 613 | (0...num).sort_by{rand}.each do |i| 614 | assert_equal(i, m.by(:val)[i].val) 615 | end 616 | 617 | #m.by(:val).dump 618 | m.delete(m.by(:val)[num]) 619 | #m.by(:val).dump 620 | assert_nil(m.by(:val)[num]) 621 | 622 | (num/2...num).sort_by{rand}.each do |v| 623 | #p v 624 | #m.by(:val).dump 625 | m.delete(m.by(:val)[v]) 626 | end 627 | 628 | a = m.by(:val).map{|v|v.val} 629 | assert_equal(num / 2, a.size) 630 | (num/2).times do |i| 631 | assert_equal(i, a[i]) 632 | end 633 | 634 | b = [] 635 | iter = m.by(:val)[0] 636 | assert_not_nil(iter) 637 | assert_nil(iter.prev(:val)) 638 | while iter 639 | b << iter.val 640 | iter = iter.succ(:val) 641 | end 642 | assert_equal(a, b) 643 | 644 | c = [] 645 | iter = m.by(:val)[num/2-1] 646 | assert_not_nil(iter) 647 | assert_nil(iter.succ(:val)) 648 | while iter 649 | c << iter.val 650 | iter = iter.prev(:val) 651 | end 652 | assert_equal(a, c.reverse) 653 | 654 | (num/2).times do |i| 655 | assert_equal(i, m.push(Num.new(i)).val) 656 | end 657 | 658 | a = m.by(:val).to_a 659 | assert_equal(num, a.size) 660 | num.times do |i| 661 | assert_equal(i / 2, a[i].val) 662 | end 663 | end 664 | end 665 | end 666 | --------------------------------------------------------------------------------