ruby-zstds 1.0.3 → 1.1.1
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/README.md +133 -170
- data/ext/extconf.rb +13 -1
- data/ext/zstds_ext/buffer.c +4 -3
- data/ext/zstds_ext/buffer.h +5 -5
- data/ext/zstds_ext/dictionary.c +104 -42
- data/ext/zstds_ext/dictionary.h +1 -1
- data/ext/zstds_ext/error.c +12 -12
- data/ext/zstds_ext/error.h +2 -1
- data/ext/zstds_ext/gvl.h +24 -0
- data/ext/zstds_ext/io.c +229 -137
- data/ext/zstds_ext/option.c +44 -43
- data/ext/zstds_ext/option.h +62 -51
- data/ext/zstds_ext/stream/compressor.c +103 -50
- data/ext/zstds_ext/stream/compressor.h +4 -1
- data/ext/zstds_ext/stream/decompressor.c +46 -22
- data/ext/zstds_ext/stream/decompressor.h +4 -1
- data/ext/zstds_ext/string.c +93 -62
- data/lib/zstds/dictionary.rb +2 -0
- data/lib/zstds/file.rb +6 -2
- data/lib/zstds/option.rb +18 -7
- data/lib/zstds/stream/abstract.rb +6 -9
- data/lib/zstds/stream/raw/abstract.rb +6 -2
- data/lib/zstds/stream/raw/compressor.rb +3 -7
- data/lib/zstds/stream/raw/decompressor.rb +1 -5
- data/lib/zstds/stream/reader.rb +72 -52
- data/lib/zstds/stream/reader_helpers.rb +1 -1
- data/lib/zstds/stream/writer.rb +9 -4
- data/lib/zstds/stream/writer_helpers.rb +3 -2
- data/lib/zstds/validation.rb +4 -2
- data/lib/zstds/version.rb +1 -1
- metadata +62 -19
    
        data/ext/extconf.rb
    CHANGED
    
    | @@ -3,6 +3,10 @@ | |
| 3 3 |  | 
| 4 4 | 
             
            require "mkmf"
         | 
| 5 5 |  | 
| 6 | 
            +
            have_func "rb_thread_call_without_gvl", "ruby/thread.h"
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            # Old zstd versions has bug: underlinking against pthreads.
         | 
| 9 | 
            +
            # https://bugs.gentoo.org/713940
         | 
| 6 10 | 
             
            $LDFLAGS << " -pthread" # rubocop:disable Style/GlobalVars
         | 
| 7 11 |  | 
| 8 12 | 
             
            def require_header(name, types = [])
         | 
| @@ -52,6 +56,7 @@ require_library( | |
| 52 56 | 
             
                ZSTD_DStreamOutSize
         | 
| 53 57 | 
             
                ZSTD_compressStream2
         | 
| 54 58 | 
             
                ZSTD_decompressStream
         | 
| 59 | 
            +
                ZDICT_isError
         | 
| 55 60 | 
             
                ZDICT_getDictID
         | 
| 56 61 | 
             
                ZDICT_trainFromBuffer
         | 
| 57 62 | 
             
              ]
         | 
| @@ -75,7 +80,14 @@ $srcs = %w[ | |
| 75 80 | 
             
            .map { |name| "src/#{extension_name}/#{name}.c" }
         | 
| 76 81 | 
             
            .freeze
         | 
| 77 82 |  | 
| 78 | 
            -
             | 
| 83 | 
            +
            # Removing library duplicates.
         | 
| 84 | 
            +
            $libs = $libs.split(%r{\s})
         | 
| 85 | 
            +
              .reject(&:empty?)
         | 
| 86 | 
            +
              .sort
         | 
| 87 | 
            +
              .uniq
         | 
| 88 | 
            +
              .join " "
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            if ENV["CI"]
         | 
| 79 91 | 
             
              $CFLAGS << " --coverage"
         | 
| 80 92 | 
             
              $LDFLAGS << " --coverage"
         | 
| 81 93 | 
             
            end
         | 
    
        data/ext/zstds_ext/buffer.c
    CHANGED
    
    | @@ -12,10 +12,11 @@ VALUE zstds_ext_create_string_buffer(VALUE length) | |
| 12 12 | 
             
              return rb_str_new(NULL, NUM2SIZET(length));
         | 
| 13 13 | 
             
            }
         | 
| 14 14 |  | 
| 15 | 
            -
            VALUE zstds_ext_resize_string_buffer(VALUE  | 
| 15 | 
            +
            VALUE zstds_ext_resize_string_buffer(VALUE buffer_args)
         | 
| 16 16 | 
             
            {
         | 
| 17 | 
            -
              VALUE buffer = rb_ary_entry( | 
| 18 | 
            -
              VALUE length = rb_ary_entry( | 
| 17 | 
            +
              VALUE buffer = rb_ary_entry(buffer_args, 0);
         | 
| 18 | 
            +
              VALUE length = rb_ary_entry(buffer_args, 1);
         | 
| 19 | 
            +
             | 
| 19 20 | 
             
              return rb_str_resize(buffer, NUM2SIZET(length));
         | 
| 20 21 | 
             
            }
         | 
| 21 22 |  | 
    
        data/ext/zstds_ext/buffer.h
    CHANGED
    
    | @@ -11,12 +11,12 @@ VALUE zstds_ext_create_string_buffer(VALUE length); | |
| 11 11 | 
             
            #define ZSTDS_EXT_CREATE_STRING_BUFFER(buffer, length, exception) \
         | 
| 12 12 | 
             
              VALUE buffer = rb_protect(zstds_ext_create_string_buffer, SIZET2NUM(length), &exception);
         | 
| 13 13 |  | 
| 14 | 
            -
            VALUE zstds_ext_resize_string_buffer(VALUE  | 
| 14 | 
            +
            VALUE zstds_ext_resize_string_buffer(VALUE buffer_args);
         | 
| 15 15 |  | 
| 16 | 
            -
            #define ZSTDS_EXT_RESIZE_STRING_BUFFER(buffer, length, exception) | 
| 17 | 
            -
              VALUE  | 
| 18 | 
            -
              buffer | 
| 19 | 
            -
              RB_GC_GUARD( | 
| 16 | 
            +
            #define ZSTDS_EXT_RESIZE_STRING_BUFFER(buffer, length, exception)                          \
         | 
| 17 | 
            +
              VALUE buffer_args = rb_ary_new_from_args(2, buffer, SIZET2NUM(length));                  \
         | 
| 18 | 
            +
              buffer            = rb_protect(zstds_ext_resize_string_buffer, buffer_args, &exception); \
         | 
| 19 | 
            +
              RB_GC_GUARD(buffer_args);
         | 
| 20 20 |  | 
| 21 21 | 
             
            void zstds_ext_buffer_exports(VALUE root_module);
         | 
| 22 22 |  | 
    
        data/ext/zstds_ext/dictionary.c
    CHANGED
    
    | @@ -9,36 +9,92 @@ | |
| 9 9 | 
             
            #include "ruby.h"
         | 
| 10 10 | 
             
            #include "zstds_ext/buffer.h"
         | 
| 11 11 | 
             
            #include "zstds_ext/error.h"
         | 
| 12 | 
            +
            #include "zstds_ext/gvl.h"
         | 
| 12 13 | 
             
            #include "zstds_ext/macro.h"
         | 
| 13 14 | 
             
            #include "zstds_ext/option.h"
         | 
| 14 15 |  | 
| 15 | 
            -
             | 
| 16 | 
            +
            // -- initialization --
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            typedef struct
         | 
| 16 19 | 
             
            {
         | 
| 17 | 
            -
               | 
| 18 | 
            -
               | 
| 19 | 
            -
             | 
| 20 | 
            +
              const char* data;
         | 
| 21 | 
            +
              size_t      size;
         | 
| 22 | 
            +
            } sample_t;
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            typedef struct
         | 
| 25 | 
            +
            {
         | 
| 26 | 
            +
              const sample_t*    samples;
         | 
| 27 | 
            +
              size_t             length;
         | 
| 28 | 
            +
              char*              buffer;
         | 
| 29 | 
            +
              size_t             capacity;
         | 
| 30 | 
            +
              zstds_result_t     result;
         | 
| 31 | 
            +
              zstds_ext_result_t ext_result;
         | 
| 32 | 
            +
            } train_args_t;
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            static inline void* train_wrapper(void* data)
         | 
| 35 | 
            +
            {
         | 
| 36 | 
            +
              train_args_t*   args    = data;
         | 
| 37 | 
            +
              const sample_t* samples = args->samples;
         | 
| 38 | 
            +
              size_t          length  = args->length;
         | 
| 39 | 
            +
              size_t          size    = 0;
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              for (size_t index = 0; index < length; index++) {
         | 
| 42 | 
            +
                size += samples[index].size;
         | 
| 20 43 | 
             
              }
         | 
| 21 44 |  | 
| 22 | 
            -
               | 
| 45 | 
            +
              zstds_ext_byte_t* group = malloc(size);
         | 
| 46 | 
            +
              if (group == NULL) {
         | 
| 47 | 
            +
                args->ext_result = ZSTDS_EXT_ERROR_ALLOCATE_FAILED;
         | 
| 48 | 
            +
                return NULL;
         | 
| 49 | 
            +
              }
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              size_t* sizes = malloc(length * sizeof(size_t));
         | 
| 52 | 
            +
              if (sizes == NULL) {
         | 
| 53 | 
            +
                free(group);
         | 
| 54 | 
            +
                args->ext_result = ZSTDS_EXT_ERROR_ALLOCATE_FAILED;
         | 
| 55 | 
            +
                return NULL;
         | 
| 56 | 
            +
              }
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              size_t offset = 0;
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              for (size_t index = 0; index < length; index++) {
         | 
| 61 | 
            +
                const sample_t* sample_ptr  = &samples[index];
         | 
| 62 | 
            +
                size_t          sample_size = sample_ptr->size;
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                memmove(group + offset, sample_ptr->data, sample_size);
         | 
| 65 | 
            +
                offset += sample_size;
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                sizes[index] = sample_size;
         | 
| 68 | 
            +
              }
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              args->result = ZDICT_trainFromBuffer((void*) args->buffer, args->capacity, group, sizes, (unsigned int) length);
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              free(group);
         | 
| 73 | 
            +
              free(sizes);
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              if (ZDICT_isError(args->result)) {
         | 
| 76 | 
            +
                args->ext_result = zstds_ext_get_error(ZSTD_getErrorCode(args->result));
         | 
| 77 | 
            +
                return NULL;
         | 
| 78 | 
            +
              }
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              args->ext_result = 0;
         | 
| 81 | 
            +
             | 
| 82 | 
            +
              return NULL;
         | 
| 23 83 | 
             
            }
         | 
| 24 84 |  | 
| 25 | 
            -
            VALUE zstds_ext_train_dictionary_buffer(VALUE ZSTDS_EXT_UNUSED(self), VALUE  | 
| 85 | 
            +
            VALUE zstds_ext_train_dictionary_buffer(VALUE ZSTDS_EXT_UNUSED(self), VALUE raw_samples, VALUE options)
         | 
| 26 86 | 
             
            {
         | 
| 27 | 
            -
              Check_Type( | 
| 87 | 
            +
              Check_Type(raw_samples, T_ARRAY);
         | 
| 28 88 |  | 
| 29 | 
            -
              size_t | 
| 30 | 
            -
              unsigned int samples_length = (unsigned int)RARRAY_LEN(samples);
         | 
| 31 | 
            -
              size_t       samples_size   = 0;
         | 
| 89 | 
            +
              size_t length = RARRAY_LEN(raw_samples);
         | 
| 32 90 |  | 
| 33 | 
            -
              for ( | 
| 34 | 
            -
                 | 
| 35 | 
            -
                Check_Type(sample, T_STRING);
         | 
| 36 | 
            -
             | 
| 37 | 
            -
                samples_size += RSTRING_LEN(sample);
         | 
| 91 | 
            +
              for (size_t index = 0; index < length; index++) {
         | 
| 92 | 
            +
                Check_Type(rb_ary_entry(raw_samples, index), T_STRING);
         | 
| 38 93 | 
             
              }
         | 
| 39 94 |  | 
| 40 95 | 
             
              Check_Type(options, T_HASH);
         | 
| 41 | 
            -
               | 
| 96 | 
            +
              ZSTDS_EXT_GET_BOOL_OPTION(options, gvl);
         | 
| 97 | 
            +
              ZSTDS_EXT_GET_SIZE_OPTION(options, capacity);
         | 
| 42 98 |  | 
| 43 99 | 
             
              if (capacity == 0) {
         | 
| 44 100 | 
             
                capacity = ZSTDS_EXT_DEFAULT_DICTIONARY_CAPACITY;
         | 
| @@ -51,42 +107,34 @@ VALUE zstds_ext_train_dictionary_buffer(VALUE ZSTDS_EXT_UNUSED(self), VALUE samp | |
| 51 107 | 
             
                zstds_ext_raise_error(ZSTDS_EXT_ERROR_ALLOCATE_FAILED);
         | 
| 52 108 | 
             
              }
         | 
| 53 109 |  | 
| 54 | 
            -
               | 
| 55 | 
            -
              if ( | 
| 110 | 
            +
              sample_t* samples = malloc(sizeof(sample_t) * length);
         | 
| 111 | 
            +
              if (samples == NULL) {
         | 
| 56 112 | 
             
                zstds_ext_raise_error(ZSTDS_EXT_ERROR_ALLOCATE_FAILED);
         | 
| 57 113 | 
             
              }
         | 
| 58 114 |  | 
| 59 | 
            -
              size_t | 
| 60 | 
            -
             | 
| 61 | 
            -
                 | 
| 62 | 
            -
                zstds_ext_raise_error(ZSTDS_EXT_ERROR_ALLOCATE_FAILED);
         | 
| 63 | 
            -
              }
         | 
| 115 | 
            +
              for (size_t index = 0; index < length; index++) {
         | 
| 116 | 
            +
                VALUE     raw_sample = rb_ary_entry(raw_samples, index);
         | 
| 117 | 
            +
                sample_t* sample     = &samples[index];
         | 
| 64 118 |  | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
              for (sample_index = 0; sample_index < samples_length; sample_index++) {
         | 
| 68 | 
            -
                VALUE       sample      = rb_ary_entry(samples, sample_index);
         | 
| 69 | 
            -
                const char* sample_data = RSTRING_PTR(sample);
         | 
| 70 | 
            -
                size_t      sample_size = RSTRING_LEN(sample);
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                memmove(samples_buffer + sample_offset, sample_data, sample_size);
         | 
| 73 | 
            -
                sample_offset += sample_size;
         | 
| 74 | 
            -
             | 
| 75 | 
            -
                samples_sizes[sample_index] = sample_size;
         | 
| 119 | 
            +
                sample->data = RSTRING_PTR(raw_sample);
         | 
| 120 | 
            +
                sample->size = RSTRING_LEN(raw_sample);
         | 
| 76 121 | 
             
              }
         | 
| 77 122 |  | 
| 78 | 
            -
               | 
| 79 | 
            -
                 | 
| 80 | 
            -
                 | 
| 123 | 
            +
              train_args_t args = {
         | 
| 124 | 
            +
                .samples  = samples,
         | 
| 125 | 
            +
                .length   = length,
         | 
| 126 | 
            +
                .buffer   = RSTRING_PTR(buffer),
         | 
| 127 | 
            +
                .capacity = capacity,
         | 
| 128 | 
            +
              };
         | 
| 81 129 |  | 
| 82 | 
            -
               | 
| 83 | 
            -
              free( | 
| 130 | 
            +
              ZSTDS_EXT_GVL_WRAP(gvl, train_wrapper, &args);
         | 
| 131 | 
            +
              free(samples);
         | 
| 84 132 |  | 
| 85 | 
            -
              if ( | 
| 86 | 
            -
                zstds_ext_raise_error( | 
| 133 | 
            +
              if (args.ext_result != 0) {
         | 
| 134 | 
            +
                zstds_ext_raise_error(args.ext_result);
         | 
| 87 135 | 
             
              }
         | 
| 88 136 |  | 
| 89 | 
            -
              ZSTDS_EXT_RESIZE_STRING_BUFFER(buffer, result, exception);
         | 
| 137 | 
            +
              ZSTDS_EXT_RESIZE_STRING_BUFFER(buffer, args.result, exception);
         | 
| 90 138 | 
             
              if (exception != 0) {
         | 
| 91 139 | 
             
                zstds_ext_raise_error(ZSTDS_EXT_ERROR_ALLOCATE_FAILED);
         | 
| 92 140 | 
             
              }
         | 
| @@ -94,6 +142,20 @@ VALUE zstds_ext_train_dictionary_buffer(VALUE ZSTDS_EXT_UNUSED(self), VALUE samp | |
| 94 142 | 
             
              return buffer;
         | 
| 95 143 | 
             
            }
         | 
| 96 144 |  | 
| 145 | 
            +
            // -- other --
         | 
| 146 | 
            +
             | 
| 147 | 
            +
            VALUE zstds_ext_get_dictionary_buffer_id(VALUE ZSTDS_EXT_UNUSED(self), VALUE buffer)
         | 
| 148 | 
            +
            {
         | 
| 149 | 
            +
              unsigned int id = ZDICT_getDictID(RSTRING_PTR(buffer), RSTRING_LEN(buffer));
         | 
| 150 | 
            +
              if (id == 0) {
         | 
| 151 | 
            +
                zstds_ext_raise_error(ZSTDS_EXT_ERROR_VALIDATE_FAILED);
         | 
| 152 | 
            +
              }
         | 
| 153 | 
            +
             | 
| 154 | 
            +
              return UINT2NUM(id);
         | 
| 155 | 
            +
            }
         | 
| 156 | 
            +
             | 
| 157 | 
            +
            // -- exports --
         | 
| 158 | 
            +
             | 
| 97 159 | 
             
            void zstds_ext_dictionary_exports(VALUE root_module)
         | 
| 98 160 | 
             
            {
         | 
| 99 161 | 
             
              VALUE dictionary = rb_define_class_under(root_module, "Dictionary", rb_cObject);
         | 
    
        data/ext/zstds_ext/dictionary.h
    CHANGED
    
    | @@ -8,8 +8,8 @@ | |
| 8 8 |  | 
| 9 9 | 
             
            #define ZSTDS_EXT_DEFAULT_DICTIONARY_CAPACITY (1 << 17); // 128 KB
         | 
| 10 10 |  | 
| 11 | 
            -
            VALUE zstds_ext_get_dictionary_buffer_id(VALUE self, VALUE buffer);
         | 
| 12 11 | 
             
            VALUE zstds_ext_train_dictionary_buffer(VALUE self, VALUE samples, VALUE options);
         | 
| 12 | 
            +
            VALUE zstds_ext_get_dictionary_buffer_id(VALUE self, VALUE buffer);
         | 
| 13 13 |  | 
| 14 14 | 
             
            void zstds_ext_dictionary_exports(VALUE root_module);
         | 
| 15 15 |  | 
    
        data/ext/zstds_ext/error.c
    CHANGED
    
    | @@ -40,7 +40,7 @@ zstds_ext_result_t zstds_ext_get_error(ZSTD_ErrorCode error_code) | |
| 40 40 | 
             
              }
         | 
| 41 41 | 
             
            }
         | 
| 42 42 |  | 
| 43 | 
            -
            static inline NORETURN(void  | 
| 43 | 
            +
            static inline NORETURN(void raise_error(const char* name, const char* description))
         | 
| 44 44 | 
             
            {
         | 
| 45 45 | 
             
              VALUE module = rb_define_module(ZSTDS_EXT_MODULE_NAME);
         | 
| 46 46 | 
             
              VALUE error  = rb_const_get(module, rb_intern(name));
         | 
| @@ -51,30 +51,30 @@ void zstds_ext_raise_error(zstds_ext_result_t ext_result) | |
| 51 51 | 
             
            {
         | 
| 52 52 | 
             
              switch (ext_result) {
         | 
| 53 53 | 
             
                case ZSTDS_EXT_ERROR_ALLOCATE_FAILED:
         | 
| 54 | 
            -
                   | 
| 54 | 
            +
                  raise_error("AllocateError", "allocate error");
         | 
| 55 55 | 
             
                case ZSTDS_EXT_ERROR_VALIDATE_FAILED:
         | 
| 56 | 
            -
                   | 
| 56 | 
            +
                  raise_error("ValidateError", "validate error");
         | 
| 57 57 |  | 
| 58 58 | 
             
                case ZSTDS_EXT_ERROR_USED_AFTER_CLOSE:
         | 
| 59 | 
            -
                   | 
| 59 | 
            +
                  raise_error("UsedAfterCloseError", "used after closed");
         | 
| 60 60 | 
             
                case ZSTDS_EXT_ERROR_NOT_ENOUGH_SOURCE_BUFFER:
         | 
| 61 | 
            -
                   | 
| 61 | 
            +
                  raise_error("NotEnoughSourceBufferError", "not enough source buffer");
         | 
| 62 62 | 
             
                case ZSTDS_EXT_ERROR_NOT_ENOUGH_DESTINATION_BUFFER:
         | 
| 63 | 
            -
                   | 
| 63 | 
            +
                  raise_error("NotEnoughDestinationBufferError", "not enough destination buffer");
         | 
| 64 64 | 
             
                case ZSTDS_EXT_ERROR_DECOMPRESSOR_CORRUPTED_SOURCE:
         | 
| 65 | 
            -
                   | 
| 65 | 
            +
                  raise_error("DecompressorCorruptedSourceError", "decompressor received corrupted source");
         | 
| 66 66 | 
             
                case ZSTDS_EXT_ERROR_CORRUPTED_DICTIONARY:
         | 
| 67 | 
            -
                   | 
| 67 | 
            +
                  raise_error("CorruptedDictionaryError", "corrupted dictionary");
         | 
| 68 68 |  | 
| 69 69 | 
             
                case ZSTDS_EXT_ERROR_ACCESS_IO:
         | 
| 70 | 
            -
                   | 
| 70 | 
            +
                  raise_error("AccessIOError", "failed to access IO");
         | 
| 71 71 | 
             
                case ZSTDS_EXT_ERROR_READ_IO:
         | 
| 72 | 
            -
                   | 
| 72 | 
            +
                  raise_error("ReadIOError", "failed to read IO");
         | 
| 73 73 | 
             
                case ZSTDS_EXT_ERROR_WRITE_IO:
         | 
| 74 | 
            -
                   | 
| 74 | 
            +
                  raise_error("WriteIOError", "failed to write IO");
         | 
| 75 75 |  | 
| 76 76 | 
             
                default:
         | 
| 77 77 | 
             
                  // ZSTDS_EXT_ERROR_UNEXPECTED
         | 
| 78 | 
            -
                   | 
| 78 | 
            +
                  raise_error("UnexpectedError", "unexpected error");
         | 
| 79 79 | 
             
              }
         | 
| 80 80 | 
             
            }
         | 
    
        data/ext/zstds_ext/error.h
    CHANGED
    
    
    
        data/ext/zstds_ext/gvl.h
    ADDED
    
    | @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            // Ruby bindings for zstd library.
         | 
| 2 | 
            +
            // Copyright (c) 2019 AUTHORS, MIT License.
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            #if !defined(ZSTDS_EXT_GVL_H)
         | 
| 5 | 
            +
            #define ZSTDS_EXT_GVL_H
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            #include "ruby/thread.h"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            #define ZSTDS_EXT_GVL_WRAP(gvl, function, data)                            \
         | 
| 12 | 
            +
              if (gvl) {                                                               \
         | 
| 13 | 
            +
                function((void*) data);                                                \
         | 
| 14 | 
            +
              } else {                                                                 \
         | 
| 15 | 
            +
                rb_thread_call_without_gvl(function, (void*) data, RUBY_UBF_IO, NULL); \
         | 
| 16 | 
            +
              }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            #else
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            #define ZSTDS_EXT_GVL_WRAP(_gvl, function, data) function((void*) data);
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            #endif
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            #endif // ZSTDS_EXT_GVL_H
         | 
    
        data/ext/zstds_ext/io.c
    CHANGED
    
    | @@ -1,26 +1,29 @@ | |
| 1 1 | 
             
            // Ruby bindings for zstd library.
         | 
| 2 2 | 
             
            // Copyright (c) 2019 AUTHORS, MIT License.
         | 
| 3 3 |  | 
| 4 | 
            -
            #include " | 
| 4 | 
            +
            #include "zstds_ext/io.h"
         | 
| 5 5 |  | 
| 6 6 | 
             
            #include <stdio.h>
         | 
| 7 7 | 
             
            #include <string.h>
         | 
| 8 8 | 
             
            #include <zstd.h>
         | 
| 9 9 |  | 
| 10 10 | 
             
            #include "ruby.h"
         | 
| 11 | 
            +
            #include "ruby/io.h"
         | 
| 11 12 | 
             
            #include "zstds_ext/error.h"
         | 
| 12 | 
            -
            #include "zstds_ext/ | 
| 13 | 
            +
            #include "zstds_ext/gvl.h"
         | 
| 13 14 | 
             
            #include "zstds_ext/macro.h"
         | 
| 14 15 | 
             
            #include "zstds_ext/option.h"
         | 
| 15 16 |  | 
| 16 17 | 
             
            // Additional possible results:
         | 
| 17 | 
            -
            enum | 
| 18 | 
            +
            enum
         | 
| 19 | 
            +
            {
         | 
| 18 20 | 
             
              ZSTDS_EXT_FILE_READ_FINISHED = 128
         | 
| 19 21 | 
             
            };
         | 
| 20 22 |  | 
| 21 23 | 
             
            // -- file --
         | 
| 22 24 |  | 
| 23 | 
            -
            static inline zstds_ext_result_t | 
| 25 | 
            +
            static inline zstds_ext_result_t
         | 
| 26 | 
            +
              read_file(FILE* source_file, zstds_ext_byte_t* source_buffer, size_t* source_length_ptr, size_t source_buffer_length)
         | 
| 24 27 | 
             
            {
         | 
| 25 28 | 
             
              size_t read_length = fread(source_buffer, 1, source_buffer_length, source_file);
         | 
| 26 29 | 
             
              if (read_length == 0 && feof(source_file)) {
         | 
| @@ -36,7 +39,8 @@ static inline zstds_ext_result_t read_file(FILE* source_file, zstds_ext_byte_t* | |
| 36 39 | 
             
              return 0;
         | 
| 37 40 | 
             
            }
         | 
| 38 41 |  | 
| 39 | 
            -
            static inline zstds_ext_result_t | 
| 42 | 
            +
            static inline zstds_ext_result_t
         | 
| 43 | 
            +
              write_file(FILE* destination_file, zstds_ext_byte_t* destination_buffer, size_t destination_length)
         | 
| 40 44 | 
             
            {
         | 
| 41 45 | 
             
              size_t written_length = fwrite(destination_buffer, 1, destination_length, destination_file);
         | 
| 42 46 | 
             
              if (written_length != destination_length) {
         | 
| @@ -49,8 +53,10 @@ static inline zstds_ext_result_t write_file(FILE* destination_file, zstds_ext_by | |
| 49 53 | 
             
            // -- buffer --
         | 
| 50 54 |  | 
| 51 55 | 
             
            static inline zstds_ext_result_t create_buffers(
         | 
| 52 | 
            -
              zstds_ext_byte_t** source_buffer_ptr, | 
| 53 | 
            -
               | 
| 56 | 
            +
              zstds_ext_byte_t** source_buffer_ptr,
         | 
| 57 | 
            +
              size_t             source_buffer_length,
         | 
| 58 | 
            +
              zstds_ext_byte_t** destination_buffer_ptr,
         | 
| 59 | 
            +
              size_t             destination_buffer_length)
         | 
| 54 60 | 
             
            {
         | 
| 55 61 | 
             
              zstds_ext_byte_t* source_buffer = malloc(source_buffer_length);
         | 
| 56 62 | 
             
              if (source_buffer == NULL) {
         | 
| @@ -77,8 +83,10 @@ static inline zstds_ext_result_t create_buffers( | |
| 77 83 |  | 
| 78 84 | 
             
            static inline zstds_ext_result_t read_more_source(
         | 
| 79 85 | 
             
              FILE*                    source_file,
         | 
| 80 | 
            -
              const zstds_ext_byte_t** source_ptr, | 
| 81 | 
            -
               | 
| 86 | 
            +
              const zstds_ext_byte_t** source_ptr,
         | 
| 87 | 
            +
              size_t*                  source_length_ptr,
         | 
| 88 | 
            +
              zstds_ext_byte_t*        source_buffer,
         | 
| 89 | 
            +
              size_t                   source_buffer_length)
         | 
| 82 90 | 
             
            {
         | 
| 83 91 | 
             
              const zstds_ext_byte_t* source        = *source_ptr;
         | 
| 84 92 | 
             
              size_t                  source_length = *source_length_ptr;
         | 
| @@ -101,7 +109,9 @@ static inline zstds_ext_result_t read_more_source( | |
| 101 109 | 
             
              zstds_ext_byte_t* remaining_source_buffer = source_buffer + source_length;
         | 
| 102 110 | 
             
              size_t            new_source_length;
         | 
| 103 111 |  | 
| 104 | 
            -
              zstds_ext_result_t ext_result = | 
| 112 | 
            +
              zstds_ext_result_t ext_result =
         | 
| 113 | 
            +
                read_file(source_file, remaining_source_buffer, &new_source_length, remaining_source_buffer_length);
         | 
| 114 | 
            +
             | 
| 105 115 | 
             
              if (ext_result != 0) {
         | 
| 106 116 | 
             
                return ext_result;
         | 
| 107 117 | 
             
              }
         | 
| @@ -111,42 +121,37 @@ static inline zstds_ext_result_t read_more_source( | |
| 111 121 | 
             
              return 0;
         | 
| 112 122 | 
             
            }
         | 
| 113 123 |  | 
| 114 | 
            -
            #define BUFFERED_READ_SOURCE(function, ...) | 
| 115 | 
            -
              do { | 
| 116 | 
            -
                bool is_function_called = false; | 
| 117 | 
            -
             | 
| 118 | 
            -
                while (true) { | 
| 119 | 
            -
                  ext_result = read_more_source( | 
| 120 | 
            -
             | 
| 121 | 
            -
                     | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
             | 
| 125 | 
            -
                     | 
| 126 | 
            -
             | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 129 | 
            -
             | 
| 130 | 
            -
                   | 
| 131 | 
            -
                   | 
| 132 | 
            -
                    return ext_result; | 
| 133 | 
            -
                  } | 
| 134 | 
            -
             | 
| 135 | 
            -
                   | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
                                                                        \
         | 
| 140 | 
            -
                   | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
                  ext_result = function(__VA_ARGS__);                   \
         | 
| 146 | 
            -
                  if (ext_result != 0) {                                \
         | 
| 147 | 
            -
                    return ext_result;                                  \
         | 
| 148 | 
            -
                  }                                                     \
         | 
| 149 | 
            -
                }                                                       \
         | 
| 124 | 
            +
            #define BUFFERED_READ_SOURCE(function, ...)                                                                     \
         | 
| 125 | 
            +
              do {                                                                                                          \
         | 
| 126 | 
            +
                bool is_function_called = false;                                                                            \
         | 
| 127 | 
            +
                                                                                                                            \
         | 
| 128 | 
            +
                while (true) {                                                                                              \
         | 
| 129 | 
            +
                  ext_result = read_more_source(source_file, &source, &source_length, source_buffer, source_buffer_length); \
         | 
| 130 | 
            +
                  if (ext_result == ZSTDS_EXT_FILE_READ_FINISHED) {                                                         \
         | 
| 131 | 
            +
                    if (source_length != 0) {                                                                               \
         | 
| 132 | 
            +
                      /* ZSTD won't provide any remainder by design. */                                                     \
         | 
| 133 | 
            +
                      return ZSTDS_EXT_ERROR_READ_IO;                                                                       \
         | 
| 134 | 
            +
                    }                                                                                                       \
         | 
| 135 | 
            +
                    break;                                                                                                  \
         | 
| 136 | 
            +
                  } else if (ext_result != 0) {                                                                             \
         | 
| 137 | 
            +
                    return ext_result;                                                                                      \
         | 
| 138 | 
            +
                  }                                                                                                         \
         | 
| 139 | 
            +
                                                                                                                            \
         | 
| 140 | 
            +
                  ext_result = function(__VA_ARGS__);                                                                       \
         | 
| 141 | 
            +
                  if (ext_result != 0) {                                                                                    \
         | 
| 142 | 
            +
                    return ext_result;                                                                                      \
         | 
| 143 | 
            +
                  }                                                                                                         \
         | 
| 144 | 
            +
                                                                                                                            \
         | 
| 145 | 
            +
                  is_function_called = true;                                                                                \
         | 
| 146 | 
            +
                }                                                                                                           \
         | 
| 147 | 
            +
                                                                                                                            \
         | 
| 148 | 
            +
                if (!is_function_called) {                                                                                  \
         | 
| 149 | 
            +
                  /* Function should be called at least once. */                                                            \
         | 
| 150 | 
            +
                  ext_result = function(__VA_ARGS__);                                                                       \
         | 
| 151 | 
            +
                  if (ext_result != 0) {                                                                                    \
         | 
| 152 | 
            +
                    return ext_result;                                                                                      \
         | 
| 153 | 
            +
                  }                                                                                                         \
         | 
| 154 | 
            +
                }                                                                                                           \
         | 
| 150 155 | 
             
              } while (false);
         | 
| 151 156 |  | 
| 152 157 | 
             
            // Algorithm has written data into destination buffer.
         | 
| @@ -155,7 +160,9 @@ static inline zstds_ext_result_t read_more_source( | |
| 155 160 |  | 
| 156 161 | 
             
            static inline zstds_ext_result_t flush_destination_buffer(
         | 
| 157 162 | 
             
              FILE*             destination_file,
         | 
| 158 | 
            -
              zstds_ext_byte_t* destination_buffer, | 
| 163 | 
            +
              zstds_ext_byte_t* destination_buffer,
         | 
| 164 | 
            +
              size_t*           destination_length_ptr,
         | 
| 165 | 
            +
              size_t            destination_buffer_length)
         | 
| 159 166 | 
             
            {
         | 
| 160 167 | 
             
              if (*destination_length_ptr == 0) {
         | 
| 161 168 | 
             
                // We want to write more data at once, than buffer has.
         | 
| @@ -172,7 +179,8 @@ static inline zstds_ext_result_t flush_destination_buffer( | |
| 172 179 | 
             
              return 0;
         | 
| 173 180 | 
             
            }
         | 
| 174 181 |  | 
| 175 | 
            -
            static inline zstds_ext_result_t | 
| 182 | 
            +
            static inline zstds_ext_result_t
         | 
| 183 | 
            +
              write_remaining_destination(FILE* destination_file, zstds_ext_byte_t* destination_buffer, size_t destination_length)
         | 
| 176 184 | 
             
            {
         | 
| 177 185 | 
             
              if (destination_length == 0) {
         | 
| 178 186 | 
             
                return 0;
         | 
| @@ -194,39 +202,57 @@ static inline zstds_ext_result_t write_remaining_destination(FILE* destination_f | |
| 194 202 | 
             
                zstds_ext_raise_error(ZSTDS_EXT_ERROR_ACCESS_IO);  \
         | 
| 195 203 | 
             
              }
         | 
| 196 204 |  | 
| 197 | 
            -
            // -- compress --
         | 
| 205 | 
            +
            // -- buffered compress --
         | 
| 206 | 
            +
             | 
| 207 | 
            +
            typedef struct
         | 
| 208 | 
            +
            {
         | 
| 209 | 
            +
              ZSTD_CCtx*      ctx;
         | 
| 210 | 
            +
              ZSTD_inBuffer*  in_buffer_ptr;
         | 
| 211 | 
            +
              ZSTD_outBuffer* out_buffer_ptr;
         | 
| 212 | 
            +
              zstds_result_t  result;
         | 
| 213 | 
            +
            } compress_args_t;
         | 
| 214 | 
            +
             | 
| 215 | 
            +
            static inline void* compress_wrapper(void* data)
         | 
| 216 | 
            +
            {
         | 
| 217 | 
            +
              compress_args_t* args = data;
         | 
| 218 | 
            +
             | 
| 219 | 
            +
              args->result = ZSTD_compressStream2(args->ctx, args->out_buffer_ptr, args->in_buffer_ptr, ZSTD_e_continue);
         | 
| 220 | 
            +
             | 
| 221 | 
            +
              return NULL;
         | 
| 222 | 
            +
            }
         | 
| 198 223 |  | 
| 199 224 | 
             
            static inline zstds_ext_result_t buffered_compress(
         | 
| 200 225 | 
             
              ZSTD_CCtx*               ctx,
         | 
| 201 | 
            -
              const zstds_ext_byte_t** source_ptr, | 
| 202 | 
            -
               | 
| 226 | 
            +
              const zstds_ext_byte_t** source_ptr,
         | 
| 227 | 
            +
              size_t*                  source_length_ptr,
         | 
| 228 | 
            +
              FILE*                    destination_file,
         | 
| 229 | 
            +
              zstds_ext_byte_t*        destination_buffer,
         | 
| 230 | 
            +
              size_t*                  destination_length_ptr,
         | 
| 231 | 
            +
              size_t                   destination_buffer_length,
         | 
| 232 | 
            +
              bool                     gvl)
         | 
| 203 233 | 
             
            {
         | 
| 204 | 
            -
              zstds_result_t     result;
         | 
| 205 234 | 
             
              zstds_ext_result_t ext_result;
         | 
| 206 | 
            -
             | 
| 207 | 
            -
               | 
| 208 | 
            -
              in_buffer.src  = *source_ptr;
         | 
| 209 | 
            -
              in_buffer.size = *source_length_ptr;
         | 
| 210 | 
            -
              in_buffer.pos  = 0;
         | 
| 211 | 
            -
             | 
| 212 | 
            -
              ZSTD_outBuffer out_buffer;
         | 
| 235 | 
            +
              ZSTD_inBuffer      in_buffer = {.src = *source_ptr, .size = *source_length_ptr, .pos = 0};
         | 
| 236 | 
            +
              compress_args_t    args      = {.ctx = ctx, .in_buffer_ptr = &in_buffer};
         | 
| 213 237 |  | 
| 214 238 | 
             
              while (true) {
         | 
| 215 | 
            -
                out_buffer | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 239 | 
            +
                ZSTD_outBuffer out_buffer = {
         | 
| 240 | 
            +
                  .dst  = destination_buffer + *destination_length_ptr,
         | 
| 241 | 
            +
                  .size = destination_buffer_length - *destination_length_ptr,
         | 
| 242 | 
            +
                  .pos  = 0};
         | 
| 218 243 |  | 
| 219 | 
            -
                 | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 244 | 
            +
                args.out_buffer_ptr = &out_buffer;
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                ZSTDS_EXT_GVL_WRAP(gvl, compress_wrapper, &args);
         | 
| 247 | 
            +
                if (ZSTD_isError(args.result)) {
         | 
| 248 | 
            +
                  return zstds_ext_get_error(ZSTD_getErrorCode(args.result));
         | 
| 222 249 | 
             
                }
         | 
| 223 250 |  | 
| 224 251 | 
             
                *destination_length_ptr += out_buffer.pos;
         | 
| 225 252 |  | 
| 226 253 | 
             
                if (*destination_length_ptr == destination_buffer_length) {
         | 
| 227 254 | 
             
                  ext_result = flush_destination_buffer(
         | 
| 228 | 
            -
                    destination_file,
         | 
| 229 | 
            -
                    destination_buffer, destination_length_ptr, destination_buffer_length);
         | 
| 255 | 
            +
                    destination_file, destination_buffer, destination_length_ptr, destination_buffer_length);
         | 
| 230 256 |  | 
| 231 257 | 
             
                  if (ext_result != 0) {
         | 
| 232 258 | 
             
                    return ext_result;
         | 
| @@ -244,36 +270,55 @@ static inline zstds_ext_result_t buffered_compress( | |
| 244 270 | 
             
              return 0;
         | 
| 245 271 | 
             
            }
         | 
| 246 272 |  | 
| 247 | 
            -
             | 
| 248 | 
            -
             | 
| 249 | 
            -
             | 
| 273 | 
            +
            // -- buffered compressor finish --
         | 
| 274 | 
            +
             | 
| 275 | 
            +
            typedef struct
         | 
| 250 276 | 
             
            {
         | 
| 251 | 
            -
               | 
| 252 | 
            -
               | 
| 277 | 
            +
              ZSTD_CCtx*      ctx;
         | 
| 278 | 
            +
              ZSTD_inBuffer*  in_buffer_ptr;
         | 
| 279 | 
            +
              ZSTD_outBuffer* out_buffer_ptr;
         | 
| 280 | 
            +
              zstds_result_t  result;
         | 
| 281 | 
            +
            } compressor_finish_args_t;
         | 
| 253 282 |  | 
| 254 | 
            -
             | 
| 255 | 
            -
             | 
| 256 | 
            -
               | 
| 257 | 
            -
              in_buffer.pos  = 0;
         | 
| 283 | 
            +
            static inline void* compressor_finish_wrapper(void* data)
         | 
| 284 | 
            +
            {
         | 
| 285 | 
            +
              compressor_finish_args_t* args = data;
         | 
| 258 286 |  | 
| 259 | 
            -
               | 
| 287 | 
            +
              args->result = ZSTD_compressStream2(args->ctx, args->out_buffer_ptr, args->in_buffer_ptr, ZSTD_e_end);
         | 
| 288 | 
            +
             | 
| 289 | 
            +
              return NULL;
         | 
| 290 | 
            +
            }
         | 
| 291 | 
            +
             | 
| 292 | 
            +
            static inline zstds_ext_result_t buffered_compressor_finish(
         | 
| 293 | 
            +
              ZSTD_CCtx*        ctx,
         | 
| 294 | 
            +
              FILE*             destination_file,
         | 
| 295 | 
            +
              zstds_ext_byte_t* destination_buffer,
         | 
| 296 | 
            +
              size_t*           destination_length_ptr,
         | 
| 297 | 
            +
              size_t            destination_buffer_length,
         | 
| 298 | 
            +
              bool              gvl)
         | 
| 299 | 
            +
            {
         | 
| 300 | 
            +
              zstds_ext_result_t       ext_result;
         | 
| 301 | 
            +
              ZSTD_inBuffer            in_buffer = {in_buffer.src = NULL, in_buffer.size = 0, in_buffer.pos = 0};
         | 
| 302 | 
            +
              compressor_finish_args_t args      = {.ctx = ctx, .in_buffer_ptr = &in_buffer};
         | 
| 260 303 |  | 
| 261 304 | 
             
              while (true) {
         | 
| 262 | 
            -
                out_buffer | 
| 263 | 
            -
             | 
| 264 | 
            -
             | 
| 305 | 
            +
                ZSTD_outBuffer out_buffer = {
         | 
| 306 | 
            +
                  out_buffer.dst  = destination_buffer + *destination_length_ptr,
         | 
| 307 | 
            +
                  out_buffer.size = destination_buffer_length - *destination_length_ptr,
         | 
| 308 | 
            +
                  out_buffer.pos  = 0};
         | 
| 265 309 |  | 
| 266 | 
            -
                 | 
| 267 | 
            -
             | 
| 268 | 
            -
             | 
| 310 | 
            +
                args.out_buffer_ptr = &out_buffer;
         | 
| 311 | 
            +
             | 
| 312 | 
            +
                ZSTDS_EXT_GVL_WRAP(gvl, compressor_finish_wrapper, &args);
         | 
| 313 | 
            +
                if (ZSTD_isError(args.result)) {
         | 
| 314 | 
            +
                  return zstds_ext_get_error(ZSTD_getErrorCode(args.result));
         | 
| 269 315 | 
             
                }
         | 
| 270 316 |  | 
| 271 317 | 
             
                *destination_length_ptr += out_buffer.pos;
         | 
| 272 318 |  | 
| 273 | 
            -
                if (result != 0) {
         | 
| 319 | 
            +
                if (args.result != 0) {
         | 
| 274 320 | 
             
                  ext_result = flush_destination_buffer(
         | 
| 275 | 
            -
                    destination_file,
         | 
| 276 | 
            -
                    destination_buffer, destination_length_ptr, destination_buffer_length);
         | 
| 321 | 
            +
                    destination_file, destination_buffer, destination_length_ptr, destination_buffer_length);
         | 
| 277 322 |  | 
| 278 323 | 
             
                  if (ext_result != 0) {
         | 
| 279 324 | 
             
                    return ext_result;
         | 
| @@ -288,13 +333,19 @@ static inline zstds_ext_result_t buffered_compressor_finish( | |
| 288 333 | 
             
              return 0;
         | 
| 289 334 | 
             
            }
         | 
| 290 335 |  | 
| 336 | 
            +
            // -- compress --
         | 
| 337 | 
            +
             | 
| 291 338 | 
             
            static inline zstds_ext_result_t compress(
         | 
| 292 | 
            -
              ZSTD_CCtx* | 
| 293 | 
            -
              FILE* | 
| 294 | 
            -
               | 
| 339 | 
            +
              ZSTD_CCtx*        ctx,
         | 
| 340 | 
            +
              FILE*             source_file,
         | 
| 341 | 
            +
              zstds_ext_byte_t* source_buffer,
         | 
| 342 | 
            +
              size_t            source_buffer_length,
         | 
| 343 | 
            +
              FILE*             destination_file,
         | 
| 344 | 
            +
              zstds_ext_byte_t* destination_buffer,
         | 
| 345 | 
            +
              size_t            destination_buffer_length,
         | 
| 346 | 
            +
              bool              gvl)
         | 
| 295 347 | 
             
            {
         | 
| 296 | 
            -
              zstds_ext_result_t | 
| 297 | 
            -
             | 
| 348 | 
            +
              zstds_ext_result_t      ext_result;
         | 
| 298 349 | 
             
              const zstds_ext_byte_t* source             = source_buffer;
         | 
| 299 350 | 
             
              size_t                  source_length      = 0;
         | 
| 300 351 | 
             
              size_t                  destination_length = 0;
         | 
| @@ -302,12 +353,16 @@ static inline zstds_ext_result_t compress( | |
| 302 353 | 
             
              BUFFERED_READ_SOURCE(
         | 
| 303 354 | 
             
                buffered_compress,
         | 
| 304 355 | 
             
                ctx,
         | 
| 305 | 
            -
                &source, | 
| 306 | 
            -
                 | 
| 356 | 
            +
                &source,
         | 
| 357 | 
            +
                &source_length,
         | 
| 358 | 
            +
                destination_file,
         | 
| 359 | 
            +
                destination_buffer,
         | 
| 360 | 
            +
                &destination_length,
         | 
| 361 | 
            +
                destination_buffer_length,
         | 
| 362 | 
            +
                gvl);
         | 
| 307 363 |  | 
| 308 364 | 
             
              ext_result = buffered_compressor_finish(
         | 
| 309 | 
            -
                ctx,
         | 
| 310 | 
            -
                destination_file, destination_buffer, &destination_length, destination_buffer_length);
         | 
| 365 | 
            +
                ctx, destination_file, destination_buffer, &destination_length, destination_buffer_length, gvl);
         | 
| 311 366 |  | 
| 312 367 | 
             
              if (ext_result != 0) {
         | 
| 313 368 | 
             
                return ext_result;
         | 
| @@ -321,9 +376,10 @@ VALUE zstds_ext_compress_io(VALUE ZSTDS_EXT_UNUSED(self), VALUE source, VALUE de | |
| 321 376 | 
             
              GET_FILE(source);
         | 
| 322 377 | 
             
              GET_FILE(destination);
         | 
| 323 378 | 
             
              Check_Type(options, T_HASH);
         | 
| 379 | 
            +
              ZSTDS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
         | 
| 380 | 
            +
              ZSTDS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
         | 
| 381 | 
            +
              ZSTDS_EXT_GET_BOOL_OPTION(options, gvl);
         | 
| 324 382 | 
             
              ZSTDS_EXT_GET_COMPRESSOR_OPTIONS(options);
         | 
| 325 | 
            -
              ZSTDS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
         | 
| 326 | 
            -
              ZSTDS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
         | 
| 327 383 |  | 
| 328 384 | 
             
              ZSTD_CCtx* ctx = ZSTD_createCCtx();
         | 
| 329 385 | 
             
              if (ctx == NULL) {
         | 
| @@ -346,10 +402,7 @@ VALUE zstds_ext_compress_io(VALUE ZSTDS_EXT_UNUSED(self), VALUE source, VALUE de | |
| 346 402 | 
             
              zstds_ext_byte_t* source_buffer;
         | 
| 347 403 | 
             
              zstds_ext_byte_t* destination_buffer;
         | 
| 348 404 |  | 
| 349 | 
            -
              ext_result = create_buffers(
         | 
| 350 | 
            -
                &source_buffer, source_buffer_length,
         | 
| 351 | 
            -
                &destination_buffer, destination_buffer_length);
         | 
| 352 | 
            -
             | 
| 405 | 
            +
              ext_result = create_buffers(&source_buffer, source_buffer_length, &destination_buffer, destination_buffer_length);
         | 
| 353 406 | 
             
              if (ext_result != 0) {
         | 
| 354 407 | 
             
                ZSTD_freeCCtx(ctx);
         | 
| 355 408 | 
             
                zstds_ext_raise_error(ext_result);
         | 
| @@ -357,8 +410,13 @@ VALUE zstds_ext_compress_io(VALUE ZSTDS_EXT_UNUSED(self), VALUE source, VALUE de | |
| 357 410 |  | 
| 358 411 | 
             
              ext_result = compress(
         | 
| 359 412 | 
             
                ctx,
         | 
| 360 | 
            -
                source_file, | 
| 361 | 
            -
                 | 
| 413 | 
            +
                source_file,
         | 
| 414 | 
            +
                source_buffer,
         | 
| 415 | 
            +
                source_buffer_length,
         | 
| 416 | 
            +
                destination_file,
         | 
| 417 | 
            +
                destination_buffer,
         | 
| 418 | 
            +
                destination_buffer_length,
         | 
| 419 | 
            +
                gvl);
         | 
| 362 420 |  | 
| 363 421 | 
             
              free(source_buffer);
         | 
| 364 422 | 
             
              free(destination_buffer);
         | 
| @@ -374,39 +432,57 @@ VALUE zstds_ext_compress_io(VALUE ZSTDS_EXT_UNUSED(self), VALUE source, VALUE de | |
| 374 432 | 
             
              return Qnil;
         | 
| 375 433 | 
             
            }
         | 
| 376 434 |  | 
| 377 | 
            -
            // -- decompress --
         | 
| 435 | 
            +
            // -- buffered decompress --
         | 
| 436 | 
            +
             | 
| 437 | 
            +
            typedef struct
         | 
| 438 | 
            +
            {
         | 
| 439 | 
            +
              ZSTD_DCtx*      ctx;
         | 
| 440 | 
            +
              ZSTD_inBuffer*  in_buffer_ptr;
         | 
| 441 | 
            +
              ZSTD_outBuffer* out_buffer_ptr;
         | 
| 442 | 
            +
              zstds_result_t  result;
         | 
| 443 | 
            +
            } decompress_args_t;
         | 
| 444 | 
            +
             | 
| 445 | 
            +
            static inline void* decompress_wrapper(void* data)
         | 
| 446 | 
            +
            {
         | 
| 447 | 
            +
              decompress_args_t* args = data;
         | 
| 448 | 
            +
             | 
| 449 | 
            +
              args->result = ZSTD_decompressStream(args->ctx, args->out_buffer_ptr, args->in_buffer_ptr);
         | 
| 450 | 
            +
             | 
| 451 | 
            +
              return NULL;
         | 
| 452 | 
            +
            }
         | 
| 378 453 |  | 
| 379 454 | 
             
            static inline zstds_ext_result_t buffered_decompress(
         | 
| 380 455 | 
             
              ZSTD_DCtx*               ctx,
         | 
| 381 | 
            -
              const zstds_ext_byte_t** source_ptr, | 
| 382 | 
            -
               | 
| 456 | 
            +
              const zstds_ext_byte_t** source_ptr,
         | 
| 457 | 
            +
              size_t*                  source_length_ptr,
         | 
| 458 | 
            +
              FILE*                    destination_file,
         | 
| 459 | 
            +
              zstds_ext_byte_t*        destination_buffer,
         | 
| 460 | 
            +
              size_t*                  destination_length_ptr,
         | 
| 461 | 
            +
              size_t                   destination_buffer_length,
         | 
| 462 | 
            +
              bool                     gvl)
         | 
| 383 463 | 
             
            {
         | 
| 384 | 
            -
              zstds_result_t     result;
         | 
| 385 464 | 
             
              zstds_ext_result_t ext_result;
         | 
| 386 | 
            -
             | 
| 387 | 
            -
               | 
| 388 | 
            -
              in_buffer.src  = *source_ptr;
         | 
| 389 | 
            -
              in_buffer.size = *source_length_ptr;
         | 
| 390 | 
            -
              in_buffer.pos  = 0;
         | 
| 391 | 
            -
             | 
| 392 | 
            -
              ZSTD_outBuffer out_buffer;
         | 
| 465 | 
            +
              ZSTD_inBuffer      in_buffer = {.src = *source_ptr, .size = *source_length_ptr, .pos = 0};
         | 
| 466 | 
            +
              decompress_args_t  args      = {.ctx = ctx, .in_buffer_ptr = &in_buffer};
         | 
| 393 467 |  | 
| 394 468 | 
             
              while (true) {
         | 
| 395 | 
            -
                out_buffer | 
| 396 | 
            -
             | 
| 397 | 
            -
             | 
| 469 | 
            +
                ZSTD_outBuffer out_buffer = {
         | 
| 470 | 
            +
                  .dst  = destination_buffer + *destination_length_ptr,
         | 
| 471 | 
            +
                  .size = destination_buffer_length - *destination_length_ptr,
         | 
| 472 | 
            +
                  .pos  = 0};
         | 
| 473 | 
            +
             | 
| 474 | 
            +
                args.out_buffer_ptr = &out_buffer;
         | 
| 398 475 |  | 
| 399 | 
            -
                 | 
| 400 | 
            -
                if (ZSTD_isError(result)) {
         | 
| 401 | 
            -
                  return zstds_ext_get_error(ZSTD_getErrorCode(result));
         | 
| 476 | 
            +
                ZSTDS_EXT_GVL_WRAP(gvl, decompress_wrapper, &args);
         | 
| 477 | 
            +
                if (ZSTD_isError(args.result)) {
         | 
| 478 | 
            +
                  return zstds_ext_get_error(ZSTD_getErrorCode(args.result));
         | 
| 402 479 | 
             
                }
         | 
| 403 480 |  | 
| 404 481 | 
             
                *destination_length_ptr += out_buffer.pos;
         | 
| 405 482 |  | 
| 406 483 | 
             
                if (*destination_length_ptr == destination_buffer_length) {
         | 
| 407 484 | 
             
                  ext_result = flush_destination_buffer(
         | 
| 408 | 
            -
                    destination_file,
         | 
| 409 | 
            -
                    destination_buffer, destination_length_ptr, destination_buffer_length);
         | 
| 485 | 
            +
                    destination_file, destination_buffer, destination_length_ptr, destination_buffer_length);
         | 
| 410 486 |  | 
| 411 487 | 
             
                  if (ext_result != 0) {
         | 
| 412 488 | 
             
                    return ext_result;
         | 
| @@ -424,13 +500,19 @@ static inline zstds_ext_result_t buffered_decompress( | |
| 424 500 | 
             
              return 0;
         | 
| 425 501 | 
             
            }
         | 
| 426 502 |  | 
| 503 | 
            +
            // -- decompress --
         | 
| 504 | 
            +
             | 
| 427 505 | 
             
            static inline zstds_ext_result_t decompress(
         | 
| 428 | 
            -
              ZSTD_DCtx* | 
| 429 | 
            -
              FILE* | 
| 430 | 
            -
               | 
| 506 | 
            +
              ZSTD_DCtx*        ctx,
         | 
| 507 | 
            +
              FILE*             source_file,
         | 
| 508 | 
            +
              zstds_ext_byte_t* source_buffer,
         | 
| 509 | 
            +
              size_t            source_buffer_length,
         | 
| 510 | 
            +
              FILE*             destination_file,
         | 
| 511 | 
            +
              zstds_ext_byte_t* destination_buffer,
         | 
| 512 | 
            +
              size_t            destination_buffer_length,
         | 
| 513 | 
            +
              bool              gvl)
         | 
| 431 514 | 
             
            {
         | 
| 432 | 
            -
              zstds_ext_result_t | 
| 433 | 
            -
             | 
| 515 | 
            +
              zstds_ext_result_t      ext_result;
         | 
| 434 516 | 
             
              const zstds_ext_byte_t* source             = source_buffer;
         | 
| 435 517 | 
             
              size_t                  source_length      = 0;
         | 
| 436 518 | 
             
              size_t                  destination_length = 0;
         | 
| @@ -438,8 +520,13 @@ static inline zstds_ext_result_t decompress( | |
| 438 520 | 
             
              BUFFERED_READ_SOURCE(
         | 
| 439 521 | 
             
                buffered_decompress,
         | 
| 440 522 | 
             
                ctx,
         | 
| 441 | 
            -
                &source, | 
| 442 | 
            -
                 | 
| 523 | 
            +
                &source,
         | 
| 524 | 
            +
                &source_length,
         | 
| 525 | 
            +
                destination_file,
         | 
| 526 | 
            +
                destination_buffer,
         | 
| 527 | 
            +
                &destination_length,
         | 
| 528 | 
            +
                destination_buffer_length,
         | 
| 529 | 
            +
                gvl);
         | 
| 443 530 |  | 
| 444 531 | 
             
              return write_remaining_destination(destination_file, destination_buffer, destination_length);
         | 
| 445 532 | 
             
            }
         | 
| @@ -449,9 +536,10 @@ VALUE zstds_ext_decompress_io(VALUE ZSTDS_EXT_UNUSED(self), VALUE source, VALUE | |
| 449 536 | 
             
              GET_FILE(source);
         | 
| 450 537 | 
             
              GET_FILE(destination);
         | 
| 451 538 | 
             
              Check_Type(options, T_HASH);
         | 
| 539 | 
            +
              ZSTDS_EXT_GET_SIZE_OPTION(options, source_buffer_length);
         | 
| 540 | 
            +
              ZSTDS_EXT_GET_SIZE_OPTION(options, destination_buffer_length);
         | 
| 541 | 
            +
              ZSTDS_EXT_GET_BOOL_OPTION(options, gvl);
         | 
| 452 542 | 
             
              ZSTDS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
         | 
| 453 | 
            -
              ZSTDS_EXT_GET_BUFFER_LENGTH_OPTION(options, source_buffer_length);
         | 
| 454 | 
            -
              ZSTDS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
         | 
| 455 543 |  | 
| 456 544 | 
             
              ZSTD_DCtx* ctx = ZSTD_createDCtx();
         | 
| 457 545 | 
             
              if (ctx == NULL) {
         | 
| @@ -474,10 +562,7 @@ VALUE zstds_ext_decompress_io(VALUE ZSTDS_EXT_UNUSED(self), VALUE source, VALUE | |
| 474 562 | 
             
              zstds_ext_byte_t* source_buffer;
         | 
| 475 563 | 
             
              zstds_ext_byte_t* destination_buffer;
         | 
| 476 564 |  | 
| 477 | 
            -
              ext_result = create_buffers(
         | 
| 478 | 
            -
                &source_buffer, source_buffer_length,
         | 
| 479 | 
            -
                &destination_buffer, destination_buffer_length);
         | 
| 480 | 
            -
             | 
| 565 | 
            +
              ext_result = create_buffers(&source_buffer, source_buffer_length, &destination_buffer, destination_buffer_length);
         | 
| 481 566 | 
             
              if (ext_result != 0) {
         | 
| 482 567 | 
             
                ZSTD_freeDCtx(ctx);
         | 
| 483 568 | 
             
                zstds_ext_raise_error(ext_result);
         | 
| @@ -485,8 +570,13 @@ VALUE zstds_ext_decompress_io(VALUE ZSTDS_EXT_UNUSED(self), VALUE source, VALUE | |
| 485 570 |  | 
| 486 571 | 
             
              ext_result = decompress(
         | 
| 487 572 | 
             
                ctx,
         | 
| 488 | 
            -
                source_file, | 
| 489 | 
            -
                 | 
| 573 | 
            +
                source_file,
         | 
| 574 | 
            +
                source_buffer,
         | 
| 575 | 
            +
                source_buffer_length,
         | 
| 576 | 
            +
                destination_file,
         | 
| 577 | 
            +
                destination_buffer,
         | 
| 578 | 
            +
                destination_buffer_length,
         | 
| 579 | 
            +
                gvl);
         | 
| 490 580 |  | 
| 491 581 | 
             
              free(source_buffer);
         | 
| 492 582 | 
             
              free(destination_buffer);
         | 
| @@ -502,6 +592,8 @@ VALUE zstds_ext_decompress_io(VALUE ZSTDS_EXT_UNUSED(self), VALUE source, VALUE | |
| 502 592 | 
             
              return Qnil;
         | 
| 503 593 | 
             
            }
         | 
| 504 594 |  | 
| 595 | 
            +
            // -- exports --
         | 
| 596 | 
            +
             | 
| 505 597 | 
             
            void zstds_ext_io_exports(VALUE root_module)
         | 
| 506 598 | 
             
            {
         | 
| 507 599 | 
             
              rb_define_module_function(root_module, "_native_compress_io", RUBY_METHOD_FUNC(zstds_ext_compress_io), 3);
         |