Ecosyste.ms: Awesome

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

Awesome Lists | Featured Topics | Projects

https://github.com/tower120/trackable_ptr

Smart pointer for any movable objects. When trackable object moved/destroyed, trackers updated with new object's pointer.
https://github.com/tower120/trackable_ptr

cpp pointer smart-pointer

Last synced: 3 months ago
JSON representation

Smart pointer for any movable objects. When trackable object moved/destroyed, trackers updated with new object's pointer.

Awesome Lists containing this project

README

        

[![Build Status](https://travis-ci.org/tower120/trackable_ptr.svg?branch=trackable_base)](https://travis-ci.org/tower120/trackable_ptr)

# trackable_ptr

Trackable pointer. When `trackable` object moved/destroyed, `trackable_ptr`s updated with new object's location.

Allow to have stable pointer on any movable object (in single-threaded environment). Objects may be stack allocated.

Header only. You need only "include" folder.

**Warning!** Performance-wise it is not faster then using heap allocated objects (probably due to size grow). See benchmarks, your mileage may vary.

```c++
struct Data{
int x,y,z;
};

std::vector< unique_trackable > list1;

list1.emplace_back();

trackable_ptr ptr {list1.back()}; // store pointer to element

list1.emplace_back();
list1.emplace_back();
list1.emplace_back();
list1.emplace_back();
// list 1 now uses another memory chuck. All pointers/iterators invalidated.

// ptr still alive and accessible;
std::cout << ptr->x;
```

```cpp
struct Box;

struct Corner{
explicit Corner(Box* box) : box(box) {}

trackable_ptr box;
int x = 0;
int y = 0;
};

struct Box : trackable_base {
Corner lt{this};
Corner rb{this};
};

std::vector boxes;

// Box can be moved around. Corner::box always valid.
// trackable_ptr can be stored in lambda callback.

Box& active_box = boxes[i];
on_some_event([box = trackable_ptr(&active_box)](){
if (!box) return;
std::cout << box->lt.x;
});
```

#### Behavior

On `trackable` destruction - all `trackable_ptr`s becomes nullptr.

On `trackable` move - all `trackable_ptr`s updates with new object location.

On `trackable` copy - `trackable_ptr`s unaffected.

#### `trackable_base`

Inherit this, if you want your class to be compatible with `trackable_ptr`.

```cpp
struct MyClass : trackable_base {}

MyClass m;
trackable_ptr p = &m;
```

#### `trackable`

```cpp
trackable i;
trackable_ptr p = &i;

auto i2 = std::move(i);
assert(p.get() == i2.get());
```

For the sake of sanity, `trackable` is forbidden, use `const trackable` instead.

* `trackable()` - construct object with default constructor, if possible.
* `trackable(T&&)` - conversion constructor.
* `trackable(Args&&... args)` - in-place construct object.
* `trackable(trackable&& other)`
* `trackable(const trackable&)`
* `trackable& operator=(trackable&&)`
* `trackable& operator=(const trackable&)`
* `T* get()` - return object pointer.
* `const T* get() const`
* `T* operator->()`
* `const T* operator->() const`
* `T& operator*()`
* `const T& operator*() const`
* `~trackable()` - update all `trackable_ptr`'s with new nullptr.

#### `unique_trackable`

Same as `trackable`, but move-only.

Useful for use in containers. For example, it is not required for `std::vector` implementation to use move instead copy, when both copy and move constructor are available. Though all tested implementations currently prefer move, whenever possible.

#### `trackable_ptr`

* `trackable_ptr()` - construct with nullptr
* `trackable_ptr(T*)`
* `trackable_ptr(trackable*)`
* `auto* get_trackable() const` - return address of `trackable`, which holds object (return `get()` otherwise).
* `operator bool() const` - return true if not nullptr
* `T* get() const` - return object pointer.
* `T* operator->() const`
* `T& operator*() const`
* `~trackable_ptr()` - exclude this from trackers list.

#### "trackable_ptr_extensions.h"

```c++
#include

#include

int main() {
std::vector> vec = {1, 2, 3, 4};

trackable_ptr p{vec.begin()};

assert(get_iterator(vec, p) == vec.begin());

return 0;
}
```
Work with contiguous containers only.

* `in_container(const Container&, const trackable_ptr &)` - check if trackable_ptr stored inside contiguous container.
* `get_index(const Container&, const trackable_ptr&)` - return index of element in contiguous container. trackable_ptr must exists inside contiguous container.
* `get_iterator(Container&&, const trackable_ptr &)` - return iterator of element in contiguous container. if trackable_ptr does not exists inside contiguous container, return end().

### Overhead
* 1 ptr for `trackable`
* 3 ptr for `trackable_ptr`
* O(n) complexity for moving/destroying `trackable`. Where n = `tracker_ptr`s per `trackable`
* O(1) complexity for moving/destroying `trackable_ptr`