Home | History | Annotate | Download | only in libpropertyinfoserializer
      1 //
      2 // Copyright (C) 2017 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "trie_builder.h"
     18 
     19 #include <android-base/strings.h>
     20 
     21 using android::base::Split;
     22 
     23 namespace android {
     24 namespace properties {
     25 
     26 TrieBuilder::TrieBuilder(const std::string& default_context, const std::string& default_type)
     27     : builder_root_("root") {
     28   auto* context_pointer = StringPointerFromContainer(default_context, &contexts_);
     29   builder_root_.set_context(context_pointer);
     30   auto* type_pointer = StringPointerFromContainer(default_type, &types_);
     31   builder_root_.set_type(type_pointer);
     32 }
     33 
     34 bool TrieBuilder::AddToTrie(const std::string& name, const std::string& context,
     35                             const std::string& type, bool exact, std::string* error) {
     36   auto* context_pointer = StringPointerFromContainer(context, &contexts_);
     37   auto* type_pointer = StringPointerFromContainer(type, &types_);
     38   return AddToTrie(name, context_pointer, type_pointer, exact, error);
     39 }
     40 
     41 bool TrieBuilder::AddToTrie(const std::string& name, const std::string* context,
     42                             const std::string* type, bool exact, std::string* error) {
     43   TrieBuilderNode* current_node = &builder_root_;
     44 
     45   auto name_pieces = Split(name, ".");
     46 
     47   bool ends_with_dot = false;
     48   if (name_pieces.back().empty()) {
     49     ends_with_dot = true;
     50     name_pieces.pop_back();
     51   }
     52 
     53   // Move us to the final node that we care about, adding incremental nodes if necessary.
     54   while (name_pieces.size() > 1) {
     55     auto child = current_node->FindChild(name_pieces.front());
     56     if (child == nullptr) {
     57       child = current_node->AddChild(name_pieces.front());
     58     }
     59     if (child == nullptr) {
     60       *error = "Unable to allocate Trie node";
     61       return false;
     62     }
     63     current_node = child;
     64     name_pieces.erase(name_pieces.begin());
     65   }
     66 
     67   // Store our context based on what type of match it is.
     68   if (exact) {
     69     if (!current_node->AddExactMatchContext(name_pieces.front(), context, type)) {
     70       *error = "Duplicate exact match detected for '" + name + "'";
     71       return false;
     72     }
     73   } else if (!ends_with_dot) {
     74     if (!current_node->AddPrefixContext(name_pieces.front(), context, type)) {
     75       *error = "Duplicate prefix match detected for '" + name + "'";
     76       return false;
     77     }
     78   } else {
     79     auto child = current_node->FindChild(name_pieces.front());
     80     if (child == nullptr) {
     81       child = current_node->AddChild(name_pieces.front());
     82     }
     83     if (child == nullptr) {
     84       *error = "Unable to allocate Trie node";
     85       return false;
     86     }
     87     if (child->context() != nullptr || child->type() != nullptr) {
     88       *error = "Duplicate prefix match detected for '" + name + "'";
     89       return false;
     90     }
     91     child->set_context(context);
     92     child->set_type(type);
     93   }
     94   return true;
     95 }
     96 
     97 const std::string* TrieBuilder::StringPointerFromContainer(const std::string& string,
     98                                                            std::set<std::string>* container) {
     99   // Get a pointer to the string in a given set, such that we only ever serialize each string once.
    100   auto [iterator, _] = container->emplace(string);
    101   return &(*iterator);
    102 }
    103 
    104 }  // namespace properties
    105 }  // namespace android
    106