blob: 7c658cfdacda4cd46d3f5aadb4a48724393dbe1b [file] [log] [blame]
// Copyright 2020 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
// This file provides the Detokenizer class, which is used to decode tokenized
// strings. To use a Detokenizer, load a binary format token database into
// memory, construct a TokenDatabase, and pass it to a Detokenizer:
//
// std::vector data = ReadFile("my_tokenized_strings.db");
// Detokenizer detok(TokenDatabase::Create(data));
//
// DetokenizedString result = detok.Detokenize(my_data);
// std::cout << result.BestString() << '\n';
//
#pragma once
#include <cstddef>
#include <cstdint>
#include <span>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "pw_tokenizer/internal/decode.h"
#include "pw_tokenizer/token_database.h"
namespace pw::tokenizer {
using TokenizedStringEntry = std::pair<FormatString, uint32_t /*date removed*/>;
// A string that has been detokenized. This class tracks all possible results if
// there are token collisions.
class DetokenizedString {
public:
DetokenizedString(uint32_t token,
const std::span<const TokenizedStringEntry>& entries,
const std::span<const uint8_t>& arguments);
DetokenizedString() : has_token_(false) {}
// True if there was only one valid match and it decoded successfully.
bool ok() const { return matches_.size() == 1 && matches_[0].ok(); }
// Returns the strings that matched the token, with the best matches first.
const std::vector<DecodedFormatString>& matches() const { return matches_; }
// Returns the detokenized string or an empty string if there were no matches.
// If there are multiple possible results, the DetokenizedString returns the
// first match.
std::string BestString() const;
// Returns the best match, with error messages inserted for arguments that
// failed to parse.
std::string BestStringWithErrors() const;
private:
uint32_t token_;
bool has_token_;
std::vector<DecodedFormatString> matches_;
};
// Decodes and detokenizes strings from a TokenDatabase. This class builds a
// hash table from the TokenDatabase to give O(1) token lookups.
class Detokenizer {
public:
// Constructs a detokenizer from a TokenDatabase. The TokenDatabase is not
// referenced by the Detokenizer after construction; its memory can be freed.
Detokenizer(const TokenDatabase& database);
// Decodes and detokenizes the encoded message. Returns a DetokenizedString
// that stores all possible detokenized string results.
DetokenizedString Detokenize(const std::span<const uint8_t>& encoded) const;
DetokenizedString Detokenize(const std::string_view& encoded) const {
return Detokenize(encoded.data(), encoded.size());
}
DetokenizedString Detokenize(const void* encoded, size_t size_bytes) const {
return Detokenize(
std::span(static_cast<const uint8_t*>(encoded), size_bytes));
}
private:
std::unordered_map<uint32_t, std::vector<TokenizedStringEntry>> database_;
};
} // namespace pw::tokenizer