Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
pistache
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
pistache
Commits
21ff3fdd
Commit
21ff3fdd
authored
Jan 19, 2016
by
octal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added a non-owning View<T> that stores a sequence of contiguous memory
parent
4035c5f1
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
485 additions
and
0 deletions
+485
-0
src/view.h
src/view.h
+251
-0
tests/CMakeLists.txt
tests/CMakeLists.txt
+4
-0
tests/cookie_test.cc
tests/cookie_test.cc
+135
-0
tests/view_test.cc
tests/view_test.cc
+95
-0
No files found.
src/view.h
0 → 100644
View file @
21ff3fdd
/* view.h
Mathieu Stefani, 19 janvier 2016
A non-owning range of contiguous memory that is represented by
a pointer to the beginning of the memory and the size.
*/
#pragma once
#include <string>
#include <vector>
#include <array>
#include <cstring>
#include <stdexcept>
template
<
typename
T
>
class
ViewBase
{
public:
typedef
T
value_type
;
typedef
T
&
reference
;
typedef
T
*
pointer
;
typedef
const
T
*
const_pointer
;
typedef
const
T
&
const_reference
;
typedef
const_pointer
iterator
;
typedef
const_pointer
const_iterator
;
explicit
ViewBase
(
std
::
nullptr_t
)
:
begin_
(
nullptr
)
,
size_
(
0
)
{
}
explicit
ViewBase
(
std
::
nullptr_t
,
size_t
)
:
begin_
(
nullptr
)
,
size_
(
0
)
{
}
explicit
ViewBase
(
const
T
*
begin
,
size_t
size
)
:
begin_
(
begin
)
,
size_
(
size
)
{
}
explicit
ViewBase
(
const
T
*
begin
,
const
T
*
end
)
{
if
(
begin
>
end
)
{
throw
std
::
invalid_argument
(
"begin > end"
);
}
begin_
=
begin
;
size_
=
std
::
distance
(
begin
,
end
);
}
size_t
size
()
const
{
return
size_
;
}
const
T
&
operator
[](
size_t
index
)
{
return
begin_
[
index
];
}
const
T
&
operator
[](
size_t
index
)
const
{
return
begin_
[
index
];
}
const
T
&
at
(
size_t
index
)
{
if
(
index
>=
size_
)
throw
std
::
invalid_argument
(
"index > size"
);
return
begin_
[
index
];
}
const
T
&
at
(
size_t
index
)
const
{
if
(
index
>=
size_
)
throw
std
::
invalid_argument
(
"index > size"
);
return
begin_
[
index
];
}
const_iterator
begin
()
const
{
return
const_iterator
(
begin_
);
}
const_iterator
end
()
const
{
return
const_iterator
(
begin_
+
size_
);
}
bool
operator
==
(
const
ViewBase
<
T
>&
other
)
const
{
return
size
()
==
other
.
size
()
&&
std
::
equal
(
begin
(),
end
(),
other
.
begin
());
}
bool
operator
!=
(
const
ViewBase
<
T
>&
other
)
const
{
return
!
(
*
this
==
other
);
}
bool
empty
()
const
{
return
begin_
==
nullptr
||
size_
==
0
;
}
const
T
*
data
()
const
{
return
begin_
;
}
private:
const
T
*
begin_
;
size_t
size_
;
};
template
<
typename
T
>
struct
View
:
public
ViewBase
<
T
>
{
explicit
View
(
std
::
nullptr_t
)
:
ViewBase
<
T
>
(
nullptr
)
{
}
explicit
View
(
std
::
nullptr_t
,
size_t
)
:
ViewBase
<
T
>
(
nullptr
,
0
)
{
}
explicit
View
(
const
T
*
begin
,
size_t
size
)
:
ViewBase
<
T
>
(
begin
,
size
)
{
}
explicit
View
(
const
T
*
begin
,
const
T
*
end
)
:
ViewBase
<
T
>
(
begin
,
end
)
{
}
};
template
<
>
struct
View
<
std
::
string
>
:
public
ViewBase
<
char
>
{
typedef
ViewBase
<
char
>
Base
;
explicit
View
(
const
char
*
begin
,
size_t
end
)
:
Base
(
begin
,
end
)
{
}
explicit
View
(
const
char
*
begin
,
const
char
*
end
)
:
Base
(
begin
,
end
)
{
}
using
Base
::
operator
==
;
bool
operator
==
(
const
char
*
str
)
const
{
return
equals
(
str
,
std
::
strlen
(
str
));
}
bool
operator
==
(
const
std
::
string
&
str
)
const
{
return
equals
(
str
.
c_str
(),
str
.
size
());
}
template
<
size_t
N
>
bool
operator
==
(
const
char
(
&
arr
)[
N
])
const
{
return
equals
(
arr
,
N
);
}
std
::
string
toString
()
const
{
return
std
::
string
(
data
(),
size
());
}
operator
std
::
string
()
const
{
return
toString
();
}
private:
bool
equals
(
const
char
*
str
,
size_t
length
)
const
{
if
(
length
!=
size
())
return
false
;
return
std
::
equal
(
begin
(),
end
(),
str
);
}
};
typedef
View
<
std
::
string
>
StringView
;
namespace
impl
{
template
<
typename
T
>
struct
ViewBuilder
;
template
<
typename
T
,
size_t
N
>
struct
ViewBuilder
<
std
::
array
<
T
,
N
>>
{
typedef
T
Type
;
static
View
<
T
>
build
(
const
std
::
array
<
T
,
N
>&
arr
)
{
return
buildSized
(
arr
,
arr
.
size
());
}
static
View
<
T
>
buildSized
(
const
std
::
array
<
T
,
N
>&
arr
,
size_t
size
)
{
if
(
size
>
arr
.
size
())
throw
std
::
invalid_argument
(
"out of bounds size"
);
return
View
<
T
>
(
&
arr
[
0
],
size
);
}
};
template
<
typename
T
,
size_t
N
>
struct
ViewBuilder
<
T
(
&
)[
N
]
>
{
typedef
T
Type
;
static
View
<
T
>
build
(
T
(
&
arr
)[
N
])
{
return
buildSize
(
arr
,
N
);
}
static
View
<
T
>
buildSize
(
T
(
&
arr
)[
N
],
size_t
size
)
{
if
(
size
>
N
)
throw
std
::
invalid_argument
(
"out of bounds size"
);
return
View
<
T
>
(
&
arr
[
0
],
size
);
}
};
template
<
typename
T
>
struct
ViewBuilder
<
std
::
vector
<
T
>>
{
typedef
T
Type
;
static
View
<
T
>
build
(
const
std
::
vector
<
T
>&
vec
)
{
return
buildSized
(
vec
,
vec
.
size
());
}
static
View
<
T
>
buildSized
(
const
std
::
vector
<
T
>&
vec
,
size_t
size
)
{
if
(
size
>
vec
.
size
())
throw
std
::
invalid_argument
(
"out of bounds size"
);
return
View
<
T
>
(
&
vec
[
0
],
size
);
}
};
template
<
>
struct
ViewBuilder
<
std
::
string
>
{
typedef
std
::
string
Type
;
static
StringView
build
(
const
std
::
string
&
str
)
{
return
buildSized
(
str
,
str
.
size
());
}
static
StringView
buildSized
(
const
std
::
string
&
str
,
size_t
size
)
{
if
(
size
>
str
.
size
())
throw
std
::
invalid_argument
(
"out of bounds size"
);
return
StringView
(
str
.
data
(),
size
);
}
};
};
template
<
typename
Cont
>
View
<
typename
impl
::
ViewBuilder
<
Cont
>::
Type
>
make_view
(
const
Cont
&
cont
)
{
return
impl
::
ViewBuilder
<
Cont
>::
build
(
cont
);
}
template
<
typename
Cont
>
View
<
typename
impl
::
ViewBuilder
<
Cont
>::
Type
>
make_view
(
const
Cont
&
cont
,
size_t
size
)
{
return
impl
::
ViewBuilder
<
Cont
>::
buildSized
(
cont
,
size
);
}
tests/CMakeLists.txt
View file @
21ff3fdd
...
...
@@ -21,3 +21,7 @@ add_test( router_test run_router_test )
add_executable
(
run_cookie_test cookie_test.cc
)
target_link_libraries
(
run_cookie_test gtest gtest_main net
)
add_test
(
cookie_test run_cookie_test
)
add_executable
(
run_view_test view_test.cc
)
target_link_libraries
(
run_view_test gtest gtest_main net
)
add_test
(
view_test run_view_test
)
tests/cookie_test.cc
0 → 100644
View file @
21ff3fdd
#include "gtest/gtest.h"
#include "cookie.h"
using
namespace
Net
;
using
namespace
Net
::
Http
;
void
parse
(
const
char
*
str
,
std
::
function
<
void
(
const
Cookie
&
)
>
testFunc
)
{
auto
c1
=
Cookie
::
fromString
(
std
::
string
(
str
));
testFunc
(
c1
);
auto
c2
=
Cookie
::
fromRaw
(
str
,
strlen
(
str
));
testFunc
(
c2
);
}
TEST
(
cookie_test
,
basic_test
)
{
parse
(
"SID=31d4d96e407aad42"
,
[](
const
Cookie
&
cookie
)
{
ASSERT_EQ
(
cookie
.
name
,
"SID"
);
ASSERT_EQ
(
cookie
.
value
,
"31d4d96e407aad42"
);
});
}
TEST
(
cookie_test
,
attributes_test
)
{
parse
(
"SID=31d4d96e407aad42; Path=/"
,
[](
const
Cookie
&
c
)
{
ASSERT_EQ
(
c
.
name
,
"SID"
);
ASSERT_EQ
(
c
.
value
,
"31d4d96e407aad42"
);
ASSERT_EQ
(
c
.
path
.
getOrElse
(
""
),
"/"
);
});
parse
(
"SID=31d4d96e407aad42; Path=/; Domain=example.com"
,
[](
const
Cookie
&
c
)
{
ASSERT_EQ
(
c
.
path
.
getOrElse
(
""
),
"/"
);
ASSERT_EQ
(
c
.
domain
.
getOrElse
(
""
),
"example.com"
);
});
parse
(
"lang=en-US; Path=/; Domain=example.com; Max-Age=10"
,
[](
const
Cookie
&
c
)
{
ASSERT_EQ
(
c
.
name
,
"lang"
);
ASSERT_EQ
(
c
.
value
,
"en-US"
);
ASSERT_EQ
(
c
.
path
.
getOrElse
(
""
),
"/"
);
ASSERT_EQ
(
c
.
domain
.
getOrElse
(
""
),
"example.com"
);
ASSERT_EQ
(
c
.
maxAge
.
getOrElse
(
0
),
10
);
});
parse
(
"lang=en-US; Expires=Wed, 09 Jun 2021 10:18:14 GMT"
,
[](
const
Cookie
&
c
)
{
ASSERT_EQ
(
c
.
name
,
"lang"
);
ASSERT_EQ
(
c
.
value
,
"en-US"
);
auto
expires
=
c
.
expires
.
getOrElse
(
FullDate
());
auto
date
=
expires
.
date
();
ASSERT_EQ
(
date
.
tm_year
,
121
);
ASSERT_EQ
(
date
.
tm_mon
,
5
);
ASSERT_EQ
(
date
.
tm_mday
,
9
);
ASSERT_EQ
(
date
.
tm_hour
,
10
);
ASSERT_EQ
(
date
.
tm_min
,
18
);
ASSERT_EQ
(
date
.
tm_sec
,
14
);
});
parse
(
"lang=en-US; Path=/; Domain=example.com;"
,
[](
const
Cookie
&
c
)
{
ASSERT_EQ
(
c
.
name
,
"lang"
);
ASSERT_EQ
(
c
.
value
,
"en-US"
);
ASSERT_EQ
(
c
.
domain
.
getOrElse
(
""
),
"example.com"
);
});
}
TEST
(
cookie_test
,
bool_test
)
{
parse
(
"SID=31d4d96e407aad42; Path=/; Secure"
,
[](
const
Cookie
&
c
)
{
ASSERT_EQ
(
c
.
name
,
"SID"
);
ASSERT_EQ
(
c
.
value
,
"31d4d96e407aad42"
);
ASSERT_EQ
(
c
.
path
.
getOrElse
(
""
),
"/"
);
ASSERT_TRUE
(
c
.
secure
);
ASSERT_FALSE
(
c
.
httpOnly
);
});
parse
(
"SID=31d4d96e407aad42; Path=/; Secure; HttpOnly"
,
[](
const
Cookie
&
c
)
{
ASSERT_EQ
(
c
.
name
,
"SID"
);
ASSERT_EQ
(
c
.
value
,
"31d4d96e407aad42"
);
ASSERT_EQ
(
c
.
path
.
getOrElse
(
""
),
"/"
);
ASSERT_TRUE
(
c
.
secure
);
ASSERT_TRUE
(
c
.
httpOnly
);
});
}
TEST
(
cookie_test
,
ext_test
)
{
parse
(
"lang=en-US; Path=/; Scope=Private"
,
[](
const
Cookie
&
c
)
{
ASSERT_EQ
(
c
.
name
,
"lang"
);
ASSERT_EQ
(
c
.
value
,
"en-US"
);
ASSERT_EQ
(
c
.
path
.
getOrElse
(
""
),
"/"
);
auto
fooIt
=
c
.
ext
.
find
(
"Scope"
);
ASSERT_TRUE
(
fooIt
!=
std
::
end
(
c
.
ext
));
ASSERT_EQ
(
fooIt
->
second
,
"Private"
);
});
}
TEST
(
cookie_test
,
write_test
)
{
Cookie
c1
(
"lang"
,
"fr-FR"
);
c1
.
path
=
Some
(
std
::
string
(
"/"
));
c1
.
domain
=
Some
(
std
::
string
(
"example.com"
));
std
::
ostringstream
oss
;
c1
.
write
(
oss
);
ASSERT_EQ
(
oss
.
str
(),
"lang=fr-FR; Path=/; Domain=example.com"
);
Cookie
c2
(
"lang"
,
"en-US"
);
std
::
tm
expires
;
std
::
memset
(
&
expires
,
0
,
sizeof
expires
);
expires
.
tm_isdst
=
1
;
expires
.
tm_mon
=
2
;
expires
.
tm_year
=
118
;
expires
.
tm_mday
=
16
;
expires
.
tm_hour
=
17
;
expires
.
tm_min
=
0
;
expires
.
tm_sec
=
0
;
c2
.
path
=
Some
(
std
::
string
(
"/"
));
c2
.
expires
=
Some
(
FullDate
(
expires
));
oss
.
str
(
""
);
c2
.
write
(
oss
);
Cookie
c3
(
"lang"
,
"en-US"
);
c3
.
secure
=
true
;
c3
.
ext
.
insert
(
std
::
make_pair
(
"Scope"
,
"Private"
));
oss
.
str
(
""
);
c3
.
write
(
oss
);
ASSERT_EQ
(
oss
.
str
(),
"lang=en-US; Secure; Scope=Private"
);
};
TEST
(
cookie_test
,
invalid_test
)
{
ASSERT_THROW
(
Cookie
::
fromString
(
"lang"
),
std
::
runtime_error
);
ASSERT_THROW
(
Cookie
::
fromString
(
"lang=en-US; Expires"
),
std
::
runtime_error
);
ASSERT_THROW
(
Cookie
::
fromString
(
"lang=en-US; Path=/; Domain"
),
std
::
runtime_error
);
ASSERT_THROW
(
Cookie
::
fromString
(
"lang=en-US; Max-Age=12ab"
),
std
::
invalid_argument
);
}
tests/view_test.cc
0 → 100644
View file @
21ff3fdd
#include "gtest/gtest.h"
#include "view.h"
template
<
typename
T
>
std
::
vector
<
T
>
make_vec
(
std
::
initializer_list
<
T
>
list
)
{
return
std
::
vector
<
T
>
(
list
);
}
TEST
(
view_test
,
test_vector
)
{
auto
vec1
=
make_vec
({
1
,
2
,
3
,
4
});
auto
v1
=
make_view
(
vec1
);
ASSERT_EQ
(
v1
.
size
(),
4
);
ASSERT_EQ
(
v1
[
0
],
1
);
ASSERT_EQ
(
v1
[
3
],
4
);
auto
v2
(
v1
);
ASSERT_EQ
(
v2
.
size
(),
4
);
ASSERT_EQ
(
v2
[
0
],
1
);
ASSERT_EQ
(
v2
[
3
],
4
);
auto
vec2
=
make_vec
({
2
,
4
,
6
,
8
,
10
});
auto
v3
=
make_view
(
vec2
,
4
);
ASSERT_EQ
(
v3
.
size
(),
4
);
ASSERT_EQ
(
v3
[
0
],
2
);
ASSERT_EQ
(
v3
[
3
],
8
);
ASSERT_THROW
(
v3
.
at
(
4
),
std
::
invalid_argument
);
ASSERT_EQ
(
v1
,
v2
);
ASSERT_NE
(
v1
,
v3
);
auto
vec3
=
make_vec
({
4
,
3
,
2
,
1
});
auto
v4
=
make_view
(
vec3
);
ASSERT_NE
(
v4
,
v1
);
std
::
vector
<
int
>
vec4
;
auto
v5
=
make_view
(
vec4
);
ASSERT_TRUE
(
v5
.
empty
());
auto
v6
=
make_view
(
vec3
,
0
);
ASSERT_TRUE
(
v6
.
empty
());
}
TEST
(
view_test
,
test_array
)
{
std
::
array
<
int
,
4
>
arr1
{
4
,
5
,
6
,
7
};
auto
v1
=
make_view
(
arr1
);
ASSERT_EQ
(
v1
.
size
(),
4
);
ASSERT_EQ
(
v1
[
0
],
4
);
ASSERT_EQ
(
v1
[
3
],
7
);
auto
v2
=
make_view
(
arr1
,
2
);
ASSERT_EQ
(
v2
.
size
(),
2
);
ASSERT_EQ
(
v2
[
1
],
5
);
ASSERT_THROW
(
v2
.
at
(
3
),
std
::
invalid_argument
);
std
::
array
<
int
,
4
>
arr2
{
6
,
8
,
1
,
2
};
ASSERT_NE
(
make_view
(
arr2
),
v1
);
std
::
array
<
int
,
4
>
arr3
{
4
,
5
,
6
,
7
};
ASSERT_EQ
(
v1
,
make_view
(
arr3
));
}
TEST
(
view_test
,
string_test
)
{
std
::
string
s1
(
"Hello"
);
auto
v1
=
make_view
(
s1
);
ASSERT_EQ
(
v1
.
size
(),
5
);
ASSERT_EQ
(
v1
[
0
],
'H'
);
ASSERT_EQ
(
v1
[
4
],
'o'
);
ASSERT_EQ
(
v1
,
"Hello"
);
auto
v2
=
make_view
(
s1
,
3
);
ASSERT_TRUE
(
std
::
strcmp
(
v2
.
data
(),
"Hel"
));
ASSERT_EQ
(
v2
,
"Hel"
);
std
::
string
s3
(
s1
);
auto
v3
=
make_view
(
s3
);
ASSERT_EQ
(
v1
,
v3
);
ASSERT_EQ
(
v3
,
s1
);
const
char
*
hello
=
"Hello"
;
ASSERT_EQ
(
v1
,
hello
);
ASSERT_EQ
(
v3
,
hello
);
std
::
string
s4
=
v3
;
ASSERT_EQ
(
s4
,
"Hello"
);
}
TEST
(
view_test
,
null_test
)
{
View
<
int
>
v1
(
nullptr
);
ASSERT_TRUE
(
v1
.
empty
());
View
<
int
>
v2
(
nullptr
,
12
);
ASSERT_TRUE
(
v2
.
empty
());
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment