// @(#)root/cont
// Author: Bianca-Cristina Cristescu February 2014

/*************************************************************************
 * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TListOfEnums                                                         //
//                                                                      //
// A collection of TEnum objects designed for fast access given a       //
// DeclId_t and for keep track of TEnum that were described             //
// unloaded enum.                                                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TListOfEnums.h"
#include "TClass.h"
#include "TExMap.h"
#include "TEnum.h"
#include "TGlobal.h"
#include "TInterpreter.h"
#include "TVirtualMutex.h"

ClassImp(TListOfEnums)

//______________________________________________________________________________
TListOfEnums::TListOfEnums(TClass *cl) : fClass(cl),fIds(0),fUnloaded(0),fIsLoaded(kFALSE),
              fLastLoadMarker(0)
{
   // Constructor.

   fIds = new TExMap;
   fUnloaded = new THashList;
}

//______________________________________________________________________________
TListOfEnums::~TListOfEnums()
{
   // Destructor.

   THashList::Delete();
   delete fIds;
   fUnloaded->Delete();
   delete fUnloaded;
}

//______________________________________________________________________________
void TListOfEnums::MapObject(TObject *obj)
{
   // Add pair<id, object> to the map of functions and their ids.

   TEnum *e = dynamic_cast<TEnum*>(obj);
   if (e) {
      fIds->Add((Long64_t)e->GetDeclId(),(Long64_t)e);
   }
}

//______________________________________________________________________________
void TListOfEnums::AddFirst(TObject *obj)
{
   // Add object at the beginning of the list.

   THashList::AddFirst(obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfEnums::AddFirst(TObject *obj, Option_t *opt)
{
   // Add object at the beginning of the list and also store option.
   // Storing an option is useful when one wants to change the behaviour
   // of an object a little without having to create a complete new
   // copy of the object. This feature is used, for example, by the Draw()
   // method. It allows the same object to be drawn in different ways.

   THashList::AddFirst(obj,opt);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfEnums::AddLast(TObject *obj)
{
   // Add object at the end of the list.

   THashList::AddLast(obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfEnums::AddLast(TObject *obj, Option_t *opt)
{
   // Add object at the end of the list and also store option.
   // Storing an option is useful when one wants to change the behaviour
   // of an object a little without having to create a complete new
   // copy of the object. This feature is used, for example, by the Draw()
   // method. It allows the same object to be drawn in different ways.

   THashList::AddLast(obj, opt);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfEnums::AddAt(TObject *obj, Int_t idx)
{
   // Insert object at location idx in the list.

   THashList::AddAt(obj, idx);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfEnums::AddAfter(const TObject *after, TObject *obj)
{
   // Insert object after object after in the list.

   THashList::AddAfter(after, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfEnums::AddAfter(TObjLink *after, TObject *obj)
{
   // Insert object after object after in the list.

   THashList::AddAfter(after, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfEnums::AddBefore(const TObject *before, TObject *obj)
{
   // Insert object before object before in the list.

   THashList::AddBefore(before, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfEnums::AddBefore(TObjLink *before, TObject *obj)
{
   // Insert object before object before in the list.

   THashList::AddBefore(before, obj);
   MapObject(obj);
}

//______________________________________________________________________________
void TListOfEnums::Clear(Option_t *option)
{
   // Remove all objects from the list. Does not delete the objects unless
   // the THashList is the owner (set via SetOwner()).

   fUnloaded->Clear(option);
   fIds->Clear();
   THashList::Clear(option);
   fIsLoaded = kFALSE;
}

//______________________________________________________________________________
void TListOfEnums::Delete(Option_t *option /* ="" */)
{
   // Delete all TDataMember object files.

   fUnloaded->Delete(option);
   THashList::Delete(option);
   fIsLoaded = kFALSE;
}

//______________________________________________________________________________
TObject *TListOfEnums::FindObject(const char *name) const
{
   // Specialize FindObject to do search for the
   // a enum just by name or create it if its not already in the list

   TObject *result = THashList::FindObject(name);
   if (!result) {
      TInterpreter::DeclId_t decl;
      if (fClass) decl = gInterpreter->GetEnum(fClass, name);
      else        decl = gInterpreter->GetEnum(0, name);
      if (decl) result = const_cast<TListOfEnums*>(this)->Get(decl, name);
   }
   return result;
}

//______________________________________________________________________________
TEnum *TListOfEnums::Get(DeclId_t id, const char *name)
{
   // Return (after creating it if necessary) the TEnum
   // describing the enum corresponding to the Decl 'id'.

   if (!id) return 0;

   TEnum *e = (TEnum*)fIds->GetValue((Long64_t)id);
   if (!e) {
      if (fClass) {
         if (!fClass->HasInterpreterInfoInMemory()) {
            // The interpreter does not know about this class yet (or a problem
            // occurred that prevented the proper updating of fClassInfo).
            // So this decl can not possibly be part of this class.
            // [In addition calling GetClassInfo would trigger a late parsing
            //  of the header which we want to avoid].
            return 0;
         }
         if (!gInterpreter->ClassInfo_Contains(fClass->GetClassInfo(),id)) return 0;
      } else {
         if (!gInterpreter->ClassInfo_Contains(0,id)) return 0;
      }

      // Let's see if this is a reload ...
      // can we check for reloads for enums?
      e = (TEnum *)fUnloaded->FindObject(name);
      if (e) {
         e->Update(id);
         gInterpreter->UpdateEnumConstants(e, fClass);
      } else {
         e = gInterpreter->CreateEnum((void*)id, fClass);
      }
      // Calling 'just' THahList::Add would turn around and call
      // TListOfEnums::AddLast which should *also* do the fIds->Add.
      THashList::AddLast(e);
      fIds->Add((Long64_t)id,(Long64_t)e);
   }
   return e;
}

//______________________________________________________________________________
void TListOfEnums::UnmapObject(TObject *obj)
{
   // Remove a pair<id, object> from the map of functions and their ids.
   TEnum *e = dynamic_cast<TEnum*>(obj);
   if (e) {
      fIds->Remove((Long64_t)e->GetDeclId());
   }
}

//______________________________________________________________________________
void TListOfEnums::RecursiveRemove(TObject *obj)
{
   // Remove object from this collection and recursively remove the object
   // from all other objects (and collections).
   // This function overrides TCollection::RecursiveRemove that calls
   // the Remove function. THashList::Remove cannot be called because
   // it uses the hash value of the hash table. This hash value
   // is not available anymore when RecursiveRemove is called from
   // the TObject destructor.

   if (!obj) return;

   THashList::RecursiveRemove(obj);
   fUnloaded->RecursiveRemove(obj);
   UnmapObject(obj);
}

//______________________________________________________________________________
TObject* TListOfEnums::Remove(TObject *obj)
{
   // Remove object from the list.

   Bool_t found;

   found = THashList::Remove(obj);
   if (!found) {
      found = fUnloaded->Remove(obj);
   }
   UnmapObject(obj);
   if (found) return obj;
   else return 0;
}

//______________________________________________________________________________
TObject* TListOfEnums::Remove(TObjLink *lnk)
{
   // Remove object via its objlink from the list.

   if (!lnk) return 0;

   TObject *obj = lnk->GetObject();

   THashList::Remove(lnk);
   fUnloaded->Remove(obj);
   UnmapObject(obj);
   return obj;
}

//______________________________________________________________________________
void TListOfEnums::Load()
{
   // Load all the DataMembers known to the intepreter for the scope 'fClass'
   // into this collection.

   if (fClass && fClass->Property() & (kIsClass|kIsStruct|kIsUnion)) {
      // Class and union are not extendable, if we already
      // loaded all the data member there is no need to recheck
      if (fIsLoaded) return;
   }

   // This will provoke the parsing of the headers if need be.
   if (fClass && fClass->GetClassInfo() == 0) return;

   ULong64_t currentTransaction = gInterpreter->GetInterpreterStateMarker();
   if (currentTransaction == fLastLoadMarker) {
      return;
   }
   fLastLoadMarker = currentTransaction;

   // In the case of namespace, even if we have loaded before we need to
   // load again in case there was new data member added.

   // Mark the list as loaded to avoid an infinite recursion in the case
   // where we have a data member that is a variable size array.  In that
   // case TDataMember::Init needs to get/load the list to find the data
   // member used as the array size.
   fIsLoaded = kTRUE;

   gInterpreter->LoadEnums(fClass);
}

//______________________________________________________________________________
void TListOfEnums::Unload()
{
   // Mark 'all func' as being unloaded.
   // After the unload, the data member can no longer be found directly,
   // until the decl can be found again in the interpreter (in which
   // the func object will be reused.

   TObjLink *lnk = FirstLink();
   while (lnk) {
      TEnum *data = (TEnum *)lnk->GetObject();

      fIds->Remove((Long64_t)data->GetDeclId());
      fUnloaded->Add(data);

      lnk = lnk->Next();
   }

   THashList::Clear();
   fIsLoaded = kFALSE;
}

//______________________________________________________________________________
void TListOfEnums::Unload(TEnum *e)
{
   // Mark 'func' as being unloaded.
   // After the unload, the data member can no longer be found directly,
   // until the decl can be found again in the interpreter (in which
   // the func object will be reused.

   if (THashList::Remove(e)) {
      // We contains the object, let remove it from the other internal
      // list and move it to the list of unloaded objects.
      fIds->Remove((Long64_t)e->GetDeclId());
      fUnloaded->Add(e);
   }
}
 TListOfEnums.cxx:1
 TListOfEnums.cxx:2
 TListOfEnums.cxx:3
 TListOfEnums.cxx:4
 TListOfEnums.cxx:5
 TListOfEnums.cxx:6
 TListOfEnums.cxx:7
 TListOfEnums.cxx:8
 TListOfEnums.cxx:9
 TListOfEnums.cxx:10
 TListOfEnums.cxx:11
 TListOfEnums.cxx:12
 TListOfEnums.cxx:13
 TListOfEnums.cxx:14
 TListOfEnums.cxx:15
 TListOfEnums.cxx:16
 TListOfEnums.cxx:17
 TListOfEnums.cxx:18
 TListOfEnums.cxx:19
 TListOfEnums.cxx:20
 TListOfEnums.cxx:21
 TListOfEnums.cxx:22
 TListOfEnums.cxx:23
 TListOfEnums.cxx:24
 TListOfEnums.cxx:25
 TListOfEnums.cxx:26
 TListOfEnums.cxx:27
 TListOfEnums.cxx:28
 TListOfEnums.cxx:29
 TListOfEnums.cxx:30
 TListOfEnums.cxx:31
 TListOfEnums.cxx:32
 TListOfEnums.cxx:33
 TListOfEnums.cxx:34
 TListOfEnums.cxx:35
 TListOfEnums.cxx:36
 TListOfEnums.cxx:37
 TListOfEnums.cxx:38
 TListOfEnums.cxx:39
 TListOfEnums.cxx:40
 TListOfEnums.cxx:41
 TListOfEnums.cxx:42
 TListOfEnums.cxx:43
 TListOfEnums.cxx:44
 TListOfEnums.cxx:45
 TListOfEnums.cxx:46
 TListOfEnums.cxx:47
 TListOfEnums.cxx:48
 TListOfEnums.cxx:49
 TListOfEnums.cxx:50
 TListOfEnums.cxx:51
 TListOfEnums.cxx:52
 TListOfEnums.cxx:53
 TListOfEnums.cxx:54
 TListOfEnums.cxx:55
 TListOfEnums.cxx:56
 TListOfEnums.cxx:57
 TListOfEnums.cxx:58
 TListOfEnums.cxx:59
 TListOfEnums.cxx:60
 TListOfEnums.cxx:61
 TListOfEnums.cxx:62
 TListOfEnums.cxx:63
 TListOfEnums.cxx:64
 TListOfEnums.cxx:65
 TListOfEnums.cxx:66
 TListOfEnums.cxx:67
 TListOfEnums.cxx:68
 TListOfEnums.cxx:69
 TListOfEnums.cxx:70
 TListOfEnums.cxx:71
 TListOfEnums.cxx:72
 TListOfEnums.cxx:73
 TListOfEnums.cxx:74
 TListOfEnums.cxx:75
 TListOfEnums.cxx:76
 TListOfEnums.cxx:77
 TListOfEnums.cxx:78
 TListOfEnums.cxx:79
 TListOfEnums.cxx:80
 TListOfEnums.cxx:81
 TListOfEnums.cxx:82
 TListOfEnums.cxx:83
 TListOfEnums.cxx:84
 TListOfEnums.cxx:85
 TListOfEnums.cxx:86
 TListOfEnums.cxx:87
 TListOfEnums.cxx:88
 TListOfEnums.cxx:89
 TListOfEnums.cxx:90
 TListOfEnums.cxx:91
 TListOfEnums.cxx:92
 TListOfEnums.cxx:93
 TListOfEnums.cxx:94
 TListOfEnums.cxx:95
 TListOfEnums.cxx:96
 TListOfEnums.cxx:97
 TListOfEnums.cxx:98
 TListOfEnums.cxx:99
 TListOfEnums.cxx:100
 TListOfEnums.cxx:101
 TListOfEnums.cxx:102
 TListOfEnums.cxx:103
 TListOfEnums.cxx:104
 TListOfEnums.cxx:105
 TListOfEnums.cxx:106
 TListOfEnums.cxx:107
 TListOfEnums.cxx:108
 TListOfEnums.cxx:109
 TListOfEnums.cxx:110
 TListOfEnums.cxx:111
 TListOfEnums.cxx:112
 TListOfEnums.cxx:113
 TListOfEnums.cxx:114
 TListOfEnums.cxx:115
 TListOfEnums.cxx:116
 TListOfEnums.cxx:117
 TListOfEnums.cxx:118
 TListOfEnums.cxx:119
 TListOfEnums.cxx:120
 TListOfEnums.cxx:121
 TListOfEnums.cxx:122
 TListOfEnums.cxx:123
 TListOfEnums.cxx:124
 TListOfEnums.cxx:125
 TListOfEnums.cxx:126
 TListOfEnums.cxx:127
 TListOfEnums.cxx:128
 TListOfEnums.cxx:129
 TListOfEnums.cxx:130
 TListOfEnums.cxx:131
 TListOfEnums.cxx:132
 TListOfEnums.cxx:133
 TListOfEnums.cxx:134
 TListOfEnums.cxx:135
 TListOfEnums.cxx:136
 TListOfEnums.cxx:137
 TListOfEnums.cxx:138
 TListOfEnums.cxx:139
 TListOfEnums.cxx:140
 TListOfEnums.cxx:141
 TListOfEnums.cxx:142
 TListOfEnums.cxx:143
 TListOfEnums.cxx:144
 TListOfEnums.cxx:145
 TListOfEnums.cxx:146
 TListOfEnums.cxx:147
 TListOfEnums.cxx:148
 TListOfEnums.cxx:149
 TListOfEnums.cxx:150
 TListOfEnums.cxx:151
 TListOfEnums.cxx:152
 TListOfEnums.cxx:153
 TListOfEnums.cxx:154
 TListOfEnums.cxx:155
 TListOfEnums.cxx:156
 TListOfEnums.cxx:157
 TListOfEnums.cxx:158
 TListOfEnums.cxx:159
 TListOfEnums.cxx:160
 TListOfEnums.cxx:161
 TListOfEnums.cxx:162
 TListOfEnums.cxx:163
 TListOfEnums.cxx:164
 TListOfEnums.cxx:165
 TListOfEnums.cxx:166
 TListOfEnums.cxx:167
 TListOfEnums.cxx:168
 TListOfEnums.cxx:169
 TListOfEnums.cxx:170
 TListOfEnums.cxx:171
 TListOfEnums.cxx:172
 TListOfEnums.cxx:173
 TListOfEnums.cxx:174
 TListOfEnums.cxx:175
 TListOfEnums.cxx:176
 TListOfEnums.cxx:177
 TListOfEnums.cxx:178
 TListOfEnums.cxx:179
 TListOfEnums.cxx:180
 TListOfEnums.cxx:181
 TListOfEnums.cxx:182
 TListOfEnums.cxx:183
 TListOfEnums.cxx:184
 TListOfEnums.cxx:185
 TListOfEnums.cxx:186
 TListOfEnums.cxx:187
 TListOfEnums.cxx:188
 TListOfEnums.cxx:189
 TListOfEnums.cxx:190
 TListOfEnums.cxx:191
 TListOfEnums.cxx:192
 TListOfEnums.cxx:193
 TListOfEnums.cxx:194
 TListOfEnums.cxx:195
 TListOfEnums.cxx:196
 TListOfEnums.cxx:197
 TListOfEnums.cxx:198
 TListOfEnums.cxx:199
 TListOfEnums.cxx:200
 TListOfEnums.cxx:201
 TListOfEnums.cxx:202
 TListOfEnums.cxx:203
 TListOfEnums.cxx:204
 TListOfEnums.cxx:205
 TListOfEnums.cxx:206
 TListOfEnums.cxx:207
 TListOfEnums.cxx:208
 TListOfEnums.cxx:209
 TListOfEnums.cxx:210
 TListOfEnums.cxx:211
 TListOfEnums.cxx:212
 TListOfEnums.cxx:213
 TListOfEnums.cxx:214
 TListOfEnums.cxx:215
 TListOfEnums.cxx:216
 TListOfEnums.cxx:217
 TListOfEnums.cxx:218
 TListOfEnums.cxx:219
 TListOfEnums.cxx:220
 TListOfEnums.cxx:221
 TListOfEnums.cxx:222
 TListOfEnums.cxx:223
 TListOfEnums.cxx:224
 TListOfEnums.cxx:225
 TListOfEnums.cxx:226
 TListOfEnums.cxx:227
 TListOfEnums.cxx:228
 TListOfEnums.cxx:229
 TListOfEnums.cxx:230
 TListOfEnums.cxx:231
 TListOfEnums.cxx:232
 TListOfEnums.cxx:233
 TListOfEnums.cxx:234
 TListOfEnums.cxx:235
 TListOfEnums.cxx:236
 TListOfEnums.cxx:237
 TListOfEnums.cxx:238
 TListOfEnums.cxx:239
 TListOfEnums.cxx:240
 TListOfEnums.cxx:241
 TListOfEnums.cxx:242
 TListOfEnums.cxx:243
 TListOfEnums.cxx:244
 TListOfEnums.cxx:245
 TListOfEnums.cxx:246
 TListOfEnums.cxx:247
 TListOfEnums.cxx:248
 TListOfEnums.cxx:249
 TListOfEnums.cxx:250
 TListOfEnums.cxx:251
 TListOfEnums.cxx:252
 TListOfEnums.cxx:253
 TListOfEnums.cxx:254
 TListOfEnums.cxx:255
 TListOfEnums.cxx:256
 TListOfEnums.cxx:257
 TListOfEnums.cxx:258
 TListOfEnums.cxx:259
 TListOfEnums.cxx:260
 TListOfEnums.cxx:261
 TListOfEnums.cxx:262
 TListOfEnums.cxx:263
 TListOfEnums.cxx:264
 TListOfEnums.cxx:265
 TListOfEnums.cxx:266
 TListOfEnums.cxx:267
 TListOfEnums.cxx:268
 TListOfEnums.cxx:269
 TListOfEnums.cxx:270
 TListOfEnums.cxx:271
 TListOfEnums.cxx:272
 TListOfEnums.cxx:273
 TListOfEnums.cxx:274
 TListOfEnums.cxx:275
 TListOfEnums.cxx:276
 TListOfEnums.cxx:277
 TListOfEnums.cxx:278
 TListOfEnums.cxx:279
 TListOfEnums.cxx:280
 TListOfEnums.cxx:281
 TListOfEnums.cxx:282
 TListOfEnums.cxx:283
 TListOfEnums.cxx:284
 TListOfEnums.cxx:285
 TListOfEnums.cxx:286
 TListOfEnums.cxx:287
 TListOfEnums.cxx:288
 TListOfEnums.cxx:289
 TListOfEnums.cxx:290
 TListOfEnums.cxx:291
 TListOfEnums.cxx:292
 TListOfEnums.cxx:293
 TListOfEnums.cxx:294
 TListOfEnums.cxx:295
 TListOfEnums.cxx:296
 TListOfEnums.cxx:297
 TListOfEnums.cxx:298
 TListOfEnums.cxx:299
 TListOfEnums.cxx:300
 TListOfEnums.cxx:301
 TListOfEnums.cxx:302
 TListOfEnums.cxx:303
 TListOfEnums.cxx:304
 TListOfEnums.cxx:305
 TListOfEnums.cxx:306
 TListOfEnums.cxx:307
 TListOfEnums.cxx:308
 TListOfEnums.cxx:309
 TListOfEnums.cxx:310
 TListOfEnums.cxx:311
 TListOfEnums.cxx:312
 TListOfEnums.cxx:313
 TListOfEnums.cxx:314
 TListOfEnums.cxx:315
 TListOfEnums.cxx:316
 TListOfEnums.cxx:317
 TListOfEnums.cxx:318
 TListOfEnums.cxx:319
 TListOfEnums.cxx:320
 TListOfEnums.cxx:321
 TListOfEnums.cxx:322
 TListOfEnums.cxx:323
 TListOfEnums.cxx:324
 TListOfEnums.cxx:325
 TListOfEnums.cxx:326
 TListOfEnums.cxx:327
 TListOfEnums.cxx:328
 TListOfEnums.cxx:329
 TListOfEnums.cxx:330
 TListOfEnums.cxx:331
 TListOfEnums.cxx:332
 TListOfEnums.cxx:333
 TListOfEnums.cxx:334
 TListOfEnums.cxx:335
 TListOfEnums.cxx:336
 TListOfEnums.cxx:337
 TListOfEnums.cxx:338
 TListOfEnums.cxx:339
 TListOfEnums.cxx:340
 TListOfEnums.cxx:341
 TListOfEnums.cxx:342
 TListOfEnums.cxx:343
 TListOfEnums.cxx:344
 TListOfEnums.cxx:345
 TListOfEnums.cxx:346
 TListOfEnums.cxx:347
 TListOfEnums.cxx:348
 TListOfEnums.cxx:349
 TListOfEnums.cxx:350
 TListOfEnums.cxx:351
 TListOfEnums.cxx:352
 TListOfEnums.cxx:353
 TListOfEnums.cxx:354
 TListOfEnums.cxx:355
 TListOfEnums.cxx:356
 TListOfEnums.cxx:357
 TListOfEnums.cxx:358
 TListOfEnums.cxx:359
 TListOfEnums.cxx:360