Skip to content

Instantly share code, notes, and snippets.

@hnrck
Created September 7, 2020 06:57
Show Gist options
  • Save hnrck/c6fe4251ab8eff97ab97ebaf3dc78638 to your computer and use it in GitHub Desktop.
Save hnrck/c6fe4251ab8eff97ab97ebaf3dc78638 to your computer and use it in GitHub Desktop.
Implementation example of a generic container class in C++20

Generic container class

Implementation example of a generic container class in C++20

Summary

Members Descriptions
class Stuff An example class.
class Stuffs The stuffs container class
struct Back for stuffs list
struct StuffAdder Stuff add functor

class Stuff

An example class.

Parameters

  • Container the kind of container to add in

Summary

Members Descriptions
public Stuff() = default Default constructor
public inline explicit Stuff(int value) Constructor
public ~Stuff() = default Default destructor
public Stuff(const Stuff &) = delete Deleted copy constructor
public Stuff&operator=(const Stuff &) = delete Deleted copy assignment
public Stuff(Stuff &&) = default
public Stuff&operator=(Stuff &&) = default Default move constructor
public inline auto get_value() const Default move assignement
public inline auto operator<(const Stuff & other) const Less than function
public inline auto operator==(const Stuff & other) const Equal function

Members

public Stuff() = default

public inline explicit Stuff(int value)

public ~Stuff() = default

public Stuff(const Stuff &) = delete

public Stuff&operator=(const Stuff &) = delete

public Stuff(Stuff &&) = default

public Stuff&operator=(Stuff &&) = default

public inline auto get_value() const

public inline auto operator<(const Stuff & other) const

public inline auto operator==(const Stuff & other) const

class Stuffs

Parameters

  • Container The kind of stuff container

  • [StuffAdder](#struct_stuff_adder) The container stuff add functor, the default Container one by default

Summary

Members Descriptions
public Stuffs() = default Default constructor
public inline auto add_stuff(Stuff && stuff) Add stuff function
public inline auto begin() Begin iterator generator
public inline auto end() End iterator generator
public inline auto begin() const Begin const iterator generator
public inline auto end() const End const iterator generator

Members

public Stuffs() = default

public inline auto add_stuff(Stuff && stuff)

public inline auto begin()

public inline auto end()

public inline auto begin() const

public inline auto end() const

struct StuffAdder

Summary

Members Descriptions
public auto operator()(Container & stuffs,Stuff && stuff) const Fonctor call operator

Members

public auto operator()(Container & stuffs,Stuff && stuff) const

Generated by Moxygen

cmake_minimum_required(VERSION 3.17)
project(generic_container_class)
set(CMAKE_CXX_STANDARD 20)
add_executable(generic_container_class main.cpp stuff.h stuffs.h)
/// @file main.cpp
/// @author Henrick Deschamps
///
/// @brief main file, example of stuffs use
#include "stuffs.h"
/// @struct Back add functor for stuffs list
struct [[maybe_unused]] ListStuffBackAdder final {
/// @fn Call operator
/// @param stuffs Stuffs list to push in
/// @param stuff Stuff to add to list
auto operator()(std::list<Stuff> &stuffs, Stuff &&stuff) const -> void { stuffs.push_back(std::move(stuff)); }
};
/// @fn test
/// @brief test function for different kind of container
/// @tparam Container a stuff container type, std::vector<Stuff> by default
/// @tparam StuffAdder a stuff container add functor, the container default one by default
/// @param stuffs a stuff list
template<class Container = std::vector<Stuff>, class StuffAdder = StuffAdder<Container>>
static inline auto test(Stuffs<Container, StuffAdder> &stuffs) -> void {
for (auto value = 0; value < 10; ++value) {
auto &&stuff = Stuff(static_cast<int>(value / 2));
stuffs.add_stuff(std::move(stuff));
}
stuffs.add_stuff(Stuff(8));
stuffs.add_stuff(Stuff(5));
stuffs.add_stuff(Stuff(9));
stuffs.add_stuff(Stuff(7));
stuffs.add_stuff(Stuff(6));
for (const auto &stuff: stuffs) {
std::cout << stuff << " ";
}
std::cout << std::endl;
std::cout << std::flush;
}
/// @fn main
/// @brief main function
/// @return EXIT_SUCCESS if OK
auto main() -> int {
auto vec_stuffs = Stuffs{};
auto array_stuffs = Stuffs<std::array<Stuff, BUFFER_LEN>>{};
auto deque_stuffs = Stuffs<std::deque<Stuff>>{};
auto list_1_stuffs = Stuffs<std::list<Stuff>>{};
auto list_2_stuffs = Stuffs<std::list<Stuff>, ListStuffBackAdder>{};
auto fwd_list_stuffs = Stuffs<std::forward_list<Stuff>>{};
auto set_stuffs = Stuffs<std::set<Stuff>>{};
auto multiset_stuffs = Stuffs<std::multiset<Stuff>>{};
auto unord_set_stuffs = Stuffs<std::unordered_set<Stuff>>{};
auto unord_multiset_stuffs = Stuffs<std::unordered_multiset<Stuff>>{};
test(vec_stuffs);
test(array_stuffs);
test(deque_stuffs);
test(list_1_stuffs);
test(list_2_stuffs);
test(fwd_list_stuffs);
test(set_stuffs);
test(multiset_stuffs);
test(unord_set_stuffs);
test(unord_multiset_stuffs);
return (EXIT_SUCCESS);
}
/// @file stuff.h
/// @author Henrick Deschamps
///
/// @brief Stuff object, for example
#ifndef GENERIC_CONTAINER_CLASS__STUFF_H
#define GENERIC_CONTAINER_CLASS__STUFF_H
#include <ostream>
/// @class Stuff
/// @brief An example class
class Stuff final {
private:
/// @var A value
int value{0};
public:
/// @fn Stuff default constructor
Stuff() = default;
/// @fn Stuff constructor
/// @param value a value
explicit Stuff(int value) : value(value) {}
/// @fn Stuff default destructor
~Stuff() = default;
/// @fn Deleted Stuff copy constructor
Stuff(const Stuff &) = delete;
/// @fn Deleted Stuff copy assignment
Stuff &operator=(const Stuff &) = delete;
/// @fn Default Stuff move constructor
Stuff(Stuff &&) noexcept = default;
/// @fn Default Stuff move assignment
Stuff &operator=(Stuff &&) noexcept = default;
/// @fn Value getter
/// @return The value
[[nodiscard]] auto get_value() const -> int { return (value); }
/// @fn Insertion operator
/// @param os An std::ostream reference to insert in
/// @param stuff A const reference to a stuff
/// @return The inserted std::ostream ref
friend auto operator<<(std::ostream &os, const Stuff &stuff) -> std::ostream & {
return (os << stuff.get_value());
}
/// @fn Less than function
/// @param other Other stuff to compare with
/// @return true if stuff is lesser than other, else false
auto operator<(const Stuff &other) const -> bool {
return (value < other.value);
}
/// @fn Equal than function
/// @param other Other stuff to compare with
/// @return true if stuff equal the other, else false
auto operator==(const Stuff &other) const -> bool {
return (value == other.value);
}
};
template<> struct [[maybe_unused]] std::hash<Stuff> {
auto operator()(const Stuff &stuff) const -> std::size_t { return (std::hash<int>{}(stuff.get_value())); }
};
#endif // GENERIC_CONTAINER_CLASS__STUFF_H
/// @file stuffs.h
/// @author Henrick Deschamps
///
/// @brief Stuffs container class
#ifndef GENERIC_CONTAINER_CLASS__STUFFS_H
#define GENERIC_CONTAINER_CLASS__STUFFS_H
#include <array>
#include <deque>
#include <iostream>
#include <iterator>
#include <forward_list>
#include <list>
#include <set>
#include <unordered_set>
#include <vector>
#include "stuff.h"
/// @class Stuff add functor
/// @tparam Container the kind of container to add in
template<class Container>
struct [[maybe_unused]] StuffAdder final {
/// @fn Call operator
/// @param stuffs The stuffs container to add in
/// @param stuff The stuff to add to the container
auto operator()(Container &stuffs, Stuff &&stuff) const -> void;
};
template<class Container>
auto StuffAdder<Container>::operator()(Container &stuffs, Stuff &&stuff) const -> void {
throw std::runtime_error("Unimplemented");
}
/// @class Stuffs container
/// @tparam Container The kind of stuff container
/// @tparam StuffAdder The container stuff add functor, the default Container one by default
template<class Container = std::vector<Stuff>, class StuffAdder = StuffAdder<Container>>
class Stuffs final {
private:
/// @var The container
Container container{};
/// @var The container stuff add functor
StuffAdder stuff_adder_functor{};
/// @typedef The container iterator
using ContainerIt = typename Container::iterator;
/// @typedef The container const iterator
using ContainerConstIt = typename Container::const_iterator;
public:
/// @fn Stuff default constructor
Stuffs() = default;
/// @fn Add stuff
/// @brief Add a stuff to the stuff container
/// @param stuff The stuff to add
[[maybe_unused]] auto add_stuff(Stuff &&stuff) -> void {
stuff_adder_functor(container, std::move(stuff));
}
/// @fn Stuff container begin iterator generator
/// @return Begin iterator
[[maybe_unused]] [[nodiscard]] inline auto begin() -> ContainerIt { return container.begin(); }
/// @fn Stuff container end iterator generator
/// @return End iterator
[[maybe_unused]] [[nodiscard]] inline auto end() -> ContainerIt { return container.end(); }
/// @fn Stuff container begin const iterator generator
/// @return Begin const iterator
[[maybe_unused]] [[nodiscard]] inline auto begin() const -> ContainerConstIt { return container.begin(); }
/// @fn Stuff container end const iterator generator
/// @return End const iterator
[[maybe_unused]] [[nodiscard]] inline auto end() const -> ContainerConstIt { return container.end(); }
};
template<>
struct [[maybe_unused]] StuffAdder<std::vector<Stuff>> final {
auto operator()(std::vector<Stuff> &stuffs,
Stuff &&stuff) const -> void { stuffs.push_back(std::move(stuff)); };
};
constexpr auto BUFFER_LEN = (10U);
template<>
struct [[maybe_unused]] StuffAdder<std::array<Stuff, BUFFER_LEN>> final {
static unsigned int index;
auto operator()(std::array<Stuff, BUFFER_LEN> &stuffs, Stuff &&stuff) const -> void {
stuffs[index++ % BUFFER_LEN] = std::move(stuff);
}
};
unsigned int StuffAdder<std::array<Stuff, BUFFER_LEN>>::index = 0U;
template<>
struct [[maybe_unused]] StuffAdder<std::deque<Stuff>> final {
auto operator()(std::deque<Stuff> &stuffs, Stuff &&stuff) const -> void { stuffs.push_back(std::move(stuff)); }
};
template<>
struct [[maybe_unused]] StuffAdder<std::list<Stuff>> final {
auto operator()(std::list<Stuff> &stuffs, Stuff &&stuff) const -> void { stuffs.push_front(std::move(stuff)); }
};
template<>
struct [[maybe_unused]] StuffAdder<std::forward_list<Stuff>> final {
auto operator()(std::forward_list<Stuff> &stuffs,
Stuff &&stuff) const -> void { stuffs.push_front(std::move(stuff)); }
};
template<>
struct [[maybe_unused]] StuffAdder<std::set<Stuff>> final {
auto operator()(std::set<Stuff> &stuffs, Stuff &&stuff) const -> void { stuffs.insert(std::move(stuff)); }
};
template<>
struct [[maybe_unused]] StuffAdder<std::multiset<Stuff>> final {
auto operator()(std::multiset<Stuff> &stuffs, Stuff &&stuff) const -> void { stuffs.insert(std::move(stuff)); }
};
template<>
struct [[maybe_unused]] StuffAdder<std::unordered_set<Stuff>> final {
auto operator()(std::unordered_set<Stuff> &stuffs, Stuff &&stuff) const -> void { stuffs.insert(std::move(stuff)); }
};
template<>
struct [[maybe_unused]] StuffAdder<std::unordered_multiset<Stuff>> final {
auto operator()(std::unordered_multiset<Stuff> &stuffs, Stuff &&stuff) -> void { stuffs.insert(std::move(stuff)); }
};
#endif //GENERIC_CONTAINER_CLASS__STUFFS_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment