Skip to content

Instantly share code, notes, and snippets.

@yohhoy
Created April 2, 2012 05:09
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 yohhoy/2280921 to your computer and use it in GitHub Desktop.
Save yohhoy/2280921 to your computer and use it in GitHub Desktop.
Mockup implementation of TBB
/*
* Mockup implementation of Threading Building Blocks(TBB) library
*
* (C) Copyright yohhoy 2012.
* Distributed under the Boost Software License, Version 1.0.
* (See copy at http://www.boost.org/LICENSE_1_0.txt)
*
* Support:
* - Range concept (except `blocked_range3d')
* - Parallel algorithms (except `pipeline'/`parallel_pipeline')
* - template class `atomic<T>'
* - Timing classes (sloppy implementation with `std::time()')
* - class `task_scheduler_init'
*/
#ifndef TBB_STUB_H_INCLUDED_
#define TBB_STUB_H_INCLUDED_
#include <cstddef>
#include <ctime>
#include <deque>
#include <algorithm>
#include <iterator>
// Version Information
#define TBB_INTERFACE_VERSION 0
#define TBB_INTERFACE_VERSION_MAJOR 0
#define TBB_COMPATIBLE_INTERFACE_VERSION 0
extern "C" inline int TBB_runtime_interface_version() { return 0; }
namespace tbb {
// Split tag
class split {};
// Range Concept
template<typename Value>
class blocked_range {
public:
typedef std::size_t size_type;
typedef Value const_iterator;
blocked_range(Value begin, Value end, size_type grainsize = 1)
: begin_(begin), end_(end), grainsize_(grainsize) {}
// blocked_range(blocked_range& range, split);
size_type size() const { return end_ - begin_; }
bool empty() const { return begin < end_; }
size_type grainsize() const { return grainsize_; }
bool is_divisible() const { return false; }
const_iterator begin() const { return begin_; }
const_iterator end() const { return end_; }
private:
Value begin_, end_;
size_type grainsize_;
};
template<typename RowValue, typename ColValue = RowValue>
class blocked_range2d {
public:
typedef blocked_range<RowValue> row_range_type;
typedef blocked_range<ColValue> col_range_type;
blocked_range2d(RowValue row_begin, RowValue row_end, typename row_range_type::size_type row_grainsize,
ColValue col_begin, ColValue col_end, typename col_range_type::size_type col_grainsize)
: row_(row_begin, row_end, row_grainsize), col_(col_begin, col_end, col_grainsize) {}
blocked_range2d(RowValue row_begin, RowValue row_end, ColValue col_begin, ColValue col_end)
: row_(row_begin, row_end), col_(col_begin, col_end) {}
// blocked_range2d( blocked_range2d& r, split );
bool empty() const { return row_.empty() || col_.empty(); }
bool is_divisible() const { return false; }
const row_range_type& rows() const { return row_; }
const col_range_type& cols() const { return col_; }
private:
row_range_type row_;
col_range_type col_;
};
// Partitioners
class auto_partitioner {};
class affinity_partitioner {};
class simple_partitioner {};
// parallel_for Template
template<class Index, class Func>
void parallel_for(Index first, Index last, const Func& func)
{
parallel_for(first, last, static_cast<Index>(1), func);
}
template<class Index, class Func>
void parallel_for(Index first, Index last, Index step, const Func& func)
{
for (; first < last; first += step)
func(first);
}
template<class Range, class Body>
void parallel_for(const Range& range, const Body& body)
{
body(range);
}
template<class Range, class Body>
void parallel_for(const Range& range, const Body& body, const auto_partitioner&)
{ parallel_for(range, body); }
template<class Range, class Body>
void parallel_for(const Range& range, const Body& body, const affinity_partitioner&)
{ parallel_for(range, body); }
template<class Range, class Body>
void parallel_for(const Range& range, const Body& body, const simple_partitioner&)
{ parallel_for(range, body); }
// parallel_reduce Template
template<typename Range, typename Value, typename Func, typename Reduction>
Value parallel_reduce(const Range& range, const Value& identity, const Func& func, const Reduction&)
{
return func(range, identity);
}
template<typename Range, typename Value, typename Func, typename Reduction>
Value parallel_reduce(const Range& range, const Value& identity, const Func& func, const Reduction&, const auto_partitioner&)
{ return parallel_reduce(range, identity, func); }
template<typename Range, typename Value, typename Func, typename Reduction>
Value parallel_reduce(const Range& range, const Value& identity, const Func& func, const Reduction&, const affinity_partitioner&)
{ return parallel_reduce(range, identity, func); }
template<typename Range, typename Value, typename Func, typename Reduction>
Value parallel_reduce(const Range& range, const Value& identity, const Func& func, const Reduction&, const simple_partitioner&)
{ return parallel_reduce(range, identity, func); }
template<typename Range, typename Body>
void parallel_reduce(const Range& range, Body& body)
{
body(range);
}
template<typename Range, typename Body>
void parallel_reduce(const Range& range, Body& body, const auto_partitioner&)
{ parallel_reduce(range, body); }
template<typename Range, typename Body>
void parallel_reduce(const Range& range, Body& body, const affinity_partitioner&)
{ parallel_reduce(range, body); }
template<typename Range, typename Body>
void parallel_reduce(const Range& range, Body& body, const simple_partitioner&)
{ parallel_reduce(range, body); }
// parallel_scan Template
struct pre_scan_tag {
static bool is_final_scan() { return false; }
};
struct final_scan_tag {
static bool is_final_scan() { return true; }
};
template<typename Range, typename Body>
void parallel_scan(const Range& range, Body& body)
{
body(range, pre_scan_tag());
body(range, final_scan_tag());
}
template<typename Range, typename Body>
void parallel_scan(const Range& range, Body& body, const auto_partitioner&)
{ parallel_scan(range, body); }
template<typename Range, typename Body>
void parallel_scan(const Range& range, Body& body, const simple_partitioner&)
{ parallel_scan(range, body); }
// parallel_do Template
template<typename Item>
struct parallel_do_feeder {
void add(const Item& item) { queue_.push_back(item); }
/*internal:*/
parallel_do_feeder(std::deque<Item>& queue) : queue_(queue) {}
std::deque<Item>& queue_;
};
template<typename InputIterator, typename Body>
void parallel_do(InputIterator first, InputIterator last, Body body)
{
typedef typename std::iterator_traits<InputIterator>::value_type Item;
std::deque<Item> queue;
parallel_do_feeder<Item> feeder(queue);
for (; first != last; ++first)
body(*first, feeder);
for (; !queue.empty(); queue.pop_front())
body(queue.front(), feeder);
}
// parallel_for_each Template
template<typename InputIterator, typename Func>
void parallel_for_each(InputIterator first, InputIterator last, const Func& func)
{
for (; first != last; ++first)
func(*first);
}
// parallel_sort Template
template<typename RandomAccessIterator>
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
{
std::sort(begin, end);
}
template<typename RandomAccessIterator, typename Compare>
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end, const Compare& comp)
{
std::sort(begin, end, comp);
}
// parallel_invoke Template
template<typename Func0, typename Func1>
void parallel_invoke(const Func0& f0, const Func1& f1)
{
f0(); f1();
}
template<typename Func0, typename Func1, typename Func2>
void parallel_invoke(const Func0& f0, const Func1& f1, const Func2& f2)
{
f0(); f1(); f2();
}
template<typename Func0, typename Func1, typename Func2, typename Func3>
void parallel_invoke(const Func0& f0, const Func1& f1, const Func2& f2, const Func3& f3)
{
f0(); f1(); f2(); f3();
}
//...Do you need more overloads? Do it YOURSELF.
// atomic Template Class
enum memory_semantics { acquire, release };
template <class T>
struct atomic {
typedef T value_type;
// NOTE: Actually, all operations are NOT atomic.
template<memory_semantics M>
value_type compare_and_swap(value_type new_value, value_type comparand)
{ value_type s = v_; v_ = (v_ == comparand) ? new_value : v_; return s; }
value_type compare_and_swap(value_type new_value, value_type comparand)
{ value_type s = v_; v_ = (v_ == comparand) ? new_value : v_; return s; }
template<memory_semantics M>
value_type fetch_and_store(value_type new_value)
{ value_type s = v_; v_ = new_value; return s; }
value_type fetch_and_store(value_type new_value)
{ value_type s = v_; v_ = new_value; return s; }
operator value_type() const { return v_; }
value_type operator=(value_type new_value) { return v_ = new_value; }
atomic<T>& operator=(const atomic<T>& value) { v_ = value.v_; return *this; }
template<memory_semantics M>
value_type fetch_and_add(value_type addend)
{ value_type s = v_; v_ += addend; return s; }
value_type fetch_and_add(value_type addend)
{ value_type s = v_; v_ += addend; return s; }
template<memory_semantics M>
value_type fetch_and_increment() { return v_++; }
value_type fetch_and_increment() { return v_++; }
template<memory_semantics M>
value_type fetch_and_decrement() { return v_--; }
value_type fetch_and_decrement() { return v_--; }
value_type operator+=(value_type x) { return v_ -= x; }
value_type operator-=(value_type x) { return v_ -= x; }
value_type operator++() { return ++v_; }
value_type operator++(int) { return v_++; }
value_type operator--() { return ++v_; }
value_type operator--(int) { return v_--; }
private:
value_type v_;
};
// tick_count Class
class tick_count {
public:
class interval_t;
static tick_count now() { return tick_count(); }
friend tick_count::interval_t operator-(const tick_count&, const tick_count&);
private:
tick_count() : tm_(std::time(0)) {}
tick_count(std::time_t t) : tm_(t) {}
std::time_t tm_;
};
// tick_count::interval_t Class
class tick_count::interval_t {
public:
interval_t() : d_(0) {}
explicit interval_t(double sec) : d_(sec) {}
double seconds() const { return d_; }
interval_t operator+=(const interval_t& i) { return interval_t(d_ + i.d_); }
interval_t operator-=(const interval_t& i) { return interval_t(d_ - i.d_); }
friend tick_count::interval_t operator+(const tick_count::interval_t& i, const tick_count::interval_t& j)
{ return tick_count::interval_t(i.d_ + j.d_); }
friend tick_count::interval_t operator-(const tick_count::interval_t& i, const tick_count::interval_t& j)
{ return tick_count::interval_t(i.d_ - j.d_); }
private:
double d_;
};
inline tick_count::interval_t operator-(const tick_count& t1, const tick_count& t0)
{
return tick_count::interval_t(static_cast<double>(t1.tm_ - t0.tm_));
}
// task_scheduler_init Class
class task_scheduler_init
{
public:
typedef std::size_t stack_size_type;
static const int automatic = 0;
static const int deferred = -1;
task_scheduler_init(int max_threads = automatic, stack_size_type /*thread_stack_size*/ = 0)
: active_(max_threads != deferred) {}
void initialize(int max_threads = automatic) { active_ = (max_threads != deferred); }
void terminate() { active_ = false; }
bool is_active() const { return active_; }
static int default_num_threads() { return 1; }
private:
bool active_;
};
} // namespace tbb
#endif // TBB_STUB_H_INCLUDED_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment