Skip to content

Commit

Permalink
Errata: fix is_ok
Browse files Browse the repository at this point in the history
  • Loading branch information
SolidWallOfCode committed Nov 27, 2023
1 parent 172f8f9 commit 1c7af86
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 95 deletions.
12 changes: 6 additions & 6 deletions code/include/swoc/Errata.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,10 +504,7 @@ class Errata {
bool is_ok() const;

/// @return If there is top level severity.
bool
has_severity() const {
return _data && _data->_severity.has_value();
}
bool has_severity() const;

/// @return Top level severity.
Severity severity() const;
Expand Down Expand Up @@ -1124,9 +1121,12 @@ Errata::assign(code_type code) -> self_type & {
return *this;
}

inline bool Errata::has_severity() const {
return _data && _data->_severity.has_value();
}
inline auto
Errata::severity() const -> Severity {
return _data ? _data->_severity.value() : DEFAULT_SEVERITY;
return this->has_severity() ? _data->_severity.value() : DEFAULT_SEVERITY;
}

inline auto
Expand All @@ -1142,7 +1142,7 @@ Errata::length() const {

inline bool
Errata::is_ok() const {
return this->empty() || _data->_severity < FAILURE_SEVERITY;
return nullptr == _data || this->severity() < FAILURE_SEVERITY;
}

inline const Errata::Annotation &
Expand Down
58 changes: 58 additions & 0 deletions code/include/swoc/swoc_meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,62 @@ template <typename... Types> struct type_list {
template <typename T> static constexpr bool contains = is_any_of<T, Types...>::value;
};

/** Scoped value change.
*
* The purpose of this class is to change the value of a variable in a scope and then change it
* back when the scope is exited. The old value will be moved to a cache variable and then moved
* back when the instance is destructed. This is very useful to temporarily tweak global variables
* which having to know what the current value is.
*
* @code
* {
* let save(var, value);
* // var now has value.
* }
* // var now has original value.
* @endcode
*
* @tparam T Type of variable to scope.
*/
template <typename T> struct let {
using self_type = let;

let(self_type const& that) = delete;
self_type & operator = (self_type const&) = delete;

T &_var; ///< Reference to scoped variable.
T _value; ///< Original value.

/** Construct a scope.
*
* @param var Variable to scope.
* @param value temporary value to assign.
*/
let(T &var, T const &value);

/** Construct a scope.
*
* @param var Variable to scope.
* @param value temporary value to assign.
*/
let(T &var, T &&value);

~let();
};

template <typename T> let<T>::let(T &var, T const &value) : _var(var), _value(std::move(var))
{
_var = value;
}
template <typename T> let<T>::let(T &var, T &&value) : _var(var), _value(std::move(var))
{
_var = std::move(value);
}

template <typename T> let<T>::~let()
{
_var = std::move(_value);
}


}}} // namespace swoc::SWOC_VERSION_NS::meta
31 changes: 27 additions & 4 deletions doc/code/TextView.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ E.g. the code to write a simple hash function [#]_ could be
return hash;
}
Although alternatively, this can be done in a non-modifying way.

.. code-block:: cpp
void hasher(TextView v) {
size_t hash = 0;
for ( auto c : v) {
hash = hash * 13 + c;
}
return hash;
}
Because |TV| inherits from :code:`std::string_view` it can also be used as a container for range
:code:`for` loops.

Expand All @@ -97,10 +109,21 @@ Because |TV| inherits from :code:`std::string_view` it can also be used as a con
return hash;
}
The first approach enables dropping out of the loop on some condition with the view updated to
no longer contain processed characters, making restart or other processing simple.

The standard functions :code:`strcmp`, :code:`memcmp`, code:`memcpy`, and :code:`strcasecmp` are
overloaded for |TV| so that a |TV| can be used as if it were a C-style string. The size is is taken
from the |TV| and doesn't need to be passed in explicitly.

.. class:: CharSet

:libswoc:`Reference documentation <swoc::CharSet>`.

This is a simple class that contains a set of characters. This is intended primarily to make
parsing faster and simpler. Rather than checking a list of delimiters the character can be checked
with a single `std::bitset` lookup.

Basic Operations
================

Expand Down Expand Up @@ -130,7 +153,7 @@ Searching
---------

Because |TV| is a subclass of :code:`std::string_view` all of its search method work on a |TV|. The
only search methods provided beyond those are :libswoc:`TextView::find_if` and
only search methods provided beyond those in :code:`std::string` are :libswoc:`TextView::find_if` and
:libswoc:`TextView::rfind_if` which search the view by a predicate. The predicate takes a single
:code:`char` argument and returns a :code:`bool`. The search terminates on the first character for
which the predicate returns :code:`true`.
Expand Down Expand Up @@ -281,12 +304,12 @@ developing |TV| parsing.

The first was to minimize the need to allocate memory to hold intermediate results. For this reason, the normal
style of use is a streaming / incremental one, where tokens are extracted from a source one by one
and placed in |TV| instances, with the orignal source |TV| being reduced by each extraction until
and placed in |TV| instances, with the original source |TV| being reduced by each extraction until
it is empty.

The second was to minimize cut and paste coding. Typical C or C++ parsing logic consists mostly of
very generic code to handle pointer and size updates. The point of |TV| is to automate all of that
so the resulting code is focused entirely on the parsing logic, not boiler plate string or view manipulation.
yielding code focused entirely on the parsing logic, not boiler plate string or view manipulation.
It is a common occurrence to not get such code exactly correct leading to hard to track bugs. Use
of |TV| eliminates those problems.

Expand All @@ -313,7 +336,7 @@ are very cheap to copy. This is essentially the same as having a current pointer
and checking for :code:`current >= end` except :code:`TextView` does all the work, leading to
simpler and less buggy code.

White space is dropped because of the calls to :code:`ltrim_if` and `rtrim_if`. By calling in the
White space is dropped because of the calls to :code:`ltrim_if` and :code:`rtrim_if`. By calling in the
loop condition, the loop exits if the remaining text is only whitespace and no token is processed.
Alternatively :code:`trim_if` could be used after extraction. The performance will be *slightly*
better because although :code:`trim_if` calls :code:`ltrim_if` and :code:`rtrim_if`, a final
Expand Down
13 changes: 10 additions & 3 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,16 @@ Solid Wall of C++
*****************

The Solid Wall of C++ library is a collection of C++ classes and utilities. This code evolved out of
infrastructure used in `Apache Traffic Server <https://trafficserver.apache.org>`__. The utilities
had become useful enough there were requests to be able to use them in ATS plugins and other,
unrelated projects. Hence this library. I hope you find it as useful as I have.
infrastructure used in `Apache Traffic Server <https://trafficserver.apache.org>`__ as I strove to combine
functionality, ease of use, and performance.
The utilities had become useful enough there were requests to be able to use them in ATS plugins and other,
unrelated projects. Hence this library. After much production use, this library has been imported back
in to Traffic Server and can be used there in the core or any plugin.
I hope you find it as useful as I have.

Most of the library is dedicated to convenience, such as :class:`TextView` which provides Python like
string manipulation on top of :code:`std::string_view`, and performance, such as :class:`IPSpace` which
enables very fast IP address range storage.

.. toctree::
:maxdepth: 1
Expand Down
82 changes: 0 additions & 82 deletions tools/ats-drop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ else
mkdir -p ${TARGET_SRC_DIR}
fi

cp code/CMakeLists.txt ${TARGET_BASE_DIR}/swoc
(cd ${ATS}/${BASE_PATH}/swoc ; sed -i -e '/^if (LIBSWOC_INSTALL)/,/^endif/d' CMakeLists.txt ; git add CMakeLists.txt)

cp code/src/*.cc ${TARGET_SRC_DIR}
(cd ${ATS}; git add ${BASE_PATH}/swoc/CMakeLists.txt ; git add ${SRC_PATH}/*.cc)

Expand All @@ -48,82 +45,3 @@ cp code/include/swoc/*.h ${TARGET_INC_DIR}
cp code/include/swoc/ext/*.h ${TARGET_INC_DIR}/ext
cp code/include/swoc/ext/HashFNV.h ${TARGET_INC_DIR}
(cd ${ATS}; git add ${INC_PATH}/*.h ; git add ${INC_PATH}/ext/*.h)

# Build the source
cat <<'TEXT' > ${ATS}/${BASE_PATH}/swoc/Makefile.am
# swoc Makefile.am
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
lib_LTLIBRARIES = libtsswoc.la
library_includedir=$(includedir)/swoc
AM_CPPFLAGS += @SWOC_INCLUDES@
libtsswoc_la_LDFLAGS = @AM_LDFLAGS@ -no-undefined -release 1.5.8
libtsswoc_la_SOURCES = \
src/ArenaWriter.cc src/bw_format.cc src/bw_ip_format.cc src/Errata.cc src/MemArena.cc src/RBTree.cc src/swoc_file.cc src/swoc_ip.cc src/TextView.cc src/string_view_util.cc
if EXPORT_SWOC_HEADERS
library_include_HEADERS = \
include/swoc/ArenaWriter.h \
include/swoc/BufferWriter.h \
include/swoc/bwf_base.h \
include/swoc/bwf_ex.h \
include/swoc/bwf_fwd.h \
include/swoc/bwf_ip.h \
include/swoc/bwf_std.h \
include/swoc/DiscreteRange.h \
include/swoc/Errata.h \
include/swoc/IntrusiveDList.h \
include/swoc/IntrusiveHashMap.h \
include/swoc/IPAddr.h \
include/swoc/IPEndpoint.h \
include/swoc/IPRange.h \
include/swoc/IPSrv.h \
include/swoc/Lexicon.h \
include/swoc/MemArena.h \
include/swoc/MemSpan.h \
include/swoc/RBTree.h \
include/swoc/Scalar.h \
include/swoc/swoc_file.h \
include/swoc/swoc_ip.h \
include/swoc/swoc_meta.h \
include/swoc/swoc_version.h\
include/swoc/string_view_util.h \
include/swoc/TextView.h \
include/swoc/Vectray.h \
include/swoc/HashFNV.h
endif
clean-local:
clang-tidy-local: $(DIST_SOURCES)
$(CXX_Clang_Tidy)
TEXT
(cd ${ATS} ; git add ${BASE_PATH}/swoc/Makefile.am)

if ! grep -q swoc ${ATS}/configure.ac ; then
sed -i -e 's!lib/yamlcpp/Makefile!lib/swoc/Makefile\n &!' ${ATS}/configure.ac
(cd ${ATS} ; git add configure.ac)
fi

if ! grep -q swoc ${ATS}/${BASE_PATH}/Makefile.am ; then
sed -i -e '/SUBDIRS =/s!$! swoc!' ${ATS}/${BASE_PATH}/Makefile.am
(cd ${ATS} ; git add ${BASE_PATH}/Makefile.am)
fi
11 changes: 11 additions & 0 deletions unit_tests/test_Errata.cc
Original file line number Diff line number Diff line change
Expand Up @@ -414,4 +414,15 @@ TEST_CASE("Errata Autotext", "[libswoc][errata]") {
REQUIRE(b.front().text() == "Bravo [2]");
Errata c{ecode(ECode::ALPHA), ERRATA_ERROR, Errata::AUTO};
REQUIRE(c.front().text() == "Error: Alpha [1]");

Errata d{ERRATA_ERROR};
REQUIRE_FALSE(d.is_ok());
Errata e{ERRATA_INFO};
REQUIRE(e.is_ok());
Errata f{ecode(ECode::BRAVO)};
REQUIRE_FALSE(f.is_ok());
// Change properties but need to restore them for other tests.
swoc::meta::let g1(Errata::DEFAULT_SEVERITY, ERRATA_WARN);
swoc::meta::let g2(Errata::FAILURE_SEVERITY, ERRATA_ERROR);
REQUIRE(f.is_ok());
}
24 changes: 24 additions & 0 deletions unit_tests/test_meta.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,27 @@ TEST_CASE("Meta vary", "[meta][vary]") {
v = "956"_tv;
REQUIRE(std::visit(visitor, v) == 956);
}

TEST_CASE("Meta let", "[meta][let]") {
using swoc::meta::let;

unsigned x = 56;
{
REQUIRE(x == 56);
let guard(x, unsigned(3136));
REQUIRE(x == 3136);
// auto bogus = guard; // should not compile.
}
REQUIRE(x == 56);

// Checking move semantics - avoid reallocating the original string.
std::string s{"Evil Dave Rulz With An Iron Keyboard"}; // force allocation.
auto sptr = s.data();
{
char const * text = "Twas brillig and the slithy toves";
let guard(s, std::string(text));
REQUIRE(s == text);
REQUIRE(s.data() != sptr);
}
REQUIRE(s.data() == sptr);
}

0 comments on commit 1c7af86

Please sign in to comment.