Skip to main content
Commonmark migration
Source Link

#Implementation

Implementation

#Review goals

Review goals

#Demo

Demo

#Implementation

#Review goals

#Demo

Implementation

Review goals

Demo

added missing header to handle.h: `<functional>`
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
#ifndef HANDLE_H
#define HANDLE_H

#include "vtable.h"
#include <cstddef>
#include <functional>

class handle
{
public:
    ~handle() noexcept;

    template<class T>
    handle(void* blk, T* src) noexcept
        : handle(get_vtable_ptr<T>(), blk, src)
    {}

    handle(handle&& other) noexcept;
    handle& operator=(handle&& other) noexcept;

    handle(handle const&) = delete;
    handle& operator=(handle const&) = delete;
    
    void destroy() noexcept;
    void transfer(void* blk, void* dst);
    handle copy(void* blk, void* dst) const;

    void swap(handle& other) noexcept;
    
    std::size_t align() const noexcept;
    std::size_t size() const noexcept;

    void* blk() const noexcept;
    void* src() const noexcept;

private:
    handle(vtable_t const* vtable, void* blk, void* src) noexcept;
    
    vtable_t const* vtable_;
    void* blk_;
    void* src_;
};

void swap(handle& a, handle& b) noexcept;
bool operator==(handle const& lhs, handle const& rhs) noexcept;
bool operator!=(handle const& lhs, handle const& rhs) noexcept;

namespace std
{
    template<>
    struct hash<handle>
    {
        size_t operator()(handle const& h) const
        {
            return hash<void*>{}(h.src());
        }
    };
}
#endif // HANDLE_H

As the name implied, this was not theThe full implementation (with iterators and a polymorphic_vectorstd::vector<> implementation, which can be implemented as a simple wrapper or derived class-like interface is omitted because of the amount of boilerplate code involved. This question is already long.

A sample toy implementation is provided in the demo below to demonstrate minimal polymorphic_vector_base. There is a lot of boilerplate involved, so I've omitted it from this already very long question usage.

  • Correctness; there are some tricky memory management spots.
  • Performance and efficiency of algorithms.
  • Container choices.

Here is some sample codeNote: The (purely for demonstration) that shows usage ofpolymorphic_vector public interface should be based on polymorphic_vector_basestd::vector<> as defined in the C++ standard. This implementation is purely for demonstrative purposes.

#ifndef HANDLE_H
#define HANDLE_H

#include "vtable.h"
#include <cstddef>

class handle
{
public:
    ~handle() noexcept;

    template<class T>
    handle(void* blk, T* src) noexcept
        : handle(get_vtable_ptr<T>(), blk, src)
    {}

    handle(handle&& other) noexcept;
    handle& operator=(handle&& other) noexcept;

    handle(handle const&) = delete;
    handle& operator=(handle const&) = delete;
    
    void destroy() noexcept;
    void transfer(void* blk, void* dst);
    handle copy(void* blk, void* dst) const;

    void swap(handle& other) noexcept;
    
    std::size_t align() const noexcept;
    std::size_t size() const noexcept;

    void* blk() const noexcept;
    void* src() const noexcept;

private:
    handle(vtable_t const* vtable, void* blk, void* src) noexcept;
    
    vtable_t const* vtable_;
    void* blk_;
    void* src_;
};

void swap(handle& a, handle& b) noexcept;
bool operator==(handle const& lhs, handle const& rhs) noexcept;
bool operator!=(handle const& lhs, handle const& rhs) noexcept;

namespace std
{
    template<>
    struct hash<handle>
    {
        size_t operator()(handle const& h) const
        {
            return hash<void*>{}(h.src());
        }
    };
}
#endif // HANDLE_H

As the name implied, this was not the full polymorphic_vector implementation, which can be implemented as a simple wrapper or derived class of polymorphic_vector_base. There is a lot of boilerplate involved, so I've omitted it from this already very long question.

  • Correctness; there are some tricky memory management spots.
  • Performance and efficiency of algorithms.

Here is some sample code (purely for demonstration) that shows usage of polymorphic_vector_base.

#ifndef HANDLE_H
#define HANDLE_H

#include "vtable.h"
#include <cstddef>
#include <functional>

class handle
{
public:
    ~handle() noexcept;

    template<class T>
    handle(void* blk, T* src) noexcept
        : handle(get_vtable_ptr<T>(), blk, src)
    {}

    handle(handle&& other) noexcept;
    handle& operator=(handle&& other) noexcept;

    handle(handle const&) = delete;
    handle& operator=(handle const&) = delete;
    
    void destroy() noexcept;
    void transfer(void* blk, void* dst);
    handle copy(void* blk, void* dst) const;

    void swap(handle& other) noexcept;
    
    std::size_t align() const noexcept;
    std::size_t size() const noexcept;

    void* blk() const noexcept;
    void* src() const noexcept;

private:
    handle(vtable_t const* vtable, void* blk, void* src) noexcept;
    
    vtable_t const* vtable_;
    void* blk_;
    void* src_;
};

void swap(handle& a, handle& b) noexcept;
bool operator==(handle const& lhs, handle const& rhs) noexcept;
bool operator!=(handle const& lhs, handle const& rhs) noexcept;

namespace std
{
    template<>
    struct hash<handle>
    {
        size_t operator()(handle const& h) const
        {
            return hash<void*>{}(h.src());
        }
    };
}
#endif // HANDLE_H

The full implementation (with iterators and a std::vector<>-like interface is omitted because of the amount of boilerplate code involved. This question is already long.

A sample toy implementation is provided in the demo below to demonstrate minimal polymorphic_vector_base usage.

  • Correctness; there are some tricky memory management spots.
  • Performance and efficiency of algorithms.
  • Container choices.

Note: The polymorphic_vector public interface should be based on std::vector<> as defined in the C++ standard. This implementation is purely for demonstrative purposes.

added 105 characters in body
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
template<class B>
class polymorphic_vector : private polymorphic_vector_base
{
public:
    auto begin()
    {
        /*
       / a proper polymorphic_vector_iterator can be implemented by wrapping
        // around an iterator or an index into handles_.
        */
        return handles_.begin();
    }

    auto end()
    {
        return handles_.end();
    }

    template<class T>
    void push_back(T&& value)
    noexcept(std::is_nothrow_move_constructible<std::decay_t<T>>::value)
    {
        using der_t = std::decay_t<T>;
        ::new (allocate<der_t>()) der_t{ std::move(value) };
    }
    
    // the actual erase function would take an iterator
    void erase(std::size_t const i)
    {
        deallocate(i);
    }
};

template<template<class...> class PolyVec, class T>
void print(PolyVec<T>& pv)
{
    // an actual iterator for polymorphic_vector should not expose handles
    for (auto& h : pv)
        reinterpret_cast<T*>(h.src())->print();
}
template<class B>
class polymorphic_vector : private polymorphic_vector_base
{
public:
    auto begin()
    {
        /*
        a proper polymorphic_vector_iterator can be implemented by wrapping
        around an iterator or an index into handles_.
        */
        return handles_.begin();
    }

    auto end()
    {
        return handles_.end();
    }

    template<class T>
    void push_back(T&& value)
    noexcept(std::is_nothrow_move_constructible<std::decay_t<T>>::value)
    {
        using der_t = std::decay_t<T>;
        ::new (allocate<der_t>()) der_t{ std::move(value) };
    }

    void erase(std::size_t const i)
    {
        deallocate(i);
    }
};

template<template<class...> class PolyVec, class T>
void print(PolyVec<T>& pv)
{
    // 
    for (auto& h : pv)
        reinterpret_cast<T*>(h.src())->print();
}
template<class B>
class polymorphic_vector : private polymorphic_vector_base
{
public:
    auto begin()
    {
        // a proper polymorphic_vector_iterator can be implemented by wrapping
        // around an iterator or an index into handles_
        return handles_.begin();
    }

    auto end()
    {
        return handles_.end();
    }

    template<class T>
    void push_back(T&& value)
    noexcept(std::is_nothrow_move_constructible<std::decay_t<T>>::value)
    {
        using der_t = std::decay_t<T>;
        ::new (allocate<der_t>()) der_t{ std::move(value) };
    }
    
    // the actual erase function would take an iterator
    void erase(std::size_t const i)
    {
        deallocate(i);
    }
};

template<template<class...> class PolyVec, class T>
void print(PolyVec<T>& pv)
{
    // an actual iterator for polymorphic_vector should not expose handles
    for (auto& h : pv)
        reinterpret_cast<T*>(h.src())->print();
}
added missing headers in polymorphic_vector_base.cpp: `<cstdlib>`, `<cassert>`
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
moved `<cassert>` header from handle.h to handle.cpp
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
simplified `transfer()` functions by using the `type` alias provided by `std::is_movable<>` in vtable.h
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
simplified public `handle` constructor by having it call the private one.
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
`get_vtable_ptr()`'s static `vtable_t` is now `const`.
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
added missing header to polymorphic_vector_base.h
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
added 3 characters in body
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
better handle description
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
better vtable_t description
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
added destructor for polymorphic_vector_base
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
added 347 characters in body
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
Tweeted twitter.com/StackCodeReview/status/786743519952134144
added 30 characters in body
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
added 36 characters in body
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
added 36 characters in body
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading
Source Link
user2296177
  • 3.6k
  • 1
  • 16
  • 37
Loading