class_factory.h 4.5 KB
Newer Older
羽飞's avatar
羽飞 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

//
// Created by Longda on 2010
//

#ifndef __COMMON_SEDA_CLASS_FACTORY_H__
#define __COMMON_SEDA_CLASS_FACTORY_H__

#include <list>

#include "common/defs.h"
#include "common/log/log.h"
namespace common {

/**
 *  A class to construct arbitrary subclass instances
 *
 *  This class provides a general solution to constructing instances
 *  of subclasses from a common generic base.  The template is
 *  instantiated for each generic base class.  Then each new subclass
 *  class creates a corresponding ClassFactory instance which includes
 *  a tag which identifies the class and a factory function which
 *  constructs an instance of the class when invoked.  The factory
 *  function takes the tag and a properties object as parameters.
 *
 *  Each class factory instance MUST be constructed before the first
 *  call to make_instance().  Otherwise, the entry will not be found
 *  on the list.  To ensure this, if the class factory instance is
 *  provided by a library, it should be declared with static linkage
 *  within the library initialization routine.  If the class factory
 *  instance is provided by the main application, it should be declared
 *  with static linkage in a global initialization routine.
 */

44
template <class T>
羽飞's avatar
羽飞 已提交
45 46
class ClassFactory {

47
public:
羽飞's avatar
羽飞 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
  typedef T *(*FactoryFunc)(const std::string &);

  /**
   * Constructor
   * @param[in] tag     Tag identifies a particular sub-class
   * @param[in] func    Factory function to create sub-class instance
   *
   * @post (tag,func) pair is entered into global factory list
   */
  ClassFactory(const std::string &tag, FactoryFunc func);

  // Destructor
  ~ClassFactory();

  /**
   * Construct an instance of a specified sub-class
   * @param[in] tag     Identifies sub-class to instantiate
   * @param[in] prop    Properties desired for the instance
   *
   * @return a reference to the desired instance
   */
  static T *make_instance(const std::string &tag);

71
private:
羽飞's avatar
羽飞 已提交
72 73 74
  // Accessor function that gets the head of the factory list
  static ClassFactory<T> *&fact_list_head();

75
  std::string identifier_;  // identifier for this factory
羽飞's avatar
羽飞 已提交
76
  FactoryFunc fact_func_;   // factory function for this class
77
  ClassFactory<T> *next_;   // next factory in global list
羽飞's avatar
羽飞 已提交
78 79 80 81 82 83 84 85 86 87 88 89
};

/**
 * Accessor function that gets the head of the factory list
 * Implementation notes:
 * The head pointer in the list must be initialized to NULL before
 * it is accessed from any ClassFactory<T> constructor.  We cannot
 * rely on C++ constructor order to achieve this.  Instead, we wrap
 * the list head in an accessor function, and declare its linkage
 * as static.  C++ guarantees that the first time the function is
 * invoked (from anywhere) the static local will be initialized.
 */
90 91 92
template <class T>
ClassFactory<T> *&ClassFactory<T>::fact_list_head()
{
羽飞's avatar
羽飞 已提交
93 94 95 96 97 98 99 100 101
  static ClassFactory<T> *fact_list = NULL;
  return fact_list;
}

/**
 * Constructor
 * Implementation notes:
 * constructor places current instance on the global factory list.
 */
102 103 104
template <class T>
ClassFactory<T>::ClassFactory(const std::string &tag, FactoryFunc func) : identifier_(tag), fact_func_(func)
{
羽飞's avatar
羽飞 已提交
105 106 107 108 109
  next_ = fact_list_head();
  fact_list_head() = this;
}

// Destructor
110 111 112
template <class T>
ClassFactory<T>::~ClassFactory()
{}
羽飞's avatar
羽飞 已提交
113 114 115 116 117 118 119

/**
 * Construct an instance of a specified sub-class
 * Implementation notes:
 * scan global list to find matching tag and use the factory func to
 * create an instance.
 */
120 121 122
template <class T>
T *ClassFactory<T>::make_instance(const std::string &tag)
{
羽飞's avatar
羽飞 已提交
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
  T *instance = NULL;
  ClassFactory<T> *current = fact_list_head();

  // search the global factory list for a match
  while ((current != NULL) && (tag != current->identifier_)) {
    current = current->next_;
  }

  // if we have a match, create and return an instance
  if (current != NULL) {
    FactoryFunc fptr = current->fact_func_;
    instance = (*fptr)(tag);
  }

  ASSERT((instance != NULL), "%s%s", tag.c_str(), "instance not created");
  return instance;
}

141 142
}  // namespace common
#endif  // __COMMON_SEDA_CLASS_FACTORY_H__