EntryID finished and passes unit test

This commit is contained in:
Fischlurch 2010-03-29 06:56:42 +02:00
parent c691213003
commit c9bf26d8c4
4 changed files with 159 additions and 62 deletions

View 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

View file

@ -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

View file

@ -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

View file

@ -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);
}
};