An open API service indexing awesome lists of open source software.

https://github.com/mohameds-dev/ordered_map_lib

Building an implementation of Ordered Map in C++.
https://github.com/mohameds-dev/ordered_map_lib

cmake cpp17 data-structures hash-tables linked-list pointers smart-pointers test-driven-development

Last synced: about 2 months ago
JSON representation

Building an implementation of Ordered Map in C++.

Awesome Lists containing this project

README

          

# Ordered Map Library

A C++ implementation of an ordered map data structure that maintains insertion order while providing O(1) key-value lookups.

## 🏆 Quality Metrics

- **Code Coverage**: 97.3% implementation coverage (271/277 lines)
- **Memory Safety**: Zero memory leaks verified by Valgrind
- **Test Suite**: 2,246 assertions across 195 test cases
- **Build Status**: [![CMake](https://github.com/mohameds-dev/ordered_map_lib/actions/workflows/cmake.yml/badge.svg)](https://github.com/mohameds-dev/ordered_map_lib/actions/workflows/cmake.yml)

## Table of Contents

- [Features](#features)
- [Usage](#usage)
- [Implementation Details](#implementation-details)
- [Class Diagram](#class-diagram)
- [Prerequisites](#prerequisites)
- [Project Structure](#project-structure)
- [Setting Up VS Code (or Cursor)](#setting-up-vs-code-or-cursor)
- [Formatting Code](#formatting-code)
- [Building and Running Tests](#building-and-running-tests)
- [Memory Leak Checks](#memory-leak-checks)
- [Code Coverage](#code-coverage)
- [GitHub Actions CI](#github-actions-ci)
- [Adding a New Test](#adding-a-new-test)
- [Future Improvements](#future-improvements)

## Features

- Maintains insertion order of key-value pairs
- O(1) key-value lookups using hash table
- O(1) insertion and deletion operations
- STL-like iterator interface
- Memory safe with smart pointers
- Exception handling for out-of-range access

## Usage

```cpp
#include "ordered_map.hpp"
#include

int main() {

// Create an ordered map
OrderedMap map;

// Insert key-value pairs
map.insert("apple", 1);
map.insert("banana", 2);
map.insert("cherry", 3);

// Access values
int value = map["apple"]; // Returns 1

// Iterate in insertion order
for (const auto& pair : map) {
std::cout << pair.first << ": " << pair.second << std::endl;
}

return 0;
}
```

## Implementation Details

The implementation of `OrderedMap` uses a combination of:

- Doubly linked list for maintaining insertion order
- Smart pointers for memory management
- Hash table (std::unordered_map) for O(1) lookups
- STL-compatible iterator interface

## Class Diagram

```mermaid
classDiagram

class Node~T~ {
+T value
+unique_ptr next
+Node~T~* prev
+Node(Node* prev, unique_ptr next, U&& value)
+Node(Node* prev, unique_ptr next, Args&&... args)
}

class DoublyLinkedList~T~ {
-unique_ptr head
-Node~T~* tail
-int _size
+push_back(const T&)
+push_back(T&&)
+push_front(const T&)
+push_front(T&&)
+emplace_back(Args&&...)
+pop_back()
+pop_front()
+move_to_begin(Iterator)
+move_to_end(Iterator)
+erase(Iterator)
+size() const
+begin()
+end()
+front() const
+back() const
+clear()
+back_iterator()
-extract_node_and_link_prev_with_next(Node~T~*)
-emplace_node_before(unique_ptr, Node~T~*)
-emplace_node_after(unique_ptr, Node~T~*)
}

class DoublyLinkedListIterator~T~ {
-Node~T~* current_node_ptr
-DoublyLinkedList~T~* list_ptr
+operator++()
+operator--()
+operator*()
+operator->()
+operator==() const
+operator!=() const
}

class OrderedMap~Key,Value~ {
-unordered_map~> _map
-DoublyLinkedList~pair~ _list
+insert(const Key&, const Value&)
+insert(const Key&, Value&&)
+move_to_front(const Key&)
+move_to_back(const Key&)
+operator[](const Key&)
+at(const Key&) const
+erase(const Key&)
+find(const Key&) const
+size() const
+begin()
+end()
+clear()
+back_iterator()
}

class OrderedMapIterator~Key,Value~ {
-DoublyLinkedListIterator~pair~ list_iterator
+operator++()
+operator*()
+operator->()
+operator!=() const
+operator==() const
}

DoublyLinkedList~T~ *-- Node~T~
DoublyLinkedList~T~ *-- DoublyLinkedListIterator~T~
OrderedMap~Key,Value~ *-- DoublyLinkedList~pair~
OrderedMap~Key,Value~ *-- OrderedMapIterator~Key,Value~
OrderedMapIterator~Key,Value~ *-- DoublyLinkedListIterator~pair~

```

## Prerequisites

- **CMake** (3.10+): `sudo apt install cmake`
- **Git**: `sudo apt install git`
- **C++ Compiler**: GCC 9.4.0+ (`sudo apt install g++`)
- **Clang-Format**: For code formatting (`sudo apt install clang-format`)
- **VS Code** or **Cursor**: Code editor with C++ support

Verify installations:

```bash
cmake --version
git --version
g++ --version
clang-format --version
```

## Project Structure

```
ordered_map/
├── .github/
│ └── workflows/
│ └── cmake.yml # GitHub Actions workflow
├── CMakeLists.txt # CMake build configuration
├── build.sh # Script to build and test
├── .clang-format # Code formatting rules
├── include/
│ ├── doubly_linked_list.hpp # Doubly-linked list implementation
│ └── ordered_map.hpp # Ordered map interface
├── src/
├── tests/
│ └── doubly_linked_list/ # Test files for doubly linked list
│ ├── front_and_back.cpp # Tests for front/back operations
│ ├── iterator_tests.cpp # Tests for iterator functionality
│ ├── pop_back_tests.cpp # Tests for pop_back operations
│ ├── pop_front_tests.cpp # Tests for pop_front operations
│ ├── push_back_tests.cpp # Tests for push_back operations
│ └── push_front_tests.cpp # Tests for push_front operations
```

## Setting Up VS Code (or Cursor)

1. **Install Extensions**:

- In VS Code/Cursor, go to Extensions (Ctrl+Shift+X).
- Install:
- **C/C++** (Microsoft): For IntelliSense and debugging.
- **CMake Tools** (Microsoft): For CMake integration.

2. **Configure IntelliSense**:

- Create `.vscode/settings.json` (or `.cursor/settings.json`):
```json
{
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
"C_Cpp.clang_format_path": "/usr/bin/clang-format",
"C_Cpp.formatting": "clangFormat",
"editor.formatOnSave": true,
"[cpp]": {
"editor.defaultFormatter": "ms-vscode.cpptools"
}
}
```

3. **Open Project**:
- Open the project folder in VS Code/Cursor.

## Formatting Code

- **Clang-Format**: Uses `.clang-format` for consistent style (Google-based).
- **Auto-Format**: Formats on save (see `editor.formatOnSave`).
- **Manual Format**:
```bash
clang-format -i src/*.cpp include/*.hpp tests/*.cpp
```
- **Via build.sh**: Formats all `.cpp`/`.hpp` files before building.

## Building and Running Tests

1. **Build and Test**:

```bash
chmod +x build.sh
./build.sh
```

- Formats code, builds with CMake/make, and runs Catch2 tests.

2. **Output**:

- Successful tests show:
```
All tests passed (X assertions in Y test cases)
```

3. **Run Specific Tests**:
```bash
cd build
./tests --tags [tag]
```

## Memory Leak Checks

This project is tested for memory leaks using Valgrind.
Below is a sample output from running the full test suite under Valgrind:

```
$ valgrind --leak-check=full ./build/tests --rng-seed 0

==12798== Memcheck, a memory error detector
==12798== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==12798== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==12798== Command: ./build/tests --rng-seed 0
==12798==
Randomness seeded to: 0
===============================================================================
All tests passed (2246 assertions in 195 test cases)

==12798==
==12798== HEAP SUMMARY:
==12798== in use at exit: 0 bytes in 0 blocks
==12798== total heap usage: 1,528,976 allocs, 1,528,976 frees, 45,317,931 bytes allocated
==12798==
==12798== All heap blocks were freed -- no leaks are possible
==12798==
==12798== For lists of detected and suppressed errors, rerun with: -s
==12798== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
```

## Code Coverage

This project includes comprehensive test coverage analysis using **LCOV**, which provides accurate coverage metrics for header-only libraries by distinguishing between implementation code and test code.

### Generate Coverage Report

From the build directory, run this script:

```bash
./create_and_run_coverage.sh
```

### Implementation Coverage Results

**Pure Implementation Coverage (excluding test code and system headers):**

- **doubly_linked_list.hpp**: **97.8%** of 185 lines covered
- **ordered_map.hpp**: **98.9%** of 91 lines covered

### Coverage Summary

This shows that:

- **97.8%** of the doubly linked list implementation is tested
- **98.9%** of the ordered map implementation is tested
- Only a few edge cases remain uncovered
- The test suite comprehensively exercises the core functionality

The HTML report provides line-by-line coverage details, showing exactly which implementation lines are covered by the test suite.

## GitHub Actions CI

- **Workflow**: `.github/workflows/cmake.yml` automates building and testing on push to `main` or pull requests to `main`.
- **Setup**:
1. Push your repository to GitHub.
2. Ensure `.github/workflows/cmake.yml` exists.
3. CI runs `build.sh` on `ubuntu-latest`, formatting, building, and testing.
- **View Results**:
- Check the "Actions" tab on GitHub for CI logs.

## Adding a New Test

1. **Choose the appropriate test file** in `tests/doubly_linked_list/` based on the functionality being tested:

- `front_and_back.cpp` for front/back operations
- `iterator_tests.cpp` for iterator functionality
- `pop_back_tests.cpp` for pop_back operations
- `pop_front_tests.cpp` for pop_front operations
- `push_back_tests.cpp` for push_back operations
- `push_front_tests.cpp` for push_front operations

2. **Add your test case**:

```cpp
TEST_CASE("Your test description", "[tag]") {
DoublyLinkedList list;
// Your test code here
REQUIRE(/* your assertion */);
}
```

3. **Rebuild and Test**:
```bash
./build.sh
```

## Future Features

- [x] Add std::move and copying semantics
- [x] **DoublyLinkedList:** Add tests for copying & moving
- [x] **DoublyLinkedList:** Add `erase` method to erase elements given their iterator
- [x] **DoublyLinkedList:** Add pre and post decrement operators
- [x] **DoublyLinkedList:** Test front(), back(), insertion and deletion functions for copying behavior
- [x] Add `move_to_front` and `move_to_back` operations in ordered_map to re-order entries (without affecting or copying the entry value)
- [x] **OrderedMap:** Add support for initializing map with intializer list
- [x] **OrderedMap:** Add support for initializing map with two container iterators
- [x] **OrderedMap:** Add `erase` method to erase elements given their iterator or key
- [x] Test for memory leaks
- [x] Add test coverage
- [ ] Add const iterators
- [ ] Add reverse iterators
- [ ] Add performance benchmarks