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
This commit is contained in:
Fischlurch 2017-01-14 03:07:48 +01:00
parent 0b0575050d
commit 3395d002bd
4 changed files with 142 additions and 9 deletions

View file

@ -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<typename TY>
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<FamilyMember> synchronised;
return memberCounter++;
}
public:
FamilyMember()
: id_{allocateNextMember()}
{ }
operator size_t() const
{
return id_;
}
};
/** allocate storage for the counter per type family */
template<typename TY>
size_t FamilyMember<TY>::memberCounter{0};
} // namespace lib
#endif

View file

@ -602,6 +602,11 @@ return: 0
END
TEST "Type-based family member IDs" TypedFamilyMemberID_test <<END
return: 0
END
TEST "for-each operations" UtilForeach_test 10 <<END
out: ---:check_foreach_plain
out: :10:9:8:7:6:5:4:3:2:1

View file

@ -28,7 +28,7 @@
** this facility is to provide a context, in which type-IDs can be allocated. In the
** case of the TypedCounter, these type-IDs are used to index into a vector of counters,
** this way allowing to access a counter for a given type.
** <P>
**
** 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;

View file

@ -0,0 +1,90 @@
/*
TypedFamilyMemberID(Test) - verify type based member ID
Copyright (C) Lumiera.org
2017, Hermann Vosseler <Ichthyostega@web.de>
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<X>{});
CHECK (1 == FamilyMember<X>{});
CHECK (2 == FamilyMember<X>{});
CHECK (0 == FamilyMember<Y>{});
CHECK (1 == FamilyMember<Y>{});
CHECK (0 == FamilyMember<Z>{});
CHECK (2 == FamilyMember<Y>{});
CHECK (3 == FamilyMember<Y>{});
CHECK (1 == FamilyMember<Z>{});
CHECK (2 == FamilyMember<Z>{});
CHECK (3 == FamilyMember<Z>{});
CHECK (4 == FamilyMember<Z>{});
CHECK (4 == FamilyMember<Y>{});
CHECK (5 == FamilyMember<Z>{});
CHECK (3 == FamilyMember<X>{});
CHECK (5 == FamilyMember<Y>{});
CHECK (4 == FamilyMember<X>{});
}
};
/** Register this test class... */
LAUNCHER (TypedFamilyMemberID_test, "unit common");
}} // namespace lib::test