Commits

David Lin committed baa8fb6

Resource and Logger

  • Participants
  • Parent commits c31e27d

Comments (0)

Files changed (11)

File engine/include/Mocha/Mocha.h

 #include "MochaPlatform.h"
 #include "MochaPrerequisites.h"
 #include "MochaString.h"
+#include "MochaLog.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 

File engine/include/Mocha/MochaDataStream.h

     };
     
   public:
+    DataStream( AccessMode mode );
+    virtual ~DataStream();
     
     
     
     
     
   private:
-    AccessMode m_Mode;
+    const AccessMode m_Mode;
   };
   
 }

File engine/include/Mocha/MochaLog.h

+#pragma once
+
+#include "MochaPrerequisites.h"
+
+namespace Mocha{
+  
+  class Log;
+  class LogStream;
+  
+  class MOCHA_EXPORT Log{
+  public:
+    enum LEVEL{
+      LEVEL_NORMAL = 0,
+      LEVEL_ERROR,
+      LEVEL_FATAL_ERROR,
+      _LEVEL_NUMBER
+    };
+    
+  private:
+    Log();
+    
+  public:
+    
+    // 
+    Log( U32 name, const char* fileName );
+    
+    // 
+    ~Log();
+    
+    // 
+    LogStream post( LEVEL level = Log::LEVEL_NORMAL );
+    
+    //
+    LogStream error();
+    
+    //
+    LogStream fatal();
+    
+    //
+    static Log& cerr();
+    
+  private:
+    void _postPrefix( LEVEL level );
+    
+    U32 m_Name;
+    
+    std::ofstream m_FileOutputStream;
+    std::ostream & m_OutputStream;
+    
+  private:
+    static Log s_StdErrLog;
+  };
+  
+  ////////
+  
+  // Logger Stream
+  // - Note that it is not thread-safe
+  //
+  class MOCHA_EXPORT LogStream{
+    friend class Log;
+  private:
+    LogStream( Log::LEVEL level, std::ostream& ost );
+    
+    LogStream( const LogStream& ); // Non-Copyable
+    void operator=( const LogStream& ); // Non-Copyable
+    
+  public:
+    ~LogStream();
+    
+    template< typename T >
+    LogStream& operator<<( const T& obj ){
+      m_OutputStream << obj;
+      return *this;
+    }
+    
+  private:
+    Log::LEVEL m_Level;
+    std::ostream & m_OutputStream;
+  };
+  
+  ////////
+  
+}

File engine/include/Mocha/MochaObject.h

   public:
     
     // Constructor
+    // The Implementation of Initialization
     Object();
     
     // Destructor
+    // The Implementation of Finalization
     virtual ~Object();
     
-    // Initialize the Object
-    void init();
-    
     // Increment Reference Count
     void retain();
     
     
   protected:
     
-    // The Implementation of Initialization
-    virtual void _init()=0;
-    
-    // The Implementation of Finalization
-    virtual void _finish()=0;
+  private:
+    // Non Copyable
+    Object( const Object& );
+    void operator=( const Object& );
     
   private:
-    void _raiseRefCountError();
     
     volatile I32 m_RefCount;
     

File engine/include/Mocha/MochaResource.h

       STATE_UNLOADED = 0,
       STATE_LOADING,
       STATE_LOADED,
-      STATE_UNLOADING
+      STATE_UNLOADING,
+      STATE_PREPARED,
+      STATE_PREPARING
     };
     
   public:
     
     // Constructor
-    Resource();
+    Resource( U32 name, U32 kind  );
     
     // Destructor
     virtual ~Resource();
     
     // Enter 
-    bool enterCriticalState();
+    void enterCriticalState();
     
     // Leave
     void leaveCriticalState();
     // Get Content State
     CONTENT_STATE getContentState()const;
     
+    // Prepare Content
+    // return = false if not perform
+    bool prepare();
+    
     // Load Content
+    // return = false if not perform
     bool load();
     
     // Unload Content
+    // return = false if not perform
     bool unload();
     
     // Get Name
     // Get Kind
     U32 getKind()const;
     
-    // Initialize
-    void init( U32 name, U32 kind );
+    //
+    bool isLoaded()const;
+    
+    // 
+    
     
   protected:
+    
+    // Implementation of Resource Content Preparation
+    // - including Streaming
+    // return = true if Success
+    virtual bool _prepareImpl()=0;
+    
+    // Implementation of Un-Preparation
+    virtual void _unprepareImpl()=0;
+    
+    // Implementation of Resource Content Loading
+    // return = true if Success
     virtual bool _loadImpl()=0;
+    
+    // Implementation of Resource Content Unloading
     virtual void _unloadImpl()=0;
-    virtual void _init();
-    virtual void _finish();
     
-  private:
-    void init();
+    // Size _calculateSize()
     
   private:
     U32 m_Name;

File engine/source/MochaLog.cpp

+#include <Mocha/MochaLog.h>
+
+namespace Mocha{
+  
+  static const char* s_LevelStr[ Log::_LEVEL_NUMBER ] = {
+    "NORMAL",
+    "ERROR",
+    "FATAL"
+  };
+  
+  //
+  
+  Log::Log()
+  :m_Name(0), m_OutputStream(std::cerr)
+  {
+  }
+  
+  //
+  
+  Log::Log( U32 name, const char* fileName )
+  :m_Name(name), 
+  m_FileOutputStream(fileName, (std::ios_base::app|std::ios_base::out)), 
+  m_OutputStream(m_FileOutputStream)
+  {
+    assert( name );
+    assert( fileName );
+    assert( m_FileOutputStream.is_open() );
+    
+    m_OutputStream << "=== Logger Opened: name = " << m_Name << " ===\n";
+  }
+  
+  Log::~Log(){
+    if(m_Name)
+      m_OutputStream << "=== Logger Closed: name = " << m_Name << " ===\n";
+    
+    if( m_FileOutputStream.is_open() )
+      m_FileOutputStream.close();
+  }
+  
+  LogStream Log::post( LEVEL level ){
+    _postPrefix( level );
+    return LogStream( level, m_OutputStream );
+  }
+  
+  LogStream Log::error(){
+    return post( LEVEL_ERROR );
+  }
+  
+  LogStream Log::fatal(){
+    return post( LEVEL_FATAL_ERROR );
+  }
+  
+  void Log::_postPrefix( LEVEL level ){
+    m_OutputStream << "[#(" << m_Name << ")_";
+    m_OutputStream << s_LevelStr[level] <<  "]: ";
+  }
+  
+  Log& Log::cerr(){
+    return s_StdErrLog;
+  }
+  
+  Log Log::s_StdErrLog;
+  
+  /////////////////////////////////
+  
+  LogStream::LogStream( Log::LEVEL level, std::ostream& ost )
+  :m_Level(level), m_OutputStream(ost)
+  {
+  }
+  
+  LogStream::~LogStream(){
+    // Flush
+    m_OutputStream << std::endl;
+    
+    // Check Level
+    switch(m_Level){
+      case Log::LEVEL_NORMAL:
+      case Log::LEVEL_ERROR:
+        break;
+      case Log::LEVEL_FATAL_ERROR:
+        std::abort();
+        break;
+    }
+    
+  }
+  
+}

File engine/source/MochaObject.cpp

 #include <Mocha/MochaObject.h>
+#include <Mocha/MochaLog.h>
 
 namespace Mocha{
   
   Object::Object()
-  :m_RefCount(0)
+  :m_RefCount(1)
   {
   }
   
   Object::~Object(){
-    if( m_RefCount != 0 )
-      _raiseRefCountError();
-  }
-  
-  void Object::init(){
-    if(atomicExchange( &m_RefCount, 1 ) != 0)
-      _raiseRefCountError();
-    
-    _init();
+    if( m_RefCount != 0 ){
+      Log::cerr().fatal() << "Object{" << this << "}." <<
+      "~Object(): m_RefCount should be 0.";
+    }
   }
   
   void Object::retain(){
-    if(atomicInc(&m_RefCount) < 2)
-      _raiseRefCountError();
+    const I32 value = atomicInc(&m_RefCount);
+    if(value < 2){
+      Log::cerr().fatal() << "Object{" << this << "}." << 
+      "retain(): m_RefCount should be 1.";
+    }
   }
   
   void Object::release(){
-    I32 value = atomicDec(&m_RefCount);
-    if( value == 0 )
-      _finish();
-    else if( value < 0 )
-      _raiseRefCountError();
+    const I32 value = atomicDec(&m_RefCount);
+    if( value < 0 ){
+      Log::cerr().fatal() << "Object{" << this << "}." << 
+      "release(): m_RefCount should not be 0.";
+    }else if( value == 0 ){
+      delete this;
+    }
   }
   
   I32 Object::getRetainCount()const{
     return m_RefCount;
   }
   
-  void Object::_raiseRefCountError(){
-    // Error
-    std::abort();
-  }
-  
 }

File engine/source/MochaResource.cpp

 #include <Mocha/MochaResource.h>
+#include <Mocha/MochaLog.h>
 
 namespace Mocha{
   
-  Resource::Resource()
-  :m_CriticalCount(0), m_ContentState(STATE_UNLOADED)
+  Resource::Resource( U32 name, U32 kind )
+  :m_Name(name), m_Kind(kind),
+  m_CriticalCount(0), m_ContentState(STATE_UNLOADED)
   {
-    
   }
   
   Resource::~Resource(){
-    if( m_CriticalCount != 0 )
-      std::abort();
-    if( m_ContentState != STATE_UNLOADED )
-      std::abort();
+    if( m_CriticalCount != 0 ){
+      Log::cerr().fatal() << "Resource{" << this << "}." << 
+      "~Resource(): m_CriticalCount should be 0.";
+    }
+    if( m_ContentState != STATE_UNLOADED ){
+      Log::cerr().fatal() << "Resource{" << this << "}." << 
+      "~Resource(): content should be unloaded.";
+    }
   }
   
-  bool Resource::enterCriticalState(){
-    if( m_ContentState != STATE_LOADED )
-      return false;
+  void Resource::enterCriticalState(){
+    if( m_ContentState != STATE_LOADED ){
+      Log::cerr().fatal() << "Resource{" << this << "}." << 
+      "enterCriticalState(): content should be loaded.";
+    }
     
     atomicInc(&m_CriticalCount);
-    return true;
   }
   
   void Resource::leaveCriticalState(){
-    if( atomicDec(&m_CriticalCount) < 0 )
-      std::abort();
+    const I32 value = atomicDec(&m_CriticalCount);
+    if( value < 0 ){
+      Log::cerr().fatal() << "Resource{" << this << "}." << 
+      "leaveCriticalState(): m_CriticalCount initially should >= 1.";
+    }
   }
   
   I32 Resource::getCriticalStateCount()const{
     return static_cast<Resource::CONTENT_STATE>(m_ContentState);
   }
   
+  bool Resource::prepare(){
+    if( m_CriticalCount != 0 ){
+      Log::cerr().fatal() << "Resource{" << this << "}." << 
+      "prepare(): m_CriticalCount should be 0.";
+    }
+    
+    if(atomicCompareExchange(&m_ContentState, STATE_PREPARING, STATE_UNLOADED)
+       != STATE_UNLOADED)
+      return false;
+    
+    bool result;
+    {
+      // Critical Section (Mutex Lock)
+      
+      result = _prepareImpl();
+    }
+    if(result)
+      atomicExchange(&m_ContentState, STATE_PREPARED);
+    else{
+      Log::cerr().fatal() << "Resource{" << this << "}." << 
+      "prepare(): failed to prepare.";
+    }
+    
+    return result;
+  }
+  
   bool Resource::load(){
-    if(atomicCompareExchange(&m_ContentState, STATE_LOADING, STATE_UNLOADED)
-       != STATE_UNLOADED )
+    if( m_CriticalCount != 0 ){
+      Log::cerr().fatal() << "Resource{" << this << "}." << 
+      "load(): m_CriticalCount should be 0.";
+    }
+    
+    if(atomicCompareExchange(&m_ContentState, STATE_LOADING, STATE_PREPARED)
+       != STATE_PREPARED )
       return false;
     
     bool result;
       // Critical Section (Mutex Lock)
       
       result = _loadImpl();
-      
-      //if(!result)
-      //  _unloadImpl();
     }
     
     if(result)
       atomicExchange(&m_ContentState, STATE_LOADED);
-    else
-      atomicExchange(&m_ContentState, STATE_UNLOADED);
+    else{
+      Log::cerr().fatal() << "Resource{" << this << "}." << 
+      "load(): failed to load.";
+    }
     
     return result;
   }
   
   bool Resource::unload(){
-    if(atomicCompareExchange(&m_ContentState, STATE_UNLOADING, STATE_LOADED)
-       != STATE_LOADED )
+    if( m_CriticalCount != 0 ){
+      Log::cerr().fatal() << "Resource{" << this << "}." << 
+      "unload(): m_CriticalCount should be 0.";
+    }
+    
+    I32 oldState = m_ContentState;
+    if(oldState != STATE_LOADED && 
+       oldState != STATE_PREPARED)
+      return false;
+    
+    if(atomicCompareExchange(&m_ContentState, STATE_UNLOADING, oldState)
+       != oldState )
       return false;
     
     {
       // Critical Section (Mutex Lock)
       
-      _unloadImpl();
+      if(oldState == STATE_PREPARED){
+        _unprepareImpl();
+      }else{
+        _unloadImpl();
+      }
     }
     
     atomicExchange(&m_ContentState, STATE_UNLOADED);
     return m_Kind;
   }
   
-  void Resource::init( U32 name, U32 kind ){
-    m_Name = name;
-    m_Kind = kind;
-    
-    Object::init();
-  }
-  
-  ////
-  
-  void Resource::init(){
-    // dummy
-  }
-  
-  void Resource::_init(){
-    if( m_ContentState != STATE_UNLOADED )
-      std::abort();
-  }
-  
-  void Resource::_finish(){
-    if( m_ContentState != STATE_UNLOADED )
-      std::abort();
+  bool Resource::isLoaded()const{
+    return m_ContentState == STATE_LOADED;
   }
   
 }

File test/TestLogger.cpp

+#include <Mocha/Mocha.h>
+using namespace Mocha;;
+
+int main( int argc, char** argv ){
+  Log::cerr();
+  
+  Log::cerr().post() << "Hello! " << 10;
+  Log::cerr().error() << "ERROR! Code = " << -1;
+  //Log::cerr().fatal() << "FATAL!";
+  
+  Log log ( 1, "log1.txt" );
+  log.post() << "Hello! 1";
+  log.post() << "Hello! 2";
+  log.post() << "Hello! 3";
+  log.post() << "Hello! 4";
+  log.post() << "Hello! 5";
+  
+  return 0;
+}

File test/TestObject.cpp

     std::cout << "Deleted.\n";
   }
 private:
-  virtual void _init(){
-    std::cout << "Initialized.\n";
-  }
-  virtual void _finish(){
-    std::cout << "Finished.\n";
-  }
 };
 
 int main( int argc, char** argv ){
   TestObject* obj = new TestObject();
   std::cout << "REFCOUNT = " << obj->getRetainCount() << std::endl;
   
-  obj->init();
-  std::cout << "REFCOUNT = " << obj->getRetainCount() << std::endl;
-  
   obj->retain();
   std::cout << "REFCOUNT = " << obj->getRetainCount() << std::endl;
   
   std::cout << "REFCOUNT = " << obj->getRetainCount() << std::endl;
   
   obj->release();
-  std::cout << "REFCOUNT = " << obj->getRetainCount() << std::endl;
-  
-  delete obj;
   
   return 0;
 }

File test/TestResource.cpp

 #include <Mocha/Mocha.h>
 using namespace Mocha;
-using namespace std;
 
-class TextResource : public Resource {
+class TextResource : public Resource{
 public:
-  TextResource(){
-    
+  TextResource( U32 name, const std::string& filename )
+  :Resource( name, UTF8String::hash("TEXT") ), m_FileName(filename)
+  {
+    Log::cerr().post() << "{name=" << getName() << "} is newed.";
+    Log::cerr().post() << "filename = " << m_FileName;
   }
   
   ~TextResource(){
-    
+    Log::cerr().post() << "{name=" << getName() << "} is deleted.";
+  }
+  
+  const char* getText()const{
+    if(!isLoaded())
+      return NULL;
+    return m_String.c_str();
   }
   
 private:
-  bool _loadImpl(){
+  virtual bool _prepareImpl(){
+    Log::cerr().post() << "{name=" << getName() << "} is preparing.";
+    //std::ifstream ifst( m_FileName.c_str() );
     
+    return true;
   }
   
-  void _unloadImpl(){
-    
+  virtual void _unprepareImpl(){
+    Log::cerr().post() << "{name=" << getName() << "} is unpreparing.";
   }
   
-  void _init(){
-    Resource::_init();
+  virtual bool _loadImpl(){
+    Log::cerr().post() << "{name=" << getName() << "} is loading.";
     
-    
+    return false;
   }
   
-  void _finish(){
-    
-    
-    Resource::_finish();
+  virtual void _unloadImpl(){
+    Log::cerr().post() << "{name=" << getName() << "} is unloading.";
   }
   
-private:
-  
+  std::string m_FileName;
+  std::string m_String;
 };
 
 int main( int argc, char** argv ){
+  if(argc == 0){
+    
+    return 0;
+  }
   
+  TextResource* resources[ argc-1 ];
+  
+  for(int i=1; i < argc; i++){
+    resources[i-1] = new TextResource( i, std::string(argv[i]) );
+  }
+  
+  for(int i=1; i < argc; i++){
+    resources[i-1]->prepare();
+    resources[i-1]->load();
+    resources[i-1]->unload();
+  }
+  
+  for(int i=1; i < argc; i++){
+    resources[i-1]->release();
+  }
   
   return 0;
 }