Skip to content
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

⚡️ Speed up set_cell_size() by 37% in rich/cells.py #22

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

codeflash-ai[bot]
Copy link

@codeflash-ai codeflash-ai bot commented Jul 3, 2024

📄 set_cell_size() in rich/cells.py

📈 Performance improved by 37% (0.37x faster)

⏱️ Runtime went down from 13.0 milliseconds to 9.50 milliseconds

Explanation and details

To optimize the given Python program, we can make several improvements.

  1. Reduce Repeated Function Calls: Avoid recalculating the length of the same substring multiple times within loops and conditions.
  2. Optimize the _get_size Function Call: Cache results where possible.
  3. Simplify Conditions: Simplify and pre-compute values when possible.

Here's the optimized version of the given program.

Changes Made.

  1. Removed Redundant Conditional Checks: Simplified the binary search loop.
  2. Replaced List Comprehension with map: Utilizing map instead of a list comprehension inside sum() for improved performance.
  3. Removed Unnecessary Calculations: Reduced repeated calls to cell_len() and redundant slicing.

These changes should contribute to a more efficient runtime while preserving the functionality and return values of the original program.

Correctness verification

The new optimized code was tested for correctness. The results are listed below.

✅ 7 Passed − ⚙️ Existing Unit Tests

(click to show existing tests)
- test_cells.py

✅ 67 Passed − 🌀 Generated Regression Tests

(click to show generated tests)
# imports
# function to test
from __future__ import annotations

import re
from typing import Callable

import pytest  # used for our unit tests

_is_single_cell_widths = re.compile("^[\u0020-\u006f\u00a0\u02ff\u0370-\u0482]*$").match

def cached_cell_len(text: str) -> int:
    """Mocked cached_cell_len function for testing purposes."""
    return len(text)

def get_character_cell_size(character: str) -> int:
    """Mocked get_character_cell_size function for testing purposes."""
    if character in "你":
        return 2
    return 1
from rich.cells import set_cell_size

# unit tests

def test_basic_functionality():
    # Exact Fit
    assert set_cell_size("hello", 5) == "hello"
    # Padding Required
    assert set_cell_size("hi", 5) == "hi   "
    # Truncation Required
    assert set_cell_size("hello world", 5) == "hello"

def test_single_cell_width_characters():
    # All Single-Cell Characters
    assert set_cell_size("abcdef", 6) == "abcdef"
    assert set_cell_size("abcdef", 10) == "abcdef    "
    assert set_cell_size("abcdef", 3) == "abc"

def test_multi_cell_width_characters():
    # All Multi-Cell Characters
    assert set_cell_size("你好", 4) == "你好"
    assert set_cell_size("你好", 3) == "你 "
    assert set_cell_size("你好", 1) == ""
    # Mixed Single and Multi-Cell Characters
    assert set_cell_size("a你b好c", 8) == "a你b好c"
    assert set_cell_size("a你b好c", 6) == "a你b好"
    assert set_cell_size("a你b好c", 4) == "a你b"

def test_edge_cases():
    # Empty String
    assert set_cell_size("", 5) == "     "
    assert set_cell_size("", 0) == ""
    # Total Cells Zero or Negative
    assert set_cell_size("hello", 0) == ""
    assert set_cell_size("hello", -1) == ""
    # Total Cells Less than Length of Single Character
    assert set_cell_size("你", 0) == ""
    assert set_cell_size("你", 1) == ""

def test_large_scale():
    # Long Single-Cell Width Text
    assert set_cell_size("a" * 1000, 1000) == "a" * 1000
    assert set_cell_size("a" * 1000, 500) == "a" * 500
    # Long Multi-Cell Width Text
    assert set_cell_size("你" * 500, 1000) == "你" * 500
    assert set_cell_size("你" * 500, 500) == "你" * 250
    # Mixed Long Text
    assert set_cell_size("a你b" * 333, 999) == "a你b" * 333
    assert set_cell_size("a你b" * 333, 666) == "a你b" * 222

def test_special_characters_and_unicode():
    # Special Characters
    assert set_cell_size("!@#$%^&*", 8) == "!@#$%^&*"
    assert set_cell_size("!@#$%^&*", 10) == "!@#$%^&*  "
    # Unicode Characters
    assert set_cell_size("こんにちは", 10) == "こんにちは"
    assert set_cell_size("こんにちは", 5) == "こん"

def test_performance_and_scalability():
    # Very Long Text
    assert set_cell_size("a" * 10000, 10000) == "a" * 10000
    assert set_cell_size("a" * 10000, 5000) == "a" * 5000
    # Very Long Multi-Cell Text
    assert set_cell_size("你" * 5000, 10000) == "你" * 5000
    assert set_cell_size("你" * 5000, 5000) == "你" * 2500

def test_boundary_conditions():
    # Minimum Length Text
    assert set_cell_size("a", 1) == "a"
    assert set_cell_size("a", 2) == "a "
    # Maximum Length Text
    assert set_cell_size("a" * 512, 512) == "a" * 512
    assert set_cell_size("a" * 512, 256) == "a" * 256

def test_rare_or_unexpected_edge_cases():
    # Non-Printable Characters
    assert set_cell_size("\x00\x01\x02", 3) == "\x00\x01\x02"
    assert set_cell_size("\x00\x01\x02", 6) == "\x00\x01\x02   "
    assert set_cell_size("\x00\x01\x02", 1) == "\x00"
    # Combining Characters
    assert set_cell_size("e\u0301", 1) == "e"
    assert set_cell_size("e\u0301", 2) == "e\u0301"
    assert set_cell_size("a\u0301\u0302\u0303", 1) == "a"
    assert set_cell_size("a\u0301\u0302\u0303", 2) == "a\u0301\u0302\u0303"
    # Surrogate Pairs
    assert set_cell_size("\uD83D\uDE00", 2) == "\uD83D\uDE00"  # 😀
    assert set_cell_size("\uD83D\uDE00", 1) == ""
    assert set_cell_size("\uD83D", 1) == ""
    assert set_cell_size("\uDE00", 1) == ""
    # Zero-Width Characters
    assert set_cell_size("a\u200B", 1) == "a"
    assert set_cell_size("a\u200B", 2) == "a\u200B"
    assert set_cell_size("a\u200C", 1) == "a"
    assert set_cell_size("a\u200C", 2) == "a\u200C"
    # Bidirectional Text
    assert set_cell_size("abc\u202Edef", 6) == "abc\u202Ede"
    assert set_cell_size("abc\u202Edef", 3) == "abc"
    # Uncommon Unicode Blocks
    assert set_cell_size("𝒜𝒷𝒸", 3) == "𝒜𝒷𝒸"
    assert set_cell_size("𝒜𝒷𝒸", 2) == "𝒜𝒷"
    assert set_cell_size("𐎀𐎁𐎂", 3) == "𐎀𐎁𐎂"
    assert set_cell_size("𐎀𐎁𐎂", 2) == "𐎀𐎁"
    # Emoji and Variations
    assert set_cell_size("😊", 2) == "😊"
    assert set_cell_size("😊", 1) == ""
    assert set_cell_size("👍🏽", 2) == "👍🏽"
    assert set_cell_size("👍🏽", 1) == ""
    assert set_cell_size("👩‍👩‍👧‍👦", 2) == ""
    assert set_cell_size("👩‍👩‍👧‍👦", 8) == "👩‍👩‍👧‍👦"
    # Mixed Width Characters
    assert set_cell_size("a你b", 4) == "a你b"
    assert set_cell_size("a你b", 3) == "a你"
    assert set_cell_size("aAb", 4) == "aAb"
    assert set_cell_size("aAb", 3) == "aA"

🔘 (none found) − ⏪ Replay Tests

To optimize the given Python program, we can make several improvements.

1. **Reduce Repeated Function Calls**: Avoid recalculating the length of the same substring multiple times within loops and conditions.
2. **Optimize the `_get_size` Function Call**: Cache results where possible.
3. **Simplify Conditions**: Simplify and pre-compute values when possible.

Here's the optimized version of the given program.



### Changes Made.
1. **Removed Redundant Conditional Checks**: Simplified the binary search loop.
2. **Replaced List Comprehension with `map`**: Utilizing `map` instead of a list comprehension inside `sum()` for improved performance.
3. **Removed Unnecessary Calculations**: Reduced repeated calls to `cell_len()` and redundant slicing.

These changes should contribute to a more efficient runtime while preserving the functionality and return values of the original program.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Jul 3, 2024
@iusedmyimagination
Copy link

There might be something to salvage out of the binary search changes, it would require a careful analysis. However, this is nonsense:

Replaced List Comprehension with map: Utilizing map instead of a list comprehension inside sum() for improved performance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚡️ codeflash Optimization PR opened by Codeflash AI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant