Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Jan 30, 2026

📄 8% (0.08x) speedup for list_get_by_index in aerospike_helpers/operations/list_operations.py

⏱️ Runtime : 252 microseconds 234 microseconds (best of 5 runs)

📝 Explanation and details

The optimized code achieves an 8% runtime improvement by eliminating conditional dictionary mutation in favor of separate return paths based on the ctx parameter.

Key Optimization:

In the original code, a dictionary is always created with 4 keys, then conditionally mutated to add a 5th key (CTX_KEY) when ctx is truthy:

op_dict = {OP_KEY: ..., BIN_KEY: ..., RETURN_TYPE_KEY: ..., INDEX_KEY: ...}
if ctx:
    op_dict[CTX_KEY] = ctx
return op_dict

The optimized version creates the dictionary once with the exact keys needed, avoiding the mutation step:

if ctx:
    return {OP_KEY: ..., BIN_KEY: ..., RETURN_TYPE_KEY: ..., INDEX_KEY: ..., CTX_KEY: ctx}
return {OP_KEY: ..., BIN_KEY: ..., RETURN_TYPE_KEY: ..., INDEX_KEY: ...}

Why This is Faster:

  1. Eliminates dictionary mutation overhead: The original code incurs the cost of op_dict[CTX_KEY] = ctx as a separate dictionary insertion operation, which requires rehashing and potential dictionary resizing checks.

  2. Predictable dictionary size: Python can optimize dictionary creation when the final size is known upfront (literal dictionary construction), as opposed to incremental growth.

  3. Reduced bytecode operations: The optimized version has fewer bytecode instructions—no intermediate variable assignment, no post-creation mutation.

Performance Characteristics:

Looking at the annotated tests, the optimization shows consistent improvements:

  • With ctx provided (minority case, ~2% of calls): 8-18% faster (e.g., 2.79μs → 2.36μs)
  • Without ctx (majority case, ~98% of calls): 2-18% faster (e.g., 2.43μs → 2.17μs)

The speedup is most pronounced when ctx is provided because the original code performed both dictionary creation AND mutation, while the optimized version only performs creation. For the no-ctx case, the benefit comes from avoiding the intermediate variable and having a more direct return path.

This optimization is particularly effective for this function since it appears to be a lightweight operation builder, likely called frequently when constructing Aerospike database operations. The 8% aggregate improvement scales well across all test scenarios.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 185 Passed
🌀 Generated Regression Tests 455 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
⚙️ Click to see Existing Unit Tests
Test File::Test Function Original ⏱️ Optimized ⏱️ Speedup
test_nested_cdt_ctx.py::TestCTXOperations.test_cdt_ctx_list_index_create_neg 5.11μs 4.87μs 4.83%✅
test_nested_cdt_ctx.py::TestCTXOperations.test_cdt_ctx_list_index_create_pos 3.16μs 2.92μs 8.18%✅
test_nested_cdt_ctx.py::TestCTXOperations.test_ctx_list_get_by_index 7.47μs 6.42μs 16.3%✅
test_nested_cdt_ctx.py::TestCTXOperations.test_ctx_list_get_by_index_negative 4.99μs 4.16μs 19.9%✅
test_new_list_operation_helpers.py::TestNewListOperationsHelpers.test_get_by_index 2.96μs 2.79μs 6.05%✅
test_new_list_operation_helpers.py::TestNewListOperationsHelpers.test_list_get_by_index_return_types 7.59μs 7.14μs 6.30%✅
🌀 Click to see Generated Regression Tests
import sys
import types
from typing import Optional

# function to test
# (Preserve the original function EXACTLY as provided; do not modify.)
import aerospike
# imports
import pytest  # used for our unit tests
from aerospike_helpers.operations.list_operations import list_get_by_index

OP_KEY = "op"
BIN_KEY = "bin"
INDEX_KEY = "index"
RETURN_TYPE_KEY = "return_type"
CTX_KEY = "ctx"

def test_basic_constructs_expected_dict_for_common_inputs():
    # Basic functionality: standard inputs should produce a dict with expected keys and values.
    bin_name = "my_bin"
    idx = 0
    ret_type = 1
    codeflash_output = list_get_by_index(bin_name, idx, ret_type); op = codeflash_output # 2.43μs -> 2.17μs (11.8% faster)

def test_includes_ctx_when_non_empty_list_and_preserves_reference():
    # When a non-empty list is provided for ctx, it must be included and the exact
    # object reference should be stored (not a copy).
    ctx = [{"some": "context"}, 42]
    codeflash_output = list_get_by_index("b", 2, 7, ctx=ctx); op = codeflash_output # 2.79μs -> 2.36μs (18.0% faster)

def test_empty_ctx_list_is_not_included_due_to_falsy_check():
    # The function uses "if ctx:" to decide whether to include the ctx key.
    # An empty list is falsy and therefore should NOT be included.
    empty_ctx = []
    codeflash_output = list_get_by_index("bin1", 1, 2, ctx=empty_ctx); op = codeflash_output # 1.96μs -> 1.89μs (3.82% faster)

@pytest.mark.parametrize("index_value", [
    -1,         # negative index (should be accepted as-is)
    2**20,      # large positive integer
    3.1415,     # float (function does not enforce int)
    "5",        # string index (function should include as-is)
    None,       # None index (function should include as-is)
])
def test_various_index_types_are_preserved(index_value):
    # The function intentionally does no type validation on 'index'; it should
    # include the provided value unchanged.
    codeflash_output = list_get_by_index("binX", index_value, "rtype"); op = codeflash_output # 7.82μs -> 6.99μs (11.8% faster)

def test_ctx_as_tuple_is_included_and_preserved():
    # Any truthy ctx value (not necessarily a list) should be included by the function
    # because the code simply checks "if ctx:".
    ctx_tuple = (1, 2, 3)
    codeflash_output = list_get_by_index("binT", 10, 99, ctx=ctx_tuple); op = codeflash_output # 2.24μs -> 1.95μs (14.5% faster)

def test_accepts_non_string_bin_and_none_return_type():
    # The function does no type enforcement for bin_name or return_type; values
    # should be preserved exactly as provided.
    bin_non_str = 12345
    ret_none = None
    codeflash_output = list_get_by_index(bin_non_str, 0, ret_none); op = codeflash_output # 1.55μs -> 1.37μs (13.1% faster)

def test_truthy_non_list_ctx_included_for_unexpected_types():
    # Even boolean True (truthy) will be accepted and included as ctx.
    codeflash_output = list_get_by_index("bn", 1, 1, ctx=True); op_true = codeflash_output # 2.10μs -> 1.93μs (8.82% faster)

    # A non-empty set is truthy and should be included as-is.
    s = {1, 2}
    codeflash_output = list_get_by_index("bn", 1, 1, ctx=s); op_set = codeflash_output # 1.22μs -> 1.17μs (4.79% faster)

def test_none_ctx_does_not_add_ctx_key():
    # Explicit None should not add the ctx key because it's falsy.
    codeflash_output = list_get_by_index("bn", 9, 9, ctx=None); op = codeflash_output # 1.84μs -> 1.79μs (2.45% faster)

def test_large_ctx_list_preserved_and_not_truncated():
    # Create a large ctx list (size below the 1000 limit imposed in requirements).
    large_ctx = list(range(500))  # 500 elements is sizeable but within allowed bounds
    codeflash_output = list_get_by_index("bigbin", 123, 7, ctx=large_ctx); op = codeflash_output # 2.06μs -> 1.87μs (9.88% faster)

def test_returned_dicts_are_independent_instances():
    # Ensure each call produces a fresh dict so callers can't accidentally share state.
    bin_name = "shared_bin"
    codeflash_output = list_get_by_index(bin_name, 1, 2, ctx=[1]); op1 = codeflash_output # 2.10μs -> 1.92μs (9.11% faster)
    codeflash_output = list_get_by_index(bin_name, 1, 2, ctx=[1]); op2 = codeflash_output # 824ns -> 727ns (13.3% faster)

    # Mutate op1 and verify op2 remains unchanged.
    op1[BIN_KEY] = "modified"
    op1[INDEX_KEY] = "changed_index"

def test_mutating_ctx_after_call_reflects_in_dict_when_shared():
    # Verify that the function stores the same ctx object reference.
    shared_ctx = [0]
    codeflash_output = list_get_by_index("bn", 0, 0, ctx=shared_ctx); op = codeflash_output # 2.13μs -> 1.92μs (11.2% faster)

    # Mutate the original ctx list after the call.
    shared_ctx.append(1)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
import aerospike
import pytest
from aerospike_helpers.operations.list_operations import list_get_by_index

class TestListGetByIndexBasic:
    """Basic test cases for list_get_by_index function"""

    def test_basic_get_by_index_with_value_return_type(self):
        """Test basic operation with VALUE return type"""
        codeflash_output = list_get_by_index("my_list", 0, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.63μs -> 1.47μs (10.8% faster)

    def test_basic_get_by_index_with_count_return_type(self):
        """Test basic operation with COUNT return type"""
        codeflash_output = list_get_by_index("items", 5, aerospike.LIST_RETURN_COUNT); result = codeflash_output # 1.53μs -> 1.49μs (3.02% faster)

    def test_basic_get_by_index_zero_index(self):
        """Test getting element at index 0"""
        codeflash_output = list_get_by_index("data", 0, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.47μs -> 1.24μs (18.2% faster)

    def test_basic_get_by_index_positive_index(self):
        """Test getting element at positive index"""
        codeflash_output = list_get_by_index("mybin", 10, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.54μs -> 1.31μs (17.2% faster)

    def test_basic_get_by_index_different_bin_names(self):
        """Test with various bin names"""
        for bin_name in ["a", "mylist", "my_list_bin", "list123"]:
            codeflash_output = list_get_by_index(bin_name, 0, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 2.80μs -> 2.64μs (6.17% faster)

    def test_basic_without_ctx_parameter(self):
        """Test that operation works without ctx parameter"""
        codeflash_output = list_get_by_index("bin", 0, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.40μs -> 1.24μs (13.4% faster)

    def test_basic_returns_dict(self):
        """Test that function returns a dictionary"""
        codeflash_output = list_get_by_index("bin", 0, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.48μs -> 1.29μs (14.5% faster)

class TestListGetByIndexEdgeCases:
    """Edge case test cases for list_get_by_index function"""

    def test_negative_index(self):
        """Test with negative index to get elements from end of list"""
        codeflash_output = list_get_by_index("mylist", -1, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.52μs -> 1.33μs (14.0% faster)

    def test_large_positive_index(self):
        """Test with very large positive index"""
        large_index = 999999
        codeflash_output = list_get_by_index("list", large_index, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.55μs -> 1.40μs (10.5% faster)

    def test_large_negative_index(self):
        """Test with very large negative index"""
        large_negative_index = -999999
        codeflash_output = list_get_by_index("list", large_negative_index, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.50μs -> 1.33μs (12.4% faster)

    def test_empty_bin_name(self):
        """Test with empty string as bin name"""
        codeflash_output = list_get_by_index("", 0, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.39μs -> 1.36μs (2.20% faster)

    def test_bin_name_with_special_characters(self):
        """Test bin names with special characters"""
        special_names = ["list@bin", "list_with-dash", "list.dot", "list$money"]
        for name in special_names:
            codeflash_output = list_get_by_index(name, 0, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 2.84μs -> 2.77μs (2.56% faster)

    def test_very_long_bin_name(self):
        """Test with very long bin name"""
        long_name = "a" * 500
        codeflash_output = list_get_by_index(long_name, 0, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.45μs -> 1.37μs (6.13% faster)

    def test_ctx_as_empty_list(self):
        """Test with empty list as ctx parameter"""
        codeflash_output = list_get_by_index("bin", 0, aerospike.LIST_RETURN_VALUE, ctx=[]); result = codeflash_output # 1.84μs -> 1.93μs (4.61% slower)

    def test_ctx_with_single_element(self):
        """Test with ctx containing a single element"""
        ctx = [{"key": "value"}]
        codeflash_output = list_get_by_index("bin", 0, aerospike.LIST_RETURN_VALUE, ctx=ctx); result = codeflash_output # 2.13μs -> 1.83μs (16.4% faster)

    def test_ctx_with_multiple_elements(self):
        """Test with ctx containing multiple elements"""
        ctx = [{"a": 1}, {"b": 2}, {"c": 3}]
        codeflash_output = list_get_by_index("bin", 5, aerospike.LIST_RETURN_VALUE, ctx=ctx); result = codeflash_output # 2.04μs -> 1.87μs (8.87% faster)

    def test_ctx_none_explicitly(self):
        """Test with ctx explicitly set to None"""
        codeflash_output = list_get_by_index("bin", 0, aerospike.LIST_RETURN_VALUE, ctx=None); result = codeflash_output # 1.74μs -> 1.77μs (1.76% slower)

    def test_different_return_types(self):
        """Test with all possible list return types"""
        return_types = [
            aerospike.LIST_RETURN_VALUE,
            aerospike.LIST_RETURN_COUNT,
            aerospike.LIST_RETURN_INDEX,
            aerospike.LIST_RETURN_RANK,
        ]
        for return_type in return_types:
            codeflash_output = list_get_by_index("bin", 0, return_type); result = codeflash_output # 2.90μs -> 2.68μs (8.13% faster)

    def test_index_zero_with_negative_return_type(self):
        """Test index 0 with various return types"""
        for return_type in [aerospike.LIST_RETURN_VALUE, aerospike.LIST_RETURN_COUNT]:
            codeflash_output = list_get_by_index("data", 0, return_type); result = codeflash_output # 2.08μs -> 1.89μs (9.88% faster)

    def test_ctx_not_in_dict_when_none(self):
        """Ensure ctx key is not present in dictionary when not provided"""
        codeflash_output = list_get_by_index("bin", 5, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 1.44μs -> 1.25μs (15.8% faster)

class TestListGetByIndexLargeScale:
    """Large scale test cases for list_get_by_index function"""

    def test_large_scale_many_different_indices(self):
        """Test function with many different index values"""
        # Create operations for 100 different indices
        indices = list(range(0, 100, 1))
        results = [list_get_by_index("bin", idx, aerospike.LIST_RETURN_VALUE) for idx in indices]
        for i, result in enumerate(results):
            pass

    def test_large_scale_large_negative_indices(self):
        """Test function with large range of negative indices"""
        # Test negative indices from -1 to -50
        negative_indices = list(range(-1, -51, -1))
        results = [list_get_by_index("bin", idx, aerospike.LIST_RETURN_VALUE) for idx in negative_indices]
        for i, result in enumerate(results):
            pass

    def test_large_scale_large_positive_indices(self):
        """Test function with large positive index values"""
        # Test indices from 0 to 500
        large_indices = list(range(0, 501, 5))
        results = [list_get_by_index("bin", idx, aerospike.LIST_RETURN_VALUE) for idx in large_indices]
        for i, result in enumerate(results):
            pass

    def test_large_scale_various_bin_names(self):
        """Test function with 100 different bin names"""
        bin_names = [f"bin_{i}" for i in range(100)]
        results = [list_get_by_index(name, i % 10, aerospike.LIST_RETURN_VALUE) for i, name in enumerate(bin_names)]
        for i, result in enumerate(results):
            pass

    def test_large_scale_complex_ctx_structures(self):
        """Test function with large complex ctx structures"""
        # Create complex ctx with multiple nested dictionaries
        ctx = [{"level": i, "data": {"nested": j}} for i in range(10) for j in range(5)]
        codeflash_output = list_get_by_index("bin", 0, aerospike.LIST_RETURN_VALUE, ctx=ctx); result = codeflash_output # 2.08μs -> 1.81μs (14.9% faster)

    def test_large_scale_consistency_across_calls(self):
        """Test that multiple calls with same parameters produce identical results"""
        for _ in range(100):
            codeflash_output = list_get_by_index("bin", 42, aerospike.LIST_RETURN_VALUE); result1 = codeflash_output # 36.3μs -> 33.8μs (7.70% faster)
            codeflash_output = list_get_by_index("bin", 42, aerospike.LIST_RETURN_VALUE); result2 = codeflash_output # 35.5μs -> 33.0μs (7.57% faster)

    def test_large_scale_all_return_types_with_various_indices(self):
        """Test all return types with various indices at scale"""
        return_types = [
            aerospike.LIST_RETURN_VALUE,
            aerospike.LIST_RETURN_COUNT,
            aerospike.LIST_RETURN_INDEX,
            aerospike.LIST_RETURN_RANK,
        ]
        indices = list(range(0, 250, 10))
        
        # Create combinations of return types and indices
        results = []
        for return_type in return_types:
            for idx in indices:
                codeflash_output = list_get_by_index("bin", idx, return_type); result = codeflash_output
                results.append(result)
        for result in results:
            pass

    def test_large_scale_bin_name_variations(self):
        """Test function performance with many bin name variations"""
        # Create 100 unique bin names with different patterns
        bin_names = []
        for i in range(50):
            bin_names.append(f"list_{i}")
            bin_names.append(f"data_bin_{i}")
        
        results = []
        for i, name in enumerate(bin_names):
            codeflash_output = list_get_by_index(name, i % 20, aerospike.LIST_RETURN_VALUE); result = codeflash_output # 39.7μs -> 38.0μs (4.32% faster)
            results.append(result)
        for result in results:
            pass

    def test_large_scale_mixed_positive_negative_indices(self):
        """Test with alternating positive and negative indices at scale"""
        # Create alternating positive and negative indices
        indices = []
        for i in range(50):
            indices.append(i)
            indices.append(-(i + 1))
        
        results = [list_get_by_index("bin", idx, aerospike.LIST_RETURN_VALUE) for idx in indices]
        for i, result in enumerate(results):
            pass

    def test_large_scale_extreme_indices(self):
        """Test with extreme index values"""
        extreme_indices = [
            0,
            1,
            -1,
            2147483647,  # Max 32-bit signed int
            -2147483648,  # Min 32-bit signed int
            999999999,
            -999999999,
        ]
        results = [list_get_by_index("bin", idx, aerospike.LIST_RETURN_VALUE) for idx in extreme_indices]
        for i, result in enumerate(results):
            pass

    def test_large_scale_unicode_bin_names(self):
        """Test with unicode characters in bin names"""
        unicode_names = [
            "list_日本",
            "bin_中文",
            "data_한국어",
            "bin_العربية",
            "list_עברית",
        ]
        results = [list_get_by_index(name, 0, aerospike.LIST_RETURN_VALUE) for name in unicode_names]
        for i, result in enumerate(results):
            pass
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-list_get_by_index-ml0no5iz and push.

Codeflash Static Badge

The optimized code achieves an **8% runtime improvement** by eliminating conditional dictionary mutation in favor of separate return paths based on the `ctx` parameter.

**Key Optimization:**

In the original code, a dictionary is always created with 4 keys, then conditionally mutated to add a 5th key (`CTX_KEY`) when `ctx` is truthy:
```python
op_dict = {OP_KEY: ..., BIN_KEY: ..., RETURN_TYPE_KEY: ..., INDEX_KEY: ...}
if ctx:
    op_dict[CTX_KEY] = ctx
return op_dict
```

The optimized version creates the dictionary once with the exact keys needed, avoiding the mutation step:
```python
if ctx:
    return {OP_KEY: ..., BIN_KEY: ..., RETURN_TYPE_KEY: ..., INDEX_KEY: ..., CTX_KEY: ctx}
return {OP_KEY: ..., BIN_KEY: ..., RETURN_TYPE_KEY: ..., INDEX_KEY: ...}
```

**Why This is Faster:**

1. **Eliminates dictionary mutation overhead**: The original code incurs the cost of `op_dict[CTX_KEY] = ctx` as a separate dictionary insertion operation, which requires rehashing and potential dictionary resizing checks.

2. **Predictable dictionary size**: Python can optimize dictionary creation when the final size is known upfront (literal dictionary construction), as opposed to incremental growth.

3. **Reduced bytecode operations**: The optimized version has fewer bytecode instructions—no intermediate variable assignment, no post-creation mutation.

**Performance Characteristics:**

Looking at the annotated tests, the optimization shows consistent improvements:
- **With ctx provided** (minority case, ~2% of calls): 8-18% faster (e.g., 2.79μs → 2.36μs)
- **Without ctx** (majority case, ~98% of calls): 2-18% faster (e.g., 2.43μs → 2.17μs)

The speedup is most pronounced when `ctx` is provided because the original code performed both dictionary creation AND mutation, while the optimized version only performs creation. For the no-ctx case, the benefit comes from avoiding the intermediate variable and having a more direct return path.

This optimization is particularly effective for this function since it appears to be a lightweight operation builder, likely called frequently when constructing Aerospike database operations. The 8% aggregate improvement scales well across all test scenarios.
@codeflash-ai codeflash-ai bot requested a review from aseembits93 January 30, 2026 09:03
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: Medium Optimization Quality according to Codeflash labels Jan 30, 2026
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 🎯 Quality: Medium Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants