| // Copyright 2017-2020 The Verible 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 |
| // |
| // http://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. |
| |
| #ifndef VERIBLE_COMMON_STRINGS_DISPLAY_UTILS_H_ |
| #define VERIBLE_COMMON_STRINGS_DISPLAY_UTILS_H_ |
| |
| #include <iosfwd> |
| |
| #include "absl/strings/str_join.h" |
| #include "absl/strings/string_view.h" |
| |
| namespace verible { |
| |
| // Stream printable object that limits the length of text printed. |
| // Applications: debugging potentially long strings, where only the head and |
| // tail are sufficient to comprehend the text being referenced. |
| // |
| // usage: stream << AutoTruncate{text, limit}; |
| // |
| // example output (limit: 9): "abc...xyz" |
| struct AutoTruncate { |
| const absl::string_view text; |
| // Maximum number of characters to show, including "..." |
| const int max_chars; |
| }; |
| |
| std::ostream& operator<<(std::ostream&, const AutoTruncate& trunc); |
| |
| // To help visualize strings with non-alphanumeric characters, this stream |
| // adapter prints special characters escaped using C escape sequences, without |
| // modifying or copying the original string. |
| // |
| // usage: stream << EscapeString(text); |
| struct EscapeString { |
| const absl::string_view text; // original text to be printed |
| |
| explicit EscapeString(absl::string_view text) : text(text) {} |
| }; |
| |
| std::ostream& operator<<(std::ostream&, const EscapeString& vis); |
| |
| // To help visualize strings that consist of whitespace, this stream adapter |
| // prints spaces, tabs, and newlines with alternate text, without modifying or |
| // copying the original string. |
| // |
| // usage: stream << VisualizeWhitespace(text_with_lots_of_spaces); |
| struct VisualizeWhitespace { |
| const absl::string_view text; // original text to be printed |
| |
| const char space_alt; // spaces replacement |
| const absl::string_view newline_alt; // newline replacement |
| const absl::string_view tab_alt; // tab replacement |
| |
| // constructor needed for C++11 |
| explicit VisualizeWhitespace(absl::string_view text, char space_alt = '.', |
| absl::string_view newline_alt = "\\\n", |
| absl::string_view tab_alt = "#") |
| : text(text), |
| space_alt(space_alt), |
| newline_alt(newline_alt), |
| tab_alt(tab_alt) {} |
| }; |
| |
| std::ostream& operator<<(std::ostream&, const VisualizeWhitespace& vis); |
| |
| // TODO(fangism): once C++17 becomes the minimum standard for building |
| // push the following block into an internal namespace, and use auto |
| // return types instead of directly naming these types. |
| // namespace internal { |
| |
| // Helper struct for bundling parameters to absl::StrJoin. |
| // This is useful for contructing printer adapters for types that |
| // are typedefs/aliases of standard containers, and not their own class. |
| // For example, not every std::vector<int> wants to be formatted the same way. |
| // Be careful not to define std::ostream& operator<< for such types, as you |
| // accidentally create conflicting definitions, and violate ODR. |
| template <class T> |
| struct SequenceStreamFormatter { |
| const T& sequence; // binds to object that is to be printed |
| absl::string_view separator; |
| absl::string_view prefix; |
| absl::string_view suffix; |
| // TODO(fangism): pass in custom formatter object, and be able to nest |
| // multiple levels of formatters. |
| }; |
| |
| // Redirects stream printing to abs::StrJoin wrapped in a single object. |
| template <class T> |
| std::ostream& operator<<(std::ostream& stream, |
| const SequenceStreamFormatter<T>& t) { |
| return stream << t.prefix |
| << absl::StrJoin(t.sequence.begin(), t.sequence.end(), |
| t.separator, absl::StreamFormatter()) |
| << t.suffix; |
| } |
| |
| // } // namespace internal |
| |
| // SequenceFormatter helps create custom formatters (pretty-printers) for |
| // standard container types, when providing a plain std::ostream& operator<< |
| // overload would be ill-advised. |
| // This is the next best alternative, even if it requires the caller to wrap |
| // plain container objects. |
| // |
| // Example usage (define the following for your specific container type): |
| // Suppose MySequenceType is a typedef to a container like std::list<int>. |
| // Define a forwarding function: |
| // |
| // [pre C++17] |
| // SequenceStreamFormatter<MySequenceType> MySequenceFormatter( |
| // const MySequenceType& t) { |
| // return verible::SequenceFormatter(t, " | ", "< ", " >"); |
| // } |
| // |
| // [C++17 and higher, supporting auto return type]: |
| // auto MySequenceFormatter(const MySequenceType& t) { |
| // return verible::SequenceFormatter(t, " | ", "< ", " >"); |
| // } |
| // |
| // and call it: |
| // stream << MySequenceFormatter(sequence_obj) << ...; |
| // |
| // to consistently produce text like: |
| // "< 1 | 2 | 3 | ... >" |
| // |
| template <class T> |
| SequenceStreamFormatter<T> SequenceFormatter(const T& t, |
| absl::string_view sep = ", ", |
| absl::string_view prefix = "", |
| absl::string_view suffix = "") { |
| return SequenceStreamFormatter<T>{t, sep, prefix, suffix}; |
| } |
| |
| } // namespace verible |
| |
| #endif // VERIBLE_COMMON_STRINGS_DISPLAY_UTILS_H_ |