The idea behind the below code is that I can index a sequence with a sequence of indices and get a std::vector
of the indexed elements:
multi_index.hpp
#ifndef NET_CODERODDE_UTIL_MULTI_INDEX_HPP
#define NET_CODERODDE_UTIL_MULTI_INDEX_HPP
#include <algorithm>
#include <exception>
#include <iostream>
#include <iterator>
#include <sstream>
namespace net::coderodde::util {
template<typename IteratorIndex>
using index_type =
typename std::iterator_traits<IteratorIndex>::value_type;
template<typename IteratorElem>
using element_count_type =
typename std::iterator_traits<IteratorElem>::difference_type;
template<typename IteratorElem>
using element_type =
typename std::iterator_traits<IteratorElem>::value_type;
//// ///////////////////////////////////////////////
// Throws an exception if the index is negative. //
/////////////////////////////////////////////// ////
template<typename index_type>
static void throw_index_negative(index_type index)
{
std::stringstream ss;
ss << "index(" << index << ") < 0";
throw std::runtime_error{ss.str()};
}
//// ////////////////////////////////////////////////
// Throws an exception if the index is too large. //
//////////////////////////////////////////////// ////
template<typename index_type,
typename element_count_type>
static void throw_index_too_large(index_type index,
element_count_type size)
{
std::stringstream ss;
ss << "index(" << index << ") >= elem_count(" << size << ")";
throw std::runtime_error{ss.str()};
}
template<typename IteratorElem,
typename IteratorIndex>
static void check_indices(IteratorElem elem_begin,
IteratorElem elem_end,
IteratorIndex index_begin,
IteratorIndex index_end)
{
// Find the length of the element sequence:
typename std::iterator_traits<IteratorElem>
::difference_type elem_count = std::distance(elem_begin,
elem_end);
using IndexType =
typename std::iterator_traits<IteratorIndex>::value_type;
// Check that each index does not refer outside the element sequence:
std::for_each(index_begin, index_end, [elem_count](IndexType index) {
if (index < 0) { throw_index_negative(index); }
if (index >= elem_count) { throw_index_too_large(index,
elem_count);}
});
}
template<typename IteratorElem,
typename IteratorIndex>
std::vector<typename std::iterator_traits<IteratorElem>::value_type>
multi_index(IteratorElem elem_begin,
IteratorElem elem_end,
IteratorIndex index_begin,
IteratorIndex index_end)
{
check_indices(elem_begin,
elem_end,
index_begin,
index_end);
using ElementType =
typename std::iterator_traits<IteratorElem>::value_type;
using IndexType =
typename std::iterator_traits<IteratorIndex>::value_type;
std::vector<ElementType> result;
std::for_each(index_begin,
index_end,
[elem_begin, &result](IndexType index) {
auto it = elem_begin;
std::advance(it, index);
result.push_back(*it);
});
return result;
}
}
#endif // NET_CODERODDE_UTIL_MULTI_INDEX_HPP
main.cpp
#include "multi_index.hpp"
#include <exception>
#include <iostream>
#include <list>
#include <vector>
using net::coderodde::util::multi_index;
static std::vector<char> get_alphabet() {
std::vector<char> alphabet;
for (char ch = 'a'; ch <= 'z'; ch++)
{
alphabet.push_back(ch);
}
for (char ch = 'A'; ch <= 'Z'; ch++)
{
alphabet.push_back(ch);
}
alphabet.push_back(',');
alphabet.push_back(' ');
alphabet.push_back('!');
alphabet.push_back('\n');
return alphabet;
}
int main(int argc, const char * argv[]) {
std::vector<char> alphabet = get_alphabet();
std::list<int> char_indices =
{ 33, 4, 11, 11, 14, 52, 53, 48, 14, 17, 11, 3, 54, 55 };
std::vector<char> result = multi_index(alphabet.cbegin(),
alphabet.cend(),
char_indices.cbegin(),
char_indices.cend());
std::ostream_iterator<char> out_iterator(std::cout);
std::copy(result.cbegin(), result.cend(), out_iterator);
try {
char_indices = { 0, 1, 2, -1, 3 };
multi_index(alphabet.cbegin(),
alphabet.cend(),
char_indices.cbegin(),
char_indices.cend());
} catch (std::runtime_error& err) {
std::cout << err.what() << "\n";
}
try {
char_indices = { 0, 1, 2, 56, 3 };
multi_index(alphabet.cbegin(),
alphabet.cend(),
char_indices.cbegin(),
char_indices.cend());
} catch (std::runtime_error& err) {
std::cout << err.what() << "\n";
}
return 0;
}
Outputs:
Hello, World! index(-1) < 0 index(56) >= elem_count(56)
Critique request
Please tell me anything that comes to mind. Also, I would like to hear about using move semantics: is there anything I could move instead of copying?