Patrick Brosi 5 роки тому
батько
коміт
cfd355044d

+ 19 - 10
src/osmfixer/index/StatIdx.cpp

@@ -62,7 +62,7 @@ void StatIdx::addStation(size_t osmid, double lat, double lng, size_t group,
62 62
   std::cout << "Record: " << osmid << " " << lat << " " << lng << std::endl;
63 63
   auto point = util::geo::latLngToWebMerc<double>(lat, lng);
64 64
 
65
-  _stations.emplace_back(Station{osmid, group, point, attrs});
65
+  _stations.emplace_back(Station{_stations.size(), osmid, group, point, attrs});
66 66
 
67 67
   // extend bounding box
68 68
   _bbox = util::geo::extendBox(point, _bbox);
@@ -72,6 +72,7 @@ void StatIdx::addStation(size_t osmid, double lat, double lng, size_t group,
72 72
 void StatIdx::addGroup(size_t osmid, const OsmAttrs& attrs) {
73 73
   std::cout << osmid << std::endl;
74 74
   Group g;
75
+	g.id = _groups.size();
75 76
   g.osmid = osmid;
76 77
   g.attrs = attrs;
77 78
   _groups.emplace_back(g);
@@ -89,8 +90,8 @@ void StatIdx::initGroups() {
89 90
     util::geo::MultiPoint<double> mp;
90 91
     for (size_t stid : _groups[i].stations) {
91 92
       double rad = 11.0;
92
-      int n = 50.0;
93
-      for (int i = 0; i <= n; i++) {
93
+      int n = 20;
94
+      for (int i = 0; i < n; i++) {
94 95
         double x = rad * cos((2.0 * M_PI / static_cast<double>(n)) *
95 96
                              static_cast<double>(i));
96 97
         double y = rad * sin((2.0 * M_PI / static_cast<double>(n)) *
@@ -110,13 +111,8 @@ void StatIdx::initIndex() {
110 111
                                                              false);
111 112
   _ggrid = util::geo::Grid<size_t, util::geo::Polygon, double>(5000, 5000,
112 113
                                                                _bbox, false);
113
-  for (size_t i = 0; i < _stations.size(); i++) {
114
-    _sgrid.add(_stations[i].pos, i);
115
-  }
116
-
117
-  for (size_t i = 0; i < _groups.size(); i++) {
118
-    _ggrid.add(_groups[i].poly, i);
119
-  }
114
+  for (size_t i = 0; i < _stations.size(); i++) _sgrid.add(_stations[i].pos, i);
115
+  for (size_t i = 0; i < _groups.size(); i++) _ggrid.add(_groups[i].poly, i);
120 116
 }
121 117
 
122 118
 // _____________________________________________________________________________
@@ -159,3 +155,16 @@ std::vector<const Station*> StatIdx::getStations(
159 155
 
160 156
   return ret;
161 157
 }
158
+
159
+// _____________________________________________________________________________
160
+const Station* StatIdx::getStation(size_t id) const {
161
+	if (id >= _stations.size()) return 0;
162
+	return &_stations[id];
163
+}
164
+
165
+
166
+// _____________________________________________________________________________
167
+const Group* StatIdx::getGroup(size_t id) const {
168
+	if (id >= _groups.size()) return 0;
169
+	return &_groups[id];
170
+}

+ 5 - 0
src/osmfixer/index/StatIdx.h

@@ -16,6 +16,7 @@ namespace osmfixer {
16 16
 typedef std::map<std::string, std::vector<std::string>> OsmAttrs;
17 17
 
18 18
 struct Station {
19
+  size_t id;
19 20
   size_t osmid;
20 21
   size_t group;
21 22
   util::geo::DPoint pos;
@@ -23,6 +24,7 @@ struct Station {
23 24
 };
24 25
 
25 26
 struct Group {
27
+  size_t id;
26 28
   size_t osmid;
27 29
   util::geo::DPolygon poly;
28 30
   OsmAttrs attrs;
@@ -38,6 +40,9 @@ class StatIdx {
38 40
   std::vector<const Station*> getStations(const util::geo::DBox bbox) const;
39 41
   std::vector<const Group*> getGroups(const util::geo::DBox bbox) const;
40 42
 
43
+  const Station* getStation(size_t id) const;
44
+  const Group* getGroup(size_t id) const;
45
+
41 46
  private:
42 47
   void addStation(size_t id, double lat, double lng, size_t group,
43 48
                   const OsmAttrs& attrs);

+ 51 - 2
src/osmfixer/server/StatServer.cpp

@@ -25,6 +25,8 @@ util::http::Answer StatServer::handle(const util::http::Req& req,
25 25
       a = util::http::Answer("200 OK", "osmfixer");
26 26
     } else if (cmd == "/map") {
27 27
       a = handleMapReq(params);
28
+    } else if (cmd == "/stat") {
29
+      a = handleStatReq(params);
28 30
     } else {
29 31
       a = util::http::Answer("404 Not Found", "dunno");
30 32
     }
@@ -103,7 +105,7 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
103 105
 void StatServer::printStation(const Station* stat, std::ostream* out) {
104 106
   auto latLng =
105 107
       util::geo::webMercToLatLng<double>(stat->pos.getX(), stat->pos.getY());
106
-  (*out) << "{\"id\":" << stat->osmid << ",\"lat\":"
108
+  (*out) << "{\"id\":" << stat->id << ",\"lat\":"
107 109
          << latLng.getY() << ",\"lon\":" << latLng.getX() << "}";
108 110
 }
109 111
 
@@ -114,7 +116,7 @@ void StatServer::printGroup(const Group* group, std::ostream* out) {
114 116
   for (auto p : group->poly.getOuter()) {
115 117
     projPoly.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
116 118
   }
117
-  (*out) << "{\"id\":" << group->osmid << ",\"poly\":[";
119
+  (*out) << "{\"id\":" << group->id << ",\"poly\":[";
118 120
   char sep = ' ';
119 121
   for (auto p : projPoly) {
120 122
     (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
@@ -147,3 +149,50 @@ std::string StatServer::parseUrl(std::string u, std::string pl,
147 149
 
148 150
   return util::urlDecode(parts.front());
149 151
 }
152
+
153
+// _____________________________________________________________________________
154
+util::http::Answer StatServer::handleStatReq(const Params& pars) const {
155
+  if (pars.count("id") == 0 || pars.find("id")->second.empty())
156
+    throw std::invalid_argument("No ID specified.");
157
+  std::string cb;
158
+  if (pars.count("cb")) cb = pars.find("cb")->second.c_str();
159
+
160
+  size_t sid = atol(pars.find("id")->second.c_str());
161
+  auto stat = _idx->getStation(sid);
162
+
163
+  if (!stat) return util::http::Answer("404 Not Found", "Station not found.");
164
+
165
+  std::stringstream json;
166
+
167
+  json << std::setprecision(10);
168
+
169
+  if (cb.size()) json << cb << "(";
170
+  json << "{\"id\":" << sid << ","
171
+    << "\"osmid\":" << stat->osmid << ","
172
+    << "\"attrs\":{";
173
+
174
+  char sep = ' ';
175
+
176
+  for (const auto& par : stat->attrs) {
177
+    json << sep;
178
+    sep = ',';
179
+    json << "\"" << util::jsonStringEscape(par.first) << "\":[";
180
+
181
+    char sep2 = ' ';
182
+    for (const auto& val : par.second) {
183
+      json << sep2;
184
+      sep2 = ',';
185
+      json << util::jsonStringEscape(val);
186
+    }
187
+    json << "]";
188
+  }
189
+
190
+  json << "}}";
191
+
192
+  if (cb.size()) json << ")";
193
+
194
+  auto answ = util::http::Answer("200 OK", json.str(), true);
195
+  answ.params["Content-Type"] = "application/javascript; charset=utf-8";
196
+
197
+  return answ;
198
+}

+ 1 - 0
src/osmfixer/server/StatServer.h

@@ -25,6 +25,7 @@ class StatServer : public util::http::Handler {
25 25
   static std::string parseUrl(std::string u, std::string pl, Params* params);
26 26
 
27 27
   util::http::Answer handleMapReq(const Params& pars) const;
28
+  util::http::Answer handleStatReq(const Params& pars) const;
28 29
 
29 30
   static void printStation(const Station* stat, std::ostream* out);
30 31
   static void printGroup(const Group* stat, std::ostream* out);

+ 12 - 9
src/util/geo/Geo.h

@@ -1269,7 +1269,7 @@ inline Polygon<T> convexHull(const RotatedBox<T>& b) {
1269 1269
 // _____________________________________________________________________________
1270 1270
 template <typename T>
1271 1271
 inline size_t convexHullImpl(const MultiPoint<T>& a, size_t p1, size_t p2,
1272
-                             Line<T>* h, uint8_t d) {
1272
+                             Line<T>* h) {
1273 1273
   // quickhull by Barber, Dobkin & Huhdanpaa
1274 1274
   Point<T> pa;
1275 1275
   bool found = false;
@@ -1277,7 +1277,7 @@ inline size_t convexHullImpl(const MultiPoint<T>& a, size_t p1, size_t p2,
1277 1277
   for (const auto& p : a) {
1278 1278
     double tmpDist = distToSegment((*h)[p1], (*h)[p2], p);
1279 1279
     double cp = crossProd(p, LineSegment<T>((*h)[p1], (*h)[p2]));
1280
-    if (((cp > 0 && !d) || (cp < 0 && d)) && tmpDist >= maxDist + EPSILON) {
1280
+    if ((cp > 0) && tmpDist > maxDist) {
1281 1281
       pa = p;
1282 1282
       found = true;
1283 1283
       maxDist = tmpDist;
@@ -1286,9 +1286,9 @@ inline size_t convexHullImpl(const MultiPoint<T>& a, size_t p1, size_t p2,
1286 1286
 
1287 1287
   if (!found) return 0;
1288 1288
 
1289
-  h->insert(h->begin() + p2 + !d, pa);
1290
-  size_t in = 1 + convexHullImpl(a, p1, p2 + !d, h, d);
1291
-  return in + convexHullImpl(a, p2 + in * d + 1 - 2 * d, p2 + in * d, h, d);
1289
+  h->insert(h->begin() + p2, pa);
1290
+  size_t in = 1 + convexHullImpl(a, p1, p2, h);
1291
+  return in + convexHullImpl(a, p2 + in - 1, p2 + in, h);
1292 1292
 }
1293 1293
 
1294 1294
 // _____________________________________________________________________________
@@ -1300,13 +1300,16 @@ inline Polygon<T> convexHull(const MultiPoint<T>& l) {
1300 1300
   Point<T> left(std::numeric_limits<T>::max(), 0);
1301 1301
   Point<T> right(std::numeric_limits<T>::lowest(), 0);
1302 1302
   for (const auto& p : l) {
1303
-    if (p.getX() <= left.getX()) left = p;
1304
-    if (p.getX() >= right.getX()) right = p;
1303
+    if (p.getX() < left.getX()) left = p;
1304
+    if (p.getX() > right.getX()) right = p;
1305 1305
   }
1306 1306
 
1307 1307
   Line<T> hull{left, right};
1308
-  convexHullImpl(l, 0, 1, &hull, 1);
1309
-  convexHullImpl(l, 0, hull.size() - 1, &hull, 0);
1308
+  convexHullImpl(l, 0, 1, &hull);
1309
+  hull.push_back(hull.front());
1310
+  convexHullImpl(l, hull.size() - 2, hull.size() - 1, &hull);
1311
+	hull.pop_back();
1312
+
1310 1313
   return Polygon<T>(hull);
1311 1314
 }
1312 1315
 

Різницю між файлами не показано, бо вона завелика
+ 1411 - 1178
src/util/tests/TestMain.cpp


+ 91 - 54
src/util/tests/lest.h

@@ -31,7 +31,11 @@
31 31
 #include <cmath>
32 32
 #include <cstddef>
33 33
 
34
-#define  lest_VERSION "1.33.1"
34
+#define lest_MAJOR  1
35
+#define lest_MINOR  35
36
+#define lest_PATCH  1
37
+
38
+#define  lest_VERSION  lest_STRINGIFY(lest_MAJOR) "." lest_STRINGIFY(lest_MINOR) "." lest_STRINGIFY(lest_PATCH)
35 39
 
36 40
 #ifndef  lest_FEATURE_AUTO_REGISTER
37 41
 # define lest_FEATURE_AUTO_REGISTER  0
@@ -49,50 +53,55 @@
49 53
 # define lest_FEATURE_REGEX_SEARCH  0
50 54
 #endif
51 55
 
52
-#ifndef lest_FEATURE_TIME_PRECISION
53
-#define lest_FEATURE_TIME_PRECISION  0
56
+#ifndef  lest_FEATURE_TIME_PRECISION
57
+# define lest_FEATURE_TIME_PRECISION  0
54 58
 #endif
55 59
 
56
-#ifndef lest_FEATURE_WSTRING
57
-#define lest_FEATURE_WSTRING  1
60
+#ifndef  lest_FEATURE_WSTRING
61
+# define lest_FEATURE_WSTRING  1
58 62
 #endif
59 63
 
60
-#ifdef lest_FEATURE_RTTI
61
-# define lest__cpp_rtti  lest_FEATURE_RTTI
64
+#ifdef    lest_FEATURE_RTTI
65
+# define  lest__cpp_rtti  lest_FEATURE_RTTI
62 66
 #elif defined(__cpp_rtti)
63
-# define lest__cpp_rtti  __cpp_rtti
67
+# define  lest__cpp_rtti  __cpp_rtti
64 68
 #elif defined(__GXX_RTTI) || defined (_CPPRTTI)
65
-# define lest__cpp_rtti  1
69
+# define  lest__cpp_rtti  1
66 70
 #else
67
-# define lest__cpp_rtti  0
71
+# define  lest__cpp_rtti  0
68 72
 #endif
69 73
 
70 74
 #if lest_FEATURE_REGEX_SEARCH
71 75
 # include <regex>
72 76
 #endif
73 77
 
78
+// Stringify:
79
+
80
+#define lest_STRINGIFY(  x )  lest_STRINGIFY_( x )
81
+#define lest_STRINGIFY_( x )  #x
82
+
74 83
 // Compiler warning suppression:
75 84
 
76
-#ifdef __clang__
85
+#if defined (__clang__)
77 86
 # pragma clang diagnostic ignored "-Waggregate-return"
78 87
 # pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses"
79 88
 # pragma clang diagnostic push
80 89
 # pragma clang diagnostic ignored "-Wunused-comparison"
81
-#elif defined __GNUC__
90
+#elif defined (__GNUC__)
82 91
 # pragma GCC   diagnostic ignored "-Waggregate-return"
83 92
 # pragma GCC   diagnostic push
84 93
 #endif
85 94
 
86 95
 // Suppress shadow and unused-value warning for sections:
87 96
 
88
-#if defined __clang__
97
+#if defined (__clang__)
89 98
 # define lest_SUPPRESS_WSHADOW    _Pragma( "clang diagnostic push" ) \
90 99
                                   _Pragma( "clang diagnostic ignored \"-Wshadow\"" )
91 100
 # define lest_SUPPRESS_WUNUSED    _Pragma( "clang diagnostic push" ) \
92 101
                                   _Pragma( "clang diagnostic ignored \"-Wunused-value\"" )
93 102
 # define lest_RESTORE_WARNINGS    _Pragma( "clang diagnostic pop"  )
94 103
 
95
-#elif defined __GNUC__
104
+#elif defined (__GNUC__)
96 105
 # define lest_SUPPRESS_WSHADOW    _Pragma( "GCC diagnostic push" ) \
97 106
                                   _Pragma( "GCC diagnostic ignored \"-Wshadow\"" )
98 107
 # define lest_SUPPRESS_WUNUSED    _Pragma( "GCC diagnostic push" ) \
@@ -104,12 +113,22 @@
104 113
 # define lest_RESTORE_WARNINGS    /*empty*/
105 114
 #endif
106 115
 
107
-#ifdef  _MSVC_LANG
108
-# define lest_CPP17_OR_GREATER_MS (  _MSVC_LANG >= 201703L )
109
-#else
110
-# define lest_CPP17_OR_GREATER_MS    0
116
+// C++ language version detection (C++20 is speculative):
117
+// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
118
+
119
+#ifndef   lest_CPLUSPLUS
120
+# if defined(_MSVC_LANG ) && !defined(__clang__)
121
+#  define lest_CPLUSPLUS  (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
122
+# else
123
+#  define lest_CPLUSPLUS  __cplusplus
124
+# endif
111 125
 #endif
112
-# define lest_CPP17_OR_GREATER    ( __cplusplus >= 201703L ||  lest_CPP17_OR_GREATER_MS )
126
+
127
+#define lest_CPP98_OR_GREATER  ( lest_CPLUSPLUS >= 199711L )
128
+#define lest_CPP11_OR_GREATER  ( lest_CPLUSPLUS >= 201103L )
129
+#define lest_CPP14_OR_GREATER  ( lest_CPLUSPLUS >= 201402L )
130
+#define lest_CPP17_OR_GREATER  ( lest_CPLUSPLUS >= 201703L )
131
+#define lest_CPP20_OR_GREATER  ( lest_CPLUSPLUS >= 202000L )
113 132
 
114 133
 #if ! defined( lest_NO_SHORT_MACRO_NAMES ) && ! defined( lest_NO_SHORT_ASSERTION_NAMES )
115 134
 # define MODULE            lest_MODULE
@@ -186,7 +205,7 @@
186 205
             if ( lest::result score = lest_DECOMPOSE( expr ) ) \
187 206
                 throw lest::failure{ lest_LOCATION, #expr, score.decomposition }; \
188 207
             else if ( lest_env.pass() ) \
189
-                lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition }, lest_env.context() ); \
208
+                lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition, lest_env.zen() }, lest_env.context() ); \
190 209
         } \
191 210
         catch(...) \
192 211
         { \
@@ -201,7 +220,7 @@
201 220
             if ( lest::result score = lest_DECOMPOSE( expr ) ) \
202 221
             { \
203 222
                 if ( lest_env.pass() ) \
204
-                    lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }, lest_env.context() ); \
223
+                    lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ), lest_env.zen() }, lest_env.context() ); \
205 224
             } \
206 225
             else \
207 226
                 throw lest::failure{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }; \
@@ -381,8 +400,8 @@ struct success : message
381 400
 
382 401
 struct passing : success
383 402
 {
384
-    passing( location where_, text expr_, text decomposition_ )
385
-    : success( "passed", where_, expr_ + " for " + decomposition_) {}
403
+    passing( location where_, text expr_, text decomposition_, bool zen )
404
+    : success( "passed", where_, expr_ + (zen ? "":" for " + decomposition_) ) {}
386 405
 };
387 406
 
388 407
 struct got_none : success
@@ -524,14 +543,45 @@ inline char const * sfx( char const  * txt ) { return txt; }
524 543
 inline char const * sfx( char const  *      ) { return ""; }
525 544
 #endif
526 545
 
527
-inline std::string to_string( std::nullptr_t               ) { return "nullptr"; }
528
-inline std::string to_string( std::string     const & txt ) { return "\"" + txt + "\"" ; }
546
+inline std::string transformed( char chr )
547
+{
548
+    struct Tr { char chr; char const * str; } table[] =
549
+    {
550
+        {'\\', "\\\\" },
551
+        {'\r', "\\r"  }, {'\f', "\\f" },
552
+        {'\n', "\\n"  }, {'\t', "\\t" },
553
+    };
554
+
555
+    for ( auto tr : table )
556
+    {
557
+        if ( chr == tr.chr )
558
+            return tr.str;
559
+    }
560
+
561
+    auto unprintable = [](char c){ return 0 <= c && c < ' '; };
562
+
563
+    auto to_hex_string = [](char c)
564
+    {
565
+        std::ostringstream os;
566
+        os << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>( static_cast<unsigned char>(c) );
567
+        return os.str();
568
+    };
569
+
570
+    return unprintable( chr  ) ? to_hex_string( chr ) : std::string( 1, chr );
571
+}
572
+
573
+inline std::string make_tran_string( std::string const & txt ) { std::ostringstream os; for(auto c:txt) os << transformed(c); return os.str(); }
574
+inline std::string make_strg_string( std::string const & txt ) { return "\"" + make_tran_string(                 txt   ) + "\"" ; }
575
+inline std::string make_char_string(                char chr ) { return "\'" + make_tran_string( std::string( 1, chr ) ) + "\'" ; }
576
+
577
+inline std::string to_string( std::nullptr_t              ) { return "nullptr"; }
578
+inline std::string to_string( std::string     const & txt ) { return make_strg_string( txt ); }
529 579
 #if lest_FEATURE_WSTRING
530 580
 inline std::string to_string( std::wstring    const & txt ) ;
531 581
 #endif
532 582
 
533
-inline std::string to_string( char    const * const   txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; }
534
-inline std::string to_string( char          * const   txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; }
583
+inline std::string to_string( char    const * const   txt ) { return txt ? make_strg_string( txt ) : "{null string}"; }
584
+inline std::string to_string( char          * const   txt ) { return txt ? make_strg_string( txt ) : "{null string}"; }
535 585
 #if lest_FEATURE_WSTRING
536 586
 inline std::string to_string( wchar_t const * const   txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; }
537 587
 inline std::string to_string( wchar_t       * const   txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; }
@@ -550,29 +600,9 @@ inline std::string to_string( unsigned  long long   value ) { return make_value_
550 600
 inline std::string to_string(         double        value ) { return make_value_string( value ) ;             }
551 601
 inline std::string to_string(          float        value ) { return make_value_string( value ) + sfx("f"  ); }
552 602
 
553
-inline std::string to_string(   signed char           chr ) { return to_string( static_cast<char>( chr ) ); }
554
-inline std::string to_string( unsigned char           chr ) { return to_string( static_cast<char>( chr ) ); }
555
-
556
-inline std::string to_string(          char           chr )
557
-{
558
-    struct Tr { char chr; char const * str; } table[] =
559
-    {
560
-        {'\r', "'\\r'" }, {'\f', "'\\f'" },
561
-        {'\n', "'\\n'" }, {'\t', "'\\t'" },
562
-    };
563
-
564
-    for ( auto tr : table )
565
-    {
566
-        if ( chr == tr.chr )
567
-            return tr.str;
568
-    }
569
-
570
-    auto unprintable = [](char c){ return 0 <= c && c < ' '; };
571
-
572
-    return unprintable( chr  )
573
-        ? to_string( static_cast<unsigned int>( chr ) )
574
-        : "\'" + std::string( 1, chr ) + "\'" ;
575
-}
603
+inline std::string to_string(   signed char           chr ) { return make_char_string( static_cast<char>( chr ) ); }
604
+inline std::string to_string( unsigned char           chr ) { return make_char_string( static_cast<char>( chr ) ); }
605
+inline std::string to_string(          char           chr ) { return make_char_string(                    chr   ); }
576 606
 
577 607
 template< typename T >
578 608
 struct is_streamable
@@ -968,7 +998,7 @@ inline bool select( text name, texts include )
968 998
 
969 999
 inline int indefinite( int repeat ) { return repeat == -1; }
970 1000
 
971
-using seed_t = unsigned long;
1001
+using seed_t = std::mt19937::result_type;
972 1002
 
973 1003
 struct options
974 1004
 {
@@ -979,6 +1009,7 @@ struct options
979 1009
     bool tags    = false;
980 1010
     bool time    = false;
981 1011
     bool pass    = false;
1012
+    bool zen     = false;
982 1013
     bool lexical = false;
983 1014
     bool random  = false;
984 1015
     bool verbose = false;
@@ -999,12 +1030,14 @@ struct env
999 1030
 
1000 1031
     env & operator()( text test )
1001 1032
     {
1002
-        testing = test; return *this;
1033
+        clear(); testing = test; return *this;
1003 1034
     }
1004 1035
 
1005 1036
     bool abort() { return opt.abort; }
1006 1037
     bool pass()  { return opt.pass; }
1038
+    bool zen()   { return opt.zen; }
1007 1039
 
1040
+    void clear() { ctx.clear(); }
1008 1041
     void pop()   { ctx.pop_back(); }
1009 1042
     void push( text proposition ) { ctx.emplace_back( proposition ); }
1010 1043
 
@@ -1311,6 +1344,7 @@ inline auto split_arguments( texts args ) -> std::tuple<options, texts>
1311 1344
             else if ( opt == "-l"      || "--list-tests" == opt ) { option.list    =  true; continue; }
1312 1345
             else if ( opt == "-t"      || "--time"       == opt ) { option.time    =  true; continue; }
1313 1346
             else if ( opt == "-p"      || "--pass"       == opt ) { option.pass    =  true; continue; }
1347
+            else if ( opt == "-z"      || "--pass-zen"   == opt ) { option.zen     =  true; continue; }
1314 1348
             else if ( opt == "-v"      || "--verbose"    == opt ) { option.verbose =  true; continue; }
1315 1349
             else if (                     "--version"    == opt ) { option.version =  true; continue; }
1316 1350
             else if ( opt == "--order" && "declared"     == val ) { /* by definition */   ; continue; }
@@ -1322,6 +1356,8 @@ inline auto split_arguments( texts args ) -> std::tuple<options, texts>
1322 1356
         }
1323 1357
         in.push_back( arg );
1324 1358
     }
1359
+    option.pass = option.pass || option.zen;
1360
+
1325 1361
     return std::make_tuple( option, in );
1326 1362
 }
1327 1363
 
@@ -1337,6 +1373,7 @@ inline int usage( std::ostream & os )
1337 1373
         "  -g, --list-tags    list tags of selected tests\n"
1338 1374
         "  -l, --list-tests   list selected tests\n"
1339 1375
         "  -p, --pass         also report passing tests\n"
1376
+        "  -z, --pass-zen     ... without expansion\n"
1340 1377
         "  -t, --time         list duration of selected tests\n"
1341 1378
         "  -v, --verbose      also report passing or failing sections\n"
1342 1379
         "  --order=declared   use source code test order (default)\n"
@@ -1437,9 +1474,9 @@ int run( test const (&specification)[N], int argc, char * argv[], std::ostream &
1437 1474
 
1438 1475
 } // namespace lest
1439 1476
 
1440
-#ifdef __clang__
1477
+#if defined (__clang__)
1441 1478
 # pragma clang diagnostic pop
1442
-#elif defined __GNUC__
1479
+#elif defined (__GNUC__)
1443 1480
 # pragma GCC   diagnostic pop
1444 1481
 #endif
1445 1482