From 3395d002bd286279432f15b8d0e665c7872c85ae Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 14 Jan 2017 03:07:48 +0100 Subject: [PATCH] Library: helper to produce threadsafe member-IDs for a family of objects This is a little bit of functionality needed again and again; first I thought to use the TypedCounter, but this would be overkill, since we do not actually need different instances, and we do not need to select by type when incrementing the counter. In fact, we do not even need anything beyond just allocating a number. So I made a new class, which can be used RAII style --- src/lib/typed-counter.hpp | 40 ++++++++- tests/12metaprogramming.tests | 5 ++ tests/basics/typed-counter-test.cpp | 16 ++-- tests/basics/typed-family-member-id-test.cpp | 90 ++++++++++++++++++++ 4 files changed, 142 insertions(+), 9 deletions(-) create mode 100644 tests/basics/typed-family-member-id-test.cpp diff --git a/src/lib/typed-counter.hpp b/src/lib/typed-counter.hpp index 88e14fc07..fdd9100a7 100644 --- a/src/lib/typed-counter.hpp +++ b/src/lib/typed-counter.hpp @@ -126,7 +126,7 @@ namespace lib { /** - * Helper providing a set of counters, each tied to a specific type. + * Utility providing a set of counters, each tied to a specific type. */ class TypedCounter : public Sync<> @@ -186,5 +186,43 @@ namespace lib { + /** + * Utility to produce member IDs + * for objects belonging to a "Family", + * as defined by a distinguishing type. + */ + template + class FamilyMember + { + const size_t id_; + + /** member counter shared per template instance */ + static size_t memberCounter; + + /** threadsafe allocation of member ID */ + static size_t + allocateNextMember() + { + ClassLock synchronised; + return memberCounter++; + } + + public: + FamilyMember() + : id_{allocateNextMember()} + { } + + operator size_t() const + { + return id_; + } + }; + + /** allocate storage for the counter per type family */ + template + size_t FamilyMember::memberCounter{0}; + + + } // namespace lib #endif diff --git a/tests/12metaprogramming.tests b/tests/12metaprogramming.tests index e7d6f59f7..3ec9cfd3c 100644 --- a/tests/12metaprogramming.tests +++ b/tests/12metaprogramming.tests @@ -602,6 +602,11 @@ return: 0 END +TEST "Type-based family member IDs" TypedFamilyMemberID_test < + ** ** This test builds several "families", each sharing a TypedCounter. Each of these ** families runs a set of member threads, which concurrently access the TypedCounter of ** this family. After waiting for all threads to finish, we compare the checksum built @@ -85,7 +85,7 @@ namespace test{ */ - /** + /** * Interface to a family of dummy types */ class DummyType @@ -180,7 +180,7 @@ namespace test{ - /** + /** * Collection of target functions, * to be invoked during the test run */ @@ -224,14 +224,14 @@ namespace test{ iterator end() { return targets_.end(); } }; - DummyTarget targetCollection; + DummyTarget targetCollection; /** * Each single check runs in a separate thread * and performs a random sequence of increments - * and decrements on random targets. + * and decrements on random targets. */ class SingleCheck : ThreadJoinable @@ -259,7 +259,7 @@ namespace test{ }; - /** + /** * Family of individual checks, sharing * a common TypedCounter instance. */ @@ -311,7 +311,7 @@ namespace test{ { void - run (Arg) + run (Arg) { simpleUsageTest(); tortureTest(); @@ -366,7 +366,7 @@ namespace test{ void - tortureTest () + tortureTest () { std::srand (::time (NULL)); sum_TypedCounter_ = 0; diff --git a/tests/basics/typed-family-member-id-test.cpp b/tests/basics/typed-family-member-id-test.cpp new file mode 100644 index 000000000..39210e3d5 --- /dev/null +++ b/tests/basics/typed-family-member-id-test.cpp @@ -0,0 +1,90 @@ +/* + TypedFamilyMemberID(Test) - verify type based member ID + + Copyright (C) Lumiera.org + 2017, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +/** @file typed-family-member-id-test.cpp + ** Unit test to verify generation of a Member ID within a type based family of objects. + */ + + + +#include "lib/test/run.hpp" +#include "lib/typed-counter.hpp" + + +namespace lib { +namespace test{ + + + + + /*******************************************************************//** + * @test simplistic unit test to demonstrate generating _member IDs + * within a family of objects delineated by type. + * @warning this test does not cover the thread safety, + * because FamilyMember relies on lib::ClassLock, + * which is assumed to be covered separately + * + * @see SessionCommandFunction_test::perform_massivelyParallel + * @see typed-counter.hpp + */ + class TypedFamilyMemberID_test : public Test + { + + void + run (Arg) + { + struct X { }; + struct Y { }; + struct Z { }; + + CHECK (0 == FamilyMember{}); + CHECK (1 == FamilyMember{}); + CHECK (2 == FamilyMember{}); + + CHECK (0 == FamilyMember{}); + CHECK (1 == FamilyMember{}); + + CHECK (0 == FamilyMember{}); + + CHECK (2 == FamilyMember{}); + CHECK (3 == FamilyMember{}); + + CHECK (1 == FamilyMember{}); + CHECK (2 == FamilyMember{}); + CHECK (3 == FamilyMember{}); + CHECK (4 == FamilyMember{}); + + CHECK (4 == FamilyMember{}); + CHECK (5 == FamilyMember{}); + CHECK (3 == FamilyMember{}); + CHECK (5 == FamilyMember{}); + CHECK (4 == FamilyMember{}); + } + }; + + + /** Register this test class... */ + LAUNCHER (TypedFamilyMemberID_test, "unit common"); + + +}} // namespace lib::test