Downtime Announcement: Please note the SAP Community Wiki will be unavailable due to a system upgrade on Thursday, September 24th between 6 and 7 AM CEST
Skip to end of metadata
Go to start of metadata

Author: JNN
Submitted: <date>
Related Links:

Contribution: MIN/MAX from any table

Class Diagram

The utility is accessed by calling the single static method TOP( ) of abstract class LCL_QUEUE. It is meant to return the top of a priority queue filled from the internal table entries according to a selected evaluation method.

Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
 TRY.
      lcl_queue=>top( EXPORTING it_table = lt_map
                                iv_column = 'TEXT'
                                iv_eval = lcl_queue=>c_min
                      IMPORTING ev_top = lv_act ).
    CATCH cx_dynamic_check cx_static_check.
*      Error handling
    ENDTRY.

A priority queue is an abstract data type (ADT) that support addition of data, but only retrieval of the data on the top. In our case, the top will be the maximum or the minimum value.

We also retrieve the average value, but this is not an generally supported by ADT as it will only work for numerical data. A more generic concept would be to retrieve a mean value. 

 

 Some notes: 

  • if you are not running Netweaver 7.40 SP05, use version 12 from the page history
  • If you are not running Netweaver 7.02, the some changes are needed, hopefully minor changes
  • I have extended the orginal logic to work with internal table without a structure. In this case, the IV_COLUMN parameter can be omitted
  • Further, the logic now accepts SORTED and HASHED internal tables without error.
  • The ABAP mechanism to auto sort an internal table according to the target table primary key while copying is used.
  • I could not get the unit test for LCL_LINE_QUEUE to work, check the comment in code. So currently the code only returns values, not complete table lines.
  • The test code uses a random number generator with a constant seed of 42 to consistently provide the same data.

    Start at the bottom and check/debug the test methods of test class LTC_QUEUE.
Error rendering macro 'code': Invalid value specified for parameter 'com.atlassian.confluence.ext.code.render.InvalidValueException'
REPORT zz_priority_queue.
INTERFACE lif_unit_test.
ENDINTERFACE.                    "lif_unit_test
*----------------------------------------------------------------------*
*       CLASS lcl_queue DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_queue DEFINITION ABSTRACT CREATE PROTECTED.
  PUBLIC SECTION.
    TYPES tv_eval TYPE byte.
    CONSTANTS:
      c_min  TYPE tv_eval VALUE 0,  " minimum
      c_max  TYPE tv_eval VALUE 1,  " maximum entry in the queue
      c_mean TYPE tv_eval VALUE 2,  " median entry in the queue
                                    " for numerical entries only:
      c_avg TYPE tv_eval VALUE 10.  " average value of all queue entries
    CLASS-METHODS factory
      IMPORTING it_table  TYPE ANY TABLE
                iv_column TYPE name_feld DEFAULT space
                iv_eval   TYPE tv_eval DEFAULT c_max
                iv_line   TYPE flag DEFAULT space
      RETURNING VALUE(ro_queue) TYPE REF TO lcl_queue
      RAISING cx_static_check.
    CLASS-METHODS top
      IMPORTING it_table  TYPE ANY TABLE
                iv_column TYPE name_feld DEFAULT space
                iv_eval   TYPE tv_eval DEFAULT c_max
                iv_line   TYPE flag DEFAULT space
      EXPORTING ev_top    TYPE any
      RAISING   cx_dynamic_check cx_static_check.
  PROTECTED SECTION.
    DATA mr_table TYPE REF TO data.
    DATA mv_column TYPE name_feld.
    DATA mv_top_index TYPE syindex.
    METHODS eval ABSTRACT
      EXPORTING ev_val TYPE any
      RAISING cx_dynamic_check cx_static_check.
    METHODS constructor
      IMPORTING it_table  TYPE ANY TABLE
                iv_column TYPE name_feld
                iv_top_index TYPE syindex.
    METHODS sort_by
      IMPORTING it_source TYPE ANY TABLE
      CHANGING  cv_any    TYPE any
      RAISING   cx_list_error.
    METHODS min_max
      EXPORTING es_line TYPE any
                ev_val  TYPE any
      RAISING   cx_list_error.
ENDCLASS.                    "lcl_queue DEFINITION


*----------------------------------------------------------------------*
*       CLASS lcl_line_queue DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_line_queue DEFINITION CREATE PROTECTED
  INHERITING FROM lcl_queue FRIENDS lcl_queue lif_unit_test.
  PROTECTED SECTION.
    METHODS eval REDEFINITION.
ENDCLASS.                    "lcl_line_queue DEFINITION


*----------------------------------------------------------------------*
*       CLASS lcl_priority_queue DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_priority_queue DEFINITION CREATE PROTECTED
  INHERITING FROM lcl_queue FRIENDS lcl_queue lif_unit_test.
  PROTECTED SECTION.
    METHODS eval REDEFINITION.
ENDCLASS.                    "lcl_priority_queue DEFINITION


*----------------------------------------------------------------------*
*       CLASS lcl_average_queue DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_average_queue DEFINITION CREATE PROTECTED
  INHERITING FROM lcl_queue FRIENDS lcl_queue lif_unit_test.
  PUBLIC SECTION.
    TYPES tv_avg TYPE f.
    CONSTANTS c_avg_tol TYPE f VALUE '1e-6'.
  PROTECTED SECTION.
    METHODS eval REDEFINITION.
ENDCLASS.


*----------------------------------------------------------------------*
CLASS lcl_queue IMPLEMENTATION.
  METHOD constructor.
    super->constructor( ).
    mr_table = REF #( it_table ).
    mv_column = iv_column.
    mv_top_index = iv_top_index.
  ENDMETHOD.
  METHOD factory.
    DATA(lv_linecount) = lines( it_table ).
    DATA(lv_top_index) = SWITCH syindex( iv_eval
      WHEN c_max THEN lv_linecount                 " (max) - get from index mv_linecount
      WHEN c_min THEN 1                            " (min) - get from index 1
      WHEN c_mean THEN ( lv_linecount + 1 ) / 2    " (mean) - get from median index
      ELSE 0 ).
    CASE iv_eval.
      WHEN c_min OR c_max OR c_mean.
        ro_queue = SWITCH #( iv_line
          WHEN abap_true THEN
            NEW lcl_line_queue( it_table  = it_table
                                iv_column = iv_column
                                iv_top_index = lv_top_index )
          ELSE
            NEW lcl_priority_queue( it_table  = it_table
                                    iv_column = iv_column
                                    iv_top_index = lv_top_index )  ).
      WHEN c_avg.
        ro_queue = SWITCH #( iv_line
          WHEN abap_false THEN
            NEW lcl_average_queue( it_table  = it_table
                                   iv_column = iv_column
                                   iv_top_index = lv_top_index )
          ELSE THROW cx_list_error( )  ).
      WHEN OTHERS.
         RAISE EXCEPTION TYPE cx_list_error.
    ENDCASE.
  ENDMETHOD.                    "constructor
  METHOD top.
    factory( iv_line = iv_line
             it_table  = it_table
             iv_column = iv_column
             iv_eval   = iv_eval )->eval( IMPORTING ev_val = ev_top ).
  ENDMETHOD.                    "top
  METHOD sort_by.
    FIELD-SYMBOLS <lt_copy> TYPE SORTED TABLE.
    FIELD-SYMBOLS <ls_line> TYPE any.
    DATA lr_copy TYPE REF TO data.
    DATA lt_keytab TYPE STANDARD TABLE OF name_feld.
    ASSIGN cv_any TO <ls_line>.
*   Create sorted copy
    IF mv_column IS INITIAL.
      APPEND 'TABLE_LINE' TO lt_keytab.
    ELSE.
      APPEND mv_column TO lt_keytab.
    ENDIF.
    DATA(lv_linecount) = lines( it_source ).
    CREATE DATA lr_copy
      LIKE SORTED TABLE OF <ls_line>
      WITH NON-UNIQUE KEY (lt_keytab)
      INITIAL SIZE lv_linecount.
    ASSIGN lr_copy->* TO <lt_copy>.
    <lt_copy>[] = it_source[].
    READ TABLE <lt_copy> INDEX mv_top_index INTO <ls_line>.
    IF sy-subrc NE 0.
      RAISE EXCEPTION TYPE cx_list_error_empty_list.
    ENDIF.
  ENDMETHOD.
  METHOD min_max.
*   Logic for max/min calculation
    FIELD-SYMBOLS <ls_line> TYPE any.   " structure
    FIELD-SYMBOLS <lv_data> TYPE any.   " field
    FIELD-SYMBOLS <lt_source> TYPE ANY TABLE.
    DATA lr_line TYPE REF TO data.
    ASSIGN mr_table->* TO <lt_source>.     " Source table
*   work area for line of table
    CREATE DATA lr_line LIKE LINE OF <lt_source>.
    ASSIGN lr_line->* TO <ls_line>.
    sort_by( EXPORTING it_source = <lt_source>[]
             CHANGING cv_any = <ls_line> ).
    IF es_line IS REQUESTED.
*     ABAP expects a character like type if no type is specified, so the
*     assignment triggers a run-time error UC_OBJECTS_NOT_CONVERTIBLE for
*     structures with non-character data types. Return only if requested:
      es_line = <ls_line>.
    ENDIF.
    IF ev_val IS REQUESTED.
*     returns the component in the structure or the whole structure
      IF mv_column IS INITIAL.
        ev_val = <ls_line>.
      ELSE.
        ASSIGN COMPONENT mv_column OF STRUCTURE <ls_line> TO <lv_data>.
        ev_val = <lv_data>.
      ENDIF.
    ENDIF.
  ENDMETHOD.
ENDCLASS.                    "lcl_queue IMPLEMENTATION
*----------------------------------------------------------------------*
*       CLASS lcl_line_queue IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_line_queue IMPLEMENTATION.
  METHOD eval.
    CLEAR ev_val.
    min_max( IMPORTING es_line = ev_val ).  " Get Line
  ENDMETHOD.
ENDCLASS.                    "lcl_line_queue IMPLEMENTATION
*----------------------------------------------------------------------*
*       CLASS lcl_priority_queue IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_priority_queue IMPLEMENTATION.
  METHOD eval.
    min_max( IMPORTING ev_val = ev_val ).  " Get field
  ENDMETHOD.
ENDCLASS.                    "lcl_priority_queue IMPLEMENTATION
CLASS lcl_average_queue IMPLEMENTATION.
  METHOD eval.                             " Get average
    FIELD-SYMBOLS <ls_line> TYPE any.
    FIELD-SYMBOLS <lv_ref> TYPE any.
    FIELD-SYMBOLS <lt_table> TYPE ANY TABLE.
    DATA lr_line TYPE REF TO data.
    DATA lv_avg TYPE tv_avg.
    ASSIGN mr_table->* TO <lt_table>.
    CREATE DATA lr_line LIKE LINE OF <lt_table>.
    ASSIGN lr_line->* TO <ls_line>.
    LOOP AT <lt_table> INTO <ls_line>.
      AT FIRST.
        ASSIGN COMPONENT mv_column OF STRUCTURE <ls_line> TO <lv_ref>.
        IF sy-subrc NE 0.
*         if the table entries have no structure...
          ASSIGN <ls_line> TO <lv_ref>.
        ENDIF.
      ENDAT.
      ADD <lv_ref> TO lv_avg.    " RAISING cx_sy_conversion_no_number.
      AT LAST.
        lv_avg = lv_avg / lines( <lt_table> ).
      ENDAT.
    ENDLOOP.
     ev_val = lv_avg.
  ENDMETHOD.
ENDCLASS.                    "lcl_average_queue IMPLEMENTATION
*&---------------------------------------------------------------------*
* ***********              BEGIN of TESTS               ****************
*&---------------------------------------------------------------------*
TYPES tv_data TYPE i.
CLASS lcl_data DEFINITION FOR TESTING.
* Helper class for testing
  PUBLIC SECTION.
    CONSTANTS:
      c_min_int TYPE i VALUE -2147483648,
      c_max_int TYPE i VALUE 2147483647.
    TYPES: BEGIN OF ts_expected,
             min TYPE tv_data,
             max TYPE tv_data,
             avg TYPE lcl_average_queue=>tv_avg,
           END OF ts_expected.
    TYPES: BEGIN OF ts_struct,
             data TYPE tv_data,
             text TYPE char20,
           END OF ts_struct.
*    TYPES tt_struct TYPE STANDARD TABLE OF ts_struct.
    TYPES tt_struct TYPE HASHED TABLE OF ts_struct
      WITH UNIQUE KEY data.
    METHODS test_data_size
      IMPORTING iv_size TYPE i
      RAISING   cx_dynamic_check cx_static_check.
    METHODS const_data_size
      IMPORTING iv_size TYPE i
      RAISING   cx_dynamic_check cx_static_check.
    METHODS test_top_of_struct
      IMPORTING iv_size TYPE i
      RAISING   cx_dynamic_check cx_static_check.
    METHODS test_of_average
      IMPORTING iv_size TYPE i DEFAULT 10
      RAISING   cx_dynamic_check.
    CLASS-METHODS create
      IMPORTING iv_size TYPE syindex
                iv_min TYPE i DEFAULT c_min_int
                iv_max TYPE i DEFAULT c_max_int
      RETURNING VALUE(ro_data) TYPE REF TO lcl_data.
    CLASS-METHODS make_message
      IMPORTING iv_size       TYPE i
                iv_suffix     TYPE char5 DEFAULT space
                iv_prefix     TYPE char20
      RETURNING VALUE(rv_msg) TYPE char70.
    METHODS test_line
      IMPORTING iv_eval   TYPE lcl_queue=>tv_eval
                iv_prefix TYPE c
                iv_exp  TYPE tv_data.
  PRIVATE SECTION.
    DATA ms_expv TYPE ts_expected.
    DATA mt_data TYPE STANDARD TABLE OF tv_data.
    DATA mt_struct TYPE tt_struct.
    DATA ms_exps TYPE ts_expected.
    METHODS expected_data_values.
    METHODS expected_struct_values.
    METHODS generate
      IMPORTING iv_size TYPE syindex
                iv_min TYPE i
                iv_max TYPE i.
    METHODS:
      top_of_struct
        IMPORTING iv_size       TYPE syindex
                  it_table      TYPE ANY TABLE
                  iv_column     TYPE name_feld DEFAULT space
                  iv_eval       TYPE lcl_queue=>tv_eval
                  iv_min TYPE i DEFAULT c_min_int
                  iv_max TYPE i DEFAULT c_max_int
        RETURNING VALUE(rv_val) TYPE tv_data
        RAISING   cx_dynamic_check cx_static_check.
    METHODS:
      top_of_struct_f
        IMPORTING iv_size       TYPE syindex
                  it_table      TYPE ANY TABLE
                  iv_column     TYPE name_feld DEFAULT space
                  iv_eval       TYPE lcl_queue=>tv_eval
                  iv_min TYPE i DEFAULT c_min_int
                  iv_max TYPE i DEFAULT c_max_int
        RETURNING VALUE(rv_val) TYPE f
        RAISING   cx_dynamic_check cx_static_check.
    METHODS:
      top_struct
        IMPORTING iv_size       TYPE syindex
                  iv_eval       TYPE lcl_queue=>tv_eval
                  iv_min TYPE i DEFAULT c_min_int
                  iv_max TYPE i DEFAULT c_max_int
        RETURNING VALUE(rv_val) TYPE tv_data
        RAISING   cx_dynamic_check cx_static_check.
    METHODS:
      top_struct_f
        IMPORTING iv_size       TYPE syindex
                  iv_eval       TYPE lcl_queue=>tv_eval
                  iv_min TYPE i DEFAULT c_min_int
                  iv_max TYPE i DEFAULT c_max_int
        RETURNING VALUE(rv_val) TYPE f
        RAISING   cx_dynamic_check cx_static_check.
    METHODS:
      top_data
        IMPORTING iv_size TYPE syindex
                  iv_eval TYPE lcl_queue=>tv_eval
                  iv_min TYPE i DEFAULT c_min_int
                  iv_max TYPE i DEFAULT c_max_int
        RETURNING VALUE(rv_val) TYPE tv_data
        RAISING   cx_dynamic_check cx_static_check.
    METHODS:
      top_data_f
        IMPORTING iv_size TYPE syindex
                  iv_eval TYPE lcl_queue=>tv_eval
                  iv_min TYPE i DEFAULT c_min_int
                  iv_max TYPE i DEFAULT c_max_int
        RETURNING VALUE(rv_val) TYPE f
        RAISING   cx_dynamic_check cx_static_check.
ENDCLASS.
*----------------------------------------------------------------------*
*       CLASS ltc_queue DEFINITION
*----------------------------------------------------------------------*
CLASS ltc_queue DEFINITION FOR TESTING RISK LEVEL HARMLESS DURATION SHORT.
  PUBLIC SECTION.
    INTERFACES lif_unit_test.
  PRIVATE SECTION.
    TYPES: BEGIN OF ts_map,
             idx  TYPE i,
             text TYPE char20,
           END OF ts_map.
    TYPES: BEGIN OF ts_time,
             size     TYPE syindex,
             time     TYPE i,
             lg_ratio TYPE f,
           END OF ts_time.
    DATA mi_timer TYPE REF TO if_abap_runtime.
    METHODS make_message
      IMPORTING iv_size       TYPE i
                iv_suffix     TYPE char5 DEFAULT space
                iv_prefix     TYPE char20
      RETURNING VALUE(rv_msg) TYPE char70.
    METHODS run_data IMPORTING iv_size TYPE syindex.
    METHODS run_struct IMPORTING iv_size TYPE syindex.
    METHODS data_test FOR TESTING.
    METHODS struct_test FOR TESTING.
    METHODS char20_max FOR TESTING.
    METHODS char20_mean FOR TESTING.
    METHODS wrong_operator FOR TESTING.
    METHODS wrong_operator_line FOR TESTING.
    METHODS map_standard_min FOR TESTING.
    METHODS map_standard_max FOR TESTING.
    METHODS map_standard_mean FOR TESTING.
    METHODS map_sorted_min FOR TESTING.
    METHODS map_sorted_max FOR TESTING.
    METHODS map_sorted_mean FOR TESTING.
    METHODS map_hashed_min FOR TESTING.
    METHODS map_hashed_max FOR TESTING.
    METHODS map_hashed_mean FOR TESTING.
    METHODS test_average FOR TESTING.
    METHODS test_line_max FOR TESTING.
    METHODS test_line_min FOR TESTING.
    METHODS test_line_mean FOR TESTING.
    METHODS profile
      IMPORTING iv_size        TYPE syindex
                iv_time        TYPE i
      RETURNING VALUE(rs_time) TYPE ts_time.
    METHODS performance FOR TESTING.
ENDCLASS.                    "ltc_queue DEFINITION
CLASS lcl_data IMPLEMENTATION.
  METHOD create.
    ro_data = NEW #( ).
    ro_data->generate( iv_size = iv_size
                       iv_min = iv_min
                       iv_max = iv_max ).
  ENDMETHOD.
  METHOD generate.
    CLEAR mt_data.
    CLEAR mt_struct.
    DATA(lo_rnd) = cl_abap_random_int=>create( seed = 42
                                               min = iv_min
                                               max = iv_max ).
    DO iv_size TIMES.
      DATA(lv_data) = lo_rnd->get_next( ).
      INSERT lv_data INTO TABLE mt_data.
      INSERT VALUE ts_struct( data = lv_data
                              text = lv_data ) INTO TABLE mt_struct.
    ENDDO.
    expected_data_values( ).
    expected_struct_values( ).
  ENDMETHOD.                    "generate
  METHOD expected_data_values.
    LOOP AT mt_data ASSIGNING FIELD-SYMBOL(<lv_data>).
      AT FIRST.
        CLEAR ms_expv-avg.
        ms_expv-min = ms_expv-max = <lv_data>.
      ENDAT.
      ADD <lv_data> TO ms_expv-avg.
      IF <lv_data> GT ms_expv-max.
        ms_expv-max = <lv_data>.
      ENDIF.
      IF <lv_data> LT ms_expv-min.
        ms_expv-min = <lv_data>.
      ENDIF.
      AT LAST.
        ms_expv-avg = ms_expv-avg / lines( mt_data ).
      ENDAT.
    ENDLOOP.
  ENDMETHOD.                    "expected_data_values
  METHOD expected_struct_values.
    LOOP AT mt_struct ASSIGNING FIELD-SYMBOL(<ls_struct>).
      AT FIRST.
        CLEAR ms_exps-avg.
        ms_exps-min = ms_exps-max = <ls_struct>-data.
      ENDAT.
      ADD <ls_struct>-data TO ms_exps-avg.
      IF <ls_struct>-data GT ms_exps-max.
        ms_exps-max = <ls_struct>-data.
      ENDIF.
      IF <ls_struct>-data LT ms_exps-min.
        ms_exps-min = <ls_struct>-data.
      ENDIF.
      AT LAST.
        ms_exps-avg = ms_exps-avg / lines( mt_struct ).
      ENDAT.
    ENDLOOP.
  ENDMETHOD.                    "expected_struct_values
  METHOD top_of_struct.
    generate( iv_size = iv_size
              iv_min = iv_min
              iv_max = iv_max ).
    lcl_queue=>top(
      EXPORTING it_table = it_table
                iv_column = iv_column
                iv_eval = iv_eval
      IMPORTING ev_top = rv_val ).
  ENDMETHOD.                    "top_of_struct
  METHOD top_of_struct_f.
    generate( iv_size = iv_size
              iv_min = iv_min
              iv_max = iv_max ).
    lcl_queue=>top(
      EXPORTING it_table = it_table
                iv_column = iv_column
                iv_eval = iv_eval
      IMPORTING ev_top = rv_val ).
  ENDMETHOD.
  METHOD top_struct.
    rv_val = top_of_struct( iv_size = iv_size
                            it_table = mt_struct
                            iv_column = 'DATA'
                            iv_eval = iv_eval
                            iv_min = iv_min
                            iv_max = iv_max ).
  ENDMETHOD.                    "top_of_struct
  METHOD top_struct_f.
    rv_val = top_of_struct_f( iv_size = iv_size
                              it_table = mt_struct
                              iv_column = 'DATA'
                              iv_eval = iv_eval
                              iv_min = iv_min
                              iv_max = iv_max ).
  ENDMETHOD.                    "top_of_struct_f
  METHOD top_data.
    rv_val = top_of_struct( iv_size = iv_size
                            it_table = mt_data
                            iv_eval = iv_eval
                            iv_min = iv_min
                            iv_max = iv_max ).
  ENDMETHOD.                    "top_data
  METHOD top_data_f.
    rv_val = top_of_struct_f( iv_size = iv_size
                              it_table = mt_data
                              iv_eval = iv_eval
                              iv_min = iv_min
                              iv_max = iv_max ).
  ENDMETHOD.                    "top_data_f
  METHOD make_message.
    rv_msg = | Error: { iv_prefix } { iv_suffix } Size: { iv_size } |.
  ENDMETHOD.                    "make_message
  METHOD test_data_size.
    DATA ls_exp TYPE ts_expected.
    ls_exp-max = top_data( iv_size = iv_size
                           iv_eval = lcl_queue=>c_max ).
    cl_abap_unit_assert=>assert_equals(
      exp = ms_expv-max
      act = ls_exp-max
      msg = make_message( iv_prefix = 'MAX DATA'
                          iv_size = iv_size ) ).
    ls_exp-min = top_data( iv_size = iv_size
                           iv_eval = lcl_queue=>c_min ).
    cl_abap_unit_assert=>assert_equals(
      exp = ms_expv-min
      act = ls_exp-min
      msg = make_message( iv_prefix = 'MIN DATA'
                          iv_size = iv_size )  ).
    ls_exp-avg = top_data_f( iv_size = iv_size
                             iv_eval = lcl_queue=>c_avg ).
    cl_abap_unit_assert=>assert_equals_float(
      exp = ms_expv-avg
      act = ls_exp-avg
      rtol = lcl_average_queue=>c_avg_tol
      msg = make_message( iv_prefix = 'AVG DATA'
                          iv_size = iv_size ) ).
  ENDMETHOD.                    "test_data_size
  METHOD const_data_size.
    CONSTANTS c_value TYPE tv_data VALUE 42.
    DATA ls_exp TYPE ts_expected.
    ls_exp-max = top_data( iv_size = iv_size
                           iv_min = c_value
                           iv_max = c_value
                           iv_eval = lcl_queue=>c_max ).
    cl_abap_unit_assert=>assert_equals(
      exp = ms_expv-max
      act = ls_exp-max
      msg = make_message( iv_prefix = 'CONST MAX DATA'
                          iv_size = iv_size ) ).
    ls_exp-min = top_data( iv_size = iv_size
                           iv_min = c_value
                           iv_max = c_value
                           iv_eval = lcl_queue=>c_min ).
    cl_abap_unit_assert=>assert_equals(
      exp = ms_expv-min
      act = ls_exp-min
      msg = make_message( iv_prefix = 'CONST MIN DATA'
                          iv_size = iv_size ) ).
    ls_exp-avg = top_data_f( iv_size = iv_size
                             iv_min = c_value
                             iv_max = c_value
                             iv_eval = lcl_queue=>c_avg ).
    cl_abap_unit_assert=>assert_equals_float(
      exp = ms_expv-avg
      act = ls_exp-avg
      rtol = lcl_average_queue=>c_avg_tol
      msg = make_message( iv_prefix = 'CONST AVG DATA'
                          iv_size = iv_size ) ).
  ENDMETHOD.
  METHOD test_of_average.
    DATA lv_avg TYPE lcl_average_queue=>tv_avg.
    TRY.
        lv_avg = top_struct_f( iv_size = iv_size
                               iv_eval = lcl_queue=>c_avg ).
        cl_abap_unit_assert=>assert_equals(
          exp = ms_exps-avg
          act = lv_avg
          tol = lcl_average_queue=>c_avg_tol
          msg = make_message( iv_prefix =  'TEST AVERAGE'
                              iv_size = iv_size )  ).
      CATCH cx_static_check.
        cl_abap_unit_assert=>fail(
          msg = make_message( iv_prefix = 'TEST AVERAGE'
                              iv_suffix = 'ABORT'
                              iv_size = iv_size ) ).
    ENDTRY.
  ENDMETHOD.
  METHOD test_top_of_struct.
    DATA ls_exp TYPE ts_expected.
    ls_exp-max = top_struct( iv_size = iv_size
                             iv_eval = lcl_queue=>c_max ).
    cl_abap_unit_assert=>assert_equals(
      exp = ms_exps-max
      act = ls_exp-max
      msg = make_message( iv_prefix = 'MAX STRUCT'
                          iv_size = iv_size ) ).
    ls_exp-min = top_struct( iv_size = iv_size
                             iv_eval = lcl_queue=>c_min ).
    cl_abap_unit_assert=>assert_equals(
      exp = ms_exps-min
      act = ls_exp-min
      msg = make_message( iv_prefix = 'MIN STRUCT'
                          iv_size = iv_size ) ).
    ls_exp-avg = top_struct_f( iv_size = iv_size
                               iv_eval = lcl_queue=>c_avg ).
    cl_abap_unit_assert=>assert_equals_float(
      exp = ms_exps-avg
      act = ls_exp-avg
      rtol = lcl_average_queue=>c_avg_tol
      msg = make_message( iv_prefix = 'AVG STRUCT'
                          iv_size = iv_size ) ).
  ENDMETHOD.                    "test_top_of_struct
  METHOD test_line.
    DATA ls_struct TYPE ts_struct.
    TRY.
        DATA(lv_size) = lines( mt_struct ).
        lcl_queue=>top(
           EXPORTING it_table = mt_struct
                     iv_column = 'TEXT'
                     iv_eval = iv_eval
                     iv_line = 'X'
           IMPORTING ev_top = ls_struct ).
        cl_abap_unit_assert=>assert_equals(
          exp = VALUE ts_struct( data = iv_exp
                                 text = iv_exp )
          act = ls_struct
          msg = make_message( iv_prefix = iv_prefix
                              iv_size = lv_size )  ).
      CATCH cx_static_check.
        cl_abap_unit_assert=>fail(
          msg = make_message( iv_prefix = iv_prefix
                              iv_suffix = 'ABORT'
                              iv_size = lv_size ) ).
    ENDTRY.
  ENDMETHOD.
ENDCLASS.
*----------------------------------------------------------------------*
*       CLASS ltc_queue IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS ltc_queue IMPLEMENTATION.
  METHOD make_message.
    rv_msg = lcl_data=>make_message( iv_prefix = iv_prefix
                                     iv_suffix = iv_suffix
                                     iv_size = iv_size ).
  ENDMETHOD.                    "make_message
  METHOD wrong_operator.
    DATA lt_struct TYPE lcl_data=>tt_struct.
    TRY.
        DATA(lv_msg) = make_message( iv_prefix = 'WRONG OPERATOR'
                                     iv_size = 255 ).
        lcl_queue=>top(
          it_table = lt_struct
          iv_column = 'TEXT'
          iv_eval = 255 ).
        cl_abap_unit_assert=>fail( msg = lv_msg ).
      CATCH cx_list_error.                              "#EC NO_HANDLER
*     Test successfull
      CATCH cx_static_check cx_dynamic_check.
        cl_abap_unit_assert=>fail( msg = lv_msg ).
    ENDTRY.
  ENDMETHOD.                    "wrong_operator
  METHOD wrong_operator_line.
    DATA lt_struct TYPE lcl_data=>tt_struct.
    DATA(lv_msg) = make_message( iv_prefix = 'WRONG OPERATOR LINE'
                                 iv_size = 0 ).
    TRY.
        lcl_queue=>top(
          it_table = lt_struct
          iv_column = 'TEXT'
          iv_line = 'X'
          iv_eval = lcl_queue=>c_avg ).
        cl_abap_unit_assert=>fail( msg = lv_msg ).
      CATCH cx_list_error.                              "#EC NO_HANDLER
*     Test successfull
      CATCH cx_static_check cx_dynamic_check.
        cl_abap_unit_assert=>fail( msg = lv_msg ).
    ENDTRY.
  ENDMETHOD.
  METHOD run_data.
    DATA(lv_msg) = make_message( iv_prefix = 'DATA'
                                 iv_size = iv_size ).
    TRY.
        DATA(lo_data) = NEW lcl_data( ).
        lo_data->test_data_size( iv_size ).
        lo_data->const_data_size( iv_size ).
        IF iv_size EQ 0.
          cl_abap_unit_assert=>fail( msg = lv_msg ).
        ENDIF.
      CATCH cx_dynamic_check cx_static_check.
        IF iv_size GT 0.
          cl_abap_unit_assert=>fail( msg = lv_msg ).
        ENDIF.
    ENDTRY.
  ENDMETHOD.                    "run_data
  METHOD data_test.
    run_data( 0 ).
    run_data( 1 ).
    run_data( 10 ).
    run_data( 100 ).
    run_data( 1000 ).
  ENDMETHOD.                    "data_test
  METHOD run_struct.
    DATA(lv_msg) = make_message( iv_prefix = 'STRUCT'
                                 iv_size = iv_size ).
    TRY.
        NEW lcl_data( )->test_top_of_struct( iv_size ).
        IF iv_size EQ 0.
          cl_abap_unit_assert=>fail( msg = lv_msg ).
        ENDIF.
      CATCH cx_dynamic_check cx_static_check.
        IF iv_size GT 0.
          cl_abap_unit_assert=>fail( msg = lv_msg ).
        ENDIF.
    ENDTRY.
  ENDMETHOD.                    "run_struct
  METHOD struct_test.
    run_struct( 0 ).
    run_struct( 1 ).
    run_struct( 10 ).
    run_struct( 100 ).
    run_struct( 1000 ).
  ENDMETHOD.                    "struct_test
  METHOD profile.
    CLEAR rs_time.
    rs_time-size = iv_size.
    DATA(lv_start) = mi_timer->get_runtime( ).
    run_data( iv_size ).
    rs_time-time = mi_timer->get_runtime( ) - lv_start.
    IF iv_time GT 0.
      rs_time-lg_ratio = log10( rs_time-time / iv_time ).
    ENDIF.
  ENDMETHOD.                    "profile
  METHOD performance.
*   empirical analysis
    CONSTANTS c_precision TYPE f VALUE '1e-2'.
    DATA lv_size TYPE syindex VALUE 1.
    mi_timer = cl_abap_runtime=>create_hr_timer( ).
    DATA(ls_time) = profile( iv_size = 0
                             iv_time = 0 ).
    DO 6 TIMES.
      ls_time = profile( iv_size = lv_size
                         iv_time = ls_time-time ).
      lv_size = lv_size * 10.
    ENDDO.
    IF ( ls_time-lg_ratio - c_precision )  > 1 .
      cl_abap_unit_assert=>fail( msg = | Performance: { ls_time-lg_ratio } | ).
    ENDIF.
  ENDMETHOD.                    "performance
  DEFINE add_map_entry.
    add 1 to ls_map-idx.
    ls_map-text = &1.
    insert ls_map into table lt_map.
  END-OF-DEFINITION.
  DEFINE map_method.
    method &1.
      types tt_map type &2 table of ts_map with &3 key idx.
      data ls_map type ts_map.
      data lt_map type tt_map.
      data lv_exp type char20 value &5.
      data lv_act type char20.
      add_map_entry:
        'que', 'j''aime', 'a',  'faire', 'connaitre',
        'ce', 'nombre', 'si', 'utile', 'aux', 'sages.'.
      try.
          lcl_queue=>top( exporting it_table = lt_map
                                    iv_column = 'TEXT'
                                    iv_eval = &4
                          importing ev_top = lv_act ).
          cl_aunit_assert=>assert_equals(
            exp = lv_exp
            act = lv_act
            msg = make_message( iv_prefix = '&1'
                                iv_size = 11 ) ).
        catch cx_dynamic_check cx_static_check.
          cl_abap_unit_assert=>fail(
            msg = make_message( iv_prefix = '&1'
                                 iv_suffix = 'ABORT'
                                 iv_size = 11 ) ).
      endtry.
    endmethod.                    "&1
  END-OF-DEFINITION.
  map_method:
    map_standard_min standard non-unique lcl_queue=>c_min 'a',
    map_standard_max standard non-unique lcl_queue=>c_max 'utile',
    map_standard_mean standard non-unique lcl_queue=>c_mean 'j''aime',
    map_sorted_min sorted unique lcl_queue=>c_min 'a',
    map_sorted_max sorted unique lcl_queue=>c_max 'utile',
    map_sorted_mean sorted unique lcl_queue=>c_mean 'j''aime'.
  map_method:
    map_hashed_min hashed unique lcl_queue=>c_min 'a',
    map_hashed_max hashed unique lcl_queue=>c_max 'utile',
    map_hashed_mean hashed unique lcl_queue=>c_mean 'j''aime'.

  METHOD char20_max.
    DATA lt_char20 TYPE STANDARD TABLE OF char20.
    DATA lv_exp TYPE char20 VALUE 'utile'.
    DATA lv_act TYPE char20.
    lt_char20 = VALUE #(
      ( 'que' ) ( 'j''aime' ) ( 'a' ) ( 'faire' ) ( 'connaitre' )
      ( 'ce' ) ( 'nombre' ) ( 'si' ) ( 'utile' ) ( 'aux' ) ( 'sages.' ) ).
    TRY.
        lcl_queue=>top( EXPORTING it_table = lt_char20
                        IMPORTING ev_top = lv_act ).
        cl_aunit_assert=>assert_equals(
          exp = lv_exp
          act = lv_act
          msg = make_message( iv_prefix = 'CHAR20 MAX'
                               iv_size = 11 ) ).
      CATCH cx_dynamic_check cx_static_check.
        cl_abap_unit_assert=>fail(
          msg = make_message( iv_prefix = 'CHAR20 MAX'
                              iv_suffix = 'ABORT'
                              iv_size = 11 ) ).
    ENDTRY.
  ENDMETHOD.                    "char20_max
  METHOD char20_mean.
    DATA lt_char20 TYPE STANDARD TABLE OF char20.
    DATA lv_exp TYPE char20 VALUE 'j''aime'.
    DATA lv_act TYPE char20.
    DATA lv_msg TYPE string.
    lt_char20 = VALUE #(
      ( 'que' ) ( 'j''aime' ) ( 'a' ) ( 'faire' ) ( 'connaitre' )
      ( 'ce' ) ( 'nombre' ) ( 'si' ) ( 'utile' ) ( 'aux' ) ( 'sages.' ) ).
    TRY.
        lcl_queue=>top( EXPORTING it_table = lt_char20
                                  iv_eval = lcl_queue=>c_mean
                        IMPORTING ev_top = lv_act ).
        lv_msg = make_message( iv_prefix = 'CHAR20 MEAN'
                               iv_size = 11 ).
        cl_aunit_assert=>assert_equals( exp = lv_exp
                                        act = lv_act
                                        msg = lv_msg ).
      CATCH cx_dynamic_check cx_static_check.
        lv_msg = make_message( iv_prefix = 'CHAR20 MEAN'
                               iv_suffix = 'ABORT'
                               iv_size = 11 ).
        cl_abap_unit_assert=>fail( msg = lv_msg ).
    ENDTRY.
  ENDMETHOD.                    "char20_mean
  METHOD test_line_min.
    CONSTANTS c_min_value TYPE tv_data VALUE -211680420.
    lcl_data=>create( 10 )->test_line(
      iv_eval = lcl_queue=>c_min
      iv_exp = c_min_value
      iv_prefix = 'LINE_TEST_MIN' ).
  ENDMETHOD.
  METHOD test_line_max.
    CONSTANTS c_max_value TYPE tv_data VALUE 1914837113.
    lcl_data=>create( 10 )->test_line(
      iv_eval = lcl_queue=>c_max
      iv_exp = c_max_value
      iv_prefix = 'LINE_TEST_MAX' ).
  ENDMETHOD.
  METHOD test_line_mean.
    CONSTANTS c_mean_value TYPE tv_data VALUE -1151077270.
    lcl_data=>create( 10 )->test_line(
      iv_eval = lcl_queue=>c_mean
      iv_exp = c_mean_value
      iv_prefix = 'LINE_TEST_MEAN' ).
  ENDMETHOD.
  METHOD test_average.
    lcl_data=>create( 10 )->test_of_average(  ).
  ENDMETHOD.
ENDCLASS.                    "ltc_queue IMPLEMENTATION
  • No labels