EntryID finished and passes unit test
This commit is contained in:
parent
c691213003
commit
c9bf26d8c4
4 changed files with 159 additions and 62 deletions
53
src/lib/meta/trait-special.hpp
Normal file
53
src/lib/meta/trait-special.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
TRAIT-SPECIAL.hpp - supplement, not so commonly used definitions and specialisations
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2010, 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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_META_TRAIT_SPECIAL_H
|
||||
#define LIB_META_TRAIT_SPECIAL_H
|
||||
|
||||
|
||||
#include "lib/meta/trait.hpp"
|
||||
|
||||
#include <tr1/unordered_map>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
|
||||
/** the tr1 hashtable(s) are notoriously difficult to handle
|
||||
* when it comes to detecting capabilities by metaprogramming,
|
||||
* because the're built up from a generic baseclass and especially
|
||||
* inherit their iterator-types as template specialisations.
|
||||
*
|
||||
* Thus we provide fixed diagnostics to bypass the traits check.
|
||||
*/
|
||||
template<typename KEY, typename VAL, typename HASH>
|
||||
struct can_STL_ForEach<std::tr1::unordered_map<KEY,VAL,HASH> >
|
||||
{
|
||||
enum { value = true };
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
|
|
@ -27,12 +27,12 @@
|
|||
** overhead of creating individual assets for each entry. The datafields in the symbolic part
|
||||
** of the ID are similar to the asset identity tuple; the idea is to promote individual entries
|
||||
** to full fledged assets on demand. Alongside with the symbolic identity, which can be reduced
|
||||
** to just a Symbol and a type identifier, we store the derived hash value as LUID.
|
||||
** to just a Symbol and (compile time) type information, we store the derived hash value as LUID.
|
||||
**
|
||||
** @note as of 3/2010 this is an experimental setup and exists somewhat in parallel
|
||||
** to the assets. We're still in the process of finding out what's really required
|
||||
** to keep track of all the various kinds of objects.
|
||||
**
|
||||
**
|
||||
** @see asset::Asset::Ident
|
||||
** @see entry-id-test.cpp
|
||||
**
|
||||
|
|
@ -54,19 +54,19 @@
|
|||
|
||||
|
||||
namespace asset {
|
||||
|
||||
|
||||
using std::string;
|
||||
using std::ostream;
|
||||
|
||||
using lumiera::error::LUMIERA_ERROR_WRONG_TYPE;
|
||||
|
||||
|
||||
|
||||
namespace idi {
|
||||
|
||||
using lib::hash::LuidH;
|
||||
|
||||
typedef size_t HashVal;
|
||||
|
||||
|
||||
/** build up a hash value, packaged as LUID.
|
||||
* @param sym symbolic ID-string to be hashed
|
||||
* @param seed (optional) hash value to combine with the sym.
|
||||
|
|
@ -110,20 +110,26 @@ namespace asset {
|
|||
string symbol_;
|
||||
LuidH hash_;
|
||||
|
||||
public:
|
||||
explicit
|
||||
BareEntryID (string const& symbolID, idi::HashVal seed =0) /////////////TODO couldn't this be protected?
|
||||
protected:
|
||||
/**
|
||||
* Not to be created stand-alone.
|
||||
* derived classes feed down the specific type information
|
||||
* encoded into a hash seed. Thus even the same symbolicID
|
||||
* generates differing hash-IDs for different type parameters
|
||||
*/
|
||||
BareEntryID (string const& symbolID, idi::HashVal seed =0)
|
||||
: symbol_(util::sanitise(symbolID))
|
||||
, hash_(idi::buildHash (symbol_, seed))
|
||||
{ }
|
||||
|
||||
/* default copy- and assignable */
|
||||
public:
|
||||
/* default copyable and assignable */
|
||||
|
||||
|
||||
bool
|
||||
isValid() const
|
||||
{
|
||||
return bool(hash_);
|
||||
return bool(hash_);
|
||||
}
|
||||
|
||||
string const&
|
||||
|
|
@ -135,9 +141,10 @@ namespace asset {
|
|||
LuidH const&
|
||||
getHash() const
|
||||
{
|
||||
return hash_;
|
||||
return hash_;
|
||||
}
|
||||
|
||||
|
||||
/** using BareEntryID derived objects as keys within tr1::unordered_map */
|
||||
struct UseEmbeddedHash
|
||||
: public std::unary_function<BareEntryID, size_t>
|
||||
|
|
@ -196,16 +203,13 @@ namespace asset {
|
|||
getIdent() const
|
||||
{
|
||||
Category cat (STRUCT, idi::StructTraits<TY>::catFolder);
|
||||
return Asset::Ident (this->getSym(), cat);
|
||||
return Asset::Ident (this->getSym(), cat);
|
||||
}
|
||||
|
||||
static idi::HashVal
|
||||
getTypeHash()
|
||||
{
|
||||
Category cat (STRUCT, idi::StructTraits<TY>::catFolder);
|
||||
asset::Category const& catz(cat);
|
||||
size_t haha = hash_value (catz);
|
||||
return haha;
|
||||
return hash_value (Category (STRUCT, idi::StructTraits<TY>::catFolder));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -217,7 +221,7 @@ namespace asset {
|
|||
static bool
|
||||
canRecast (BareEntryID const& bID)
|
||||
{
|
||||
return bID.getHash() == buildHash (bID.getSym(), getTypeHash());
|
||||
return bID.getHash() == idi::buildHash (bID.getSym(), getTypeHash());
|
||||
}
|
||||
|
||||
static EntryID
|
||||
|
|
@ -235,9 +239,9 @@ namespace asset {
|
|||
{
|
||||
return "ID<"+idi::StructTraits<TY>::idSymbol+">-"+EntryID::getSym();
|
||||
}
|
||||
|
||||
|
||||
friend ostream& operator<< (ostream& os, EntryID const& id) { return os << string(id); }
|
||||
friend bool operator< (EntryID const& i1, EntryID const& i2) { return i1.getSym() < i2.getSym(); }
|
||||
friend bool operator< (EntryID const& i1, EntryID const& i2) { return i1.getSym() < i2.getSym(); }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -246,9 +250,9 @@ namespace asset {
|
|||
{
|
||||
return i1.getHash() == i2.getHash();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** try to upcast this BareEntryID to a fully typed EntryID.
|
||||
* Effectively, this is the attempt to reverse a type erasure;
|
||||
|
|
@ -266,8 +270,8 @@ namespace asset {
|
|||
{
|
||||
return EntryID<TAR>::recast(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace asset
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,7 +33,15 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
PLANNED "plain entry-ID" EntryID_test <<END
|
||||
TEST "plain entry-ID" EntryID_test <<END
|
||||
out: ID<..asset.+Dummy.>-..asset.+Dummy.\.001
|
||||
out: ID<..asset.+Dummy.>-strange
|
||||
out: ID<..asset.+Dummy.>-..asset.+Dummy.\.002
|
||||
out: ID<track>-track\.001
|
||||
out: ID<track>-track\.002
|
||||
out: ID<track>-special
|
||||
out: sizeof\( ..asset.+EntryID.+mobject.+session.+Track.+ \) =
|
||||
out: sizeof\( ..asset.+BareEntryID. \) =
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "proc/asset/entry-id.hpp"
|
||||
#include "proc/mobject/session/clip.hpp"
|
||||
#include "proc/mobject/session/track.hpp"
|
||||
#include "lib/meta/trait-special.hpp"
|
||||
#include "lib/util-foreach.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
|
||||
|
|
@ -37,7 +38,7 @@
|
|||
using lib::test::showSizeof;
|
||||
using lib::test::randStr;
|
||||
using util::isSameObject;
|
||||
using util::for_each;
|
||||
using util::and_all;
|
||||
using lib::Literal;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
|
|
@ -58,6 +59,9 @@ namespace test {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* @test proof-of-concept test for a combined symbolic and hash based ID.
|
||||
* - create some symbolic IDs
|
||||
|
|
@ -65,7 +69,7 @@ namespace test {
|
|||
* - check comparisons
|
||||
* - check hashing
|
||||
* - use the embedded hash ID (LUID) as hashtable key
|
||||
*
|
||||
*
|
||||
* @see lib::HashIndexed::Id
|
||||
* @see mobject::Placement real world usage example
|
||||
*/
|
||||
|
|
@ -115,11 +119,6 @@ namespace test {
|
|||
cout << tID2 << endl;
|
||||
cout << tID3 << endl;
|
||||
|
||||
cout << showSizeof<TrackID>() << endl;
|
||||
cout << showSizeof<BareEntryID>() << endl;
|
||||
CHECK (sizeof(TrackID) == sizeof(BareEntryID));
|
||||
CHECK (sizeof(TrackID) == sizeof(lumiera_uid) + sizeof(void*));
|
||||
|
||||
DummyID x (dID2); // copy ctor
|
||||
CHECK (x == dID2);
|
||||
CHECK (!isSameObject (x, dID2));
|
||||
|
|
@ -129,22 +128,22 @@ namespace test {
|
|||
void
|
||||
checkBasicProperties ()
|
||||
{
|
||||
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #582
|
||||
TrackID tID(" test ⚡ ☠ ☭ ⚡ track ");
|
||||
CHECK (tID.getIdent() == Asset::Ident("test_track", Category(STRUCT,"tracks"), "lumi", 0));
|
||||
|
||||
CHECK (tID.getHash() == TrackID("☢ test ☢ track ☢").getHash());
|
||||
|
||||
CHECK (isSameObject (tID.getSym(), tID.getIdent().name));
|
||||
CHECK ("tracks" == TrackID().getIdent().category.path);
|
||||
CHECK ("clips" == ClipID().getIdent().category.path);
|
||||
CHECK (tID.getSym() == tID.getIdent().name);
|
||||
CHECK (TrackID().getIdent().category == Category (STRUCT,"tracks"));
|
||||
CHECK (ClipID().getIdent().category == Category (STRUCT,"clips"));
|
||||
|
||||
CHECK (ClipID().getSym() < ClipID().getSym());
|
||||
ClipID cID2,cID3;
|
||||
CHECK (cID2.getSym() < cID3.getSym());
|
||||
CHECK (ClipID("x").getSym() == ClipID(" x ").getSym());
|
||||
|
||||
for (uint i=0; i<1000; ++i)
|
||||
for (uint i=0; i<10000; ++i)
|
||||
{
|
||||
TrackID arbitrary(randStr(20));
|
||||
TrackID arbitrary(randStr(30));
|
||||
CHECK (0 < arbitrary.getHash());
|
||||
CHECK (tID.getHash() != arbitrary.getHash());
|
||||
tID = arbitrary;
|
||||
|
|
@ -153,15 +152,16 @@ namespace test {
|
|||
CHECK (tID.getIdent()== arbitrary.getIdent());
|
||||
}
|
||||
|
||||
CHECK (sizeof (tID) == sizeof(hash::LuidH) + sizeof(Literal));
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #582
|
||||
cout << showSizeof<TrackID>() << endl;
|
||||
cout << showSizeof<BareEntryID>() << endl;
|
||||
CHECK (sizeof(TrackID) == sizeof(BareEntryID));
|
||||
CHECK (sizeof(TrackID) == sizeof(lumiera_uid) + sizeof(void*));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
checkComparisions ()
|
||||
{
|
||||
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #582
|
||||
TrackID tID1("a1");
|
||||
TrackID tID2("a1");
|
||||
TrackID tID3("a2");
|
||||
|
|
@ -178,15 +178,23 @@ namespace test {
|
|||
CHECK (tID4 >= tID3);
|
||||
CHECK (tID4 > tID3);
|
||||
|
||||
CHECK (TrackID() < TrackID());
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #582
|
||||
TrackID trackID1, trackID2;
|
||||
CHECK (trackID1 < trackID2); // auto generated IDs are prefix + running counter
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test handling of EntryIDs through their common base class,
|
||||
* which means erasing the specific type information.
|
||||
* While this type information can't be recovered
|
||||
* after erasure, we can try to upcast back
|
||||
* to a known type; this upcast is safe,
|
||||
* because the embedded hash-ID
|
||||
* is based on the type info.
|
||||
*/
|
||||
void
|
||||
checkErasure ()
|
||||
{
|
||||
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #582
|
||||
TrackID tID("suspicious");
|
||||
ClipID cID("suspicious");
|
||||
|
||||
|
|
@ -201,35 +209,52 @@ namespace test {
|
|||
CHECK (bIDt.getSym() == bIDc.getSym());
|
||||
CHECK ("suspicious" == bIDc.getSym());
|
||||
|
||||
TrackID tIDnew = bIDt.recast<TrackID>();
|
||||
ClipID cIDnew = bIDc.recast<ClipID>();
|
||||
using mobject::session::Track;
|
||||
using mobject::session::Clip;
|
||||
TrackID tIDnew = bIDt.recast<Track>();
|
||||
ClipID cIDnew = bIDc.recast<Clip>();
|
||||
CHECK (tIDnew == tID);
|
||||
CHECK (cIDnew == cID);
|
||||
|
||||
VERIFY_ERROR (WRONG_TYPE, bIDt.recast<ClipID>());
|
||||
VERIFY_ERROR (WRONG_TYPE, bIDc.recast<TrackID>());
|
||||
VERIFY_ERROR (WRONG_TYPE, bIDt.recast<Clip>());
|
||||
VERIFY_ERROR (WRONG_TYPE, bIDc.recast<Track>());
|
||||
VERIFY_ERROR (WRONG_TYPE, bIDc.recast<Dummy>());
|
||||
VERIFY_ERROR (WRONG_TYPE, bIDt.recast<Dummy>());
|
||||
|
||||
CHECK (tID == bIDt.recast<mobject::session::Track>()); // alternatively can specify type directly
|
||||
CHECK (tID == TrackID::recast (bIDt)); // equivalent static API on typed subclass
|
||||
CHECK (tID == TrackID::recast (bIDt)); // equivalent static API on typed subclass
|
||||
VERIFY_ERROR (WRONG_TYPE, TrackID::recast(bIDc));
|
||||
VERIFY_ERROR (WRONG_TYPE, ClipID::recast(bIDt));
|
||||
VERIFY_ERROR (WRONG_TYPE, DummyID::recast(bIDc));
|
||||
VERIFY_ERROR (WRONG_TYPE, DummyID::recast(bIDt));
|
||||
|
||||
lumiera_uid plainLUID;
|
||||
lumiera_uid_copy (&plainLUID, tID.getHash().get());
|
||||
// mixed equality comparisons (based on the hash)
|
||||
BareEntryID bIDt_copy (bIDt);
|
||||
CHECK (bIDt == bIDt_copy);
|
||||
CHECK (!isSameObject (bIDt, bIDt_copy));
|
||||
|
||||
CHECK (cID == ClipID::recast ("suspicious", plainLUID)); // upcast from type erased data (note: changed type)
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #582
|
||||
CHECK (tID != bIDc);
|
||||
CHECK (cID != bIDt_copy);
|
||||
CHECK (tID == bIDt_copy);
|
||||
|
||||
CHECK (bIDt == TrackID ("suspicious"));
|
||||
CHECK (bIDt != ClipID ("suspicious"));
|
||||
CHECK (bIDc == ClipID ("suspicious"));
|
||||
CHECK (TrackID ("suspicious") != ClipID ("suspicious"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---key--+-value-+-hash-function---
|
||||
typedef std::tr1::unordered_map<DummyID, string, DummyID::UseEmbeddedHash> Hashtable;
|
||||
|
||||
/** @test build a hashtable, using EntryID as key,
|
||||
* thereby using the embedded hash-ID */
|
||||
void
|
||||
buildHashtable ()
|
||||
{ //---key--+-value-+-hash-function---
|
||||
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #582
|
||||
typedef std::tr1::unordered_map<DummyID, string, DummyID::UseEmbeddedHash()> Hashtable;
|
||||
|
||||
{
|
||||
Hashtable tab;
|
||||
|
||||
for (uint i=0; i<1000; ++i)
|
||||
for (uint i=0; i<1000; ++i) /////////////////////////////////////TICKET #587 we get strange collisions for 10000 entries
|
||||
{
|
||||
DummyID dummy;
|
||||
tab[dummy] = string(dummy);
|
||||
|
|
@ -237,9 +262,16 @@ namespace test {
|
|||
|
||||
CHECK (1000 == tab.size());
|
||||
|
||||
for_each (tab.getKeys(), tab[_1] == string(_1)); /////TODO use boost::lambda to make this happen....
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #582
|
||||
CHECK (and_all (tab, verifyEntry));
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
verifyEntry (Hashtable::value_type entry)
|
||||
{
|
||||
return entry.second == string(entry.first);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue