예제 #1
0
void ComponentStorage::createTypeInfo(TypeIndex typeIndex, 
                                  void* storedSingleton, 
                                  void (*destroy)(void*)) {
  auto itr = typeRegistry.find(typeIndex);
  if (itr == typeRegistry.end()) {
    // This type wasn't registered yet, register it.
    TypeInfo& typeInfo = typeRegistry[typeIndex];
    typeInfo.storedSingleton = storedSingleton;
    typeInfo.destroy = destroy;
  } else {
    // This type was already registered.
    TypeInfo& ourInfo = itr->second;
    check(ourInfo.storedSingleton != nullptr, [=](){ return multipleBindingsError(typeIndex); });
    // At this point it's guaranteed that ourInfo.storedSingleton!=nullptr.
    // If the stored singletons and destroy operations are equal ok, but if they aren't we
    // can't be sure that they're equivalent and we abort.
    bool equal = ourInfo.storedSingleton == storedSingleton
      && ourInfo.destroy == destroy;
    check(equal, [=](){ return multipleBindingsError(typeIndex); });
  }
}
예제 #2
0
void ComponentStorage::createTypeInfo(TypeIndex typeIndex, 
                                  std::pair<void*, void(*)(void*)> (*create)(ComponentStorage&, void*), 
                                  void* createArgument) {
  auto itr = typeRegistry.find(typeIndex);
  if (itr == typeRegistry.end()) {
    // This type wasn't registered yet, register it.
    TypeInfo& typeInfo = typeRegistry[typeIndex];
    typeInfo.create = create;
    typeInfo.createArgument = createArgument;
    typeInfo.storedSingleton = nullptr;
  } else {
    // This type was already registered.
    TypeInfo& ourInfo = itr->second;
    check(ourInfo.storedSingleton == nullptr, [=](){ return multipleBindingsError(typeIndex); });
    // At this point it's guaranteed that ourInfo.storedSingleton==nullptr.
    // If the create operations and arguments are equal ok, but if they aren't we
    // can't be sure that they're equivalent and we abort.
    bool equal = ourInfo.create == create && ourInfo.createArgument == createArgument;
    check(equal, [=](){ return multipleBindingsError(typeIndex); });
  }
}
예제 #3
0
void InjectorStorage::normalizeBindings(std::vector<std::pair<TypeId, BindingData>>& bindings_vector,
                                        FixedSizeAllocator::FixedSizeAllocatorData& fixed_size_allocator_data,
                                        std::vector<CompressedBinding>&& compressed_bindings_vector,
                                        const std::vector<std::pair<TypeId, MultibindingData>>& multibindings_vector,
                                        const std::vector<TypeId>& exposed_types,
                                        BindingCompressionInfoMap& bindingCompressionInfoMap) {
  std::unordered_map<TypeId, BindingData> binding_data_map;
  
  for (auto& p : bindings_vector) {
    auto itr = binding_data_map.find(p.first);
    if (itr != binding_data_map.end()) {
      if (!(p.second == itr->second)) {
        std::cerr << multipleBindingsError(p.first) << std::endl;
        exit(1);
      }
      // Otherwise ok, duplicate but consistent binding.
      
    } else {
      // New binding, add it to the map.
      binding_data_map[p.first] = p.second;
    }
  }
  
  for (const auto& p : bindings_vector) {
    if (p.second.needsAllocation()) {
      fixed_size_allocator_data.addType(p.first);
    } else {
      fixed_size_allocator_data.addExternallyAllocatedType(p.first);
    }
  }
  
  // Remove duplicates from `compressedBindingsVector'.
  
  // CtypeId -> (ItypeId, bindingData)
  std::unordered_map<TypeId, std::pair<TypeId, BindingData>> compressed_bindings_map;
  
  // This also removes any duplicates. No need to check for multiple I->C, I2->C mappings, will filter these out later when 
  // considering deps.
  for (CompressedBinding& compressed_binding : compressed_bindings_vector) {
    compressed_bindings_map[compressed_binding.class_id] = {compressed_binding.interface_id, compressed_binding.binding_data};
  }
  
  // We can't compress the binding if C is a dep of a multibinding.
  for (auto p : multibindings_vector) {
    const BindingDeps* deps = p.second.deps;
    if (deps != nullptr) {
      for (std::size_t i = 0; i < deps->num_deps; ++i) {
        compressed_bindings_map.erase(deps->deps[i]);
      }
    }
  }
  
  // We can't compress the binding if C is an exposed type (but I is likely to be exposed instead).
  for (TypeId type : exposed_types) {
    compressed_bindings_map.erase(type);
  }
  
  // We can't compress the binding if some type X depends on C and X!=I.
  for (auto& p : binding_data_map) {
    TypeId x_id = p.first;
    BindingData binding_data = p.second;
    if (!binding_data.isCreated()) {
      for (std::size_t i = 0; i < binding_data.getDeps()->num_deps; ++i) {
        TypeId c_id = binding_data.getDeps()->deps[i];
        auto itr = compressed_bindings_map.find(c_id);
        if (itr != compressed_bindings_map.end() && itr->second.first != x_id) {
          compressed_bindings_map.erase(itr);
        }
      }
    }
  }
  
  // Two pairs of compressible bindings (I->C) and (C->X) can not exist (the C of a compressible binding is always bound either
  // using constructor binding or provider binding, it can't be a binding itself). So no need to check for that.
  
  // Now perform the binding compression.
  for (auto& p : compressed_bindings_map) {
    TypeId c_id = p.first;
    TypeId i_id = p.second.first;
    BindingData binding_data = p.second.second;
    auto i_binding_data = binding_data_map.find(i_id);
    auto c_binding_data = binding_data_map.find(c_id);
    assert(i_binding_data != binding_data_map.end());
    assert(c_binding_data != binding_data_map.end());
    bindingCompressionInfoMap[c_id] = BindingCompressionInfo{i_id, i_binding_data->second, c_binding_data->second};
    // Note that even if I is the one that remains, C is the one that will be allocated, not I.
    assert(!i_binding_data->second.needsAllocation());
    i_binding_data->second = binding_data;
    binding_data_map.erase(c_binding_data);
#ifdef FRUIT_EXTRA_DEBUG
    std::cout << "InjectorStorage: performing binding compression for the edge " << i_id << "->" << c_id << std::endl;
#endif
  }
  
  // Copy the resulting bindings back into the vector.
  bindings_vector.clear();
  for (auto& p : binding_data_map) {
    bindings_vector.push_back(p);
  }
}
예제 #4
0
InjectorStorage::InjectorStorage(const NormalizedComponentStorage& normalized_component,
                                 ComponentStorage&& component,
                                 std::vector<TypeId>&& exposed_types)
  : multibindings(normalized_component.multibindings) {

  FixedSizeAllocator::FixedSizeAllocatorData fixed_size_allocator_data = normalized_component.fixed_size_allocator_data;
  
  std::vector<std::pair<TypeId, BindingData>> component_bindings(std::move(component.bindings));
  
  // Step 1: Remove duplicates among the new bindings, and check for inconsistent bindings within `component' alone.
  // Note that we do NOT use component.compressed_bindings here, to avoid having to check if these compressions can be undone.
  // We don't expect many binding compressions here that weren't already performed in the normalized component.
  BindingCompressionInfoMap bindingCompressionInfoMapUnused;
  normalizeBindings(component_bindings,
                    fixed_size_allocator_data,
                    std::vector<CompressedBinding>{},
                    component.multibindings,
                    std::move(exposed_types),
                    bindingCompressionInfoMapUnused);
  assert(bindingCompressionInfoMapUnused.empty());
  
  std::unordered_set<TypeId> binding_compressions_to_undo;
  
  // Step 2: Filter out already-present bindings, and check for inconsistent bindings between `normalizedComponent' and
  // `component'. Also determine what binding compressions must be undone
  auto itr = std::remove_if(component_bindings.begin(), component_bindings.end(),
                            [&normalized_component, &binding_compressions_to_undo](const std::pair<TypeId, BindingData>& p) {
                              if (!p.second.isCreated()) {
                                for (std::size_t i = 0; i < p.second.getDeps()->num_deps; ++i) {
                                  auto binding_compression_itr = 
                                      normalized_component.bindingCompressionInfoMap.find(p.second.getDeps()->deps[i]);
                                  if (binding_compression_itr != normalized_component.bindingCompressionInfoMap.end()
                                      && binding_compression_itr->second.iTypeId != p.first) {
                                    // The binding compression for `p.second.getDeps()->deps[i]' must be undone because something
                                    // different from binding_compression_itr->iTypeId is now bound to it.
                                    binding_compressions_to_undo.insert(p.second.getDeps()->deps[i]);
                                  }
                                }
                              }
                              auto node_itr = normalized_component.bindings.find(p.first);
                              if (node_itr == normalized_component.bindings.end()) {
                                // Not bound yet, keep the new binding.
                                return false;
                              }
                              if (!(node_itr.getNode() == NormalizedBindingData(p.second))) {
                                std::cerr << multipleBindingsError(p.first) << std::endl;
                                exit(1);
                              }
                              // Already bound in the same way. Skip the new binding.
                              return true;
                            });
  component_bindings.erase(itr, component_bindings.end());
  
  // Step 3: undo any binding compressions that can no longer be applied.
  for (TypeId cTypeId : binding_compressions_to_undo) {
    auto binding_compression_itr = normalized_component.bindingCompressionInfoMap.find(cTypeId);
    assert(binding_compression_itr != normalized_component.bindingCompressionInfoMap.end());
    assert(!binding_compression_itr->second.iBinding.needsAllocation());
    component_bindings.emplace_back(cTypeId, binding_compression_itr->second.cBinding);
    // This TypeId is already in normalized_component.bindings, we overwrite it here.
    assert(!(normalized_component.bindings.find(binding_compression_itr->second.iTypeId) == normalized_component.bindings.end()));
    component_bindings.emplace_back(binding_compression_itr->second.iTypeId, binding_compression_itr->second.iBinding);
#ifdef FRUIT_EXTRA_DEBUG
    std::cout << "InjectorStorage: undoing binding compression for: " << binding_compression_itr->second.iTypeId << "->" << cTypeId << std::endl;  
#endif
  }
  
  bindings = Graph(normalized_component.bindings,
                   BindingDataNodeIter{component_bindings.begin()},
                   BindingDataNodeIter{component_bindings.end()});
  
  // Step 4: Add multibindings.
  addMultibindings(multibindings, fixed_size_allocator_data, std::move(component.multibindings));
  
  allocator = FixedSizeAllocator(fixed_size_allocator_data);
  
#ifdef FRUIT_EXTRA_DEBUG
  bindings.checkFullyConstructed();
#endif
}