d_heap 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -0
- data/Gemfile.lock +10 -1
- data/README.md +42 -41
- data/d_heap.gemspec +2 -0
- data/ext/d_heap/d_heap.c +283 -176
- data/ext/d_heap/d_heap.h +11 -35
- data/ext/d_heap/extconf.rb +2 -0
- data/lib/d_heap/version.rb +1 -1
- metadata +17 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5a20fe814944fa8945bc2cc0ce87f810c8bf8d21102b8c454ae5d639f0548576
         | 
| 4 | 
            +
              data.tar.gz: 65a1af345ae84c7f6e5da8af89a00730ffc4cbdb6bb2cac59461c3728eb0ad28
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 27c240634013397033925ee258de08135587c31c7a046a902c028842680dadec20e2ccc0f76570e6f7db34d2292e5dae2ae7d17449436f890498697de4352c91
         | 
| 7 | 
            +
              data.tar.gz: 8eb2cba120747cc7788c42f264d2109ef1afee8a28caa7effb8bcb1ff36ed7c99a0556b48b7d9e9479f6e8be8945eea3bf1ddb7f608c13c63252684643154179
         | 
    
        data/.rubocop.yml
    CHANGED
    
    | @@ -44,6 +44,7 @@ Layout/EmptyLineBetweenDefs: | |
| 44 44 | 
             
            Layout/EmptyLinesAroundAttributeAccessor:
         | 
| 45 45 | 
             
              inherit_mode:
         | 
| 46 46 | 
             
                merge:
         | 
| 47 | 
            +
                  - Exclude
         | 
| 47 48 | 
             
                  - AllowedMethods
         | 
| 48 49 | 
             
              Enabled: true
         | 
| 49 50 | 
             
              AllowedMethods:
         | 
| @@ -139,8 +140,17 @@ Style/TernaryParentheses: | |
| 139 140 | 
             
              Enabled: false
         | 
| 140 141 |  | 
| 141 142 | 
             
            Style/BlockDelimiters:
         | 
| 143 | 
            +
              inherit_mode:
         | 
| 144 | 
            +
                merge:
         | 
| 145 | 
            +
                  - Exclude
         | 
| 146 | 
            +
                  - ProceduralMethods
         | 
| 147 | 
            +
                  - IgnoredMethods
         | 
| 148 | 
            +
                  - FunctionalMethods
         | 
| 142 149 | 
             
              EnforcedStyle: semantic
         | 
| 143 150 | 
             
              AllowBracesOnProceduralOneLiners: true
         | 
| 151 | 
            +
              IgnoredMethods:
         | 
| 152 | 
            +
                - expect
         | 
| 153 | 
            +
             | 
| 144 154 |  | 
| 145 155 | 
             
            Style/FormatString:
         | 
| 146 156 | 
             
              EnforcedStyle: percent
         | 
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,12 +1,15 @@ | |
| 1 1 | 
             
            PATH
         | 
| 2 2 | 
             
              remote: .
         | 
| 3 3 | 
             
              specs:
         | 
| 4 | 
            -
                d_heap (0. | 
| 4 | 
            +
                d_heap (0.3.0)
         | 
| 5 5 |  | 
| 6 6 | 
             
            GEM
         | 
| 7 7 | 
             
              remote: https://rubygems.org/
         | 
| 8 8 | 
             
              specs:
         | 
| 9 9 | 
             
                ast (2.4.1)
         | 
| 10 | 
            +
                benchmark-malloc (0.2.0)
         | 
| 11 | 
            +
                benchmark-perf (0.6.0)
         | 
| 12 | 
            +
                benchmark-trend (0.4.0)
         | 
| 10 13 | 
             
                diff-lcs (1.4.4)
         | 
| 11 14 | 
             
                parallel (1.19.2)
         | 
| 12 15 | 
             
                parser (2.7.2.0)
         | 
| @@ -21,6 +24,11 @@ GEM | |
| 21 24 | 
             
                  rspec-core (~> 3.10.0)
         | 
| 22 25 | 
             
                  rspec-expectations (~> 3.10.0)
         | 
| 23 26 | 
             
                  rspec-mocks (~> 3.10.0)
         | 
| 27 | 
            +
                rspec-benchmark (0.6.0)
         | 
| 28 | 
            +
                  benchmark-malloc (~> 0.2)
         | 
| 29 | 
            +
                  benchmark-perf (~> 0.6)
         | 
| 30 | 
            +
                  benchmark-trend (~> 0.4)
         | 
| 31 | 
            +
                  rspec (>= 3.0)
         | 
| 24 32 | 
             
                rspec-core (3.10.0)
         | 
| 25 33 | 
             
                  rspec-support (~> 3.10.0)
         | 
| 26 34 | 
             
                rspec-expectations (3.10.0)
         | 
| @@ -52,6 +60,7 @@ DEPENDENCIES | |
| 52 60 | 
             
              rake (~> 13.0)
         | 
| 53 61 | 
             
              rake-compiler
         | 
| 54 62 | 
             
              rspec (~> 3.10)
         | 
| 63 | 
            +
              rspec-benchmark
         | 
| 55 64 | 
             
              rubocop (~> 1.0)
         | 
| 56 65 |  | 
| 57 66 | 
             
            BUNDLED WITH
         | 
    
        data/README.md
    CHANGED
    
    | @@ -14,6 +14,48 @@ worst-case time complexity. In the worst case, a _d_-ary heap requires only | |
| 14 14 | 
             
            Although you should probably just stick with the default _d_ value  of `4`, it
         | 
| 15 15 | 
             
            may be worthwhile to benchmark your specific scenario.
         | 
| 16 16 |  | 
| 17 | 
            +
            ## Usage
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            The simplest way to use it is simply with `#push` and `#pop`.  Push takes a
         | 
| 20 | 
            +
            score and a value, and pop returns the value with the current minimum score.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ```ruby
         | 
| 23 | 
            +
            require "d_heap"
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            heap = DHeap.new # defaults to a 4-ary heap
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            # storing [score, value] tuples
         | 
| 28 | 
            +
            heap.push Time.now + 5*60, Task.new(1)
         | 
| 29 | 
            +
            heap.push Time.now +   30, Task.new(2)
         | 
| 30 | 
            +
            heap.push Time.now +   60, Task.new(3)
         | 
| 31 | 
            +
            heap.push Time.now +    5, Task.new(4)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            # peeking and popping (using last to get the task and ignore the time)
         | 
| 34 | 
            +
            heap.pop.last  # => Task[4]
         | 
| 35 | 
            +
            heap.pop.last  # => Task[2]
         | 
| 36 | 
            +
            heap.peak.last # => Task[3], but don't pop it
         | 
| 37 | 
            +
            heap.pop.last  # => Task[3]
         | 
| 38 | 
            +
            heap.pop.last  # => Task[1]
         | 
| 39 | 
            +
            ```
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            Read the `rdoc` for more detailed documentation and examples.
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            ## Installation
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            Add this line to your application's Gemfile:
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            ```ruby
         | 
| 48 | 
            +
            gem 'd_heap'
         | 
| 49 | 
            +
            ```
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            And then execute:
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                $ bundle install
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            Or install it yourself as:
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                $ gem install d_heap
         | 
| 58 | 
            +
             | 
| 17 59 | 
             
            ## Motivation
         | 
| 18 60 |  | 
| 19 61 | 
             
            Sometimes you just need a priority queue, right?  With a regular queue, you
         | 
| @@ -49,47 +91,6 @@ unnecessary.  This is definitely hotspot code, and the basic ruby implementation | |
| 49 91 | 
             
            would work fine, if not for that `<=>` overhead.  Until then... this gem gets
         | 
| 50 92 | 
             
            the job done.
         | 
| 51 93 |  | 
| 52 | 
            -
            ## Installation
         | 
| 53 | 
            -
             | 
| 54 | 
            -
            Add this line to your application's Gemfile:
         | 
| 55 | 
            -
             | 
| 56 | 
            -
            ```ruby
         | 
| 57 | 
            -
            gem 'd_heap'
         | 
| 58 | 
            -
            ```
         | 
| 59 | 
            -
             | 
| 60 | 
            -
            And then execute:
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                $ bundle install
         | 
| 63 | 
            -
             | 
| 64 | 
            -
            Or install it yourself as:
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                $ gem install d_heap
         | 
| 67 | 
            -
             | 
| 68 | 
            -
            ## Usage
         | 
| 69 | 
            -
             | 
| 70 | 
            -
            The simplest way to use it is simply with `#push` and `#pop`.  Push will 
         | 
| 71 | 
            -
             | 
| 72 | 
            -
            ```ruby
         | 
| 73 | 
            -
            require "d_heap"
         | 
| 74 | 
            -
             | 
| 75 | 
            -
            heap = DHeap.new # defaults to a 4-ary heap
         | 
| 76 | 
            -
             | 
| 77 | 
            -
            # storing [time, task] tuples
         | 
| 78 | 
            -
            heap << [Time.now + 5*60, Task.new(1)]
         | 
| 79 | 
            -
            heap << [Time.now +   30, Task.new(2)]
         | 
| 80 | 
            -
            heap << [Time.now +   60, Task.new(3)]
         | 
| 81 | 
            -
            heap << [Time.now +    5, Task.new(4)]
         | 
| 82 | 
            -
             | 
| 83 | 
            -
            # peeking and popping (using last to get the task and ignore the time)
         | 
| 84 | 
            -
            heap.pop.last # => Task[4]
         | 
| 85 | 
            -
            heap.pop.last # => Task[2]
         | 
| 86 | 
            -
            heap.peak.last # => Task[3]
         | 
| 87 | 
            -
            heap.pop.last # => Task[3]
         | 
| 88 | 
            -
            heap.pop.last # => Task[1]
         | 
| 89 | 
            -
            ```
         | 
| 90 | 
            -
             | 
| 91 | 
            -
            Read the `rdoc` for more detailed documentation and examples.
         | 
| 92 | 
            -
             | 
| 93 94 | 
             
            ## TODOs...
         | 
| 94 95 |  | 
| 95 96 | 
             
            _TODO:_ In addition to a basic _d_-ary heap class (`DHeap`), this library
         | 
    
        data/d_heap.gemspec
    CHANGED
    
    
    
        data/ext/d_heap/d_heap.c
    CHANGED
    
    | @@ -1,27 +1,29 @@ | |
| 1 1 | 
             
            #include "d_heap.h"
         | 
| 2 2 |  | 
| 3 | 
            -
            ID  | 
| 3 | 
            +
            ID id_cmp; // <=>
         | 
| 4 | 
            +
            ID id_ivar_values;
         | 
| 5 | 
            +
            ID id_ivar_scores;
         | 
| 4 6 | 
             
            ID id_ivar_d;
         | 
| 5 7 |  | 
| 6 | 
            -
            #define  | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
            #define  | 
| 10 | 
            -
            #define  | 
| 11 | 
            -
             | 
| 12 | 
            -
            #define  | 
| 13 | 
            -
            #define  | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
                 | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 8 | 
            +
            #define Get_DHeap(hobj, hstruct) ((hstruct) = get_dheap_struct(hobj))
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            #define DHEAP_IDX_LAST(heap) (DHEAP_SIZE(heap) - 1)
         | 
| 11 | 
            +
            #define DHEAP_IDX_PARENT(heap, idx) ((idx - 1) / heap->d)
         | 
| 12 | 
            +
            #define DHEAP_IDX_CHILD0(heap, idx) ((idx * heap->d) + 1)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            #define DHEAP_SIZE(heap) (RARRAY_LEN((heap)->scores))
         | 
| 15 | 
            +
            #define DHEAP_VALUE(heap, idx) RARRAY_AREF((heap)->values, idx)
         | 
| 16 | 
            +
            #define DHEAP_SCORE(heap, idx) RARRAY_AREF((heap)->scores, idx)
         | 
| 17 | 
            +
            #define DHEAP_ASSIGN(heap, idx, scr, val) \
         | 
| 18 | 
            +
                rb_ary_store(heap->scores, idx, scr); \
         | 
| 19 | 
            +
                rb_ary_store(heap->values, idx, val);
         | 
| 20 | 
            +
            #define DHEAP_APPEND(heap, scr, val) \
         | 
| 21 | 
            +
                rb_ary_push((heap)->scores, scr); \
         | 
| 22 | 
            +
                rb_ary_push((heap)->values, val);
         | 
| 23 | 
            +
            #define DHEAP_DROP_LAST(heap) ( \
         | 
| 24 | 
            +
                    rb_ary_pop(heap->scores), \
         | 
| 25 | 
            +
                    rb_ary_pop(heap->values) \
         | 
| 22 26 | 
             
                ) // score, value
         | 
| 23 | 
            -
            #define IDX_PARENT(idx) ((idx - 1) / d)
         | 
| 24 | 
            -
            #define IDX_CHILD0(idx) ((idx * d) + 1)
         | 
| 25 27 |  | 
| 26 28 | 
             
            #define DHEAP_Check_d_size(d) \
         | 
| 27 29 | 
             
                if (d < 2) { \
         | 
| @@ -31,64 +33,219 @@ ID id_ivar_d; | |
| 31 33 | 
             
                    rb_raise(rb_eArgError, "DHeap d=%d is too large", d); \
         | 
| 32 34 | 
             
                }
         | 
| 33 35 |  | 
| 34 | 
            -
            #define  | 
| 35 | 
            -
                if ( | 
| 36 | 
            -
                    rb_raise(rb_eIndexError, " | 
| 36 | 
            +
            #define DHEAP_Check_Index(index, last_index) \
         | 
| 37 | 
            +
                if (index < 0) { \
         | 
| 38 | 
            +
                    rb_raise(rb_eIndexError, "DHeap index %ld too small", index); \
         | 
| 37 39 | 
             
                } \
         | 
| 38 | 
            -
                else if (last_index <  | 
| 39 | 
            -
                    rb_raise(rb_eIndexError, " | 
| 40 | 
            +
                else if (last_index < index) { \
         | 
| 41 | 
            +
                    rb_raise(rb_eIndexError, "DHeap index %ld too large", index); \
         | 
| 40 42 | 
             
                }
         | 
| 41 43 |  | 
| 42 | 
            -
             | 
| 43 | 
            -
                 | 
| 44 | 
            -
                 | 
| 45 | 
            -
                 | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 44 | 
            +
            struct dheap_struct {
         | 
| 45 | 
            +
                int d;
         | 
| 46 | 
            +
                VALUE scores;
         | 
| 47 | 
            +
                VALUE values;
         | 
| 48 | 
            +
            };
         | 
| 49 | 
            +
            typedef struct dheap_struct dheap_t;
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            static void
         | 
| 52 | 
            +
            dheap_compact(void *ptr)
         | 
| 53 | 
            +
            {
         | 
| 54 | 
            +
                dheap_t *heap = ptr;
         | 
| 55 | 
            +
                if (heap->scores) dheap_gc_location( heap->scores );
         | 
| 56 | 
            +
                if (heap->values) dheap_gc_location( heap->values );
         | 
| 57 | 
            +
            }
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            static void
         | 
| 60 | 
            +
            dheap_mark(void *ptr)
         | 
| 61 | 
            +
            {
         | 
| 62 | 
            +
                dheap_t *heap = ptr;
         | 
| 63 | 
            +
                if (heap->scores) rb_gc_mark_movable(heap->scores);
         | 
| 64 | 
            +
                if (heap->values) rb_gc_mark_movable(heap->values);
         | 
| 65 | 
            +
            }
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            static size_t
         | 
| 68 | 
            +
            dheap_memsize(const void *ptr)
         | 
| 69 | 
            +
            {
         | 
| 70 | 
            +
                const dheap_t *heap = ptr;
         | 
| 71 | 
            +
                size_t size = sizeof(*heap);
         | 
| 72 | 
            +
                return size;
         | 
| 73 | 
            +
            }
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            static const rb_data_type_t dheap_data_type = {
         | 
| 76 | 
            +
                "DHeap",
         | 
| 77 | 
            +
                {
         | 
| 78 | 
            +
                    (void (*)(void*))dheap_mark,
         | 
| 79 | 
            +
                    (void (*)(void*))RUBY_DEFAULT_FREE,
         | 
| 80 | 
            +
                    (size_t (*)(const void *))dheap_memsize,
         | 
| 81 | 
            +
                    dheap_compact_callback(dheap_compact),
         | 
| 82 | 
            +
                },
         | 
| 83 | 
            +
                0, 0,
         | 
| 84 | 
            +
                RUBY_TYPED_FREE_IMMEDIATELY,
         | 
| 85 | 
            +
            };
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            static VALUE
         | 
| 88 | 
            +
            dheap_s_alloc(VALUE klass)
         | 
| 89 | 
            +
            {
         | 
| 90 | 
            +
                VALUE obj;
         | 
| 91 | 
            +
                dheap_t *heap;
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                obj = TypedData_Make_Struct(klass, dheap_t, &dheap_data_type, heap);
         | 
| 94 | 
            +
                heap->d = DHEAP_DEFAULT_D;
         | 
| 95 | 
            +
                heap->scores = Qnil;
         | 
| 96 | 
            +
                heap->values = Qnil;
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                return obj;
         | 
| 99 | 
            +
            }
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            static inline dheap_t *
         | 
| 102 | 
            +
            get_dheap_struct(VALUE self)
         | 
| 103 | 
            +
            {
         | 
| 104 | 
            +
                dheap_t *heap;
         | 
| 105 | 
            +
                TypedData_Get_Struct(self, dheap_t, &dheap_data_type, heap);
         | 
| 106 | 
            +
                Check_Type(heap->scores, T_ARRAY);
         | 
| 107 | 
            +
                return heap;
         | 
| 108 | 
            +
            }
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            /*
         | 
| 111 | 
            +
             * @overload initialize(d = DHeap::DEFAULT_D)
         | 
| 112 | 
            +
             *   Initialize a _d_-ary min-heap.
         | 
| 113 | 
            +
             *
         | 
| 114 | 
            +
             *   @param d [Integer] maximum number of children per parent
         | 
| 115 | 
            +
             */
         | 
| 116 | 
            +
            static VALUE
         | 
| 117 | 
            +
            dheap_initialize(int argc, VALUE *argv, VALUE self) {
         | 
| 118 | 
            +
                rb_check_arity(argc, 0, 1);
         | 
| 119 | 
            +
                dheap_t *heap;
         | 
| 120 | 
            +
                TypedData_Get_Struct(self, dheap_t, &dheap_data_type, heap);
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                int d = DHEAP_DEFAULT_D;
         | 
| 123 | 
            +
                if (argc) {
         | 
| 124 | 
            +
                    d = NUM2INT(argv[0]);
         | 
| 125 | 
            +
                }
         | 
| 126 | 
            +
                DHEAP_Check_d_size(d);
         | 
| 127 | 
            +
                heap->d = d;
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                heap->scores = rb_ary_new_capa(10000);
         | 
| 130 | 
            +
                heap->values = rb_ary_new_capa(10000);
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                return self;
         | 
| 133 | 
            +
            }
         | 
| 134 | 
            +
             | 
| 135 | 
            +
            /*
         | 
| 136 | 
            +
            static inline VALUE
         | 
| 137 | 
            +
            make_dheap_element(VALUE score, VALUE value)
         | 
| 138 | 
            +
            {
         | 
| 139 | 
            +
                elem_t *elem;
         | 
| 140 | 
            +
                VALUE obj = TypedData_Make_Struct(
         | 
| 141 | 
            +
                        rb_cObject,
         | 
| 142 | 
            +
                        elem_t,
         | 
| 143 | 
            +
                        &dheap_elem_type,
         | 
| 144 | 
            +
                        elem);
         | 
| 145 | 
            +
                elem->score = score;
         | 
| 146 | 
            +
                elem->value = value;
         | 
| 147 | 
            +
                return obj;
         | 
| 148 | 
            +
            }
         | 
| 149 | 
            +
             | 
| 150 | 
            +
            #define IsDHeapElem(value) rb_typeddata_is_kind_of((value), &dheap_elem_type)
         | 
| 151 | 
            +
            #define Get_DHeap_Elem(value) \
         | 
| 152 | 
            +
                TypedData_Get_Struct((obj), elem_t, &dheap_elem_type, (elem))
         | 
| 153 | 
            +
             | 
| 154 | 
            +
            static inline elem_t *
         | 
| 155 | 
            +
            get_dheap_element(VALUE obj)
         | 
| 156 | 
            +
            {
         | 
| 157 | 
            +
                elem_t *elem;
         | 
| 158 | 
            +
                TypedData_Get_Struct((obj), elem_t, &dheap_elem_type, (elem));
         | 
| 159 | 
            +
                return elem;
         | 
| 160 | 
            +
            }
         | 
| 161 | 
            +
             | 
| 162 | 
            +
            */
         | 
| 163 | 
            +
             | 
| 164 | 
            +
            #define CMP_LT(a, b)  (optimized_cmp(a, b) <  0)
         | 
| 165 | 
            +
            #define CMP_LTE(a, b) (optimized_cmp(a, b) <= 0)
         | 
| 166 | 
            +
            #define CMP_GT(a, b)  (optimized_cmp(a, b) >  0)
         | 
| 167 | 
            +
            #define CMP_GTE(a, b) (optimized_cmp(a, b) >= 0)
         | 
| 168 | 
            +
             | 
| 169 | 
            +
            /*
         | 
| 170 | 
            +
             * short-circuit evaluation for a few basic types.
         | 
| 171 | 
            +
             *
         | 
| 172 | 
            +
             * Only Integer, Float, and String are optimized,
         | 
| 173 | 
            +
             * and only when both arguments are the same type.
         | 
| 174 | 
            +
             */
         | 
| 175 | 
            +
            static inline int
         | 
| 176 | 
            +
            optimized_cmp(VALUE a, VALUE b) {
         | 
| 177 | 
            +
                if (a == b) // Fixnum equality and object equality
         | 
| 178 | 
            +
                    return 0;
         | 
| 179 | 
            +
                if (FIXNUM_P(a) && FIXNUM_P(b))
         | 
| 180 | 
            +
                    return (FIX2LONG(a) < FIX2LONG(b)) ? -1 : 1;
         | 
| 181 | 
            +
                if (RB_FLOAT_TYPE_P(a) && RB_FLOAT_TYPE_P(b))
         | 
| 182 | 
            +
                {
         | 
| 183 | 
            +
                    double x, y;
         | 
| 184 | 
            +
                    x = RFLOAT_VALUE(a);
         | 
| 185 | 
            +
                    y = RFLOAT_VALUE(b);
         | 
| 186 | 
            +
                    if (isnan(x) || isnan(y)) rb_cmperr(a, b); // raise ArgumentError
         | 
| 187 | 
            +
                    return (x < y) ? -1 : ((x == y) ? 0 : 1);
         | 
| 188 | 
            +
                }
         | 
| 189 | 
            +
                if (RB_TYPE_P(a, T_BIGNUM) && RB_TYPE_P(b, T_BIGNUM))
         | 
| 190 | 
            +
                    return FIX2INT(rb_big_cmp(a, b));
         | 
| 191 | 
            +
                if (STRING_P(a) && STRING_P(b))
         | 
| 192 | 
            +
                    return rb_str_cmp(a, b);
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                // give up on an optimized version and just call (a <=> b)
         | 
| 195 | 
            +
                return rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b);
         | 
| 196 | 
            +
            }
         | 
| 50 197 |  | 
| 51 198 | 
             
            VALUE
         | 
| 52 | 
            -
            dheap_ary_sift_up( | 
| 53 | 
            -
                 | 
| 199 | 
            +
            dheap_ary_sift_up(dheap_t *heap, long sift_index) {
         | 
| 200 | 
            +
                long last_index = DHEAP_IDX_LAST(heap);
         | 
| 201 | 
            +
                DHEAP_Check_Index(sift_index, last_index);
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                VALUE sift_value = DHEAP_VALUE(heap, sift_index);
         | 
| 204 | 
            +
                VALUE sift_score = DHEAP_SCORE(heap, sift_index);
         | 
| 205 | 
            +
             | 
| 54 206 | 
             
                // sift it up to where it belongs
         | 
| 55 207 | 
             
                for (long parent_index; 0 < sift_index; sift_index = parent_index) {
         | 
| 56 | 
            -
                    debug(rb_sprintf("sift up(%"PRIsVALUE", %d, %ld)",  | 
| 57 | 
            -
                    parent_index =  | 
| 58 | 
            -
                    VALUE parent_score = DHEAP_SCORE( | 
| 208 | 
            +
                    debug(rb_sprintf("sift up(%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
         | 
| 209 | 
            +
                    parent_index = DHEAP_IDX_PARENT(heap, sift_index);
         | 
| 210 | 
            +
                    VALUE parent_score = DHEAP_SCORE(heap, parent_index);
         | 
| 59 211 |  | 
| 60 212 | 
             
                    // parent is smaller: heap is restored
         | 
| 61 213 | 
             
                    if (CMP_LTE(parent_score, sift_score)) break;
         | 
| 62 214 |  | 
| 63 215 | 
             
                    // parent is larger: swap and continue sifting up
         | 
| 64 | 
            -
                    VALUE parent_value = DHEAP_VALUE( | 
| 65 | 
            -
                    DHEAP_ASSIGN( | 
| 66 | 
            -
                    DHEAP_ASSIGN( | 
| 216 | 
            +
                    VALUE parent_value = DHEAP_VALUE(heap, parent_index);
         | 
| 217 | 
            +
                    DHEAP_ASSIGN(heap, sift_index, parent_score, parent_value);
         | 
| 218 | 
            +
                    DHEAP_ASSIGN(heap, parent_index, sift_score, sift_value);
         | 
| 67 219 | 
             
                }
         | 
| 68 | 
            -
                debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)",  | 
| 220 | 
            +
                debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
         | 
| 69 221 | 
             
                return LONG2NUM(sift_index);
         | 
| 70 222 | 
             
            }
         | 
| 71 223 |  | 
| 72 224 | 
             
            VALUE
         | 
| 73 | 
            -
            dheap_ary_sift_down( | 
| 74 | 
            -
                 | 
| 225 | 
            +
            dheap_ary_sift_down(dheap_t *heap, long sift_index) {
         | 
| 226 | 
            +
                long last_index = DHEAP_IDX_LAST(heap);
         | 
| 227 | 
            +
                DHEAP_Check_Index(sift_index, last_index);
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                VALUE sift_value = DHEAP_VALUE(heap, sift_index);
         | 
| 230 | 
            +
                VALUE sift_score = DHEAP_SCORE(heap, sift_index);
         | 
| 75 231 |  | 
| 76 232 | 
             
                 // iteratively sift it down to where it belongs
         | 
| 77 233 | 
             
                for (long child_index; sift_index < last_index; sift_index = child_index) {
         | 
| 78 | 
            -
                    debug(rb_sprintf("sift dn(%"PRIsVALUE", %d, %ld)",  | 
| 234 | 
            +
                    debug(rb_sprintf("sift dn(%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
         | 
| 79 235 | 
             
                    // find first child index, and break if we've reached the last layer
         | 
| 80 | 
            -
                    long child_idx0 = child_index =  | 
| 236 | 
            +
                    long child_idx0 = child_index = DHEAP_IDX_CHILD0(heap, sift_index);
         | 
| 81 237 | 
             
                    if (last_index < child_idx0) break;
         | 
| 82 238 |  | 
| 83 239 | 
             
                    // find the min child (and its child_index)
         | 
| 84 240 | 
             
                    // requires "d" comparisons to find min child and compare to sift_score
         | 
| 85 | 
            -
                     | 
| 241 | 
            +
                    long last_sibidx = child_idx0 + heap->d - 1;
         | 
| 242 | 
            +
                    if (last_index < last_sibidx) last_sibidx = last_index;
         | 
| 243 | 
            +
                    VALUE child_score = DHEAP_SCORE(heap, child_idx0);
         | 
| 86 244 | 
             
                    child_index = child_idx0;
         | 
| 87 | 
            -
                    for ( | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
                        VALUE sibling_score = DHEAP_SCORE(heap_array, sibling_index);
         | 
| 245 | 
            +
                    for (long sibling_index = child_idx0 + 1;
         | 
| 246 | 
            +
                            sibling_index <= last_sibidx;
         | 
| 247 | 
            +
                            ++sibling_index) {
         | 
| 248 | 
            +
                        VALUE sibling_score = DHEAP_SCORE(heap, sibling_index);
         | 
| 92 249 |  | 
| 93 250 | 
             
                        if (CMP_LT(sibling_score, child_score)) {
         | 
| 94 251 | 
             
                            child_score = sibling_score;
         | 
| @@ -100,106 +257,45 @@ dheap_ary_sift_down(VALUE heap_array, int d, long sift_index) { | |
| 100 257 | 
             
                    if (CMP_LTE(sift_score, child_score)) break;
         | 
| 101 258 |  | 
| 102 259 | 
             
                    // child is smaller: swap and continue sifting down
         | 
| 103 | 
            -
                    VALUE child_value = DHEAP_VALUE( | 
| 104 | 
            -
                    DHEAP_ASSIGN( | 
| 105 | 
            -
                    DHEAP_ASSIGN( | 
| 260 | 
            +
                    VALUE child_value = DHEAP_VALUE(heap, child_index);
         | 
| 261 | 
            +
                    DHEAP_ASSIGN(heap, sift_index, child_score, child_value);
         | 
| 262 | 
            +
                    DHEAP_ASSIGN(heap, child_index, sift_score, sift_value);
         | 
| 106 263 | 
             
                }
         | 
| 107 | 
            -
                debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)",  | 
| 264 | 
            +
                debug(rb_sprintf("sifted (%"PRIsVALUE", %d, %ld)", heap->values, heap->d, sift_index));
         | 
| 108 265 | 
             
                return LONG2NUM(sift_index);
         | 
| 109 266 | 
             
            }
         | 
| 110 267 |  | 
| 111 | 
            -
            #define DHEAP_Load_Sift_Vals(heap_array, dval, idxval) \
         | 
| 112 | 
            -
                Check_Type(dval, T_FIXNUM); \
         | 
| 113 | 
            -
                int dint = FIX2INT(dval); \
         | 
| 114 | 
            -
                long idx = NUM2LONG(idxval);
         | 
| 115 | 
            -
             | 
| 116 | 
            -
            /*
         | 
| 117 | 
            -
             * Treats a +heap_array+ as a +d+-ary heap and sifts up from +sift_index+ to
         | 
| 118 | 
            -
             * restore the heap property for all nodes between it and the root of the tree.
         | 
| 119 | 
            -
             *
         | 
| 120 | 
            -
             * The array is interpreted as holding two entries for each node, a score and a
         | 
| 121 | 
            -
             * value.  The scores will held in every even-numbered array index and the
         | 
| 122 | 
            -
             * values in every odd numbered index.  The array is flat, not an array of
         | 
| 123 | 
            -
             * length=2 arrays.
         | 
| 124 | 
            -
             *
         | 
| 125 | 
            -
             * Time complexity: <b>O(log n / log d)</b> <i>(worst-case)</i>
         | 
| 126 | 
            -
             *
         | 
| 127 | 
            -
             * @param heap_array [Array] the array which is treated a heap.
         | 
| 128 | 
            -
             * @param d [Integer] the maximum number of children per parent
         | 
| 129 | 
            -
             * @param sift_index [Integer] the index to start sifting from
         | 
| 130 | 
            -
             * @return [Integer] the new index for the object that starts at +sift_index+.
         | 
| 131 | 
            -
             */
         | 
| 132 | 
            -
            static VALUE
         | 
| 133 | 
            -
            dheap_sift_up_s(VALUE unused, VALUE heap_array, VALUE d, VALUE sift_index) {
         | 
| 134 | 
            -
                DHEAP_Load_Sift_Vals(heap_array, d, sift_index);
         | 
| 135 | 
            -
                return dheap_ary_sift_up(heap_array, dint, idx);
         | 
| 136 | 
            -
            }
         | 
| 137 | 
            -
             | 
| 138 | 
            -
            /*
         | 
| 139 | 
            -
             * Treats +heap_array+ as a +d+-ary heap and sifts down from +sift_index+ to
         | 
| 140 | 
            -
             * restore the heap property. If all _d_ subtrees below +sift_index+ are already
         | 
| 141 | 
            -
             * heaps, this method ensures the entire subtree rooted at +sift_index+ will be
         | 
| 142 | 
            -
             * a heap.
         | 
| 143 | 
            -
             *
         | 
| 144 | 
            -
             * The array is interpreted as holding two entries for each node, a score and a
         | 
| 145 | 
            -
             * value.  The scores will held in every even-numbered array index and the
         | 
| 146 | 
            -
             * values in every odd numbered index.  The array is flat, not an array of
         | 
| 147 | 
            -
             * length=2 arrays.
         | 
| 148 | 
            -
             *
         | 
| 149 | 
            -
             * Time complexity: <b>O(d log n / log d)</b> <i>(worst-case)</i>
         | 
| 150 | 
            -
             *
         | 
| 151 | 
            -
             * @param heap_array [Array] the array which is treated a heap.
         | 
| 152 | 
            -
             * @param d [Integer] the maximum number of children per parent
         | 
| 153 | 
            -
             * @param sift_index [Integer] the index to start sifting down from
         | 
| 154 | 
            -
             * @return [Integer] the new index for the object that starts at +sift_index+.
         | 
| 155 | 
            -
             */
         | 
| 156 | 
            -
            static VALUE
         | 
| 157 | 
            -
            dheap_sift_down_s(VALUE unused, VALUE heap_array, VALUE d, VALUE sift_index) {
         | 
| 158 | 
            -
                DHEAP_Load_Sift_Vals(heap_array, d, sift_index);
         | 
| 159 | 
            -
                return dheap_ary_sift_down(heap_array, dint, idx);
         | 
| 160 | 
            -
            }
         | 
| 161 | 
            -
             | 
| 162 | 
            -
            /*
         | 
| 163 | 
            -
             * @overload initialize(d = DHeap::DEFAULT_D)
         | 
| 164 | 
            -
             *   Initialize a _d_-ary min-heap.
         | 
| 165 | 
            -
             *
         | 
| 166 | 
            -
             *   @param d [Integer] maximum number of children per parent
         | 
| 167 | 
            -
             */
         | 
| 168 | 
            -
            static VALUE
         | 
| 169 | 
            -
            dheap_initialize(int argc, VALUE *argv, VALUE self) {
         | 
| 170 | 
            -
                rb_check_arity(argc, 0, 1);
         | 
| 171 | 
            -
                int d = DHEAP_DEFAULT_D;
         | 
| 172 | 
            -
                if (argc) {
         | 
| 173 | 
            -
                    d = NUM2INT(argv[0]);
         | 
| 174 | 
            -
                }
         | 
| 175 | 
            -
                DHEAP_Check_d_size(d);
         | 
| 176 | 
            -
                rb_ivar_set(self, id_ivar_d, INT2FIX(d));
         | 
| 177 | 
            -
                rb_ivar_set(self, id_ivar_a, rb_ary_new());
         | 
| 178 | 
            -
                return self;
         | 
| 179 | 
            -
            }
         | 
| 180 | 
            -
             | 
| 181 268 | 
             
            /*
         | 
| 182 269 | 
             
             * @return [Integer] the number of elements in the heap
         | 
| 183 270 | 
             
             */
         | 
| 184 | 
            -
            static VALUE | 
| 185 | 
            -
             | 
| 186 | 
            -
             | 
| 271 | 
            +
            static VALUE
         | 
| 272 | 
            +
            dheap_size(VALUE self)
         | 
| 273 | 
            +
            {
         | 
| 274 | 
            +
                dheap_t *heap = get_dheap_struct(self);
         | 
| 275 | 
            +
                long size = DHEAP_SIZE(heap);
         | 
| 187 276 | 
             
                return LONG2NUM(size);
         | 
| 188 277 | 
             
            }
         | 
| 189 278 |  | 
| 190 279 | 
             
            /*
         | 
| 191 280 | 
             
             * @return [Boolean] is the heap empty?
         | 
| 192 281 | 
             
             */
         | 
| 193 | 
            -
            static VALUE | 
| 194 | 
            -
             | 
| 195 | 
            -
             | 
| 282 | 
            +
            static VALUE
         | 
| 283 | 
            +
            dheap_empty_p(VALUE self)
         | 
| 284 | 
            +
            {
         | 
| 285 | 
            +
                dheap_t *heap = get_dheap_struct(self);
         | 
| 286 | 
            +
                long size = DHEAP_SIZE(heap);
         | 
| 196 287 | 
             
                return size == 0 ? Qtrue : Qfalse;
         | 
| 197 288 | 
             
            }
         | 
| 198 289 |  | 
| 199 290 | 
             
            /*
         | 
| 200 291 | 
             
             * @return [Integer] the maximum number of children per parent
         | 
| 201 292 | 
             
             */
         | 
| 202 | 
            -
            static VALUE | 
| 293 | 
            +
            static VALUE
         | 
| 294 | 
            +
            dheap_attr_d(VALUE self)
         | 
| 295 | 
            +
            {
         | 
| 296 | 
            +
                dheap_t *heap = get_dheap_struct(self);
         | 
| 297 | 
            +
                return INT2FIX(heap->d);
         | 
| 298 | 
            +
            }
         | 
| 203 299 |  | 
| 204 300 | 
             
            /*
         | 
| 205 301 | 
             
             * Freezes the heap as well as its underlying array, but does <i>not</i>
         | 
| @@ -209,20 +305,13 @@ static VALUE dheap_attr_d(VALUE self) { return DHEAP_GET_D(self); } | |
| 209 305 | 
             
             */
         | 
| 210 306 | 
             
            static VALUE
         | 
| 211 307 | 
             
            dheap_freeze(VALUE self) {
         | 
| 212 | 
            -
                 | 
| 308 | 
            +
                dheap_t *heap = get_dheap_struct(self);
         | 
| 213 309 | 
             
                ID id_freeze = rb_intern("freeze");
         | 
| 214 | 
            -
                rb_funcall( | 
| 310 | 
            +
                rb_funcall(heap->scores, id_freeze, 0);
         | 
| 311 | 
            +
                rb_funcall(heap->values, id_freeze, 0);
         | 
| 215 312 | 
             
                return rb_call_super(0, NULL);
         | 
| 216 313 | 
             
            }
         | 
| 217 314 |  | 
| 218 | 
            -
            static VALUE
         | 
| 219 | 
            -
            dheap_ary_push(VALUE ary, int d, VALUE val, VALUE scr)
         | 
| 220 | 
            -
            {
         | 
| 221 | 
            -
                DHEAP_APPEND(ary, scr, val);
         | 
| 222 | 
            -
                long last_index = DHEAP_LAST_IDX(ary);
         | 
| 223 | 
            -
                return dheap_ary_sift_up(ary, d, last_index);
         | 
| 224 | 
            -
            }
         | 
| 225 | 
            -
             | 
| 226 315 | 
             
            /*
         | 
| 227 316 | 
             
             * @overload push(score, value = score)
         | 
| 228 317 | 
             
             *
         | 
| @@ -244,11 +333,11 @@ dheap_push(int argc, VALUE *argv, VALUE self) { | |
| 244 333 | 
             
                VALUE scr  = argv[0];
         | 
| 245 334 | 
             
                VALUE val  = argc < 2 ? scr : argv[1];
         | 
| 246 335 |  | 
| 247 | 
            -
                 | 
| 248 | 
            -
                VALUE dval = DHEAP_GET_D(self);
         | 
| 249 | 
            -
                int d = FIX2INT(dval);
         | 
| 336 | 
            +
                dheap_t *heap = get_dheap_struct(self);
         | 
| 250 337 |  | 
| 251 | 
            -
                 | 
| 338 | 
            +
                DHEAP_APPEND(heap, scr, val);
         | 
| 339 | 
            +
                long last_index = DHEAP_IDX_LAST(heap);
         | 
| 340 | 
            +
                return dheap_ary_sift_up(heap, last_index);
         | 
| 252 341 | 
             
            }
         | 
| 253 342 |  | 
| 254 343 | 
             
            /*
         | 
| @@ -267,18 +356,29 @@ dheap_left_shift(VALUE self, VALUE value) { | |
| 267 356 | 
             
                return self;
         | 
| 268 357 | 
             
            }
         | 
| 269 358 |  | 
| 270 | 
            -
             | 
| 271 | 
            -
                 | 
| 272 | 
            -
                 | 
| 273 | 
            -
                 | 
| 274 | 
            -
             | 
| 275 | 
            -
             | 
| 276 | 
            -
             | 
| 277 | 
            -
             | 
| 278 | 
            -
             | 
| 279 | 
            -
             | 
| 280 | 
            -
             | 
| 281 | 
            -
                 | 
| 359 | 
            +
            /*
         | 
| 360 | 
            +
                dheap_t hstruct; \
         | 
| 361 | 
            +
                Get_DHeap(self, hstruct); \
         | 
| 362 | 
            +
                VALUE values = hstruct.values; \
         | 
| 363 | 
            +
                VALUE scores = hstruct.scores; \
         | 
| 364 | 
            +
                VALUE dval = INT2FIX(hstruct.d); \
         | 
| 365 | 
            +
            */
         | 
| 366 | 
            +
             | 
| 367 | 
            +
            static inline void
         | 
| 368 | 
            +
            dheap_pop_swap_last_and_sift_down(dheap_t *heap, long last_index)
         | 
| 369 | 
            +
            {
         | 
| 370 | 
            +
                if (last_index == 0) {
         | 
| 371 | 
            +
                    DHEAP_DROP_LAST(heap);
         | 
| 372 | 
            +
                }
         | 
| 373 | 
            +
                else
         | 
| 374 | 
            +
                {
         | 
| 375 | 
            +
                    VALUE sift_value = DHEAP_VALUE(heap, last_index);
         | 
| 376 | 
            +
                    VALUE sift_score = DHEAP_SCORE(heap, last_index);
         | 
| 377 | 
            +
                    DHEAP_ASSIGN(heap, 0, sift_score, sift_value);
         | 
| 378 | 
            +
                    DHEAP_DROP_LAST(heap);
         | 
| 379 | 
            +
                    dheap_ary_sift_down(heap, 0);
         | 
| 380 | 
            +
                }
         | 
| 381 | 
            +
            }
         | 
| 282 382 |  | 
| 283 383 | 
             
            /*
         | 
| 284 384 | 
             
             * Returns the next value on the heap to be popped without popping it.
         | 
| @@ -288,8 +388,9 @@ dheap_left_shift(VALUE self, VALUE value) { | |
| 288 388 | 
             
             */
         | 
| 289 389 | 
             
            static VALUE
         | 
| 290 390 | 
             
            dheap_peek(VALUE self) {
         | 
| 291 | 
            -
                 | 
| 292 | 
            -
                 | 
| 391 | 
            +
                dheap_t *heap = get_dheap_struct(self);
         | 
| 392 | 
            +
                if (DHEAP_IDX_LAST(heap) < 0) return Qnil;
         | 
| 393 | 
            +
                return DHEAP_VALUE(heap, 0);
         | 
| 293 394 | 
             
            }
         | 
| 294 395 |  | 
| 295 396 | 
             
            /*
         | 
| @@ -299,11 +400,13 @@ dheap_peek(VALUE self) { | |
| 299 400 | 
             
             */
         | 
| 300 401 | 
             
            static VALUE
         | 
| 301 402 | 
             
            dheap_pop(VALUE self) {
         | 
| 302 | 
            -
                 | 
| 303 | 
            -
                 | 
| 304 | 
            -
                VALUE pop_value = DHEAP_VALUE(ary, 0);
         | 
| 403 | 
            +
                dheap_t *heap = get_dheap_struct(self);
         | 
| 404 | 
            +
                long last_index = DHEAP_IDX_LAST(heap);
         | 
| 305 405 |  | 
| 306 | 
            -
                 | 
| 406 | 
            +
                if (last_index < 0) return Qnil;
         | 
| 407 | 
            +
                VALUE pop_value = DHEAP_VALUE(heap, 0);
         | 
| 408 | 
            +
             | 
| 409 | 
            +
                dheap_pop_swap_last_and_sift_down(heap, last_index);
         | 
| 307 410 | 
             
                return pop_value;
         | 
| 308 411 | 
             
            }
         | 
| 309 412 |  | 
| @@ -316,14 +419,16 @@ dheap_pop(VALUE self) { | |
| 316 419 | 
             
             */
         | 
| 317 420 | 
             
            static VALUE
         | 
| 318 421 | 
             
            dheap_pop_lte(VALUE self, VALUE max_score) {
         | 
| 319 | 
            -
                 | 
| 422 | 
            +
                dheap_t *heap = get_dheap_struct(self);
         | 
| 423 | 
            +
                long last_index = DHEAP_IDX_LAST(heap);
         | 
| 424 | 
            +
             | 
| 320 425 | 
             
                if (last_index <  0) return Qnil;
         | 
| 321 | 
            -
                VALUE pop_value = DHEAP_VALUE( | 
| 426 | 
            +
                VALUE pop_value = DHEAP_VALUE(heap, 0);
         | 
| 322 427 |  | 
| 323 | 
            -
                VALUE pop_score = DHEAP_SCORE( | 
| 428 | 
            +
                VALUE pop_score = DHEAP_SCORE(heap, 0);
         | 
| 324 429 | 
             
                if (max_score && !CMP_LTE(pop_score, max_score)) return Qnil;
         | 
| 325 430 |  | 
| 326 | 
            -
                 | 
| 431 | 
            +
                dheap_pop_swap_last_and_sift_down(heap, last_index);
         | 
| 327 432 | 
             
                return pop_value;
         | 
| 328 433 | 
             
            }
         | 
| 329 434 |  | 
| @@ -336,14 +441,16 @@ dheap_pop_lte(VALUE self, VALUE max_score) { | |
| 336 441 | 
             
             */
         | 
| 337 442 | 
             
            static VALUE
         | 
| 338 443 | 
             
            dheap_pop_lt(VALUE self, VALUE max_score) {
         | 
| 339 | 
            -
                 | 
| 444 | 
            +
                dheap_t *heap = get_dheap_struct(self);
         | 
| 445 | 
            +
                long last_index = DHEAP_IDX_LAST(heap);
         | 
| 446 | 
            +
             | 
| 340 447 | 
             
                if (last_index <  0) return Qnil;
         | 
| 341 | 
            -
                VALUE pop_value = DHEAP_VALUE( | 
| 448 | 
            +
                VALUE pop_value = DHEAP_VALUE(heap, 0);
         | 
| 342 449 |  | 
| 343 | 
            -
                VALUE pop_score = DHEAP_SCORE( | 
| 450 | 
            +
                VALUE pop_score = DHEAP_SCORE(heap, 0);
         | 
| 344 451 | 
             
                if (max_score && !CMP_LT(pop_score, max_score)) return Qnil;
         | 
| 345 452 |  | 
| 346 | 
            -
                 | 
| 453 | 
            +
                dheap_pop_swap_last_and_sift_down(heap, last_index);
         | 
| 347 454 | 
             
                return pop_value;
         | 
| 348 455 | 
             
            }
         | 
| 349 456 |  | 
| @@ -351,16 +458,16 @@ void | |
| 351 458 | 
             
            Init_d_heap(void)
         | 
| 352 459 | 
             
            {
         | 
| 353 460 | 
             
                id_cmp = rb_intern_const("<=>");
         | 
| 354 | 
            -
                 | 
| 461 | 
            +
                id_ivar_values = rb_intern_const("values");
         | 
| 462 | 
            +
                id_ivar_scores = rb_intern_const("scores");
         | 
| 355 463 | 
             
                id_ivar_d = rb_intern_const("d");
         | 
| 356 464 |  | 
| 357 465 | 
             
                rb_cDHeap = rb_define_class("DHeap", rb_cObject);
         | 
| 466 | 
            +
                rb_define_alloc_func(rb_cDHeap, dheap_s_alloc);
         | 
| 467 | 
            +
             | 
| 358 468 | 
             
                rb_define_const(rb_cDHeap, "MAX_D", INT2NUM(DHEAP_MAX_D));
         | 
| 359 469 | 
             
                rb_define_const(rb_cDHeap, "DEFAULT_D", INT2NUM(DHEAP_DEFAULT_D));
         | 
| 360 470 |  | 
| 361 | 
            -
                rb_define_singleton_method(rb_cDHeap, "heap_sift_down", dheap_sift_down_s, 3);
         | 
| 362 | 
            -
                rb_define_singleton_method(rb_cDHeap, "heap_sift_up",   dheap_sift_up_s, 3);
         | 
| 363 | 
            -
             | 
| 364 471 | 
             
                rb_define_method(rb_cDHeap, "initialize", dheap_initialize, -1);
         | 
| 365 472 | 
             
                rb_define_method(rb_cDHeap, "d", dheap_attr_d, 0);
         | 
| 366 473 | 
             
                rb_define_method(rb_cDHeap, "freeze", dheap_freeze, 0);
         | 
    
        data/ext/d_heap/d_heap.h
    CHANGED
    
    | @@ -13,46 +13,22 @@ | |
| 13 13 |  | 
| 14 14 | 
             
            VALUE rb_cDHeap;
         | 
| 15 15 |  | 
| 16 | 
            -
             | 
| 17 | 
            -
            #define CMP_LTE(a, b) (optimized_cmp(a, b) <= 0)
         | 
| 18 | 
            -
            #define CMP_GT(a, b)  (optimized_cmp(a, b) >  0)
         | 
| 19 | 
            -
            #define CMP_GTE(a, b) (optimized_cmp(a, b) >= 0)
         | 
| 16 | 
            +
            // copied from pg gem
         | 
| 20 17 |  | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 18 | 
            +
            #define UNUSED(x) ((void)(x))
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            #ifdef HAVE_RB_GC_MARK_MOVABLE
         | 
| 21 | 
            +
            #define dheap_compact_callback(x) ((void (*)(void*))(x))
         | 
| 22 | 
            +
            #define dheap_gc_location(x) x = rb_gc_location(x)
         | 
| 23 | 
            +
            #else
         | 
| 24 | 
            +
            #define rb_gc_mark_movable(x) rb_gc_mark(x)
         | 
| 25 | 
            +
            #define dheap_compact_callback(x) {(x)}
         | 
| 26 | 
            +
            #define dheap_gc_location(x) UNUSED(x)
         | 
| 27 | 
            +
            #endif
         | 
| 23 28 |  | 
| 24 29 | 
             
            // from internal/compar.h
         | 
| 25 30 | 
             
            #define STRING_P(s) (RB_TYPE_P((s), T_STRING) && CLASS_OF(s) == rb_cString)
         | 
| 26 31 |  | 
| 27 | 
            -
            /*
         | 
| 28 | 
            -
             * short-circuit evaluation for a few basic types.
         | 
| 29 | 
            -
             *
         | 
| 30 | 
            -
             * Only Integer, Float, and String are optimized,
         | 
| 31 | 
            -
             * and only when both arguments are the same type.
         | 
| 32 | 
            -
             */
         | 
| 33 | 
            -
            static inline int
         | 
| 34 | 
            -
            optimized_cmp(VALUE a, VALUE b) {
         | 
| 35 | 
            -
                if (a == b) // Fixnum equality and object equality
         | 
| 36 | 
            -
                    return 0;
         | 
| 37 | 
            -
                if (FIXNUM_P(a) && FIXNUM_P(b))
         | 
| 38 | 
            -
                    return (FIX2LONG(a) < FIX2LONG(b)) ? -1 : 1;
         | 
| 39 | 
            -
                if (RB_FLOAT_TYPE_P(a) && RB_FLOAT_TYPE_P(b))
         | 
| 40 | 
            -
                {
         | 
| 41 | 
            -
                    double x, y;
         | 
| 42 | 
            -
                    x = RFLOAT_VALUE(a);
         | 
| 43 | 
            -
                    y = RFLOAT_VALUE(b);
         | 
| 44 | 
            -
                    if (isnan(x) || isnan(y)) rb_cmperr(a, b); // raise ArgumentError
         | 
| 45 | 
            -
                    return (x < y) ? -1 : ((x == y) ? 0 : 1);
         | 
| 46 | 
            -
                }
         | 
| 47 | 
            -
                if (RB_TYPE_P(a, T_BIGNUM) && RB_TYPE_P(b, T_BIGNUM))
         | 
| 48 | 
            -
                    return FIX2INT(rb_big_cmp(a, b));
         | 
| 49 | 
            -
                if (STRING_P(a) && STRING_P(b))
         | 
| 50 | 
            -
                    return rb_str_cmp(a, b);
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                // give up on an optimized version and just call (a <=> b)
         | 
| 53 | 
            -
                return rb_cmpint(rb_funcallv(a, id_cmp, 1, &b), a, b);
         | 
| 54 | 
            -
            }
         | 
| 55 | 
            -
             | 
| 56 32 | 
             
            #ifdef __D_HEAP_DEBUG
         | 
| 57 33 | 
             
            #define debug(v) { \
         | 
| 58 34 | 
             
                ID sym_puts = rb_intern("puts"); \
         | 
    
        data/ext/d_heap/extconf.rb
    CHANGED
    
    
    
        data/lib/d_heap/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,15 +1,29 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: d_heap
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - nicholas a. evans
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2020-12- | 
| 12 | 
            -
            dependencies: | 
| 11 | 
            +
            date: 2020-12-29 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: rspec-benchmark
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">="
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0'
         | 
| 20 | 
            +
              type: :development
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">="
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0'
         | 
| 13 27 | 
             
            description: |
         | 
| 14 28 | 
             
              A C extension implementation of a d-ary heap data structure, suitable for
         | 
| 15 29 | 
             
              use in e.g. priority queues or Djikstra's algorithm.
         |