Skip to content

Fix binsearch #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 2, 2025
Merged

Fix binsearch #36

merged 1 commit into from
Apr 2, 2025

Conversation

kimkulling
Copy link
Owner

@kimkulling kimkulling commented Apr 2, 2025

Summary by CodeRabbit

  • New Features

    • Enhanced sorting and searching capabilities by introducing new comparison operations, swapping mechanisms, an efficient sorting algorithm, a check for sorted data, and expanded binary search functionality.
  • Documentation

    • Updated the memory allocation method’s description to clearly explain its behavior and return value, improving overall clarity for end-users.

Copy link
Contributor

coderabbitai bot commented Apr 2, 2025

Walkthrough

This pull request extends functionalities in the cppcore namespace. It adds new template functions for comparison (ascending and descending), various swap functions (generic, specific to uint8_t, and bitwise), a quicksort implementation with its helper, and binary search functions including an updated implementation. In addition, the documentation for the TPoolAllocator::alloc method has been updated to provide a clearer description of its purpose and return value.

Changes

File Change Summary
include/cppcore/Common/Sort.h Added template functions compAscending and compDescending; introduced three variations of swap (generic, uint8_t-specific, and bitwise); implemented quicksortImpl and a wrapper quicksort; added isSorted; updated binSearchImpl and added template binSearch.
include/cppcore/Memory/TPoolAllocator.h Updated the documentation for the alloc method in TPoolAllocator to describe that it allocates one item from the pool and clarifies the return value (pointer to the allocated item).

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Caller
    participant QS as quicksort
    participant QI as quicksortImpl
    participant Swap as swap functions
    participant CF as comparison functions

    Caller->>QS: Call quicksort(data, num, stride, comp)
    QS->>QI: Delegate to quicksortImpl()
    QI->>CF: Compare elements during partition
    CF-->>QI: Return comparison result
    QI->>Swap: Perform swap operations as needed
    Swap-->>QI: Swapped elements
    QI-->>QS: Return sorted data
    QS-->>Caller: Provide sorted array
Loading
sequenceDiagram
    participant User as User
    participant BS as binSearch
    participant BI as binSearchImpl
    participant CF as comparison function

    User->>BS: Call binSearch(key, data, num, comp)
    BS->>BI: Forward call to binSearchImpl()
    BI->>CF: Compare key with current element
    CF-->>BI: Return comparison outcome
    BI-->>BS: Return index (or -1 if not found)
    BS-->>User: Provide search result
Loading

Poem

Hop into the code, a clever little spree,
Sorting bits and bytes as quick as can be.
I swap and compare with a twitch of my ear,
Binary search finds treasures far and near.
With pool memories and docs so sweet,
This rabbit hops through changes—what a treat!
🐇💻✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

sonarqubecloud bot commented Apr 2, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
C Maintainability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
include/cppcore/Common/Sort.h (1)

140-153: 🛠️ Refactor suggestion

Improve the isSorted function to handle different ordering.

The current implementation of isSorted only returns false when result == -1, but doesn't handle cases where result > 0. This implies that the function only works correctly for ascending order. Consider improving the implementation to make it more flexible:

bool isSorted(const void *data, size_t num, size_t stride, ComparisonFn func) {
    if (num  < 2) {
        return true;
    }
    uint8_t *data_ = (uint8_t *)data;
    for (size_t i=1; i<num; ++i) {
        const int32_t result = func(&data_[(i-1)*stride], &data_[i * stride]);
-        if (result == -1) {
+        if (result > 0) {
            return false;
        }
    }

    return true;
}

This change would properly check for array ordering according to the provided comparison function, regardless of whether it's for ascending or descending order.

🧹 Nitpick comments (5)
include/cppcore/Memory/TPoolAllocator.h (1)

61-62: Fix the typo in the documentation.

There's a typo in the documentation: "WIll" should be "Will" for consistency and professionalism.

-    /// @brief  WIll alloc one item from the pool.
+    /// @brief  Will alloc one item from the pool.
include/cppcore/Common/Sort.h (4)

49-52: Maintain consistent template parameter naming.

The template parameter naming is inconsistent between compAscending (uses T) and compDescending (uses Ty). For better code consistency, use the same template parameter name in both functions.

-template <typename Ty>
-inline int32_t compDescending(const void *_lhs, const void *_rhs) {
-    return compAscending<Ty>(_rhs, _lhs);
+template <typename T>
+inline int32_t compDescending(const void *_lhs, const void *_rhs) {
+    return compAscending<T>(_rhs, _lhs);
}

77-84: Use consistent parameter naming in function signature and body.

The parameter names in the function signature (v1, v2) don't match the names used in the function body (lhs, rhs), which can cause confusion for readers. Consider unifying the naming convention:

-inline void swap(void *v1, void *v2, size_t stride) {
-    uint8_t *lhs = (uint8_t*) v1;
-    uint8_t *rhs = (uint8_t*) v2;
+inline void swap(void *lhs, void *rhs, size_t stride) {
+    uint8_t *lhs_ptr = (uint8_t*) lhs;
+    uint8_t *rhs_ptr = (uint8_t*) rhs;
-    const uint8_t *end = rhs + stride;
+    const uint8_t *end = rhs_ptr + stride;
-    while (rhs != end) {
-        swap(*lhs++, *rhs++);
+    while (rhs_ptr != end) {
+        swap(*lhs_ptr++, *rhs_ptr++);
    }
}

162-177: Improve binary search implementation and documentation.

The current return value documentation could be clearer about what the negative return value means. Also, there's an opportunity to improve the loop condition's readability:

/// @brief Implements a binary search algorithm.
/// @param key      The key to search for
/// @param data     The data to search in
/// @param num      The number of elements to search
/// @param stride   The stride of the data, i.e. the size of each element
/// @param func     The comparison function
-/// @return The index of the key if found, otherwise ~index
+/// @return The index of the key if found, otherwise the bitwise complement (~) of the insertion point
inline int32_t binSearchImpl(const void *key, const void *data, size_t num, size_t stride, ComparisonFn func) {
    size_t offset = 0;
    const uint8_t *_data = (uint8_t *)data;
-    for (size_t i = num; offset < i;) {
+    for (size_t high = num; offset < high;) {
-        size_t idx = (offset + i) / 2;
+        size_t idx = (offset + high) / 2;
        int32_t result = func(key, &_data[idx * stride]);
        if (result < 0) {
-            i = idx;
+            high = idx;
        } else if (result > 0) {
            offset = idx + 1;
        } else {
            return idx;
        }
    }
    return ~offset;
}

This change improves both the documentation and code readability by making it clearer that high represents the upper bound of the search space.


92-122: Consider further optimizing the quicksort implementation.

The quicksort implementation is functional, but there are a few potential optimizations to consider:

  1. For very small arrays (e.g., less than 10 elements), insertion sort is often faster than quicksort due to its lower overhead.
  2. The current implementation uses the first element as the pivot, which can lead to worst-case O(n²) performance on already sorted or reverse-sorted arrays.

Consider incorporating these optimizations:

inline void quicksortImpl(void *pivot, void *_data, size_t num, size_t stride, ComparisonFn func) {
    if (num < 2) {
        return;
    }

    if (_data == nullptr) {
        return;
    }

+    // Use insertion sort for small arrays
+    if (num < 10) {
+        uint8_t *data = (uint8_t*) _data;
+        for (size_t i = 1; i < num; ++i) {
+            for (size_t j = i; j > 0; --j) {
+                if (func(&data[(j-1)*stride], &data[j*stride]) <= 0) {
+                    break;
+                }
+                swap(&data[(j-1)*stride], &data[j*stride], stride);
+            }
+        }
+        return;
+    }

    uint8_t *data = (uint8_t*) _data;
-    memcpy(pivot, &data[0], stride);
+    // Choose a better pivot (median of three)
+    size_t mid = num / 2;
+    size_t last = num - 1;
+    if (func(&data[0], &data[mid*stride]) > 0) {
+        swap(&data[0], &data[mid*stride], stride);
+    }
+    if (func(&data[0], &data[last*stride]) > 0) {
+        swap(&data[0], &data[last*stride], stride);
+    }
+    if (func(&data[mid*stride], &data[last*stride]) > 0) {
+        swap(&data[mid*stride], &data[last*stride], stride);
+    }
+    memcpy(pivot, &data[mid*stride], stride);

    // Rest of the implementation...

These changes would make the quicksort algorithm more efficient across different input distributions.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c7cd0b and b5c3b18.

📒 Files selected for processing (2)
  • include/cppcore/Common/Sort.h (5 hunks)
  • include/cppcore/Memory/TPoolAllocator.h (1 hunks)

@kimkulling kimkulling merged commit f01433e into master Apr 2, 2025
2 of 3 checks passed
@kimkulling kimkulling deleted the bugfix/fix/binsearch branch April 2, 2025 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant