SCHEDULED DOWNTIME: GitLab's virtual host needs to be rebooted in order to apply security updates. The reboot will occur on Wednesday 2021-10-18 between 03:45 and 4:00 AM.

README.md 7.25 KB
Newer Older
1
2
3
4
5
6

# emlabcpp

This library is a collection of small tools used by our laboratory in C++ code.
The tools are primary designed for embedded environment - we avoid dynamic allocation of memory.

Jan Koniarik's avatar
Jan Koniarik committed
7
Repository is at https://gitlab.fi.muni.cz/xkoniar/emlabcpp and mirrored to github repository https://github.com/emlab-fi/emlabcpp 
Jan Koniarik's avatar
Jan Koniarik committed
8
NOTE: examples were not tested. may contain typos
Jan Koniarik's avatar
Jan Koniarik committed
9

10
11
12
## algorithm.h
Contains a subset of algorithms from \<algorith\> standard library, with a two major changes:
 1. All functions expects container with begin/end iterators as an input, not the iterators themselves
13
 2. Functions are able to iterate over `std::tuple`
14
15
 
This is expanded with other short functions representing simple algorithms and necessary stuff.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
The two core functions are `find_if` and `for_each`, both are implemented with variant over containers and tuples.

```cpp
std::tuple< int, std::string > tpl_data;
std::vector< int > vec_data;
for_each(tpl_data, [&]( const auto & item ){
    std::cout << item << '\n';
});
for_each(vec_data, [&]( int item ){
    std::cout << item << '\n';
});

std::size_t index = find_if(tpl_data, [&]( auto item ){
    return std::is_same_v< decltype(item), std::string >(item);
});
auto iter = find_if(vec_data, [&]( int i ){
    return i != 0;
});

```

37
38
39

## either.h

40
`either<A,B>` is `std::variant` alternative able to hold only two types.
41
42
43
Either however contains multiple methods to transform it's state and type.
This makes it possible to chain the changes in the code.

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
```cpp
using error = std::string;

either<U, error> fuu();

either<T, error> foo(int i)
{
    return fuu()
        .convert_left([&](U val){
            T res{val};
            T.do_magic(i);
            return res;
        })
        .convert_right([&](error e){
            return "Magic was not done :(, sub error is: " + e;
        });
}

foo(42).match(
    [&](T val){
        std::cout << "T happend\o/: " << val << "\n";
    },[&](error e){
        std::cerr << "error happend :(: " << e << "\n";
    })
```

70
71
72
## iterator.h

contains generic_iterator\<Derived\> CRTP baseclass. 
73
This simplifies implementation of custom iterators, as most of the methods/operators we expect of iterators can be implemented based on a small set of functions. (operator+, operator++(int), operator++ can be implemetned with operator+=)
74
75

For implementing iterator, you only provide the basic subset for this class and it takes care of the rest.
76
Keep in mind that this is for "general" use case, and for optimallity you may be better served with fully custom iterator.
77
78
79
80
81

### iterators/access.h

Iterators overlays the data stored in input container, and provides access only to 'reference' provided by function out of item in the container.

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
```cpp

struct foo{
    std::string attr;
}

std::vector<foo> vec_data;

auto acview = access_view(vec_data, [](const foo& item){ return item.attr; });

for(const std::string & item : acview)
{
    std::cout << item << '\n';
}
```

98
99
### iterators/numeric.h

100
101
102
103
Iterator that mimics real data container of sequence of numbers. The number is stored inside the iterator and when iterator is advanced, so is the internal value changed. Contains also functions like `range(from,to)` that creates a range from this iterators.

```cpp
std::vector<int> vec_data;
104

105
106
107
108
109
for(std::size_t i : range(vec_data.size()-1))
{
    std::cout << vec_data[i] << '-' << vec_data[i+1] << '\n';
}
```
110
111
112

### iterators/subscript.h

113
114
115
116
117
118
119
120
121
122
Iterator over datatype that implemented operator[] but does not have iterators.

```cpp
std::bitset<32> bit_data;

for(bool b : subscript_view(bit_data))
{
    std::cout << (b ? 'a' : 'b');
}
```
123
124
125
126
127
128
129
130
131
132

## physical_quantity.h

System of physical quantities based on quantity.hs
These represent physical quantity that remembers it's unit in it's own type (templated).

This makes it possible to have velocity/length/time represented with this template, where each quantity is different type.
Also, the result type of operations like  length divided by time is of type velocity.

This increases safety of physical computations, as it enforces correct units in the math.
133
134
135
136
137
138
139
140
141
142
The `operator<<` is overloaded to output units for the type, such as: `0.25m`

```cpp
position uniform_accel(position s0, velocity v0, acceleration a, timeq t)
{
    return s0 + v0*t + 0.5*a*t*t;
}

std::cout << position{0.25};
```
143
144
145

## pid.h

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
Basic PID regulator implementation using floats, templated based on the time type;

```cpp
using time_t = uint32_t;
pid<time_t>::config conf = {
    .p = 0.5f, 
    .i = 0.005f, 
    .d = 0.2f, 
    .min = 0.0f, 
    .max = 256.0f
    };
pid<time_t> regulator{time{0}, conf};

time_t time = 0;
float state = 0.0f;
while(true)
{
    regulator.update(time, state, std::cos(time*0.05f));
    state = regulator.output();

    time += 1;
}
```
169
170
171
172

## quantity.h

Simple thin overlay over numeric types, that gives abillity to implement strongly typed numeric types.
173
This is handy in case you want to enforce correctness on type level. See implementation of physical_quantity as an example.
174
175
176
177
178
179

## static_circular_buffer.h

Basic implementation of circular buffer with static maximal size, that can store non-default constructible elements.
No dynamic allocation is used.

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
```cpp
static_circular_buffer<std::byte, 256> buffr;

for(int i : {0,1,2,3,4,5,6})
{
    buffr.push_back(i);
}

for(int i : buffr)
{
    std::cout << i << ",";
}

while(!buffr.empty())
{
    buffr.pop_front();
}
```

199
200
201
202
203
204
205
## static_vector.h

Basic implementation of vector with static maximal size, that can store non-default constructible elements.
No dynamic allocation is used.

## types.h

206
207
208
209
210
211
212
213
214
215
216
217
218
219
A library of helpers for type inspection, this contains types similar to type_traits of standard library.
This follows the pattern of std:: library - type check is structure with `::value`/`::type` attributes and using for \_v/\_t suffixed aliases exists.

```cpp
using data = std::vector<int>;

auto fun = [](int i) -> std::string
{
    return std::to_string(i)
};
using fun = decltype(fun);

static_assert(std::is_same_v<mapped_t<data, fun>, std::string>);
```
220
221
222
223
224

## view.h

Simple container storing a pair of iterators to different container - non-owning container of data.
This makes it possible to use API that expects data container as input, rather then pair of iterators.
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
You can also use this to return as a iterator range instead of just `std::pair` of iterators.

```cpp

std::vector<int> vec_data{1,2,3,4,5,6};

for(int i : view{vec_data})
{
    std::cout << i << ',';
}
std::cout << '\n';

for(int i : view{vec_data.begin() + 2, vec_data.end()})
{
    std::cout << i << ',';
}
std::cout << '\n';

for(int i : view_n(vec_data, 4))
{
    std::cout << i << ',';
}
std::cout << '\n';

for(int i : reversed(vec_data))
{
    std::cout << i << ',';
}
std::cout << '\n';
```
255
256
257
258
259
260
261

## zip.h

zip iterator over multiple data containers, which dereference value is tuple of references to provided containers.

This is especially handy in combination with numeric iterator. Example is `enumerate(cont)` which returns zip of range over cont size and cont itself, which behaves same as enumerate on python.

262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
```cpp

std::vector<int> vec_data{-1,1,-1,1,-1,1};

for(int [i,val] : enumerate(vec_data))
{
    std::cout << i << "\t:" << val << '\n';
}

std::vector<std::string> names = {"john", "clark"};
std::vector<std::string> surnames = {"deer", "kent"};

for(int [name, surname] : zip(names, surnames))
{
    std::cout << name << '\t' << surname << '\n';
}

```