cmdopt: add simple reimplementation of libcmdopt
This commit is contained in:
parent
1d65a7ed77
commit
250b8d21ec
@ -16,6 +16,9 @@ UTIL_FILES = \
|
|||||||
bezier.hpp \
|
bezier.hpp \
|
||||||
bitwise.cpp \
|
bitwise.cpp \
|
||||||
bitwise.hpp \
|
bitwise.hpp \
|
||||||
|
cmdopt.cpp \
|
||||||
|
cmdopt.hpp \
|
||||||
|
cmdopt.ipp \
|
||||||
colour.cpp \
|
colour.cpp \
|
||||||
colour.hpp \
|
colour.hpp \
|
||||||
colour.ipp \
|
colour.ipp \
|
||||||
|
263
cmdopt.cpp
Normal file
263
cmdopt.cpp
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cmdopt.hpp"
|
||||||
|
|
||||||
|
#include "debug.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using util::cmdopt::option::base;
|
||||||
|
using util::cmdopt::option::bytes;
|
||||||
|
using util::cmdopt::option::count;
|
||||||
|
using util::cmdopt::option::value;
|
||||||
|
using util::cmdopt::parser;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
base::base (std::string _name):
|
||||||
|
m_name (_name)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
base::~base ()
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
base::execute (void)
|
||||||
|
{
|
||||||
|
throw invalid_null (m_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
base::execute (const char *restrict)
|
||||||
|
{
|
||||||
|
throw invalid_value (m_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
base::start (void)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
base::finish (void)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
std::string
|
||||||
|
base::name (void) const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
value<T>::value (std::string _name, T &_data):
|
||||||
|
base (_name),
|
||||||
|
m_data (_data)
|
||||||
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
value<T>::execute (const char *restrict str)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
std::istringstream os (str);
|
||||||
|
os.exceptions (
|
||||||
|
std::istringstream::failbit
|
||||||
|
| std::istringstream::badbit
|
||||||
|
);
|
||||||
|
os >> m_data;
|
||||||
|
|
||||||
|
if (!os.eof ())
|
||||||
|
throw invalid_value (__func__);
|
||||||
|
} catch (...) {
|
||||||
|
throw invalid_value (__func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
T
|
||||||
|
value<T>::data (void) const
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
T&
|
||||||
|
value<T>::data (void)
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
namespace util { namespace cmdopt { namespace option {
|
||||||
|
template class value<uint16_t>;
|
||||||
|
template class value<uint32_t>;
|
||||||
|
template class value<uint64_t>;
|
||||||
|
} } }
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
count<T>::execute (void)
|
||||||
|
{
|
||||||
|
++ this->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
namespace util { namespace cmdopt { namespace option {
|
||||||
|
template class count<unsigned>;
|
||||||
|
} } }
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
int
|
||||||
|
parser::scan (int argc, char *const *argv)
|
||||||
|
{
|
||||||
|
CHECK_GE (argc, 0);
|
||||||
|
CHECK (argv);
|
||||||
|
|
||||||
|
// start iterating after our program's name
|
||||||
|
int i = 1;
|
||||||
|
while (i < argc) {
|
||||||
|
auto len = strlen (argv[i]);
|
||||||
|
|
||||||
|
// bail if there's no potential for an option
|
||||||
|
if (len < 2 || argv[i][0] != '-')
|
||||||
|
return i;
|
||||||
|
|
||||||
|
// parse longopt
|
||||||
|
auto inc = argv[i][1] == '-'
|
||||||
|
? parse_long (i, argc, argv)
|
||||||
|
: parse_short (i, argc, argv);
|
||||||
|
|
||||||
|
CHECK_GT (inc, 0);
|
||||||
|
i += inc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
int
|
||||||
|
parser::parse_long (int pos, int argc, char *const *argv)
|
||||||
|
{
|
||||||
|
CHECK_LT (pos, argc);
|
||||||
|
CHECK_GE (pos, 0);
|
||||||
|
CHECK_GE (argc, 0);
|
||||||
|
CHECK (argv);
|
||||||
|
|
||||||
|
CHECK_EQ (argv[pos][0], '-');
|
||||||
|
CHECK_EQ (argv[pos][1], '-');
|
||||||
|
|
||||||
|
// break first atom into components and extract the key
|
||||||
|
const char *start = argv[pos] + 2;
|
||||||
|
const char *eq = strchr (start, '=');
|
||||||
|
const char *last = start + strlen (start);
|
||||||
|
|
||||||
|
std::string key { start, eq ? eq : last };
|
||||||
|
|
||||||
|
// find the handler
|
||||||
|
auto handle_pos = std::find_if (m_long.begin (),
|
||||||
|
m_long.end (),
|
||||||
|
[&] (auto i) { return std::get<0> (i) == key; });
|
||||||
|
if (handle_pos == m_long.end ())
|
||||||
|
throw invalid_key (key);
|
||||||
|
|
||||||
|
auto &handler = std::get<1> (*handle_pos);
|
||||||
|
|
||||||
|
// maybe grab a value from the next atom and dispatch
|
||||||
|
if (!eq) {
|
||||||
|
// check the next atom for the value
|
||||||
|
if (pos + 1 < argc)
|
||||||
|
if (argv[pos + 1][0] != '-') {
|
||||||
|
handler.execute (argv[pos+1]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.execute ();
|
||||||
|
} else {
|
||||||
|
handler.execute (eq+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
int
|
||||||
|
parser::parse_short (int pos, int argc, char *const *argv)
|
||||||
|
{
|
||||||
|
CHECK_LT (pos, argc);
|
||||||
|
CHECK_GE (pos, 0);
|
||||||
|
CHECK_GE (argc, 0);
|
||||||
|
CHECK (argv);
|
||||||
|
|
||||||
|
CHECK_EQ (argv[pos][0], '-');
|
||||||
|
CHECK_NEQ (argv[pos][1], '-');
|
||||||
|
|
||||||
|
// we have a run of no-value keys
|
||||||
|
auto len = strlen (argv[pos]);
|
||||||
|
if (len > 2 || pos + 1 == argc || argv[pos+1][0] == '-') {
|
||||||
|
for (size_t i = 1; i < len; ++i) {
|
||||||
|
auto letter = argv[pos][i];
|
||||||
|
|
||||||
|
auto hpos = std::find_if (m_short.begin (),
|
||||||
|
m_short.end (),
|
||||||
|
[letter] (auto j) { return std::get<0> (j) == letter; });
|
||||||
|
if (hpos == m_short.end ())
|
||||||
|
throw invalid_key (std::to_string (letter));
|
||||||
|
std::get<1> (*hpos).execute ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have a value following
|
||||||
|
auto letter = argv[pos][1];
|
||||||
|
auto hpos = std::find_if (m_short.begin (),
|
||||||
|
m_short.end (),
|
||||||
|
[letter] (auto i) { return std::get<0> (i) == letter; });
|
||||||
|
if (hpos == m_short.end ())
|
||||||
|
throw invalid_key (std::to_string (letter));
|
||||||
|
std::get<1> (*hpos).execute (argv[pos+1]);
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
117
cmdopt.hpp
Normal file
117
cmdopt.hpp
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __UTIL_CMDLINE_HPP
|
||||||
|
#define __UTIL_CMDLINE_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace util { namespace cmdopt {
|
||||||
|
namespace option {
|
||||||
|
class base {
|
||||||
|
public:
|
||||||
|
base (std::string name);
|
||||||
|
virtual ~base ();
|
||||||
|
|
||||||
|
virtual void execute (void);
|
||||||
|
virtual void execute (const char *restrict);
|
||||||
|
virtual void start (void);
|
||||||
|
virtual void finish (void);
|
||||||
|
|
||||||
|
std::string name (void) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class value : public base {
|
||||||
|
public:
|
||||||
|
value (std::string name, T&);
|
||||||
|
|
||||||
|
void execute (const char *restrict) override;
|
||||||
|
|
||||||
|
T data (void) const;
|
||||||
|
T& data (void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
T& m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T = unsigned>
|
||||||
|
class count : public value<T> {
|
||||||
|
public:
|
||||||
|
count (std::string name);
|
||||||
|
void execute (void) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class bytes : public value<size_t> {
|
||||||
|
public:
|
||||||
|
bytes (std::string name);
|
||||||
|
void execute (const char *restrict) override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class error : public std::runtime_error
|
||||||
|
{ using runtime_error::runtime_error; };
|
||||||
|
|
||||||
|
class invalid_key : public error
|
||||||
|
{ using error::error; };
|
||||||
|
|
||||||
|
class invalid_value : public error
|
||||||
|
{ using error::error; };
|
||||||
|
|
||||||
|
class invalid_null : public error
|
||||||
|
{ using error::error; };
|
||||||
|
|
||||||
|
|
||||||
|
class parser {
|
||||||
|
public:
|
||||||
|
template <typename T, typename ...Args>
|
||||||
|
T& add (char shortname,
|
||||||
|
std::string longname,
|
||||||
|
std::string description,
|
||||||
|
Args&&...);
|
||||||
|
|
||||||
|
int scan (int argc, char *const *argv);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int parse_long (int pos, int argc, char *const *argv);
|
||||||
|
int parse_short (int pos, int argc, char *const *argv);
|
||||||
|
|
||||||
|
|
||||||
|
using short_t = std::tuple<char,option::base&>;
|
||||||
|
using long_t = std::tuple<std::string,option::base&>;
|
||||||
|
|
||||||
|
std::vector<short_t> m_short;
|
||||||
|
std::vector<long_t> m_long;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<option::base>> m_options;
|
||||||
|
};
|
||||||
|
} }
|
||||||
|
|
||||||
|
#include "cmdopt.ipp"
|
||||||
|
|
||||||
|
#endif
|
37
cmdopt.ipp
Normal file
37
cmdopt.ipp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __UTIL_CMDLINE_IPP
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
#define __UTIL_CMDLINE_IPP
|
||||||
|
|
||||||
|
namespace util { namespace cmdopt {
|
||||||
|
template <typename T, typename ...Args>
|
||||||
|
T&
|
||||||
|
parser::add (char shortname, std::string longname, std::string description, Args&&... args)
|
||||||
|
{
|
||||||
|
auto handler = std::make_unique<T> (longname, std::forward<Args> (args)...);
|
||||||
|
T& ref = *handler;
|
||||||
|
|
||||||
|
m_short.emplace_back (shortname, ref);
|
||||||
|
m_long .emplace_back (longname, ref);
|
||||||
|
|
||||||
|
m_options.emplace_back (std::move (handler));
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
} }
|
@ -270,20 +270,33 @@ adjust_ocean (util::image::buffer<float> &height,
|
|||||||
static const unsigned THERMAL_ITERATIONS = 10;
|
static const unsigned THERMAL_ITERATIONS = 10;
|
||||||
static const unsigned HYDRAULIC_ITERATIONS = 100;
|
static const unsigned HYDRAULIC_ITERATIONS = 100;
|
||||||
|
|
||||||
|
#include "cmdopt.hpp"
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (void)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
// setup the output buffer
|
// setup default variables
|
||||||
#ifdef ENABLE_DEBUGGING
|
#ifdef ENABLE_DEBUGGING
|
||||||
util::extent2u size {320, 240};
|
util::extent2u res {320, 240};
|
||||||
#else
|
#else
|
||||||
util::extent2u size {1920, 1080};
|
util::extent2u res {1920, 1080};
|
||||||
#endif
|
#endif
|
||||||
util::image::buffer<float> img (size);
|
|
||||||
|
|
||||||
uint64_t seed = time (nullptr);
|
uint64_t seed = time (nullptr);
|
||||||
|
|
||||||
|
// fill variables from arguments
|
||||||
|
util::cmdopt::parser args;
|
||||||
|
args.add<util::cmdopt::option::value<size_t>> ('w', "width", "output image width", res.w);
|
||||||
|
args.add<util::cmdopt::option::value<size_t>> ('h', "height", "output image height", res.h);
|
||||||
|
args.add<util::cmdopt::option::value<uint64_t>> ('s', "seed", "random seed", seed);
|
||||||
|
//args.add<util::cmdopt::option::value<unsigned>> ('o', "octaves", "total fractal iterations", octaves);
|
||||||
|
//args.add<util::cmdopt::option::value<float>> ('H', "hurst", "Hurst exponent", H);
|
||||||
|
|
||||||
|
args.scan (argc, argv);
|
||||||
|
|
||||||
|
util::image::buffer<float> img (res);
|
||||||
|
|
||||||
// setup the noise generator
|
// setup the noise generator
|
||||||
#if 0
|
#if 0
|
||||||
//util::noise::fractal::fbm<float, util::noise::basis::worley<float>> b (seed);
|
//util::noise::fractal::fbm<float, util::noise::basis::worley<float>> b (seed);
|
||||||
@ -294,7 +307,7 @@ main (void)
|
|||||||
util::noise::fractal::hetero<float, util::noise::basis::value<float,util::lerp::quintic>> b (seed);
|
util::noise::fractal::hetero<float, util::noise::basis::value<float,util::lerp::quintic>> b (seed);
|
||||||
|
|
||||||
b.octaves (8);
|
b.octaves (8);
|
||||||
b.frequency (10.f / size.w);
|
b.frequency (10.f / res.w);
|
||||||
b.lacunarity = 2.f;
|
b.lacunarity = 2.f;
|
||||||
b.H = 1.0f;
|
b.H = 1.0f;
|
||||||
b.seed (seed);
|
b.seed (seed);
|
||||||
@ -306,21 +319,21 @@ main (void)
|
|||||||
util::noise::fractal::fbm<float, util::noise::basis::perlin<float,util::lerp::quintic>>
|
util::noise::fractal::fbm<float, util::noise::basis::perlin<float,util::lerp::quintic>>
|
||||||
> b (seed, { 0.13f, 0.13f });
|
> b (seed, { 0.13f, 0.13f });
|
||||||
|
|
||||||
b.data.frequency (1.f / size.w);
|
b.data.frequency (1.f / res.w);
|
||||||
b.perturb[0].octaves (4);
|
b.perturb[0].octaves (4);
|
||||||
b.perturb[1].octaves (4);
|
b.perturb[1].octaves (4);
|
||||||
b.perturb[0].frequency (10.f / size.w);
|
b.perturb[0].frequency (10.f / res.w);
|
||||||
b.perturb[1].frequency (10.f / size.w);
|
b.perturb[1].frequency (10.f / res.w);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// generate the values. offset positions slightly to observe simple axis issues with perlin basis
|
// generate the values. offset positions slightly to observe simple axis issues with perlin basis
|
||||||
{
|
{
|
||||||
auto offset = util::vector2f { -100 };
|
auto offset = util::vector2f { -100 };
|
||||||
|
|
||||||
for (size_t y = 0; y < size.h; ++y)
|
for (size_t y = 0; y < res.h; ++y)
|
||||||
for (size_t x = 0; x < size.w; ++x) {
|
for (size_t x = 0; x < res.w; ++x) {
|
||||||
auto v = b (util::point2f {float (x), float (y)} + offset);
|
auto v = b (util::point2f {float (x), float (y)} + offset);
|
||||||
img.data ()[y * size.w + x] = v;
|
img.data ()[y * res.w + x] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,7 +355,7 @@ main (void)
|
|||||||
|
|
||||||
std::cerr << "thermal_erosion\n";
|
std::cerr << "thermal_erosion\n";
|
||||||
for (size_t i = 0; i < THERMAL_ITERATIONS; ++i)
|
for (size_t i = 0; i < THERMAL_ITERATIONS; ++i)
|
||||||
thermal_erode (soft, to_radians (30.f), 1.f / size.w, 0.f);
|
thermal_erode (soft, to_radians (30.f), 1.f / res.w, 0.f);
|
||||||
|
|
||||||
hydraulic_erode (soft, HYDRAULIC_ITERATIONS);
|
hydraulic_erode (soft, HYDRAULIC_ITERATIONS);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user