Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@BruJu
Last active February 22, 2020 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BruJu/f382850fee3a309681be71b9b6795ffb to your computer and use it in GitHub Desktop.
Save BruJu/f382850fee3a309681be71b9b6795ffb to your computer and use it in GitHub Desktop.
Misc C++ Experiments

For a personal project I work a lot on C++ but for some reason, I can't make my work public.

I often do some experiments on an online compiler website called cpp.sh and I thought "why not expose these experiments to show the world I'm actually learning C++".

// "How to pass a function in a template parameter ?"
// (I wanted to pass a lambda but it is not possible)
// 2019-12-27
#include <iostream>
#include <string>
#include <vector>
#include <array>
template <typename NUMBER>
struct Reducer {
constexpr int operator()(NUMBER value) {
return value % 3;
}
};
template <typename NUMBER, typename REDUCER = Reducer<NUMBER>>
struct Storage {
std::vector<NUMBER> values{};
std::array<unsigned int, 3> reduced{{0, 0, 0}};
void add(NUMBER n) {
values.push_back(n);
++reduced[REDUCER()(n)];
}
};
int main()
{
Storage<int> s{};
s.add(7);
s.add(4);
s.add(1);
for (size_t i = 0 ; i != 3 ; ++i) {
printf("reduced[%zu] = %u\n", i, s.reduced[i]);
}
}
// "A std::vector / flat_unordered_set where some elements can be missing"
// 2019-12-27
// I dropped this implementation because the optional part means there is a boolean
// for each value so I decided to use another approach to know if there is a value or not.
// (using a function)
// Returning a pointer that means "no value if nullptr" is a behaviour required by the
// project. (This class has been created to replace and improve another implementation)
#include <vector>
#include <optional>
/**
* A class that stores a list of values that are indexed by a number (their ID).
* They are contiguously stored, with some values that may be missing.
*/
template <typename DATA>
class PropertyIndexer final {
private:
std::vector<std::optional<DATA>> _data{};
public:
/**
* Insert the data at the position index
* @param index The position where to insert the data
* @param data The data to insert. Will be placed using a copy.
*/
void insert(size_t index, const DATA & data) {
if (_data.size() <= index) {
_data.reserve(index * 2);
_data.resize(index - 1);
}
if (_data.size() == index) {
_data.emplace_back(data);
} else {
_data[index] = data;
}
}
void optimize() {
_data.shrink_to_fit();
}
DATA * get(size_t index) {
if (index >= _data.size()) {
return nullptr;
} else {
auto & data = _data[index];
if (data.has_value()) {
return &(data.value());
} else {
return nullptr;
}
}
}
const DATA * get(size_t index) const {
if (index >= _data.size()) {
return nullptr;
} else {
const auto & data = _data[index];
if (data.has_value()) {
return &(data.value());
} else {
return nullptr;
}
}
}
template <typename DATA>
class Iterator {
private:
PropertyIndexer<DATA> * indexer;
size_t currentPosition;
public:
Iterator(PropertyIndexer<DATA> * indexer) : indexer(indexer) {
currentPosition = 0;
while (currentPosition != indexer->_data.size() && !indexer->_data[currentPosition].has_value()) {
++currentPosition;
}
}
Iterator(PropertyIndexer<DATA> * indexer, size_t position)
: indexer(indexer), currentPosition(position) { }
Iterator & operator++() {
if (currentPosition != indexer->_data.size()) {
do {
++currentPosition;
} while (currentPosition != indexer->_data.size() && !indexer->_data[currentPosition].has_value());
}
return *this;
}
Iterator operator++(int) {
Iterator copy = *this;
operator++();
return copy;
}
bool operator==(const Iterator & other) {
return indexer == other.indexer && currentPosition == other.currentPosition;
}
bool operator!=(const Iterator & other) { return !operator==(other); }
DATA & operator*() {
auto & it = indexer->_data[currentPosition];
return indexer->_data[currentPosition].value();
}
};
Iterator<DATA> begin() {
return Iterator<DATA>(this);
}
Iterator<DATA> end() {
return Iterator<DATA>(this, _data.size());
}
};
// I thought it was funny that a function templated by a value that is ignored
// can still have an impact on the program output
template<int _>
int print(bool silence = false) {
static int counter = 0;
if (!silence)
std::cout << "Blah ";
return ++counter;
}
int main()
{
for (size_t i = 0 ; i != 50 ; ++i) {
if (i % 3 == 0) {
print<0>();
} else if (i % 7 == 0) {
print<1>();
} else {
print<2>();
}
if (i % 10 == 9) {
std::cout << "\n";
}
}
int zero = print<0>(true);
int one = print<1>(true);
int two = print<2>(true);
std::cout << "\n" << zero << " " << one << " " << two << "\n"; // 18 6 29
}
// When std::guard_lock and std::mutex::try_lock have a son
// (Currently looking for a fun name for my utility namespace based on my name)
namespace brutil {
class try_guard_lock final {
private:
std::mutex * mutex;
public:
explicit try_guard_lock(std::mutex & mutex) {
if (mutex.try_lock()) {
this->mutex = &mutex;
} else {
this->mutex = nullptr;
}
}
try_guard_lock(const try_guard_lock & other) = delete;
try_guard_lock & operator=(const try_guard_lock & other) = delete;
try_guard_lock(try_guard_lock && other) noexcept : mutex(other.mutex) {
other.mutex = nullptr;
}
try_guard_lock & operator=(try_guard_lock && other) noexcept {
if (mutex) {
mutex->unlock();
}
mutex = other.mutex;
other.mutex = nullptr;
return *this;
}
~try_guard_lock() {
if (mutex) {
mutex->unlock();
}
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment