| Index: net/tools/domain_security_preload_generator/huffman/huffman_frequency_tracker.cc | 
| diff --git a/net/tools/domain_security_preload_generator/huffman/huffman_frequency_tracker.cc b/net/tools/domain_security_preload_generator/huffman/huffman_frequency_tracker.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..f2e68b7c3ef957774d6d6753c52caff0240fe036 | 
| --- /dev/null | 
| +++ b/net/tools/domain_security_preload_generator/huffman/huffman_frequency_tracker.cc | 
| @@ -0,0 +1,159 @@ | 
| +// Copyright (c) 2016 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "net/tools/domain_security_preload_generator/huffman/huffman_frequency_tracker.h" | 
| + | 
| +#include <algorithm> | 
| + | 
| +#include "base/logging.h" | 
| + | 
| +namespace net { | 
| + | 
| +namespace transport_security_state { | 
| + | 
| +namespace { | 
| + | 
| +class HuffmanNode { | 
| + public: | 
| +  HuffmanNode(uint8_t value, | 
| +              uint32_t count, | 
| +              std::unique_ptr<HuffmanNode> left, | 
| +              std::unique_ptr<HuffmanNode> right) | 
| +      : value_(value), | 
| +        count_(count), | 
| +        left_(std::move(left)), | 
| +        right_(std::move(right)) {} | 
| +  ~HuffmanNode() {} | 
| + | 
| +  bool IsLeaf() const { | 
| +    return left_.get() == nullptr && right_.get() == nullptr; | 
| +  } | 
| + | 
| +  uint8_t value() const { return value_; } | 
| +  uint32_t count() const { return count_; } | 
| +  const std::unique_ptr<HuffmanNode>& left() const { return left_; } | 
| +  const std::unique_ptr<HuffmanNode>& right() const { return right_; } | 
| + | 
| + private: | 
| +  uint8_t value_; | 
| +  uint32_t count_; | 
| +  std::unique_ptr<HuffmanNode> left_; | 
| +  std::unique_ptr<HuffmanNode> right_; | 
| +}; | 
| + | 
| +bool CompareNodes(const std::unique_ptr<HuffmanNode>& lhs, | 
| +                  const std::unique_ptr<HuffmanNode>& rhs) { | 
| +  return lhs->count() < rhs->count(); | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +HuffmanFrequencyTracker::HuffmanFrequencyTracker() {} | 
| + | 
| +HuffmanFrequencyTracker::~HuffmanFrequencyTracker() {} | 
| + | 
| +void HuffmanFrequencyTracker::RecordUsage(uint8_t character) { | 
| +  counts_[character] += 1; | 
| +} | 
| + | 
| +HuffmanRepresentationTable HuffmanFrequencyTracker::ToTable() { | 
| +  HuffmanRepresentationTable table; | 
| +  std::unique_ptr<HuffmanNode> node(BuildTree()); | 
| + | 
| +  TreeToTable(node.get(), 0, 0, &table); | 
| +  return table; | 
| +} | 
| + | 
| +void HuffmanFrequencyTracker::TreeToTable(HuffmanNode* node, | 
| +                                          uint32_t bits, | 
| +                                          uint32_t number_of_bits, | 
| +                                          HuffmanRepresentationTable* table) { | 
| +  if (node->IsLeaf()) { | 
| +    HuffmanRepresentation item; | 
| +    item.bits = bits; | 
| +    item.number_of_bits = number_of_bits; | 
| + | 
| +    table->insert(HuffmanRepresentationPair(node->value(), item)); | 
| +  } else { | 
| +    uint32_t new_bits = bits << 1; | 
| +    TreeToTable(node->left().get(), new_bits, number_of_bits + 1, table); | 
| +    TreeToTable(node->right().get(), new_bits | 1, number_of_bits + 1, table); | 
| +  } | 
| +} | 
| + | 
| +std::vector<uint8_t> HuffmanFrequencyTracker::ToVector() { | 
| +  std::vector<uint8_t> bytes; | 
| +  std::unique_ptr<HuffmanNode> node(BuildTree()); | 
| +  WriteToVector(node.get(), &bytes); | 
| +  return bytes; | 
| +} | 
| + | 
| +uint32_t HuffmanFrequencyTracker::WriteToVector(HuffmanNode* node, | 
| +                                                std::vector<uint8_t>* vector) { | 
| +  uint8_t left_value; | 
| +  uint8_t right_value; | 
| +  uint32_t child_position; | 
| + | 
| +  if (node->left()->IsLeaf()) { | 
| +    left_value = 128 | node->left()->value(); | 
| +  } else { | 
| +    child_position = WriteToVector(node->left().get(), vector); | 
| +    CHECK(child_position < 512) << "huffman tree too large"; | 
| +    left_value = child_position / 2; | 
| +  } | 
| + | 
| +  if (node->right()->IsLeaf()) { | 
| +    right_value = 128 | node->right()->value(); | 
| +  } else { | 
| +    child_position = WriteToVector(node->right().get(), vector); | 
| +    CHECK(child_position < 512) << "huffman tree to large"; | 
| +    right_value = child_position / 2; | 
| +  } | 
| + | 
| +  uint32_t position = static_cast<uint32_t>(vector->size()); | 
| +  vector->push_back(left_value); | 
| +  vector->push_back(right_value); | 
| +  return position; | 
| +} | 
| + | 
| +std::unique_ptr<HuffmanNode> HuffmanFrequencyTracker::BuildTree() { | 
| +  std::vector<std::unique_ptr<HuffmanNode>> nodes; | 
| +  nodes.reserve(counts_.size()); | 
| + | 
| +  for (const auto& item : counts_) { | 
| +    if (item.second > 0) { | 
| +      std::unique_ptr<HuffmanNode> node( | 
| +          new HuffmanNode(item.first, item.second, nullptr, nullptr)); | 
| +      nodes.push_back(std::move(node)); | 
| +    } | 
| +  } | 
| + | 
| +  if (nodes.size() < 2) { | 
| +    return std::move(nodes[0]); | 
| +  } | 
| + | 
| +  std::stable_sort(nodes.begin(), nodes.end(), CompareNodes); | 
| + | 
| +  while (nodes.size() > 1) { | 
| +    std::unique_ptr<HuffmanNode> a = std::move(nodes[0]); | 
| +    std::unique_ptr<HuffmanNode> b = std::move(nodes[1]); | 
| + | 
| +    uint32_t count_a = a->count(); | 
| +    uint32_t count_b = b->count(); | 
| + | 
| +    std::unique_ptr<HuffmanNode> parent( | 
| +        new HuffmanNode(0, count_a + count_b, std::move(a), std::move(b))); | 
| + | 
| +    nodes.erase(nodes.begin()); | 
| +    nodes[0] = std::move(parent); | 
| + | 
| +    std::stable_sort(nodes.begin(), nodes.end(), CompareNodes); | 
| +  } | 
| + | 
| +  return std::move(nodes[0]); | 
| +} | 
| + | 
| +}  // namespace transport_security_state | 
| + | 
| +}  // namespace net | 
|  |