public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Marvin Häuser" <mhaeuser@posteo.de>
To: devel@edk2.groups.io, ianx.kuo@intel.com
Cc: amy.chan@intel.com, ray.ni@intel.com,
	Michael D Kinney <michael.d.kinney@intel.com>,
	Liming Gao <gaoliming@byosoft.com.cn>,
	Zhiguang Liu <zhiguang.liu@intel.com>
Subject: Re: [edk2-devel] [PATCH v5 1/4] MdePkg/BaseLib: Add QuickSort function on BaseLib
Date: Mon,  4 Oct 2021 12:56:29 +0000	[thread overview]
Message-ID: <2b5a17e9-8894-fa95-15d1-a00d8732ff1e@posteo.de> (raw)
In-Reply-To: <20211004050318.1816-2-ianx.kuo@intel.com>

Good day IanX,

On 04/10/2021 07:03, IanX Kuo wrote:
> From: IanX Kuo <ianx.kuo@intel.com>
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3675
>
> Add QuickSort function into BaseLib
>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Signed-off-by: IanX Kuo <ianx.kuo@intel.com>
> ---
>   MdePkg/Include/Library/BaseLib.h              |  49 ++++++++
>   MdePkg/Library/BaseLib/BaseLib.inf            |   1 +
>   MdePkg/Library/BaseLib/QuickSort.c            | 117 ++++++++++++++++++
>   .../Library/BaseLib/UnitTestHostBaseLib.inf   |   3 +-
>   4 files changed, 169 insertions(+), 1 deletion(-)
>   create mode 100644 MdePkg/Library/BaseLib/QuickSort.c
>
> diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
> index 2452c1d92e..2423169be4 100644
> --- a/MdePkg/Include/Library/BaseLib.h
> +++ b/MdePkg/Include/Library/BaseLib.h
> @@ -13,6 +13,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>   
>   #ifndef __BASE_LIB__
>   #define __BASE_LIB__
> +#include <Uefi/UefiBaseType.h>

Accidental change?

>   
>   //
>   // Definitions for architecture-specific types
> @@ -2856,6 +2857,54 @@ RemoveEntryList (
>   //
>   // Math Services
>   //
> +/**
> +  Prototype for comparison function for any two element types.
> +
> +  @param[in] Buffer1                  The pointer to first buffer.
> +  @param[in] Buffer2                  The pointer to second buffer.
> +
> +  @retval 0                           Buffer1 equal to Buffer2.
> +  @return <0                          Buffer1 is less than Buffer2.
> +  @return >0                          Buffer1 is greater than Buffer2.
> +**/
> +typedef
> +INTN
> +(EFIAPI *BASE_SORT_COMPARE)(
> +  IN CONST VOID                 *Buffer1,
> +  IN CONST VOID                 *Buffer2
> +  );
> +
> +/**
> +  Worker function for QuickSorting.

"Worker" functions are usually private.

> This function is identical to perform QuickSort,
> +  except that is uses the pre-allocated buffer so the in place sorting does not need to
> +  allocate and free buffers constantly.
> +
> +  Each element must be equal sized.
> +
> +  if Count is < 2 then perform no action.

This follows directly from the definition of sorting.

> +  if Size is < 1 then perform no action.

It would be perfectly valid to ASSERT on this in my opinion, so I would 
not hardcode the behaviour in the function spec.

> +
> +  @param[in, out] BufferToSort   on call a Buffer of (possibly sorted) elements
> +                                 on return a buffer of sorted elements
> +  @param[in] Count               the number of elements in the buffer to sort
> +  @param[in] ElementSize         Size of an element in bytes
> +  @param[in] CompareFunction     The function to call to perform the comparison
> +                                 of any 2 elements
> +  @param [in] BufferOneElement   Caller provided buffer whose size equals to ElementSize.
> +                                 It's used by QuickSort() for swapping in sorting.

This is out, not in. Maybe add a note its content is undefined on return?

> +
> +  @retval EFI_SUCCESS            The quick sort is finished.
> +  @retval EFI_INVALID_PARAMETER  When BufferToSort is NULL, CompareFunction is NULL or Buffer is NULL

These constraints are all caller constraints and not constraints on e.g. 
untrusted, external data. Hence, in my opinion it is perfectly valid to 
ASSERT them rather than runtime-check and emit status codes. This would 
mean the function could return VOID, there'd be no need to check status 
codes, and there'd be no need to worry about intermediate states (e.g. 
what is the content of BufferToSort when an error is returned?).

> +**/
> +EFI_STATUS
> +EFIAPI
> +QuickSort (
> +  IN OUT VOID                           *BufferToSort,
> +  IN CONST UINTN                        Count,
> +  IN CONST UINTN                        ElementSize,
> +  IN       BASE_SORT_COMPARE            CompareFunction,
> +  IN VOID                               *BufferOneElement

This is OUT, not IN.

> +  );
>   
>   /**
>     Shifts a 64-bit integer left between 0 and 63 bits. The low bits are filled
> diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
> index 6efa5315b6..cebda3b210 100644
> --- a/MdePkg/Library/BaseLib/BaseLib.inf
> +++ b/MdePkg/Library/BaseLib/BaseLib.inf
> @@ -32,6 +32,7 @@
>     SwapBytes16.c
>     LongJump.c
>     SetJump.c
> +  QuickSort.c
>     RShiftU64.c
>     RRotU64.c
>     RRotU32.c
> diff --git a/MdePkg/Library/BaseLib/QuickSort.c b/MdePkg/Library/BaseLib/QuickSort.c
> new file mode 100644
> index 0000000000..f95af9e238
> --- /dev/null
> +++ b/MdePkg/Library/BaseLib/QuickSort.c
> @@ -0,0 +1,117 @@
> +/** @file
> +  Math worker functions.
> +
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "BaseLibInternals.h"
> +#include <Uefi/UefiBaseType.h>

Is the second include not implied by the first?

> +
> +/**
> +  Worker function for QuickSorting.  This function is identical to perform QuickSort,
> +  except that is uses the pre-allocated buffer so the in place sorting does not need to
> +  allocate and free buffers constantly.
> +
> +  Each element must be equal sized.
> +
> +  if Count is < 2 then perform no action.
> +  if Size is < 1 then perform no action.
> +
> +  @param[in, out] BufferToSort   on call a Buffer of (possibly sorted) elements
> +                                 on return a buffer of sorted elements
> +  @param[in] Count               the number of elements in the buffer to sort
> +  @param[in] ElementSize         Size of an element in bytes
> +  @param[in] CompareFunction     The function to call to perform the comparison
> +                                 of any 2 elements
> +  @param [in] BufferOneElement   Caller provided buffer whose size equals to ElementSize.
> +                                 It's used by QuickSort() for swapping in sorting.
> +
> +  @retval EFI_SUCCESS            The quick sort is finished.
> +  @retval EFI_INVALID_PARAMETER  When BufferToSort is NULL, CompareFunction is NULL, or BufferOneElement is NULL
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +QuickSort (
> +  IN OUT VOID                           *BufferToSort,
> +  IN CONST UINTN                        Count,
> +  IN CONST UINTN                        ElementSize,
> +  IN       BASE_SORT_COMPARE            CompareFunction,
> +  IN VOID                               *BufferOneElement
> +  )
> +{
> +  VOID        *Pivot;
> +  UINTN       LoopCount;
> +  UINTN       NextSwapLocation;
> +
> +  if ((BufferToSort == NULL) || (CompareFunction == NULL) || (BufferOneElement == NULL)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (Count < 2 || ElementSize  < 1) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  NextSwapLocation = 0;
> +
> +  //
> +  // pick a pivot (we choose last element)
> +  //
> +  Pivot = ((UINT8*) BufferToSort + ((Count - 1) * ElementSize));
> +
> +  //
> +  // Now get the pivot such that all on "left" are below it
> +  // and everything "right" are above it
> +  //
> +  for (LoopCount = 0; LoopCount < Count -1; LoopCount++) {
> +    //
> +    // if the element is less than the pivot
> +    //
> +    if (CompareFunction ((VOID*) ((UINT8*) BufferToSort + ((LoopCount) * ElementSize)), Pivot) <= 0){

Comment mismatches logic, logic swaps on equality too.

Best regards,
Marvin

> +      //
> +      // swap
> +      //
> +      CopyMem (BufferOneElement, (UINT8*) BufferToSort + (NextSwapLocation * ElementSize), ElementSize);
> +      CopyMem ((UINT8*) BufferToSort + (NextSwapLocation * ElementSize), (UINT8*) BufferToSort + ((LoopCount) * ElementSize), ElementSize);
> +      CopyMem ((UINT8*) BufferToSort + ((LoopCount)*ElementSize), BufferOneElement, ElementSize);
> +
> +      //
> +      // increment NextSwapLocation
> +      //
> +      NextSwapLocation++;
> +    }
> +  }
> +  //
> +  // swap pivot to it's final position (NextSwapLocation)
> +  //
> +  CopyMem (BufferOneElement, Pivot, ElementSize);
> +  CopyMem (Pivot, (UINT8*) BufferToSort + (NextSwapLocation * ElementSize), ElementSize);
> +  CopyMem ((UINT8*) BufferToSort + (NextSwapLocation * ElementSize), BufferOneElement, ElementSize);
> +
> +  //
> +  // Now recurse on 2 partial lists.  neither of these will have the 'pivot' element
> +  // IE list is sorted left half, pivot element, sorted right half...
> +  //
> +  if (NextSwapLocation >= 2) {
> +    QuickSort (
> +      BufferToSort,
> +      NextSwapLocation,
> +      ElementSize,
> +      CompareFunction,
> +      BufferOneElement
> +      );
> +  }
> +
> +  if ((Count - NextSwapLocation - 1) >= 2) {
> +    QuickSort (
> +      (UINT8 *)BufferToSort + (NextSwapLocation + 1) * ElementSize,
> +      Count - NextSwapLocation - 1,
> +      ElementSize,
> +      CompareFunction,
> +      BufferOneElement
> +      );
> +  }
> +  return EFI_SUCCESS;
> +}
> diff --git a/MdePkg/Library/BaseLib/UnitTestHostBaseLib.inf b/MdePkg/Library/BaseLib/UnitTestHostBaseLib.inf
> index eae1a7158d..d09bd12bef 100644
> --- a/MdePkg/Library/BaseLib/UnitTestHostBaseLib.inf
> +++ b/MdePkg/Library/BaseLib/UnitTestHostBaseLib.inf
> @@ -1,7 +1,7 @@
>   ## @file
>   #  Base Library implementation for use with host based unit tests.
>   #
> -#  Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.<BR>
> +#  Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
>   #  Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
>   #  Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
>   #  Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
> @@ -33,6 +33,7 @@
>     SwapBytes16.c
>     LongJump.c
>     SetJump.c
> +  QuickSort.c
>     RShiftU64.c
>     RRotU64.c
>     RRotU32.c


  reply	other threads:[~2021-10-04 12:56 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-04  5:03 [PATCH v5 0/4] Add function QuickSort into MdePkg/BaseLib IanX Kuo
2021-10-04  5:03 ` [PATCH v5 1/4] MdePkg/BaseLib: Add QuickSort function on BaseLib IanX Kuo
2021-10-04 12:56   ` Marvin Häuser [this message]
2021-10-04 14:51     ` [edk2-devel] " IanX Kuo
2021-10-04 15:33       ` Marvin Häuser
2021-10-04  5:03 ` [PATCH v5 2/4] MdeModulePkg/SortLib: " IanX Kuo
2021-10-04  5:03 ` [PATCH v5 3/4] CryptoPkg/CryptLib: " IanX Kuo
2021-10-04  5:03 ` [PATCH v5 4/4] UefiCpuPkg/CpuCacheInfoLib: " IanX Kuo
2021-10-04 12:59   ` [edk2-devel] " Marvin Häuser

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2b5a17e9-8894-fa95-15d1-a00d8732ff1e@posteo.de \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox