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:
parent
0b0575050d
commit
3395d002bd
4 changed files with 142 additions and 9 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
90
tests/basics/typed-family-member-id-test.cpp
Normal file
90
tests/basics/typed-family-member-id-test.cpp
Normal 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
|
||||
Loading…
Reference in a new issue