From 6d603deeb1f741aabe8cb66054135f3be7dbfb65 Mon Sep 17 00:00:00 2001 From: Lars Hvam Date: Sat, 17 Feb 2018 12:41:20 +0100 Subject: [PATCH] git: optimize type_and_length (#1208) * add unit tests * optimize type_and_length this is around 10 times faster --- src/git/zcl_abapgit_git_pack.clas.abap | 92 ++++++++------- ...zcl_abapgit_git_pack.clas.testclasses.abap | 109 ++++++++++++------ 2 files changed, 125 insertions(+), 76 deletions(-) diff --git a/src/git/zcl_abapgit_git_pack.clas.abap b/src/git/zcl_abapgit_git_pack.clas.abap index 869ef9254..a71cc18c7 100644 --- a/src/git/zcl_abapgit_git_pack.clas.abap +++ b/src/git/zcl_abapgit_git_pack.clas.abap @@ -758,66 +758,72 @@ CLASS ZCL_ABAPGIT_GIT_PACK IMPLEMENTATION. METHOD type_and_length. - DATA: lv_bits TYPE string, - lv_type TYPE string, - lv_result TYPE string, - lv_c TYPE c, - lv_offset TYPE i, - lv_x4 TYPE x LENGTH 4, - lv_x TYPE x LENGTH 1. +* see http://stefan.saasen.me/articles/git-clone-in-haskell-from-the-bottom-up/#pack_file_objects + + DATA: lv_result TYPE i, + lv_type TYPE i, + lv_length TYPE i, + lv_hex TYPE x LENGTH 1. CASE iv_type. WHEN zif_abapgit_definitions=>gc_type-commit. - lv_type = '001'. + lv_type = 16. WHEN zif_abapgit_definitions=>gc_type-tree. - lv_type = '010'. + lv_type = 32. WHEN zif_abapgit_definitions=>gc_type-blob. - lv_type = '011'. + lv_type = 48. WHEN zif_abapgit_definitions=>gc_type-ref_d. - lv_type = '111'. + lv_type = 112. WHEN OTHERS. zcx_abapgit_exception=>raise( 'Unexpected object type while encoding pack' ). ENDCASE. - lv_x4 = iv_length. - DO 32 TIMES. - GET BIT sy-index OF lv_x4 INTO lv_c. - CONCATENATE lv_bits lv_c INTO lv_bits. - ENDDO. + lv_length = iv_length. - IF lv_bits(28) = '0000000000000000000000000000'. - CONCATENATE '0' lv_type lv_bits+28(4) INTO lv_result. - ELSEIF lv_bits(21) = '000000000000000000000'. - CONCATENATE '1' lv_type lv_bits+28(4) INTO lv_result. - CONCATENATE lv_result '0' lv_bits+21(7) INTO lv_result. - ELSEIF lv_bits(14) = '00000000000000'. - CONCATENATE '1' lv_type lv_bits+28(4) INTO lv_result. - CONCATENATE lv_result '1' lv_bits+21(7) INTO lv_result. - CONCATENATE lv_result '0' lv_bits+14(7) INTO lv_result. - ELSEIF lv_bits(7) = '0000000'. - CONCATENATE '1' lv_type lv_bits+28(4) INTO lv_result. - CONCATENATE lv_result '1' lv_bits+21(7) INTO lv_result. - CONCATENATE lv_result '1' lv_bits+14(7) INTO lv_result. - CONCATENATE lv_result '0' lv_bits+7(7) INTO lv_result. + IF lv_length <= 15. + lv_hex = 0 + lv_type + lv_length MOD 16. + rv_xstring = lv_hex. + lv_length = lv_length DIV 16. + + ELSEIF lv_length <= 2047. + lv_hex = 128 + lv_type + lv_length MOD 16. + rv_xstring = lv_hex. + lv_length = lv_length DIV 16. + + lv_hex = lv_length. + CONCATENATE rv_xstring lv_hex INTO rv_xstring IN BYTE MODE. + ELSEIF lv_length <= 262143. + lv_hex = 128 + lv_type + lv_length MOD 16. + rv_xstring = lv_hex. + lv_length = lv_length DIV 16. + + lv_hex = 128 + lv_length MOD 128. + CONCATENATE rv_xstring lv_hex INTO rv_xstring IN BYTE MODE. + lv_length = lv_length DIV 128. + + lv_hex = lv_length. + CONCATENATE rv_xstring lv_hex INTO rv_xstring IN BYTE MODE. + ELSEIF lv_length <= 33554431. + lv_hex = 128 + lv_type + lv_length MOD 16. + rv_xstring = lv_hex. + lv_length = lv_length DIV 16. + + lv_hex = 128 + lv_length MOD 128. + CONCATENATE rv_xstring lv_hex INTO rv_xstring IN BYTE MODE. + lv_length = lv_length DIV 128. + + lv_hex = 128 + lv_length MOD 128. + CONCATENATE rv_xstring lv_hex INTO rv_xstring IN BYTE MODE. + lv_length = lv_length DIV 128. + + lv_hex = lv_length. + CONCATENATE rv_xstring lv_hex INTO rv_xstring IN BYTE MODE. ELSE. * this IF can be refactored, use shifting? zcx_abapgit_exception=>raise( 'Todo, encoding length' ). ENDIF. -* convert bit string to xstring - CLEAR lv_x. - DO strlen( lv_result ) TIMES. - lv_offset = sy-index - 1. - IF lv_result+lv_offset(1) = '1'. - SET BIT ( lv_offset MOD 8 ) + 1 OF lv_x. - ENDIF. - IF ( lv_offset + 1 ) MOD 8 = 0. - CONCATENATE rv_xstring lv_x INTO rv_xstring IN BYTE MODE. - CLEAR lv_x. - ENDIF. - ENDDO. - ENDMETHOD. "type_and_length diff --git a/src/git/zcl_abapgit_git_pack.clas.testclasses.abap b/src/git/zcl_abapgit_git_pack.clas.testclasses.abap index b1339d7c2..34529a054 100644 --- a/src/git/zcl_abapgit_git_pack.clas.testclasses.abap +++ b/src/git/zcl_abapgit_git_pack.clas.testclasses.abap @@ -1,42 +1,18 @@ -CLASS ltcl_pack DEFINITION DEFERRED. -CLASS zcl_abapgit_git_pack DEFINITION LOCAL FRIENDS ltcl_pack. +CLASS ltcl_type_and_length DEFINITION DEFERRED. +CLASS zcl_abapgit_git_pack DEFINITION LOCAL FRIENDS ltcl_type_and_length. -CLASS ltcl_pack DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. +CLASS ltcl_type_and_length DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. PRIVATE SECTION. - - CONSTANTS: c_sha TYPE zif_abapgit_definitions=>ty_sha1 VALUE '5f46cb3c4b7f0b3600b64f744cde614a283a88dc'. - METHODS: - tree FOR TESTING - RAISING zcx_abapgit_exception, - commit FOR TESTING - RAISING zcx_abapgit_exception, - commit_newline FOR TESTING - RAISING zcx_abapgit_exception, - pack_short FOR TESTING - RAISING zcx_abapgit_exception, - pack_long FOR TESTING - RAISING zcx_abapgit_exception, - pack_multiple FOR TESTING - RAISING zcx_abapgit_exception, - sort_tree1 FOR TESTING, - sort_tree2 FOR TESTING, - type_and_length01 FOR TESTING - RAISING zcx_abapgit_exception, - type_and_length02 FOR TESTING - RAISING zcx_abapgit_exception. + type_and_length01 FOR TESTING RAISING zcx_abapgit_exception, + type_and_length02 FOR TESTING RAISING zcx_abapgit_exception, + type_and_length03 FOR TESTING RAISING zcx_abapgit_exception, + type_and_length04 FOR TESTING RAISING zcx_abapgit_exception. - METHODS: - object_blob - IMPORTING iv_data TYPE xstring - RETURNING VALUE(rs_object) TYPE zif_abapgit_definitions=>ty_object - RAISING zcx_abapgit_exception. +ENDCLASS. -ENDCLASS. "ltcl_Pack - - -CLASS ltcl_pack IMPLEMENTATION. +CLASS ltcl_type_and_length IMPLEMENTATION. METHOD type_and_length01. @@ -66,6 +42,73 @@ CLASS ltcl_pack IMPLEMENTATION. ENDMETHOD. + METHOD type_and_length03. + + DATA: lv_result TYPE xstring. + + lv_result = zcl_abapgit_git_pack=>type_and_length( + iv_type = zif_abapgit_definitions=>gc_type-commit + iv_length = 10 ). + + cl_abap_unit_assert=>assert_equals( + act = lv_result + exp = '1A' ). + + ENDMETHOD. + + METHOD type_and_length04. + + DATA: lv_result TYPE xstring. + + lv_result = zcl_abapgit_git_pack=>type_and_length( + iv_type = zif_abapgit_definitions=>gc_type-commit + iv_length = 1000000 ). + + cl_abap_unit_assert=>assert_equals( + act = lv_result + exp = '90A4E803' ). + + ENDMETHOD. + +ENDCLASS. + + +CLASS ltcl_pack DEFINITION DEFERRED. +CLASS zcl_abapgit_git_pack DEFINITION LOCAL FRIENDS ltcl_pack. + +CLASS ltcl_pack DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS. + + PRIVATE SECTION. + + CONSTANTS: c_sha TYPE zif_abapgit_definitions=>ty_sha1 VALUE '5f46cb3c4b7f0b3600b64f744cde614a283a88dc'. + + METHODS: + tree FOR TESTING + RAISING zcx_abapgit_exception, + commit FOR TESTING + RAISING zcx_abapgit_exception, + commit_newline FOR TESTING + RAISING zcx_abapgit_exception, + pack_short FOR TESTING + RAISING zcx_abapgit_exception, + pack_long FOR TESTING + RAISING zcx_abapgit_exception, + pack_multiple FOR TESTING + RAISING zcx_abapgit_exception, + sort_tree1 FOR TESTING, + sort_tree2 FOR TESTING. + + METHODS: + object_blob + IMPORTING iv_data TYPE xstring + RETURNING VALUE(rs_object) TYPE zif_abapgit_definitions=>ty_object + RAISING zcx_abapgit_exception. + +ENDCLASS. "ltcl_Pack + + +CLASS ltcl_pack IMPLEMENTATION. + METHOD sort_tree1. DATA: lt_tree TYPE zcl_abapgit_git_pack=>ty_nodes_tt.