Commit 812a9a26 by lucapegolotti

Fix style of linearizability_tester.h

parent cc1e3c42
......@@ -81,22 +81,22 @@ using std::make_unique;
/// Linearizability tester
namespace lt
{
/************* Core data structures && algorithms *************/
/************* Core data structures && algorithms *************/
template<class S>
class Entry;
template<class S>
class Entry;
/// Doubly-linked list of log entries
/// Doubly-linked list of log entries
/// S - sequential data type
template<class S>
using EntryPtr = Entry<S>*;
/// S - sequential data type
template<class S>
using EntryPtr = Entry<S>*;
/// Bounded stack of call entries that have been linearized
/// S - sequential data type
template<class S>
class Stack
{
/// Bounded stack of call entries that have been linearized
/// S - sequential data type
template<class S>
class Stack
{
private:
typedef std::tuple<EntryPtr<S>, S> Pair;
typedef std::vector<Pair> Pairs;
......@@ -164,27 +164,27 @@ namespace lt
assert(pos < m_top);
return std::get<0>(m_vector[pos]);
}
};
};
enum class Option : unsigned char
{
enum class Option : unsigned char
{
NEVER_CACHE,
LRU_CACHE,
ALWAYS_CACHE,
};
};
template<class S> class Entry;
template<class S> class Log;
template<class S> class ConcurrentLog;
template<class S> class Slicer;
template<class S, Option> class LinearizabilityTester;
template<class S> class Entry;
template<class S> class Log;
template<class S> class ConcurrentLog;
template<class S> class Slicer;
template<class S, Option> class LinearizabilityTester;
/// A kind of "functor" in C++ terminology
/// A kind of "functor" in C++ terminology
/// S - sequential data type
template<class S>
class Op
{
/// S - sequential data type
template<class S>
class Op
{
private:
friend class Entry<S>;
......@@ -250,11 +250,11 @@ namespace lt
return op.print(os);
}
#endif
};
};
/// Fixed-size set of bits with persistence features
class Bitset
{
/// Fixed-size set of bits with persistence features
class Bitset
{
public:
typedef std::size_t Pos;
......@@ -385,36 +385,36 @@ namespace lt
return m_number_of_set_bits != other.m_number_of_set_bits ||
m_blocks != other.m_blocks;
}
};
};
/// Constant-time, O(1), hash function
struct BitsetHash
{
/// Constant-time, O(1), hash function
struct BitsetHash
{
std::size_t operator()(const Bitset& bitset) const noexcept
{
return bitset.m_hash;
}
};
};
/// States of abstract data types
namespace state
{
/// States of abstract data types
namespace state
{
template<class T>
struct Hash
{
std::size_t operator()(const T&) const noexcept;
};
}
}
template<class S>
using OpPtr = std::unique_ptr<Op<S>>;
template<class S>
using OpPtr = std::unique_ptr<Op<S>>;
/// Call/ret log entry
/// Call/ret log entry
/// S - sequential data type
template<class S>
class Entry
{
/// S - sequential data type
template<class S>
class Entry
{
private:
friend class Log<S>;
friend class Slicer<S>;
......@@ -630,13 +630,13 @@ namespace lt
{
return m_is_call;
}
};
};
#ifdef _LT_DEBUG_
/// S - sequential data type
template<class S>
std::ostream& operator<<(std::ostream& os, EntryPtr<S> entry_ptr)
{
/// S - sequential data type
template<class S>
std::ostream& operator<<(std::ostream& os, EntryPtr<S> entry_ptr)
{
if (entry_ptr == nullptr)
return os << "entry id: none, thread id: none [nullptr]";
......@@ -646,12 +646,12 @@ namespace lt
", thread id: " << entry.thread_id() <<
", " << (entry.is_call() ? "call: " : "return: ") <<
entry.op();
}
}
#endif
template<class S>
void Stack<S>::push(EntryPtr<S> ptr, S&& s)
{
template<class S>
void Stack<S>::push(EntryPtr<S> ptr, S&& s)
{
assert(!is_full());
assert(ptr != nullptr);
assert(ptr->is_call());
......@@ -659,14 +659,14 @@ namespace lt
// no overflow
m_vector[m_top++] = std::make_pair(ptr, std::move(s));
assert(0U != m_top);
}
}
/// Input to linearizabilty testers
/// Input to linearizabilty testers
/// S - sequential data type
template<class S>
class LogInfo
{
/// S - sequential data type
template<class S>
class LogInfo
{
private:
friend class Slicer<S>;
......@@ -706,13 +706,13 @@ namespace lt
{
return m_log_head_ptr == nullptr && m_number_of_entries == 0U;
}
};
};
#ifdef _LT_DEBUG_
/// S - sequential data type
template<class S>
std::ostream& operator<<(std::ostream& os, const LogInfo<S>& log_info)
{
/// S - sequential data type
template<class S>
std::ostream& operator<<(std::ostream& os, const LogInfo<S>& log_info)
{
EntryPtr<S> entry_ptr{ log_info.log_head_ptr() };
os << "log info, number of entries: " << log_info.number_of_entries() << std::endl;
......@@ -720,17 +720,17 @@ namespace lt
os << entry_ptr << std::endl;
return os;
}
}
#endif
/// Bounded history log
/// Bounded history log
/// If you need thread-safety, use ConcurrentLog<S> instead.
///
/// S - sequential data type
template<class S>
class Log
{
/// If you need thread-safety, use ConcurrentLog<S> instead.
///
/// S - sequential data type
template<class S>
class Log
{
private:
// fixed-size vector
typedef std::vector<Entry<S>> Entries;
......@@ -848,14 +848,14 @@ namespace lt
{
return{ log_head_ptr(), number_of_entries() };
}
};
};
/// Output of linearizability tester
/// Output of linearizability tester
/// S - sequential data type
template<class S>
class Result
{
/// S - sequential data type
template<class S>
class Result
{
private:
friend class LinearizabilityTester<S, Option::NEVER_CACHE>;
friend class LinearizabilityTester<S, Option::LRU_CACHE>;
......@@ -953,12 +953,12 @@ namespace lt
}
}
#endif
};
};
#ifdef _LT_TIMEOUT_
template <typename Clock = std::chrono::steady_clock>
struct Timeout
{
template <typename Clock = std::chrono::steady_clock>
struct Timeout
{
const typename Clock::time_point start_time;
const typename Clock::duration max_duration;
......@@ -974,13 +974,13 @@ namespace lt
{
return max_duration < (Clock::now() - start_time);
}
};
};
#endif
/// Least-recently used cache eviction
template<class Key, class Hash = std::hash<Key>>
class LruCache
{
/// Least-recently used cache eviction
template<class Key, class Hash = std::hash<Key>>
class LruCache
{
private:
typedef std::list<Key> List;
typedef typename List::iterator ListIterator;
......@@ -1023,10 +1023,10 @@ namespace lt
return pair.second;
}
};
};
namespace cache
{
namespace cache
{
// regardless of caching, we need to keep track of the current state of type S
template<class S>
using State = std::pair<Bitset, S>;
......@@ -1097,12 +1097,12 @@ namespace lt
return std::get<1>(cache.emplace(bs, s));
}
};
}
}
/// S - sequential data type
template<class S, Option option = Option::ALWAYS_CACHE>
class LinearizabilityTester
{
/// S - sequential data type
template<class S, Option option = Option::ALWAYS_CACHE>
class LinearizabilityTester
{
private:
typedef cache::Switch<S, option> Cache;
......@@ -1329,12 +1329,12 @@ namespace lt
internal_check(result, disregard_cutoff_entry_id);
#endif
}
};
};
template<class S, class Duration>
void compositional_check(Log<S>& log, Result<S> &result,
template<class S, class Duration>
void compositional_check(Log<S>& log, Result<S> &result,
unsigned number_of_partitions, Duration max_duration)
{
{
Slicer<S> slicer{ log.info(), number_of_partitions };
for (unsigned partition = 0; partition < slicer.number_of_partitions; ++partition)
{
......@@ -1343,11 +1343,11 @@ namespace lt
if (!(result.is_timeout() || result.is_linearizable()))
break;
}
}
}
/// RAII class to ensure a thread becomes unjoinable on all paths
class Thread
{
/// RAII class to ensure a thread becomes unjoinable on all paths
class Thread
{
private:
std::thread m_thread;
......@@ -1387,26 +1387,26 @@ namespace lt
m_thread = std::move(thread.m_thread);
return *this;
}
};
/// Partition history into sub-histories
/// A slicer partitions the history into independent sub-histories.
/// Our partitioning scheme hinges on Theorem 3.6.1 in "The Art of
/// Multiprocessor Programming" (Revised Ed.) by Herlihy && Shavit.
///
/// Typically only associative concurrent abstract data types (ADTs)
/// such as sets && hash tables are suitable for this partitioning
/// scheme. && !all operations on such ADTs are always supported.
/// For example, the partitioning scheme is incompatible with 0-arg
/// operations such as "empty?" on sets. But it is very effective if
/// we want to only check linearizability of say "insert", "remove"
/// && "contains".
///
/// S - sequential data type
template<class S>
class Slicer
{
};
/// Partition history into sub-histories
/// A slicer partitions the history into independent sub-histories.
/// Our partitioning scheme hinges on Theorem 3.6.1 in "The Art of
/// Multiprocessor Programming" (Revised Ed.) by Herlihy && Shavit.
///
/// Typically only associative concurrent abstract data types (ADTs)
/// such as sets && hash tables are suitable for this partitioning
/// scheme. && !all operations on such ADTs are always supported.
/// For example, the partitioning scheme is incompatible with 0-arg
/// operations such as "empty?" on sets. But it is very effective if
/// we want to only check linearizability of say "insert", "remove"
/// && "contains".
///
/// S - sequential data type
template<class S>
class Slicer
{
private:
typedef std::vector<LogInfo<S>> Sublogs;
......@@ -1493,12 +1493,12 @@ namespace lt
return s_empty_log;
}
};
};
/// S - sequential data type
template<class S>
class ConcurrentLog
{
/// S - sequential data type
template<class S>
class ConcurrentLog
{
private:
typedef std::vector<Entry<S>> Entries;
typedef typename Entries::size_type Size;
......@@ -1601,12 +1601,12 @@ namespace lt
{
return{ log_head_ptr(), number_of_entries() };
}
};
};
/************* Models for sequential abstract data types *************/
/************* Models for sequential abstract data types *************/
class FlexibleBitset
{
class FlexibleBitset
{
public:
typedef Bitset::Pos Pos;
......@@ -1669,15 +1669,15 @@ namespace lt
{
return m_bitset.m_hash;
}
};
};
namespace state
{
namespace internal
{
template<class S, class Ret>
struct RetOp : public Op<S>
{
namespace state
{
namespace internal
{
template<class S, class Ret>
struct RetOp : public Op<S>
{
typedef RetOp<S, Ret> Base;
const Ret ret;
......@@ -1694,11 +1694,11 @@ namespace lt
return os << "ret: " << ret;
}
#endif
};
};
template<class S, const char* const op_name>
struct ZeroArgOp : public Op<S>
{
template<class S, const char* const op_name>
struct ZeroArgOp : public Op<S>
{
typedef ZeroArgOp<S, op_name> Base;
ZeroArgOp()
......@@ -1710,11 +1710,11 @@ namespace lt
return os << op_name << "()";
}
#endif
};
};
template<class S, class Value, const char* const op_name>
struct ArgOp : public Op<S>
{
template<class S, class Value, const char* const op_name>
struct ArgOp : public Op<S>
{
typedef ArgOp<S, Value, op_name> Base;
const Value value;
......@@ -1731,12 +1731,12 @@ namespace lt
return os << op_name << "(" << std::to_string(value) << ")";
}
#endif
};
}
};
}
/// Byte read-write register with CAS
class Atomic
{
/// Byte read-write register with CAS
class Atomic
{
public:
typedef signed char Value;
......@@ -1978,20 +1978,20 @@ namespace lt
{
return m_value != atomic.m_value;
}
};
};
constexpr char Atomic::s_read_op_name[];
constexpr char Atomic::s_write_op_name[];
constexpr char Atomic::s_read_op_name[];
constexpr char Atomic::s_write_op_name[];
template<>
struct Hash<Atomic>
{
template<>
struct Hash<Atomic>
{
std::size_t operator()(const Atomic& atomic) const noexcept
{
return atomic.get() * 193U;
}
};
}
};
}
}
#endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment