def __mul__(self, unit): """ SiPrefix * BaseUnit yields new BaseUnit SiPrefix * ScaledUnit yields new ScaledUnit SiPrefix * Unit with exactly one BaseUnit or ScaledUnit yields new Unit """ if isinstance(unit, BaseUnit): # BaseUnit version symbol = self.symbol + unit.symbol name = self.prefix + unit.name factor = self.factor # TODO - check for existing BaseUnit with same name, symbol, and factor new_base_unit = BaseUnit(unit.dimension, name, symbol) new_base_unit.define_conversion_factor_to(unit, factor) return new_base_unit elif isinstance(unit, ScaledUnit): # ScaledUnit version symbol = self.symbol + unit.symbol name = self.prefix + unit.name factor = self.factor * unit.factor # TODO - check for existing BaseUnit with same name, symbol, and factor return ScaledUnit(factor, unit.master, name, symbol) elif isinstance(unit, Unit): base_units = list(unit.iter_base_or_scaled_units()) if 1 != len(base_units): raise TypeError('Unit prefix "%s" can only be with simple Units containing one component.' % self.prefix) if 1 != base_units[0][1]: raise TypeError('Unit prefix "%s" can only be with simple Units with an exponent of 1.' % self.prefix) base_unit = base_units[0][0] # Delegate to Base or Scaled Unit multiply new_base_unit = self * base_unit new_unit = Unit({new_base_unit: 1.0}) return new_unit else: raise TypeError('Unit prefix "%s" can only be applied to a Unit, BaseUnit, or ScaledUnit.' % self.prefix)
def copy_stdqt_class(self, name, dstname): stdunit = BaseUnit('multicompress', 'StdQtStruct.h', self.config.root) cursor = stdunit.find_class_cursor(name) if not cursor: raise RuntimeError('cannot find class "{}" in file "{}"'.format( name, stdunit.filepath)) exists, target = util.find_or_insert(self.def_unit.cursor, CursorKind.CLASS_DECL, lambda c : self.is_cache_class(c.spelling), lambda c : c.spelling == dstname) if exists: print('Class "{}" already exists in file "{}" at line {}'.format( dstname, target.translation_unit.spelling, target.location.line )) else: util.copy_class(cursor, target.extent.end, dstname) return cursor
def create_unit(self, scale, name, symbol): """ Convenience method for creating a new simple unit from another simple unit. Both units must consist of a single BaseUnit. """ # TODO - also handle non-simple units, i.e. units with multiple BaseUnits/ScaledUnits assert len(self._top_base_units) == 1 assert len(self._scaled_units) == 0 dimension = self._top_base_units.iterkeys().next() base_unit_dict = self._top_base_units[dimension] assert len(base_unit_dict) == 1 parent_base_unit = base_unit_dict.iterkeys().next() parent_exponent = base_unit_dict[parent_base_unit] new_base_unit = BaseUnit(parent_base_unit.dimension, name, symbol) # BaseUnit scale might be different depending on exponent true_scale = scale if parent_exponent != 1.0: true_scale = math.pow(scale, 1.0/parent_exponent) new_base_unit.define_conversion_factor_to(parent_base_unit, true_scale) new_unit = Unit({new_base_unit: 1.0}) return new_unit
def add_notify_method(self, cache_class_name): method_name = 'Notify' result_type = 'void' args = [ ('const vector<SCltRegInfo> &', 'info') ] if self.config.notify.stockid: args.append(('const char *', 'stockID')) if self.config.notify.market: args.append(('unsigned short', 'marketID')) args.append(('const {} *'.format(cache_class_name), 'data')) args.append(('const {} *'.format(cache_class_name), 'old')) self.mcd_unit.add_method_declaration( 'CDataNotify', method_name, result_type, args, func_type = util.PURE_VIRTUAL ) unit = BaseUnit('multicachedata', 'notifytransfer.h', self.config.root) unit.add_method_declaration( 'CNotifyTransfrer', method_name, result_type, args, func_type = util.VIRTUAL )
def add_mds_staff(self, cache_class_name): ph_unit = BaseUnit('multidatasvr', 'process.h', self.config.root) pcpp_unit = BaseUnit('multidatasvr', 'process.cpp', self.config.root) if self.config.stock_data: macro_name = 'PACK_PC_STK_{}'.format(self.config.DATA_MODEL) else: macro_name = 'PACK_PC_{}'.format(self.config.DATA_MODEL) same, def_cursor = ph_unit.find_or_insert(CursorKind.MACRO_DEFINITION, lambda c : c.spelling.startswith('PACK_PC'), lambda c : c.spelling == macro_name ) if not same: # TODO: libclang does not find macro definition at now. last_macro = () # 4-elements tuple(line, length, name, value) pattern = re.compile(r'#define +(PACK_PC_\w+) +(\d+)') with open(ph_unit.filepath) as f: for i, line in enumerate(f): m = pattern.search(line) if m: last_macro = (i, m.group(1), m.group(2)) if m.group(2) == macro_name: break if last_macro[1] == macro_name: print('Macro "{}" is already there'.format(macro_name)) else: text = '#define {:<{}} {}'.format(macro_name, len(last_macro[1]), int(last_macro[2]) + 1) util.insert_after_line(ph_unit.filepath, last_macro[0] + 1, text) # add the case statement to process.cpp cursor = pcpp_unit.find(CursorKind.CXX_METHOD, lambda c : c.spelling == '_ProcReq') if cursor: for c in cursor.get_children(): if c.kind == CursorKind.COMPOUND_STMT: for c in cursor.get_children(): print(c.kind, c.spelling)
# needed for manipulation of units from prefix import * import math import sys ##################### ### DIMENSIONLESS ### ##################### # dimensionless = Unit({}); # defined in unit.py ############## ### LENGTH ### ############## meter_base_unit = BaseUnit(length_dimension, "meter", "m") meters = meter = Unit({meter_base_unit: 1.0}) define_prefixed_units(meter_base_unit, module=sys.modules[__name__]) angstrom_base_unit = BaseUnit(length_dimension, "angstrom", "A") angstrom_base_unit.define_conversion_factor_to(meter_base_unit, 1e-10) angstroms = angstrom = Unit({angstrom_base_unit: 1.0}) planck_length_base_unit = BaseUnit(length_dimension, "Planck length", "l_P") planck_length_base_unit.define_conversion_factor_to(meter_base_unit, 1.61625281e-35) inch_base_unit = BaseUnit(length_dimension, "inch", "in") inch_base_unit.define_conversion_factor_to(centimeter_base_unit, 2.5400) inch = inches = Unit({inch_base_unit: 1.0})
##################### ### DIMENSIONLESS ### ##################### # dimensionless = Unit({}); # defined in unit.py ############## ### LENGTH ### ############## meter_base_unit = BaseUnit(length_dimension, "meter", "m") meters = meter = Unit({meter_base_unit: 1.0}) define_prefixed_units(meter_base_unit, module = sys.modules[__name__]) angstrom_base_unit = BaseUnit(length_dimension, "angstrom", "A") angstrom_base_unit.define_conversion_factor_to(meter_base_unit, 1e-10) angstroms = angstrom = Unit({angstrom_base_unit: 1.0}) planck_length_base_unit = BaseUnit(length_dimension, "Planck length", "l_P") planck_length_base_unit.define_conversion_factor_to(meter_base_unit, 1.61625281e-35) inch_base_unit = BaseUnit(length_dimension, "inch", "in") inch_base_unit.define_conversion_factor_to(centimeter_base_unit, 2.5400) inch = inches = Unit({inch_base_unit: 1.0}) foot_base_unit = BaseUnit(length_dimension, "foot", "ft") foot_base_unit.define_conversion_factor_to(inch_base_unit, 12.0) foot = feet = Unit({foot_base_unit: 1.0}) yard_base_unit = BaseUnit(length_dimension, "yard", "yd")
def __init__(self, config = 'config'): self.config = importlib.import_module(config) self.def_unit = BaseUnit('multicachedata', 'stdstructdef.h', self.config.root) self.mcd_unit = BaseUnit('multicachedata', 'multicachedata.h', self.config.root)
class MultiCache(object): def __init__(self, config = 'config'): self.config = importlib.import_module(config) self.def_unit = BaseUnit('multicachedata', 'stdstructdef.h', self.config.root) self.mcd_unit = BaseUnit('multicachedata', 'multicachedata.h', self.config.root) def add_new_class(self, name): if name.startswith(self.config.STD_CLASS_PREFIX): cache_class_name = self.config.CACHE_CLASS_PREFIX + \ name[len(self.config.STD_CLASS_PREFIX):] srccursor = self.copy_stdqt_class(name, cache_class_name) self.add_to_embeded_class(srccursor, cache_class_name) self.add_notify_method(cache_class_name) self.add_mds_staff(cache_class_name) else: print('class name "{}" does not start with "{}"'.format(name, MultiCache.STD_CLASS_PREFIX)) def copy_stdqt_class(self, name, dstname): stdunit = BaseUnit('multicompress', 'StdQtStruct.h', self.config.root) cursor = stdunit.find_class_cursor(name) if not cursor: raise RuntimeError('cannot find class "{}" in file "{}"'.format( name, stdunit.filepath)) exists, target = util.find_or_insert(self.def_unit.cursor, CursorKind.CLASS_DECL, lambda c : self.is_cache_class(c.spelling), lambda c : c.spelling == dstname) if exists: print('Class "{}" already exists in file "{}" at line {}'.format( dstname, target.translation_unit.spelling, target.location.line )) else: util.copy_class(cursor, target.extent.end, dstname) return cursor def _add_reg_type(self): cursor = self.mcd_unit.find(CursorKind.ENUM_DECL, lambda c : c.spelling == 'DataModelType') if cursor: exist, pos = util.find_or_insert( cursor, CursorKind.ENUM_CONSTANT_DECL, lambda c : True, lambda c : c.spelling == self.config.REG_TYPE ) if not exist: util.insert_after_line(self.mcd_unit.filepath, pos.extent.end.line, util.INDENT + self.config.REG_TYPE + ',') else: print('Error: cannot find enum "{}" in file {}'.format( self.config.embed_class, self.mcd_unit.filepath) ) def add_to_embeded_class(self, srccursor, cache_class_name): impl_class = self.config.embed_impl[1] impl_header = BaseUnit('multicachedata', self.config.embed_impl[0]+ '.h', self.config.root) impl_cpp = BaseUnit('multicachedata', self.config.embed_impl[0]+ '.cpp', self.config.root) def add_convert_method(srccursor): method_name = 'Convert' result_type = 'void' args = [ ('const {} &'.format(srccursor.spelling), 'src'), ('{} &'.format(cache_class_name), 'dest') ] impl_header.add_method_declaration( impl_class, method_name, result_type, args ) body = '' for c in srccursor.get_children(): if c.kind == CursorKind.FIELD_DECL: body += util.INDENT if c.type.kind == TypeKind.CONSTANTARRAY: body += 'memcpy(dest.{0}, src.{0}, sizeof(dest.{0}));\n'.format(c.spelling) else: body += 'dest.{0} = src.{0};\n'.format(c.spelling) impl_cpp.add_method_definitaion( impl_class, method_name, result_type, args, body = body ) def add_update_method(data_type): method_name = 'Update' result_type = 'bool' args = [ ('const {} *'.format(data_type), 'data') ] impl_header.add_method_declaration( impl_class, method_name, result_type, args, func_type = True ) body = '' if self.config.embed_impl[0] == 'stddataunitimp': body = update_method_tmpl.render(indent = util.INDENT, cache_name = cache_class_name, reg_type = self.config.REG_TYPE, member = self.field_name(cache_class_name) ) impl_cpp.add_method_definitaion( impl_class, method_name, result_type, args, body = body) if not self.config.is_embeded: return cls_cursor = self.mcd_unit.find_class_cursor(self.config.embed_class) if not cls_cursor: print('Error: cannot find class "{}"'.format(self.config.embed_class)) return # Add field declaration into the embeded class exist, cursor = util.find_or_insert(cls_cursor, CursorKind.FIELD_DECL, lambda c : self.is_cache_class(c.type.spelling), lambda c : c.type.spelling == cache_class_name) if exist: print('Error: "{}" already has field "{}" of type "{}" at line {}'.format( self.config.embed_class, cursor.spelling, cache_class_name, cursor.location.line)) else: util.insert_after_line(self.mcd_unit.filepath, cursor.extent.end.line, util.INDENT + self.field_decl(cache_class_name)) self._add_reg_type() add_convert_method(srccursor) add_update_method(srccursor.spelling) def add_notify_method(self, cache_class_name): method_name = 'Notify' result_type = 'void' args = [ ('const vector<SCltRegInfo> &', 'info') ] if self.config.notify.stockid: args.append(('const char *', 'stockID')) if self.config.notify.market: args.append(('unsigned short', 'marketID')) args.append(('const {} *'.format(cache_class_name), 'data')) args.append(('const {} *'.format(cache_class_name), 'old')) self.mcd_unit.add_method_declaration( 'CDataNotify', method_name, result_type, args, func_type = util.PURE_VIRTUAL ) unit = BaseUnit('multicachedata', 'notifytransfer.h', self.config.root) unit.add_method_declaration( 'CNotifyTransfrer', method_name, result_type, args, func_type = util.VIRTUAL ) def add_mds_staff(self, cache_class_name): ph_unit = BaseUnit('multidatasvr', 'process.h', self.config.root) pcpp_unit = BaseUnit('multidatasvr', 'process.cpp', self.config.root) if self.config.stock_data: macro_name = 'PACK_PC_STK_{}'.format(self.config.DATA_MODEL) else: macro_name = 'PACK_PC_{}'.format(self.config.DATA_MODEL) same, def_cursor = ph_unit.find_or_insert(CursorKind.MACRO_DEFINITION, lambda c : c.spelling.startswith('PACK_PC'), lambda c : c.spelling == macro_name ) if not same: # TODO: libclang does not find macro definition at now. last_macro = () # 4-elements tuple(line, length, name, value) pattern = re.compile(r'#define +(PACK_PC_\w+) +(\d+)') with open(ph_unit.filepath) as f: for i, line in enumerate(f): m = pattern.search(line) if m: last_macro = (i, m.group(1), m.group(2)) if m.group(2) == macro_name: break if last_macro[1] == macro_name: print('Macro "{}" is already there'.format(macro_name)) else: text = '#define {:<{}} {}'.format(macro_name, len(last_macro[1]), int(last_macro[2]) + 1) util.insert_after_line(ph_unit.filepath, last_macro[0] + 1, text) # add the case statement to process.cpp cursor = pcpp_unit.find(CursorKind.CXX_METHOD, lambda c : c.spelling == '_ProcReq') if cursor: for c in cursor.get_children(): if c.kind == CursorKind.COMPOUND_STMT: for c in cursor.get_children(): print(c.kind, c.spelling) def field_decl(self, cache_class_name): return cache_class_name + ' ' + self.field_name(cache_class_name) + ';' def field_name(self, cache_class_name): name = cache_class_name[len(self.config.CACHE_CLASS_PREFIX):] return 'm_' + name[0].lower() + name[1:] def is_cache_class(self, class_name): return class_name.startswith(self.config.CACHE_CLASS_PREFIX)